diff options
Diffstat (limited to 'khelpcenter/history.cpp')
-rw-r--r-- | khelpcenter/history.cpp | 351 |
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 |