~ubuntu-branches/ubuntu/wily/kmenuedit/wily

« back to all changes in this revision

Viewing changes to treeview.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2014-10-14 13:48:27 UTC
  • Revision ID: package-import@ubuntu.com-20141014134827-c4gvv92bbv7zww8j
Tags: upstream-5.1.0.1
ImportĀ upstreamĀ versionĀ 5.1.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *   Copyright (C) 2000 Matthias Elter <elter@kde.org>
 
3
 *   Copyright (C) 2001-2002 Raffaele Sandrini <sandrini@kde.org>
 
4
 *   Copyright (C) 2003 Waldo Bastian <bastian@kde.org>
 
5
 *   Copyright (C) 2008 Laurent Montel <montel@kde.org>
 
6
 *
 
7
 *   This program is free software; you can redistribute it and/or modify
 
8
 *   it under the terms of the GNU General Public License as published by
 
9
 *   the Free Software Foundation; either version 2 of the License, or
 
10
 *   (at your option) any later version.
 
11
 *
 
12
 *   This program is distributed in the hope that it will be useful,
 
13
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 *   GNU General Public License for more details.
 
16
 *
 
17
 *   You should have received a copy of the GNU General Public License
 
18
 *   along with this program; if not, write to the Free Software
 
19
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
20
 *
 
21
 */
 
22
 
 
23
#include "treeview.h"
 
24
 
 
25
#include <unistd.h>
 
26
 
 
27
#include <QDir>
 
28
#include <QDrag>
 
29
#include <QHeaderView>
 
30
#include <QPainter>
 
31
#include <QRegExp>
 
32
#include <QPixmap>
 
33
#include <QDropEvent>
 
34
#include <QMenu>
 
35
#include <QApplication>
 
36
#include <QtDBus/QtDBus>
 
37
#include <QSignalMapper>
 
38
 
 
39
#include <KAction>
 
40
#include <KActionCollection>
 
41
#include <KBuildSycocaProgressDialog>
 
42
#include <KDebug>
 
43
#include <KDesktopFile>
 
44
#include <KGlobal>
 
45
#include <KIconLoader>
 
46
#include <KInputDialog>
 
47
#include <KLocalizedString>
 
48
#include <KMessageBox>
 
49
#include <KService>
 
50
#include <KServiceGroup>
 
51
#include <KConfig>
 
52
#include <KConfigGroup>
 
53
#include <KStandardDirs>
 
54
#include <kio/netaccess.h>
 
55
#include <KUrl>
 
56
 
 
57
#include "treeview.moc"
 
58
#include "menufile.h"
 
59
#include "menuinfo.h"
 
60
 
 
61
#define MOVE_FOLDER 'M'
 
62
#define COPY_FOLDER 'C'
 
63
#define MOVE_FILE   'm'
 
64
#define COPY_FILE   'c'
 
65
#define COPY_SEPARATOR 'S'
 
66
 
 
67
static const char *s_internalMimeType = "application/x-kmenuedit-internal";
 
68
 
 
69
class SeparatorWidget : public QWidget
 
70
{
 
71
public:
 
72
    SeparatorWidget()
 
73
        : QWidget(0)
 
74
    {
 
75
    }
 
76
 
 
77
protected:
 
78
    void paintEvent(QPaintEvent * /*event*/)
 
79
    {
 
80
        QPainter p(this);
 
81
        // Draw Separator
 
82
        int h = (height() / 2) -1;
 
83
//        if (isSelected()) {
 
84
//            p->setPen( palette().color( QPalette::HighlightedText ) );
 
85
//        } else {
 
86
//            p->setPen( palette().color( QPalette::Text ) );
 
87
//        }
 
88
 
 
89
        p.drawLine(2, h, width() - 4, h);
 
90
    }
 
91
};
 
92
 
 
93
 
 
94
TreeItem::TreeItem(QTreeWidgetItem *parent, QTreeWidgetItem *after, const QString& menuId, bool _m_init)
 
95
    : QTreeWidgetItem(parent, after),
 
96
      m_hidden(false),
 
97
      m_init(_m_init),
 
98
      m_layoutDirty(false),
 
99
      m_menuId(menuId),
 
100
      m_folderInfo(0),
 
101
      m_entryInfo(0)
 
102
{
 
103
}
 
104
 
 
105
TreeItem::TreeItem(QTreeWidget *parent, QTreeWidgetItem *after, const QString& menuId, bool _m_init)
 
106
    : QTreeWidgetItem(parent, after),
 
107
      m_hidden(false),
 
108
      m_init(_m_init),
 
109
      m_layoutDirty(false),
 
110
      m_menuId(menuId),
 
111
      m_folderInfo(0),
 
112
      m_entryInfo(0)
 
113
{
 
114
    load();
 
115
}
 
116
 
 
117
TreeItem::~TreeItem()
 
118
{
 
119
}
 
120
 
 
121
/**
 
122
 * @brief Return the description.
 
123
 * @return Description, or an empty string if none.
 
124
 */
 
125
QString TreeItem::description() const
 
126
{
 
127
    QString description;
 
128
    if (isEntry()) {
 
129
        description = entryInfo()->description;
 
130
    }
 
131
    return description;
 
132
}
 
133
 
 
134
/**
 
135
 * @brief Compare two items using their names.
 
136
 * @param item1 First item.
 
137
 * @param item2 Second item.
 
138
 * @return Integer less than, equal to, or greater than zero if item1 is less than, equal to, or greater than item2.
 
139
 */
 
140
bool TreeItem::itemNameLessThan(QTreeWidgetItem *item1, QTreeWidgetItem *item2)
 
141
{
 
142
    TreeItem *treeItem1 = static_cast<TreeItem*>(item1);
 
143
    TreeItem *treeItem2 = static_cast<TreeItem*>(item2);
 
144
    return treeItem1->name().toLower() < treeItem2->name().toLower();
 
145
}
 
146
 
 
147
/**
 
148
 * @brief Compare two items using their descriptions. If both are empty, sort them by name.
 
149
 * @param item1 First item.
 
150
 * @param item2 Second item.
 
151
 * @return Integer less than, equal to, or greater than zero if item1 is less than, equal to, or greater than item2.
 
152
 */
 
153
bool TreeItem::itemDescriptionLessThan(QTreeWidgetItem *item1, QTreeWidgetItem *item2)
 
154
{
 
155
    // extract descriptions in lower case
 
156
    TreeItem *treeItem1 = static_cast<TreeItem*>(item1);
 
157
    TreeItem *treeItem2 = static_cast<TreeItem*>(item2);
 
158
    const QString description1 = treeItem1->description().toLower();
 
159
    const QString description2 = treeItem2->description().toLower();
 
160
 
 
161
    // if description is missing for both items, sort them using their names
 
162
    if (description1.isEmpty() && description2.isEmpty()) {
 
163
        return itemNameLessThan(item1, item2);
 
164
    }
 
165
    else {
 
166
        return description1 < description2;
 
167
    }
 
168
}
 
169
 
 
170
void TreeItem::setName(const QString &name)
 
171
{
 
172
    if (m_name == name) {
 
173
        return;
 
174
    }
 
175
 
 
176
    m_name = name;
 
177
    update();
 
178
}
 
179
 
 
180
void TreeItem::setHiddenInMenu(bool b)
 
181
{
 
182
    if (m_hidden == b) {
 
183
        return;
 
184
    }
 
185
 
 
186
    m_hidden = b;
 
187
    update();
 
188
}
 
189
 
 
190
void TreeItem::update()
 
191
{
 
192
    QString s = m_name;
 
193
    if (m_hidden) {
 
194
       s += i18n(" [Hidden]");
 
195
    }
 
196
 
 
197
    setText(0, s);
 
198
}
 
199
 
 
200
void TreeItem::load()
 
201
{
 
202
    if (m_folderInfo && !m_init) {
 
203
       m_init = true;
 
204
       TreeView *tv = static_cast<TreeView *>(treeWidget());
 
205
       tv->fillBranch(m_folderInfo, this);
 
206
    }
 
207
}
 
208
 
 
209
bool TreeItem::isLayoutDirty() const
 
210
{
 
211
    if (m_layoutDirty) {
 
212
        return true;
 
213
    }
 
214
 
 
215
    for (int i = 0; i < childCount(); ++i) {
 
216
        TreeItem *item = dynamic_cast<TreeItem *>(child(i));
 
217
        if (!item) {
 
218
            continue;
 
219
        }
 
220
 
 
221
        if (item->isLayoutDirty()) {
 
222
            return true;
 
223
        }
 
224
    }
 
225
 
 
226
    return false;
 
227
}
 
228
 
 
229
static QPixmap appIcon(const QString &iconName)
 
230
{
 
231
    QPixmap normal = KIconLoader::global()->loadIcon(iconName, KIconLoader::Small, 0, KIconLoader::DefaultState, QStringList(), 0L, true);
 
232
    return normal;
 
233
}
 
234
 
 
235
 
 
236
TreeView::TreeView( KActionCollection *ac, QWidget *parent, const char *name )
 
237
    : QTreeWidget(parent), m_ac(ac), m_popupMenu(0), m_clipboard(0),
 
238
      m_clipboardFolderInfo(0), m_clipboardEntryInfo(0),
 
239
      m_layoutDirty(false),
 
240
      m_detailedMenuEntries(true), m_detailedEntriesNamesFirst(true)
 
241
{
 
242
    m_dropMimeTypes << s_internalMimeType << KUrl::List::mimeDataTypes();
 
243
    qRegisterMetaType<TreeItem *>("TreeItem");
 
244
    setObjectName(name);
 
245
    setAllColumnsShowFocus(true);
 
246
    setRootIsDecorated(true);
 
247
    setSortingEnabled(false);
 
248
    setDragEnabled(true);
 
249
    setAcceptDrops(true);
 
250
    setMinimumWidth(240);
 
251
 
 
252
    setHeaderLabels(QStringList() << QString(""));
 
253
    header()->hide();
 
254
 
 
255
    // listen for creation
 
256
    connect(m_ac->action(NEW_ITEM_ACTION_NAME), SIGNAL(triggered()), SLOT(newitem()));
 
257
    connect(m_ac->action(NEW_SUBMENU_ACTION_NAME), SIGNAL(triggered()), SLOT(newsubmenu()));
 
258
    connect(m_ac->action(NEW_SEPARATOR_ACTION_NAME), SIGNAL(triggered()), SLOT(newsep()));
 
259
 
 
260
    // listen for copy
 
261
    connect(m_ac->action(CUT_ACTION_NAME), SIGNAL(triggered()), SLOT(cut()));
 
262
    connect(m_ac->action(COPY_ACTION_NAME), SIGNAL(triggered()), SLOT(copy()));
 
263
    connect(m_ac->action(PASTE_ACTION_NAME), SIGNAL(triggered()), SLOT(paste()));
 
264
 
 
265
    // listen for deleting
 
266
    connect(m_ac->action(DELETE_ACTION_NAME), SIGNAL(triggered()), SLOT(del()));
 
267
 
 
268
    // listen for sorting
 
269
    m_sortSignalMapper = new QSignalMapper(this);
 
270
    QAction *action = m_ac->action(SORT_BY_NAME_ACTION_NAME);
 
271
    connect(action, SIGNAL(triggered()), m_sortSignalMapper, SLOT(map()));
 
272
    m_sortSignalMapper->setMapping(action, SortByName);
 
273
    action = m_ac->action(SORT_BY_DESCRIPTION_ACTION_NAME);
 
274
    connect(action, SIGNAL(triggered()), m_sortSignalMapper, SLOT(map()));
 
275
    m_sortSignalMapper->setMapping(action, SortByDescription);
 
276
    action = m_ac->action(SORT_ALL_BY_NAME_ACTION_NAME);
 
277
    connect(action, SIGNAL(triggered()), m_sortSignalMapper, SLOT(map()));
 
278
    m_sortSignalMapper->setMapping(action, SortAllByName);
 
279
    action = m_ac->action(SORT_ALL_BY_DESCRIPTION_ACTION_NAME);
 
280
    connect(action, SIGNAL(triggered()), m_sortSignalMapper, SLOT(map()));
 
281
    m_sortSignalMapper->setMapping(action, SortAllByDescription);
 
282
    connect(m_sortSignalMapper, SIGNAL(mapped(const int)), this, SLOT(sort(const int)));
 
283
 
 
284
    // connect moving up/down actions
 
285
    connect(m_ac->action(MOVE_UP_ACTION_NAME), SIGNAL(triggered()), SLOT(moveUpItem()));
 
286
    connect(m_ac->action(MOVE_DOWN_ACTION_NAME), SIGNAL(triggered()), SLOT(moveDownItem()));
 
287
 
 
288
    // listen for selection
 
289
    connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
 
290
            SLOT(itemSelected(QTreeWidgetItem*)));
 
291
 
 
292
    m_menuFile = new MenuFile(KStandardDirs::locateLocal("xdgconf-menu", "applications-kmenuedit.menu"));
 
293
    m_rootFolder = new MenuFolderInfo;
 
294
    m_separator = new MenuSeparatorInfo;
 
295
}
 
296
 
 
297
TreeView::~TreeView()
 
298
{
 
299
    cleanupClipboard();
 
300
    delete m_rootFolder;
 
301
    delete m_separator;
 
302
}
 
303
 
 
304
void TreeView::setViewMode(bool showHidden)
 
305
{
 
306
    // setup popup menu
 
307
    delete m_popupMenu;
 
308
    m_popupMenu = new QMenu(this);
 
309
 
 
310
    // creation
 
311
    m_popupMenu->addAction(m_ac->action(NEW_ITEM_ACTION_NAME));
 
312
    m_popupMenu->addAction(m_ac->action(NEW_SUBMENU_ACTION_NAME));
 
313
    m_popupMenu->addAction(m_ac->action(NEW_SEPARATOR_ACTION_NAME));
 
314
    m_popupMenu->addSeparator();
 
315
 
 
316
    // copy
 
317
    m_popupMenu->addAction(m_ac->action(CUT_ACTION_NAME));
 
318
    m_popupMenu->addAction(m_ac->action(COPY_ACTION_NAME));
 
319
    m_popupMenu->addAction(m_ac->action(PASTE_ACTION_NAME));
 
320
    m_popupMenu->addSeparator();
 
321
 
 
322
    // delete
 
323
    m_popupMenu->addAction( m_ac->action(DELETE_ACTION_NAME));
 
324
    m_popupMenu->addSeparator();
 
325
 
 
326
    // move
 
327
    m_popupMenu->addAction(m_ac->action(MOVE_UP_ACTION_NAME));
 
328
    m_popupMenu->addAction(m_ac->action(MOVE_DOWN_ACTION_NAME));
 
329
    m_popupMenu->addSeparator();
 
330
 
 
331
    // sort
 
332
    m_popupMenu->addAction(m_ac->action(SORT_ACTION_NAME));
 
333
 
 
334
    m_showHidden = showHidden;
 
335
    readMenuFolderInfo();
 
336
    fill();
 
337
}
 
338
 
 
339
void TreeView::readMenuFolderInfo(MenuFolderInfo *folderInfo, KServiceGroup::Ptr folder, const QString &prefix)
 
340
{
 
341
    if (!folderInfo)
 
342
    {
 
343
       folderInfo = m_rootFolder;
 
344
       folder = KServiceGroup::root();
 
345
    }
 
346
 
 
347
    if (!folder || !folder->isValid())
 
348
        return;
 
349
 
 
350
    folderInfo->caption = folder->caption();
 
351
    folderInfo->comment = folder->comment();
 
352
 
 
353
    // Item names may contain ampersands. To avoid them being converted
 
354
    // to accelerators, replace them with two ampersands.
 
355
    folderInfo->hidden = folder->noDisplay();
 
356
    folderInfo->directoryFile = folder->directoryEntryPath();
 
357
    folderInfo->icon = folder->icon();
 
358
    QString id = folder->relPath();
 
359
    int i = id.lastIndexOf('/', -2);
 
360
    id = id.mid(i+1);
 
361
    folderInfo->id = id;
 
362
    folderInfo->fullId = prefix + id;
 
363
 
 
364
    for (const KSycocaEntry::Ptr &e : folder->entries(true, !m_showHidden, true, m_detailedMenuEntries && !m_detailedEntriesNamesFirst))
 
365
    {
 
366
        if (e->isType(KST_KServiceGroup))
 
367
        {
 
368
            const KServiceGroup::Ptr serviceGroup(static_cast<KServiceGroup*>(e.data()));
 
369
            MenuFolderInfo *subFolderInfo = new MenuFolderInfo();
 
370
            readMenuFolderInfo(subFolderInfo, serviceGroup, folderInfo->fullId);
 
371
            folderInfo->add(subFolderInfo, true);
 
372
        }
 
373
        else if (e->isType(KST_KService))
 
374
        {
 
375
            const KService::Ptr service(static_cast<KService*>(e.data()));
 
376
            folderInfo->add(new MenuEntryInfo(service), true);
 
377
        }
 
378
        else if (e->isType(KST_KServiceSeparator))
 
379
        {
 
380
            folderInfo->add(m_separator, true);
 
381
        }
 
382
    }
 
383
}
 
384
 
 
385
void TreeView::fill()
 
386
{
 
387
    QApplication::setOverrideCursor(Qt::WaitCursor);
 
388
    clear();
 
389
    fillBranch(m_rootFolder, 0);
 
390
    QApplication::restoreOverrideCursor();
 
391
}
 
392
 
 
393
QString TreeView::findName(KDesktopFile *df, bool deleted)
 
394
{
 
395
    QString name = df->readName();
 
396
    if (deleted)
 
397
    {
 
398
       if (name == "empty")
 
399
          name.clear();
 
400
       if (name.isEmpty())
 
401
       {
 
402
          bool isLocal = true;
 
403
          const QStringList files = QStandardPaths::locateAll(df->resource(), df->fileName(), QStandardPaths::LocateFile);
 
404
          for(QStringList::ConstIterator it = files.constBegin();
 
405
              it != files.constEnd();
 
406
              ++it)
 
407
          {
 
408
             if (isLocal)
 
409
             {
 
410
                isLocal = false;
 
411
                continue;
 
412
             }
 
413
 
 
414
             KDesktopFile df2(*it);
 
415
             name = df2.readName();
 
416
 
 
417
             if (!name.isEmpty() && (name != "empty"))
 
418
                return name;
 
419
          }
 
420
       }
 
421
    }
 
422
    return name;
 
423
}
 
424
 
 
425
TreeItem *TreeView::createTreeItem(TreeItem *parent, QTreeWidgetItem *after, MenuFolderInfo *folderInfo, bool m_init)
 
426
{
 
427
    TreeItem *item;
 
428
    if (parent) {
 
429
        item = new TreeItem(parent, after, QString(), m_init);
 
430
    } else {
 
431
        item = new TreeItem(this, after, QString(), m_init);
 
432
    }
 
433
 
 
434
    item->setMenuFolderInfo(folderInfo);
 
435
    item->setName(folderInfo->caption);
 
436
    item->setIcon(0, appIcon(folderInfo->icon));
 
437
    item->setDirectoryPath(folderInfo->fullId);
 
438
    item->setHiddenInMenu(folderInfo->hidden);
 
439
    item->load();
 
440
    return item;
 
441
}
 
442
 
 
443
TreeItem *TreeView::createTreeItem(TreeItem *parent, QTreeWidgetItem *after, MenuEntryInfo *entryInfo, bool m_init)
 
444
{
 
445
    bool hidden = entryInfo->hidden;
 
446
 
 
447
    TreeItem* item;
 
448
    if (parent) {
 
449
        item = new TreeItem(parent, after, entryInfo->menuId(),m_init);
 
450
    } else {
 
451
        item = new TreeItem(this, after, entryInfo->menuId(), m_init);
 
452
    }
 
453
 
 
454
    QString name;
 
455
 
 
456
    if (m_detailedMenuEntries && entryInfo->description.length() != 0) {
 
457
        if (m_detailedEntriesNamesFirst) {
 
458
            name = entryInfo->caption + " (" + entryInfo->description + ')';
 
459
        } else {
 
460
            name = entryInfo->description + " (" + entryInfo->caption + ')';
 
461
        }
 
462
    } else {
 
463
        name = entryInfo->caption;
 
464
    }
 
465
 
 
466
    //kDebug() << parent << after << name;
 
467
    item->setMenuEntryInfo(entryInfo);
 
468
    item->setName(name);
 
469
    item->setIcon(0, appIcon(entryInfo->icon));
 
470
    item->setHiddenInMenu(hidden);
 
471
    item->load();
 
472
 
 
473
    return item;
 
474
}
 
475
 
 
476
TreeItem *TreeView::createTreeItem(TreeItem *parent, QTreeWidgetItem *after, MenuSeparatorInfo *, bool init)
 
477
{
 
478
    TreeItem* item;
 
479
    if (parent) {
 
480
        item = new TreeItem(parent, after, QString(), init);
 
481
    } else {
 
482
        item = new TreeItem(this, after, QString(), init);
 
483
    }
 
484
 
 
485
    setItemWidget(item, 0, new SeparatorWidget);
 
486
    return item;
 
487
}
 
488
 
 
489
void TreeView::fillBranch(MenuFolderInfo *folderInfo, TreeItem *parent)
 
490
{
 
491
    QString relPath = parent ? parent->directory() : QString();
 
492
    TreeItem *after = 0;
 
493
    foreach (MenuInfo *info, folderInfo->initialLayout)
 
494
    {
 
495
       MenuEntryInfo *entry = dynamic_cast<MenuEntryInfo*>(info);
 
496
       if (entry)
 
497
       {
 
498
          after = createTreeItem(parent, after, entry);
 
499
          continue;
 
500
       }
 
501
 
 
502
       MenuFolderInfo *subFolder = dynamic_cast<MenuFolderInfo*>(info);
 
503
       if (subFolder)
 
504
       {
 
505
          after = createTreeItem(parent, after, subFolder);
 
506
          continue;
 
507
       }
 
508
       MenuSeparatorInfo *separator = dynamic_cast<MenuSeparatorInfo*>(info);
 
509
       if (separator)
 
510
       {
 
511
          after = createTreeItem(parent, after, separator);
 
512
          continue;
 
513
       }
 
514
    }
 
515
}
 
516
 
 
517
void TreeView::closeAllItems(QTreeWidgetItem *item)
 
518
{
 
519
    item->setExpanded(false);
 
520
    for (int i = 0; i < item->childCount(); ++i) {
 
521
        closeAllItems(item->child(i));
 
522
    }
 
523
}
 
524
 
 
525
TreeItem *TreeView::expandPath(TreeItem *item, const QString &path)
 
526
{
 
527
   int i = path.indexOf("/");
 
528
   QString subMenu = path.left(i+1);
 
529
   QString restMenu = path.mid(i+1);
 
530
 
 
531
   for (int i = 0; i < item->childCount(); ++i) {
 
532
       TreeItem *childItem = dynamic_cast<TreeItem *>(item->child(i));
 
533
       if (!childItem) {
 
534
           continue;
 
535
       }
 
536
 
 
537
       MenuFolderInfo *folderInfo = childItem->folderInfo();
 
538
       if (folderInfo && (folderInfo->id == subMenu)) {
 
539
           childItem->setExpanded(true);
 
540
           if (!restMenu.isEmpty()) {
 
541
               return expandPath(childItem, restMenu);
 
542
           } else {
 
543
               return childItem;
 
544
           }
 
545
       }
 
546
   }
 
547
 
 
548
   return 0;
 
549
}
 
550
 
 
551
void TreeView::selectMenu(const QString &menu)
 
552
{
 
553
   for (int i = 0; i < topLevelItemCount(); ++i) {
 
554
       closeAllItems(topLevelItem(i));
 
555
   }
 
556
 
 
557
   if (menu.length() <= 1)
 
558
   {
 
559
      setCurrentItem(topLevelItem(0));
 
560
      clearSelection();
 
561
      return; // Root menu
 
562
   }
 
563
 
 
564
   QString restMenu = menu;
 
565
   if ( menu.startsWith( '/' ) )
 
566
       restMenu = menu.mid(1);
 
567
   if (!restMenu.endsWith('/'))
 
568
       restMenu += '/';
 
569
 
 
570
   TreeItem *item = 0;
 
571
   int i = restMenu.indexOf("/");
 
572
   QString subMenu = restMenu.left(i+1);
 
573
   restMenu = restMenu.mid(i+1);
 
574
 
 
575
   for (int i = 0; i < topLevelItemCount(); ++i) {
 
576
       item = dynamic_cast<TreeItem *>(topLevelItem(i));
 
577
       if (!item) {
 
578
           continue;
 
579
       }
 
580
 
 
581
       MenuFolderInfo *folderInfo = item->folderInfo();
 
582
       if (folderInfo && (folderInfo->id == subMenu)) {
 
583
           if (!restMenu.isEmpty()) {
 
584
               item = expandPath(item, restMenu);
 
585
           }
 
586
           break;
 
587
       }
 
588
   }
 
589
 
 
590
   if (item)
 
591
   {
 
592
      setCurrentItem(item);
 
593
      scrollToItem(item);
 
594
   }
 
595
}
 
596
 
 
597
void TreeView::selectMenuEntry(const QString &menuEntry)
 
598
{
 
599
    TreeItem *item = static_cast<TreeItem *>(selectedItem());
 
600
    if (!item) {
 
601
        item = static_cast<TreeItem *>(currentItem());
 
602
    }
 
603
 
 
604
    if (!item) {
 
605
        return;
 
606
    }
 
607
 
 
608
    QTreeWidgetItem *parent = item->parent();
 
609
    if (parent) {
 
610
        for (int i = 0; i < parent->childCount(); ++i) {
 
611
            TreeItem *item = dynamic_cast<TreeItem *>(parent->child(i));
 
612
            if (!item || item->isDirectory()) {
 
613
                continue;
 
614
            }
 
615
 
 
616
            MenuEntryInfo *entry = item->entryInfo();
 
617
            if (entry && entry->menuId() == menuEntry) {
 
618
                setCurrentItem(item);
 
619
                scrollToItem(item);
 
620
                return;
 
621
            }
 
622
        }
 
623
    } else {
 
624
        // top level
 
625
        for (int i = 0; i < topLevelItemCount(); ++i) {
 
626
            TreeItem *item = dynamic_cast<TreeItem *>(topLevelItem(i));
 
627
            if (!item || item->isDirectory()) {
 
628
                continue;
 
629
            }
 
630
 
 
631
            MenuEntryInfo *entry = item->entryInfo();
 
632
            if (entry && entry->menuId() == menuEntry) {
 
633
                setCurrentItem(item);
 
634
                scrollToItem(item);
 
635
                return;
 
636
            }
 
637
        }
 
638
    }
 
639
}
 
640
 
 
641
void TreeView::itemSelected(QTreeWidgetItem *item)
 
642
{
 
643
    // ensure the item is visible as selected
 
644
    setItemSelected(item, true);
 
645
 
 
646
    TreeItem *_item = static_cast<TreeItem*>(item);
 
647
    TreeItem *parentItem = 0;
 
648
    bool selected = false;
 
649
    bool dselected = false;
 
650
    if (_item) {
 
651
        selected = true;
 
652
        dselected = _item->isHiddenInMenu();
 
653
        parentItem = getParentItem(_item);
 
654
    }
 
655
 
 
656
    // change actions activation
 
657
    m_ac->action(CUT_ACTION_NAME)->setEnabled(selected);
 
658
    m_ac->action(COPY_ACTION_NAME)->setEnabled(selected);
 
659
    m_ac->action(PASTE_ACTION_NAME)->setEnabled(m_clipboard != 0);
 
660
 
 
661
    if (m_ac->action(DELETE_ACTION_NAME)) {
 
662
        m_ac->action(DELETE_ACTION_NAME)->setEnabled(selected && !dselected);
 
663
    }
 
664
 
 
665
    m_ac->action(SORT_BY_NAME_ACTION_NAME)->setEnabled(selected && _item->isDirectory() && (_item->childCount() > 0));
 
666
    m_ac->action(SORT_BY_DESCRIPTION_ACTION_NAME)->setEnabled(m_ac->action(SORT_BY_NAME_ACTION_NAME)->isEnabled());
 
667
 
 
668
    m_ac->action(MOVE_UP_ACTION_NAME)->setEnabled(selected && (parentItem->indexOfChild(_item) > 0));
 
669
    m_ac->action(MOVE_DOWN_ACTION_NAME)->setEnabled(selected && (parentItem->indexOfChild(_item) < parentItem->childCount() - 1));
 
670
 
 
671
    if (!item) {
 
672
        emit disableAction();
 
673
        return;
 
674
    }
 
675
 
 
676
    if (_item->isDirectory()) {
 
677
       emit entrySelected(_item->folderInfo());
 
678
    } else {
 
679
       emit entrySelected(_item->entryInfo());
 
680
    }
 
681
}
 
682
 
 
683
void TreeView::currentDataChanged(MenuFolderInfo *folderInfo)
 
684
{
 
685
    TreeItem *item = (TreeItem*)selectedItem();
 
686
    if (item == 0 || folderInfo == 0) {
 
687
        return;
 
688
    }
 
689
 
 
690
    item->setName(folderInfo->caption);
 
691
    item->setIcon(0, appIcon(folderInfo->icon));
 
692
}
 
693
 
 
694
void TreeView::currentDataChanged(MenuEntryInfo *entryInfo)
 
695
{
 
696
    TreeItem *item = (TreeItem*)selectedItem();
 
697
    if (item == 0 || entryInfo == 0) {
 
698
        return;
 
699
    }
 
700
 
 
701
    QString name;
 
702
 
 
703
    if (m_detailedMenuEntries && entryInfo->description.length() != 0) {
 
704
        if (m_detailedEntriesNamesFirst) {
 
705
            name = entryInfo->caption + " (" + entryInfo->description + ')';
 
706
        } else {
 
707
            name = entryInfo->description + " (" + entryInfo->caption + ')';
 
708
        }
 
709
    } else {
 
710
        name = entryInfo->caption;
 
711
    }
 
712
 
 
713
    item->setName(name);
 
714
    item->setIcon(0, appIcon(entryInfo->icon));
 
715
}
 
716
 
 
717
QStringList TreeView::fileList(const QString& rPath)
 
718
{
 
719
    QString relativePath = rPath;
 
720
 
 
721
    // truncate "/.directory"
 
722
    int pos = relativePath.lastIndexOf("/.directory");
 
723
    if (pos > 0) relativePath.truncate(pos);
 
724
 
 
725
    QStringList filelist;
 
726
 
 
727
    // loop through all resource dirs and build a file list
 
728
    const QStringList resdirlist = KGlobal::dirs()->resourceDirs("apps");
 
729
    for (QStringList::ConstIterator it = resdirlist.constBegin(); it != resdirlist.constEnd(); ++it)
 
730
    {
 
731
        QDir dir((*it) + '/' + relativePath);
 
732
        if(!dir.exists()) continue;
 
733
 
 
734
        dir.setFilter(QDir::Files);
 
735
        dir.setNameFilters(QStringList() << "*.desktop;*.kdelnk");
 
736
 
 
737
        // build a list of files
 
738
        const QStringList files = dir.entryList();
 
739
        for (QStringList::ConstIterator it = files.constBegin(); it != files.constEnd(); ++it) {
 
740
            // does not work?!
 
741
            //if (filelist.contains(*it)) continue;
 
742
 
 
743
            if (relativePath.isEmpty()) {
 
744
                filelist.removeAll(*it); // hack
 
745
                filelist.append(*it);
 
746
            }
 
747
            else {
 
748
                filelist.removeAll(relativePath + '/' + *it); //hack
 
749
                filelist.append(relativePath + '/' + *it);
 
750
            }
 
751
        }
 
752
    }
 
753
    return filelist;
 
754
}
 
755
 
 
756
QStringList TreeView::dirList(const QString& rPath)
 
757
{
 
758
    QString relativePath = rPath;
 
759
 
 
760
    // truncate "/.directory"
 
761
    int pos = relativePath.lastIndexOf("/.directory");
 
762
    if (pos > 0) relativePath.truncate(pos);
 
763
 
 
764
    QStringList dirlist;
 
765
 
 
766
    // loop through all resource dirs and build a subdir list
 
767
    const QStringList resdirlist = KGlobal::dirs()->resourceDirs("apps");
 
768
    for (QStringList::ConstIterator it = resdirlist.constBegin(); it != resdirlist.constEnd(); ++it)
 
769
    {
 
770
        QDir dir((*it) + '/' + relativePath);
 
771
        if(!dir.exists()) continue;
 
772
        dir.setFilter(QDir::Dirs);
 
773
 
 
774
        // build a list of subdirs
 
775
        const QStringList subdirs = dir.entryList();
 
776
        for (QStringList::ConstIterator it = subdirs.constBegin(); it != subdirs.constEnd(); ++it) {
 
777
            if ((*it) == "." || (*it) == "..") continue;
 
778
            // does not work?!
 
779
            // if (dirlist.contains(*it)) continue;
 
780
 
 
781
            if (relativePath.isEmpty()) {
 
782
                dirlist.removeAll(*it); //hack
 
783
                dirlist.append(*it);
 
784
            }
 
785
            else {
 
786
                dirlist.removeAll(relativePath + '/' + *it); //hack
 
787
                dirlist.append(relativePath + '/' + *it);
 
788
            }
 
789
        }
 
790
    }
 
791
    return dirlist;
 
792
}
 
793
 
 
794
Qt::DropActions TreeView::supportedDropActions() const
 
795
{
 
796
    return Qt::CopyAction | Qt::MoveAction;
 
797
}
 
798
 
 
799
QStringList TreeView::mimeTypes() const
 
800
{
 
801
    return m_dropMimeTypes;
 
802
}
 
803
 
 
804
void TreeView::startDrag(Qt::DropActions supportedActions)
 
805
{
 
806
    QList<QTreeWidgetItem *> items;
 
807
    items << selectedItem();
 
808
    QMimeData *data = mimeData(items);
 
809
    if (!data) {
 
810
        return;
 
811
    }
 
812
 
 
813
    QDrag *drag = new QDrag(this);
 
814
    int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small);
 
815
    drag->setPixmap(selectedItem()->icon(0).pixmap(iconSize, iconSize));
 
816
    drag->setMimeData(data);
 
817
    drag->exec(supportedActions, Qt::MoveAction);
 
818
}
 
819
 
 
820
QMimeData *TreeView::mimeData(const QList<QTreeWidgetItem *> items) const
 
821
{
 
822
    if (items.isEmpty()) {
 
823
        return 0;
 
824
    }
 
825
 
 
826
    return new MenuItemMimeData(dynamic_cast<TreeItem *>(items.first()));
 
827
}
 
828
 
 
829
static QString createDesktopFile(const QString &file, QString *menuId, QStringList *excludeList)
 
830
{
 
831
   QString base = file.mid(file.lastIndexOf('/')+1);
 
832
   base = base.left(base.lastIndexOf('.'));
 
833
 
 
834
   QRegExp r("(.*)(?=-\\d+)");
 
835
   base = (r.indexIn(base) > -1) ? r.cap(1) : base;
 
836
 
 
837
   QString result = KService::newServicePath(true, base, menuId, excludeList);
 
838
   excludeList->append(*menuId);
 
839
   // Todo for Undo-support: Undo menuId allocation:
 
840
 
 
841
   return result;
 
842
}
 
843
 
 
844
static KDesktopFile *copyDesktopFile(MenuEntryInfo *entryInfo, QString *menuId, QStringList *excludeList)
 
845
{
 
846
   QString result = createDesktopFile(entryInfo->file(), menuId, excludeList);
 
847
   KDesktopFile *df = entryInfo->desktopFile()->copyTo(result);
 
848
   df->desktopGroup().deleteEntry("Categories"); // Don't set any categories!
 
849
 
 
850
   return df;
 
851
}
 
852
 
 
853
static QString createDirectoryFile(const QString &file, QStringList *excludeList)
 
854
{
 
855
   QString base = file.mid(file.lastIndexOf('/')+1);
 
856
   base = base.left(base.lastIndexOf('.'));
 
857
 
 
858
   QString result;
 
859
   int i = 1;
 
860
   while(true)
 
861
   {
 
862
      if (i == 1)
 
863
         result = base + ".directory";
 
864
      else
 
865
         result = base + QString("-%1.directory").arg(i);
 
866
 
 
867
      if (!excludeList->contains(result))
 
868
      {
 
869
         if (KStandardDirs::locate("xdgdata-dirs", result).isEmpty())
 
870
            break;
 
871
      }
 
872
      i++;
 
873
   }
 
874
   excludeList->append(result);
 
875
   result = KStandardDirs::locateLocal("xdgdata-dirs", result);
 
876
   return result;
 
877
}
 
878
 
 
879
 
 
880
bool TreeView::dropMimeData(QTreeWidgetItem *item, int index, const QMimeData *data, Qt::DropAction action)
 
881
{
 
882
   // get destination folder
 
883
    TreeItem *titem = item ? dynamic_cast<TreeItem*>(item) : 0;
 
884
    if (item && !titem) {
 
885
        return false;
 
886
    }
 
887
 
 
888
    TreeItem *parentItem = 0;
 
889
    QTreeWidgetItem *after = titem;
 
890
    // find the parent item and which item the dropped item should go after
 
891
    if (titem) {
 
892
        if (titem->isDirectory()) {
 
893
            parentItem = titem;
 
894
            after = titem->child(index);
 
895
            if (!after) {
 
896
                after = titem->child(titem->childCount() - 1);
 
897
            }
 
898
        } else {
 
899
            parentItem = dynamic_cast<TreeItem *>(titem->parent());
 
900
            if (titem->parent() && !parentItem) {
 
901
                return false;
 
902
            }
 
903
        }
 
904
    } else if (index > 0) {
 
905
        after = topLevelItem(index);
 
906
        if (!after) {
 
907
            after = topLevelItem(topLevelItemCount() - 1);
 
908
        }
 
909
    }
 
910
 
 
911
    QString folder = parentItem ? parentItem->directory() : "/";
 
912
    MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
 
913
    kDebug() << "think we're dropping on" << (parentItem ? parentItem->text(0) : "Top Level") <<  index;
 
914
 
 
915
    if (!data->hasFormat(s_internalMimeType)) {
 
916
        // External drop
 
917
        if (!KUrl::List::canDecode(data)) {
 
918
            return false;
 
919
        }
 
920
 
 
921
        KUrl::List urls = KUrl::List::fromMimeData(data);;
 
922
        if (urls.isEmpty() || !urls[0].isLocalFile()) {
 
923
            return false;
 
924
        }
 
925
 
 
926
        //FIXME: this should really support multiple DnD
 
927
        QString path = urls[0].path();
 
928
        if (!path.endsWith(QLatin1String(".desktop"))) {
 
929
            return false;
 
930
        }
 
931
 
 
932
        QString menuId;
 
933
        QString result = createDesktopFile(path, &menuId, &m_newMenuIds);
 
934
        KDesktopFile orig_df(path);
 
935
        KDesktopFile *df = orig_df.copyTo(result);
 
936
        df->desktopGroup().deleteEntry("Categories"); // Don't set any categories!
 
937
 
 
938
        KService::Ptr s(new KService(df));
 
939
        s->setMenuId(menuId);
 
940
 
 
941
        MenuEntryInfo *entryInfo = new MenuEntryInfo(s, df);
 
942
 
 
943
        QString oldCaption = entryInfo->caption;
 
944
        QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption, oldCaption);
 
945
        entryInfo->setCaption(newCaption);
 
946
 
 
947
        // Add file to menu
 
948
        // m_menuFile->addEntry(folder, menuId);
 
949
        m_menuFile->pushAction(MenuFile::ADD_ENTRY, folder, menuId);
 
950
 
 
951
        // create the TreeItem
 
952
        if (parentItem) {
 
953
            parentItem->setExpanded(true);
 
954
        }
 
955
 
 
956
        // update fileInfo data
 
957
        parentFolderInfo->add(entryInfo);
 
958
 
 
959
        TreeItem *newItem = createTreeItem(parentItem, after, entryInfo, true);
 
960
        setCurrentItem(newItem);
 
961
 
 
962
        setLayoutDirty(parentItem);
 
963
        return true;
 
964
    }
 
965
 
 
966
    QVariant p(data->data(s_internalMimeType));
 
967
    const MenuItemMimeData *itemData = dynamic_cast<const MenuItemMimeData *>(data);
 
968
    if (!itemData) {
 
969
        return false;
 
970
    }
 
971
 
 
972
    TreeItem *dragItem = itemData->item();
 
973
    if (!dragItem || dragItem == after) {
 
974
        return false; // Nothing to do
 
975
    }
 
976
 
 
977
    //kDebug() << "an internal drag of" << dragItem->text(0) << (parentItem ? parentItem->text(0) : "Top level");
 
978
    if (dragItem->isDirectory()) {
 
979
        MenuFolderInfo *folderInfo = dragItem->folderInfo();
 
980
        if (action == Qt::CopyAction) {
 
981
            // FIXME:
 
982
            // * Create new .directory file
 
983
        } else {
 
984
            TreeItem *tmpItem = static_cast<TreeItem*>(parentItem);
 
985
            while (tmpItem) {
 
986
                if (tmpItem == dragItem) {
 
987
                    return false;
 
988
                }
 
989
 
 
990
                tmpItem = static_cast<TreeItem*>(tmpItem->parent());
 
991
            }
 
992
 
 
993
            // Remove MenuFolderInfo
 
994
            TreeItem *oldParentItem = static_cast<TreeItem*>(dragItem->parent());
 
995
            MenuFolderInfo *oldParentFolderInfo = oldParentItem ? oldParentItem->folderInfo() : m_rootFolder;
 
996
            oldParentFolderInfo->take(folderInfo);
 
997
 
 
998
            // Move menu
 
999
            QString oldFolder = folderInfo->fullId;
 
1000
            QString folderName = folderInfo->id;
 
1001
            QString newFolder = m_menuFile->uniqueMenuName(folder, folderName, parentFolderInfo->existingMenuIds());
 
1002
            folderInfo->id = newFolder;
 
1003
 
 
1004
            // Add file to menu
 
1005
            //m_menuFile->moveMenu(oldFolder, folder + newFolder);
 
1006
            kDebug() << "moving" << dragItem->text(0) << "to" << folder + newFolder;
 
1007
            m_menuFile->pushAction(MenuFile::MOVE_MENU, oldFolder, folder + newFolder);
 
1008
 
 
1009
            // Make sure caption is unique
 
1010
            QString newCaption = parentFolderInfo->uniqueMenuCaption(folderInfo->caption);
 
1011
            if (newCaption != folderInfo->caption) {
 
1012
                folderInfo->setCaption(newCaption);
 
1013
            }
 
1014
 
 
1015
            // create the TreeItem
 
1016
            if (parentItem) {
 
1017
                parentItem->setExpanded(true);
 
1018
            }
 
1019
 
 
1020
            // update fileInfo data
 
1021
            folderInfo->updateFullId(parentFolderInfo->fullId);
 
1022
            folderInfo->setInUse(true);
 
1023
            parentFolderInfo->add(folderInfo);
 
1024
 
 
1025
            if (parentItem != oldParentItem) {
 
1026
                if (oldParentItem) {
 
1027
                    oldParentItem->takeChild(oldParentItem->indexOfChild(dragItem));
 
1028
                } else {
 
1029
                    takeTopLevelItem(indexOfTopLevelItem(dragItem));
 
1030
                }
 
1031
            }
 
1032
 
 
1033
            if (parentItem) {
 
1034
                parentItem->insertChild(after ? parentItem->indexOfChild(after) + 1 : parentItem->childCount(), dragItem);
 
1035
            } else {
 
1036
                insertTopLevelItem(after ? indexOfTopLevelItem(after) : topLevelItemCount(), dragItem);
 
1037
            }
 
1038
 
 
1039
            dragItem->setName(folderInfo->caption);
 
1040
            dragItem->setDirectoryPath(folderInfo->fullId);
 
1041
            setCurrentItem(dragItem);
 
1042
        }
 
1043
    } else if (dragItem->isEntry()) {
 
1044
        MenuEntryInfo *entryInfo = dragItem->entryInfo();
 
1045
        QString menuId = entryInfo->menuId();
 
1046
 
 
1047
        if (action == Qt::CopyAction) {
 
1048
            // Need to copy file and then add it
 
1049
            KDesktopFile *df = copyDesktopFile(entryInfo, &menuId, &m_newMenuIds); // Duplicate
 
1050
            //UNDO-ACTION: NEW_MENU_ID (menuId)
 
1051
 
 
1052
            KService::Ptr s(new KService(df));
 
1053
            s->setMenuId(menuId);
 
1054
 
 
1055
            entryInfo = new MenuEntryInfo(s, df);
 
1056
 
 
1057
            QString oldCaption = entryInfo->caption;
 
1058
            QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption, oldCaption);
 
1059
            entryInfo->setCaption(newCaption);
 
1060
        } else {
 
1061
            del(dragItem, false);
 
1062
            QString oldCaption = entryInfo->caption;
 
1063
            QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption);
 
1064
            entryInfo->setCaption(newCaption);
 
1065
            entryInfo->setInUse(true);
 
1066
        }
 
1067
 
 
1068
        // Add file to menu
 
1069
        // m_menuFile->addEntry(folder, menuId);
 
1070
        m_menuFile->pushAction(MenuFile::ADD_ENTRY, folder, menuId);
 
1071
 
 
1072
        // create the TreeItem
 
1073
        if (parentItem) {
 
1074
            parentItem->setExpanded(true);
 
1075
        }
 
1076
 
 
1077
        // update fileInfo data
 
1078
        parentFolderInfo->add(entryInfo);
 
1079
 
 
1080
        TreeItem *newItem = createTreeItem(parentItem, after, entryInfo);
 
1081
        setCurrentItem(newItem);
 
1082
    } else  {
 
1083
        // copying a separator
 
1084
        if (action != Qt::CopyAction) {
 
1085
            del(dragItem, false);
 
1086
        }
 
1087
 
 
1088
        TreeItem *newItem = createTreeItem(parentItem, after, m_separator);
 
1089
        setCurrentItem(newItem);
 
1090
    }
 
1091
 
 
1092
    kDebug() << "setting the layout to be dirty at" << parentItem;
 
1093
    setLayoutDirty(parentItem);
 
1094
    return true;
 
1095
}
 
1096
 
 
1097
 
 
1098
QTreeWidgetItem *TreeView::selectedItem()
 
1099
{
 
1100
    QList<QTreeWidgetItem *> selection = selectedItems();
 
1101
 
 
1102
    if (selection.isEmpty()) {
 
1103
        return 0;
 
1104
    }
 
1105
 
 
1106
    return selection.first();
 
1107
}
 
1108
 
 
1109
void TreeView::contextMenuEvent(QContextMenuEvent *event)
 
1110
{
 
1111
    if (m_popupMenu && itemAt(event->pos())) {
 
1112
        m_popupMenu->exec(event->globalPos());
 
1113
    }
 
1114
}
 
1115
 
 
1116
void TreeView::dropEvent(QDropEvent *event)
 
1117
{
 
1118
    // this prevents QTreeWidget from interfering with our moves
 
1119
    QTreeView::dropEvent(event);
 
1120
}
 
1121
 
 
1122
void TreeView::newsubmenu()
 
1123
{
 
1124
   TreeItem *parentItem = 0;
 
1125
   TreeItem *item = (TreeItem*)selectedItem();
 
1126
 
 
1127
   bool ok;
 
1128
   QString caption = KInputDialog::getText( i18n( "New Submenu" ),
 
1129
        i18n( "Submenu name:" ), QString(), &ok, this );
 
1130
 
 
1131
   if (!ok) return;
 
1132
 
 
1133
   QString file = caption;
 
1134
   file.replace('/', '-');
 
1135
 
 
1136
   file = createDirectoryFile(file, &m_newDirectoryList); // Create
 
1137
 
 
1138
   // get destination folder
 
1139
   QString folder;
 
1140
 
 
1141
   if(!item)
 
1142
   {
 
1143
      parentItem = 0;
 
1144
      folder.clear();
 
1145
   }
 
1146
   else if(item->isDirectory())
 
1147
   {
 
1148
      parentItem = item;
 
1149
      item = 0;
 
1150
      folder = parentItem->directory();
 
1151
   }
 
1152
   else
 
1153
   {
 
1154
      parentItem = static_cast<TreeItem*>(item->parent());
 
1155
      folder = parentItem ? parentItem->directory() : QString();
 
1156
   }
 
1157
 
 
1158
   MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
 
1159
   MenuFolderInfo *folderInfo = new MenuFolderInfo();
 
1160
   folderInfo->caption = parentFolderInfo->uniqueMenuCaption(caption);
 
1161
   folderInfo->id = m_menuFile->uniqueMenuName(folder, caption, parentFolderInfo->existingMenuIds());
 
1162
   folderInfo->directoryFile = file;
 
1163
   folderInfo->icon = "package";
 
1164
   folderInfo->hidden = false;
 
1165
   folderInfo->setDirty();
 
1166
 
 
1167
   KDesktopFile *df = new KDesktopFile(file);
 
1168
   KConfigGroup desktopGroup = df->desktopGroup();
 
1169
   desktopGroup.writeEntry("Name", folderInfo->caption);
 
1170
   desktopGroup.writeEntry("Icon", folderInfo->icon);
 
1171
   df->sync();
 
1172
   delete df;
 
1173
   // Add file to menu
 
1174
   // m_menuFile->addMenu(folder + folderInfo->id, file);
 
1175
   m_menuFile->pushAction(MenuFile::ADD_MENU, folder + folderInfo->id, file);
 
1176
 
 
1177
   folderInfo->fullId = parentFolderInfo->fullId + folderInfo->id;
 
1178
 
 
1179
   // create the TreeItem
 
1180
   if (parentItem)
 
1181
      parentItem->setExpanded(true);
 
1182
 
 
1183
   // update fileInfo data
 
1184
   parentFolderInfo->add(folderInfo);
 
1185
 
 
1186
   TreeItem *newItem = createTreeItem(parentItem, item, folderInfo, true);
 
1187
 
 
1188
   setCurrentItem(newItem);
 
1189
   setLayoutDirty(parentItem);
 
1190
}
 
1191
 
 
1192
void TreeView::newitem()
 
1193
{
 
1194
   TreeItem *parentItem = 0;
 
1195
   TreeItem *item = (TreeItem*)selectedItem();
 
1196
 
 
1197
   bool ok;
 
1198
   QString caption = KInputDialog::getText( i18n( "New Item" ),
 
1199
        i18n( "Item name:" ), QString(), &ok, this );
 
1200
 
 
1201
   if (!ok) return;
 
1202
 
 
1203
   QString menuId;
 
1204
   QString file = caption;
 
1205
   file.replace('/', '-');
 
1206
 
 
1207
   file = createDesktopFile(file, &menuId, &m_newMenuIds); // Create
 
1208
 
 
1209
   KDesktopFile *df = new KDesktopFile(file);
 
1210
   KConfigGroup desktopGroup = df->desktopGroup();
 
1211
   desktopGroup.writeEntry("Name", caption);
 
1212
   desktopGroup.writeEntry("Type", "Application");
 
1213
 
 
1214
   // get destination folder
 
1215
   QString folder;
 
1216
 
 
1217
   if(!item)
 
1218
   {
 
1219
      parentItem = 0;
 
1220
      folder.clear();
 
1221
   }
 
1222
   else if(item->isDirectory())
 
1223
   {
 
1224
      parentItem = item;
 
1225
      item = 0;
 
1226
      folder = parentItem->directory();
 
1227
   }
 
1228
   else
 
1229
   {
 
1230
      parentItem = static_cast<TreeItem*>(item->parent());
 
1231
      folder = parentItem ? parentItem->directory() : QString();
 
1232
   }
 
1233
 
 
1234
   MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
 
1235
 
 
1236
   // Add file to menu
 
1237
   // m_menuFile->addEntry(folder, menuId);
 
1238
   m_menuFile->pushAction(MenuFile::ADD_ENTRY, folder, menuId);
 
1239
 
 
1240
   KService::Ptr s(new KService(df));
 
1241
   s->setMenuId(menuId);
 
1242
 
 
1243
   MenuEntryInfo *entryInfo = new MenuEntryInfo(s, df);
 
1244
 
 
1245
   // create the TreeItem
 
1246
   if(parentItem)
 
1247
      parentItem->setExpanded(true);
 
1248
 
 
1249
   // update fileInfo data
 
1250
   parentFolderInfo->add(entryInfo);
 
1251
 
 
1252
   TreeItem *newItem = createTreeItem(parentItem, item, entryInfo, true);
 
1253
 
 
1254
   setCurrentItem(newItem);
 
1255
   setLayoutDirty(parentItem);
 
1256
}
 
1257
 
 
1258
void TreeView::newsep()
 
1259
{
 
1260
   TreeItem *parentItem = 0;
 
1261
   TreeItem *item = (TreeItem*)selectedItem();
 
1262
 
 
1263
   if(!item)
 
1264
   {
 
1265
      parentItem = 0;
 
1266
   }
 
1267
   else if(item->isDirectory())
 
1268
   {
 
1269
      parentItem = item;
 
1270
      item = 0;
 
1271
   }
 
1272
   else
 
1273
   {
 
1274
      parentItem = static_cast<TreeItem*>(item->parent());
 
1275
   }
 
1276
 
 
1277
   // create the TreeItem
 
1278
   if(parentItem)
 
1279
      parentItem->setExpanded(true);
 
1280
 
 
1281
   TreeItem *newItem = createTreeItem(parentItem, item, m_separator, true);
 
1282
 
 
1283
   setCurrentItem(newItem);
 
1284
   setLayoutDirty(parentItem);
 
1285
}
 
1286
 
 
1287
void TreeView::cut()
 
1288
{
 
1289
    copy( true );
 
1290
 
 
1291
    // Select new current item
 
1292
    // TODO: is this completely redundant?
 
1293
    setCurrentItem(currentItem());
 
1294
}
 
1295
 
 
1296
void TreeView::copy()
 
1297
{
 
1298
    copy( false );
 
1299
}
 
1300
 
 
1301
void TreeView::copy( bool cutting )
 
1302
{
 
1303
    TreeItem *item = (TreeItem*)selectedItem();
 
1304
 
 
1305
    // nil selected? -> nil to copy
 
1306
    if (item == 0) return;
 
1307
 
 
1308
    if (cutting)
 
1309
       setLayoutDirty((TreeItem*)item->parent());
 
1310
 
 
1311
    // clean up old stuff
 
1312
    cleanupClipboard();
 
1313
 
 
1314
    // is item a folder or a file?
 
1315
    if(item->isDirectory())
 
1316
    {
 
1317
        QString folder = item->directory();
 
1318
        if (cutting)
 
1319
        {
 
1320
           // Place in clipboard
 
1321
           m_clipboard = MOVE_FOLDER;
 
1322
           m_clipboardFolderInfo = item->folderInfo();
 
1323
 
 
1324
           del(item, false);
 
1325
        }
 
1326
        else
 
1327
        {
 
1328
           // Place in clipboard
 
1329
           m_clipboard = COPY_FOLDER;
 
1330
           m_clipboardFolderInfo = item->folderInfo();
 
1331
        }
 
1332
    }
 
1333
    else if (item->isEntry())
 
1334
    {
 
1335
        if (cutting)
 
1336
        {
 
1337
           // Place in clipboard
 
1338
           m_clipboard = MOVE_FILE;
 
1339
           m_clipboardEntryInfo = item->entryInfo();
 
1340
 
 
1341
           del(item, false);
 
1342
        }
 
1343
        else
 
1344
        {
 
1345
           // Place in clipboard
 
1346
           m_clipboard = COPY_FILE;
 
1347
           m_clipboardEntryInfo = item->entryInfo();
 
1348
        }
 
1349
    }
 
1350
    else
 
1351
    {
 
1352
        // Place in clipboard
 
1353
        m_clipboard = COPY_SEPARATOR;
 
1354
        if (cutting)
 
1355
           del(item, false);
 
1356
    }
 
1357
 
 
1358
    m_ac->action(PASTE_ACTION_NAME)->setEnabled(true);
 
1359
}
 
1360
 
 
1361
 
 
1362
void TreeView::paste()
 
1363
{
 
1364
   TreeItem *parentItem = 0;
 
1365
   TreeItem *item = (TreeItem*)selectedItem();
 
1366
 
 
1367
   // nil selected? -> nil to paste to
 
1368
   if (item == 0) return;
 
1369
 
 
1370
   // is there content in the clipboard?
 
1371
   if (!m_clipboard) return;
 
1372
 
 
1373
  // get destination folder
 
1374
   QString folder;
 
1375
 
 
1376
   if(item->isDirectory())
 
1377
   {
 
1378
      parentItem = item;
 
1379
      item = 0;
 
1380
      folder = parentItem->directory();
 
1381
   }
 
1382
   else
 
1383
   {
 
1384
      parentItem = static_cast<TreeItem*>(item->parent());
 
1385
      folder = parentItem ? parentItem->directory() : QString();
 
1386
   }
 
1387
 
 
1388
   MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
 
1389
   int command = m_clipboard;
 
1390
   if ((command == COPY_FOLDER) || (command == MOVE_FOLDER))
 
1391
   {
 
1392
      MenuFolderInfo *folderInfo = m_clipboardFolderInfo;
 
1393
      if (command == COPY_FOLDER)
 
1394
      {
 
1395
         // Ugh.. this is hard :)
 
1396
         // * Create new .directory file
 
1397
         // Add
 
1398
      }
 
1399
      else if (command == MOVE_FOLDER)
 
1400
      {
 
1401
         // Move menu
 
1402
         QString oldFolder = folderInfo->fullId;
 
1403
         QString folderName = folderInfo->id;
 
1404
         QString newFolder = m_menuFile->uniqueMenuName(folder, folderName, parentFolderInfo->existingMenuIds());
 
1405
         folderInfo->id = newFolder;
 
1406
 
 
1407
         // Add file to menu
 
1408
         // m_menuFile->moveMenu(oldFolder, folder + newFolder);
 
1409
         m_menuFile->pushAction(MenuFile::MOVE_MENU, oldFolder, folder + newFolder);
 
1410
 
 
1411
         // Make sure caption is unique
 
1412
         QString newCaption = parentFolderInfo->uniqueMenuCaption(folderInfo->caption);
 
1413
         if (newCaption != folderInfo->caption)
 
1414
         {
 
1415
            folderInfo->setCaption(newCaption);
 
1416
         }
 
1417
         // create the TreeItem
 
1418
         if(parentItem)
 
1419
             parentItem->setExpanded(true);
 
1420
 
 
1421
         // update fileInfo data
 
1422
         folderInfo->fullId = parentFolderInfo->fullId + folderInfo->id;
 
1423
         folderInfo->setInUse(true);
 
1424
         parentFolderInfo->add(folderInfo);
 
1425
 
 
1426
         TreeItem *newItem = createTreeItem(parentItem, item, folderInfo);
 
1427
 
 
1428
         setCurrentItem(newItem);
 
1429
      }
 
1430
 
 
1431
      m_clipboard = COPY_FOLDER; // Next one copies.
 
1432
   }
 
1433
   else if ((command == COPY_FILE) || (command == MOVE_FILE))
 
1434
   {
 
1435
      MenuEntryInfo *entryInfo = m_clipboardEntryInfo;
 
1436
      QString menuId;
 
1437
 
 
1438
      if (command == COPY_FILE)
 
1439
      {
 
1440
         // Need to copy file and then add it
 
1441
         KDesktopFile *df = copyDesktopFile(entryInfo, &menuId, &m_newMenuIds); // Duplicate
 
1442
 
 
1443
         KService::Ptr s(new KService(df));
 
1444
         s->setMenuId(menuId);
 
1445
         entryInfo = new MenuEntryInfo(s, df);
 
1446
 
 
1447
         QString oldCaption = entryInfo->caption;
 
1448
         QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption, oldCaption);
 
1449
         entryInfo->setCaption(newCaption);
 
1450
      }
 
1451
      else if (command == MOVE_FILE)
 
1452
      {
 
1453
         menuId = entryInfo->menuId();
 
1454
         m_clipboard = COPY_FILE; // Next one copies.
 
1455
 
 
1456
         QString oldCaption = entryInfo->caption;
 
1457
         QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption);
 
1458
         entryInfo->setCaption(newCaption);
 
1459
         entryInfo->setInUse(true);
 
1460
      }
 
1461
      // Add file to menu
 
1462
      // m_menuFile->addEntry(folder, menuId);
 
1463
      m_menuFile->pushAction(MenuFile::ADD_ENTRY, folder, menuId);
 
1464
 
 
1465
      // create the TreeItem
 
1466
      if(parentItem)
 
1467
         parentItem->setExpanded(true);
 
1468
 
 
1469
      // update fileInfo data
 
1470
      parentFolderInfo->add(entryInfo);
 
1471
 
 
1472
      TreeItem *newItem = createTreeItem(parentItem, item, entryInfo, true);
 
1473
 
 
1474
      setCurrentItem(newItem);
 
1475
   }
 
1476
   else
 
1477
   {
 
1478
      // create separator
 
1479
      if(parentItem)
 
1480
         parentItem->setExpanded(true);
 
1481
 
 
1482
      TreeItem *newItem = createTreeItem(parentItem, item, m_separator, true);
 
1483
 
 
1484
      setCurrentItem(newItem);
 
1485
   }
 
1486
   setLayoutDirty(parentItem);
 
1487
}
 
1488
 
 
1489
/**
 
1490
 * This slot is called from the signal mapper to sort children contained in an item.
 
1491
 * This item is determinated according to the chosen sort type.
 
1492
 *
 
1493
 * @brief Determine which item is to sort, and do it.
 
1494
 * @param sortCmd Sort type.
 
1495
 */
 
1496
void TreeView::sort(const int sortCmd)
 
1497
{
 
1498
    // determine the chosen sort type and the selected item
 
1499
    SortType sortType = (SortType) sortCmd;
 
1500
    TreeItem *itemToSort;
 
1501
    if (sortType == SortByName || sortType == SortByDescription) {
 
1502
        itemToSort = static_cast<TreeItem*>(selectedItem());
 
1503
    } else if (sortType == SortAllByDescription) {
 
1504
        sortType = SortByDescription;
 
1505
        itemToSort = static_cast<TreeItem*>(invisibleRootItem());
 
1506
    } else /* if (sortType == SortAllByName) */ {
 
1507
        sortType = SortByName;
 
1508
        itemToSort = static_cast<TreeItem*>(invisibleRootItem());
 
1509
    }
 
1510
 
 
1511
    // proceed to the sorting
 
1512
    sortItem(itemToSort, sortType);
 
1513
}
 
1514
 
 
1515
/**
 
1516
 * Sort children of the given item, according to the sort type.
 
1517
 * The sorting is done on children groups, splited by separator items.
 
1518
 *
 
1519
 * @brief Sort item children.
 
1520
 * @param item Item to sort.
 
1521
 * @param sortType Sort type.
 
1522
 */
 
1523
void TreeView::sortItem(TreeItem *item, const SortType& sortType)
 
1524
{
 
1525
    // sort the selected item only if contains children
 
1526
    if ( (!item->isDirectory()) || (item->childCount() == 0) ) {
 
1527
        return;
 
1528
    }
 
1529
 
 
1530
    // remove contained children
 
1531
    QList<QTreeWidgetItem*> children = item->takeChildren();
 
1532
 
 
1533
    // sort children groups, splited by separator items
 
1534
    QList<QTreeWidgetItem*>::iterator startIt = children.begin();
 
1535
    QList<QTreeWidgetItem*>::iterator currentIt = children.begin();
 
1536
    while (currentIt != children.end()) {
 
1537
        TreeItem *child = static_cast<TreeItem*>(*currentIt);
 
1538
        // if it's a separator, sort previous items and continue on following items
 
1539
        if (child->isSeparator() && startIt != currentIt) {
 
1540
            sortItemChildren(startIt, currentIt, sortType);
 
1541
            startIt = currentIt + 1;
 
1542
        }
 
1543
        ++currentIt;
 
1544
    }
 
1545
    sortItemChildren(startIt, currentIt, sortType);
 
1546
 
 
1547
    // insert sorted children in the tree
 
1548
    item->addChildren(children);
 
1549
    foreach (QTreeWidgetItem *child, children) {
 
1550
        // recreate item widget for separators
 
1551
        TreeItem *treeItem = static_cast<TreeItem*>(child);
 
1552
        if (treeItem->isSeparator()) {
 
1553
            setItemWidget(treeItem, 0, new SeparatorWidget);
 
1554
        }
 
1555
 
 
1556
        // try to sort sub-children
 
1557
        sortItem(static_cast<TreeItem*>(child), sortType);
 
1558
    }
 
1559
 
 
1560
    // flag current item as dirty
 
1561
    TreeItem *itemToFlagAsDirty = item;
 
1562
    // if tree root item, set the entire layout as dirty
 
1563
    if (item == invisibleRootItem()) {
 
1564
        itemToFlagAsDirty = 0;
 
1565
    }
 
1566
    setLayoutDirty(itemToFlagAsDirty);
 
1567
}
 
1568
 
 
1569
/**
 
1570
 * Sort a children range defined with two list iterators, according to the sort type.
 
1571
 *
 
1572
 * @brief Sort a children range.
 
1573
 * @param begin First child iterator.
 
1574
 * @param end Last child iterator (exclusive, pointed child won't be affected).
 
1575
 * @param sortType Sort type.
 
1576
 */
 
1577
void TreeView::sortItemChildren(const QList<QTreeWidgetItem*>::iterator& begin, const QList<QTreeWidgetItem*>::iterator& end, const SortType& sortType)
 
1578
{
 
1579
    // sort by name
 
1580
    if (sortType == SortByName) {
 
1581
        qSort(begin, end, TreeItem::itemNameLessThan);
 
1582
    }
 
1583
    // sort by description
 
1584
    else if (sortType == SortByDescription) {
 
1585
        qSort(begin, end, TreeItem::itemDescriptionLessThan);
 
1586
    }
 
1587
}
 
1588
 
 
1589
/**
 
1590
 * @brief Move up the selected item.
 
1591
 */
 
1592
void TreeView::moveUpItem() {
 
1593
    moveUpOrDownItem(true);
 
1594
}
 
1595
 
 
1596
/**
 
1597
 * @brief Move down the selected item.
 
1598
 */
 
1599
void TreeView::moveDownItem() {
 
1600
    moveUpOrDownItem(false);
 
1601
}
 
1602
 
 
1603
/**
 
1604
 * Move the selected item on desired direction (up or down).
 
1605
 *
 
1606
 * @brief Move up/down the selected item.
 
1607
 * @param isMovingUpAction True to move up, false to move down.
 
1608
 */
 
1609
void TreeView::moveUpOrDownItem(bool isMovingUpAction)
 
1610
{
 
1611
    // get the selected item and its parent
 
1612
    TreeItem *sourceItem = static_cast<TreeItem*>(selectedItem());
 
1613
    if (!sourceItem)
 
1614
       return;
 
1615
    TreeItem *parentItem = getParentItem(sourceItem);
 
1616
 
 
1617
    // get selected item index
 
1618
    int sourceItemIndex = parentItem->indexOfChild(sourceItem);
 
1619
 
 
1620
    // find the second item to swap
 
1621
    TreeItem *destItem = 0;
 
1622
    int destIndex;
 
1623
    if (isMovingUpAction) {
 
1624
        destIndex = sourceItemIndex - 1;
 
1625
        destItem = static_cast<TreeItem*>(parentItem->child(destIndex));
 
1626
    }
 
1627
    else {
 
1628
        destIndex = sourceItemIndex + 1;
 
1629
        destItem = static_cast<TreeItem*>(parentItem->child(destIndex));
 
1630
    }
 
1631
 
 
1632
    // swap items
 
1633
    parentItem->removeChild(sourceItem);
 
1634
    parentItem->insertChild(destIndex, sourceItem);
 
1635
 
 
1636
    // recreate item widget for separators
 
1637
    if (sourceItem->isSeparator()) {
 
1638
        setItemWidget(sourceItem, 0, new SeparatorWidget);
 
1639
    }
 
1640
    if (destItem->isSeparator()) {
 
1641
        setItemWidget(destItem, 0, new SeparatorWidget);
 
1642
    }
 
1643
 
 
1644
    // set the focus on the source item
 
1645
    setCurrentItem(sourceItem);
 
1646
 
 
1647
    // flag parent item as dirty (if the parent is the root item, set the entire layout as dirty)
 
1648
    if (parentItem == invisibleRootItem()) {
 
1649
        parentItem = 0;
 
1650
    }
 
1651
    setLayoutDirty(parentItem);
 
1652
}
 
1653
 
 
1654
/**
 
1655
 * For a given item, return its parent. For top items, return the invisible root item.
 
1656
 *
 
1657
 * @brief Get the parent item.
 
1658
 * @param item Item.
 
1659
 * @return Parent item.
 
1660
 */
 
1661
TreeItem* TreeView::getParentItem(QTreeWidgetItem *item) const
 
1662
{
 
1663
    QTreeWidgetItem *parentItem = item->parent();
 
1664
    if (!parentItem) {
 
1665
        parentItem = invisibleRootItem();
 
1666
    }
 
1667
    return static_cast<TreeItem*>(parentItem);
 
1668
}
 
1669
 
 
1670
void TreeView::del()
 
1671
{
 
1672
    TreeItem *item = (TreeItem*)selectedItem();
 
1673
 
 
1674
    // nil selected? -> nil to delete
 
1675
    if (item == 0) return;
 
1676
 
 
1677
    del(item, true);
 
1678
 
 
1679
    // Select new current item
 
1680
    // TODO: is this completely redundant?
 
1681
    setCurrentItem(currentItem());
 
1682
}
 
1683
 
 
1684
void TreeView::del(TreeItem *item, bool deleteInfo)
 
1685
{
 
1686
    TreeItem *parentItem = static_cast<TreeItem*>(item->parent());
 
1687
    // is file a .directory or a .desktop file
 
1688
    if(item->isDirectory())
 
1689
    {
 
1690
        if ( KMessageBox::warningYesNo(this, i18n("All submenus of '%1' will be removed. Do you want to continue?", item->name() ) ) == KMessageBox::No )
 
1691
             return;
 
1692
 
 
1693
        MenuFolderInfo *folderInfo = item->folderInfo();
 
1694
 
 
1695
        // Remove MenuFolderInfo
 
1696
        MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
 
1697
        parentFolderInfo->take(folderInfo);
 
1698
        folderInfo->setInUse(false);
 
1699
 
 
1700
        if (m_clipboard == COPY_FOLDER && (m_clipboardFolderInfo == folderInfo))
 
1701
        {
 
1702
           // Copy + Del == Cut
 
1703
           m_clipboard = MOVE_FOLDER; // Clipboard now owns folderInfo
 
1704
 
 
1705
        }
 
1706
        else
 
1707
        {
 
1708
           if (folderInfo->takeRecursive(m_clipboardFolderInfo))
 
1709
              m_clipboard = MOVE_FOLDER; // Clipboard now owns m_clipboardFolderInfo
 
1710
 
 
1711
           if (deleteInfo)
 
1712
              delete folderInfo; // Delete folderInfo
 
1713
        }
 
1714
 
 
1715
        // Remove from menu
 
1716
        // m_menuFile->removeMenu(item->directory());
 
1717
        m_menuFile->pushAction(MenuFile::REMOVE_MENU, item->directory(), QString());
 
1718
 
 
1719
        // Remove tree item
 
1720
        delete item;
 
1721
    }
 
1722
    else if (item->isEntry())
 
1723
    {
 
1724
        MenuEntryInfo *entryInfo = item->entryInfo();
 
1725
        QString menuId = entryInfo->menuId();
 
1726
 
 
1727
        // Remove MenuFolderInfo
 
1728
        MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
 
1729
        parentFolderInfo->take(entryInfo);
 
1730
        entryInfo->setInUse(false);
 
1731
 
 
1732
        if (m_clipboard == COPY_FILE && (m_clipboardEntryInfo == entryInfo))
 
1733
        {
 
1734
           // Copy + Del == Cut
 
1735
           m_clipboard = MOVE_FILE; // Clipboard now owns entryInfo
 
1736
        }
 
1737
        else
 
1738
        {
 
1739
           if (deleteInfo)
 
1740
              delete entryInfo; // Delete entryInfo
 
1741
        }
 
1742
 
 
1743
        // Remove from menu
 
1744
        QString folder = parentItem ? parentItem->directory() : QString();
 
1745
        // m_menuFile->removeEntry(folder, menuId);
 
1746
        m_menuFile->pushAction(MenuFile::REMOVE_ENTRY, folder, menuId);
 
1747
 
 
1748
        // Remove tree item
 
1749
        delete item;
 
1750
    }
 
1751
    else
 
1752
    {
 
1753
        // Remove separator
 
1754
        delete item;
 
1755
    }
 
1756
 
 
1757
    setLayoutDirty(parentItem);
 
1758
}
 
1759
 
 
1760
void TreeView::cleanupClipboard() {
 
1761
    if (m_clipboard == MOVE_FOLDER)
 
1762
       delete m_clipboardFolderInfo;
 
1763
    m_clipboardFolderInfo = 0;
 
1764
 
 
1765
    if (m_clipboard == MOVE_FILE)
 
1766
       delete m_clipboardEntryInfo;
 
1767
    m_clipboardEntryInfo = 0;
 
1768
 
 
1769
    m_clipboard = 0;
 
1770
}
 
1771
 
 
1772
static QStringList extractLayout(QTreeWidget *tree, QTreeWidgetItem *parent)
 
1773
{
 
1774
    QStringList layout;
 
1775
    if (!parent && !tree) {
 
1776
        return layout;
 
1777
    }
 
1778
 
 
1779
    bool firstFolder = true;
 
1780
    bool firstEntry = true;
 
1781
    int max = parent ? parent->childCount() : tree->topLevelItemCount();
 
1782
    for (int i = 0; i < max; ++i) {
 
1783
        TreeItem *item = dynamic_cast<TreeItem *>(parent ? parent->child(i) : tree->topLevelItem(i));
 
1784
        if (!item) {
 
1785
            continue;
 
1786
        }
 
1787
 
 
1788
        if (item->isDirectory()) {
 
1789
            if (firstFolder) {
 
1790
                firstFolder = false;
 
1791
                layout << ":M"; // Add new folders here...
 
1792
            }
 
1793
            layout << (item->folderInfo()->id);
 
1794
        } else if (item->isEntry()) {
 
1795
            if (firstEntry) {
 
1796
                firstEntry = false;
 
1797
                layout << ":F"; // Add new entries here...
 
1798
            }
 
1799
            layout << (item->entryInfo()->menuId());
 
1800
        } else {
 
1801
            layout << ":S";
 
1802
        }
 
1803
    }
 
1804
 
 
1805
    return layout;
 
1806
}
 
1807
 
 
1808
void TreeItem::saveLayout(MenuFile *menuFile)
 
1809
{
 
1810
    if (m_layoutDirty) {
 
1811
        QStringList layout = extractLayout(0, this);
 
1812
        menuFile->setLayout(folderInfo()->fullId, layout);
 
1813
        m_layoutDirty = false;
 
1814
    }
 
1815
 
 
1816
    for (int i = 0; i < childCount(); ++i) {
 
1817
        TreeItem *item = dynamic_cast<TreeItem *>(child(i));
 
1818
        if (item) {
 
1819
            item->saveLayout(menuFile);
 
1820
        }
 
1821
    }
 
1822
}
 
1823
 
 
1824
void TreeView::saveLayout()
 
1825
{
 
1826
    if (m_layoutDirty) {
 
1827
       QStringList layout = extractLayout(this, 0);
 
1828
       m_menuFile->setLayout(m_rootFolder->fullId, layout);
 
1829
       m_layoutDirty = false;
 
1830
    }
 
1831
 
 
1832
    for (int i = 0; i < topLevelItemCount(); ++i) {
 
1833
        TreeItem *item = dynamic_cast<TreeItem *>(topLevelItem(i));
 
1834
        if (item) {
 
1835
            item->saveLayout(m_menuFile);
 
1836
        }
 
1837
    }
 
1838
}
 
1839
 
 
1840
bool TreeView::save()
 
1841
{
 
1842
    saveLayout();
 
1843
    m_rootFolder->save(m_menuFile);
 
1844
 
 
1845
    bool success = m_menuFile->performAllActions();
 
1846
 
 
1847
    m_newMenuIds.clear();
 
1848
    m_newDirectoryList.clear();
 
1849
 
 
1850
    if (success)
 
1851
    {
 
1852
       KBuildSycocaProgressDialog::rebuildKSycoca(this);
 
1853
    }
 
1854
    else
 
1855
    {
 
1856
       KMessageBox::sorry(this, "<qt>"+i18n("Menu changes could not be saved because of the following problem:")+"<br><br>"+
 
1857
                                m_menuFile->error()+"</qt>");
 
1858
    }
 
1859
 
 
1860
    sendReloadMenu();
 
1861
 
 
1862
    return success;
 
1863
}
 
1864
 
 
1865
void TreeView::setLayoutDirty(TreeItem *parentItem)
 
1866
{
 
1867
    if (parentItem)
 
1868
       parentItem->setLayoutDirty();
 
1869
    else
 
1870
       m_layoutDirty = true;
 
1871
}
 
1872
 
 
1873
bool TreeView::isLayoutDirty()
 
1874
{
 
1875
   for (int i = 0; i < topLevelItemCount(); ++i) {
 
1876
       TreeItem *item = dynamic_cast<TreeItem *>(topLevelItem(i));
 
1877
       if (!item) {
 
1878
           continue;
 
1879
       }
 
1880
 
 
1881
       if (item->isLayoutDirty()) {
 
1882
           return true;
 
1883
       }
 
1884
   }
 
1885
 
 
1886
   return false;
 
1887
}
 
1888
 
 
1889
bool TreeView::dirty()
 
1890
{
 
1891
    return m_layoutDirty || m_rootFolder->hasDirt() || m_menuFile->dirty() || isLayoutDirty();
 
1892
}
 
1893
 
 
1894
void TreeView::findServiceShortcut(const KShortcut&cut, KService::Ptr &service)
 
1895
{
 
1896
    service = m_rootFolder->findServiceShortcut(cut);
 
1897
}
 
1898
 
 
1899
void TreeView::restoreMenuSystem()
 
1900
{
 
1901
    if ( KMessageBox::warningYesNo( this, i18n( "Do you want to restore the system menu? Warning: This will remove all custom menus." ) )==KMessageBox::No )
 
1902
        return;
 
1903
    QString kmenueditfile = KStandardDirs::locateLocal("xdgconf-menu", "applications-kmenuedit.menu");
 
1904
    if ( QFile::exists( kmenueditfile ) )
 
1905
    {
 
1906
        if ( !QFile::remove( kmenueditfile ) )
 
1907
            qWarning()<<"Could not delete "<<kmenueditfile;
 
1908
    }
 
1909
 
 
1910
    QString xdgdir = KGlobal::dirs()->KStandardDirs::localxdgdatadir();
 
1911
    if ( !KIO::NetAccess::del( QUrl::fromLocalFile(xdgdir + QStringLiteral("/applications")) , this) )
 
1912
        qWarning()<<"Could not delete dir :"<<( xdgdir+"/applications" );
 
1913
    if ( !KIO::NetAccess::del( QUrl::fromLocalFile(xdgdir + QStringLiteral("/desktop-directories")) , this) )
 
1914
        qWarning()<<"Could not delete dir :"<<( xdgdir + "/desktop-directories");
 
1915
 
 
1916
    KBuildSycocaProgressDialog::rebuildKSycoca(this);
 
1917
    clear();
 
1918
    cleanupClipboard();
 
1919
    delete m_rootFolder;
 
1920
    delete m_separator;
 
1921
 
 
1922
    m_layoutDirty = false;
 
1923
    m_newMenuIds.clear();
 
1924
    m_newDirectoryList.clear();
 
1925
    m_menuFile->restoreMenuSystem(kmenueditfile);
 
1926
 
 
1927
    m_rootFolder = new MenuFolderInfo;
 
1928
    m_separator = new MenuSeparatorInfo;
 
1929
 
 
1930
    readMenuFolderInfo();
 
1931
    fill();
 
1932
    sendReloadMenu();
 
1933
    emit disableAction();
 
1934
    emit entrySelected(( MenuEntryInfo* ) 0 );
 
1935
}
 
1936
 
 
1937
void TreeView::updateTreeView(bool showHidden)
 
1938
{
 
1939
    m_showHidden = showHidden;
 
1940
    clear();
 
1941
    cleanupClipboard();
 
1942
    delete m_rootFolder;
 
1943
    delete m_separator;
 
1944
 
 
1945
    m_layoutDirty = false;
 
1946
    m_newMenuIds.clear();
 
1947
    m_newDirectoryList.clear();
 
1948
 
 
1949
    m_rootFolder = new MenuFolderInfo;
 
1950
    m_separator = new MenuSeparatorInfo;
 
1951
 
 
1952
    readMenuFolderInfo();
 
1953
    fill();
 
1954
    sendReloadMenu();
 
1955
    emit disableAction();
 
1956
    emit entrySelected(( MenuEntryInfo* ) 0 );
 
1957
}
 
1958
 
 
1959
void TreeView::sendReloadMenu()
 
1960
{
 
1961
    QDBusMessage message = QDBusMessage::createSignal("/kickoff", "org.kde.plasma", "reloadMenu");
 
1962
    QDBusConnection::sessionBus().send(message);
 
1963
}
 
1964
 
 
1965
MenuItemMimeData::MenuItemMimeData(TreeItem *item)
 
1966
    : QMimeData(),
 
1967
      m_item(item)
 
1968
{
 
1969
}
 
1970
 
 
1971
TreeItem *MenuItemMimeData::item() const
 
1972
{
 
1973
    return m_item;
 
1974
}
 
1975
 
 
1976
QStringList MenuItemMimeData::formats() const
 
1977
{
 
1978
    QStringList formats;
 
1979
    if (!m_item) {
 
1980
        return formats;
 
1981
    }
 
1982
 
 
1983
    formats << s_internalMimeType;
 
1984
    return formats;
 
1985
}
 
1986
 
 
1987
bool MenuItemMimeData::hasFormat(const QString &mimeType) const
 
1988
{
 
1989
    return m_item && mimeType == s_internalMimeType;
 
1990
}
 
1991
 
 
1992
QVariant MenuItemMimeData::retrieveData(const QString &mimeType, QVariant::Type type) const
 
1993
{
 
1994
    Q_UNUSED(type);
 
1995
 
 
1996
    if (m_item && mimeType == s_internalMimeType) {
 
1997
        return qVariantFromValue<TreeItem*>(m_item);
 
1998
    }
 
1999
 
 
2000
    return QVariant();
 
2001
}
 
2002