2 * Copyright (C) 2003 Waldo Bastian <bastian@kde.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include <kdesktopfile.h>
29 #include <kstandarddirs.h>
30 #include <kconfiggroup.h>
36 static QStringList
*s_newShortcuts
= 0;
37 static QStringList
*s_freeShortcuts
= 0;
38 static QStringList
*s_deletedApps
= 0;
41 void MenuFolderInfo::add(MenuSeparatorInfo
*info
, bool initial
)
44 initialLayout
.append(info
);
48 void MenuFolderInfo::add(MenuFolderInfo
*info
, bool initial
)
50 subFolders
.append(info
);
52 initialLayout
.append(info
);
55 // Remove sub menu (without deleting it)
56 void MenuFolderInfo::take(MenuFolderInfo
*info
)
58 subFolders
.take(subFolders
.findRef(info
));
61 // Remove sub menu (without deleting it)
62 bool MenuFolderInfo::takeRecursive(MenuFolderInfo
*info
)
64 int i
= subFolders
.findRef(info
);
71 for(MenuFolderInfo
*subFolderInfo
= subFolders
.first();
72 subFolderInfo
; subFolderInfo
= subFolders
.next())
74 if (subFolderInfo
->takeRecursive(info
))
80 // Recursively update all fullIds
81 void MenuFolderInfo::updateFullId(const QString
&parentId
)
83 fullId
= parentId
+ id
;
85 for(MenuFolderInfo
*subFolderInfo
= subFolders
.first();
86 subFolderInfo
; subFolderInfo
= subFolders
.next())
88 subFolderInfo
->updateFullId(fullId
);
93 void MenuFolderInfo::add(MenuEntryInfo
*entry
, bool initial
)
95 entries
.append(entry
);
97 initialLayout
.append(entry
);
101 void MenuFolderInfo::take(MenuEntryInfo
*entry
)
103 entries
.removeRef(entry
);
107 // Return a unique sub-menu caption inspired by @p caption
108 QString
MenuFolderInfo::uniqueMenuCaption(const QString
&caption
)
110 QRegExp
r("(.*)(?=-\\d+)");
111 QString cap
= (r
.indexIn(caption
) > -1) ? r
.cap(1) : caption
;
113 QString result
= caption
;
115 for(int n
= 1; ++n
; )
118 for(MenuFolderInfo
*subFolderInfo
= subFolders
.first();
119 subFolderInfo
; subFolderInfo
= subFolders
.next())
121 if (subFolderInfo
->caption
== result
)
130 result
= cap
+ QString("-%1").arg(n
);
132 return QString(); // Never reached
135 // Return a unique item caption inspired by @p caption
136 QString
MenuFolderInfo::uniqueItemCaption(const QString
&caption
, const QString
&exclude
)
138 QRegExp
r("(.*)(?=-\\d+)");
139 QString cap
= (r
.indexIn(caption
) > -1) ? r
.cap(1) : caption
;
141 QString result
= caption
;
143 for(int n
= 1; ++n
; )
146 if (result
== exclude
)
148 MenuEntryInfo
*entryInfo
;
149 for(Q3PtrListIterator
<MenuEntryInfo
> it(entries
);
150 ok
&& (entryInfo
= it
.current()); ++it
)
152 if (entryInfo
->caption
== result
)
158 result
= cap
+ QString("-%1").arg(n
);
160 return QString(); // Never reached
163 // Return a list of existing submenu ids
164 QStringList
MenuFolderInfo::existingMenuIds()
167 for(MenuFolderInfo
*subFolderInfo
= subFolders
.first();
168 subFolderInfo
; subFolderInfo
= subFolders
.next())
170 result
.append(subFolderInfo
->id
);
175 void MenuFolderInfo::setDirty()
180 void MenuFolderInfo::save(MenuFile
*menuFile
)
185 // Remove hotkeys for applications that have been deleted
186 for(QStringList::ConstIterator it
= s_deletedApps
->constBegin();
187 it
!= s_deletedApps
->constEnd(); ++it
)
189 // The shorcut is deleted if we set a empty sequence
190 KHotKeys::changeMenuEntryShortcut(*it
, "");
193 delete s_deletedApps
;
199 QString local
= KDesktopFile::locateLocal(directoryFile
);
201 KDesktopFile
*df
= 0;
202 if (directoryFile
!= local
)
204 KDesktopFile
orig("apps", directoryFile
);
205 df
= orig
.copyTo(local
);
209 df
= new KDesktopFile("apps", directoryFile
);
212 KConfigGroup
dg( df
->desktopGroup() );
213 dg
.writeEntry("Name", caption
);
214 dg
.writeEntry("GenericName", genericname
);
215 dg
.writeEntry("Comment", comment
);
216 dg
.writeEntry("Icon", icon
);
223 for(MenuFolderInfo
*subFolderInfo
= subFolders
.first();
224 subFolderInfo
; subFolderInfo
= subFolders
.next())
226 subFolderInfo
->save(menuFile
);
230 MenuEntryInfo
*entryInfo
;
231 for(Q3PtrListIterator
<MenuEntryInfo
> it(entries
);
232 (entryInfo
= it
.current()); ++it
)
234 if (entryInfo
->needInsertion())
235 menuFile
->addEntry(fullId
, entryInfo
->menuId());
240 bool MenuFolderInfo::hasDirt()
242 if (dirty
) return true;
245 for(MenuFolderInfo
*subFolderInfo
= subFolders
.first();
246 subFolderInfo
; subFolderInfo
= subFolders
.next())
248 if (subFolderInfo
->hasDirt()) return true;
252 MenuEntryInfo
*entryInfo
;
253 for(Q3PtrListIterator
<MenuEntryInfo
> it(entries
);
254 (entryInfo
= it
.current()); ++it
)
256 if (entryInfo
->dirty
) return true;
257 if (entryInfo
->shortcutDirty
) return true;
262 KService::Ptr
MenuFolderInfo::findServiceShortcut(const KShortcut
&cut
)
264 KService::Ptr result
;
266 for(MenuFolderInfo
*subFolderInfo
= subFolders
.first();
267 subFolderInfo
; subFolderInfo
= subFolders
.next())
269 result
= subFolderInfo
->findServiceShortcut(cut
);
275 MenuEntryInfo
*entryInfo
;
276 for(Q3PtrListIterator
<MenuEntryInfo
> it(entries
);
277 (entryInfo
= it
.current()); ++it
)
279 if (entryInfo
->shortCut
== cut
)
280 return entryInfo
->service
;
282 return KService::Ptr();
285 void MenuFolderInfo::setInUse(bool inUse
)
287 // Propagate to sub-menus
288 for(MenuFolderInfo
*subFolderInfo
= subFolders
.first();
289 subFolderInfo
; subFolderInfo
= subFolders
.next())
291 subFolderInfo
->setInUse(inUse
);
294 // Propagate to entries
295 MenuEntryInfo
*entryInfo
;
296 for(Q3PtrListIterator
<MenuEntryInfo
> it(entries
);
297 (entryInfo
= it
.current()); ++it
)
299 entryInfo
->setInUse(inUse
);
307 MenuEntryInfo::~MenuEntryInfo()
309 m_desktopFile
->markAsClean();
310 delete m_desktopFile
;
313 KDesktopFile
*MenuEntryInfo::desktopFile()
317 m_desktopFile
= new KDesktopFile(service
->entryPath());
319 return m_desktopFile
;
322 void MenuEntryInfo::setDirty()
328 QString local
= KStandardDirs::locateLocal("xdgdata-apps", service
->menuId());
329 if (local
!= service
->entryPath())
331 KDesktopFile
*oldDf
= desktopFile();
332 m_desktopFile
= oldDf
->copyTo(local
);
337 bool MenuEntryInfo::needInsertion()
339 // If entry is dirty and previously stored under applnk, then we need to be added explicitly
340 return dirty
&& !service
->entryPath().startsWith('/');
343 void MenuEntryInfo::save()
347 m_desktopFile
->sync();
353 if( KHotKeys::present())
355 KHotKeys::changeMenuEntryShortcut( service
->storageId(), shortCut
.toString() );
357 shortcutDirty
= false;
362 void MenuEntryInfo::setCaption(const QString
&_caption
)
364 if (caption
== _caption
)
368 desktopFile()->desktopGroup().writeEntry("Name", caption
);
371 void MenuEntryInfo::setDescription(const QString
&_description
)
373 if (description
== _description
)
375 description
= _description
;
377 desktopFile()->desktopGroup().writeEntry("GenericName", description
);
380 void MenuEntryInfo::setIcon(const QString
&_icon
)
387 desktopFile()->desktopGroup().writeEntry("Icon", icon
);
390 KShortcut
MenuEntryInfo::shortcut()
395 shortcutLoaded
= true;
396 if( KHotKeys::present())
398 shortCut
= KShortcut(KHotKeys::getMenuEntryShortcut( service
->storageId() ));
405 static void freeShortcut(const KShortcut
&shortCut
)
407 if (!shortCut
.isEmpty())
409 QString shortcutKey
= shortCut
.toString();
411 s_newShortcuts
->removeAll(shortcutKey
);
413 if (!s_freeShortcuts
)
414 s_freeShortcuts
= new QStringList
;
416 s_freeShortcuts
->append(shortcutKey
);
420 static void allocateShortcut(const KShortcut
&shortCut
)
422 if (!shortCut
.isEmpty())
424 QString shortcutKey
= shortCut
.toString();
426 s_freeShortcuts
->removeAll(shortcutKey
);
429 s_newShortcuts
= new QStringList
;
431 s_newShortcuts
->append(shortcutKey
);
435 void MenuEntryInfo::setShortcut(const KShortcut
&_shortcut
)
437 if (shortCut
== _shortcut
)
440 freeShortcut(shortCut
);
441 allocateShortcut(_shortcut
);
443 shortCut
= _shortcut
;
444 if (shortCut
.isEmpty())
445 shortCut
= KShortcut(); // Normalize
447 shortcutLoaded
= true;
448 shortcutDirty
= true;
451 void MenuEntryInfo::setInUse(bool inUse
)
455 KShortcut temp
= shortcut();
456 shortCut
= KShortcut();
457 if (isShortcutAvailable(temp
))
460 shortcutDirty
= true;
461 allocateShortcut(shortCut
);
464 s_deletedApps
->removeAll(service
->storageId());
468 freeShortcut(shortcut());
470 // Add to list of deleted apps
472 s_deletedApps
= new QStringList
;
474 s_deletedApps
->append(service
->storageId());
478 bool MenuEntryInfo::isShortcutAvailable(const KShortcut
&_shortcut
)
480 // We only have to check agains not saved local shortcuts.
481 // KKeySequenceWidget checks against all other registered shortcuts.
482 if (shortCut
== _shortcut
)
485 QString shortcutKey
= _shortcut
.toString();
486 bool available
= true;
487 if (available
&& s_newShortcuts
)
489 available
= !s_newShortcuts
->contains(shortcutKey
);
491 if (!available
&& s_freeShortcuts
)
493 available
= s_freeShortcuts
->contains(shortcutKey
);