delay a few things on startup, such as setting the visibility mode, which ensures...
[personal-kdebase.git] / runtime / khelpcenter / history.cpp
bloba93e0a4b8330b322715563e87a684b642e6490a7
1 /*
2 * This file is part of the KDE Help Center
4 * Copyright (C) 2002 Frerich Raabe <raabe@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.
20 #include "history.h"
21 #include "view.h"
22 #include <QMenu>
23 #include <kaction.h>
24 #include <kactioncollection.h>
25 #include <kapplication.h>
26 #include <kdebug.h>
27 #include <kicon.h>
28 #include <kxmlguiwindow.h>
29 #include <kmenu.h>
30 #include <kstandardguiitem.h>
31 #include <kstringhandler.h>
32 #include <ktoolbarpopupaction.h>
33 #include <kxmlguifactory.h>
36 using namespace KHC;
38 History *History::m_instance = 0;
40 History &History::self()
42 if ( !m_instance )
43 m_instance = new History;
44 return *m_instance;
47 History::History() : QObject(),
48 m_goBuffer( 0 )
50 m_entries.setAutoDelete( true );
53 History::~History()
57 void History::setupActions( KActionCollection *coll )
59 QPair<KGuiItem, KGuiItem> backForward = KStandardGuiItem::backAndForward();
61 m_backAction = new KToolBarPopupAction( KIcon( backForward.first.iconName() ), backForward.first.text(), this );
62 coll->addAction( "back", m_backAction );
63 m_backAction->setShortcut( Qt::ALT+Qt::Key_Left );
64 connect( m_backAction, SIGNAL( triggered() ), this, SLOT( back() ) );
66 connect( m_backAction->menu(), SIGNAL( activated( int ) ),
67 SLOT( backActivated( int ) ) );
68 connect( m_backAction->menu(), SIGNAL( aboutToShow() ),
69 SLOT( fillBackMenu() ) );
70 m_backAction->setEnabled( false );
72 m_forwardAction = new KToolBarPopupAction( KIcon( backForward.second.iconName() ), backForward.second.text(), this );
73 coll->addAction( QLatin1String("forward"), m_forwardAction );
74 m_forwardAction->setShortcut( Qt::ALT+Qt::Key_Right );
75 connect( m_forwardAction, SIGNAL( triggered() ), this, SLOT( forward() ) );
77 connect( m_forwardAction->menu(), SIGNAL( activated( int ) ),
78 SLOT( forwardActivated( int ) ) );
79 connect( m_forwardAction->menu(), SIGNAL( aboutToShow() ),
80 SLOT( fillForwardMenu() ) );
81 m_forwardAction->setEnabled( false );
83 void History::installMenuBarHook( KXmlGuiWindow *mainWindow )
85 QMenu *goMenu = dynamic_cast<QMenu *>(
86 mainWindow->guiFactory()->container( QLatin1String("go_web"), mainWindow ) );
87 if ( goMenu ) {
88 connect( goMenu, SIGNAL( aboutToShow() ), SLOT( fillGoMenu() ) );
89 connect( goMenu, SIGNAL( activated( int ) ),
90 SLOT( goMenuActivated( int ) ) );
91 m_goMenuIndex = goMenu->actions().count();
95 void History::createEntry()
97 kDebug() << "History::createEntry()";
99 // First, remove any forward history
100 Entry * current = m_entries.current();
101 if (current)
103 m_entries.at( m_entries.count() - 1 ); // go to last one
104 for ( ; m_entries.current() != current ; )
106 if ( !m_entries.removeLast() ) { // and remove from the end (faster and easier)
107 Q_ASSERT(0);
108 return;
110 else
111 m_entries.at( m_entries.count() - 1 );
113 // Now current is the current again.
115 // If current entry is empty reuse it.
116 if ( !current->view ) return;
119 // Append a new entry
120 m_entries.append( new Entry ); // made current
121 Q_ASSERT( m_entries.at() == (int) m_entries.count() - 1 );
124 void History::updateCurrentEntry( View *view )
126 if ( m_entries.isEmpty() )
127 return;
129 KUrl url = view->url();
131 Entry *current = m_entries.current();
133 QDataStream stream( &current->buffer, QIODevice::WriteOnly );
134 view->browserExtension()->saveState( stream );
136 current->view = view;
138 if ( url.isEmpty() ) {
139 kDebug() << "History::updateCurrentEntry(): internal url";
140 url = view->internalUrl();
143 kDebug() << "History::updateCurrentEntry(): " << view->title()
144 << " (URL: " << url.url() << ")" << endl;
146 current->url = url;
147 current->title = view->title();
149 current->search = view->state() == View::Search;
152 void History::updateActions()
154 m_backAction->setEnabled( canGoBack() );
155 m_forwardAction->setEnabled( canGoForward() );
158 void History::back()
160 kDebug( 1400 ) << "History::back()";
161 goHistoryActivated( -1 );
164 void History::backActivated( int id )
166 kDebug( 1400 ) << "History::backActivated(): id = " << id;
167 goHistoryActivated( -( m_backAction->menu()->indexOf( id ) + 1 ) );
170 void History::forward()
172 kDebug( 1400 ) << "History::forward()";
173 goHistoryActivated( 1 );
176 void History::forwardActivated( int id )
178 kDebug( 1400 ) << "History::forwardActivated(): id = " << id;
179 goHistoryActivated( m_forwardAction->menu()->indexOf( id ) + 1 );
182 void History::goHistoryActivated( int steps )
184 kDebug( 1400 ) << "History::goHistoryActivated(): m_goBuffer = " << m_goBuffer;
185 if ( m_goBuffer )
186 return;
187 m_goBuffer = steps;
188 QTimer::singleShot( 0, this, SLOT( goHistoryDelayed() ) );
191 void History::goHistoryDelayed()
193 kDebug( 1400 ) << "History::goHistoryDelayed(): m_goBuffer = " << m_goBuffer;
194 if ( !m_goBuffer )
195 return;
196 int steps = m_goBuffer;
197 m_goBuffer = 0;
198 goHistory( steps );
201 void History::goHistory( int steps )
203 kDebug() << "History::goHistory(): " << steps;
205 // If current entry is empty remove it.
206 Entry *current = m_entries.current();
207 if ( current && !current->view ) m_entries.remove();
209 int newPos = m_entries.at() + steps;
211 current = m_entries.at( newPos );
212 if ( !current ) {
213 kError() << "No History entry at position " << newPos << endl;
214 return;
217 if ( !current->view ) {
218 kWarning() << "Empty history entry." ;
219 return;
222 if ( current->search ) {
223 kDebug() << "History::goHistory(): search";
224 current->view->lastSearch();
225 return;
228 if ( current->url.protocol() == QLatin1String("khelpcenter") ) {
229 kDebug() << "History::goHistory(): internal";
230 emit goInternalUrl( current->url );
231 return;
234 kDebug() << "History::goHistory(): restore state";
236 emit goUrl( current->url );
238 Entry h( *current );
239 h.buffer.detach();
241 QDataStream stream( h.buffer );
243 h.view->closeUrl();
244 updateCurrentEntry( h.view );
245 h.view->browserExtension()->restoreState( stream );
247 updateActions();
250 void History::fillBackMenu()
252 QMenu *menu = m_backAction->menu();
253 menu->clear();
254 fillHistoryPopup( menu, true, false, false );
257 void History::fillForwardMenu()
259 QMenu *menu = m_forwardAction->menu();
260 menu->clear();
261 fillHistoryPopup( menu, false, true, false );
264 void History::fillGoMenu()
266 KXmlGuiWindow *mainWindow = static_cast<KXmlGuiWindow *>( kapp->activeWindow() );
267 QMenu *goMenu = dynamic_cast<QMenu *>( mainWindow->guiFactory()->container( QLatin1String( "go" ), mainWindow ) );
268 if ( !goMenu || m_goMenuIndex == -1 )
269 return;
271 for ( int i = goMenu->actions().count() - 1 ; i >= m_goMenuIndex; i-- )
272 goMenu->removeAction( goMenu->actions()[i] );
274 // TODO perhaps smarter algorithm (rename existing items, create new ones only if not enough) ?
276 // Ok, we want to show 10 items in all, among which the current url...
278 if ( m_entries.count() <= 9 )
280 // First case: limited history in both directions -> show it all
281 m_goMenuHistoryStartPos = m_entries.count() - 1; // Start right from the end
282 } else
283 // Second case: big history, in one or both directions
285 // Assume both directions first (in this case we place the current URL in the middle)
286 m_goMenuHistoryStartPos = m_entries.at() + 4;
288 // Forward not big enough ?
289 if ( m_entries.at() > (int)m_entries.count() - 4 )
290 m_goMenuHistoryStartPos = m_entries.count() - 1;
292 Q_ASSERT( m_goMenuHistoryStartPos >= 0 && (uint)m_goMenuHistoryStartPos < m_entries.count() );
293 m_goMenuHistoryCurrentPos = m_entries.at(); // for slotActivated
294 fillHistoryPopup( goMenu, false, false, true, m_goMenuHistoryStartPos );
297 void History::goMenuActivated( int id )
299 KXmlGuiWindow *mainWindow = static_cast<KXmlGuiWindow *>( kapp->activeWindow() );
300 QMenu *goMenu = dynamic_cast<QMenu *>( mainWindow->guiFactory()->container( QLatin1String( "go" ), mainWindow ) );
301 if ( !goMenu )
302 return;
304 // 1 for first item in the list, etc.
305 int index = goMenu->indexOf(id) - m_goMenuIndex + 1;
306 if ( index > 0 )
308 kDebug(1400) << "Item clicked has index " << index;
309 // -1 for one step back, 0 for don't move, +1 for one step forward, etc.
310 int steps = ( m_goMenuHistoryStartPos+1 ) - index - m_goMenuHistoryCurrentPos; // make a drawing to understand this :-)
311 kDebug(1400) << "Emit activated with steps = " << steps;
312 goHistory( steps );
316 void History::fillHistoryPopup( QMenu *popup, bool onlyBack, bool onlyForward, bool checkCurrentItem, uint startPos )
318 Q_ASSERT ( popup ); // kill me if this 0... :/
320 Entry * current = m_entries.current();
321 Q3PtrListIterator<Entry> it( m_entries );
322 if (onlyBack || onlyForward)
324 it += m_entries.at(); // Jump to current item
325 if ( !onlyForward ) --it; else ++it; // And move off it
326 } else if ( startPos )
327 it += startPos; // Jump to specified start pos
329 uint i = 0;
330 while ( it.current() )
332 QString text = it.current()->title;
333 text = KStringHandler::csqueeze(text, 50); //CT: squeeze
334 text.replace( "&", "&&" );
335 if ( checkCurrentItem && it.current() == current )
337 popup->addAction( text )->setChecked( true ); // no pixmap if checked
338 } else
339 popup->addAction( text );
340 if ( ++i > 10 )
341 break;
342 if ( !onlyForward ) --it; else ++it;
346 bool History::canGoBack() const
348 return m_entries.at() > 0;
351 bool History::canGoForward() const
353 return m_entries.at() != static_cast<int>( m_entries.count() ) - 1;
356 #include "history.moc"
357 // vim:ts=2:sw=2:et