1 // -*- mode: c++; c-basic-offset: 2 -*-
2 /* This file is part of the KDE project
3    Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9 
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14 
15    You should have received a copy of the GNU Library General Public License
16    along with this library; see the file COPYING.LIB.  If not, write to
17    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.
19 */
20 
21 
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 
25 #include <assert.h>
26 #include <dirent.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <stddef.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 
33 #include "kcelbookmarkmenu.h"
34 #include <kbookmarkmenu.h>
35 #include "kbookmarkimporter.h"
36 #include "kcelbookmarkowner.h"
37 
38 #include <qfile.h>
39 #include <qregexp.h>
40 
41 #include <kaction.h>
42 #include <kdebug.h>
43 #include <klocale.h>
44 #include <kmessagebox.h>
45 #include <kpopupmenu.h>
46 #include <kstdaccel.h>
47 #include <kstdaction.h>
48 
49 template class QPtrList<KCelBookmarkMenu>;
50 
51 /********************************************************************
52  *
53  * KCelBookmarkMenu
54  *
55  ********************************************************************/
56 
KCelBookmarkMenu(KBookmarkManager * mgr,KCelBookmarkOwner * _owner,KPopupMenu * _parentMenu,KActionCollection * collec,bool _isRoot,bool _add,const QString & parentAddress)57 KCelBookmarkMenu::KCelBookmarkMenu( KBookmarkManager* mgr,
58                               KCelBookmarkOwner * _owner, KPopupMenu * _parentMenu,
59                               KActionCollection *collec, bool _isRoot, bool _add,
60                               const QString & parentAddress )
61   : m_bIsRoot(_isRoot), m_bAddBookmark(_add),
62     m_pManager(mgr), m_pOwner(_owner),
63     m_parentMenu( _parentMenu ),
64     m_actionCollection( collec ),
65     m_parentAddress( parentAddress )
66 {
67   m_lstSubMenus.setAutoDelete( true );
68   m_actions.setAutoDelete( true );
69 
70   m_bNSBookmark = m_parentAddress.isNull();
71   if ( !m_bNSBookmark ) // not for the netscape bookmark
72   {
73     //kdDebug(1203) << "KBookmarkMenu::KBookmarkMenu " << this << " address : " << m_parentAddress << endl;
74 
75     connect( _parentMenu, SIGNAL( aboutToShow() ),
76              SLOT( slotAboutToShow() ) );
77 
78     if ( m_bIsRoot )
79     {
80       connect( m_pManager, SIGNAL( changed(const QString &, const QString &) ),
81                SLOT( slotBookmarksChanged(const QString &) ) );
82     }
83   }
84 
85   // add entries that possibly have a shortcut, so they are available _before_ first popup
86   if ( m_bIsRoot )
87   {
88     if ( m_bAddBookmark ) {
89           addAddBookmark();
90     }
91 
92     addEditBookmarks();
93   }
94 
95   m_bDirty = true;
96 }
97 
~KCelBookmarkMenu()98 KCelBookmarkMenu::~KCelBookmarkMenu()
99 {
100   //kdDebug(1203) << "KBookmarkMenu::~KBookmarkMenu() " << this << endl;
101   QPtrListIterator<KAction> it( m_actions );
102   for (; it.current(); ++it )
103     it.current()->unplugAll();
104 
105   m_lstSubMenus.clear();
106   m_actions.clear();
107 }
108 
ensureUpToDate()109 void KCelBookmarkMenu::ensureUpToDate()
110 {
111   slotAboutToShow();
112 }
113 
114 
slotAboutToShow()115 void KCelBookmarkMenu::slotAboutToShow()
116 {
117   // Did the bookmarks change since the last time we showed them ?
118   if ( m_bDirty )
119   {
120     m_bDirty = false;
121     refill();
122   }
123 }
124 
slotBookmarksChanged(const QString & groupAddress)125 void KCelBookmarkMenu::slotBookmarksChanged( const QString & groupAddress )
126 {
127   if (m_bNSBookmark)
128     return;
129 
130   if ( groupAddress == m_parentAddress )
131   {
132     //kdDebug(1203) << "KBookmarkMenu::slotBookmarksChanged -> setting m_bDirty on " << groupAddress << endl;
133     m_bDirty = true;
134   }
135   else
136   {
137     // Iterate recursively into child menus
138     QPtrListIterator<KCelBookmarkMenu> it( m_lstSubMenus );
139     for (; it.current(); ++it )
140     {
141       it.current()->slotBookmarksChanged( groupAddress );
142     }
143   }
144 }
145 
refill()146 void KCelBookmarkMenu::refill()
147 {
148   //kdDebug(1203) << "KBookmarkMenu::refill()" << endl;
149   m_lstSubMenus.clear();
150 
151   QPtrListIterator<KAction> it( m_actions );
152   for (; it.current(); ++it )
153     it.current()->unplug( m_parentMenu );
154 
155   m_parentMenu->clear();
156   m_actions.clear();
157 
158   fillBookmarkMenu();
159   m_parentMenu->adjustSize();
160 }
161 
addAddBookmark()162 void KCelBookmarkMenu::addAddBookmark()
163 {
164   KAction * paAddBookmarks = new KAction( i18n( "&Add Bookmark" ),
165                                           "bookmark_add",
166                                           m_bIsRoot ? ALT + Key_B : 0,
167                                           this,
168                                           SLOT( slotAddBookmark() ),
169                                           m_actionCollection, m_bIsRoot ? "add_bookmark" : 0 );
170 
171   paAddBookmarks->setStatusText( i18n( "Add a bookmark for the current document" ) );
172 
173   paAddBookmarks->plug( m_parentMenu );
174   m_actions.append( paAddBookmarks );
175   addAddRelativeBookmark();
176   addAddSettingsBookmark();
177 }
178 
addAddRelativeBookmark()179 void KCelBookmarkMenu::addAddRelativeBookmark()
180 {
181   KAction * paAddBookmarks = new KAction( i18n( "Add &Relative Bookmark" ),
182                                           "bookmark_add",
183                                           m_bIsRoot ? ALT + Key_R : 0, //m_bIsRoot ? KStdAccel::addBookmark() : KShortcut(),
184                                           this,
185                                           SLOT( slotAddRelativeBookmark() ),
186                                           m_actionCollection, m_bIsRoot ? "add_relative_bookmark" : 0 );
187 
188   paAddBookmarks->setStatusText( i18n( "Add a relative bookmark for the current document" ) );
189 
190   paAddBookmarks->plug( m_parentMenu );
191   m_actions.append( paAddBookmarks );
192 }
193 
addAddSettingsBookmark()194 void KCelBookmarkMenu::addAddSettingsBookmark()
195 {
196   KAction * paAddBookmarks = new KAction( i18n( "Add &Settings Bookmark" ),
197                                           "bookmark_add",
198                                           m_bIsRoot ? CTRL + ALT + Key_S : 0, //m_bIsRoot ? KStdAccel::addBookmark() : KShortcut(),
199                                           this,
200                                           SLOT( slotAddSettingsBookmark() ),
201                                           m_actionCollection, m_bIsRoot ? "add_settings_bookmark" : 0 );
202 
203   paAddBookmarks->setStatusText( i18n( "Add a settings bookmark for the current document" ) );
204 
205   paAddBookmarks->plug( m_parentMenu );
206   m_actions.append( paAddBookmarks );
207 }
208 
addEditBookmarks()209 void KCelBookmarkMenu::addEditBookmarks()
210 {
211   KAction * m_paEditBookmarks = KStdAction::editBookmarks( m_pManager, SLOT( slotEditBookmarks() ),
212                                                              m_actionCollection, "edit_bookmarks" );
213   m_paEditBookmarks->plug( m_parentMenu );
214   m_paEditBookmarks->setStatusText( i18n( "Edit your bookmark collection in a separate window" ) );
215   m_actions.append( m_paEditBookmarks );
216 }
217 
addNewFolder()218 void KCelBookmarkMenu::addNewFolder()
219 {
220   KAction * paNewFolder = new KAction( i18n( "&New Folder..." ),
221                                        "folder_new", //"folder",
222                                        0,
223                                        this,
224                                        SLOT( slotNewFolder() ),
225                                        m_actionCollection );
226 
227   paNewFolder->setStatusText( i18n( "Create a new bookmark folder in this menu" ) );
228 
229   paNewFolder->plug( m_parentMenu );
230   m_actions.append( paNewFolder );
231 }
232 
fillBookmarkMenu()233 void KCelBookmarkMenu::fillBookmarkMenu()
234 {
235   if ( m_bIsRoot )
236   {
237     if ( m_bAddBookmark )
238       addAddBookmark();
239 
240     addEditBookmarks();
241 
242     if ( m_bAddBookmark )
243       addNewFolder();
244 
245   }
246 
247   KBookmarkGroup parentBookmark = m_pManager->findByAddress( m_parentAddress ).toGroup();
248   Q_ASSERT(!parentBookmark.isNull());
249   bool separatorInserted = false;
250   for ( KBookmark bm = parentBookmark.first(); !bm.isNull();  bm = parentBookmark.next(bm) )
251   {
252     QString text = bm.text();
253     text.replace( QRegExp( "&" ), "&&" );
254     if ( !separatorInserted && m_bIsRoot) { // inserted before the first konq bookmark, to avoid the separator if no konq bookmark
255       m_parentMenu->insertSeparator();
256       separatorInserted = true;
257     }
258     if ( !bm.isGroup() )
259     {
260       if ( bm.isSeparator() )
261       {
262         m_parentMenu->insertSeparator();
263       }
264       else
265       {
266         // kdDebug(1203) << "Creating URL bookmark menu item for " << bm.text() << endl;
267         // create a normal URL item, with ID as a name
268         KAction * action = new KAction( text, bm.icon(), 0,
269                                         this, SLOT( slotBookmarkSelected() ),
270                                         m_actionCollection, bm.url().url().utf8() );
271 
272         action->setStatusText( bm.url().prettyURL() );
273 
274         action->plug( m_parentMenu );
275         m_actions.append( action );
276       }
277     }
278     else
279     {
280       // kdDebug(1203) << "Creating bookmark submenu named " << bm.text() << endl;
281       KActionMenu * actionMenu = new KActionMenu( text, bm.icon(),
282                                                   m_actionCollection, 0L );
283       actionMenu->plug( m_parentMenu );
284       m_actions.append( actionMenu );
285       KCelBookmarkMenu *subMenu = new KCelBookmarkMenu( m_pManager, m_pOwner, actionMenu->popupMenu(),
286                                                   m_actionCollection, false,
287                                                   m_bAddBookmark,
288                                                   bm.address() );
289       m_lstSubMenus.append( subMenu );
290     }
291   }
292 
293   if ( !m_bIsRoot && m_bAddBookmark )
294   {
295     m_parentMenu->insertSeparator();
296     addAddBookmark();
297     addNewFolder();
298   }
299 }
300 
slotAddRelativeBookmark()301 void KCelBookmarkMenu::slotAddRelativeBookmark()
302 {
303   Url Url = m_pOwner->currentUrl(Url::Relative);
304   QString url = QString(Url.getAsString().c_str());;
305   if (url.isEmpty())
306   {
307     KMessageBox::error( 0L, i18n("Can't add bookmark with empty URL"));
308     return;
309   }
310   QString title = QString::fromUtf8(Url::decodeString(Url.getName()).c_str());
311   if (title.isEmpty())
312     title = url;
313 
314   KBookmarkGroup parentBookmark = m_pManager->findByAddress( m_parentAddress ).toGroup();
315   Q_ASSERT(!parentBookmark.isNull());
316   // If this title is already used, we'll try to find something unused.
317   KBookmark ch = parentBookmark.first();
318   int count = 1;
319   QString uniqueTitle = title;
320   do
321   {
322     while ( !ch.isNull() )
323     {
324       if ( uniqueTitle == ch.text() )
325       {
326         // Title already used !
327         if ( url != ch.url().url() )
328         {
329           uniqueTitle = title + QString(" (%1)").arg(++count);
330           // New title -> restart search from the beginning
331           ch = parentBookmark.first();
332           break;
333         }
334         else
335         {
336           // this exact URL already exists
337           return;
338         }
339       }
340       ch = parentBookmark.next( ch );
341     }
342   } while ( !ch.isNull() );
343 
344   parentBookmark.addBookmark( m_pManager, uniqueTitle, url, m_pOwner->currentIcon() );
345   m_pManager->emitChanged( parentBookmark );
346 }
347 
slotAddSettingsBookmark()348 void KCelBookmarkMenu::slotAddSettingsBookmark()
349 {
350   Url Url = m_pOwner->currentUrl(Url::Settings);
351   QString url = QString(Url.getAsString().c_str());;
352   if (url.isEmpty())
353   {
354     KMessageBox::error( 0L, i18n("Can't add bookmark with empty URL"));
355     return;
356   }
357   QString title = QString::fromUtf8(Url::decodeString(Url.getName()).c_str());
358   if (title.isEmpty())
359     title = url;
360 
361   KBookmarkGroup parentBookmark = m_pManager->findByAddress( m_parentAddress ).toGroup();
362   Q_ASSERT(!parentBookmark.isNull());
363   // If this title is already used, we'll try to find something unused.
364   KBookmark ch = parentBookmark.first();
365   int count = 1;
366   QString uniqueTitle = title;
367   do
368   {
369     while ( !ch.isNull() )
370     {
371       if ( uniqueTitle == ch.text() )
372       {
373         // Title already used !
374         if ( url != ch.url().url() )
375         {
376           uniqueTitle = title + QString(" (%1)").arg(++count);
377           // New title -> restart search from the beginning
378           ch = parentBookmark.first();
379           break;
380         }
381         else
382         {
383           // this exact URL already exists
384           return;
385         }
386       }
387       ch = parentBookmark.next( ch );
388     }
389   } while ( !ch.isNull() );
390 
391   parentBookmark.addBookmark( m_pManager, uniqueTitle, url, m_pOwner->currentIcon() );
392   m_pManager->emitChanged( parentBookmark );
393 }
394 
slotAddBookmark()395 void KCelBookmarkMenu::slotAddBookmark()
396 {
397   Url Url = m_pOwner->currentUrl(Url::Absolute);
398   QString url = QString(Url.getAsString().c_str());;
399   if (url.isEmpty())
400   {
401     KMessageBox::error( 0L, i18n("Can't add bookmark with empty URL"));
402     return;
403   }
404   QString title = QString::fromUtf8(Url::decodeString(Url.getName()).c_str());
405   if (title.isEmpty())
406     title = url;
407 
408   KBookmarkGroup parentBookmark = m_pManager->findByAddress( m_parentAddress ).toGroup();
409   Q_ASSERT(!parentBookmark.isNull());
410   // If this title is already used, we'll try to find something unused.
411   KBookmark ch = parentBookmark.first();
412   int count = 1;
413   QString uniqueTitle = title;
414   do
415   {
416     while ( !ch.isNull() )
417     {
418       if ( uniqueTitle == ch.text() )
419       {
420         // Title already used !
421         if ( url != ch.url().url() )
422         {
423           uniqueTitle = title + QString(" (%1)").arg(++count);
424           // New title -> restart search from the beginning
425           ch = parentBookmark.first();
426           break;
427         }
428         else
429         {
430           // this exact URL already exists
431           return;
432         }
433       }
434       ch = parentBookmark.next( ch );
435     }
436   } while ( !ch.isNull() );
437 
438   parentBookmark.addBookmark( m_pManager, uniqueTitle, url, m_pOwner->currentIcon() );
439   m_pManager->emitChanged( parentBookmark );
440 }
441 
slotNewFolder()442 void KCelBookmarkMenu::slotNewFolder()
443 {
444   if ( !m_pOwner ) return; // this view doesn't handle bookmarks...
445   KBookmarkGroup parentBookmark = m_pManager->findByAddress( m_parentAddress ).toGroup();
446   Q_ASSERT(!parentBookmark.isNull());
447   KBookmarkGroup group = parentBookmark.createNewFolder( m_pManager );
448   if ( !group.isNull() )
449   {
450     KBookmarkGroup parentGroup = group.parentGroup();
451     m_pManager->emitChanged( parentGroup );
452   }
453 }
454 
slotBookmarkSelected()455 void KCelBookmarkMenu::slotBookmarkSelected()
456 {
457   //kdDebug(1203) << "KBookmarkMenu::slotBookmarkSelected()" << endl;
458   if ( !m_pOwner ) return; // this view doesn't handle bookmarks...
459   //kdDebug(1203) << sender()->name() << endl;
460 
461   // The name of the action is the URL to open
462   m_pOwner->openBookmarkURL( QString::fromUtf8(sender()->name()) );
463 }
464 
465 // -----------------------------------------------------------------------------
466 
467 
468