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 <kstandarddirs.h>
55
#include <k3multipledrag.h>
56
#include <k3urldrag.h>
59
#include "treeview.moc"
64
#define MOVE_FOLDER 'M'
65
#define COPY_FOLDER 'C'
68
#define COPY_SEPARATOR 'S'
70
TreeItem::TreeItem(Q3ListViewItem *parent, Q3ListViewItem *after, const QString& menuId, bool __init)
71
:Q3ListViewItem(parent, after), _hidden(false), _init(__init), _layoutDirty(false), _menuId(menuId),
72
m_folderInfo(0), m_entryInfo(0) {}
74
TreeItem::TreeItem(Q3ListView *parent, Q3ListViewItem *after, const QString& menuId, bool __init)
75
: Q3ListViewItem(parent, after), _hidden(false), _init(__init), _layoutDirty(false), _menuId(menuId),
76
m_folderInfo(0), m_entryInfo(0) {}
78
void TreeItem::setName(const QString &name)
84
void TreeItem::setHidden(bool b)
86
if (_hidden == b) return;
91
void TreeItem::update()
95
s += i18n(" [Hidden]");
99
void TreeItem::setOpen(bool o)
104
Q3ListViewItem::setOpen(o);
107
void TreeItem::load()
109
if (m_folderInfo && !_init)
112
TreeView *tv = static_cast<TreeView *>(listView());
113
tv->fillBranch(m_folderInfo, this);
117
void TreeItem::paintCell ( QPainter * p, const QColorGroup & cg, int column, int width, int align )
119
Q3ListViewItem::paintCell(p, cg, column, width, align);
121
if (!m_folderInfo && !m_entryInfo)
124
int h = (height() / 2) -1;
126
p->setPen( cg.color( QPalette::HighlightedText ) );
128
p->setPen( cg.color( QPalette::Text ) );
134
void TreeItem::setup()
136
Q3ListViewItem::setup();
137
if (!m_folderInfo && !m_entryInfo)
141
static QPixmap appIcon(const QString &iconName)
143
QPixmap normal = KIconLoader::global()->loadIcon(iconName, K3Icon::Small, 0, K3Icon::DefaultState, QStringList(), 0L, true);
144
// make sure they are not larger than 20x20
145
if (normal.width() > 20 || normal.height() > 20)
147
QImage tmp = normal.toImage();
148
tmp = tmp.scaled(20, 20, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
149
normal = QPixmap::fromImage(tmp);
155
TreeView::TreeView( bool controlCenter, KActionCollection *ac, QWidget *parent, const char *name )
156
: K3ListView(parent), m_ac(ac), m_rmb(0), m_clipboard(0),
157
m_clipboardFolderInfo(0), m_clipboardEntryInfo(0),
158
m_controlCenter(controlCenter), m_layoutDirty(false)
161
setFrameStyle(QFrame::WinPanel | QFrame::Sunken);
162
setAllColumnsShowFocus(true);
163
setRootIsDecorated(true);
165
setAcceptDrops(true);
166
setDropVisualizer(true);
167
setDragEnabled(true);
168
setMinimumWidth(240);
173
connect(this, SIGNAL(dropped(QDropEvent*, Q3ListViewItem*, Q3ListViewItem*)),
174
SLOT(slotDropped(QDropEvent*, Q3ListViewItem*, Q3ListViewItem*)));
176
connect(this, SIGNAL(clicked( Q3ListViewItem* )),
177
SLOT(itemSelected( Q3ListViewItem* )));
179
connect(this,SIGNAL(selectionChanged ( Q3ListViewItem * )),
180
SLOT(itemSelected( Q3ListViewItem* )));
182
connect(this, SIGNAL(rightButtonPressed(Q3ListViewItem*, const QPoint&, int)),
183
SLOT(slotRMBPressed(Q3ListViewItem*, const QPoint&)));
186
connect(m_ac->action("newitem"), SIGNAL(activated()), SLOT(newitem()));
187
connect(m_ac->action("newsubmenu"), SIGNAL(activated()), SLOT(newsubmenu()));
188
if (m_ac->action("newsep"))
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);
206
TreeView::~TreeView() {
212
void TreeView::setViewMode(bool showHidden)
217
m_rmb = new QMenu(this);
220
action = m_ac->action("edit_cut");
222
m_rmb->addAction( action );
223
action->setEnabled(false);
224
connect(action, SIGNAL(activated()), SLOT(cut()));
227
action = m_ac->action("edit_copy");
229
m_rmb->addAction( action );
230
action->setEnabled(false);
231
connect(action, SIGNAL(activated()), SLOT(copy()));
234
action = m_ac->action("edit_paste");
236
m_rmb->addAction( action );
237
action->setEnabled(false);
238
connect(action, SIGNAL(activated()), SLOT(paste()));
241
m_rmb->addSeparator();
243
action = m_ac->action("delete");
245
m_rmb->addAction( action );
246
action->setEnabled(false);
247
connect(action, SIGNAL(activated()), SLOT(del()));
250
m_rmb->addSeparator();
252
if(m_ac->action("newitem"))
253
m_rmb->addAction( m_ac->action("newitem") );
254
if(m_ac->action("newsubmenu"))
255
m_rmb->addAction( m_ac->action("newsubmenu") );
256
if(m_ac->action("newsep"))
257
m_rmb->addAction( m_ac->action("newsep") );
259
m_showHidden = showHidden;
260
readMenuFolderInfo();
264
void TreeView::readMenuFolderInfo(MenuFolderInfo *folderInfo, KServiceGroup::Ptr folder, const QString &prefix)
268
folderInfo = m_rootFolder;
270
folder = KServiceGroup::baseGroup("settings");
272
folder = KServiceGroup::root();
275
if (!folder || !folder->isValid())
278
folderInfo->caption = folder->caption();
279
folderInfo->comment = folder->comment();
281
// Item names may contain ampersands. To avoid them being converted
282
// to accelerators, replace them with two ampersands.
283
folderInfo->hidden = folder->noDisplay();
284
folderInfo->directoryFile = folder->directoryEntryPath();
285
folderInfo->icon = folder->icon();
286
QString id = folder->relPath();
287
int i = id.lastIndexOf('/', -2);
290
folderInfo->fullId = prefix + id;
292
foreach(const KSycocaEntry::Ptr &e, folder->entries(true, !m_showHidden, true, m_detailedMenuEntries && !m_detailedEntriesNamesFirst))
294
if (e->isType(KST_KServiceGroup))
296
KServiceGroup::Ptr g(KServiceGroup::Ptr::staticCast(e));
297
MenuFolderInfo *subFolderInfo = new MenuFolderInfo();
298
readMenuFolderInfo(subFolderInfo, g, folderInfo->fullId);
299
folderInfo->add(subFolderInfo, true);
301
else if (e->isType(KST_KService))
303
folderInfo->add(new MenuEntryInfo(KService::Ptr::staticCast(e)), true);
305
else if (e->isType(KST_KServiceSeparator))
307
folderInfo->add(m_separator, true);
312
void TreeView::fill()
314
QApplication::setOverrideCursor(Qt::WaitCursor);
316
fillBranch(m_rootFolder, 0);
317
QApplication::restoreOverrideCursor();
320
QString TreeView::findName(KDesktopFile *df, bool deleted)
322
QString name = df->readName();
329
QString file = df->fileName();
330
QString res = df->resource();
333
QStringList files = KGlobal::dirs()->findAllResources(res.toLatin1(), file);
334
for(QStringList::ConstIterator it = files.begin();
344
KDesktopFile df2(*it);
345
name = df2.readName();
347
if (!name.isEmpty() && (name != "empty"))
355
TreeItem *TreeView::createTreeItem(TreeItem *parent, Q3ListViewItem *after, MenuFolderInfo *folderInfo, bool _init)
359
item = new TreeItem(this, after, QString(), _init);
361
item = new TreeItem(parent, after, QString(), _init);
363
item->setMenuFolderInfo(folderInfo);
364
item->setName(folderInfo->caption);
365
item->setPixmap(0, appIcon(folderInfo->icon));
366
item->setDirectoryPath(folderInfo->fullId);
367
item->setHidden(folderInfo->hidden);
368
item->setExpandable(true);
372
TreeItem *TreeView::createTreeItem(TreeItem *parent, Q3ListViewItem *after, MenuEntryInfo *entryInfo, bool _init)
374
bool hidden = entryInfo->hidden;
378
item = new TreeItem(this, after, entryInfo->menuId(), _init);
380
item = new TreeItem(parent, after, entryInfo->menuId(),_init);
384
if (m_detailedMenuEntries && entryInfo->description.length() != 0)
386
if (m_detailedEntriesNamesFirst)
388
name = entryInfo->caption + " (" + entryInfo->description + ')';
392
name = entryInfo->description + " (" + entryInfo->caption + ')';
397
name = entryInfo->caption;
399
item->setMenuEntryInfo(entryInfo);
401
item->setPixmap(0, appIcon(entryInfo->icon));
403
item->setHidden(hidden);
407
TreeItem *TreeView::createTreeItem(TreeItem *parent, Q3ListViewItem *after, MenuSeparatorInfo *, bool _init)
411
item = new TreeItem(this, after, QString(), _init);
413
item = new TreeItem(parent, after, QString(),_init);
418
void TreeView::fillBranch(MenuFolderInfo *folderInfo, TreeItem *parent)
420
QString relPath = parent ? parent->directory() : QString();
421
Q3PtrListIterator<MenuInfo> it( folderInfo->initialLayout );
423
for (MenuInfo *info; (info = it.current()); ++it)
425
MenuEntryInfo *entry = dynamic_cast<MenuEntryInfo*>(info);
428
after = createTreeItem(parent, after, entry);
432
MenuFolderInfo *subFolder = dynamic_cast<MenuFolderInfo*>(info);
435
after = createTreeItem(parent, after, subFolder);
438
MenuSeparatorInfo *separator = dynamic_cast<MenuSeparatorInfo*>(info);
441
after = createTreeItem(parent, after, separator);
447
void TreeView::closeAllItems(Q3ListViewItem *item)
452
item->setOpen(false);
453
closeAllItems(item->firstChild());
454
item = item->nextSibling();
458
void TreeView::selectMenu(const QString &menu)
460
closeAllItems(firstChild());
462
if (menu.length() <= 1)
464
setCurrentItem(firstChild());
469
QString restMenu = menu.mid(1);
470
if (!restMenu.endsWith('/'))
476
int i = restMenu.indexOf("/");
477
QString subMenu = restMenu.left(i+1);
478
restMenu = restMenu.mid(i+1);
480
item = (TreeItem*)(item ? item->firstChild() : firstChild());
483
MenuFolderInfo *folderInfo = item->folderInfo();
484
if (folderInfo && (folderInfo->id == subMenu))
489
item = (TreeItem*) item->nextSibling();
492
while( item && !restMenu.isEmpty());
496
setCurrentItem(item);
497
ensureItemVisible(item);
501
void TreeView::selectMenuEntry(const QString &menuEntry)
503
TreeItem *item = (TreeItem *) selectedItem();
506
item = (TreeItem *) currentItem();
507
while (item && item->isDirectory())
508
item = (TreeItem*) item->nextSibling();
511
item = (TreeItem *) item->firstChild();
515
MenuEntryInfo *entry = item->entryInfo();
516
if (entry && (entry->menuId() == menuEntry))
518
setCurrentItem(item);
519
ensureItemVisible(item);
522
item = (TreeItem*) item->nextSibling();
526
void TreeView::itemSelected(Q3ListViewItem *item)
528
TreeItem *_item = (TreeItem*)item;
529
bool selected = false;
530
bool dselected = false;
533
dselected = _item->isHidden();
536
m_ac->action("edit_cut")->setEnabled(selected);
537
m_ac->action("edit_copy")->setEnabled(selected);
539
if (m_ac->action("delete"))
540
m_ac->action("delete")->setEnabled(selected && !dselected);
544
emit disableAction();
548
if (_item->isDirectory())
549
emit entrySelected(_item->folderInfo());
551
emit entrySelected(_item->entryInfo());
554
void TreeView::currentChanged(MenuFolderInfo *folderInfo)
556
TreeItem *item = (TreeItem*)selectedItem();
557
if (item == 0) return;
558
if (folderInfo == 0) return;
560
item->setName(folderInfo->caption);
561
item->setPixmap(0, appIcon(folderInfo->icon));
564
void TreeView::currentChanged(MenuEntryInfo *entryInfo)
566
TreeItem *item = (TreeItem*)selectedItem();
567
if (item == 0) return;
568
if (entryInfo == 0) return;
572
if (m_detailedMenuEntries && entryInfo->description.length() != 0)
574
if (m_detailedEntriesNamesFirst)
576
name = entryInfo->caption + " (" + entryInfo->description + ')';
580
name = entryInfo->description + " (" + entryInfo->caption + ')';
585
name = entryInfo->caption;
588
item->setPixmap(0, appIcon(entryInfo->icon));
591
QStringList TreeView::fileList(const QString& rPath)
593
QString relativePath = rPath;
595
// truncate "/.directory"
596
int pos = relativePath.lastIndexOf("/.directory");
597
if (pos > 0) relativePath.truncate(pos);
599
QStringList filelist;
601
// loop through all resource dirs and build a file list
602
QStringList resdirlist = KGlobal::dirs()->resourceDirs("apps");
603
for (QStringList::ConstIterator it = resdirlist.begin(); it != resdirlist.end(); ++it)
605
QDir dir((*it) + '/' + relativePath);
606
if(!dir.exists()) continue;
608
dir.setFilter(QDir::Files);
609
dir.setNameFilter("*.desktop;*.kdelnk");
611
// build a list of files
612
QStringList files = dir.entryList();
613
for (QStringList::ConstIterator it = files.begin(); it != files.end(); ++it) {
615
//if (filelist.contains(*it)) continue;
617
if (relativePath.isEmpty()) {
618
filelist.removeAll(*it); // hack
619
filelist.append(*it);
622
filelist.removeAll(relativePath + '/' + *it); //hack
623
filelist.append(relativePath + '/' + *it);
630
QStringList TreeView::dirList(const QString& rPath)
632
QString relativePath = rPath;
634
// truncate "/.directory"
635
int pos = relativePath.lastIndexOf("/.directory");
636
if (pos > 0) relativePath.truncate(pos);
640
// loop through all resource dirs and build a subdir list
641
QStringList resdirlist = KGlobal::dirs()->resourceDirs("apps");
642
for (QStringList::ConstIterator it = resdirlist.begin(); it != resdirlist.end(); ++it)
644
QDir dir((*it) + '/' + relativePath);
645
if(!dir.exists()) continue;
646
dir.setFilter(QDir::Dirs);
648
// build a list of subdirs
649
QStringList subdirs = dir.entryList();
650
for (QStringList::ConstIterator it = subdirs.begin(); it != subdirs.end(); ++it) {
651
if ((*it) == "." || (*it) == "..") continue;
653
// if (dirlist.contains(*it)) continue;
655
if (relativePath.isEmpty()) {
656
dirlist.removeAll(*it); //hack
660
dirlist.removeAll(relativePath + '/' + *it); //hack
661
dirlist.append(relativePath + '/' + *it);
668
bool TreeView::acceptDrag(QDropEvent* e) const
670
if (e->provides("application/x-kmenuedit-internal") &&
671
(e->source() == const_cast<TreeView *>(this)))
674
if (K3URLDrag::decode(e, urls) && (urls.count() == 1) &&
675
urls[0].isLocalFile() && urls[0].path().endsWith(".desktop"))
681
static QString createDesktopFile(const QString &file, QString *menuId, QStringList *excludeList)
683
QString base = file.mid(file.lastIndexOf('/')+1);
684
base = base.left(base.lastIndexOf('.'));
686
QRegExp r("(.*)(?=-\\d+)");
687
base = (r.indexIn(base) > -1) ? r.cap(1) : base;
689
QString result = KService::newServicePath(true, base, menuId, excludeList);
690
excludeList->append(*menuId);
691
// Todo for Undo-support: Undo menuId allocation:
696
static KDesktopFile *copyDesktopFile(MenuEntryInfo *entryInfo, QString *menuId, QStringList *excludeList)
698
QString result = createDesktopFile(entryInfo->file(), menuId, excludeList);
699
KDesktopFile *df = entryInfo->desktopFile()->copyTo(result);
700
df->desktopGroup().deleteEntry("Categories"); // Don't set any categories!
705
static QString createDirectoryFile(const QString &file, QStringList *excludeList)
707
QString base = file.mid(file.lastIndexOf('/')+1);
708
base = base.left(base.lastIndexOf('.'));
715
result = base + ".directory";
717
result = base + QString("-%1.directory").arg(i);
719
if (!excludeList->contains(result))
721
if (KStandardDirs::locate("xdgdata-dirs", result).isEmpty())
726
excludeList->append(result);
727
result = KStandardDirs::locateLocal("xdgdata-dirs", result);
732
void TreeView::slotDropped (QDropEvent * e, Q3ListViewItem *parent, Q3ListViewItem*after)
736
// get destination folder
737
TreeItem *parentItem = static_cast<TreeItem*>(parent);
738
QString folder = parentItem ? parentItem->directory() : QString();
739
MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
741
if (e->source() != this)
745
if (!K3URLDrag::decode(e, urls) || (urls.count() != 1) || !urls[0].isLocalFile())
747
QString path = urls[0].path();
748
if (!path.endsWith(".desktop"))
752
QString result = createDesktopFile(path, &menuId, &m_newMenuIds);
753
KDesktopFile orig_df(path);
754
KDesktopFile *df = orig_df.copyTo(result);
755
df->desktopGroup().deleteEntry("Categories"); // Don't set any categories!
757
KService::Ptr s(new KService(df));
758
s->setMenuId(menuId);
760
MenuEntryInfo *entryInfo = new MenuEntryInfo(s, df);
762
QString oldCaption = entryInfo->caption;
763
QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption, oldCaption);
764
entryInfo->setCaption(newCaption);
767
// m_menuFile->addEntry(folder, menuId);
768
m_menuFile->pushAction(MenuFile::ADD_ENTRY, folder, menuId);
770
// create the TreeItem
772
parentItem->setOpen(true);
774
// update fileInfo data
775
parentFolderInfo->add(entryInfo);
777
TreeItem *newItem = createTreeItem(parentItem, after, entryInfo, true);
779
setSelected ( newItem, true);
780
itemSelected( newItem);
783
setLayoutDirty(parentItem);
787
// is there content in the clipboard?
790
if (m_dragItem == after) return; // Nothing to do
792
int command = m_drag;
793
if (command == MOVE_FOLDER)
795
MenuFolderInfo *folderInfo = m_dragInfo;
796
if (e->action() == QDropEvent::Copy)
798
// Ugh.. this is hard :)
799
// * Create new .directory file
804
TreeItem *tmpItem = static_cast<TreeItem*>(parentItem);
807
if ( tmpItem == m_dragItem )
812
tmpItem = static_cast<TreeItem*>(tmpItem->parent() );
815
// Remove MenuFolderInfo
816
TreeItem *oldParentItem = static_cast<TreeItem*>(m_dragItem->parent());
817
MenuFolderInfo *oldParentFolderInfo = oldParentItem ? oldParentItem->folderInfo() : m_rootFolder;
818
oldParentFolderInfo->take(folderInfo);
821
QString oldFolder = folderInfo->fullId;
822
QString folderName = folderInfo->id;
823
QString newFolder = m_menuFile->uniqueMenuName(folder, folderName, parentFolderInfo->existingMenuIds());
824
folderInfo->id = newFolder;
827
//m_menuFile->moveMenu(oldFolder, folder + newFolder);
828
m_menuFile->pushAction(MenuFile::MOVE_MENU, oldFolder, folder + newFolder);
830
// Make sure caption is unique
831
QString newCaption = parentFolderInfo->uniqueMenuCaption(folderInfo->caption);
832
if (newCaption != folderInfo->caption)
834
folderInfo->setCaption(newCaption);
837
// create the TreeItem
839
parentItem->setOpen(true);
841
// update fileInfo data
842
folderInfo->updateFullId(parentFolderInfo->fullId);
843
folderInfo->setInUse(true);
844
parentFolderInfo->add(folderInfo);
846
if ((parentItem != oldParentItem) || !after)
849
oldParentItem->takeItem(m_dragItem);
851
takeItem(m_dragItem);
853
parentItem->insertItem(m_dragItem);
855
insertItem(m_dragItem);
857
m_dragItem->moveItem(after);
858
m_dragItem->setName(folderInfo->caption);
859
m_dragItem->setDirectoryPath(folderInfo->fullId);
860
setSelected(m_dragItem, true);
861
itemSelected(m_dragItem);
864
else if (command == MOVE_FILE)
866
MenuEntryInfo *entryInfo = m_dragItem->entryInfo();
867
QString menuId = entryInfo->menuId();
869
if (e->action() == QDropEvent::Copy)
872
// Need to copy file and then add it
873
KDesktopFile *df = copyDesktopFile(entryInfo, &menuId, &m_newMenuIds); // Duplicate
874
//UNDO-ACTION: NEW_MENU_ID (menuId)
876
KService::Ptr s(new KService(df));
877
s->setMenuId(menuId);
879
entryInfo = new MenuEntryInfo(s, df);
881
QString oldCaption = entryInfo->caption;
882
QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption, oldCaption);
883
entryInfo->setCaption(newCaption);
887
del(m_dragItem, false);
888
QString oldCaption = entryInfo->caption;
889
QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption);
890
entryInfo->setCaption(newCaption);
891
entryInfo->setInUse(true);
894
// m_menuFile->addEntry(folder, menuId);
895
m_menuFile->pushAction(MenuFile::ADD_ENTRY, folder, menuId);
897
// create the TreeItem
899
parentItem->setOpen(true);
901
// update fileInfo data
902
parentFolderInfo->add(entryInfo);
904
TreeItem *newItem = createTreeItem(parentItem, after, entryInfo, true);
906
setSelected ( newItem, true);
907
itemSelected( newItem);
909
else if (command == COPY_SEPARATOR)
911
if (e->action() != QDropEvent::Copy)
912
del(m_dragItem, false);
914
TreeItem *newItem = createTreeItem(parentItem, after, m_separator, true);
916
setSelected ( newItem, true);
917
itemSelected( newItem);
924
setLayoutDirty(parentItem);
928
void TreeView::startDrag()
930
Q3DragObject *drag = dragObject();
938
Q3DragObject *TreeView::dragObject()
941
TreeItem *item = (TreeItem*)selectedItem();
942
if(item == 0) return 0;
944
K3MultipleDrag *drag = new K3MultipleDrag( this );
946
if (item->isDirectory())
948
m_drag = MOVE_FOLDER;
949
m_dragInfo = item->folderInfo();
952
else if (item->isEntry())
957
QString menuId = item->menuId();
958
m_dragPath = item->entryInfo()->service->desktopEntryPath();
959
if (!m_dragPath.isEmpty())
960
m_dragPath = KStandardDirs::locate("apps", m_dragPath);
961
if (!m_dragPath.isEmpty())
964
url.setPath(m_dragPath);
965
drag->addDragObject( new K3URLDrag(url, 0));
970
m_drag = COPY_SEPARATOR;
975
drag->addDragObject( new Q3StoredDrag("application/x-kmenuedit-internal", 0));
976
if ( item->pixmap(0) )
977
drag->setPixmap(*item->pixmap(0));
981
void TreeView::slotRMBPressed(Q3ListViewItem*, const QPoint& p)
983
TreeItem *item = (TreeItem*)selectedItem();
984
if(item == 0) return;
986
if(m_rmb) m_rmb->exec(p);
989
void TreeView::newsubmenu()
991
TreeItem *parentItem = 0;
992
TreeItem *item = (TreeItem*)selectedItem();
995
QString caption = KInputDialog::getText( i18n( "New Submenu" ),
996
i18n( "Submenu name:" ), QString(), &ok, this );
1000
QString file = caption;
1001
file.replace('/', '-');
1003
file = createDirectoryFile(file, &m_newDirectoryList); // Create
1005
// get destination folder
1013
else if(item->isDirectory())
1017
folder = parentItem->directory();
1021
parentItem = static_cast<TreeItem*>(item->parent());
1022
folder = parentItem ? parentItem->directory() : QString();
1025
MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
1026
MenuFolderInfo *folderInfo = new MenuFolderInfo();
1027
folderInfo->caption = parentFolderInfo->uniqueMenuCaption(caption);
1028
folderInfo->id = m_menuFile->uniqueMenuName(folder, caption, parentFolderInfo->existingMenuIds());
1029
folderInfo->directoryFile = file;
1030
folderInfo->icon = "package";
1031
folderInfo->hidden = false;
1032
folderInfo->setDirty();
1034
KDesktopFile *df = new KDesktopFile(file);
1035
KConfigGroup desktopGroup = df->desktopGroup();
1036
desktopGroup.writeEntry("Name", folderInfo->caption);
1037
desktopGroup.writeEntry("Icon", folderInfo->icon);
1041
// m_menuFile->addMenu(folder + folderInfo->id, file);
1042
m_menuFile->pushAction(MenuFile::ADD_MENU, folder + folderInfo->id, file);
1044
folderInfo->fullId = parentFolderInfo->fullId + folderInfo->id;
1046
// create the TreeItem
1048
parentItem->setOpen(true);
1050
// update fileInfo data
1051
parentFolderInfo->add(folderInfo);
1053
TreeItem *newItem = createTreeItem(parentItem, item, folderInfo, true);
1055
setSelected ( newItem, true);
1056
itemSelected( newItem);
1058
setLayoutDirty(parentItem);
1061
void TreeView::newitem()
1063
TreeItem *parentItem = 0;
1064
TreeItem *item = (TreeItem*)selectedItem();
1067
QString caption = KInputDialog::getText( i18n( "New Item" ),
1068
i18n( "Item name:" ), QString(), &ok, this );
1073
QString file = caption;
1074
file.replace('/', '-');
1076
file = createDesktopFile(file, &menuId, &m_newMenuIds); // Create
1078
KDesktopFile *df = new KDesktopFile(file);
1079
KConfigGroup desktopGroup = df->desktopGroup();
1080
desktopGroup.writeEntry("Name", caption);
1081
desktopGroup.writeEntry("Type", "Application");
1083
// get destination folder
1091
else if(item->isDirectory())
1095
folder = parentItem->directory();
1099
parentItem = static_cast<TreeItem*>(item->parent());
1100
folder = parentItem ? parentItem->directory() : QString();
1103
MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
1106
// m_menuFile->addEntry(folder, menuId);
1107
m_menuFile->pushAction(MenuFile::ADD_ENTRY, folder, menuId);
1109
KService::Ptr s(new KService(df));
1110
s->setMenuId(menuId);
1112
MenuEntryInfo *entryInfo = new MenuEntryInfo(s, df);
1114
// create the TreeItem
1116
parentItem->setOpen(true);
1118
// update fileInfo data
1119
parentFolderInfo->add(entryInfo);
1121
TreeItem *newItem = createTreeItem(parentItem, item, entryInfo, true);
1123
setSelected ( newItem, true);
1124
itemSelected( newItem);
1126
setLayoutDirty(parentItem);
1129
void TreeView::newsep()
1131
TreeItem *parentItem = 0;
1132
TreeItem *item = (TreeItem*)selectedItem();
1138
else if(item->isDirectory())
1145
parentItem = static_cast<TreeItem*>(item->parent());
1148
// create the TreeItem
1150
parentItem->setOpen(true);
1152
TreeItem *newItem = createTreeItem(parentItem, item, m_separator, true);
1154
setSelected ( newItem, true);
1155
itemSelected( newItem);
1157
setLayoutDirty(parentItem);
1160
void TreeView::cut()
1164
m_ac->action("edit_cut")->setEnabled(false);
1165
m_ac->action("edit_copy")->setEnabled(false);
1166
m_ac->action("delete")->setEnabled(false);
1168
// Select new current item
1169
setSelected( currentItem(), true );
1170
// Switch the UI to show that item
1171
itemSelected( selectedItem() );
1174
void TreeView::copy()
1179
void TreeView::copy( bool cutting )
1181
TreeItem *item = (TreeItem*)selectedItem();
1183
// nil selected? -> nil to copy
1184
if (item == 0) return;
1187
setLayoutDirty((TreeItem*)item->parent());
1189
// clean up old stuff
1192
// is item a folder or a file?
1193
if(item->isDirectory())
1195
QString folder = item->directory();
1198
// Place in clipboard
1199
m_clipboard = MOVE_FOLDER;
1200
m_clipboardFolderInfo = item->folderInfo();
1206
// Place in clipboard
1207
m_clipboard = COPY_FOLDER;
1208
m_clipboardFolderInfo = item->folderInfo();
1211
else if (item->isEntry())
1215
// Place in clipboard
1216
m_clipboard = MOVE_FILE;
1217
m_clipboardEntryInfo = item->entryInfo();
1223
// Place in clipboard
1224
m_clipboard = COPY_FILE;
1225
m_clipboardEntryInfo = item->entryInfo();
1230
// Place in clipboard
1231
m_clipboard = COPY_SEPARATOR;
1236
m_ac->action("edit_paste")->setEnabled(true);
1240
void TreeView::paste()
1242
TreeItem *parentItem = 0;
1243
TreeItem *item = (TreeItem*)selectedItem();
1245
// nil selected? -> nil to paste to
1246
if (item == 0) return;
1248
// is there content in the clipboard?
1249
if (!m_clipboard) return;
1251
// get destination folder
1254
if(item->isDirectory())
1258
folder = parentItem->directory();
1262
parentItem = static_cast<TreeItem*>(item->parent());
1263
folder = parentItem ? parentItem->directory() : QString();
1266
MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
1267
int command = m_clipboard;
1268
if ((command == COPY_FOLDER) || (command == MOVE_FOLDER))
1270
MenuFolderInfo *folderInfo = m_clipboardFolderInfo;
1271
if (command == COPY_FOLDER)
1273
// Ugh.. this is hard :)
1274
// * Create new .directory file
1277
else if (command == MOVE_FOLDER)
1280
QString oldFolder = folderInfo->fullId;
1281
QString folderName = folderInfo->id;
1282
QString newFolder = m_menuFile->uniqueMenuName(folder, folderName, parentFolderInfo->existingMenuIds());
1283
folderInfo->id = newFolder;
1286
// m_menuFile->moveMenu(oldFolder, folder + newFolder);
1287
m_menuFile->pushAction(MenuFile::MOVE_MENU, oldFolder, folder + newFolder);
1289
// Make sure caption is unique
1290
QString newCaption = parentFolderInfo->uniqueMenuCaption(folderInfo->caption);
1291
if (newCaption != folderInfo->caption)
1293
folderInfo->setCaption(newCaption);
1295
// create the TreeItem
1297
parentItem->setOpen(true);
1299
// update fileInfo data
1300
folderInfo->fullId = parentFolderInfo->fullId + folderInfo->id;
1301
folderInfo->setInUse(true);
1302
parentFolderInfo->add(folderInfo);
1304
TreeItem *newItem = createTreeItem(parentItem, item, folderInfo);
1306
setSelected ( newItem, true);
1307
itemSelected( newItem);
1310
m_clipboard = COPY_FOLDER; // Next one copies.
1312
else if ((command == COPY_FILE) || (command == MOVE_FILE))
1314
MenuEntryInfo *entryInfo = m_clipboardEntryInfo;
1317
if (command == COPY_FILE)
1319
// Need to copy file and then add it
1320
KDesktopFile *df = copyDesktopFile(entryInfo, &menuId, &m_newMenuIds); // Duplicate
1322
KService::Ptr s(new KService(df));
1323
s->setMenuId(menuId);
1324
entryInfo = new MenuEntryInfo(s, df);
1326
QString oldCaption = entryInfo->caption;
1327
QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption, oldCaption);
1328
entryInfo->setCaption(newCaption);
1330
else if (command == MOVE_FILE)
1332
menuId = entryInfo->menuId();
1333
m_clipboard = COPY_FILE; // Next one copies.
1335
QString oldCaption = entryInfo->caption;
1336
QString newCaption = parentFolderInfo->uniqueItemCaption(oldCaption);
1337
entryInfo->setCaption(newCaption);
1338
entryInfo->setInUse(true);
1341
// m_menuFile->addEntry(folder, menuId);
1342
m_menuFile->pushAction(MenuFile::ADD_ENTRY, folder, menuId);
1344
// create the TreeItem
1346
parentItem->setOpen(true);
1348
// update fileInfo data
1349
parentFolderInfo->add(entryInfo);
1351
TreeItem *newItem = createTreeItem(parentItem, item, entryInfo, true);
1353
setSelected ( newItem, true);
1354
itemSelected( newItem);
1360
parentItem->setOpen(true);
1362
TreeItem *newItem = createTreeItem(parentItem, item, m_separator, true);
1364
setSelected ( newItem, true);
1365
itemSelected( newItem);
1367
setLayoutDirty(parentItem);
1370
void TreeView::del()
1372
TreeItem *item = (TreeItem*)selectedItem();
1374
// nil selected? -> nil to delete
1375
if (item == 0) return;
1379
m_ac->action("edit_cut")->setEnabled(false);
1380
m_ac->action("edit_copy")->setEnabled(false);
1381
m_ac->action("delete")->setEnabled(false);
1382
// Select new current item
1383
setSelected( currentItem(), true );
1384
// Switch the UI to show that item
1385
itemSelected( selectedItem() );
1388
void TreeView::del(TreeItem *item, bool deleteInfo)
1390
TreeItem *parentItem = static_cast<TreeItem*>(item->parent());
1391
// is file a .directory or a .desktop file
1392
if(item->isDirectory())
1394
MenuFolderInfo *folderInfo = item->folderInfo();
1396
// Remove MenuFolderInfo
1397
MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
1398
parentFolderInfo->take(folderInfo);
1399
folderInfo->setInUse(false);
1401
if (m_clipboard == COPY_FOLDER && (m_clipboardFolderInfo == folderInfo))
1403
// Copy + Del == Cut
1404
m_clipboard = MOVE_FOLDER; // Clipboard now owns folderInfo
1409
if (folderInfo->takeRecursive(m_clipboardFolderInfo))
1410
m_clipboard = MOVE_FOLDER; // Clipboard now owns m_clipboardFolderInfo
1413
delete folderInfo; // Delete folderInfo
1417
// m_menuFile->removeMenu(item->directory());
1418
m_menuFile->pushAction(MenuFile::REMOVE_MENU, item->directory(), QString());
1423
else if (item->isEntry())
1425
MenuEntryInfo *entryInfo = item->entryInfo();
1426
QString menuId = entryInfo->menuId();
1428
// Remove MenuFolderInfo
1429
MenuFolderInfo *parentFolderInfo = parentItem ? parentItem->folderInfo() : m_rootFolder;
1430
parentFolderInfo->take(entryInfo);
1431
entryInfo->setInUse(false);
1433
if (m_clipboard == COPY_FILE && (m_clipboardEntryInfo == entryInfo))
1435
// Copy + Del == Cut
1436
m_clipboard = MOVE_FILE; // Clipboard now owns entryInfo
1441
delete entryInfo; // Delete entryInfo
1445
QString folder = parentItem ? parentItem->directory() : QString();
1446
// m_menuFile->removeEntry(folder, menuId);
1447
m_menuFile->pushAction(MenuFile::REMOVE_ENTRY, folder, menuId);
1457
setLayoutDirty(parentItem);
1460
void TreeView::cleanupClipboard() {
1461
if (m_clipboard == MOVE_FOLDER)
1462
delete m_clipboardFolderInfo;
1463
m_clipboardFolderInfo = 0;
1465
if (m_clipboard == MOVE_FILE)
1466
delete m_clipboardEntryInfo;
1467
m_clipboardEntryInfo = 0;
1472
static QStringList extractLayout(TreeItem *item)
1474
bool firstFolder = true;
1475
bool firstEntry = true;
1477
for(;item; item = static_cast<TreeItem*>(item->nextSibling()))
1479
if (item->isDirectory())
1483
firstFolder = false;
1484
layout << ":M"; // Add new folders here...
1486
layout << (item->folderInfo()->id);
1488
else if (item->isEntry())
1493
layout << ":F"; // Add new entries here...
1495
layout << (item->entryInfo()->menuId());
1505
QStringList TreeItem::layout()
1507
QStringList layout = extractLayout(static_cast<TreeItem*>(firstChild()));
1508
_layoutDirty = false;
1512
void TreeView::saveLayout()
1516
QStringList layout = extractLayout(static_cast<TreeItem*>(firstChild()));
1517
m_menuFile->setLayout(m_rootFolder->fullId, layout);
1518
m_layoutDirty = false;
1521
Q3PtrList<Q3ListViewItem> lst;
1522
Q3ListViewItemIterator it( this );
1523
while ( it.current() ) {
1524
TreeItem *item = static_cast<TreeItem*>(it.current());
1525
if ( item->isLayoutDirty() )
1527
m_menuFile->setLayout(item->folderInfo()->fullId, item->layout());
1533
bool TreeView::save()
1536
m_rootFolder->save(m_menuFile);
1538
bool success = m_menuFile->performAllActions();
1540
m_newMenuIds.clear();
1541
m_newDirectoryList.clear();
1545
KBuildSycocaProgressDialog::rebuildKSycoca(this);
1549
KMessageBox::sorry(this, "<qt>"+i18n("Menu changes could not be saved because of the following problem:")+"<br><br>"+
1550
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);