• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mcallegari / qlcplus / 7252848206

18 Dec 2023 07:26PM UTC coverage: 32.067% (+0.001%) from 32.066%
7252848206

push

github

mcallegari
Code style review #1427

199 of 628 new or added lines in 101 files covered. (31.69%)

8 existing lines in 2 files now uncovered.

15169 of 47304 relevant lines covered (32.07%)

23733.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

3.11
/ui/src/functionstreewidget.cpp
1
/*
2
  Q Light Controller Plus
3
  functionstreewidget.cpp
4

5
  Copyright (c) Massimo Callegari
6

7
  Licensed under the Apache License, Version 2.0 (the "License");
8
  you may not use this file except in compliance with the License.
9
  You may obtain a copy of the License at
10

11
      http://www.apache.org/licenses/LICENSE-2.0.txt
12

13
  Unless required by applicable law or agreed to in writing, software
14
  distributed under the License is distributed on an "AS IS" BASIS,
15
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
  See the License for the specific language governing permissions and
17
  limitations under the License.
18
*/
19

20
#include <QContextMenuEvent>
21
#include <QDebug>
22

23
#include "functionstreewidget.h"
24
#include "function.h"
25
#include "doc.h"
26

27
#define COL_NAME 0
28
#define COL_PATH 1
29

30
FunctionsTreeWidget::FunctionsTreeWidget(Doc *doc, QWidget *parent) :
6✔
31
    QTreeWidget(parent)
32
  , m_doc(doc)
6✔
33
{
34
    sortItems(COL_NAME, Qt::AscendingOrder);
6✔
35

36
    QTreeWidgetItem *root = invisibleRootItem();
6✔
37
    root->setFlags(root->flags() & ~Qt::ItemIsDropEnabled);
6✔
38

39
    connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
6✔
40
                this, SLOT(slotItemChanged(QTreeWidgetItem*)));
41
}
6✔
42

43
void FunctionsTreeWidget::updateTree()
×
44
{
45
    blockSignals(true);
×
46

47
    clearTree();
×
48

49
    foreach (Function* function, m_doc->functions())
×
50
    {
51
        if (function->isVisible())
×
52
            updateFunctionItem(new QTreeWidgetItem(parentItem(function)), function);
×
53
    }
54

55
    blockSignals(false);
×
56
}
×
57

58
void FunctionsTreeWidget::clearTree()
×
59
{
60
    m_foldersMap.clear();
×
61
    clear();
×
62
}
×
63

64
void FunctionsTreeWidget::functionNameChanged(quint32 fid)
×
65
{
66
    blockSignals(true);
×
67
    Function* function = m_doc->function(fid);
×
68
    if (function == NULL)
×
69
    {
70
        blockSignals(false);
×
71
        return;
×
72
    }
73

74
    QTreeWidgetItem* item = functionItem(function);
×
75
    if (item != NULL)
×
76
        updateFunctionItem(item, function);
×
77

78
    blockSignals(false);
×
79
}
80

81
QTreeWidgetItem *FunctionsTreeWidget::addFunction(quint32 fid)
×
82
{
83
    Function* function = m_doc->function(fid);
×
84
    if (function == NULL || function->isVisible() == false)
×
85
        return NULL;
×
86

87
    QTreeWidgetItem* item = functionItem(function);
×
88
    if (item != NULL)
×
89
        return item;
×
90

91
    blockSignals(true);
×
92
    QTreeWidgetItem* parent = parentItem(function);
×
93
    item = new QTreeWidgetItem(parent);
×
94
    updateFunctionItem(item, function);
×
95
    if (parent != NULL)
×
96
        function->setPath(parent->text(COL_PATH));
×
97
    blockSignals(false);
×
98
    return item;
×
99
}
100

101
void FunctionsTreeWidget::updateFunctionItem(QTreeWidgetItem* item, const Function* function)
×
102
{
103
    Q_ASSERT(item != NULL);
×
104
    Q_ASSERT(function != NULL);
×
105
    item->setText(COL_NAME, function->name());
×
106
    item->setIcon(COL_NAME, function->getIcon());
×
107
    item->setData(COL_NAME, Qt::UserRole, function->id());
×
108
    item->setData(COL_NAME, Qt::UserRole + 1, function->type());
×
109
    item->setFlags(item->flags() & ~Qt::ItemIsDropEnabled);
×
110
}
×
111

112
QTreeWidgetItem* FunctionsTreeWidget::parentItem(const Function* function)
×
113
{
114
    Q_ASSERT(function != NULL);
×
115

116
    if (function->isVisible() == false)
×
117
        return NULL;
×
118

119
    QString basePath = Function::typeToString(function->type());
×
120
    if (m_foldersMap.contains(QString(basePath + "/")) == false)
×
121
    {
122
        // Parent item for the given type doesn't exist yet so create one
123
        QTreeWidgetItem* item = new QTreeWidgetItem(this);
×
124
        item->setText(COL_NAME, basePath);
×
125
        item->setIcon(COL_NAME, function->getIcon());
×
126
        item->setData(COL_NAME, Qt::UserRole, Function::invalidId());
×
127
        item->setData(COL_NAME, Qt::UserRole + 1, function->type());
×
128
        item->setText(COL_PATH, QString(basePath + "/"));
×
129
        item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled);
×
130
        m_foldersMap[QString(basePath + "/")] = item;
×
131
    }
132

133
    QTreeWidgetItem *pItem = folderItem(function->path());
×
134

135
    if (pItem != NULL)
×
136
    {
137
        //qDebug() << "Found item for function:" << function->name() << ", path: " << function->path();
138
        return pItem;
×
139
    }
140

141
    return NULL;
×
142
}
143

144
quint32 FunctionsTreeWidget::itemFunctionId(const QTreeWidgetItem* item) const
×
145
{
146
    if (item == NULL || item->parent() == NULL)
×
147
        return Function::invalidId();
×
148
    else
149
    {
150
        QVariant var = item->data(COL_NAME, Qt::UserRole);
×
151
        if (var.isValid() == false)
×
152
            return Function::invalidId();
×
153

154
        return var.toUInt();
×
155
    }
156
}
157

158
QTreeWidgetItem* FunctionsTreeWidget::functionItem(const Function* function)
×
159
{
160
    Q_ASSERT(function != NULL);
×
161

162
    if (function->isVisible() == false)
×
163
        return NULL;
×
164

165
    QTreeWidgetItem* parent = parentItem(function);
×
166
    Q_ASSERT(parent != NULL);
×
167

168
    for (int i = 0; i < parent->childCount(); i++)
×
169
    {
170
        QTreeWidgetItem* item = parent->child(i);
×
171
        if (itemFunctionId(item) == function->id())
×
172
            return item;
×
173
    }
174

175
    return NULL;
×
176
}
177

178
/*********************************************************************
179
 * Tree folders
180
 *********************************************************************/
181

182
void FunctionsTreeWidget::addFolder()
×
183
{
184
    blockSignals(true);
×
185
    if (selectedItems().isEmpty())
×
186
    {
187
        blockSignals(false);
×
188
        return;
×
189
    }
190

191
    QTreeWidgetItem *item = selectedItems().first();
×
192
    if (item->text(COL_PATH).isEmpty())
×
193
        item = item->parent();
×
194

195
    int type = item->data(COL_NAME, Qt::UserRole + 1).toInt();
×
196

197
    QString fullPath = item->text(COL_PATH);
×
198
    if (fullPath.endsWith('/') == false)
×
199
        fullPath.append("/");
×
200

201
    QString newName = "New folder";
×
202

203
    int folderCount = 1;
×
204

205
    while (m_foldersMap.contains(fullPath + newName))
×
206
    {
207
        newName = "New Folder " + QString::number(folderCount++);
×
208
    }
209

210
    fullPath += newName;
×
211

212
    QTreeWidgetItem *folder = new QTreeWidgetItem(item);
×
213
    folder->setText(COL_NAME, newName);
×
214
    folder->setIcon(COL_NAME, QIcon(":/folder.png"));
×
215
    folder->setData(COL_NAME, Qt::UserRole, Function::invalidId());
×
216
    folder->setData(COL_NAME, Qt::UserRole + 1, type);
×
217
    folder->setText(COL_PATH, fullPath);
×
218
    folder->setFlags(folder->flags() | Qt::ItemIsDropEnabled | Qt::ItemIsEditable);
×
219

220
    m_foldersMap[fullPath] = folder;
×
221
    item->setExpanded(true);
×
222

223
    blockSignals(false);
×
224

225
    scrollToItem(folder, QAbstractItemView::PositionAtCenter);
×
226
}
227

228
void FunctionsTreeWidget::deleteFolder(QTreeWidgetItem *item)
×
229
{
230
    if (item == NULL)
×
231
        return;
×
232

233
    QList<QTreeWidgetItem*> childrenList;
×
234
    for (int i = 0; i < item->childCount(); i++)
×
235
        childrenList.append(item->child(i));
×
236

237
    QListIterator <QTreeWidgetItem*> it(childrenList);
×
238
    while (it.hasNext() == true)
×
239
    {
240
        QTreeWidgetItem *child = it.next();
×
241
        quint32 fid = child->data(COL_NAME, Qt::UserRole).toUInt();
×
242
        if (fid != Function::invalidId())
×
243
        {
244
            m_doc->deleteFunction(fid);
×
245
            delete child;
×
246
        }
247
        else
248
            deleteFolder(child);
×
249
    }
250

251
    QString name = item->text(COL_PATH);
×
252

253
    if (m_foldersMap.contains(name))
×
254
        m_foldersMap.remove(name);
×
255

256
    delete item;
×
257
}
258

259
QTreeWidgetItem *FunctionsTreeWidget::folderItem(QString name)
×
260
{
261
    if (selectedItems().count() > 0)
×
262
    {
263
        QString currFolder = selectedItems().first()->text(COL_PATH);
×
264
        if (currFolder.contains(name) && m_foldersMap.contains(currFolder))
×
265
            return m_foldersMap[currFolder];
×
266
    }
267

268
    if (m_foldersMap.contains(name))
×
269
        return m_foldersMap[name];
×
270

271
    if (name.endsWith('/'))
×
272
        return NULL;
×
273

274
    qDebug() << "Folder" << name << "doesn't exist. Creating it...";
×
275

276
    QTreeWidgetItem *parentNode = NULL;
×
277
    int type = Function::Undefined;
×
278
    QString fullPath;
×
279
    QStringList levelsList = name.split("/");
×
NEW
280
    foreach (QString level, levelsList)
×
281
    {
282
        // the first round is a category node. Just retrieve the item pointer
283
        // and the type, then skip it.
284
        if (fullPath.isEmpty())
×
285
        {
286
            if (m_foldersMap.contains(level + "/"))
×
287
            {
288
                parentNode = m_foldersMap[level + "/"];
×
289
                type = parentNode->data(COL_NAME, Qt::UserRole + 1).toInt();
×
290
            }
291
            fullPath = level;
×
292
            continue;
×
293
        }
294

295
        fullPath.append("/");
×
296
        fullPath.append(level);
×
297

298
        // create only missing levels
299
        if (m_foldersMap.contains(fullPath) == false)
×
300
        {
301
            QTreeWidgetItem *folder = new QTreeWidgetItem(parentNode);
×
302
            folder->setText(COL_NAME, level);
×
303
            folder->setIcon(COL_NAME, QIcon(":/folder.png"));
×
304
            folder->setData(COL_NAME, Qt::UserRole, Function::invalidId());
×
305
            folder->setData(COL_NAME, Qt::UserRole + 1, type);
×
306
            folder->setText(COL_PATH, fullPath);
×
307
            folder->setFlags(folder->flags() | Qt::ItemIsDropEnabled | Qt::ItemIsEditable);
×
308

309
            m_foldersMap[fullPath] = folder;
×
310
            parentNode = folder;
×
311
        }
312
        else
313
            parentNode = m_foldersMap[fullPath];
×
314
    }
315

316
    return m_foldersMap[name];
×
317
}
318

319
void FunctionsTreeWidget::slotItemChanged(QTreeWidgetItem *item)
×
320
{
321
    blockSignals(true);
×
322
    qDebug() << "[FunctionsTreeWidget] TREE item changed";
×
323
    if (item->text(COL_PATH).isEmpty())
×
324
    {
325
        blockSignals(false);
×
326
        return;
×
327
    }
328

329
    QTreeWidgetItem *parent = item->parent();
×
330
    if (parent != NULL)
×
331
    {
332
        QString fullPath = parent->text(COL_PATH);
×
333

334
        if (fullPath.endsWith('/') == false)
×
335
            fullPath.append("/");
×
336
        fullPath.append(item->text(COL_NAME));
×
337

338
        m_foldersMap.remove(item->text(COL_PATH));
×
339
        item->setText(COL_PATH, fullPath);
×
340
        m_foldersMap[fullPath] = item;
×
341
        slotUpdateChildrenPath(item);
×
342
    }
343
    blockSignals(false);
×
344
}
345

346
void FunctionsTreeWidget::slotUpdateChildrenPath(QTreeWidgetItem *root)
×
347
{
348
    if (root->childCount() == 0)
×
349
        return;
×
350
    for (int i = 0; i < root->childCount(); i++)
×
351
    {
352
        QTreeWidgetItem *child = root->child(i);
×
353

354
        // child can be a function node or another folder
355
        QString path = child->text(COL_PATH);
×
356
        if (path.isEmpty()) // function node
×
357
        {
358
            quint32 fid = child->data(COL_NAME, Qt::UserRole).toUInt();
×
359
            Function *func = m_doc->function(fid);
×
360
            if (func != NULL)
×
361
                func->setPath(root->text(COL_PATH));
×
362
        }
363
        else
364
        {
365
            slotItemChanged(child);
×
366
        }
367
    }
368
}
369

370
void FunctionsTreeWidget::mousePressEvent(QMouseEvent *event)
×
371
{
372
    QTreeWidget::mousePressEvent(event);
×
373

374
    m_draggedItems = selectedItems(); //itemAt(event->pos());
×
375
}
×
376

377

378
void FunctionsTreeWidget::dropEvent(QDropEvent *event)
×
379
{
380
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
381
    QTreeWidgetItem *dropItem = itemAt(event->pos());
×
382
#else
383
    QTreeWidgetItem *dropItem = itemAt(event->position().toPoint());
384
#endif
385
    if (m_draggedItems.count() == 0 || dropItem == NULL)
×
386
        return;
×
387

388
    QVariant var = dropItem->data(COL_NAME, Qt::UserRole + 1);
×
389
    if (var.isValid() == false)
×
390
        return;
×
391

392
    int dropType = var.toInt();
×
393
    //QString folderName = dropItem->text(COL_PATH);
394

395
    foreach (QTreeWidgetItem *item, m_draggedItems)
×
396
    {
397
        quint32 dragFID = item->data(COL_NAME, Qt::UserRole).toUInt();
×
398
        Function *dragFunc = m_doc->function(dragFID);
×
399
        if (dragFunc != NULL && dragFunc->type() == dropType)
×
400
        {
401
            QTreeWidget::dropEvent(event);
×
402
            quint32 fid = item->data(COL_NAME, Qt::UserRole).toUInt();
×
403
            Function *func = m_doc->function(fid);
×
404
            if (func != NULL)
×
405
                func->setPath(dropItem->text(COL_PATH));
×
406
        }
407
        else
408
        {
409
            // m_draggedItem is a folder
410
            int dragType = item->data(COL_NAME, Qt::UserRole + 1).toInt();
×
411
            if (dragType == dropType)
×
412
                QTreeWidget::dropEvent(event);
×
413
            slotItemChanged(item);
×
414
        }
415
    }
416

417
    m_draggedItems.clear();
×
418
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc