~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kmenuedit/menuinfo.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *   Copyright (C) 2003 Waldo Bastian <bastian@kde.org>
 
3
 *
 
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.
 
8
 *
 
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.
 
13
 *
 
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.
 
17
 *
 
18
 */
 
19
 
 
20
#include "menuinfo.h"
 
21
#include "menufile.h"
 
22
 
 
23
#include <QRegExp>
 
24
 
 
25
#include <kdesktopfile.h>
 
26
#ifndef Q_WS_WIN
 
27
#include <khotkeys.h>
 
28
#endif
 
29
#include <kstandarddirs.h>
 
30
#include <kconfiggroup.h>
 
31
 
 
32
//
 
33
// MenuFolderInfo
 
34
//
 
35
 
 
36
static QStringList *s_newShortcuts = 0;
 
37
static QStringList *s_freeShortcuts = 0;
 
38
static QStringList *s_deletedApps = 0;
 
39
 
 
40
// Add separator
 
41
void MenuFolderInfo::add(MenuSeparatorInfo *info, bool initial)
 
42
{
 
43
   if (initial)
 
44
      initialLayout.append(info);
 
45
}
 
46
 
 
47
// Add sub menu
 
48
void MenuFolderInfo::add(MenuFolderInfo *info, bool initial)
 
49
{
 
50
   subFolders.append(info);
 
51
   if (initial)
 
52
      initialLayout.append(info);
 
53
}
 
54
 
 
55
// Remove sub menu (without deleting it)
 
56
void MenuFolderInfo::take(MenuFolderInfo *info)
 
57
{
 
58
   subFolders.take(subFolders.findRef(info));
 
59
}
 
60
 
 
61
// Remove sub menu (without deleting it)
 
62
bool MenuFolderInfo::takeRecursive(MenuFolderInfo *info)
 
63
{
 
64
   int i = subFolders.findRef(info);
 
65
   if (i >= 0)
 
66
   {
 
67
      subFolders.take(i);
 
68
      return true;
 
69
   }
 
70
 
 
71
   for(MenuFolderInfo *subFolderInfo = subFolders.first();
 
72
       subFolderInfo; subFolderInfo = subFolders.next())
 
73
   {
 
74
      if (subFolderInfo->takeRecursive(info))
 
75
         return true;
 
76
   }
 
77
   return false;
 
78
}
 
79
 
 
80
// Recursively update all fullIds
 
81
void MenuFolderInfo::updateFullId(const QString &parentId)
 
82
{
 
83
   fullId = parentId + id;
 
84
 
 
85
   for(MenuFolderInfo *subFolderInfo = subFolders.first();
 
86
       subFolderInfo; subFolderInfo = subFolders.next())
 
87
   {
 
88
      subFolderInfo->updateFullId(fullId);
 
89
   }
 
90
}
 
91
 
 
92
// Add entry
 
93
void MenuFolderInfo::add(MenuEntryInfo *entry, bool initial)
 
94
{
 
95
   entries.append(entry);
 
96
   if (initial)
 
97
      initialLayout.append(entry);
 
98
}
 
99
 
 
100
// Remove entry
 
101
void MenuFolderInfo::take(MenuEntryInfo *entry)
 
102
{
 
103
   entries.removeRef(entry);
 
104
}
 
105
 
 
106
 
 
107
// Return a unique sub-menu caption inspired by @p caption
 
108
QString MenuFolderInfo::uniqueMenuCaption(const QString &caption)
 
109
{
 
110
   QRegExp r("(.*)(?=-\\d+)");
 
111
   QString cap = (r.indexIn(caption) > -1) ? r.cap(1) : caption;
 
112
 
 
113
   QString result = caption;
 
114
 
 
115
   for(int n = 1; ++n; )
 
116
   {
 
117
      bool ok = true;
 
118
      for(MenuFolderInfo *subFolderInfo = subFolders.first();
 
119
          subFolderInfo; subFolderInfo = subFolders.next())
 
120
      {
 
121
         if (subFolderInfo->caption == result)
 
122
         {
 
123
            ok = false;
 
124
            break;
 
125
         }
 
126
      }
 
127
      if (ok)
 
128
         return result;
 
129
 
 
130
      result = cap + QString("-%1").arg(n);
 
131
   }
 
132
   return QString(); // Never reached
 
133
}
 
134
 
 
135
// Return a unique item caption inspired by @p caption
 
136
QString MenuFolderInfo::uniqueItemCaption(const QString &caption, const QString &exclude)
 
137
{
 
138
   QRegExp r("(.*)(?=-\\d+)");
 
139
   QString cap = (r.indexIn(caption) > -1) ? r.cap(1) : caption;
 
140
 
 
141
   QString result = caption;
 
142
 
 
143
   for(int n = 1; ++n; )
 
144
   {
 
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)
 
151
      {
 
152
         if (entryInfo->caption == result)
 
153
            ok = false;
 
154
      }
 
155
      if (ok)
 
156
         return result;
 
157
 
 
158
      result = cap + QString("-%1").arg(n);
 
159
   }
 
160
   return QString(); // Never reached
 
161
}
 
162
 
 
163
// Return a list of existing submenu ids
 
164
QStringList MenuFolderInfo::existingMenuIds()
 
165
{
 
166
   QStringList result;
 
167
   for(MenuFolderInfo *subFolderInfo = subFolders.first();
 
168
       subFolderInfo; subFolderInfo = subFolders.next())
 
169
   {
 
170
       result.append(subFolderInfo->id);
 
171
   }
 
172
   return result;
 
173
}
 
174
 
 
175
void MenuFolderInfo::setDirty()
 
176
{
 
177
   dirty = true;
 
178
}
 
179
 
 
180
void MenuFolderInfo::save(MenuFile *menuFile)
 
181
{
 
182
   if (s_deletedApps)
 
183
   {
 
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)
 
188
      {
 
189
         // The shorcut is deleted if we set a empty sequence
 
190
         KHotKeys::changeMenuEntryShortcut(*it, "");
 
191
      }
 
192
#endif
 
193
      delete s_deletedApps;
 
194
      s_deletedApps = 0;
 
195
   }
 
196
 
 
197
   if (dirty)
 
198
   {
 
199
      QString local = KDesktopFile::locateLocal(directoryFile);
 
200
 
 
201
      KDesktopFile *df = 0;
 
202
      if (directoryFile != local)
 
203
      {
 
204
         KDesktopFile orig("apps", directoryFile);
 
205
         df = orig.copyTo(local);
 
206
      }
 
207
      else
 
208
      {
 
209
         df = new KDesktopFile("apps", directoryFile);
 
210
      }
 
211
 
 
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;
 
220
   }
 
221
 
 
222
   // Save sub-menus
 
223
   for(MenuFolderInfo *subFolderInfo = subFolders.first();
 
224
       subFolderInfo; subFolderInfo = subFolders.next())
 
225
   {
 
226
      subFolderInfo->save(menuFile);
 
227
   }
 
228
 
 
229
   // Save entries
 
230
   MenuEntryInfo *entryInfo;
 
231
   for(Q3PtrListIterator<MenuEntryInfo> it(entries);
 
232
       (entryInfo = it.current()); ++it)
 
233
   {
 
234
      if (entryInfo->needInsertion())
 
235
         menuFile->addEntry(fullId, entryInfo->menuId());
 
236
      entryInfo->save();
 
237
   }
 
238
}
 
239
 
 
240
bool MenuFolderInfo::hasDirt()
 
241
{
 
242
   if (dirty) return true;
 
243
 
 
244
   // Check sub-menus
 
245
   for(MenuFolderInfo *subFolderInfo = subFolders.first();
 
246
       subFolderInfo; subFolderInfo = subFolders.next())
 
247
   {
 
248
      if (subFolderInfo->hasDirt()) return true;
 
249
   }
 
250
 
 
251
   // Check entries
 
252
   MenuEntryInfo *entryInfo;
 
253
   for(Q3PtrListIterator<MenuEntryInfo> it(entries);
 
254
       (entryInfo = it.current()); ++it)
 
255
   {
 
256
      if (entryInfo->dirty) return true;
 
257
      if (entryInfo->shortcutDirty) return true;
 
258
   }
 
259
   return false;
 
260
}
 
261
 
 
262
KService::Ptr MenuFolderInfo::findServiceShortcut(const KShortcut&cut)
 
263
{
 
264
   KService::Ptr result;
 
265
   // Check sub-menus
 
266
   for(MenuFolderInfo *subFolderInfo = subFolders.first();
 
267
       subFolderInfo; subFolderInfo = subFolders.next())
 
268
   {
 
269
      result = subFolderInfo->findServiceShortcut(cut);
 
270
      if (result)
 
271
          return result;
 
272
   }
 
273
 
 
274
   // Check entries
 
275
   MenuEntryInfo *entryInfo;
 
276
   for(Q3PtrListIterator<MenuEntryInfo> it(entries);
 
277
       (entryInfo = it.current()); ++it)
 
278
   {
 
279
      if (entryInfo->shortCut == cut)
 
280
         return entryInfo->service;
 
281
   }
 
282
   return KService::Ptr();
 
283
}
 
284
 
 
285
void MenuFolderInfo::setInUse(bool inUse)
 
286
{
 
287
   // Propagate to sub-menus
 
288
   for(MenuFolderInfo *subFolderInfo = subFolders.first();
 
289
       subFolderInfo; subFolderInfo = subFolders.next())
 
290
   {
 
291
      subFolderInfo->setInUse(inUse);
 
292
   }
 
293
 
 
294
   // Propagate to entries
 
295
   MenuEntryInfo *entryInfo;
 
296
   for(Q3PtrListIterator<MenuEntryInfo> it(entries);
 
297
       (entryInfo = it.current()); ++it)
 
298
   {
 
299
      entryInfo->setInUse(inUse);
 
300
   }
 
301
}
 
302
 
 
303
//
 
304
// MenuEntryInfo
 
305
//
 
306
 
 
307
MenuEntryInfo::~MenuEntryInfo()
 
308
{
 
309
   m_desktopFile->markAsClean();
 
310
   delete m_desktopFile;
 
311
}
 
312
 
 
313
KDesktopFile *MenuEntryInfo::desktopFile()
 
314
{
 
315
   if (!m_desktopFile)
 
316
   {
 
317
      m_desktopFile = new KDesktopFile(service->entryPath());
 
318
   }
 
319
   return m_desktopFile;
 
320
}
 
321
 
 
322
void MenuEntryInfo::setDirty()
 
323
{
 
324
   if (dirty) return;
 
325
 
 
326
   dirty = true;
 
327
 
 
328
   QString local = KStandardDirs::locateLocal("xdgdata-apps", service->menuId());
 
329
   if (local != service->entryPath())
 
330
   {
 
331
      KDesktopFile *oldDf = desktopFile();
 
332
      m_desktopFile = oldDf->copyTo(local);
 
333
      delete oldDf;
 
334
   }
 
335
}
 
336
 
 
337
bool MenuEntryInfo::needInsertion()
 
338
{
 
339
   // If entry is dirty and previously stored under applnk, then we need to be added explicitly
 
340
   return dirty && !service->entryPath().startsWith('/');
 
341
}
 
342
 
 
343
void MenuEntryInfo::save()
 
344
{
 
345
   if (dirty)
 
346
   {
 
347
      m_desktopFile->sync();
 
348
      dirty = false;
 
349
   }
 
350
#ifndef Q_WS_WIN
 
351
   if (shortcutDirty)
 
352
   {
 
353
      if( KHotKeys::present())
 
354
      {
 
355
         KHotKeys::changeMenuEntryShortcut( service->storageId(), shortCut.toString() );
 
356
      }
 
357
      shortcutDirty = false;
 
358
   }
 
359
#endif
 
360
}
 
361
 
 
362
void MenuEntryInfo::setCaption(const QString &_caption)
 
363
{
 
364
   if (caption == _caption)
 
365
      return;
 
366
   caption = _caption;
 
367
   setDirty();
 
368
   desktopFile()->desktopGroup().writeEntry("Name", caption);
 
369
}
 
370
 
 
371
void MenuEntryInfo::setDescription(const QString &_description)
 
372
{
 
373
    if (description == _description)
 
374
        return;
 
375
    description = _description;
 
376
    setDirty();
 
377
    desktopFile()->desktopGroup().writeEntry("GenericName", description);
 
378
}
 
379
 
 
380
void MenuEntryInfo::setIcon(const QString &_icon)
 
381
{
 
382
   if (icon == _icon)
 
383
      return;
 
384
 
 
385
   icon = _icon;
 
386
   setDirty();
 
387
   desktopFile()->desktopGroup().writeEntry("Icon", icon);
 
388
}
 
389
 
 
390
KShortcut MenuEntryInfo::shortcut()
 
391
{
 
392
#ifndef Q_WS_WIN
 
393
   if (!shortcutLoaded)
 
394
   {
 
395
      shortcutLoaded = true;
 
396
      if( KHotKeys::present())
 
397
      {
 
398
         shortCut = KShortcut(KHotKeys::getMenuEntryShortcut( service->storageId() ));
 
399
      }
 
400
   }
 
401
#endif
 
402
   return shortCut;
 
403
}
 
404
 
 
405
static void freeShortcut(const KShortcut &shortCut)
 
406
{
 
407
   if (!shortCut.isEmpty())
 
408
   {
 
409
      QString shortcutKey = shortCut.toString();
 
410
      if (s_newShortcuts)
 
411
         s_newShortcuts->removeAll(shortcutKey);
 
412
 
 
413
      if (!s_freeShortcuts)
 
414
         s_freeShortcuts = new QStringList;
 
415
 
 
416
      s_freeShortcuts->append(shortcutKey);
 
417
   }
 
418
}
 
419
 
 
420
static void allocateShortcut(const KShortcut &shortCut)
 
421
{
 
422
   if (!shortCut.isEmpty())
 
423
   {
 
424
      QString shortcutKey = shortCut.toString();
 
425
      if (s_freeShortcuts)
 
426
          s_freeShortcuts->removeAll(shortcutKey);
 
427
 
 
428
      if (!s_newShortcuts)
 
429
         s_newShortcuts = new QStringList;
 
430
 
 
431
      s_newShortcuts->append(shortcutKey);
 
432
   }
 
433
}
 
434
 
 
435
void MenuEntryInfo::setShortcut(const KShortcut &_shortcut)
 
436
{
 
437
   if (shortCut == _shortcut)
 
438
      return;
 
439
 
 
440
   freeShortcut(shortCut);
 
441
   allocateShortcut(_shortcut);
 
442
 
 
443
   shortCut = _shortcut;
 
444
   if (shortCut.isEmpty())
 
445
      shortCut = KShortcut(); // Normalize
 
446
 
 
447
   shortcutLoaded = true;
 
448
   shortcutDirty = true;
 
449
}
 
450
 
 
451
void MenuEntryInfo::setInUse(bool inUse)
 
452
{
 
453
   if (inUse)
 
454
   {
 
455
      KShortcut temp = shortcut();
 
456
      shortCut = KShortcut();
 
457
      if (isShortcutAvailable(temp))
 
458
         shortCut = temp;
 
459
      else
 
460
         shortcutDirty = true;
 
461
      allocateShortcut(shortCut);
 
462
 
 
463
      if (s_deletedApps)
 
464
         s_deletedApps->removeAll(service->storageId());
 
465
   }
 
466
   else
 
467
   {
 
468
      freeShortcut(shortcut());
 
469
 
 
470
      // Add to list of deleted apps
 
471
      if (!s_deletedApps)
 
472
         s_deletedApps = new QStringList;
 
473
 
 
474
      s_deletedApps->append(service->storageId());
 
475
   }
 
476
}
 
477
 
 
478
bool MenuEntryInfo::isShortcutAvailable(const KShortcut &_shortcut)
 
479
{
 
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;
 
484
 
 
485
   QString shortcutKey = _shortcut.toString();
 
486
   bool available = true;
 
487
   if (available && s_newShortcuts)
 
488
   {
 
489
      available = !s_newShortcuts->contains(shortcutKey);
 
490
   }
 
491
   if (!available && s_freeShortcuts)
 
492
   {
 
493
      available = s_freeShortcuts->contains(shortcutKey);
 
494
   }
 
495
   return available;
 
496
}