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.
26 #include <QDataStream>
30 #include <Qt3Support/Q3Header>
39 #include <QtDBus/QtDBus>
42 #include <kactioncollection.h>
43 #include <kapplication.h>
44 #include <kbuildsycocaprogressdialog.h>
46 #include <kdesktopfile.h>
48 #include <kiconloader.h>
49 #include <kinputdialog.h>
51 #include <kmessagebox.h>
53 #include <kservicegroup.h>
55 #include <kconfiggroup.h>
56 #include <kstandarddirs.h>
57 #include <k3multipledrag.h>
58 #include <k3urldrag.h>
59 #include <kio/netaccess.h>
62 #include "treeview.moc"
66 #define MOVE_FOLDER 'M'
67 #define COPY_FOLDER 'C'
70 #define COPY_SEPARATOR 'S'
72 TreeItem::TreeItem(Q3ListViewItem
*parent
, Q3ListViewItem
*after
, const QString
& menuId
, bool __init
)
73 :Q3ListViewItem(parent
, after
), _hidden(false), _init(__init
), _layoutDirty(false), _menuId(menuId
),
74 m_folderInfo(0), m_entryInfo(0) {}
76 TreeItem::TreeItem(Q3ListView
*parent
, Q3ListViewItem
*after
, const QString
& menuId
, bool __init
)
77 : Q3ListViewItem(parent
, after
), _hidden(false), _init(__init
), _layoutDirty(false), _menuId(menuId
),
78 m_folderInfo(0), m_entryInfo(0) {}
80 void TreeItem::setName(const QString
&name
)
86 void TreeItem::setHidden(bool b
)
88 if (_hidden
== b
) return;
93 void TreeItem::update()
97 s
+= i18n(" [Hidden]");
101 void TreeItem::setOpen(bool o
)
106 Q3ListViewItem::setOpen(o
);
109 void TreeItem::load()
111 if (m_folderInfo
&& !_init
)
114 TreeView
*tv
= static_cast<TreeView
*>(listView());
115 tv
->fillBranch(m_folderInfo
, this);
119 void TreeItem::paintCell ( QPainter
* p
, const QColorGroup
& cg
, int column
, int width
, int align
)
121 Q3ListViewItem::paintCell(p
, cg
, column
, width
, align
);
123 if (!m_folderInfo
&& !m_entryInfo
)
126 int h
= (height() / 2) -1;
128 p
->setPen( cg
.color( QPalette::HighlightedText
) );
130 p
->setPen( cg
.color( QPalette::Text
) );
136 void TreeItem::setup()
138 Q3ListViewItem::setup();
139 if (!m_folderInfo
&& !m_entryInfo
)
143 static QPixmap
appIcon(const QString
&iconName
)
145 QPixmap normal
= KIconLoader::global()->loadIcon(iconName
, KIconLoader::Small
, 0, KIconLoader::DefaultState
, QStringList(), 0L, true);
146 // make sure they are not larger than 20x20
147 if (normal
.width() > 20 || normal
.height() > 20)
149 QImage tmp
= normal
.toImage();
150 tmp
= tmp
.scaled(20, 20, Qt::IgnoreAspectRatio
, Qt::SmoothTransformation
);
151 normal
= QPixmap::fromImage(tmp
);
157 TreeView::TreeView( KActionCollection
*ac
, QWidget
*parent
, const char *name
)
158 : K3ListView(parent
), m_ac(ac
), m_rmb(0), m_clipboard(0),
159 m_clipboardFolderInfo(0), m_clipboardEntryInfo(0),
163 setFrameStyle(QFrame::WinPanel
| QFrame::Sunken
);
164 setAllColumnsShowFocus(true);
165 setRootIsDecorated(true);
167 setAcceptDrops(true);
168 setDropVisualizer(true);
169 setDragEnabled(true);
170 setMinimumWidth(240);
175 connect(this, SIGNAL(dropped(QDropEvent
*, Q3ListViewItem
*, Q3ListViewItem
*)),
176 SLOT(slotDropped(QDropEvent
*, Q3ListViewItem
*, Q3ListViewItem
*)));
178 connect(this, SIGNAL(clicked( Q3ListViewItem
* )),
179 SLOT(itemSelected( Q3ListViewItem
* )));
181 connect(this,SIGNAL(selectionChanged ( Q3ListViewItem
* )),
182 SLOT(itemSelected( Q3ListViewItem
* )));
184 connect(this, SIGNAL(rightButtonPressed(Q3ListViewItem
*, const QPoint
&, int)),
185 SLOT(slotRMBPressed(Q3ListViewItem
*, const QPoint
&)));
188 connect(m_ac
->action("newitem"), SIGNAL(activated()), SLOT(newitem()));
189 connect(m_ac
->action("newsubmenu"), SIGNAL(activated()), SLOT(newsubmenu()));
190 connect(m_ac
->action("newsep"), SIGNAL(activated()), SLOT(newsep()));
192 m_menuFile
= new MenuFile( KStandardDirs::locateLocal("xdgconf-menu", "applications-kmenuedit.menu"));
193 m_rootFolder
= new MenuFolderInfo
;
194 m_separator
= new MenuSeparatorInfo
;
197 // Read menu format configuration information
198 KSharedConfig::Ptr pConfig
= KSharedConfig::openConfig("kickerrc");
199 KConfigGroup
cg(pConfig
, "menus");
200 m_detailedMenuEntries
= cg
.readEntry("DetailedMenuEntries", true);
201 if (m_detailedMenuEntries
)
203 m_detailedEntriesNamesFirst
= cg
.readEntry("DetailedEntriesNamesFirst", false);
208 TreeView::~TreeView() {
214 void TreeView::setViewMode(bool showHidden
)
219 m_rmb
= new QMenu(this);
222 action
= m_ac
->action("edit_cut");
223 m_rmb
->addAction( action
);
224 action
->setEnabled(false);
225 connect(action
, SIGNAL(activated()), SLOT(cut()));
227 action
= m_ac
->action("edit_copy");
228 m_rmb
->addAction( action
);
229 action
->setEnabled(false);
230 connect(action
, SIGNAL(activated()), SLOT(copy()));
232 action
= m_ac
->action("edit_paste");
233 m_rmb
->addAction( action
);
234 action
->setEnabled(false);
235 connect(action
, SIGNAL(activated()), SLOT(paste()));
237 m_rmb
->addSeparator();
239 action
= m_ac
->action("delete");
240 m_rmb
->addAction( action
);
241 action
->setEnabled(false);
242 connect(action
, SIGNAL(activated()), SLOT(del()));
244 m_rmb
->addSeparator();
246 m_rmb
->addAction( m_ac
->action("newitem") );
247 m_rmb
->addAction( m_ac
->action("newsubmenu") );
248 m_rmb
->addAction( m_ac
->action("newsep") );
250 m_showHidden
= showHidden
;
251 readMenuFolderInfo();
255 void TreeView::readMenuFolderInfo(MenuFolderInfo
*folderInfo
, KServiceGroup::Ptr folder
, const QString
&prefix
)
259 folderInfo
= m_rootFolder
;
260 folder
= KServiceGroup::root();
263 if (!folder
|| !folder
->isValid())
266 folderInfo
->caption
= folder
->caption();
267 folderInfo
->comment
= folder
->comment();
269 // Item names may contain ampersands. To avoid them being converted
270 // to accelerators, replace them with two ampersands.
271 folderInfo
->hidden
= folder
->noDisplay();
272 folderInfo
->directoryFile
= folder
->directoryEntryPath();
273 folderInfo
->icon
= folder
->icon();
274 QString id
= folder
->relPath();
275 int i
= id
.lastIndexOf('/', -2);
278 folderInfo
->fullId
= prefix
+ id
;
280 foreach(const KSycocaEntry::Ptr
&e
, folder
->entries(true, !m_showHidden
, true, m_detailedMenuEntries
&& !m_detailedEntriesNamesFirst
))
282 if (e
->isType(KST_KServiceGroup
))
284 KServiceGroup::Ptr
g(KServiceGroup::Ptr::staticCast(e
));
285 MenuFolderInfo
*subFolderInfo
= new MenuFolderInfo();
286 readMenuFolderInfo(subFolderInfo
, g
, folderInfo
->fullId
);
287 folderInfo
->add(subFolderInfo
, true);
289 else if (e
->isType(KST_KService
))
291 folderInfo
->add(new MenuEntryInfo(KService::Ptr::staticCast(e
)), true);
293 else if (e
->isType(KST_KServiceSeparator
))
295 folderInfo
->add(m_separator
, true);
300 void TreeView::fill()
302 QApplication::setOverrideCursor(Qt::WaitCursor
);
304 fillBranch(m_rootFolder
, 0);
305 QApplication::restoreOverrideCursor();
308 QString
TreeView::findName(KDesktopFile
*df
, bool deleted
)
310 QString name
= df
->readName();
317 QString file
= df
->fileName();
318 QString res
= df
->resource();
321 const QStringList files
= KGlobal::dirs()->findAllResources(res
.toLatin1(), file
);
322 for(QStringList::ConstIterator it
= files
.constBegin();
323 it
!= files
.constEnd();
332 KDesktopFile
df2(*it
);
333 name
= df2
.readName();
335 if (!name
.isEmpty() && (name
!= "empty"))
343 TreeItem
*TreeView::createTreeItem(TreeItem
*parent
, Q3ListViewItem
*after
, MenuFolderInfo
*folderInfo
, bool _init
)
347 item
= new TreeItem(this, after
, QString(), _init
);
349 item
= new TreeItem(parent
, after
, QString(), _init
);
351 item
->setMenuFolderInfo(folderInfo
);
352 item
->setName(folderInfo
->caption
);
353 item
->setPixmap(0, appIcon(folderInfo
->icon
));
354 item
->setDirectoryPath(folderInfo
->fullId
);
355 item
->setHidden(folderInfo
->hidden
);
356 item
->setExpandable(true);
360 TreeItem
*TreeView::createTreeItem(TreeItem
*parent
, Q3ListViewItem
*after
, MenuEntryInfo
*entryInfo
, bool _init
)
362 bool hidden
= entryInfo
->hidden
;
366 item
= new TreeItem(this, after
, entryInfo
->menuId(), _init
);
368 item
= new TreeItem(parent
, after
, entryInfo
->menuId(),_init
);
372 if (m_detailedMenuEntries
&& entryInfo
->description
.length() != 0)
374 if (m_detailedEntriesNamesFirst
)
376 name
= entryInfo
->caption
+ " (" + entryInfo
->description
+ ')';
380 name
= entryInfo
->description
+ " (" + entryInfo
->caption
+ ')';
385 name
= entryInfo
->caption
;
387 item
->setMenuEntryInfo(entryInfo
);
389 item
->setPixmap(0, appIcon(entryInfo
->icon
));
391 item
->setHidden(hidden
);
395 TreeItem
*TreeView::createTreeItem(TreeItem
*parent
, Q3ListViewItem
*after
, MenuSeparatorInfo
*, bool _init
)
399 item
= new TreeItem(this, after
, QString(), _init
);
401 item
= new TreeItem(parent
, after
, QString(),_init
);
406 void TreeView::fillBranch(MenuFolderInfo
*folderInfo
, TreeItem
*parent
)
408 QString relPath
= parent
? parent
->directory() : QString();
409 Q3PtrListIterator
<MenuInfo
> it( folderInfo
->initialLayout
);
411 for (MenuInfo
*info
; (info
= it
.current()); ++it
)
413 MenuEntryInfo
*entry
= dynamic_cast<MenuEntryInfo
*>(info
);
416 after
= createTreeItem(parent
, after
, entry
);
420 MenuFolderInfo
*subFolder
= dynamic_cast<MenuFolderInfo
*>(info
);
423 after
= createTreeItem(parent
, after
, subFolder
);
426 MenuSeparatorInfo
*separator
= dynamic_cast<MenuSeparatorInfo
*>(info
);
429 after
= createTreeItem(parent
, after
, separator
);
435 void TreeView::closeAllItems(Q3ListViewItem
*item
)
440 item
->setOpen(false);
441 closeAllItems(item
->firstChild());
442 item
= item
->nextSibling();
446 void TreeView::selectMenu(const QString
&menu
)
448 closeAllItems(firstChild());
450 if (menu
.length() <= 1)
452 setCurrentItem(firstChild());
457 QString restMenu
= menu
;
458 if ( menu
.startsWith( '/' ) )
459 restMenu
= menu
.mid(1);
460 if (!restMenu
.endsWith('/'))
466 int i
= restMenu
.indexOf("/");
467 QString subMenu
= restMenu
.left(i
+1);
468 restMenu
= restMenu
.mid(i
+1);
470 item
= (TreeItem
*)(item
? item
->firstChild() : firstChild());
473 MenuFolderInfo
*folderInfo
= item
->folderInfo();
474 if (folderInfo
&& (folderInfo
->id
== subMenu
))
479 item
= (TreeItem
*) item
->nextSibling();
482 while( item
&& !restMenu
.isEmpty());
486 setCurrentItem(item
);
487 ensureItemVisible(item
);
491 void TreeView::selectMenuEntry(const QString
&menuEntry
)
493 TreeItem
*item
= (TreeItem
*) selectedItem();
496 item
= (TreeItem
*) currentItem();
497 while (item
&& item
->isDirectory())
498 item
= (TreeItem
*) item
->nextSibling();
501 item
= (TreeItem
*) item
->firstChild();
505 MenuEntryInfo
*entry
= item
->entryInfo();
508 kDebug()<<" entry->menuId() :"<<entry
->menuId();
509 if ( entry
->menuId() == menuEntry
)
511 setCurrentItem(item
);
512 ensureItemVisible(item
);
516 item
= (TreeItem
*) item
->nextSibling();
520 void TreeView::itemSelected(Q3ListViewItem
*item
)
522 TreeItem
*_item
= (TreeItem
*)item
;
523 bool selected
= false;
524 bool dselected
= false;
527 dselected
= _item
->isHidden();
530 m_ac
->action("edit_cut")->setEnabled(selected
);
531 m_ac
->action("edit_copy")->setEnabled(selected
);
533 if (m_ac
->action("delete"))
534 m_ac
->action("delete")->setEnabled(selected
&& !dselected
);
538 emit
disableAction();
542 if (_item
->isDirectory())
543 emit
entrySelected(_item
->folderInfo());
545 emit
entrySelected(_item
->entryInfo());
548 void TreeView::currentChanged(MenuFolderInfo
*folderInfo
)
550 TreeItem
*item
= (TreeItem
*)selectedItem();
551 if (item
== 0) return;
552 if (folderInfo
== 0) return;
554 item
->setName(folderInfo
->caption
);
555 item
->setPixmap(0, appIcon(folderInfo
->icon
));
558 void TreeView::currentChanged(MenuEntryInfo
*entryInfo
)
560 TreeItem
*item
= (TreeItem
*)selectedItem();
561 if (item
== 0) return;
562 if (entryInfo
== 0) return;
566 if (m_detailedMenuEntries
&& entryInfo
->description
.length() != 0)
568 if (m_detailedEntriesNamesFirst
)
570 name
= entryInfo
->caption
+ " (" + entryInfo
->description
+ ')';
574 name
= entryInfo
->description
+ " (" + entryInfo
->caption
+ ')';
579 name
= entryInfo
->caption
;
582 item
->setPixmap(0, appIcon(entryInfo
->icon
));
585 QStringList
TreeView::fileList(const QString
& rPath
)
587 QString relativePath
= rPath
;
589 // truncate "/.directory"
590 int pos
= relativePath
.lastIndexOf("/.directory");
591 if (pos
> 0) relativePath
.truncate(pos
);
593 QStringList filelist
;
595 // loop through all resource dirs and build a file list
596 const QStringList resdirlist
= KGlobal::dirs()->resourceDirs("apps");
597 for (QStringList::ConstIterator it
= resdirlist
.constBegin(); it
!= resdirlist
.constEnd(); ++it
)
599 QDir
dir((*it
) + '/' + relativePath
);
600 if(!dir
.exists()) continue;
602 dir
.setFilter(QDir::Files
);
603 dir
.setNameFilters(QStringList() << "*.desktop;*.kdelnk");
605 // build a list of files
606 const QStringList files
= dir
.entryList();
607 for (QStringList::ConstIterator it
= files
.constBegin(); it
!= files
.constEnd(); ++it
) {
609 //if (filelist.contains(*it)) continue;
611 if (relativePath
.isEmpty()) {
612 filelist
.removeAll(*it
); // hack
613 filelist
.append(*it
);
616 filelist
.removeAll(relativePath
+ '/' + *it
); //hack
617 filelist
.append(relativePath
+ '/' + *it
);
624 QStringList
TreeView::dirList(const QString
& rPath
)
626 QString relativePath
= rPath
;
628 // truncate "/.directory"
629 int pos
= relativePath
.lastIndexOf("/.directory");
630 if (pos
> 0) relativePath
.truncate(pos
);
634 // loop through all resource dirs and build a subdir list
635 const QStringList resdirlist
= KGlobal::dirs()->resourceDirs("apps");
636 for (QStringList::ConstIterator it
= resdirlist
.constBegin(); it
!= resdirlist
.constEnd(); ++it
)
638 QDir
dir((*it
) + '/' + relativePath
);
639 if(!dir
.exists()) continue;
640 dir
.setFilter(QDir::Dirs
);
642 // build a list of subdirs
643 const QStringList subdirs
= dir
.entryList();
644 for (QStringList::ConstIterator it
= subdirs
.constBegin(); it
!= subdirs
.constEnd(); ++it
) {
645 if ((*it
) == "." || (*it
) == "..") continue;
647 // if (dirlist.contains(*it)) continue;
649 if (relativePath
.isEmpty()) {
650 dirlist
.removeAll(*it
); //hack
654 dirlist
.removeAll(relativePath
+ '/' + *it
); //hack
655 dirlist
.append(relativePath
+ '/' + *it
);
662 bool TreeView::acceptDrag(QDropEvent
* e
) const
664 if (e
->provides("application/x-kmenuedit-internal") &&
665 (e
->source() == const_cast<TreeView
*>(this)))
668 if (K3URLDrag::decode(e
, urls
) && (urls
.count() == 1) &&
669 urls
[0].isLocalFile() && urls
[0].path().endsWith(".desktop"))
675 static QString
createDesktopFile(const QString
&file
, QString
*menuId
, QStringList
*excludeList
)
677 QString base
= file
.mid(file
.lastIndexOf('/')+1);
678 base
= base
.left(base
.lastIndexOf('.'));
680 QRegExp
r("(.*)(?=-\\d+)");
681 base
= (r
.indexIn(base
) > -1) ? r
.cap(1) : base
;
683 QString result
= KService::newServicePath(true, base
, menuId
, excludeList
);
684 excludeList
->append(*menuId
);
685 // Todo for Undo-support: Undo menuId allocation:
690 static KDesktopFile
*copyDesktopFile(MenuEntryInfo
*entryInfo
, QString
*menuId
, QStringList
*excludeList
)
692 QString result
= createDesktopFile(entryInfo
->file(), menuId
, excludeList
);
693 KDesktopFile
*df
= entryInfo
->desktopFile()->copyTo(result
);
694 df
->desktopGroup().deleteEntry("Categories"); // Don't set any categories!
699 static QString
createDirectoryFile(const QString
&file
, QStringList
*excludeList
)
701 QString base
= file
.mid(file
.lastIndexOf('/')+1);
702 base
= base
.left(base
.lastIndexOf('.'));
709 result
= base
+ ".directory";
711 result
= base
+ QString("-%1.directory").arg(i
);
713 if (!excludeList
->contains(result
))
715 if (KStandardDirs::locate("xdgdata-dirs", result
).isEmpty())
720 excludeList
->append(result
);
721 result
= KStandardDirs::locateLocal("xdgdata-dirs", result
);
726 void TreeView::slotDropped (QDropEvent
* e
, Q3ListViewItem
*parent
, Q3ListViewItem
*after
)
730 // get destination folder
731 TreeItem
*parentItem
= static_cast<TreeItem
*>(parent
);
732 QString folder
= parentItem
? parentItem
->directory() : QString();
733 MenuFolderInfo
*parentFolderInfo
= parentItem
? parentItem
->folderInfo() : m_rootFolder
;
735 if (e
->source() != this)
739 if (!K3URLDrag::decode(e
, urls
) || (urls
.count() != 1) || !urls
[0].isLocalFile())
741 QString path
= urls
[0].path();
742 if (!path
.endsWith(".desktop"))
746 QString result
= createDesktopFile(path
, &menuId
, &m_newMenuIds
);
747 KDesktopFile
orig_df(path
);
748 KDesktopFile
*df
= orig_df
.copyTo(result
);
749 df
->desktopGroup().deleteEntry("Categories"); // Don't set any categories!
751 KService::Ptr
s(new KService(df
));
752 s
->setMenuId(menuId
);
754 MenuEntryInfo
*entryInfo
= new MenuEntryInfo(s
, df
);
756 QString oldCaption
= entryInfo
->caption
;
757 QString newCaption
= parentFolderInfo
->uniqueItemCaption(oldCaption
, oldCaption
);
758 entryInfo
->setCaption(newCaption
);
761 // m_menuFile->addEntry(folder, menuId);
762 m_menuFile
->pushAction(MenuFile::ADD_ENTRY
, folder
, menuId
);
764 // create the TreeItem
766 parentItem
->setOpen(true);
768 // update fileInfo data
769 parentFolderInfo
->add(entryInfo
);
771 TreeItem
*newItem
= createTreeItem(parentItem
, after
, entryInfo
, true);
773 setSelected ( newItem
, true);
774 itemSelected( newItem
);
777 setLayoutDirty(parentItem
);
781 // is there content in the clipboard?
784 if (m_dragItem
== after
) return; // Nothing to do
786 int command
= m_drag
;
787 if (command
== MOVE_FOLDER
)
789 MenuFolderInfo
*folderInfo
= m_dragInfo
;
790 if (e
->action() == QDropEvent::Copy
)
792 // Ugh.. this is hard :)
793 // * Create new .directory file
798 TreeItem
*tmpItem
= static_cast<TreeItem
*>(parentItem
);
801 if ( tmpItem
== m_dragItem
)
806 tmpItem
= static_cast<TreeItem
*>(tmpItem
->parent() );
809 // Remove MenuFolderInfo
810 TreeItem
*oldParentItem
= static_cast<TreeItem
*>(m_dragItem
->parent());
811 MenuFolderInfo
*oldParentFolderInfo
= oldParentItem
? oldParentItem
->folderInfo() : m_rootFolder
;
812 oldParentFolderInfo
->take(folderInfo
);
815 QString oldFolder
= folderInfo
->fullId
;
816 QString folderName
= folderInfo
->id
;
817 QString newFolder
= m_menuFile
->uniqueMenuName(folder
, folderName
, parentFolderInfo
->existingMenuIds());
818 folderInfo
->id
= newFolder
;
821 //m_menuFile->moveMenu(oldFolder, folder + newFolder);
822 m_menuFile
->pushAction(MenuFile::MOVE_MENU
, oldFolder
, folder
+ newFolder
);
824 // Make sure caption is unique
825 QString newCaption
= parentFolderInfo
->uniqueMenuCaption(folderInfo
->caption
);
826 if (newCaption
!= folderInfo
->caption
)
828 folderInfo
->setCaption(newCaption
);
831 // create the TreeItem
833 parentItem
->setOpen(true);
835 // update fileInfo data
836 folderInfo
->updateFullId(parentFolderInfo
->fullId
);
837 folderInfo
->setInUse(true);
838 parentFolderInfo
->add(folderInfo
);
840 if ((parentItem
!= oldParentItem
) || !after
)
843 oldParentItem
->takeItem(m_dragItem
);
845 takeItem(m_dragItem
);
847 parentItem
->insertItem(m_dragItem
);
849 insertItem(m_dragItem
);
851 m_dragItem
->moveItem(after
);
852 m_dragItem
->setName(folderInfo
->caption
);
853 m_dragItem
->setDirectoryPath(folderInfo
->fullId
);
854 setSelected(m_dragItem
, true);
855 itemSelected(m_dragItem
);
858 else if (command
== MOVE_FILE
)
860 MenuEntryInfo
*entryInfo
= m_dragItem
->entryInfo();
861 QString menuId
= entryInfo
->menuId();
863 if (e
->action() == QDropEvent::Copy
)
866 // Need to copy file and then add it
867 KDesktopFile
*df
= copyDesktopFile(entryInfo
, &menuId
, &m_newMenuIds
); // Duplicate
868 //UNDO-ACTION: NEW_MENU_ID (menuId)
870 KService::Ptr
s(new KService(df
));
871 s
->setMenuId(menuId
);
873 entryInfo
= new MenuEntryInfo(s
, df
);
875 QString oldCaption
= entryInfo
->caption
;
876 QString newCaption
= parentFolderInfo
->uniqueItemCaption(oldCaption
, oldCaption
);
877 entryInfo
->setCaption(newCaption
);
881 del(m_dragItem
, false);
882 QString oldCaption
= entryInfo
->caption
;
883 QString newCaption
= parentFolderInfo
->uniqueItemCaption(oldCaption
);
884 entryInfo
->setCaption(newCaption
);
885 entryInfo
->setInUse(true);
888 // m_menuFile->addEntry(folder, menuId);
889 m_menuFile
->pushAction(MenuFile::ADD_ENTRY
, folder
, menuId
);
891 // create the TreeItem
893 parentItem
->setOpen(true);
895 // update fileInfo data
896 parentFolderInfo
->add(entryInfo
);
898 TreeItem
*newItem
= createTreeItem(parentItem
, after
, entryInfo
, true);
900 setSelected ( newItem
, true);
901 itemSelected( newItem
);
903 else if (command
== COPY_SEPARATOR
)
905 if (e
->action() != QDropEvent::Copy
)
906 del(m_dragItem
, false);
908 TreeItem
*newItem
= createTreeItem(parentItem
, after
, m_separator
, true);
910 setSelected ( newItem
, true);
911 itemSelected( newItem
);
918 setLayoutDirty(parentItem
);
922 void TreeView::startDrag()
924 Q3DragObject
*drag
= dragObject();
932 Q3DragObject
*TreeView::dragObject()
935 TreeItem
*item
= (TreeItem
*)selectedItem();
936 if(item
== 0) return 0;
938 K3MultipleDrag
*drag
= new K3MultipleDrag( this );
940 if (item
->isDirectory())
942 m_drag
= MOVE_FOLDER
;
943 m_dragInfo
= item
->folderInfo();
946 else if (item
->isEntry())
951 QString menuId
= item
->menuId();
952 m_dragPath
= item
->entryInfo()->service
->entryPath();
953 if (!m_dragPath
.isEmpty())
954 m_dragPath
= KStandardDirs::locate("apps", m_dragPath
);
955 if (!m_dragPath
.isEmpty())
958 url
.setPath(m_dragPath
);
959 drag
->addDragObject( new K3URLDrag(url
, 0));
964 m_drag
= COPY_SEPARATOR
;
969 drag
->addDragObject( new Q3StoredDrag("application/x-kmenuedit-internal", 0));
970 if ( item
->pixmap(0) )
971 drag
->setPixmap(*item
->pixmap(0));
975 void TreeView::slotRMBPressed(Q3ListViewItem
*, const QPoint
& p
)
977 TreeItem
*item
= (TreeItem
*)selectedItem();
978 if(item
== 0) return;
980 if(m_rmb
) m_rmb
->exec(p
);
983 void TreeView::newsubmenu()
985 TreeItem
*parentItem
= 0;
986 TreeItem
*item
= (TreeItem
*)selectedItem();
989 QString caption
= KInputDialog::getText( i18n( "New Submenu" ),
990 i18n( "Submenu name:" ), QString(), &ok
, this );
994 QString file
= caption
;
995 file
.replace('/', '-');
997 file
= createDirectoryFile(file
, &m_newDirectoryList
); // Create
999 // get destination folder
1007 else if(item
->isDirectory())
1011 folder
= parentItem
->directory();
1015 parentItem
= static_cast<TreeItem
*>(item
->parent());
1016 folder
= parentItem
? parentItem
->directory() : QString();
1019 MenuFolderInfo
*parentFolderInfo
= parentItem
? parentItem
->folderInfo() : m_rootFolder
;
1020 MenuFolderInfo
*folderInfo
= new MenuFolderInfo();
1021 folderInfo
->caption
= parentFolderInfo
->uniqueMenuCaption(caption
);
1022 folderInfo
->id
= m_menuFile
->uniqueMenuName(folder
, caption
, parentFolderInfo
->existingMenuIds());
1023 folderInfo
->directoryFile
= file
;
1024 folderInfo
->icon
= "package";
1025 folderInfo
->hidden
= false;
1026 folderInfo
->setDirty();
1028 KDesktopFile
*df
= new KDesktopFile(file
);
1029 KConfigGroup desktopGroup
= df
->desktopGroup();
1030 desktopGroup
.writeEntry("Name", folderInfo
->caption
);
1031 desktopGroup
.writeEntry("Icon", folderInfo
->icon
);
1035 // m_menuFile->addMenu(folder + folderInfo->id, file);
1036 m_menuFile
->pushAction(MenuFile::ADD_MENU
, folder
+ folderInfo
->id
, file
);
1038 folderInfo
->fullId
= parentFolderInfo
->fullId
+ folderInfo
->id
;
1040 // create the TreeItem
1042 parentItem
->setOpen(true);
1044 // update fileInfo data
1045 parentFolderInfo
->add(folderInfo
);
1047 TreeItem
*newItem
= createTreeItem(parentItem
, item
, folderInfo
, true);
1049 setSelected ( newItem
, true);
1050 itemSelected( newItem
);
1052 setLayoutDirty(parentItem
);
1055 void TreeView::newitem()
1057 TreeItem
*parentItem
= 0;
1058 TreeItem
*item
= (TreeItem
*)selectedItem();
1061 QString caption
= KInputDialog::getText( i18n( "New Item" ),
1062 i18n( "Item name:" ), QString(), &ok
, this );
1067 QString file
= caption
;
1068 file
.replace('/', '-');
1070 file
= createDesktopFile(file
, &menuId
, &m_newMenuIds
); // Create
1072 KDesktopFile
*df
= new KDesktopFile(file
);
1073 KConfigGroup desktopGroup
= df
->desktopGroup();
1074 desktopGroup
.writeEntry("Name", caption
);
1075 desktopGroup
.writeEntry("Type", "Application");
1077 // get destination folder
1085 else if(item
->isDirectory())
1089 folder
= parentItem
->directory();
1093 parentItem
= static_cast<TreeItem
*>(item
->parent());
1094 folder
= parentItem
? parentItem
->directory() : QString();
1097 MenuFolderInfo
*parentFolderInfo
= parentItem
? parentItem
->folderInfo() : m_rootFolder
;
1100 // m_menuFile->addEntry(folder, menuId);
1101 m_menuFile
->pushAction(MenuFile::ADD_ENTRY
, folder
, menuId
);
1103 KService::Ptr
s(new KService(df
));
1104 s
->setMenuId(menuId
);
1106 MenuEntryInfo
*entryInfo
= new MenuEntryInfo(s
, df
);
1108 // create the TreeItem
1110 parentItem
->setOpen(true);
1112 // update fileInfo data
1113 parentFolderInfo
->add(entryInfo
);
1115 TreeItem
*newItem
= createTreeItem(parentItem
, item
, entryInfo
, true);
1117 setSelected ( newItem
, true);
1118 itemSelected( newItem
);
1120 setLayoutDirty(parentItem
);
1123 void TreeView::newsep()
1125 TreeItem
*parentItem
= 0;
1126 TreeItem
*item
= (TreeItem
*)selectedItem();
1132 else if(item
->isDirectory())
1139 parentItem
= static_cast<TreeItem
*>(item
->parent());
1142 // create the TreeItem
1144 parentItem
->setOpen(true);
1146 TreeItem
*newItem
= createTreeItem(parentItem
, item
, m_separator
, true);
1148 setSelected ( newItem
, true);
1149 itemSelected( newItem
);
1151 setLayoutDirty(parentItem
);
1154 void TreeView::cut()
1158 m_ac
->action("edit_cut")->setEnabled(false);
1159 m_ac
->action("edit_copy")->setEnabled(false);
1160 m_ac
->action("delete")->setEnabled(false);
1162 // Select new current item
1163 setSelected( currentItem(), true );
1164 // Switch the UI to show that item
1165 itemSelected( selectedItem() );
1168 void TreeView::copy()
1173 void TreeView::copy( bool cutting
)
1175 TreeItem
*item
= (TreeItem
*)selectedItem();
1177 // nil selected? -> nil to copy
1178 if (item
== 0) return;
1181 setLayoutDirty((TreeItem
*)item
->parent());
1183 // clean up old stuff
1186 // is item a folder or a file?
1187 if(item
->isDirectory())
1189 QString folder
= item
->directory();
1192 // Place in clipboard
1193 m_clipboard
= MOVE_FOLDER
;
1194 m_clipboardFolderInfo
= item
->folderInfo();
1200 // Place in clipboard
1201 m_clipboard
= COPY_FOLDER
;
1202 m_clipboardFolderInfo
= item
->folderInfo();
1205 else if (item
->isEntry())
1209 // Place in clipboard
1210 m_clipboard
= MOVE_FILE
;
1211 m_clipboardEntryInfo
= item
->entryInfo();
1217 // Place in clipboard
1218 m_clipboard
= COPY_FILE
;
1219 m_clipboardEntryInfo
= item
->entryInfo();
1224 // Place in clipboard
1225 m_clipboard
= COPY_SEPARATOR
;
1230 m_ac
->action("edit_paste")->setEnabled(true);
1234 void TreeView::paste()
1236 TreeItem
*parentItem
= 0;
1237 TreeItem
*item
= (TreeItem
*)selectedItem();
1239 // nil selected? -> nil to paste to
1240 if (item
== 0) return;
1242 // is there content in the clipboard?
1243 if (!m_clipboard
) return;
1245 // get destination folder
1248 if(item
->isDirectory())
1252 folder
= parentItem
->directory();
1256 parentItem
= static_cast<TreeItem
*>(item
->parent());
1257 folder
= parentItem
? parentItem
->directory() : QString();
1260 MenuFolderInfo
*parentFolderInfo
= parentItem
? parentItem
->folderInfo() : m_rootFolder
;
1261 int command
= m_clipboard
;
1262 if ((command
== COPY_FOLDER
) || (command
== MOVE_FOLDER
))
1264 MenuFolderInfo
*folderInfo
= m_clipboardFolderInfo
;
1265 if (command
== COPY_FOLDER
)
1267 // Ugh.. this is hard :)
1268 // * Create new .directory file
1271 else if (command
== MOVE_FOLDER
)
1274 QString oldFolder
= folderInfo
->fullId
;
1275 QString folderName
= folderInfo
->id
;
1276 QString newFolder
= m_menuFile
->uniqueMenuName(folder
, folderName
, parentFolderInfo
->existingMenuIds());
1277 folderInfo
->id
= newFolder
;
1280 // m_menuFile->moveMenu(oldFolder, folder + newFolder);
1281 m_menuFile
->pushAction(MenuFile::MOVE_MENU
, oldFolder
, folder
+ newFolder
);
1283 // Make sure caption is unique
1284 QString newCaption
= parentFolderInfo
->uniqueMenuCaption(folderInfo
->caption
);
1285 if (newCaption
!= folderInfo
->caption
)
1287 folderInfo
->setCaption(newCaption
);
1289 // create the TreeItem
1291 parentItem
->setOpen(true);
1293 // update fileInfo data
1294 folderInfo
->fullId
= parentFolderInfo
->fullId
+ folderInfo
->id
;
1295 folderInfo
->setInUse(true);
1296 parentFolderInfo
->add(folderInfo
);
1298 TreeItem
*newItem
= createTreeItem(parentItem
, item
, folderInfo
);
1300 setSelected ( newItem
, true);
1301 itemSelected( newItem
);
1304 m_clipboard
= COPY_FOLDER
; // Next one copies.
1306 else if ((command
== COPY_FILE
) || (command
== MOVE_FILE
))
1308 MenuEntryInfo
*entryInfo
= m_clipboardEntryInfo
;
1311 if (command
== COPY_FILE
)
1313 // Need to copy file and then add it
1314 KDesktopFile
*df
= copyDesktopFile(entryInfo
, &menuId
, &m_newMenuIds
); // Duplicate
1316 KService::Ptr
s(new KService(df
));
1317 s
->setMenuId(menuId
);
1318 entryInfo
= new MenuEntryInfo(s
, df
);
1320 QString oldCaption
= entryInfo
->caption
;
1321 QString newCaption
= parentFolderInfo
->uniqueItemCaption(oldCaption
, oldCaption
);
1322 entryInfo
->setCaption(newCaption
);
1324 else if (command
== MOVE_FILE
)
1326 menuId
= entryInfo
->menuId();
1327 m_clipboard
= COPY_FILE
; // Next one copies.
1329 QString oldCaption
= entryInfo
->caption
;
1330 QString newCaption
= parentFolderInfo
->uniqueItemCaption(oldCaption
);
1331 entryInfo
->setCaption(newCaption
);
1332 entryInfo
->setInUse(true);
1335 // m_menuFile->addEntry(folder, menuId);
1336 m_menuFile
->pushAction(MenuFile::ADD_ENTRY
, folder
, menuId
);
1338 // create the TreeItem
1340 parentItem
->setOpen(true);
1342 // update fileInfo data
1343 parentFolderInfo
->add(entryInfo
);
1345 TreeItem
*newItem
= createTreeItem(parentItem
, item
, entryInfo
, true);
1347 setSelected ( newItem
, true);
1348 itemSelected( newItem
);
1354 parentItem
->setOpen(true);
1356 TreeItem
*newItem
= createTreeItem(parentItem
, item
, m_separator
, true);
1358 setSelected ( newItem
, true);
1359 itemSelected( newItem
);
1361 setLayoutDirty(parentItem
);
1364 void TreeView::del()
1366 TreeItem
*item
= (TreeItem
*)selectedItem();
1368 // nil selected? -> nil to delete
1369 if (item
== 0) return;
1373 m_ac
->action("edit_cut")->setEnabled(false);
1374 m_ac
->action("edit_copy")->setEnabled(false);
1375 m_ac
->action("delete")->setEnabled(false);
1376 // Select new current item
1377 setSelected( currentItem(), true );
1378 // Switch the UI to show that item
1379 itemSelected( selectedItem() );
1382 void TreeView::del(TreeItem
*item
, bool deleteInfo
)
1384 TreeItem
*parentItem
= static_cast<TreeItem
*>(item
->parent());
1385 // is file a .directory or a .desktop file
1386 if(item
->isDirectory())
1388 if ( KMessageBox::warningYesNo(this, i18n("All submenus of '%1' will be removed. Do you want to continue?", item
->name() ) ) == KMessageBox::No
)
1391 MenuFolderInfo
*folderInfo
= item
->folderInfo();
1393 // Remove MenuFolderInfo
1394 MenuFolderInfo
*parentFolderInfo
= parentItem
? parentItem
->folderInfo() : m_rootFolder
;
1395 parentFolderInfo
->take(folderInfo
);
1396 folderInfo
->setInUse(false);
1398 if (m_clipboard
== COPY_FOLDER
&& (m_clipboardFolderInfo
== folderInfo
))
1400 // Copy + Del == Cut
1401 m_clipboard
= MOVE_FOLDER
; // Clipboard now owns folderInfo
1406 if (folderInfo
->takeRecursive(m_clipboardFolderInfo
))
1407 m_clipboard
= MOVE_FOLDER
; // Clipboard now owns m_clipboardFolderInfo
1410 delete folderInfo
; // Delete folderInfo
1414 // m_menuFile->removeMenu(item->directory());
1415 m_menuFile
->pushAction(MenuFile::REMOVE_MENU
, item
->directory(), QString());
1420 else if (item
->isEntry())
1422 MenuEntryInfo
*entryInfo
= item
->entryInfo();
1423 QString menuId
= entryInfo
->menuId();
1425 // Remove MenuFolderInfo
1426 MenuFolderInfo
*parentFolderInfo
= parentItem
? parentItem
->folderInfo() : m_rootFolder
;
1427 parentFolderInfo
->take(entryInfo
);
1428 entryInfo
->setInUse(false);
1430 if (m_clipboard
== COPY_FILE
&& (m_clipboardEntryInfo
== entryInfo
))
1432 // Copy + Del == Cut
1433 m_clipboard
= MOVE_FILE
; // Clipboard now owns entryInfo
1438 delete entryInfo
; // Delete entryInfo
1442 QString folder
= parentItem
? parentItem
->directory() : QString();
1443 // m_menuFile->removeEntry(folder, menuId);
1444 m_menuFile
->pushAction(MenuFile::REMOVE_ENTRY
, folder
, menuId
);
1454 setLayoutDirty(parentItem
);
1457 void TreeView::cleanupClipboard() {
1458 if (m_clipboard
== MOVE_FOLDER
)
1459 delete m_clipboardFolderInfo
;
1460 m_clipboardFolderInfo
= 0;
1462 if (m_clipboard
== MOVE_FILE
)
1463 delete m_clipboardEntryInfo
;
1464 m_clipboardEntryInfo
= 0;
1469 static QStringList
extractLayout(TreeItem
*item
)
1471 bool firstFolder
= true;
1472 bool firstEntry
= true;
1474 for(;item
; item
= static_cast<TreeItem
*>(item
->nextSibling()))
1476 if (item
->isDirectory())
1480 firstFolder
= false;
1481 layout
<< ":M"; // Add new folders here...
1483 layout
<< (item
->folderInfo()->id
);
1485 else if (item
->isEntry())
1490 layout
<< ":F"; // Add new entries here...
1492 layout
<< (item
->entryInfo()->menuId());
1502 QStringList
TreeItem::layout()
1504 QStringList layout
= extractLayout(static_cast<TreeItem
*>(firstChild()));
1505 _layoutDirty
= false;
1509 void TreeView::saveLayout()
1513 QStringList layout
= extractLayout(static_cast<TreeItem
*>(firstChild()));
1514 m_menuFile
->setLayout(m_rootFolder
->fullId
, layout
);
1515 m_layoutDirty
= false;
1518 Q3PtrList
<Q3ListViewItem
> lst
;
1519 Q3ListViewItemIterator
it( this );
1520 while ( it
.current() ) {
1521 TreeItem
*item
= static_cast<TreeItem
*>(it
.current());
1522 if ( item
->isLayoutDirty() )
1524 m_menuFile
->setLayout(item
->folderInfo()->fullId
, item
->layout());
1530 bool TreeView::save()
1533 m_rootFolder
->save(m_menuFile
);
1535 bool success
= m_menuFile
->performAllActions();
1537 m_newMenuIds
.clear();
1538 m_newDirectoryList
.clear();
1542 KBuildSycocaProgressDialog::rebuildKSycoca(this);
1546 KMessageBox::sorry(this, "<qt>"+i18n("Menu changes could not be saved because of the following problem:")+"<br><br>"+
1547 m_menuFile
->error()+"</qt>");
1555 void TreeView::setLayoutDirty(TreeItem
*parentItem
)
1558 parentItem
->setLayoutDirty();
1560 m_layoutDirty
= true;
1563 bool TreeView::isLayoutDirty()
1565 Q3PtrList
<Q3ListViewItem
> lst
;
1566 Q3ListViewItemIterator
it( this );
1567 while ( it
.current() ) {
1568 if ( static_cast<TreeItem
*>(it
.current())->isLayoutDirty() )
1575 bool TreeView::dirty()
1577 return m_layoutDirty
|| m_rootFolder
->hasDirt() || m_menuFile
->dirty() || isLayoutDirty();
1580 void TreeView::findServiceShortcut(const KShortcut
&cut
, KService::Ptr
&service
)
1582 service
= m_rootFolder
->findServiceShortcut(cut
);
1585 void TreeView::restoreMenuSystem()
1587 if ( KMessageBox::warningYesNo( this, i18n( "Do you want to restore the system menu? Warning: This will remove all custom menus." ) )==KMessageBox::No
)
1589 QString kmenueditfile
= KStandardDirs::locateLocal("xdgconf-menu", "applications-kmenuedit.menu");
1590 if ( QFile::exists( kmenueditfile
) )
1592 if ( !QFile::remove( kmenueditfile
) )
1593 qWarning()<<"Could not delete "<<kmenueditfile
;
1596 QString xdgdir
= KGlobal::dirs()->KStandardDirs::localxdgdatadir();
1597 if ( !KIO::NetAccess::del( xdgdir
+ "/applications" , this) )
1598 qWarning()<<"Could not delete dir :"<<( xdgdir
+"/applications" );
1599 if ( !KIO::NetAccess::del( xdgdir
+"/desktop-directories" , this) )
1600 qWarning()<<"Could not delete dir :"<<( xdgdir
+ "/desktop-directories");
1602 KBuildSycocaProgressDialog::rebuildKSycoca(this);
1605 delete m_rootFolder
;
1608 m_layoutDirty
= false;
1609 m_newMenuIds
.clear();
1610 m_newDirectoryList
.clear();
1611 m_menuFile
->restoreMenuSystem(kmenueditfile
);
1613 m_rootFolder
= new MenuFolderInfo
;
1614 m_separator
= new MenuSeparatorInfo
;
1616 readMenuFolderInfo();
1619 emit
disableAction();
1620 emit
entrySelected(( MenuEntryInfo
* ) 0 );
1623 void TreeView::updateTreeView(bool showHidden
)
1625 m_showHidden
= showHidden
;
1628 delete m_rootFolder
;
1631 m_layoutDirty
= false;
1632 m_newMenuIds
.clear();
1633 m_newDirectoryList
.clear();
1635 m_rootFolder
= new MenuFolderInfo
;
1636 m_separator
= new MenuSeparatorInfo
;
1638 readMenuFolderInfo();
1641 emit
disableAction();
1642 emit
entrySelected(( MenuEntryInfo
* ) 0 );
1645 void TreeView::sendReloadMenu()
1647 QDBusMessage message
=
1648 QDBusMessage::createSignal("/kickoff", "org.kde.plasma", "reloadMenu");
1649 QDBusConnection::sessionBus().send(message
);