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>
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.
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.
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.
29
#include <QHeaderView>
35
#include <QApplication>
36
#include <QtDBus/QtDBus>
37
#include <QSignalMapper>
40
#include <KActionCollection>
41
#include <KBuildSycocaProgressDialog>
43
#include <KDesktopFile>
45
#include <KIconLoader>
46
#include <KInputDialog>
47
#include <KLocalizedString>
48
#include <KMessageBox>
50
#include <KServiceGroup>
52
#include <KConfigGroup>
53
#include <KStandardDirs>
54
#include <kio/netaccess.h>
57
#include "treeview.moc"
61
#define MOVE_FOLDER 'M'
62
#define COPY_FOLDER 'C'
65
#define COPY_SEPARATOR 'S'
67
static const char *s_internalMimeType = "application/x-kmenuedit-internal";
69
class SeparatorWidget : public QWidget
78
void paintEvent(QPaintEvent * /*event*/)
82
int h = (height() / 2) -1;
83
// if (isSelected()) {
84
// p->setPen( palette().color( QPalette::HighlightedText ) );
86
// p->setPen( palette().color( QPalette::Text ) );
89
p.drawLine(2, h, width() - 4, h);
94
TreeItem::TreeItem(QTreeWidgetItem *parent, QTreeWidgetItem *after, const QString& menuId, bool _m_init)
95
: QTreeWidgetItem(parent, after),
105
TreeItem::TreeItem(QTreeWidget *parent, QTreeWidgetItem *after, const QString& menuId, bool _m_init)
106
: QTreeWidgetItem(parent, after),
109
m_layoutDirty(false),
117
TreeItem::~TreeItem()
122
* @brief Return the description.
123
* @return Description, or an empty string if none.
125
QString TreeItem::description() const
129
description = entryInfo()->description;
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.
140
bool TreeItem::itemNameLessThan(QTreeWidgetItem *item1, QTreeWidgetItem *item2)
142
TreeItem *treeItem1 = static_cast<TreeItem*>(item1);
143
TreeItem *treeItem2 = static_cast<TreeItem*>(item2);
144
return treeItem1->name().toLower() < treeItem2->name().toLower();
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.
153
bool TreeItem::itemDescriptionLessThan(QTreeWidgetItem *item1, QTreeWidgetItem *item2)
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();
161
// if description is missing for both items, sort them using their names
162
if (description1.isEmpty() && description2.isEmpty()) {
163
return itemNameLessThan(item1, item2);
166
return description1 < description2;
170
void TreeItem::setName(const QString &name)
172
if (m_name == name) {
180
void TreeItem::setHiddenInMenu(bool b)
190
void TreeItem::update()
194
s += i18n(" [Hidden]");
200
void TreeItem::load()
202
if (m_folderInfo && !m_init) {
204
TreeView *tv = static_cast<TreeView *>(treeWidget());
205
tv->fillBranch(m_folderInfo, this);
209
bool TreeItem::isLayoutDirty() const
215
for (int i = 0; i < childCount(); ++i) {
216
TreeItem *item = dynamic_cast<TreeItem *>(child(i));
221
if (item->isLayoutDirty()) {
229
static QPixmap appIcon(const QString &iconName)
231
QPixmap normal = KIconLoader::global()->loadIcon(iconName, KIconLoader::Small, 0, KIconLoader::DefaultState, QStringList(), 0L, true);
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)
242
m_dropMimeTypes << s_internalMimeType << KUrl::List::mimeDataTypes();
243
qRegisterMetaType<TreeItem *>("TreeItem");
245
setAllColumnsShowFocus(true);
246
setRootIsDecorated(true);
247
setSortingEnabled(false);
248
setDragEnabled(true);
249
setAcceptDrops(true);
250
setMinimumWidth(240);
252
setHeaderLabels(QStringList() << QString(""));
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()));
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()));
265
// listen for deleting
266
connect(m_ac->action(DELETE_ACTION_NAME), SIGNAL(triggered()), SLOT(del()));
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)));
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()));
288
// listen for selection
289
connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
290
SLOT(itemSelected(QTreeWidgetItem*)));
292
m_menuFile = new MenuFile(KStandardDirs::locateLocal("xdgconf-menu", "applications-kmenuedit.menu"));
293
m_rootFolder = new MenuFolderInfo;
294
m_separator = new MenuSeparatorInfo;
297
TreeView::~TreeView()
304
void TreeView::setViewMode(bool showHidden)
308
m_popupMenu = new QMenu(this);
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();
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();
323
m_popupMenu->addAction( m_ac->action(DELETE_ACTION_NAME));
324
m_popupMenu->addSeparator();
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();
332
m_popupMenu->addAction(m_ac->action(SORT_ACTION_NAME));
334
m_showHidden = showHidden;
335
readMenuFolderInfo();
339
void TreeView::readMenuFolderInfo(MenuFolderInfo *folderInfo, KServiceGroup::Ptr folder, const QString &prefix)
343
folderInfo = m_rootFolder;
344
folder = KServiceGroup::root();
347
if (!folder || !folder->isValid())
350
folderInfo->caption = folder->caption();
351
folderInfo->comment = folder->comment();
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);
362
folderInfo->fullId = prefix + id;
364
for (const KSycocaEntry::Ptr &e : folder->entries(true, !m_showHidden, true, m_detailedMenuEntries && !m_detailedEntriesNamesFirst))
366
if (e->isType(KST_KServiceGroup))
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);
373
else if (e->isType(KST_KService))
375
const KService::Ptr service(static_cast<KService*>(e.data()));
376
folderInfo->add(new MenuEntryInfo(service), true);
378
else if (e->isType(KST_KServiceSeparator))
380
folderInfo->add(m_separator, true);
385
void TreeView::fill()
387
QApplication::setOverrideCursor(Qt::WaitCursor);
389
fillBranch(m_rootFolder, 0);
390
QApplication::restoreOverrideCursor();
393
QString TreeView::findName(KDesktopFile *df, bool deleted)
395
QString name = df->readName();
403
const QStringList files = QStandardPaths::locateAll(df->resource(), df->fileName(), QStandardPaths::LocateFile);
404
for(QStringList::ConstIterator it = files.constBegin();
405
it != files.constEnd();
414
KDesktopFile df2(*it);
415
name = df2.readName();
417
if (!name.isEmpty() && (name != "empty"))
425
TreeItem *TreeView::createTreeItem(TreeItem *parent, QTreeWidgetItem *after, MenuFolderInfo *folderInfo, bool m_init)
429
item = new TreeItem(parent, after, QString(), m_init);
431
item = new TreeItem(this, after, QString(), m_init);
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);
443
TreeItem *TreeView::createTreeItem(TreeItem *parent, QTreeWidgetItem *after, MenuEntryInfo *entryInfo, bool m_init)
445
bool hidden = entryInfo->hidden;
449
item = new TreeItem(parent, after, entryInfo->menuId(),m_init);
451
item = new TreeItem(this, after, entryInfo->menuId(), m_init);
456
if (m_detailedMenuEntries && entryInfo->description.length() != 0) {
457
if (m_detailedEntriesNamesFirst) {
458
name = entryInfo->caption + " (" + entryInfo->description + ')';
460
name = entryInfo->description + " (" + entryInfo->caption + ')';
463
name = entryInfo->caption;
466
//kDebug() << parent << after << name;
467
item->setMenuEntryInfo(entryInfo);
469
item->setIcon(0, appIcon(entryInfo->icon));
470
item->setHiddenInMenu(hidden);
476
TreeItem *TreeView::createTreeItem(TreeItem *parent, QTreeWidgetItem *after, MenuSeparatorInfo *, bool init)
480
item = new TreeItem(parent, after, QString(), init);
482
item = new TreeItem(this, after, QString(), init);
485
setItemWidget(item, 0, new SeparatorWidget);
489
void TreeView::fillBranch(MenuFolderInfo *folderInfo, TreeItem *parent)
491
QString relPath = parent ? parent->directory() : QString();
493
foreach (MenuInfo *info, folderInfo->initialLayout)
495
MenuEntryInfo *entry = dynamic_cast<MenuEntryInfo*>(info);
498
after = createTreeItem(parent, after, entry);
502
MenuFolderInfo *subFolder = dynamic_cast<MenuFolderInfo*>(info);
505
after = createTreeItem(parent, after, subFolder);
508
MenuSeparatorInfo *separator = dynamic_cast<MenuSeparatorInfo*>(info);
511
after = createTreeItem(parent, after, separator);
517
void TreeView::closeAllItems(QTreeWidgetItem *item)
519
item->setExpanded(false);
520
for (int i = 0; i < item->childCount(); ++i) {
521
closeAllItems(item->child(i));
525
TreeItem *TreeView::expandPath(TreeItem *item, const QString &path)
527
int i = path.indexOf("/");
528
QString subMenu = path.left(i+1);
529
QString restMenu = path.mid(i+1);
531
for (int i = 0; i < item->childCount(); ++i) {
532
TreeItem *childItem = dynamic_cast<TreeItem *>(item->child(i));
537
MenuFolderInfo *folderInfo = childItem->folderInfo();
538
if (folderInfo && (folderInfo->id == subMenu)) {
539
childItem->setExpanded(true);
540
if (!restMenu.isEmpty()) {
541
return expandPath(childItem, restMenu);
551
void TreeView::selectMenu(const QString &menu)
553
for (int i = 0; i < topLevelItemCount(); ++i) {
554
closeAllItems(topLevelItem(i));
557
if (menu.length() <= 1)
559
setCurrentItem(topLevelItem(0));
564
QString restMenu = menu;
565
if ( menu.startsWith( '/' ) )
566
restMenu = menu.mid(1);
567
if (!restMenu.endsWith('/'))
571
int i = restMenu.indexOf("/");
572
QString subMenu = restMenu.left(i+1);
573
restMenu = restMenu.mid(i+1);
575
for (int i = 0; i < topLevelItemCount(); ++i) {
576
item = dynamic_cast<TreeItem *>(topLevelItem(i));
581
MenuFolderInfo *folderInfo = item->folderInfo();
582
if (folderInfo && (folderInfo->id == subMenu)) {
583
if (!restMenu.isEmpty()) {
584
item = expandPath(item, restMenu);
592
setCurrentItem(item);
597
void TreeView::selectMenuEntry(const QString &menuEntry)
599
TreeItem *item = static_cast<TreeItem *>(selectedItem());
601
item = static_cast<TreeItem *>(currentItem());
608
QTreeWidgetItem *parent = item->parent();
610
for (int i = 0; i < parent->childCount(); ++i) {
611
TreeItem *item = dynamic_cast<TreeItem *>(parent->child(i));
612
if (!item || item->isDirectory()) {
616
MenuEntryInfo *entry = item->entryInfo();
617
if (entry && entry->menuId() == menuEntry) {
618
setCurrentItem(item);
625
for (int i = 0; i < topLevelItemCount(); ++i) {
626
TreeItem *item = dynamic_cast<TreeItem *>(topLevelItem(i));
627
if (!item || item->isDirectory()) {
631
MenuEntryInfo *entry = item->entryInfo();
632
if (entry && entry->menuId() == menuEntry) {
633
setCurrentItem(item);
641
void TreeView::itemSelected(QTreeWidgetItem *item)
643
// ensure the item is visible as selected
644
setItemSelected(item, true);
646
TreeItem *_item = static_cast<TreeItem*>(item);
647
TreeItem *parentItem = 0;
648
bool selected = false;
649
bool dselected = false;
652
dselected = _item->isHiddenInMenu();
653
parentItem = getParentItem(_item);
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);
661
if (m_ac->action(DELETE_ACTION_NAME)) {
662
m_ac->action(DELETE_ACTION_NAME)->setEnabled(selected && !dselected);
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());
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));
672
emit disableAction();
676
if (_item->isDirectory()) {
677
emit entrySelected(_item->folderInfo());
679
emit entrySelected(_item->entryInfo());
683
void TreeView::currentDataChanged(MenuFolderInfo *folderInfo)
685
TreeItem *item = (TreeItem*)selectedItem();
686
if (item == 0 || folderInfo == 0) {
690
item->setName(folderInfo->caption);
691
item->setIcon(0, appIcon(folderInfo->icon));
694
void TreeView::currentDataChanged(MenuEntryInfo *entryInfo)
696
TreeItem *item = (TreeItem*)selectedItem();
697
if (item == 0 || entryInfo == 0) {
703
if (m_detailedMenuEntries && entryInfo->description.length() != 0) {
704
if (m_detailedEntriesNamesFirst) {
705
name = entryInfo->caption + " (" + entryInfo->description + ')';
707
name = entryInfo->description + " (" + entryInfo->caption + ')';
710
name = entryInfo->caption;
714
item->setIcon(0, appIcon(entryInfo->icon));
717
QStringList TreeView::fileList(const QString& rPath)
719
QString relativePath = rPath;
721
// truncate "/.directory"
722
int pos = relativePath.lastIndexOf("/.directory");
723
if (pos > 0) relativePath.truncate(pos);
725
QStringList filelist;
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)
731
QDir dir((*it) + '/' + relativePath);
732
if(!dir.exists()) continue;
734
dir.setFilter(QDir::Files);
735
dir.setNameFilters(QStringList() << "*.desktop;*.kdelnk");
737
// build a list of files
738
const QStringList files = dir.entryList();
739
for (QStringList::ConstIterator it = files.constBegin(); it != files.constEnd(); ++it) {
741
//if (filelist.contains(*it)) continue;
743
if (relativePath.isEmpty()) {
744
filelist.removeAll(*it); // hack
745
filelist.append(*it);
748
filelist.removeAll(relativePath + '/' + *it); //hack
749
filelist.append(relativePath + '/' + *it);
756
QStringList TreeView::dirList(const QString& rPath)
758
QString relativePath = rPath;
760
// truncate "/.directory"
761
int pos = relativePath.lastIndexOf("/.directory");
762
if (pos > 0) relativePath.truncate(pos);
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)
770
QDir dir((*it) + '/' + relativePath);
771
if(!dir.exists()) continue;
772
dir.setFilter(QDir::Dirs);
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;
779
// if (dirlist.contains(*it)) continue;
781
if (relativePath.isEmpty()) {
782
dirlist.removeAll(*it); //hack
786
dirlist.removeAll(relativePath + '/' + *it); //hack
787
dirlist.append(relativePath + '/' + *it);
794
Qt::DropActions TreeView::supportedDropActions() const
796
return Qt::CopyAction | Qt::MoveAction;
799
QStringList TreeView::mimeTypes() const
801
return m_dropMimeTypes;
804
void TreeView::startDrag(Qt::DropActions supportedActions)
806
QList<QTreeWidgetItem *> items;
807
items << selectedItem();
808
QMimeData *data = mimeData(items);
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);
820
QMimeData *TreeView::mimeData(const QList<QTreeWidgetItem *> items) const
822
if (items.isEmpty()) {
826
return new MenuItemMimeData(dynamic_cast<TreeItem *>(items.first()));
829
static QString createDesktopFile(const QString &file, QString *menuId, QStringList *excludeList)
831
QString base = file.mid(file.lastIndexOf('/')+1);
832
base = base.left(base.lastIndexOf('.'));
834
QRegExp r("(.*)(?=-\\d+)");
835
base = (r.indexIn(base) > -1) ? r.cap(1) : base;
837
QString result = KService::newServicePath(true, base, menuId, excludeList);
838
excludeList->append(*menuId);
839
// Todo for Undo-support: Undo menuId allocation:
844
static KDesktopFile *copyDesktopFile(MenuEntryInfo *entryInfo, QString *menuId, QStringList *excludeList)
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!
853
static QString createDirectoryFile(const QString &file, QStringList *excludeList)
855
QString base = file.mid(file.lastIndexOf('/')+1);
856
base = base.left(base.lastIndexOf('.'));
863
result = base + ".directory";
865
result = base + QString("-%1.directory").arg(i);
867
if (!excludeList->contains(result))
869
if (KStandardDirs::locate("xdgdata-dirs", result).isEmpty())
874
excludeList->append(result);
875
result = KStandardDirs::locateLocal("xdgdata-dirs", result);
880
bool TreeView::dropMimeData(QTreeWidgetItem *item, int index, const QMimeData *data, Qt::DropAction action)
882
// get destination folder
883
TreeItem *titem = item ? dynamic_cast<TreeItem*>(item) : 0;
884
if (item && !titem) {
888
TreeItem *parentItem = 0;
889
QTreeWidgetItem *after = titem;
890
// find the parent item and which item the dropped item should go after
892
if (titem->isDirectory()) {
894
after = titem->child(index);
896
after = titem->child(titem->childCount() - 1);
899
parentItem = dynamic_cast<TreeItem *>(titem->parent());
900
if (titem->parent() && !parentItem) {
904
} else if (index > 0) {
905
after = topLevelItem(index);
907
after = topLevelItem(topLevelItemCount() - 1);
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;
915
if (!data->hasFormat(s_internalMimeType)) {
917
if (!KUrl::List::canDecode(data)) {
921
KUrl::List urls = KUrl::List::fromMimeData(data);;
922
if (urls.isEmpty() || !urls[0].isLocalFile()) {
926
//FIXME: this should really support multiple DnD
927
QString path = urls[0].path();
928
if (!path.endsWith(QLatin1String(".desktop"))) {
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!
938
KService::Ptr s(new KService(df));
939
s->setMenuId(menuId);
941
MenuEntryInfo *entryInfo = new MenuEntryInfo(s, df);
943
QString oldCaption = entryInfo->caption;
944
QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption, oldCaption);
945
entryInfo->setCaption(newCaption);
948
// m_menuFile->addEntry(folder, menuId);
949
m_menuFile->pushAction(MenuFile::ADD_ENTRY, folder, menuId);
951
// create the TreeItem
953
parentItem->setExpanded(true);
956
// update fileInfo data
957
parentFolderInfo->add(entryInfo);
959
TreeItem *newItem = createTreeItem(parentItem, after, entryInfo, true);
960
setCurrentItem(newItem);
962
setLayoutDirty(parentItem);
966
QVariant p(data->data(s_internalMimeType));
967
const MenuItemMimeData *itemData = dynamic_cast<const MenuItemMimeData *>(data);
972
TreeItem *dragItem = itemData->item();
973
if (!dragItem || dragItem == after) {
974
return false; // Nothing to do
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) {
982
// * Create new .directory file
984
TreeItem *tmpItem = static_cast<TreeItem*>(parentItem);
986
if (tmpItem == dragItem) {
990
tmpItem = static_cast<TreeItem*>(tmpItem->parent());
993
// Remove MenuFolderInfo
994
TreeItem *oldParentItem = static_cast<TreeItem*>(dragItem->parent());
995
MenuFolderInfo *oldParentFolderInfo = oldParentItem ? oldParentItem->folderInfo() : m_rootFolder;
996
oldParentFolderInfo->take(folderInfo);
999
QString oldFolder = folderInfo->fullId;
1000
QString folderName = folderInfo->id;
1001
QString newFolder = m_menuFile->uniqueMenuName(folder, folderName, parentFolderInfo->existingMenuIds());
1002
folderInfo->id = newFolder;
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);
1009
// Make sure caption is unique
1010
QString newCaption = parentFolderInfo->uniqueMenuCaption(folderInfo->caption);
1011
if (newCaption != folderInfo->caption) {
1012
folderInfo->setCaption(newCaption);
1015
// create the TreeItem
1017
parentItem->setExpanded(true);
1020
// update fileInfo data
1021
folderInfo->updateFullId(parentFolderInfo->fullId);
1022
folderInfo->setInUse(true);
1023
parentFolderInfo->add(folderInfo);
1025
if (parentItem != oldParentItem) {
1026
if (oldParentItem) {
1027
oldParentItem->takeChild(oldParentItem->indexOfChild(dragItem));
1029
takeTopLevelItem(indexOfTopLevelItem(dragItem));
1034
parentItem->insertChild(after ? parentItem->indexOfChild(after) + 1 : parentItem->childCount(), dragItem);
1036
insertTopLevelItem(after ? indexOfTopLevelItem(after) : topLevelItemCount(), dragItem);
1039
dragItem->setName(folderInfo->caption);
1040
dragItem->setDirectoryPath(folderInfo->fullId);
1041
setCurrentItem(dragItem);
1043
} else if (dragItem->isEntry()) {
1044
MenuEntryInfo *entryInfo = dragItem->entryInfo();
1045
QString menuId = entryInfo->menuId();
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)
1052
KService::Ptr s(new KService(df));
1053
s->setMenuId(menuId);
1055
entryInfo = new MenuEntryInfo(s, df);
1057
QString oldCaption = entryInfo->caption;
1058
QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption, oldCaption);
1059
entryInfo->setCaption(newCaption);
1061
del(dragItem, false);
1062
QString oldCaption = entryInfo->caption;
1063
QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption);
1064
entryInfo->setCaption(newCaption);
1065
entryInfo->setInUse(true);
1069
// m_menuFile->addEntry(folder, menuId);
1070
m_menuFile->pushAction(MenuFile::ADD_ENTRY, folder, menuId);
1072
// create the TreeItem
1074
parentItem->setExpanded(true);
1077
// update fileInfo data
1078
parentFolderInfo->add(entryInfo);
1080
TreeItem *newItem = createTreeItem(parentItem, after, entryInfo);
1081
setCurrentItem(newItem);
1083
// copying a separator
1084
if (action != Qt::CopyAction) {
1085
del(dragItem, false);
1088
TreeItem *newItem = createTreeItem(parentItem, after, m_separator);
1089
setCurrentItem(newItem);
1092
kDebug() << "setting the layout to be dirty at" << parentItem;
1093
setLayoutDirty(parentItem);
1098
QTreeWidgetItem *TreeView::selectedItem()
1100
QList<QTreeWidgetItem *> selection = selectedItems();
1102
if (selection.isEmpty()) {
1106
return selection.first();
1109
void TreeView::contextMenuEvent(QContextMenuEvent *event)
1111
if (m_popupMenu && itemAt(event->pos())) {
1112
m_popupMenu->exec(event->globalPos());
1116
void TreeView::dropEvent(QDropEvent *event)
1118
// this prevents QTreeWidget from interfering with our moves
1119
QTreeView::dropEvent(event);
1122
void TreeView::newsubmenu()
1124
TreeItem *parentItem = 0;
1125
TreeItem *item = (TreeItem*)selectedItem();
1128
QString caption = KInputDialog::getText( i18n( "New Submenu" ),
1129
i18n( "Submenu name:" ), QString(), &ok, this );
1133
QString file = caption;
1134
file.replace('/', '-');
1136
file = createDirectoryFile(file, &m_newDirectoryList); // Create
1138
// get destination folder
1146
else if(item->isDirectory())
1150
folder = parentItem->directory();
1154
parentItem = static_cast<TreeItem*>(item->parent());
1155
folder = parentItem ? parentItem->directory() : QString();
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();
1167
KDesktopFile *df = new KDesktopFile(file);
1168
KConfigGroup desktopGroup = df->desktopGroup();
1169
desktopGroup.writeEntry("Name", folderInfo->caption);
1170
desktopGroup.writeEntry("Icon", folderInfo->icon);
1174
// m_menuFile->addMenu(folder + folderInfo->id, file);
1175
m_menuFile->pushAction(MenuFile::ADD_MENU, folder + folderInfo->id, file);
1177
folderInfo->fullId = parentFolderInfo->fullId + folderInfo->id;
1179
// create the TreeItem
1181
parentItem->setExpanded(true);
1183
// update fileInfo data
1184
parentFolderInfo->add(folderInfo);
1186
TreeItem *newItem = createTreeItem(parentItem, item, folderInfo, true);
1188
setCurrentItem(newItem);
1189
setLayoutDirty(parentItem);
1192
void TreeView::newitem()
1194
TreeItem *parentItem = 0;
1195
TreeItem *item = (TreeItem*)selectedItem();
1198
QString caption = KInputDialog::getText( i18n( "New Item" ),
1199
i18n( "Item name:" ), QString(), &ok, this );
1204
QString file = caption;
1205
file.replace('/', '-');
1207
file = createDesktopFile(file, &menuId, &m_newMenuIds); // Create
1209
KDesktopFile *df = new KDesktopFile(file);
1210
KConfigGroup desktopGroup = df->desktopGroup();
1211
desktopGroup.writeEntry("Name", caption);
1212
desktopGroup.writeEntry("Type", "Application");
1214
// get destination folder
1222
else if(item->isDirectory())
1226
folder = parentItem->directory();
1230
parentItem = static_cast<TreeItem*>(item->parent());
1231
folder = parentItem ? parentItem->directory() : QString();
1234
MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
1237
// m_menuFile->addEntry(folder, menuId);
1238
m_menuFile->pushAction(MenuFile::ADD_ENTRY, folder, menuId);
1240
KService::Ptr s(new KService(df));
1241
s->setMenuId(menuId);
1243
MenuEntryInfo *entryInfo = new MenuEntryInfo(s, df);
1245
// create the TreeItem
1247
parentItem->setExpanded(true);
1249
// update fileInfo data
1250
parentFolderInfo->add(entryInfo);
1252
TreeItem *newItem = createTreeItem(parentItem, item, entryInfo, true);
1254
setCurrentItem(newItem);
1255
setLayoutDirty(parentItem);
1258
void TreeView::newsep()
1260
TreeItem *parentItem = 0;
1261
TreeItem *item = (TreeItem*)selectedItem();
1267
else if(item->isDirectory())
1274
parentItem = static_cast<TreeItem*>(item->parent());
1277
// create the TreeItem
1279
parentItem->setExpanded(true);
1281
TreeItem *newItem = createTreeItem(parentItem, item, m_separator, true);
1283
setCurrentItem(newItem);
1284
setLayoutDirty(parentItem);
1287
void TreeView::cut()
1291
// Select new current item
1292
// TODO: is this completely redundant?
1293
setCurrentItem(currentItem());
1296
void TreeView::copy()
1301
void TreeView::copy( bool cutting )
1303
TreeItem *item = (TreeItem*)selectedItem();
1305
// nil selected? -> nil to copy
1306
if (item == 0) return;
1309
setLayoutDirty((TreeItem*)item->parent());
1311
// clean up old stuff
1314
// is item a folder or a file?
1315
if(item->isDirectory())
1317
QString folder = item->directory();
1320
// Place in clipboard
1321
m_clipboard = MOVE_FOLDER;
1322
m_clipboardFolderInfo = item->folderInfo();
1328
// Place in clipboard
1329
m_clipboard = COPY_FOLDER;
1330
m_clipboardFolderInfo = item->folderInfo();
1333
else if (item->isEntry())
1337
// Place in clipboard
1338
m_clipboard = MOVE_FILE;
1339
m_clipboardEntryInfo = item->entryInfo();
1345
// Place in clipboard
1346
m_clipboard = COPY_FILE;
1347
m_clipboardEntryInfo = item->entryInfo();
1352
// Place in clipboard
1353
m_clipboard = COPY_SEPARATOR;
1358
m_ac->action(PASTE_ACTION_NAME)->setEnabled(true);
1362
void TreeView::paste()
1364
TreeItem *parentItem = 0;
1365
TreeItem *item = (TreeItem*)selectedItem();
1367
// nil selected? -> nil to paste to
1368
if (item == 0) return;
1370
// is there content in the clipboard?
1371
if (!m_clipboard) return;
1373
// get destination folder
1376
if(item->isDirectory())
1380
folder = parentItem->directory();
1384
parentItem = static_cast<TreeItem*>(item->parent());
1385
folder = parentItem ? parentItem->directory() : QString();
1388
MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
1389
int command = m_clipboard;
1390
if ((command == COPY_FOLDER) || (command == MOVE_FOLDER))
1392
MenuFolderInfo *folderInfo = m_clipboardFolderInfo;
1393
if (command == COPY_FOLDER)
1395
// Ugh.. this is hard :)
1396
// * Create new .directory file
1399
else if (command == MOVE_FOLDER)
1402
QString oldFolder = folderInfo->fullId;
1403
QString folderName = folderInfo->id;
1404
QString newFolder = m_menuFile->uniqueMenuName(folder, folderName, parentFolderInfo->existingMenuIds());
1405
folderInfo->id = newFolder;
1408
// m_menuFile->moveMenu(oldFolder, folder + newFolder);
1409
m_menuFile->pushAction(MenuFile::MOVE_MENU, oldFolder, folder + newFolder);
1411
// Make sure caption is unique
1412
QString newCaption = parentFolderInfo->uniqueMenuCaption(folderInfo->caption);
1413
if (newCaption != folderInfo->caption)
1415
folderInfo->setCaption(newCaption);
1417
// create the TreeItem
1419
parentItem->setExpanded(true);
1421
// update fileInfo data
1422
folderInfo->fullId = parentFolderInfo->fullId + folderInfo->id;
1423
folderInfo->setInUse(true);
1424
parentFolderInfo->add(folderInfo);
1426
TreeItem *newItem = createTreeItem(parentItem, item, folderInfo);
1428
setCurrentItem(newItem);
1431
m_clipboard = COPY_FOLDER; // Next one copies.
1433
else if ((command == COPY_FILE) || (command == MOVE_FILE))
1435
MenuEntryInfo *entryInfo = m_clipboardEntryInfo;
1438
if (command == COPY_FILE)
1440
// Need to copy file and then add it
1441
KDesktopFile *df = copyDesktopFile(entryInfo, &menuId, &m_newMenuIds); // Duplicate
1443
KService::Ptr s(new KService(df));
1444
s->setMenuId(menuId);
1445
entryInfo = new MenuEntryInfo(s, df);
1447
QString oldCaption = entryInfo->caption;
1448
QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption, oldCaption);
1449
entryInfo->setCaption(newCaption);
1451
else if (command == MOVE_FILE)
1453
menuId = entryInfo->menuId();
1454
m_clipboard = COPY_FILE; // Next one copies.
1456
QString oldCaption = entryInfo->caption;
1457
QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption);
1458
entryInfo->setCaption(newCaption);
1459
entryInfo->setInUse(true);
1462
// m_menuFile->addEntry(folder, menuId);
1463
m_menuFile->pushAction(MenuFile::ADD_ENTRY, folder, menuId);
1465
// create the TreeItem
1467
parentItem->setExpanded(true);
1469
// update fileInfo data
1470
parentFolderInfo->add(entryInfo);
1472
TreeItem *newItem = createTreeItem(parentItem, item, entryInfo, true);
1474
setCurrentItem(newItem);
1480
parentItem->setExpanded(true);
1482
TreeItem *newItem = createTreeItem(parentItem, item, m_separator, true);
1484
setCurrentItem(newItem);
1486
setLayoutDirty(parentItem);
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.
1493
* @brief Determine which item is to sort, and do it.
1494
* @param sortCmd Sort type.
1496
void TreeView::sort(const int sortCmd)
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());
1511
// proceed to the sorting
1512
sortItem(itemToSort, sortType);
1516
* Sort children of the given item, according to the sort type.
1517
* The sorting is done on children groups, splited by separator items.
1519
* @brief Sort item children.
1520
* @param item Item to sort.
1521
* @param sortType Sort type.
1523
void TreeView::sortItem(TreeItem *item, const SortType& sortType)
1525
// sort the selected item only if contains children
1526
if ( (!item->isDirectory()) || (item->childCount() == 0) ) {
1530
// remove contained children
1531
QList<QTreeWidgetItem*> children = item->takeChildren();
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;
1545
sortItemChildren(startIt, currentIt, sortType);
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);
1556
// try to sort sub-children
1557
sortItem(static_cast<TreeItem*>(child), sortType);
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;
1566
setLayoutDirty(itemToFlagAsDirty);
1570
* Sort a children range defined with two list iterators, according to the sort type.
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.
1577
void TreeView::sortItemChildren(const QList<QTreeWidgetItem*>::iterator& begin, const QList<QTreeWidgetItem*>::iterator& end, const SortType& sortType)
1580
if (sortType == SortByName) {
1581
qSort(begin, end, TreeItem::itemNameLessThan);
1583
// sort by description
1584
else if (sortType == SortByDescription) {
1585
qSort(begin, end, TreeItem::itemDescriptionLessThan);
1590
* @brief Move up the selected item.
1592
void TreeView::moveUpItem() {
1593
moveUpOrDownItem(true);
1597
* @brief Move down the selected item.
1599
void TreeView::moveDownItem() {
1600
moveUpOrDownItem(false);
1604
* Move the selected item on desired direction (up or down).
1606
* @brief Move up/down the selected item.
1607
* @param isMovingUpAction True to move up, false to move down.
1609
void TreeView::moveUpOrDownItem(bool isMovingUpAction)
1611
// get the selected item and its parent
1612
TreeItem *sourceItem = static_cast<TreeItem*>(selectedItem());
1615
TreeItem *parentItem = getParentItem(sourceItem);
1617
// get selected item index
1618
int sourceItemIndex = parentItem->indexOfChild(sourceItem);
1620
// find the second item to swap
1621
TreeItem *destItem = 0;
1623
if (isMovingUpAction) {
1624
destIndex = sourceItemIndex - 1;
1625
destItem = static_cast<TreeItem*>(parentItem->child(destIndex));
1628
destIndex = sourceItemIndex + 1;
1629
destItem = static_cast<TreeItem*>(parentItem->child(destIndex));
1633
parentItem->removeChild(sourceItem);
1634
parentItem->insertChild(destIndex, sourceItem);
1636
// recreate item widget for separators
1637
if (sourceItem->isSeparator()) {
1638
setItemWidget(sourceItem, 0, new SeparatorWidget);
1640
if (destItem->isSeparator()) {
1641
setItemWidget(destItem, 0, new SeparatorWidget);
1644
// set the focus on the source item
1645
setCurrentItem(sourceItem);
1647
// flag parent item as dirty (if the parent is the root item, set the entire layout as dirty)
1648
if (parentItem == invisibleRootItem()) {
1651
setLayoutDirty(parentItem);
1655
* For a given item, return its parent. For top items, return the invisible root item.
1657
* @brief Get the parent item.
1659
* @return Parent item.
1661
TreeItem* TreeView::getParentItem(QTreeWidgetItem *item) const
1663
QTreeWidgetItem *parentItem = item->parent();
1665
parentItem = invisibleRootItem();
1667
return static_cast<TreeItem*>(parentItem);
1670
void TreeView::del()
1672
TreeItem *item = (TreeItem*)selectedItem();
1674
// nil selected? -> nil to delete
1675
if (item == 0) return;
1679
// Select new current item
1680
// TODO: is this completely redundant?
1681
setCurrentItem(currentItem());
1684
void TreeView::del(TreeItem *item, bool deleteInfo)
1686
TreeItem *parentItem = static_cast<TreeItem*>(item->parent());
1687
// is file a .directory or a .desktop file
1688
if(item->isDirectory())
1690
if ( KMessageBox::warningYesNo(this, i18n("All submenus of '%1' will be removed. Do you want to continue?", item->name() ) ) == KMessageBox::No )
1693
MenuFolderInfo *folderInfo = item->folderInfo();
1695
// Remove MenuFolderInfo
1696
MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
1697
parentFolderInfo->take(folderInfo);
1698
folderInfo->setInUse(false);
1700
if (m_clipboard == COPY_FOLDER && (m_clipboardFolderInfo == folderInfo))
1702
// Copy + Del == Cut
1703
m_clipboard = MOVE_FOLDER; // Clipboard now owns folderInfo
1708
if (folderInfo->takeRecursive(m_clipboardFolderInfo))
1709
m_clipboard = MOVE_FOLDER; // Clipboard now owns m_clipboardFolderInfo
1712
delete folderInfo; // Delete folderInfo
1716
// m_menuFile->removeMenu(item->directory());
1717
m_menuFile->pushAction(MenuFile::REMOVE_MENU, item->directory(), QString());
1722
else if (item->isEntry())
1724
MenuEntryInfo *entryInfo = item->entryInfo();
1725
QString menuId = entryInfo->menuId();
1727
// Remove MenuFolderInfo
1728
MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
1729
parentFolderInfo->take(entryInfo);
1730
entryInfo->setInUse(false);
1732
if (m_clipboard == COPY_FILE && (m_clipboardEntryInfo == entryInfo))
1734
// Copy + Del == Cut
1735
m_clipboard = MOVE_FILE; // Clipboard now owns entryInfo
1740
delete entryInfo; // Delete entryInfo
1744
QString folder = parentItem ? parentItem->directory() : QString();
1745
// m_menuFile->removeEntry(folder, menuId);
1746
m_menuFile->pushAction(MenuFile::REMOVE_ENTRY, folder, menuId);
1757
setLayoutDirty(parentItem);
1760
void TreeView::cleanupClipboard() {
1761
if (m_clipboard == MOVE_FOLDER)
1762
delete m_clipboardFolderInfo;
1763
m_clipboardFolderInfo = 0;
1765
if (m_clipboard == MOVE_FILE)
1766
delete m_clipboardEntryInfo;
1767
m_clipboardEntryInfo = 0;
1772
static QStringList extractLayout(QTreeWidget *tree, QTreeWidgetItem *parent)
1775
if (!parent && !tree) {
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));
1788
if (item->isDirectory()) {
1790
firstFolder = false;
1791
layout << ":M"; // Add new folders here...
1793
layout << (item->folderInfo()->id);
1794
} else if (item->isEntry()) {
1797
layout << ":F"; // Add new entries here...
1799
layout << (item->entryInfo()->menuId());
1808
void TreeItem::saveLayout(MenuFile *menuFile)
1810
if (m_layoutDirty) {
1811
QStringList layout = extractLayout(0, this);
1812
menuFile->setLayout(folderInfo()->fullId, layout);
1813
m_layoutDirty = false;
1816
for (int i = 0; i < childCount(); ++i) {
1817
TreeItem *item = dynamic_cast<TreeItem *>(child(i));
1819
item->saveLayout(menuFile);
1824
void TreeView::saveLayout()
1826
if (m_layoutDirty) {
1827
QStringList layout = extractLayout(this, 0);
1828
m_menuFile->setLayout(m_rootFolder->fullId, layout);
1829
m_layoutDirty = false;
1832
for (int i = 0; i < topLevelItemCount(); ++i) {
1833
TreeItem *item = dynamic_cast<TreeItem *>(topLevelItem(i));
1835
item->saveLayout(m_menuFile);
1840
bool TreeView::save()
1843
m_rootFolder->save(m_menuFile);
1845
bool success = m_menuFile->performAllActions();
1847
m_newMenuIds.clear();
1848
m_newDirectoryList.clear();
1852
KBuildSycocaProgressDialog::rebuildKSycoca(this);
1856
KMessageBox::sorry(this, "<qt>"+i18n("Menu changes could not be saved because of the following problem:")+"<br><br>"+
1857
m_menuFile->error()+"</qt>");
1865
void TreeView::setLayoutDirty(TreeItem *parentItem)
1868
parentItem->setLayoutDirty();
1870
m_layoutDirty = true;
1873
bool TreeView::isLayoutDirty()
1875
for (int i = 0; i < topLevelItemCount(); ++i) {
1876
TreeItem *item = dynamic_cast<TreeItem *>(topLevelItem(i));
1881
if (item->isLayoutDirty()) {
1889
bool TreeView::dirty()
1891
return m_layoutDirty || m_rootFolder->hasDirt() || m_menuFile->dirty() || isLayoutDirty();
1894
void TreeView::findServiceShortcut(const KShortcut&cut, KService::Ptr &service)
1896
service = m_rootFolder->findServiceShortcut(cut);
1899
void TreeView::restoreMenuSystem()
1901
if ( KMessageBox::warningYesNo( this, i18n( "Do you want to restore the system menu? Warning: This will remove all custom menus." ) )==KMessageBox::No )
1903
QString kmenueditfile = KStandardDirs::locateLocal("xdgconf-menu", "applications-kmenuedit.menu");
1904
if ( QFile::exists( kmenueditfile ) )
1906
if ( !QFile::remove( kmenueditfile ) )
1907
qWarning()<<"Could not delete "<<kmenueditfile;
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");
1916
KBuildSycocaProgressDialog::rebuildKSycoca(this);
1919
delete m_rootFolder;
1922
m_layoutDirty = false;
1923
m_newMenuIds.clear();
1924
m_newDirectoryList.clear();
1925
m_menuFile->restoreMenuSystem(kmenueditfile);
1927
m_rootFolder = new MenuFolderInfo;
1928
m_separator = new MenuSeparatorInfo;
1930
readMenuFolderInfo();
1933
emit disableAction();
1934
emit entrySelected(( MenuEntryInfo* ) 0 );
1937
void TreeView::updateTreeView(bool showHidden)
1939
m_showHidden = showHidden;
1942
delete m_rootFolder;
1945
m_layoutDirty = false;
1946
m_newMenuIds.clear();
1947
m_newDirectoryList.clear();
1949
m_rootFolder = new MenuFolderInfo;
1950
m_separator = new MenuSeparatorInfo;
1952
readMenuFolderInfo();
1955
emit disableAction();
1956
emit entrySelected(( MenuEntryInfo* ) 0 );
1959
void TreeView::sendReloadMenu()
1961
QDBusMessage message = QDBusMessage::createSignal("/kickoff", "org.kde.plasma", "reloadMenu");
1962
QDBusConnection::sessionBus().send(message);
1965
MenuItemMimeData::MenuItemMimeData(TreeItem *item)
1971
TreeItem *MenuItemMimeData::item() const
1976
QStringList MenuItemMimeData::formats() const
1978
QStringList formats;
1983
formats << s_internalMimeType;
1987
bool MenuItemMimeData::hasFormat(const QString &mimeType) const
1989
return m_item && mimeType == s_internalMimeType;
1992
QVariant MenuItemMimeData::retrieveData(const QString &mimeType, QVariant::Type type) const
1996
if (m_item && mimeType == s_internalMimeType) {
1997
return qVariantFromValue<TreeItem*>(m_item);