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