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
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
connect(m_ac->action("newsep"), SIGNAL(activated()), SLOT(newsep()));
191
m_menuFile = new MenuFile( KStandardDirs::locateLocal("xdgconf-menu", "applications-kmenuedit.menu"));
192
m_rootFolder = new MenuFolderInfo;
193
m_separator = new MenuSeparatorInfo;
196
// Read menu format configuration information
197
KSharedConfig::Ptr pConfig = KSharedConfig::openConfig("kickerrc");
198
KConfigGroup cg(pConfig, "menus");
199
m_detailedMenuEntries = cg.readEntry("DetailedMenuEntries", true);
200
if (m_detailedMenuEntries)
202
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");
222
m_rmb->addAction( action );
223
action->setEnabled(false);
224
connect(action, SIGNAL(activated()), SLOT(cut()));
226
action = m_ac->action("edit_copy");
227
m_rmb->addAction( action );
228
action->setEnabled(false);
229
connect(action, SIGNAL(activated()), SLOT(copy()));
231
action = m_ac->action("edit_paste");
232
m_rmb->addAction( action );
233
action->setEnabled(false);
234
connect(action, SIGNAL(activated()), SLOT(paste()));
236
m_rmb->addSeparator();
238
action = m_ac->action("delete");
239
m_rmb->addAction( action );
240
action->setEnabled(false);
241
connect(action, SIGNAL(activated()), SLOT(del()));
243
m_rmb->addSeparator();
245
m_rmb->addAction( m_ac->action("newitem") );
246
m_rmb->addAction( m_ac->action("newsubmenu") );
247
m_rmb->addAction( m_ac->action("newsep") );
249
m_showHidden = showHidden;
250
readMenuFolderInfo();
254
void TreeView::readMenuFolderInfo(MenuFolderInfo *folderInfo, KServiceGroup::Ptr folder, const QString &prefix)
258
folderInfo = m_rootFolder;
259
folder = KServiceGroup::root();
262
if (!folder || !folder->isValid())
265
folderInfo->caption = folder->caption();
266
folderInfo->comment = folder->comment();
268
// Item names may contain ampersands. To avoid them being converted
269
// to accelerators, replace them with two ampersands.
270
folderInfo->hidden = folder->noDisplay();
271
folderInfo->directoryFile = folder->directoryEntryPath();
272
folderInfo->icon = folder->icon();
273
QString id = folder->relPath();
274
int i = id.lastIndexOf('/', -2);
277
folderInfo->fullId = prefix + id;
279
foreach(const KSycocaEntry::Ptr &e, folder->entries(true, !m_showHidden, true, m_detailedMenuEntries && !m_detailedEntriesNamesFirst))
281
if (e->isType(KST_KServiceGroup))
283
KServiceGroup::Ptr g(KServiceGroup::Ptr::staticCast(e));
284
MenuFolderInfo *subFolderInfo = new MenuFolderInfo();
285
readMenuFolderInfo(subFolderInfo, g, folderInfo->fullId);
286
folderInfo->add(subFolderInfo, true);
288
else if (e->isType(KST_KService))
290
folderInfo->add(new MenuEntryInfo(KService::Ptr::staticCast(e)), true);
292
else if (e->isType(KST_KServiceSeparator))
294
folderInfo->add(m_separator, true);
299
void TreeView::fill()
301
QApplication::setOverrideCursor(Qt::WaitCursor);
303
fillBranch(m_rootFolder, 0);
304
QApplication::restoreOverrideCursor();
307
QString TreeView::findName(KDesktopFile *df, bool deleted)
309
QString name = df->readName();
316
QString file = df->fileName();
317
QString res = df->resource();
320
const QStringList files = KGlobal::dirs()->findAllResources(res.toLatin1(), file);
321
for(QStringList::ConstIterator it = files.constBegin();
322
it != files.constEnd();
331
KDesktopFile df2(*it);
332
name = df2.readName();
334
if (!name.isEmpty() && (name != "empty"))
342
TreeItem *TreeView::createTreeItem(TreeItem *parent, Q3ListViewItem *after, MenuFolderInfo *folderInfo, bool _init)
346
item = new TreeItem(this, after, QString(), _init);
348
item = new TreeItem(parent, after, QString(), _init);
350
item->setMenuFolderInfo(folderInfo);
351
item->setName(folderInfo->caption);
352
item->setPixmap(0, appIcon(folderInfo->icon));
353
item->setDirectoryPath(folderInfo->fullId);
354
item->setHidden(folderInfo->hidden);
355
item->setExpandable(true);
359
TreeItem *TreeView::createTreeItem(TreeItem *parent, Q3ListViewItem *after, MenuEntryInfo *entryInfo, bool _init)
361
bool hidden = entryInfo->hidden;
365
item = new TreeItem(this, after, entryInfo->menuId(), _init);
367
item = new TreeItem(parent, after, entryInfo->menuId(),_init);
371
if (m_detailedMenuEntries && entryInfo->description.length() != 0)
373
if (m_detailedEntriesNamesFirst)
375
name = entryInfo->caption + " (" + entryInfo->description + ')';
379
name = entryInfo->description + " (" + entryInfo->caption + ')';
384
name = entryInfo->caption;
386
item->setMenuEntryInfo(entryInfo);
388
item->setPixmap(0, appIcon(entryInfo->icon));
390
item->setHidden(hidden);
394
TreeItem *TreeView::createTreeItem(TreeItem *parent, Q3ListViewItem *after, MenuSeparatorInfo *, bool _init)
398
item = new TreeItem(this, after, QString(), _init);
400
item = new TreeItem(parent, after, QString(),_init);
405
void TreeView::fillBranch(MenuFolderInfo *folderInfo, TreeItem *parent)
407
QString relPath = parent ? parent->directory() : QString();
408
Q3PtrListIterator<MenuInfo> it( folderInfo->initialLayout );
410
for (MenuInfo *info; (info = it.current()); ++it)
412
MenuEntryInfo *entry = dynamic_cast<MenuEntryInfo*>(info);
415
after = createTreeItem(parent, after, entry);
419
MenuFolderInfo *subFolder = dynamic_cast<MenuFolderInfo*>(info);
422
after = createTreeItem(parent, after, subFolder);
425
MenuSeparatorInfo *separator = dynamic_cast<MenuSeparatorInfo*>(info);
428
after = createTreeItem(parent, after, separator);
434
void TreeView::closeAllItems(Q3ListViewItem *item)
439
item->setOpen(false);
440
closeAllItems(item->firstChild());
441
item = item->nextSibling();
445
void TreeView::selectMenu(const QString &menu)
447
closeAllItems(firstChild());
449
if (menu.length() <= 1)
451
setCurrentItem(firstChild());
456
QString restMenu = menu;
457
if ( menu.startsWith( '/' ) )
458
restMenu = menu.mid(1);
459
if (!restMenu.endsWith('/'))
465
int i = restMenu.indexOf("/");
466
QString subMenu = restMenu.left(i+1);
467
restMenu = restMenu.mid(i+1);
469
item = (TreeItem*)(item ? item->firstChild() : firstChild());
472
MenuFolderInfo *folderInfo = item->folderInfo();
473
if (folderInfo && (folderInfo->id == subMenu))
478
item = (TreeItem*) item->nextSibling();
481
while( item && !restMenu.isEmpty());
485
setCurrentItem(item);
486
ensureItemVisible(item);
490
void TreeView::selectMenuEntry(const QString &menuEntry)
492
TreeItem *item = (TreeItem *) selectedItem();
495
item = (TreeItem *) currentItem();
496
while (item && item->isDirectory())
497
item = (TreeItem*) item->nextSibling();
500
item = (TreeItem *) item->firstChild();
504
MenuEntryInfo *entry = item->entryInfo();
507
kDebug()<<" entry->menuId() :"<<entry->menuId();
508
if ( entry->menuId() == menuEntry )
510
setCurrentItem(item);
511
ensureItemVisible(item);
515
item = (TreeItem*) item->nextSibling();
519
void TreeView::itemSelected(Q3ListViewItem *item)
521
TreeItem *_item = (TreeItem*)item;
522
bool selected = false;
523
bool dselected = false;
526
dselected = _item->isHidden();
529
m_ac->action("edit_cut")->setEnabled(selected);
530
m_ac->action("edit_copy")->setEnabled(selected);
532
if (m_ac->action("delete"))
533
m_ac->action("delete")->setEnabled(selected && !dselected);
537
emit disableAction();
541
if (_item->isDirectory())
542
emit entrySelected(_item->folderInfo());
544
emit entrySelected(_item->entryInfo());
547
void TreeView::currentChanged(MenuFolderInfo *folderInfo)
549
TreeItem *item = (TreeItem*)selectedItem();
550
if (item == 0) return;
551
if (folderInfo == 0) return;
553
item->setName(folderInfo->caption);
554
item->setPixmap(0, appIcon(folderInfo->icon));
557
void TreeView::currentChanged(MenuEntryInfo *entryInfo)
559
TreeItem *item = (TreeItem*)selectedItem();
560
if (item == 0) return;
561
if (entryInfo == 0) return;
565
if (m_detailedMenuEntries && entryInfo->description.length() != 0)
567
if (m_detailedEntriesNamesFirst)
569
name = entryInfo->caption + " (" + entryInfo->description + ')';
573
name = entryInfo->description + " (" + entryInfo->caption + ')';
578
name = entryInfo->caption;
581
item->setPixmap(0, appIcon(entryInfo->icon));
584
QStringList TreeView::fileList(const QString& rPath)
586
QString relativePath = rPath;
588
// truncate "/.directory"
589
int pos = relativePath.lastIndexOf("/.directory");
590
if (pos > 0) relativePath.truncate(pos);
592
QStringList filelist;
594
// loop through all resource dirs and build a file list
595
const QStringList resdirlist = KGlobal::dirs()->resourceDirs("apps");
596
for (QStringList::ConstIterator it = resdirlist.constBegin(); it != resdirlist.constEnd(); ++it)
598
QDir dir((*it) + '/' + relativePath);
599
if(!dir.exists()) continue;
601
dir.setFilter(QDir::Files);
602
dir.setNameFilters(QStringList() << "*.desktop;*.kdelnk");
604
// build a list of files
605
const QStringList files = dir.entryList();
606
for (QStringList::ConstIterator it = files.constBegin(); it != files.constEnd(); ++it) {
608
//if (filelist.contains(*it)) continue;
610
if (relativePath.isEmpty()) {
611
filelist.removeAll(*it); // hack
612
filelist.append(*it);
615
filelist.removeAll(relativePath + '/' + *it); //hack
616
filelist.append(relativePath + '/' + *it);
623
QStringList TreeView::dirList(const QString& rPath)
625
QString relativePath = rPath;
627
// truncate "/.directory"
628
int pos = relativePath.lastIndexOf("/.directory");
629
if (pos > 0) relativePath.truncate(pos);
633
// loop through all resource dirs and build a subdir list
634
const QStringList resdirlist = KGlobal::dirs()->resourceDirs("apps");
635
for (QStringList::ConstIterator it = resdirlist.constBegin(); it != resdirlist.constEnd(); ++it)
637
QDir dir((*it) + '/' + relativePath);
638
if(!dir.exists()) continue;
639
dir.setFilter(QDir::Dirs);
641
// build a list of subdirs
642
const QStringList subdirs = dir.entryList();
643
for (QStringList::ConstIterator it = subdirs.constBegin(); it != subdirs.constEnd(); ++it) {
644
if ((*it) == "." || (*it) == "..") continue;
646
// if (dirlist.contains(*it)) continue;
648
if (relativePath.isEmpty()) {
649
dirlist.removeAll(*it); //hack
653
dirlist.removeAll(relativePath + '/' + *it); //hack
654
dirlist.append(relativePath + '/' + *it);
661
bool TreeView::acceptDrag(QDropEvent* e) const
663
if (e->provides("application/x-kmenuedit-internal") &&
664
(e->source() == const_cast<TreeView *>(this)))
667
if (K3URLDrag::decode(e, urls) && (urls.count() == 1) &&
668
urls[0].isLocalFile() && urls[0].path().endsWith(".desktop"))
674
static QString createDesktopFile(const QString &file, QString *menuId, QStringList *excludeList)
676
QString base = file.mid(file.lastIndexOf('/')+1);
677
base = base.left(base.lastIndexOf('.'));
679
QRegExp r("(.*)(?=-\\d+)");
680
base = (r.indexIn(base) > -1) ? r.cap(1) : base;
682
QString result = KService::newServicePath(true, base, menuId, excludeList);
683
excludeList->append(*menuId);
684
// Todo for Undo-support: Undo menuId allocation:
689
static KDesktopFile *copyDesktopFile(MenuEntryInfo *entryInfo, QString *menuId, QStringList *excludeList)
691
QString result = createDesktopFile(entryInfo->file(), menuId, excludeList);
692
KDesktopFile *df = entryInfo->desktopFile()->copyTo(result);
693
df->desktopGroup().deleteEntry("Categories"); // Don't set any categories!
698
static QString createDirectoryFile(const QString &file, QStringList *excludeList)
700
QString base = file.mid(file.lastIndexOf('/')+1);
701
base = base.left(base.lastIndexOf('.'));
708
result = base + ".directory";
710
result = base + QString("-%1.directory").arg(i);
712
if (!excludeList->contains(result))
714
if (KStandardDirs::locate("xdgdata-dirs", result).isEmpty())
719
excludeList->append(result);
720
result = KStandardDirs::locateLocal("xdgdata-dirs", result);
725
void TreeView::slotDropped (QDropEvent * e, Q3ListViewItem *parent, Q3ListViewItem*after)
729
// get destination folder
730
TreeItem *parentItem = static_cast<TreeItem*>(parent);
731
QString folder = parentItem ? parentItem->directory() : QString();
732
MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
734
if (e->source() != this)
738
if (!K3URLDrag::decode(e, urls) || (urls.count() != 1) || !urls[0].isLocalFile())
740
QString path = urls[0].path();
741
if (!path.endsWith(".desktop"))
745
QString result = createDesktopFile(path, &menuId, &m_newMenuIds);
746
KDesktopFile orig_df(path);
747
KDesktopFile *df = orig_df.copyTo(result);
748
df->desktopGroup().deleteEntry("Categories"); // Don't set any categories!
750
KService::Ptr s(new KService(df));
751
s->setMenuId(menuId);
753
MenuEntryInfo *entryInfo = new MenuEntryInfo(s, df);
755
QString oldCaption = entryInfo->caption;
756
QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption, oldCaption);
757
entryInfo->setCaption(newCaption);
760
// m_menuFile->addEntry(folder, menuId);
761
m_menuFile->pushAction(MenuFile::ADD_ENTRY, folder, menuId);
763
// create the TreeItem
765
parentItem->setOpen(true);
767
// update fileInfo data
768
parentFolderInfo->add(entryInfo);
770
TreeItem *newItem = createTreeItem(parentItem, after, entryInfo, true);
772
setSelected ( newItem, true);
773
itemSelected( newItem);
776
setLayoutDirty(parentItem);
780
// is there content in the clipboard?
783
if (m_dragItem == after) return; // Nothing to do
785
int command = m_drag;
786
if (command == MOVE_FOLDER)
788
MenuFolderInfo *folderInfo = m_dragInfo;
789
if (e->action() == QDropEvent::Copy)
791
// Ugh.. this is hard :)
792
// * Create new .directory file
797
TreeItem *tmpItem = static_cast<TreeItem*>(parentItem);
800
if ( tmpItem == m_dragItem )
805
tmpItem = static_cast<TreeItem*>(tmpItem->parent() );
808
// Remove MenuFolderInfo
809
TreeItem *oldParentItem = static_cast<TreeItem*>(m_dragItem->parent());
810
MenuFolderInfo *oldParentFolderInfo = oldParentItem ? oldParentItem->folderInfo() : m_rootFolder;
811
oldParentFolderInfo->take(folderInfo);
814
QString oldFolder = folderInfo->fullId;
815
QString folderName = folderInfo->id;
816
QString newFolder = m_menuFile->uniqueMenuName(folder, folderName, parentFolderInfo->existingMenuIds());
817
folderInfo->id = newFolder;
820
//m_menuFile->moveMenu(oldFolder, folder + newFolder);
821
m_menuFile->pushAction(MenuFile::MOVE_MENU, oldFolder, folder + newFolder);
823
// Make sure caption is unique
824
QString newCaption = parentFolderInfo->uniqueMenuCaption(folderInfo->caption);
825
if (newCaption != folderInfo->caption)
827
folderInfo->setCaption(newCaption);
830
// create the TreeItem
832
parentItem->setOpen(true);
834
// update fileInfo data
835
folderInfo->updateFullId(parentFolderInfo->fullId);
836
folderInfo->setInUse(true);
837
parentFolderInfo->add(folderInfo);
839
if ((parentItem != oldParentItem) || !after)
842
oldParentItem->takeItem(m_dragItem);
844
takeItem(m_dragItem);
846
parentItem->insertItem(m_dragItem);
848
insertItem(m_dragItem);
850
m_dragItem->moveItem(after);
851
m_dragItem->setName(folderInfo->caption);
852
m_dragItem->setDirectoryPath(folderInfo->fullId);
853
setSelected(m_dragItem, true);
854
itemSelected(m_dragItem);
857
else if (command == MOVE_FILE)
859
MenuEntryInfo *entryInfo = m_dragItem->entryInfo();
860
QString menuId = entryInfo->menuId();
862
if (e->action() == QDropEvent::Copy)
865
// Need to copy file and then add it
866
KDesktopFile *df = copyDesktopFile(entryInfo, &menuId, &m_newMenuIds); // Duplicate
867
//UNDO-ACTION: NEW_MENU_ID (menuId)
869
KService::Ptr s(new KService(df));
870
s->setMenuId(menuId);
872
entryInfo = new MenuEntryInfo(s, df);
874
QString oldCaption = entryInfo->caption;
875
QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption, oldCaption);
876
entryInfo->setCaption(newCaption);
880
del(m_dragItem, false);
881
QString oldCaption = entryInfo->caption;
882
QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption);
883
entryInfo->setCaption(newCaption);
884
entryInfo->setInUse(true);
887
// m_menuFile->addEntry(folder, menuId);
888
m_menuFile->pushAction(MenuFile::ADD_ENTRY, folder, menuId);
890
// create the TreeItem
892
parentItem->setOpen(true);
894
// update fileInfo data
895
parentFolderInfo->add(entryInfo);
897
TreeItem *newItem = createTreeItem(parentItem, after, entryInfo, true);
899
setSelected ( newItem, true);
900
itemSelected( newItem);
902
else if (command == COPY_SEPARATOR)
904
if (e->action() != QDropEvent::Copy)
905
del(m_dragItem, false);
907
TreeItem *newItem = createTreeItem(parentItem, after, m_separator, true);
909
setSelected ( newItem, true);
910
itemSelected( newItem);
917
setLayoutDirty(parentItem);
921
void TreeView::startDrag()
923
Q3DragObject *drag = dragObject();
931
Q3DragObject *TreeView::dragObject()
934
TreeItem *item = (TreeItem*)selectedItem();
935
if(item == 0) return 0;
937
K3MultipleDrag *drag = new K3MultipleDrag( this );
939
if (item->isDirectory())
941
m_drag = MOVE_FOLDER;
942
m_dragInfo = item->folderInfo();
945
else if (item->isEntry())
950
QString menuId = item->menuId();
951
m_dragPath = item->entryInfo()->service->entryPath();
952
if (!m_dragPath.isEmpty())
953
m_dragPath = KStandardDirs::locate("apps", m_dragPath);
954
if (!m_dragPath.isEmpty())
957
url.setPath(m_dragPath);
958
drag->addDragObject( new K3URLDrag(url, 0));
963
m_drag = COPY_SEPARATOR;
968
drag->addDragObject( new Q3StoredDrag("application/x-kmenuedit-internal", 0));
969
if ( item->pixmap(0) )
970
drag->setPixmap(*item->pixmap(0));
974
void TreeView::slotRMBPressed(Q3ListViewItem*, const QPoint& p)
976
TreeItem *item = (TreeItem*)selectedItem();
977
if(item == 0) return;
979
if(m_rmb) m_rmb->exec(p);
982
void TreeView::newsubmenu()
984
TreeItem *parentItem = 0;
985
TreeItem *item = (TreeItem*)selectedItem();
988
QString caption = KInputDialog::getText( i18n( "New Submenu" ),
989
i18n( "Submenu name:" ), QString(), &ok, this );
993
QString file = caption;
994
file.replace('/', '-');
996
file = createDirectoryFile(file, &m_newDirectoryList); // Create
998
// get destination folder
1006
else if(item->isDirectory())
1010
folder = parentItem->directory();
1014
parentItem = static_cast<TreeItem*>(item->parent());
1015
folder = parentItem ? parentItem->directory() : QString();
1018
MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
1019
MenuFolderInfo *folderInfo = new MenuFolderInfo();
1020
folderInfo->caption = parentFolderInfo->uniqueMenuCaption(caption);
1021
folderInfo->id = m_menuFile->uniqueMenuName(folder, caption, parentFolderInfo->existingMenuIds());
1022
folderInfo->directoryFile = file;
1023
folderInfo->icon = "package";
1024
folderInfo->hidden = false;
1025
folderInfo->setDirty();
1027
KDesktopFile *df = new KDesktopFile(file);
1028
KConfigGroup desktopGroup = df->desktopGroup();
1029
desktopGroup.writeEntry("Name", folderInfo->caption);
1030
desktopGroup.writeEntry("Icon", folderInfo->icon);
1034
// m_menuFile->addMenu(folder + folderInfo->id, file);
1035
m_menuFile->pushAction(MenuFile::ADD_MENU, folder + folderInfo->id, file);
1037
folderInfo->fullId = parentFolderInfo->fullId + folderInfo->id;
1039
// create the TreeItem
1041
parentItem->setOpen(true);
1043
// update fileInfo data
1044
parentFolderInfo->add(folderInfo);
1046
TreeItem *newItem = createTreeItem(parentItem, item, folderInfo, true);
1048
setSelected ( newItem, true);
1049
itemSelected( newItem);
1051
setLayoutDirty(parentItem);
1054
void TreeView::newitem()
1056
TreeItem *parentItem = 0;
1057
TreeItem *item = (TreeItem*)selectedItem();
1060
QString caption = KInputDialog::getText( i18n( "New Item" ),
1061
i18n( "Item name:" ), QString(), &ok, this );
1066
QString file = caption;
1067
file.replace('/', '-');
1069
file = createDesktopFile(file, &menuId, &m_newMenuIds); // Create
1071
KDesktopFile *df = new KDesktopFile(file);
1072
KConfigGroup desktopGroup = df->desktopGroup();
1073
desktopGroup.writeEntry("Name", caption);
1074
desktopGroup.writeEntry("Type", "Application");
1076
// get destination folder
1084
else if(item->isDirectory())
1088
folder = parentItem->directory();
1092
parentItem = static_cast<TreeItem*>(item->parent());
1093
folder = parentItem ? parentItem->directory() : QString();
1096
MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
1099
// m_menuFile->addEntry(folder, menuId);
1100
m_menuFile->pushAction(MenuFile::ADD_ENTRY, folder, menuId);
1102
KService::Ptr s(new KService(df));
1103
s->setMenuId(menuId);
1105
MenuEntryInfo *entryInfo = new MenuEntryInfo(s, df);
1107
// create the TreeItem
1109
parentItem->setOpen(true);
1111
// update fileInfo data
1112
parentFolderInfo->add(entryInfo);
1114
TreeItem *newItem = createTreeItem(parentItem, item, entryInfo, true);
1116
setSelected ( newItem, true);
1117
itemSelected( newItem);
1119
setLayoutDirty(parentItem);
1122
void TreeView::newsep()
1124
TreeItem *parentItem = 0;
1125
TreeItem *item = (TreeItem*)selectedItem();
1131
else if(item->isDirectory())
1138
parentItem = static_cast<TreeItem*>(item->parent());
1141
// create the TreeItem
1143
parentItem->setOpen(true);
1145
TreeItem *newItem = createTreeItem(parentItem, item, m_separator, true);
1147
setSelected ( newItem, true);
1148
itemSelected( newItem);
1150
setLayoutDirty(parentItem);
1153
void TreeView::cut()
1157
m_ac->action("edit_cut")->setEnabled(false);
1158
m_ac->action("edit_copy")->setEnabled(false);
1159
m_ac->action("delete")->setEnabled(false);
1161
// Select new current item
1162
setSelected( currentItem(), true );
1163
// Switch the UI to show that item
1164
itemSelected( selectedItem() );
1167
void TreeView::copy()
1172
void TreeView::copy( bool cutting )
1174
TreeItem *item = (TreeItem*)selectedItem();
1176
// nil selected? -> nil to copy
1177
if (item == 0) return;
1180
setLayoutDirty((TreeItem*)item->parent());
1182
// clean up old stuff
1185
// is item a folder or a file?
1186
if(item->isDirectory())
1188
QString folder = item->directory();
1191
// Place in clipboard
1192
m_clipboard = MOVE_FOLDER;
1193
m_clipboardFolderInfo = item->folderInfo();
1199
// Place in clipboard
1200
m_clipboard = COPY_FOLDER;
1201
m_clipboardFolderInfo = item->folderInfo();
1204
else if (item->isEntry())
1208
// Place in clipboard
1209
m_clipboard = MOVE_FILE;
1210
m_clipboardEntryInfo = item->entryInfo();
1216
// Place in clipboard
1217
m_clipboard = COPY_FILE;
1218
m_clipboardEntryInfo = item->entryInfo();
1223
// Place in clipboard
1224
m_clipboard = COPY_SEPARATOR;
1229
m_ac->action("edit_paste")->setEnabled(true);
1233
void TreeView::paste()
1235
TreeItem *parentItem = 0;
1236
TreeItem *item = (TreeItem*)selectedItem();
1238
// nil selected? -> nil to paste to
1239
if (item == 0) return;
1241
// is there content in the clipboard?
1242
if (!m_clipboard) return;
1244
// get destination folder
1247
if(item->isDirectory())
1251
folder = parentItem->directory();
1255
parentItem = static_cast<TreeItem*>(item->parent());
1256
folder = parentItem ? parentItem->directory() : QString();
1259
MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
1260
int command = m_clipboard;
1261
if ((command == COPY_FOLDER) || (command == MOVE_FOLDER))
1263
MenuFolderInfo *folderInfo = m_clipboardFolderInfo;
1264
if (command == COPY_FOLDER)
1266
// Ugh.. this is hard :)
1267
// * Create new .directory file
1270
else if (command == MOVE_FOLDER)
1273
QString oldFolder = folderInfo->fullId;
1274
QString folderName = folderInfo->id;
1275
QString newFolder = m_menuFile->uniqueMenuName(folder, folderName, parentFolderInfo->existingMenuIds());
1276
folderInfo->id = newFolder;
1279
// m_menuFile->moveMenu(oldFolder, folder + newFolder);
1280
m_menuFile->pushAction(MenuFile::MOVE_MENU, oldFolder, folder + newFolder);
1282
// Make sure caption is unique
1283
QString newCaption = parentFolderInfo->uniqueMenuCaption(folderInfo->caption);
1284
if (newCaption != folderInfo->caption)
1286
folderInfo->setCaption(newCaption);
1288
// create the TreeItem
1290
parentItem->setOpen(true);
1292
// update fileInfo data
1293
folderInfo->fullId = parentFolderInfo->fullId + folderInfo->id;
1294
folderInfo->setInUse(true);
1295
parentFolderInfo->add(folderInfo);
1297
TreeItem *newItem = createTreeItem(parentItem, item, folderInfo);
1299
setSelected ( newItem, true);
1300
itemSelected( newItem);
1303
m_clipboard = COPY_FOLDER; // Next one copies.
1305
else if ((command == COPY_FILE) || (command == MOVE_FILE))
1307
MenuEntryInfo *entryInfo = m_clipboardEntryInfo;
1310
if (command == COPY_FILE)
1312
// Need to copy file and then add it
1313
KDesktopFile *df = copyDesktopFile(entryInfo, &menuId, &m_newMenuIds); // Duplicate
1315
KService::Ptr s(new KService(df));
1316
s->setMenuId(menuId);
1317
entryInfo = new MenuEntryInfo(s, df);
1319
QString oldCaption = entryInfo->caption;
1320
QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption, oldCaption);
1321
entryInfo->setCaption(newCaption);
1323
else if (command == MOVE_FILE)
1325
menuId = entryInfo->menuId();
1326
m_clipboard = COPY_FILE; // Next one copies.
1328
QString oldCaption = entryInfo->caption;
1329
QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption);
1330
entryInfo->setCaption(newCaption);
1331
entryInfo->setInUse(true);
1334
// m_menuFile->addEntry(folder, menuId);
1335
m_menuFile->pushAction(MenuFile::ADD_ENTRY, folder, menuId);
1337
// create the TreeItem
1339
parentItem->setOpen(true);
1341
// update fileInfo data
1342
parentFolderInfo->add(entryInfo);
1344
TreeItem *newItem = createTreeItem(parentItem, item, entryInfo, true);
1346
setSelected ( newItem, true);
1347
itemSelected( newItem);
1353
parentItem->setOpen(true);
1355
TreeItem *newItem = createTreeItem(parentItem, item, m_separator, true);
1357
setSelected ( newItem, true);
1358
itemSelected( newItem);
1360
setLayoutDirty(parentItem);
1363
void TreeView::del()
1365
TreeItem *item = (TreeItem*)selectedItem();
1367
// nil selected? -> nil to delete
1368
if (item == 0) return;
1372
m_ac->action("edit_cut")->setEnabled(false);
1373
m_ac->action("edit_copy")->setEnabled(false);
1374
m_ac->action("delete")->setEnabled(false);
1375
// Select new current item
1376
setSelected( currentItem(), true );
1377
// Switch the UI to show that item
1378
itemSelected( selectedItem() );
1381
void TreeView::del(TreeItem *item, bool deleteInfo)
1383
TreeItem *parentItem = static_cast<TreeItem*>(item->parent());
1384
// is file a .directory or a .desktop file
1385
if(item->isDirectory())
1387
if ( KMessageBox::warningYesNo(this, i18n("All submenus of '%1' will be removed. Do you want to continue?", item->name() ) ) == KMessageBox::No )
1390
MenuFolderInfo *folderInfo = item->folderInfo();
1392
// Remove MenuFolderInfo
1393
MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
1394
parentFolderInfo->take(folderInfo);
1395
folderInfo->setInUse(false);
1397
if (m_clipboard == COPY_FOLDER && (m_clipboardFolderInfo == folderInfo))
1399
// Copy + Del == Cut
1400
m_clipboard = MOVE_FOLDER; // Clipboard now owns folderInfo
1405
if (folderInfo->takeRecursive(m_clipboardFolderInfo))
1406
m_clipboard = MOVE_FOLDER; // Clipboard now owns m_clipboardFolderInfo
1409
delete folderInfo; // Delete folderInfo
1413
// m_menuFile->removeMenu(item->directory());
1414
m_menuFile->pushAction(MenuFile::REMOVE_MENU, item->directory(), QString());
1419
else if (item->isEntry())
1421
MenuEntryInfo *entryInfo = item->entryInfo();
1422
QString menuId = entryInfo->menuId();
1424
// Remove MenuFolderInfo
1425
MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
1426
parentFolderInfo->take(entryInfo);
1427
entryInfo->setInUse(false);
1429
if (m_clipboard == COPY_FILE && (m_clipboardEntryInfo == entryInfo))
1431
// Copy + Del == Cut
1432
m_clipboard = MOVE_FILE; // Clipboard now owns entryInfo
1437
delete entryInfo; // Delete entryInfo
1441
QString folder = parentItem ? parentItem->directory() : QString();
1442
// m_menuFile->removeEntry(folder, menuId);
1443
m_menuFile->pushAction(MenuFile::REMOVE_ENTRY, folder, menuId);
1453
setLayoutDirty(parentItem);
1456
void TreeView::cleanupClipboard() {
1457
if (m_clipboard == MOVE_FOLDER)
1458
delete m_clipboardFolderInfo;
1459
m_clipboardFolderInfo = 0;
1461
if (m_clipboard == MOVE_FILE)
1462
delete m_clipboardEntryInfo;
1463
m_clipboardEntryInfo = 0;
1468
static QStringList extractLayout(TreeItem *item)
1470
bool firstFolder = true;
1471
bool firstEntry = true;
1473
for(;item; item = static_cast<TreeItem*>(item->nextSibling()))
1475
if (item->isDirectory())
1479
firstFolder = false;
1480
layout << ":M"; // Add new folders here...
1482
layout << (item->folderInfo()->id);
1484
else if (item->isEntry())
1489
layout << ":F"; // Add new entries here...
1491
layout << (item->entryInfo()->menuId());
1501
QStringList TreeItem::layout()
1503
QStringList layout = extractLayout(static_cast<TreeItem*>(firstChild()));
1504
_layoutDirty = false;
1508
void TreeView::saveLayout()
1512
QStringList layout = extractLayout(static_cast<TreeItem*>(firstChild()));
1513
m_menuFile->setLayout(m_rootFolder->fullId, layout);
1514
m_layoutDirty = false;
1517
Q3PtrList<Q3ListViewItem> lst;
1518
Q3ListViewItemIterator it( this );
1519
while ( it.current() ) {
1520
TreeItem *item = static_cast<TreeItem*>(it.current());
1521
if ( item->isLayoutDirty() )
1523
m_menuFile->setLayout(item->folderInfo()->fullId, item->layout());
1529
bool TreeView::save()
1532
m_rootFolder->save(m_menuFile);
1534
bool success = m_menuFile->performAllActions();
1536
m_newMenuIds.clear();
1537
m_newDirectoryList.clear();
1541
KBuildSycocaProgressDialog::rebuildKSycoca(this);
1545
KMessageBox::sorry(this, "<qt>"+i18n("Menu changes could not be saved because of the following problem:")+"<br><br>"+
1546
m_menuFile->error()+"</qt>");
1554
void TreeView::setLayoutDirty(TreeItem *parentItem)
1557
parentItem->setLayoutDirty();
1559
m_layoutDirty = true;
1562
bool TreeView::isLayoutDirty()
1564
Q3PtrList<Q3ListViewItem> lst;
1565
Q3ListViewItemIterator it( this );
1566
while ( it.current() ) {
1567
if ( static_cast<TreeItem*>(it.current())->isLayoutDirty() )
1574
bool TreeView::dirty()
1576
return m_layoutDirty || m_rootFolder->hasDirt() || m_menuFile->dirty() || isLayoutDirty();
1579
void TreeView::findServiceShortcut(const KShortcut&cut, KService::Ptr &service)
1581
service = m_rootFolder->findServiceShortcut(cut);
1584
void TreeView::restoreMenuSystem()
1586
if ( KMessageBox::warningYesNo( this, i18n( "Do you want to restore the system menu? Warning: This will remove all custom menus." ) )==KMessageBox::No )
1588
QString kmenueditfile = KStandardDirs::locateLocal("xdgconf-menu", "applications-kmenuedit.menu");
1589
if ( QFile::exists( kmenueditfile ) )
1591
if ( !QFile::remove( kmenueditfile ) )
1592
qWarning()<<"Could not delete "<<kmenueditfile;
1595
QString xdgdir = KGlobal::dirs()->KStandardDirs::localxdgdatadir();
1596
if ( !KIO::NetAccess::del( QString(xdgdir + "/applications") , this) )
1597
qWarning()<<"Could not delete dir :"<<( xdgdir+"/applications" );
1598
if ( !KIO::NetAccess::del( QString(xdgdir +"/desktop-directories") , this) )
1599
qWarning()<<"Could not delete dir :"<<( xdgdir + "/desktop-directories");
1601
KBuildSycocaProgressDialog::rebuildKSycoca(this);
1604
delete m_rootFolder;
1607
m_layoutDirty = false;
1608
m_newMenuIds.clear();
1609
m_newDirectoryList.clear();
1610
m_menuFile->restoreMenuSystem(kmenueditfile);
1612
m_rootFolder = new MenuFolderInfo;
1613
m_separator = new MenuSeparatorInfo;
1615
readMenuFolderInfo();
1618
emit disableAction();
1619
emit entrySelected(( MenuEntryInfo* ) 0 );
1622
void TreeView::updateTreeView(bool showHidden)
1624
m_showHidden = showHidden;
1627
delete m_rootFolder;
1630
m_layoutDirty = false;
1631
m_newMenuIds.clear();
1632
m_newDirectoryList.clear();
1634
m_rootFolder = new MenuFolderInfo;
1635
m_separator = new MenuSeparatorInfo;
1637
readMenuFolderInfo();
1640
emit disableAction();
1641
emit entrySelected(( MenuEntryInfo* ) 0 );
1644
void TreeView::sendReloadMenu()
1646
QDBusMessage message =
1647
QDBusMessage::createSignal("/kickoff", "org.kde.plasma", "reloadMenu");
1648
QDBusConnection::sessionBus().send(message);