add more spacing
[personal-kdebase.git] / workspace / kmenuedit / menuinfo.cpp
blob9af7b0d225963edd1fe5b73e13e5c463aef565b7
1 /*
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.
20 #include "menuinfo.h"
21 #include "menufile.h"
23 #include <QRegExp>
25 #include <kdesktopfile.h>
26 #ifndef Q_WS_WIN
27 #include <khotkeys.h>
28 #endif
29 #include <kstandarddirs.h>
30 #include <kconfiggroup.h>
33 // MenuFolderInfo
36 static QStringList *s_newShortcuts = 0;
37 static QStringList *s_freeShortcuts = 0;
38 static QStringList *s_deletedApps = 0;
40 // Add separator
41 void MenuFolderInfo::add(MenuSeparatorInfo *info, bool initial)
43 if (initial)
44 initialLayout.append(info);
47 // Add sub menu
48 void MenuFolderInfo::add(MenuFolderInfo *info, bool initial)
50 subFolders.append(info);
51 if (initial)
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);
65 if (i >= 0)
67 subFolders.take(i);
68 return true;
71 for(MenuFolderInfo *subFolderInfo = subFolders.first();
72 subFolderInfo; subFolderInfo = subFolders.next())
74 if (subFolderInfo->takeRecursive(info))
75 return true;
77 return false;
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);
92 // Add entry
93 void MenuFolderInfo::add(MenuEntryInfo *entry, bool initial)
95 entries.append(entry);
96 if (initial)
97 initialLayout.append(entry);
100 // Remove 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; )
117 bool ok = true;
118 for(MenuFolderInfo *subFolderInfo = subFolders.first();
119 subFolderInfo; subFolderInfo = subFolders.next())
121 if (subFolderInfo->caption == result)
123 ok = false;
124 break;
127 if (ok)
128 return 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; )
145 bool ok = true;
146 if (result == exclude)
147 ok = false;
148 MenuEntryInfo *entryInfo;
149 for(Q3PtrListIterator<MenuEntryInfo> it(entries);
150 ok && (entryInfo = it.current()); ++it)
152 if (entryInfo->caption == result)
153 ok = false;
155 if (ok)
156 return 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()
166 QStringList result;
167 for(MenuFolderInfo *subFolderInfo = subFolders.first();
168 subFolderInfo; subFolderInfo = subFolders.next())
170 result.append(subFolderInfo->id);
172 return result;
175 void MenuFolderInfo::setDirty()
177 dirty = true;
180 void MenuFolderInfo::save(MenuFile *menuFile)
182 if (s_deletedApps)
184 #ifndef Q_WS_WIN
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, "");
192 #endif
193 delete s_deletedApps;
194 s_deletedApps = 0;
197 if (dirty)
199 QString local = KDesktopFile::locateLocal(directoryFile);
201 KDesktopFile *df = 0;
202 if (directoryFile != local)
204 KDesktopFile orig("apps", directoryFile);
205 df = orig.copyTo(local);
207 else
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);
217 dg.sync();
218 delete df;
219 dirty = false;
222 // Save sub-menus
223 for(MenuFolderInfo *subFolderInfo = subFolders.first();
224 subFolderInfo; subFolderInfo = subFolders.next())
226 subFolderInfo->save(menuFile);
229 // Save entries
230 MenuEntryInfo *entryInfo;
231 for(Q3PtrListIterator<MenuEntryInfo> it(entries);
232 (entryInfo = it.current()); ++it)
234 if (entryInfo->needInsertion())
235 menuFile->addEntry(fullId, entryInfo->menuId());
236 entryInfo->save();
240 bool MenuFolderInfo::hasDirt()
242 if (dirty) return true;
244 // Check sub-menus
245 for(MenuFolderInfo *subFolderInfo = subFolders.first();
246 subFolderInfo; subFolderInfo = subFolders.next())
248 if (subFolderInfo->hasDirt()) return true;
251 // Check entries
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;
259 return false;
262 KService::Ptr MenuFolderInfo::findServiceShortcut(const KShortcut&cut)
264 KService::Ptr result;
265 // Check sub-menus
266 for(MenuFolderInfo *subFolderInfo = subFolders.first();
267 subFolderInfo; subFolderInfo = subFolders.next())
269 result = subFolderInfo->findServiceShortcut(cut);
270 if (result)
271 return result;
274 // Check entries
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);
304 // MenuEntryInfo
307 MenuEntryInfo::~MenuEntryInfo()
309 m_desktopFile->markAsClean();
310 delete m_desktopFile;
313 KDesktopFile *MenuEntryInfo::desktopFile()
315 if (!m_desktopFile)
317 m_desktopFile = new KDesktopFile(service->entryPath());
319 return m_desktopFile;
322 void MenuEntryInfo::setDirty()
324 if (dirty) return;
326 dirty = true;
328 QString local = KStandardDirs::locateLocal("xdgdata-apps", service->menuId());
329 if (local != service->entryPath())
331 KDesktopFile *oldDf = desktopFile();
332 m_desktopFile = oldDf->copyTo(local);
333 delete oldDf;
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()
345 if (dirty)
347 m_desktopFile->sync();
348 dirty = false;
350 #ifndef Q_WS_WIN
351 if (shortcutDirty)
353 if( KHotKeys::present())
355 KHotKeys::changeMenuEntryShortcut( service->storageId(), shortCut.toString() );
357 shortcutDirty = false;
359 #endif
362 void MenuEntryInfo::setCaption(const QString &_caption)
364 if (caption == _caption)
365 return;
366 caption = _caption;
367 setDirty();
368 desktopFile()->desktopGroup().writeEntry("Name", caption);
371 void MenuEntryInfo::setDescription(const QString &_description)
373 if (description == _description)
374 return;
375 description = _description;
376 setDirty();
377 desktopFile()->desktopGroup().writeEntry("GenericName", description);
380 void MenuEntryInfo::setIcon(const QString &_icon)
382 if (icon == _icon)
383 return;
385 icon = _icon;
386 setDirty();
387 desktopFile()->desktopGroup().writeEntry("Icon", icon);
390 KShortcut MenuEntryInfo::shortcut()
392 #ifndef Q_WS_WIN
393 if (!shortcutLoaded)
395 shortcutLoaded = true;
396 if( KHotKeys::present())
398 shortCut = KShortcut(KHotKeys::getMenuEntryShortcut( service->storageId() ));
401 #endif
402 return shortCut;
405 static void freeShortcut(const KShortcut &shortCut)
407 if (!shortCut.isEmpty())
409 QString shortcutKey = shortCut.toString();
410 if (s_newShortcuts)
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();
425 if (s_freeShortcuts)
426 s_freeShortcuts->removeAll(shortcutKey);
428 if (!s_newShortcuts)
429 s_newShortcuts = new QStringList;
431 s_newShortcuts->append(shortcutKey);
435 void MenuEntryInfo::setShortcut(const KShortcut &_shortcut)
437 if (shortCut == _shortcut)
438 return;
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)
453 if (inUse)
455 KShortcut temp = shortcut();
456 shortCut = KShortcut();
457 if (isShortcutAvailable(temp))
458 shortCut = temp;
459 else
460 shortcutDirty = true;
461 allocateShortcut(shortCut);
463 if (s_deletedApps)
464 s_deletedApps->removeAll(service->storageId());
466 else
468 freeShortcut(shortcut());
470 // Add to list of deleted apps
471 if (!s_deletedApps)
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)
483 return true;
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);
495 return available;