summaryrefslogtreecommitdiffstats
path: root/khelpcenter/history.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'khelpcenter/history.cpp')
-rw-r--r--khelpcenter/history.cpp351
1 files changed, 351 insertions, 0 deletions
diff --git a/khelpcenter/history.cpp b/khelpcenter/history.cpp
new file mode 100644
index 000000000..9162d7640
--- /dev/null
+++ b/khelpcenter/history.cpp
@@ -0,0 +1,351 @@
+/*
+ * This file is part of the KDE Help Center
+ *
+ * Copyright (C) 2002 Frerich Raabe <raabe@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "history.h"
+#include "view.h"
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kmainwindow.h>
+#include <kpopupmenu.h>
+#include <kstdguiitem.h>
+#include <kstringhandler.h>
+
+
+
+using namespace KHC;
+
+History *History::m_instance = 0;
+
+History &History::self()
+{
+ if ( !m_instance )
+ m_instance = new History;
+ return *m_instance;
+}
+
+History::History() : QObject(),
+ m_goBuffer( 0 )
+{
+ m_entries.setAutoDelete( true );
+}
+
+History::~History()
+{
+}
+
+void History::setupActions( KActionCollection *coll )
+{
+ QPair<KGuiItem, KGuiItem> backForward = KStdGuiItem::backAndForward();
+
+ m_backAction = new KToolBarPopupAction( backForward.first, ALT+Key_Left,
+ this, SLOT( back() ), coll, "back" );
+ connect( m_backAction->popupMenu(), SIGNAL( activated( int ) ),
+ SLOT( backActivated( int ) ) );
+ connect( m_backAction->popupMenu(), SIGNAL( aboutToShow() ),
+ SLOT( fillBackMenu() ) );
+ m_backAction->setEnabled( false );
+
+ m_forwardAction = new KToolBarPopupAction( backForward.second, ALT+Key_Right,
+ this, SLOT( forward() ), coll,
+ "forward" );
+ connect( m_forwardAction->popupMenu(), SIGNAL( activated( int ) ),
+ SLOT( forwardActivated( int ) ) );
+ connect( m_forwardAction->popupMenu(), SIGNAL( aboutToShow() ),
+ SLOT( fillForwardMenu() ) );
+ m_forwardAction->setEnabled( false );
+}
+
+void History::installMenuBarHook( KMainWindow *mainWindow )
+{
+ QPopupMenu *goMenu = dynamic_cast<QPopupMenu *>(
+ mainWindow->guiFactory()->container( "go_web", mainWindow ) );
+ if ( goMenu ) {
+ connect( goMenu, SIGNAL( aboutToShow() ), SLOT( fillGoMenu() ) );
+ connect( goMenu, SIGNAL( activated( int ) ),
+ SLOT( goMenuActivated( int ) ) );
+ m_goMenuIndex = goMenu->count();
+ }
+}
+
+void History::createEntry()
+{
+ kdDebug() << "History::createEntry()" << endl;
+
+ // First, remove any forward history
+ Entry * current = m_entries.current();
+ if (current)
+ {
+ m_entries.at( m_entries.count() - 1 ); // go to last one
+ for ( ; m_entries.current() != current ; )
+ {
+ if ( !m_entries.removeLast() ) { // and remove from the end (faster and easier)
+ Q_ASSERT(0);
+ return;
+ }
+ else
+ m_entries.at( m_entries.count() - 1 );
+ }
+ // Now current is the current again.
+
+ // If current entry is empty reuse it.
+ if ( !current->view ) return;
+ }
+
+ // Append a new entry
+ m_entries.append( new Entry ); // made current
+ Q_ASSERT( m_entries.at() == (int) m_entries.count() - 1 );
+}
+
+void History::updateCurrentEntry( View *view )
+{
+ if ( m_entries.isEmpty() )
+ return;
+
+ KURL url = view->url();
+
+ Entry *current = m_entries.current();
+
+ QDataStream stream( current->buffer, IO_WriteOnly );
+ view->browserExtension()->saveState( stream );
+
+ current->view = view;
+
+ if ( url.isEmpty() ) {
+ kdDebug() << "History::updateCurrentEntry(): internal url" << endl;
+ url = view->internalUrl();
+ }
+
+ kdDebug() << "History::updateCurrentEntry(): " << view->title()
+ << " (URL: " << url.url() << ")" << endl;
+
+ current->url = url;
+ current->title = view->title();
+
+ current->search = view->state() == View::Search;
+}
+
+void History::updateActions()
+{
+ m_backAction->setEnabled( canGoBack() );
+ m_forwardAction->setEnabled( canGoForward() );
+}
+
+void History::back()
+{
+ kdDebug( 1400 ) << "History::back()" << endl;
+ goHistoryActivated( -1 );
+}
+
+void History::backActivated( int id )
+{
+ kdDebug( 1400 ) << "History::backActivated(): id = " << id << endl;
+ goHistoryActivated( -( m_backAction->popupMenu()->indexOf( id ) + 1 ) );
+}
+
+void History::forward()
+{
+ kdDebug( 1400 ) << "History::forward()" << endl;
+ goHistoryActivated( 1 );
+}
+
+void History::forwardActivated( int id )
+{
+ kdDebug( 1400 ) << "History::forwardActivated(): id = " << id << endl;
+ goHistoryActivated( m_forwardAction->popupMenu()->indexOf( id ) + 1 );
+}
+
+void History::goHistoryActivated( int steps )
+{
+ kdDebug( 1400 ) << "History::goHistoryActivated(): m_goBuffer = " << m_goBuffer << endl;
+ if ( m_goBuffer )
+ return;
+ m_goBuffer = steps;
+ QTimer::singleShot( 0, this, SLOT( goHistoryDelayed() ) );
+}
+
+void History::goHistoryDelayed()
+{
+ kdDebug( 1400 ) << "History::goHistoryDelayed(): m_goBuffer = " << m_goBuffer << endl;
+ if ( !m_goBuffer )
+ return;
+ int steps = m_goBuffer;
+ m_goBuffer = 0;
+ goHistory( steps );
+}
+
+void History::goHistory( int steps )
+{
+ kdDebug() << "History::goHistory(): " << steps << endl;
+
+ // If current entry is empty remove it.
+ Entry *current = m_entries.current();
+ if ( current && !current->view ) m_entries.remove();
+
+ int newPos = m_entries.at() + steps;
+
+ current = m_entries.at( newPos );
+ if ( !current ) {
+ kdError() << "No History entry at position " << newPos << endl;
+ return;
+ }
+
+ if ( !current->view ) {
+ kdWarning() << "Empty history entry." << endl;
+ return;
+ }
+
+ if ( current->search ) {
+ kdDebug() << "History::goHistory(): search" << endl;
+ current->view->lastSearch();
+ return;
+ }
+
+ if ( current->url.protocol() == "khelpcenter" ) {
+ kdDebug() << "History::goHistory(): internal" << endl;
+ emit goInternalUrl( current->url );
+ return;
+ }
+
+ kdDebug() << "History::goHistory(): restore state" << endl;
+
+ emit goUrl( current->url );
+
+ Entry h( *current );
+ h.buffer.detach();
+
+ QDataStream stream( h.buffer, IO_ReadOnly );
+
+ h.view->closeURL();
+ updateCurrentEntry( h.view );
+ h.view->browserExtension()->restoreState( stream );
+
+ updateActions();
+}
+
+void History::fillBackMenu()
+{
+ QPopupMenu *menu = m_backAction->popupMenu();
+ menu->clear();
+ fillHistoryPopup( menu, true, false, false );
+}
+
+void History::fillForwardMenu()
+{
+ QPopupMenu *menu = m_forwardAction->popupMenu();
+ menu->clear();
+ fillHistoryPopup( menu, false, true, false );
+}
+
+void History::fillGoMenu()
+{
+ KMainWindow *mainWindow = static_cast<KMainWindow *>( kapp->mainWidget() );
+ QPopupMenu *goMenu = dynamic_cast<QPopupMenu *>( mainWindow->guiFactory()->container( QString::fromLatin1( "go" ), mainWindow ) );
+ if ( !goMenu || m_goMenuIndex == -1 )
+ return;
+
+ for ( int i = goMenu->count() - 1 ; i >= m_goMenuIndex; i-- )
+ goMenu->removeItemAt( i );
+
+ // TODO perhaps smarter algorithm (rename existing items, create new ones only if not enough) ?
+
+ // Ok, we want to show 10 items in all, among which the current url...
+
+ if ( m_entries.count() <= 9 )
+ {
+ // First case: limited history in both directions -> show it all
+ m_goMenuHistoryStartPos = m_entries.count() - 1; // Start right from the end
+ } else
+ // Second case: big history, in one or both directions
+ {
+ // Assume both directions first (in this case we place the current URL in the middle)
+ m_goMenuHistoryStartPos = m_entries.at() + 4;
+
+ // Forward not big enough ?
+ if ( m_entries.at() > (int)m_entries.count() - 4 )
+ m_goMenuHistoryStartPos = m_entries.count() - 1;
+ }
+ Q_ASSERT( m_goMenuHistoryStartPos >= 0 && (uint)m_goMenuHistoryStartPos < m_entries.count() );
+ m_goMenuHistoryCurrentPos = m_entries.at(); // for slotActivated
+ fillHistoryPopup( goMenu, false, false, true, m_goMenuHistoryStartPos );
+}
+
+void History::goMenuActivated( int id )
+{
+ KMainWindow *mainWindow = static_cast<KMainWindow *>( kapp->mainWidget() );
+ QPopupMenu *goMenu = dynamic_cast<QPopupMenu *>( mainWindow->guiFactory()->container( QString::fromLatin1( "go" ), mainWindow ) );
+ if ( !goMenu )
+ return;
+
+ // 1 for first item in the list, etc.
+ int index = goMenu->indexOf(id) - m_goMenuIndex + 1;
+ if ( index > 0 )
+ {
+ kdDebug(1400) << "Item clicked has index " << index << endl;
+ // -1 for one step back, 0 for don't move, +1 for one step forward, etc.
+ int steps = ( m_goMenuHistoryStartPos+1 ) - index - m_goMenuHistoryCurrentPos; // make a drawing to understand this :-)
+ kdDebug(1400) << "Emit activated with steps = " << steps << endl;
+ goHistory( steps );
+ }
+}
+
+void History::fillHistoryPopup( QPopupMenu *popup, bool onlyBack, bool onlyForward, bool checkCurrentItem, uint startPos )
+{
+ Q_ASSERT ( popup ); // kill me if this 0... :/
+
+ Entry * current = m_entries.current();
+ QPtrListIterator<Entry> it( m_entries );
+ if (onlyBack || onlyForward)
+ {
+ it += m_entries.at(); // Jump to current item
+ if ( !onlyForward ) --it; else ++it; // And move off it
+ } else if ( startPos )
+ it += startPos; // Jump to specified start pos
+
+ uint i = 0;
+ while ( it.current() )
+ {
+ QString text = it.current()->title;
+ text = KStringHandler::csqueeze(text, 50); //CT: squeeze
+ text.replace( "&", "&&" );
+ if ( checkCurrentItem && it.current() == current )
+ {
+ int id = popup->insertItem( text ); // no pixmap if checked
+ popup->setItemChecked( id, true );
+ } else
+ popup->insertItem( text );
+ if ( ++i > 10 )
+ break;
+ if ( !onlyForward ) --it; else ++it;
+ }
+}
+
+bool History::canGoBack() const
+{
+ return m_entries.at() > 0;
+}
+
+bool History::canGoForward() const
+{
+ return m_entries.at() != static_cast<int>( m_entries.count() ) - 1;
+}
+
+#include "history.moc"
+// vim:ts=2:sw=2:et