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>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include <QDataStream>
27 #include <Qt3Support/Q3ColorDrag>
30 #include <Qt3Support/Q3Header>
41 #include <kactioncollection.h>
42 #include <kapplication.h>
43 #include <kbuildsycocaprogressdialog.h>
45 #include <kdesktopfile.h>
47 #include <kiconloader.h>
48 #include <kinputdialog.h>
50 #include <kmessagebox.h>
52 #include <kservicegroup.h>
54 #include <kconfiggroup.h>
55 #include <kstandarddirs.h>
56 #include <k3multipledrag.h>
57 #include <k3urldrag.h>
60 #include "treeview.moc"
65 #define MOVE_FOLDER 'M'
66 #define COPY_FOLDER 'C'
69 #define COPY_SEPARATOR 'S'
71 TreeItem::TreeItem(Q3ListViewItem
*parent
, Q3ListViewItem
*after
, const QString
& menuId
, bool __init
)
72 :Q3ListViewItem(parent
, after
), _hidden(false), _init(__init
), _layoutDirty(false), _menuId(menuId
),
73 m_folderInfo(0), m_entryInfo(0) {}
75 TreeItem::TreeItem(Q3ListView
*parent
, Q3ListViewItem
*after
, const QString
& menuId
, bool __init
)
76 : Q3ListViewItem(parent
, after
), _hidden(false), _init(__init
), _layoutDirty(false), _menuId(menuId
),
77 m_folderInfo(0), m_entryInfo(0) {}
79 void TreeItem::setName(const QString
&name
)
85 void TreeItem::setHidden(bool b
)
87 if (_hidden
== b
) return;
92 void TreeItem::update()
96 s
+= i18n(" [Hidden]");
100 void TreeItem::setOpen(bool o
)
105 Q3ListViewItem::setOpen(o
);
108 void TreeItem::load()
110 if (m_folderInfo
&& !_init
)
113 TreeView
*tv
= static_cast<TreeView
*>(listView());
114 tv
->fillBranch(m_folderInfo
, this);
118 void TreeItem::paintCell ( QPainter
* p
, const QColorGroup
& cg
, int column
, int width
, int align
)
120 Q3ListViewItem::paintCell(p
, cg
, column
, width
, align
);
122 if (!m_folderInfo
&& !m_entryInfo
)
125 int h
= (height() / 2) -1;
127 p
->setPen( cg
.color( QPalette::HighlightedText
) );
129 p
->setPen( cg
.color( QPalette::Text
) );
135 void TreeItem::setup()
137 Q3ListViewItem::setup();
138 if (!m_folderInfo
&& !m_entryInfo
)
142 static QPixmap
appIcon(const QString
&iconName
)
144 QPixmap normal
= KIconLoader::global()->loadIcon(iconName
, KIconLoader::Small
, 0, KIconLoader::DefaultState
, QStringList(), 0L, true);
145 // make sure they are not larger than 20x20
146 if (normal
.width() > 20 || normal
.height() > 20)
148 QImage tmp
= normal
.toImage();
149 tmp
= tmp
.scaled(20, 20, Qt::IgnoreAspectRatio
, Qt::SmoothTransformation
);
150 normal
= QPixmap::fromImage(tmp
);
156 TreeView::TreeView( bool controlCenter
, KActionCollection
*ac
, QWidget
*parent
, const char *name
)
157 : K3ListView(parent
), m_ac(ac
), m_rmb(0), m_clipboard(0),
158 m_clipboardFolderInfo(0), m_clipboardEntryInfo(0),
159 m_controlCenter(controlCenter
), m_layoutDirty(false)
162 setFrameStyle(QFrame::WinPanel
| QFrame::Sunken
);
163 setAllColumnsShowFocus(true);
164 setRootIsDecorated(true);
166 setAcceptDrops(true);
167 setDropVisualizer(true);
168 setDragEnabled(true);
169 setMinimumWidth(240);
174 connect(this, SIGNAL(dropped(QDropEvent
*, Q3ListViewItem
*, Q3ListViewItem
*)),
175 SLOT(slotDropped(QDropEvent
*, Q3ListViewItem
*, Q3ListViewItem
*)));
177 connect(this, SIGNAL(clicked( Q3ListViewItem
* )),
178 SLOT(itemSelected( Q3ListViewItem
* )));
180 connect(this,SIGNAL(selectionChanged ( Q3ListViewItem
* )),
181 SLOT(itemSelected( Q3ListViewItem
* )));
183 connect(this, SIGNAL(rightButtonPressed(Q3ListViewItem
*, const QPoint
&, int)),
184 SLOT(slotRMBPressed(Q3ListViewItem
*, const QPoint
&)));
187 connect(m_ac
->action("newitem"), SIGNAL(activated()), SLOT(newitem()));
188 connect(m_ac
->action("newsubmenu"), SIGNAL(activated()), SLOT(newsubmenu()));
189 if (m_ac
->action("newsep"))
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);
207 TreeView::~TreeView() {
213 void TreeView::setViewMode(bool showHidden
)
218 m_rmb
= new QMenu(this);
221 action
= m_ac
->action("edit_cut");
223 m_rmb
->addAction( action
);
224 action
->setEnabled(false);
225 connect(action
, SIGNAL(activated()), SLOT(cut()));
228 action
= m_ac
->action("edit_copy");
230 m_rmb
->addAction( action
);
231 action
->setEnabled(false);
232 connect(action
, SIGNAL(activated()), SLOT(copy()));
235 action
= m_ac
->action("edit_paste");
237 m_rmb
->addAction( action
);
238 action
->setEnabled(false);
239 connect(action
, SIGNAL(activated()), SLOT(paste()));
242 m_rmb
->addSeparator();
244 action
= m_ac
->action("delete");
246 m_rmb
->addAction( action
);
247 action
->setEnabled(false);
248 connect(action
, SIGNAL(activated()), SLOT(del()));
251 m_rmb
->addSeparator();
253 if(m_ac
->action("newitem"))
254 m_rmb
->addAction( m_ac
->action("newitem") );
255 if(m_ac
->action("newsubmenu"))
256 m_rmb
->addAction( m_ac
->action("newsubmenu") );
257 if(m_ac
->action("newsep"))
258 m_rmb
->addAction( m_ac
->action("newsep") );
260 m_showHidden
= showHidden
;
261 readMenuFolderInfo();
265 void TreeView::readMenuFolderInfo(MenuFolderInfo
*folderInfo
, KServiceGroup::Ptr folder
, const QString
&prefix
)
269 folderInfo
= m_rootFolder
;
271 folder
= KServiceGroup::baseGroup("settings");
273 folder
= KServiceGroup::root();
276 if (!folder
|| !folder
->isValid())
279 folderInfo
->caption
= folder
->caption();
280 folderInfo
->comment
= folder
->comment();
282 // Item names may contain ampersands. To avoid them being converted
283 // to accelerators, replace them with two ampersands.
284 folderInfo
->hidden
= folder
->noDisplay();
285 folderInfo
->directoryFile
= folder
->directoryEntryPath();
286 folderInfo
->icon
= folder
->icon();
287 QString id
= folder
->relPath();
288 int i
= id
.lastIndexOf('/', -2);
291 folderInfo
->fullId
= prefix
+ id
;
293 foreach(const KSycocaEntry::Ptr
&e
, folder
->entries(true, !m_showHidden
, true, m_detailedMenuEntries
&& !m_detailedEntriesNamesFirst
))
295 if (e
->isType(KST_KServiceGroup
))
297 KServiceGroup::Ptr
g(KServiceGroup::Ptr::staticCast(e
));
298 MenuFolderInfo
*subFolderInfo
= new MenuFolderInfo();
299 readMenuFolderInfo(subFolderInfo
, g
, folderInfo
->fullId
);
300 folderInfo
->add(subFolderInfo
, true);
302 else if (e
->isType(KST_KService
))
304 folderInfo
->add(new MenuEntryInfo(KService::Ptr::staticCast(e
)), true);
306 else if (e
->isType(KST_KServiceSeparator
))
308 folderInfo
->add(m_separator
, true);
313 void TreeView::fill()
315 QApplication::setOverrideCursor(Qt::WaitCursor
);
317 fillBranch(m_rootFolder
, 0);
318 QApplication::restoreOverrideCursor();
321 QString
TreeView::findName(KDesktopFile
*df
, bool deleted
)
323 QString name
= df
->readName();
330 QString file
= df
->fileName();
331 QString res
= df
->resource();
334 QStringList files
= KGlobal::dirs()->findAllResources(res
.toLatin1(), file
);
335 for(QStringList::ConstIterator it
= files
.begin();
345 KDesktopFile
df2(*it
);
346 name
= df2
.readName();
348 if (!name
.isEmpty() && (name
!= "empty"))
356 TreeItem
*TreeView::createTreeItem(TreeItem
*parent
, Q3ListViewItem
*after
, MenuFolderInfo
*folderInfo
, bool _init
)
360 item
= new TreeItem(this, after
, QString(), _init
);
362 item
= new TreeItem(parent
, after
, QString(), _init
);
364 item
->setMenuFolderInfo(folderInfo
);
365 item
->setName(folderInfo
->caption
);
366 item
->setPixmap(0, appIcon(folderInfo
->icon
));
367 item
->setDirectoryPath(folderInfo
->fullId
);
368 item
->setHidden(folderInfo
->hidden
);
369 item
->setExpandable(true);
373 TreeItem
*TreeView::createTreeItem(TreeItem
*parent
, Q3ListViewItem
*after
, MenuEntryInfo
*entryInfo
, bool _init
)
375 bool hidden
= entryInfo
->hidden
;
379 item
= new TreeItem(this, after
, entryInfo
->menuId(), _init
);
381 item
= new TreeItem(parent
, after
, entryInfo
->menuId(),_init
);
385 if (m_detailedMenuEntries
&& entryInfo
->description
.length() != 0)
387 if (m_detailedEntriesNamesFirst
)
389 name
= entryInfo
->caption
+ " (" + entryInfo
->description
+ ')';
393 name
= entryInfo
->description
+ " (" + entryInfo
->caption
+ ')';
398 name
= entryInfo
->caption
;
400 item
->setMenuEntryInfo(entryInfo
);
402 item
->setPixmap(0, appIcon(entryInfo
->icon
));
404 item
->setHidden(hidden
);
408 TreeItem
*TreeView::createTreeItem(TreeItem
*parent
, Q3ListViewItem
*after
, MenuSeparatorInfo
*, bool _init
)
412 item
= new TreeItem(this, after
, QString(), _init
);
414 item
= new TreeItem(parent
, after
, QString(),_init
);
419 void TreeView::fillBranch(MenuFolderInfo
*folderInfo
, TreeItem
*parent
)
421 QString relPath
= parent
? parent
->directory() : QString();
422 Q3PtrListIterator
<MenuInfo
> it( folderInfo
->initialLayout
);
424 for (MenuInfo
*info
; (info
= it
.current()); ++it
)
426 MenuEntryInfo
*entry
= dynamic_cast<MenuEntryInfo
*>(info
);
429 after
= createTreeItem(parent
, after
, entry
);
433 MenuFolderInfo
*subFolder
= dynamic_cast<MenuFolderInfo
*>(info
);
436 after
= createTreeItem(parent
, after
, subFolder
);
439 MenuSeparatorInfo
*separator
= dynamic_cast<MenuSeparatorInfo
*>(info
);
442 after
= createTreeItem(parent
, after
, separator
);
448 void TreeView::closeAllItems(Q3ListViewItem
*item
)
453 item
->setOpen(false);
454 closeAllItems(item
->firstChild());
455 item
= item
->nextSibling();
459 void TreeView::selectMenu(const QString
&menu
)
461 closeAllItems(firstChild());
463 if (menu
.length() <= 1)
465 setCurrentItem(firstChild());
470 QString restMenu
= menu
.mid(1);
471 if (!restMenu
.endsWith('/'))
477 int i
= restMenu
.indexOf("/");
478 QString subMenu
= restMenu
.left(i
+1);
479 restMenu
= restMenu
.mid(i
+1);
481 item
= (TreeItem
*)(item
? item
->firstChild() : firstChild());
484 MenuFolderInfo
*folderInfo
= item
->folderInfo();
485 if (folderInfo
&& (folderInfo
->id
== subMenu
))
490 item
= (TreeItem
*) item
->nextSibling();
493 while( item
&& !restMenu
.isEmpty());
497 setCurrentItem(item
);
498 ensureItemVisible(item
);
502 void TreeView::selectMenuEntry(const QString
&menuEntry
)
504 TreeItem
*item
= (TreeItem
*) selectedItem();
507 item
= (TreeItem
*) currentItem();
508 while (item
&& item
->isDirectory())
509 item
= (TreeItem
*) item
->nextSibling();
512 item
= (TreeItem
*) item
->firstChild();
516 MenuEntryInfo
*entry
= item
->entryInfo();
517 if (entry
&& (entry
->menuId() == menuEntry
))
519 setCurrentItem(item
);
520 ensureItemVisible(item
);
523 item
= (TreeItem
*) item
->nextSibling();
527 void TreeView::itemSelected(Q3ListViewItem
*item
)
529 TreeItem
*_item
= (TreeItem
*)item
;
530 bool selected
= false;
531 bool dselected
= false;
534 dselected
= _item
->isHidden();
537 m_ac
->action("edit_cut")->setEnabled(selected
);
538 m_ac
->action("edit_copy")->setEnabled(selected
);
540 if (m_ac
->action("delete"))
541 m_ac
->action("delete")->setEnabled(selected
&& !dselected
);
545 emit
disableAction();
549 if (_item
->isDirectory())
550 emit
entrySelected(_item
->folderInfo());
552 emit
entrySelected(_item
->entryInfo());
555 void TreeView::currentChanged(MenuFolderInfo
*folderInfo
)
557 TreeItem
*item
= (TreeItem
*)selectedItem();
558 if (item
== 0) return;
559 if (folderInfo
== 0) return;
561 item
->setName(folderInfo
->caption
);
562 item
->setPixmap(0, appIcon(folderInfo
->icon
));
565 void TreeView::currentChanged(MenuEntryInfo
*entryInfo
)
567 TreeItem
*item
= (TreeItem
*)selectedItem();
568 if (item
== 0) return;
569 if (entryInfo
== 0) return;
573 if (m_detailedMenuEntries
&& entryInfo
->description
.length() != 0)
575 if (m_detailedEntriesNamesFirst
)
577 name
= entryInfo
->caption
+ " (" + entryInfo
->description
+ ')';
581 name
= entryInfo
->description
+ " (" + entryInfo
->caption
+ ')';
586 name
= entryInfo
->caption
;
589 item
->setPixmap(0, appIcon(entryInfo
->icon
));
592 QStringList
TreeView::fileList(const QString
& rPath
)
594 QString relativePath
= rPath
;
596 // truncate "/.directory"
597 int pos
= relativePath
.lastIndexOf("/.directory");
598 if (pos
> 0) relativePath
.truncate(pos
);
600 QStringList filelist
;
602 // loop through all resource dirs and build a file list
603 QStringList resdirlist
= KGlobal::dirs()->resourceDirs("apps");
604 for (QStringList::ConstIterator it
= resdirlist
.begin(); it
!= resdirlist
.end(); ++it
)
606 QDir
dir((*it
) + '/' + relativePath
);
607 if(!dir
.exists()) continue;
609 dir
.setFilter(QDir::Files
);
610 dir
.setNameFilters(QStringList() << "*.desktop;*.kdelnk");
612 // build a list of files
613 QStringList files
= dir
.entryList();
614 for (QStringList::ConstIterator it
= files
.begin(); it
!= files
.end(); ++it
) {
616 //if (filelist.contains(*it)) continue;
618 if (relativePath
.isEmpty()) {
619 filelist
.removeAll(*it
); // hack
620 filelist
.append(*it
);
623 filelist
.removeAll(relativePath
+ '/' + *it
); //hack
624 filelist
.append(relativePath
+ '/' + *it
);
631 QStringList
TreeView::dirList(const QString
& rPath
)
633 QString relativePath
= rPath
;
635 // truncate "/.directory"
636 int pos
= relativePath
.lastIndexOf("/.directory");
637 if (pos
> 0) relativePath
.truncate(pos
);
641 // loop through all resource dirs and build a subdir list
642 QStringList resdirlist
= KGlobal::dirs()->resourceDirs("apps");
643 for (QStringList::ConstIterator it
= resdirlist
.begin(); it
!= resdirlist
.end(); ++it
)
645 QDir
dir((*it
) + '/' + relativePath
);
646 if(!dir
.exists()) continue;
647 dir
.setFilter(QDir::Dirs
);
649 // build a list of subdirs
650 QStringList subdirs
= dir
.entryList();
651 for (QStringList::ConstIterator it
= subdirs
.begin(); it
!= subdirs
.end(); ++it
) {
652 if ((*it
) == "." || (*it
) == "..") continue;
654 // if (dirlist.contains(*it)) continue;
656 if (relativePath
.isEmpty()) {
657 dirlist
.removeAll(*it
); //hack
661 dirlist
.removeAll(relativePath
+ '/' + *it
); //hack
662 dirlist
.append(relativePath
+ '/' + *it
);
669 bool TreeView::acceptDrag(QDropEvent
* e
) const
671 if (e
->provides("application/x-kmenuedit-internal") &&
672 (e
->source() == const_cast<TreeView
*>(this)))
675 if (K3URLDrag::decode(e
, urls
) && (urls
.count() == 1) &&
676 urls
[0].isLocalFile() && urls
[0].path().endsWith(".desktop"))
682 static QString
createDesktopFile(const QString
&file
, QString
*menuId
, QStringList
*excludeList
)
684 QString base
= file
.mid(file
.lastIndexOf('/')+1);
685 base
= base
.left(base
.lastIndexOf('.'));
687 QRegExp
r("(.*)(?=-\\d+)");
688 base
= (r
.indexIn(base
) > -1) ? r
.cap(1) : base
;
690 QString result
= KService::newServicePath(true, base
, menuId
, excludeList
);
691 excludeList
->append(*menuId
);
692 // Todo for Undo-support: Undo menuId allocation:
697 static KDesktopFile
*copyDesktopFile(MenuEntryInfo
*entryInfo
, QString
*menuId
, QStringList
*excludeList
)
699 QString result
= createDesktopFile(entryInfo
->file(), menuId
, excludeList
);
700 KDesktopFile
*df
= entryInfo
->desktopFile()->copyTo(result
);
701 df
->desktopGroup().deleteEntry("Categories"); // Don't set any categories!
706 static QString
createDirectoryFile(const QString
&file
, QStringList
*excludeList
)
708 QString base
= file
.mid(file
.lastIndexOf('/')+1);
709 base
= base
.left(base
.lastIndexOf('.'));
716 result
= base
+ ".directory";
718 result
= base
+ QString("-%1.directory").arg(i
);
720 if (!excludeList
->contains(result
))
722 if (KStandardDirs::locate("xdgdata-dirs", result
).isEmpty())
727 excludeList
->append(result
);
728 result
= KStandardDirs::locateLocal("xdgdata-dirs", result
);
733 void TreeView::slotDropped (QDropEvent
* e
, Q3ListViewItem
*parent
, Q3ListViewItem
*after
)
737 // get destination folder
738 TreeItem
*parentItem
= static_cast<TreeItem
*>(parent
);
739 QString folder
= parentItem
? parentItem
->directory() : QString();
740 MenuFolderInfo
*parentFolderInfo
= parentItem
? parentItem
->folderInfo() : m_rootFolder
;
742 if (e
->source() != this)
746 if (!K3URLDrag::decode(e
, urls
) || (urls
.count() != 1) || !urls
[0].isLocalFile())
748 QString path
= urls
[0].path();
749 if (!path
.endsWith(".desktop"))
753 QString result
= createDesktopFile(path
, &menuId
, &m_newMenuIds
);
754 KDesktopFile
orig_df(path
);
755 KDesktopFile
*df
= orig_df
.copyTo(result
);
756 df
->desktopGroup().deleteEntry("Categories"); // Don't set any categories!
758 KService::Ptr
s(new KService(df
));
759 s
->setMenuId(menuId
);
761 MenuEntryInfo
*entryInfo
= new MenuEntryInfo(s
, df
);
763 QString oldCaption
= entryInfo
->caption
;
764 QString newCaption
= parentFolderInfo
->uniqueItemCaption(oldCaption
, oldCaption
);
765 entryInfo
->setCaption(newCaption
);
768 // m_menuFile->addEntry(folder, menuId);
769 m_menuFile
->pushAction(MenuFile::ADD_ENTRY
, folder
, menuId
);
771 // create the TreeItem
773 parentItem
->setOpen(true);
775 // update fileInfo data
776 parentFolderInfo
->add(entryInfo
);
778 TreeItem
*newItem
= createTreeItem(parentItem
, after
, entryInfo
, true);
780 setSelected ( newItem
, true);
781 itemSelected( newItem
);
784 setLayoutDirty(parentItem
);
788 // is there content in the clipboard?
791 if (m_dragItem
== after
) return; // Nothing to do
793 int command
= m_drag
;
794 if (command
== MOVE_FOLDER
)
796 MenuFolderInfo
*folderInfo
= m_dragInfo
;
797 if (e
->action() == QDropEvent::Copy
)
799 // Ugh.. this is hard :)
800 // * Create new .directory file
805 TreeItem
*tmpItem
= static_cast<TreeItem
*>(parentItem
);
808 if ( tmpItem
== m_dragItem
)
813 tmpItem
= static_cast<TreeItem
*>(tmpItem
->parent() );
816 // Remove MenuFolderInfo
817 TreeItem
*oldParentItem
= static_cast<TreeItem
*>(m_dragItem
->parent());
818 MenuFolderInfo
*oldParentFolderInfo
= oldParentItem
? oldParentItem
->folderInfo() : m_rootFolder
;
819 oldParentFolderInfo
->take(folderInfo
);
822 QString oldFolder
= folderInfo
->fullId
;
823 QString folderName
= folderInfo
->id
;
824 QString newFolder
= m_menuFile
->uniqueMenuName(folder
, folderName
, parentFolderInfo
->existingMenuIds());
825 folderInfo
->id
= newFolder
;
828 //m_menuFile->moveMenu(oldFolder, folder + newFolder);
829 m_menuFile
->pushAction(MenuFile::MOVE_MENU
, oldFolder
, folder
+ newFolder
);
831 // Make sure caption is unique
832 QString newCaption
= parentFolderInfo
->uniqueMenuCaption(folderInfo
->caption
);
833 if (newCaption
!= folderInfo
->caption
)
835 folderInfo
->setCaption(newCaption
);
838 // create the TreeItem
840 parentItem
->setOpen(true);
842 // update fileInfo data
843 folderInfo
->updateFullId(parentFolderInfo
->fullId
);
844 folderInfo
->setInUse(true);
845 parentFolderInfo
->add(folderInfo
);
847 if ((parentItem
!= oldParentItem
) || !after
)
850 oldParentItem
->takeItem(m_dragItem
);
852 takeItem(m_dragItem
);
854 parentItem
->insertItem(m_dragItem
);
856 insertItem(m_dragItem
);
858 m_dragItem
->moveItem(after
);
859 m_dragItem
->setName(folderInfo
->caption
);
860 m_dragItem
->setDirectoryPath(folderInfo
->fullId
);
861 setSelected(m_dragItem
, true);
862 itemSelected(m_dragItem
);
865 else if (command
== MOVE_FILE
)
867 MenuEntryInfo
*entryInfo
= m_dragItem
->entryInfo();
868 QString menuId
= entryInfo
->menuId();
870 if (e
->action() == QDropEvent::Copy
)
873 // Need to copy file and then add it
874 KDesktopFile
*df
= copyDesktopFile(entryInfo
, &menuId
, &m_newMenuIds
); // Duplicate
875 //UNDO-ACTION: NEW_MENU_ID (menuId)
877 KService::Ptr
s(new KService(df
));
878 s
->setMenuId(menuId
);
880 entryInfo
= new MenuEntryInfo(s
, df
);
882 QString oldCaption
= entryInfo
->caption
;
883 QString newCaption
= parentFolderInfo
->uniqueItemCaption(oldCaption
, oldCaption
);
884 entryInfo
->setCaption(newCaption
);
888 del(m_dragItem
, false);
889 QString oldCaption
= entryInfo
->caption
;
890 QString newCaption
= parentFolderInfo
->uniqueItemCaption(oldCaption
);
891 entryInfo
->setCaption(newCaption
);
892 entryInfo
->setInUse(true);
895 // m_menuFile->addEntry(folder, menuId);
896 m_menuFile
->pushAction(MenuFile::ADD_ENTRY
, folder
, menuId
);
898 // create the TreeItem
900 parentItem
->setOpen(true);
902 // update fileInfo data
903 parentFolderInfo
->add(entryInfo
);
905 TreeItem
*newItem
= createTreeItem(parentItem
, after
, entryInfo
, true);
907 setSelected ( newItem
, true);
908 itemSelected( newItem
);
910 else if (command
== COPY_SEPARATOR
)
912 if (e
->action() != QDropEvent::Copy
)
913 del(m_dragItem
, false);
915 TreeItem
*newItem
= createTreeItem(parentItem
, after
, m_separator
, true);
917 setSelected ( newItem
, true);
918 itemSelected( newItem
);
925 setLayoutDirty(parentItem
);
929 void TreeView::startDrag()
931 Q3DragObject
*drag
= dragObject();
939 Q3DragObject
*TreeView::dragObject()
942 TreeItem
*item
= (TreeItem
*)selectedItem();
943 if(item
== 0) return 0;
945 K3MultipleDrag
*drag
= new K3MultipleDrag( this );
947 if (item
->isDirectory())
949 m_drag
= MOVE_FOLDER
;
950 m_dragInfo
= item
->folderInfo();
953 else if (item
->isEntry())
958 QString menuId
= item
->menuId();
959 m_dragPath
= item
->entryInfo()->service
->entryPath();
960 if (!m_dragPath
.isEmpty())
961 m_dragPath
= KStandardDirs::locate("apps", m_dragPath
);
962 if (!m_dragPath
.isEmpty())
965 url
.setPath(m_dragPath
);
966 drag
->addDragObject( new K3URLDrag(url
, 0));
971 m_drag
= COPY_SEPARATOR
;
976 drag
->addDragObject( new Q3StoredDrag("application/x-kmenuedit-internal", 0));
977 if ( item
->pixmap(0) )
978 drag
->setPixmap(*item
->pixmap(0));
982 void TreeView::slotRMBPressed(Q3ListViewItem
*, const QPoint
& p
)
984 TreeItem
*item
= (TreeItem
*)selectedItem();
985 if(item
== 0) return;
987 if(m_rmb
) m_rmb
->exec(p
);
990 void TreeView::newsubmenu()
992 TreeItem
*parentItem
= 0;
993 TreeItem
*item
= (TreeItem
*)selectedItem();
996 QString caption
= KInputDialog::getText( i18n( "New Submenu" ),
997 i18n( "Submenu name:" ), QString(), &ok
, this );
1001 QString file
= caption
;
1002 file
.replace('/', '-');
1004 file
= createDirectoryFile(file
, &m_newDirectoryList
); // Create
1006 // get destination folder
1014 else if(item
->isDirectory())
1018 folder
= parentItem
->directory();
1022 parentItem
= static_cast<TreeItem
*>(item
->parent());
1023 folder
= parentItem
? parentItem
->directory() : QString();
1026 MenuFolderInfo
*parentFolderInfo
= parentItem
? parentItem
->folderInfo() : m_rootFolder
;
1027 MenuFolderInfo
*folderInfo
= new MenuFolderInfo();
1028 folderInfo
->caption
= parentFolderInfo
->uniqueMenuCaption(caption
);
1029 folderInfo
->id
= m_menuFile
->uniqueMenuName(folder
, caption
, parentFolderInfo
->existingMenuIds());
1030 folderInfo
->directoryFile
= file
;
1031 folderInfo
->icon
= "package";
1032 folderInfo
->hidden
= false;
1033 folderInfo
->setDirty();
1035 KDesktopFile
*df
= new KDesktopFile(file
);
1036 KConfigGroup desktopGroup
= df
->desktopGroup();
1037 desktopGroup
.writeEntry("Name", folderInfo
->caption
);
1038 desktopGroup
.writeEntry("Icon", folderInfo
->icon
);
1042 // m_menuFile->addMenu(folder + folderInfo->id, file);
1043 m_menuFile
->pushAction(MenuFile::ADD_MENU
, folder
+ folderInfo
->id
, file
);
1045 folderInfo
->fullId
= parentFolderInfo
->fullId
+ folderInfo
->id
;
1047 // create the TreeItem
1049 parentItem
->setOpen(true);
1051 // update fileInfo data
1052 parentFolderInfo
->add(folderInfo
);
1054 TreeItem
*newItem
= createTreeItem(parentItem
, item
, folderInfo
, true);
1056 setSelected ( newItem
, true);
1057 itemSelected( newItem
);
1059 setLayoutDirty(parentItem
);
1062 void TreeView::newitem()
1064 TreeItem
*parentItem
= 0;
1065 TreeItem
*item
= (TreeItem
*)selectedItem();
1068 QString caption
= KInputDialog::getText( i18n( "New Item" ),
1069 i18n( "Item name:" ), QString(), &ok
, this );
1074 QString file
= caption
;
1075 file
.replace('/', '-');
1077 file
= createDesktopFile(file
, &menuId
, &m_newMenuIds
); // Create
1079 KDesktopFile
*df
= new KDesktopFile(file
);
1080 KConfigGroup desktopGroup
= df
->desktopGroup();
1081 desktopGroup
.writeEntry("Name", caption
);
1082 desktopGroup
.writeEntry("Type", "Application");
1084 // get destination folder
1092 else if(item
->isDirectory())
1096 folder
= parentItem
->directory();
1100 parentItem
= static_cast<TreeItem
*>(item
->parent());
1101 folder
= parentItem
? parentItem
->directory() : QString();
1104 MenuFolderInfo
*parentFolderInfo
= parentItem
? parentItem
->folderInfo() : m_rootFolder
;
1107 // m_menuFile->addEntry(folder, menuId);
1108 m_menuFile
->pushAction(MenuFile::ADD_ENTRY
, folder
, menuId
);
1110 KService::Ptr
s(new KService(df
));
1111 s
->setMenuId(menuId
);
1113 MenuEntryInfo
*entryInfo
= new MenuEntryInfo(s
, df
);
1115 // create the TreeItem
1117 parentItem
->setOpen(true);
1119 // update fileInfo data
1120 parentFolderInfo
->add(entryInfo
);
1122 TreeItem
*newItem
= createTreeItem(parentItem
, item
, entryInfo
, true);
1124 setSelected ( newItem
, true);
1125 itemSelected( newItem
);
1127 setLayoutDirty(parentItem
);
1130 void TreeView::newsep()
1132 TreeItem
*parentItem
= 0;
1133 TreeItem
*item
= (TreeItem
*)selectedItem();
1139 else if(item
->isDirectory())
1146 parentItem
= static_cast<TreeItem
*>(item
->parent());
1149 // create the TreeItem
1151 parentItem
->setOpen(true);
1153 TreeItem
*newItem
= createTreeItem(parentItem
, item
, m_separator
, true);
1155 setSelected ( newItem
, true);
1156 itemSelected( newItem
);
1158 setLayoutDirty(parentItem
);
1161 void TreeView::cut()
1165 m_ac
->action("edit_cut")->setEnabled(false);
1166 m_ac
->action("edit_copy")->setEnabled(false);
1167 m_ac
->action("delete")->setEnabled(false);
1169 // Select new current item
1170 setSelected( currentItem(), true );
1171 // Switch the UI to show that item
1172 itemSelected( selectedItem() );
1175 void TreeView::copy()
1180 void TreeView::copy( bool cutting
)
1182 TreeItem
*item
= (TreeItem
*)selectedItem();
1184 // nil selected? -> nil to copy
1185 if (item
== 0) return;
1188 setLayoutDirty((TreeItem
*)item
->parent());
1190 // clean up old stuff
1193 // is item a folder or a file?
1194 if(item
->isDirectory())
1196 QString folder
= item
->directory();
1199 // Place in clipboard
1200 m_clipboard
= MOVE_FOLDER
;
1201 m_clipboardFolderInfo
= item
->folderInfo();
1207 // Place in clipboard
1208 m_clipboard
= COPY_FOLDER
;
1209 m_clipboardFolderInfo
= item
->folderInfo();
1212 else if (item
->isEntry())
1216 // Place in clipboard
1217 m_clipboard
= MOVE_FILE
;
1218 m_clipboardEntryInfo
= item
->entryInfo();
1224 // Place in clipboard
1225 m_clipboard
= COPY_FILE
;
1226 m_clipboardEntryInfo
= item
->entryInfo();
1231 // Place in clipboard
1232 m_clipboard
= COPY_SEPARATOR
;
1237 m_ac
->action("edit_paste")->setEnabled(true);
1241 void TreeView::paste()
1243 TreeItem
*parentItem
= 0;
1244 TreeItem
*item
= (TreeItem
*)selectedItem();
1246 // nil selected? -> nil to paste to
1247 if (item
== 0) return;
1249 // is there content in the clipboard?
1250 if (!m_clipboard
) return;
1252 // get destination folder
1255 if(item
->isDirectory())
1259 folder
= parentItem
->directory();
1263 parentItem
= static_cast<TreeItem
*>(item
->parent());
1264 folder
= parentItem
? parentItem
->directory() : QString();
1267 MenuFolderInfo
*parentFolderInfo
= parentItem
? parentItem
->folderInfo() : m_rootFolder
;
1268 int command
= m_clipboard
;
1269 if ((command
== COPY_FOLDER
) || (command
== MOVE_FOLDER
))
1271 MenuFolderInfo
*folderInfo
= m_clipboardFolderInfo
;
1272 if (command
== COPY_FOLDER
)
1274 // Ugh.. this is hard :)
1275 // * Create new .directory file
1278 else if (command
== MOVE_FOLDER
)
1281 QString oldFolder
= folderInfo
->fullId
;
1282 QString folderName
= folderInfo
->id
;
1283 QString newFolder
= m_menuFile
->uniqueMenuName(folder
, folderName
, parentFolderInfo
->existingMenuIds());
1284 folderInfo
->id
= newFolder
;
1287 // m_menuFile->moveMenu(oldFolder, folder + newFolder);
1288 m_menuFile
->pushAction(MenuFile::MOVE_MENU
, oldFolder
, folder
+ newFolder
);
1290 // Make sure caption is unique
1291 QString newCaption
= parentFolderInfo
->uniqueMenuCaption(folderInfo
->caption
);
1292 if (newCaption
!= folderInfo
->caption
)
1294 folderInfo
->setCaption(newCaption
);
1296 // create the TreeItem
1298 parentItem
->setOpen(true);
1300 // update fileInfo data
1301 folderInfo
->fullId
= parentFolderInfo
->fullId
+ folderInfo
->id
;
1302 folderInfo
->setInUse(true);
1303 parentFolderInfo
->add(folderInfo
);
1305 TreeItem
*newItem
= createTreeItem(parentItem
, item
, folderInfo
);
1307 setSelected ( newItem
, true);
1308 itemSelected( newItem
);
1311 m_clipboard
= COPY_FOLDER
; // Next one copies.
1313 else if ((command
== COPY_FILE
) || (command
== MOVE_FILE
))
1315 MenuEntryInfo
*entryInfo
= m_clipboardEntryInfo
;
1318 if (command
== COPY_FILE
)
1320 // Need to copy file and then add it
1321 KDesktopFile
*df
= copyDesktopFile(entryInfo
, &menuId
, &m_newMenuIds
); // Duplicate
1323 KService::Ptr
s(new KService(df
));
1324 s
->setMenuId(menuId
);
1325 entryInfo
= new MenuEntryInfo(s
, df
);
1327 QString oldCaption
= entryInfo
->caption
;
1328 QString newCaption
= parentFolderInfo
->uniqueItemCaption(oldCaption
, oldCaption
);
1329 entryInfo
->setCaption(newCaption
);
1331 else if (command
== MOVE_FILE
)
1333 menuId
= entryInfo
->menuId();
1334 m_clipboard
= COPY_FILE
; // Next one copies.
1336 QString oldCaption
= entryInfo
->caption
;
1337 QString newCaption
= parentFolderInfo
->uniqueItemCaption(oldCaption
);
1338 entryInfo
->setCaption(newCaption
);
1339 entryInfo
->setInUse(true);
1342 // m_menuFile->addEntry(folder, menuId);
1343 m_menuFile
->pushAction(MenuFile::ADD_ENTRY
, folder
, menuId
);
1345 // create the TreeItem
1347 parentItem
->setOpen(true);
1349 // update fileInfo data
1350 parentFolderInfo
->add(entryInfo
);
1352 TreeItem
*newItem
= createTreeItem(parentItem
, item
, entryInfo
, true);
1354 setSelected ( newItem
, true);
1355 itemSelected( newItem
);
1361 parentItem
->setOpen(true);
1363 TreeItem
*newItem
= createTreeItem(parentItem
, item
, m_separator
, true);
1365 setSelected ( newItem
, true);
1366 itemSelected( newItem
);
1368 setLayoutDirty(parentItem
);
1371 void TreeView::del()
1373 TreeItem
*item
= (TreeItem
*)selectedItem();
1375 // nil selected? -> nil to delete
1376 if (item
== 0) return;
1380 m_ac
->action("edit_cut")->setEnabled(false);
1381 m_ac
->action("edit_copy")->setEnabled(false);
1382 m_ac
->action("delete")->setEnabled(false);
1383 // Select new current item
1384 setSelected( currentItem(), true );
1385 // Switch the UI to show that item
1386 itemSelected( selectedItem() );
1389 void TreeView::del(TreeItem
*item
, bool deleteInfo
)
1391 TreeItem
*parentItem
= static_cast<TreeItem
*>(item
->parent());
1392 // is file a .directory or a .desktop file
1393 if(item
->isDirectory())
1395 MenuFolderInfo
*folderInfo
= item
->folderInfo();
1397 // Remove MenuFolderInfo
1398 MenuFolderInfo
*parentFolderInfo
= parentItem
? parentItem
->folderInfo() : m_rootFolder
;
1399 parentFolderInfo
->take(folderInfo
);
1400 folderInfo
->setInUse(false);
1402 if (m_clipboard
== COPY_FOLDER
&& (m_clipboardFolderInfo
== folderInfo
))
1404 // Copy + Del == Cut
1405 m_clipboard
= MOVE_FOLDER
; // Clipboard now owns folderInfo
1410 if (folderInfo
->takeRecursive(m_clipboardFolderInfo
))
1411 m_clipboard
= MOVE_FOLDER
; // Clipboard now owns m_clipboardFolderInfo
1414 delete folderInfo
; // Delete folderInfo
1418 // m_menuFile->removeMenu(item->directory());
1419 m_menuFile
->pushAction(MenuFile::REMOVE_MENU
, item
->directory(), QString());
1424 else if (item
->isEntry())
1426 MenuEntryInfo
*entryInfo
= item
->entryInfo();
1427 QString menuId
= entryInfo
->menuId();
1429 // Remove MenuFolderInfo
1430 MenuFolderInfo
*parentFolderInfo
= parentItem
? parentItem
->folderInfo() : m_rootFolder
;
1431 parentFolderInfo
->take(entryInfo
);
1432 entryInfo
->setInUse(false);
1434 if (m_clipboard
== COPY_FILE
&& (m_clipboardEntryInfo
== entryInfo
))
1436 // Copy + Del == Cut
1437 m_clipboard
= MOVE_FILE
; // Clipboard now owns entryInfo
1442 delete entryInfo
; // Delete entryInfo
1446 QString folder
= parentItem
? parentItem
->directory() : QString();
1447 // m_menuFile->removeEntry(folder, menuId);
1448 m_menuFile
->pushAction(MenuFile::REMOVE_ENTRY
, folder
, menuId
);
1458 setLayoutDirty(parentItem
);
1461 void TreeView::cleanupClipboard() {
1462 if (m_clipboard
== MOVE_FOLDER
)
1463 delete m_clipboardFolderInfo
;
1464 m_clipboardFolderInfo
= 0;
1466 if (m_clipboard
== MOVE_FILE
)
1467 delete m_clipboardEntryInfo
;
1468 m_clipboardEntryInfo
= 0;
1473 static QStringList
extractLayout(TreeItem
*item
)
1475 bool firstFolder
= true;
1476 bool firstEntry
= true;
1478 for(;item
; item
= static_cast<TreeItem
*>(item
->nextSibling()))
1480 if (item
->isDirectory())
1484 firstFolder
= false;
1485 layout
<< ":M"; // Add new folders here...
1487 layout
<< (item
->folderInfo()->id
);
1489 else if (item
->isEntry())
1494 layout
<< ":F"; // Add new entries here...
1496 layout
<< (item
->entryInfo()->menuId());
1506 QStringList
TreeItem::layout()
1508 QStringList layout
= extractLayout(static_cast<TreeItem
*>(firstChild()));
1509 _layoutDirty
= false;
1513 void TreeView::saveLayout()
1517 QStringList layout
= extractLayout(static_cast<TreeItem
*>(firstChild()));
1518 m_menuFile
->setLayout(m_rootFolder
->fullId
, layout
);
1519 m_layoutDirty
= false;
1522 Q3PtrList
<Q3ListViewItem
> lst
;
1523 Q3ListViewItemIterator
it( this );
1524 while ( it
.current() ) {
1525 TreeItem
*item
= static_cast<TreeItem
*>(it
.current());
1526 if ( item
->isLayoutDirty() )
1528 m_menuFile
->setLayout(item
->folderInfo()->fullId
, item
->layout());
1534 bool TreeView::save()
1537 m_rootFolder
->save(m_menuFile
);
1539 bool success
= m_menuFile
->performAllActions();
1541 m_newMenuIds
.clear();
1542 m_newDirectoryList
.clear();
1546 KBuildSycocaProgressDialog::rebuildKSycoca(this);
1550 KMessageBox::sorry(this, "<qt>"+i18n("Menu changes could not be saved because of the following problem:")+"<br><br>"+
1551 m_menuFile
->error()+"</qt>");
1556 void TreeView::setLayoutDirty(TreeItem
*parentItem
)
1559 parentItem
->setLayoutDirty();
1561 m_layoutDirty
= true;
1564 bool TreeView::isLayoutDirty()
1566 Q3PtrList
<Q3ListViewItem
> lst
;
1567 Q3ListViewItemIterator
it( this );
1568 while ( it
.current() ) {
1569 if ( static_cast<TreeItem
*>(it
.current())->isLayoutDirty() )
1576 bool TreeView::dirty()
1578 return m_layoutDirty
|| m_rootFolder
->hasDirt() || m_menuFile
->dirty() || isLayoutDirty();
1581 void TreeView::findServiceShortcut(const KShortcut
&cut
, KService::Ptr
&service
)
1583 service
= m_rootFolder
->findServiceShortcut(cut
);