diff options
| author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-15 18:23:18 +0000 | 
|---|---|---|
| committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-15 18:23:18 +0000 | 
| commit | 3133bbc63a2d32dac638db58fa13e966488e88b5 (patch) | |
| tree | 326595b5fefc87fd7cf5ab3905bc00883fe3c919 /src/kchmmainwindow.cpp | |
| download | kchmviewer-3133bbc63a2d32dac638db58fa13e966488e88b5.tar.gz kchmviewer-3133bbc63a2d32dac638db58fa13e966488e88b5.zip  | |
Added abandoned KDE3 version of kchmviewer
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kchmviewer@1090662 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/kchmmainwindow.cpp')
| -rw-r--r-- | src/kchmmainwindow.cpp | 1298 | 
1 files changed, 1298 insertions, 0 deletions
diff --git a/src/kchmmainwindow.cpp b/src/kchmmainwindow.cpp new file mode 100644 index 0000000..13417f1 --- /dev/null +++ b/src/kchmmainwindow.cpp @@ -0,0 +1,1298 @@ +/*************************************************************************** + *   Copyright (C) 2004-2007 by Georgy Yunaev, gyunaev@ulduzsoft.com       * + *   Please do not use email address above for bug reports; see            * + *   the README file                                                       * + *                                                                         * + *   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 <stdlib.h> +#include <signal.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> + +#include "kde-qt.h" + +#include <qaccel.h> +#include <qevent.h> + +#include "libchmfile.h" +#include "libchmfileimpl.h" +#include "libchmurlfactory.h" + +#include "kchmmainwindow.h" +#include "kchmconfig.h" +#include "kchmindexwindow.h" +#include "kchmsearchwindow.h" +#include "kchmbookmarkwindow.h" +#include "kchmtreeviewitem.h" +#include "kchmsearchtoolbar.h" +#include "kchmsettings.h" +#include "kchmsetupdialog.h" +#include "iconstorage.h" +#include "kchmnavtoolbar.h" +#include "kchmviewwindow.h" +#include "kchmviewwindowmgr.h" +#include "kchmkeyeventfilter.h" +#include "kchmcontentswindow.h" + +#if !defined (USE_KDE) +	#include "kqrunprocess.h" +#endif + +#include "kchmmainwindow.moc" + + +KCHMMainWindow::KCHMMainWindow() +    : KQMainWindow ( 0, "KCHMMainWindow", WDestructiveClose ) +{ +	const unsigned int WND_X_SIZE = 700; +	const unsigned int WND_Y_SIZE = 500; +	const unsigned int SPLT_X_SIZE = 200; + +	m_FirstTimeShow = true; +	m_chmFile = 0; +	 +	m_indexWindow = 0; +	m_searchWindow = 0; +	m_contentsWindow = 0; +	m_viewWindowMgr = 0; + +	m_tabContextPage = -1; +	m_tabIndexPage = -1; +	m_tabSearchPage = -1; +	m_tabBookmarkPage = -1; +	 +	setupSignals(); + +	m_currentSettings = new KCHMSettings; +		 +	// Create the initial layout - a splitter with tab window in left, and text browser in right +	m_windowSplitter = new QSplitter(this); +	m_tabWidget = new KQTabWidget( m_windowSplitter ); +	m_viewWindowMgr = new KCHMViewWindowMgr( m_windowSplitter ); +	 +	m_bookmarkWindow = new KCHMBookmarkWindow (m_tabWidget); + +	// Add the tabs +	m_tabWidget->addTab( m_bookmarkWindow, i18n("Bookmarks") ); + +	setupToolbarsAndMenu(); +		 +	setCentralWidget( m_windowSplitter ); +	 +	QValueList<int> sizes; +	sizes.push_back (SPLT_X_SIZE); +	sizes.push_back (WND_X_SIZE - SPLT_X_SIZE); +	m_windowSplitter->setSizes (sizes); +	 +	resize (WND_X_SIZE, WND_Y_SIZE); + +#if defined (ENABLE_AUTOTEST_SUPPORT) +	m_autoteststate = STATE_OFF; +	m_useShortAutotest = false; +#endif /* defined (ENABLE_AUTOTEST_SUPPORT) */ + +	QAccel * accel = new QAccel( this ); +	accel->connectItem ( accel->insertItem ( Key_F11 ), this, SLOT ( slotToggleFullScreenMode() ) ); +	accel->connectItem ( accel->insertItem ( CTRL + Key_1), this, SLOT ( slotActivateContentTab() ) ); +	accel->connectItem ( accel->insertItem ( CTRL + Key_2), this, SLOT ( slotActivateIndexTab() ) ); +	accel->connectItem ( accel->insertItem ( CTRL + Key_3), this, SLOT ( slotActivateSearchTab() ) ); +	accel->connectItem ( accel->insertItem ( CTRL + Key_4), this, SLOT ( slotActivateBookmarkTab() ) ); +	accel->connectItem ( accel->insertItem ( Key_F3 ), m_searchToolbar, SLOT ( onBtnNextSearchResult() ) ); + +	statusBar()->show(); +	setIcon( *gIconStorage.getApplicationIcon() ); + +	m_aboutDlgMenuText = i18n( "%1 version %2\n\nCopyright (C) George Yunaev," +			"gyunaev@ulduzsoft.com, 2004-2007\nhttp://www.kchmviewer.net\n\n" +			"Licensed under GNU GPL license.\n\n" +			"Please check my another project, http://www.transientmail.com - temporary " +			"e-mail address, which expires automatically." ) +			. arg(APP_NAME) . arg(APP_VERSION); +} + + +KCHMMainWindow::~KCHMMainWindow() +{ +} + + +void KCHMMainWindow::slotOpenMenuItemActivated() +{ +#if defined (USE_KDE) +    QString fn = KFileDialog::getOpenFileName( appConfig.m_lastOpenedDir, i18n("*.chm|Compressed Help Manual (*.chm)"), this); +#else +    QString fn = QFileDialog::getOpenFileName( appConfig.m_lastOpenedDir, i18n("Compressed Help Manual (*.chm)"), this); +#endif + +    if ( !fn.isEmpty() ) +		loadChmFile( fn ); +    else +	{ +		if ( !m_chmFile ) +			exit (1); +			 +		statusBar()->message( i18n("Loading aborted"), 2000 ); +	} +} + + +bool KCHMMainWindow::loadChmFile ( const QString &fileName, bool call_open_page ) +{ +	LCHMFile * new_chmfile = new LCHMFile(); +	 +	if ( new_chmfile->loadFile( fileName ) ) +	{ +		// The new file is opened, so we can close the old one +		if ( m_chmFile ) +		{ +			closeChmFile( ); +			delete m_chmFile; +		} +	 +		m_chmFile = new_chmfile; +		 +		// Show current encoding in status bar +		showInStatusBar( tr("Detected chm file charset: %1") . arg(m_chmFile->currentEncoding()->language) ); + +		// Make the file name absolute; we'll need it later +		QDir qd; +		qd.setPath (fileName); +		m_chmFilename = qd.absPath(); +		 +		// Qt's 'dirname' does not work well +		QFileInfo qf ( m_chmFilename ); +		appConfig.m_lastOpenedDir = qf.dirPath(true); + +		// Order the tabulations +		int number_of_pages = 0; +		 +		if ( m_chmFile->hasTableOfContents() ) +			m_tabContextPage = number_of_pages++; +		else +			m_tabContextPage = -1; + +		if ( m_chmFile->hasIndexTable() ) +			m_tabIndexPage = number_of_pages++; +		else +			m_tabIndexPage = -1; + +		// We always show search +		m_tabSearchPage = number_of_pages++; + +		m_tabBookmarkPage = number_of_pages; + +		showOrHideContextWindow( m_tabContextPage ); +		showOrHideIndexWindow( m_tabIndexPage ); +		showOrHideSearchWindow( m_tabSearchPage ); +		 +		m_bookmarkWindow->invalidate(); +		m_navToolbar->updateIconStatus( false, false ); +		m_viewWindowMgr->invalidate(); +		refreshCurrentBrowser(); + +		if ( m_currentSettings->loadSettings (fileName) ) +		{ +			const LCHMTextEncoding * encoding =  +					m_chmFile->impl()->lookupByLCID(  m_currentSettings->m_activeencodinglcid ); + +			m_tabWidget->setCurrentPage( m_currentSettings->m_activetabsystem ); +			 +			if ( encoding ) +			{ +				m_chmFile->setCurrentEncoding( encoding ); +				m_searchToolbar->setChosenEncodingInMenu( encoding ); +			} +			 +			if ( m_searchWindow ) +				m_searchWindow->restoreSettings (m_currentSettings->m_searchhistory); +				 +			m_bookmarkWindow->restoreSettings (m_currentSettings->m_bookmarks); + +			if ( call_open_page ) +			{ +				m_viewWindowMgr->restoreSettings( m_currentSettings->m_viewwindows ); +				m_viewWindowMgr->setCurrentPage( m_currentSettings->m_activetabwindow ); +			} +			 +			// Restore the main window size +			QValueList<int> sizes; +			sizes.push_back( m_currentSettings->m_window_size_splitter ); +			sizes.push_back( m_currentSettings->m_window_size_x - m_currentSettings->m_window_size_splitter ); +			 +			m_windowSplitter->setSizes( sizes ); +			resize( m_currentSettings->m_window_size_x, m_currentSettings->m_window_size_y ); +		} +		else +		{ +			m_tabWidget->setCurrentPage (0); +			m_searchToolbar->setChosenEncodingInMenu( m_chmFile->currentEncoding() ); +			 +			if ( call_open_page ) +				openPage( m_chmFile->homeUrl() ); +		} + +		m_searchToolbar->setEnabled (true); +		appConfig.addFileToHistory( m_chmFilename ); +		updateHistoryMenu(); +		return true; +	} +	else +	{ +		QMessageBox mbox( +				i18n("%1 - failed to load the chm file") . arg(APP_NAME), +				i18n("Unable to load the chm file %1") . arg(fileName),  +				QMessageBox::Critical,  +				QMessageBox::Ok,  +				QMessageBox::NoButton,  +				QMessageBox::NoButton); +		mbox.exec(); +		 +		statusBar()->message(  +				i18n("Could not load file %1").arg(fileName), +				2000 ); +		delete new_chmfile;	 +		return false; +	} +} + + +void KCHMMainWindow::slotPrintMenuItemActivated() +{ +	currentBrowser()->printCurrentPage(); +} + + +void KCHMMainWindow::slotAboutMenuItemActivated() +{ +	QString caption = i18n( "About %1" ) . arg(APP_NAME); +	QString text = m_aboutDlgMenuText; +	 +	// It is quite funny that the argument order differs +#if defined (USE_KDE) +	KMessageBox::about( this, text, caption ); +#else +    QMessageBox::about( this, caption, text ); +#endif +} + + +void KCHMMainWindow::slotAboutQtMenuItemActivated() +{ +    QMessageBox::aboutQt( this, APP_NAME); +} + +void KCHMMainWindow::refreshCurrentBrowser( ) +{ +	QString title = m_chmFile->title(); +	 +	if ( !title ) +		title = APP_NAME; +	// KDE adds application name automatically, so we don't need it here	 +#if !defined (USE_KDE) +	else +		title = (QString) APP_NAME + " - " + title; +#endif	 +	 +	setCaption ( title ); +	 +	currentBrowser()->invalidate(); +	 +	if ( m_contentsWindow ) +		m_contentsWindow->refillTableOfContents(); +} + +void KCHMMainWindow::slotOnTreeClicked( QListViewItem * item ) +{ +	bool unused; +	 +	if ( !item ) +		return; +	 +	KCHMIndTocItem * treeitem = (KCHMIndTocItem*) item; +	slotLinkClicked( treeitem->getUrl(), unused ); +} + + +void KCHMMainWindow::slotLinkClicked ( const QString & link, bool& follow_link ) +{ +	if ( link.isEmpty() ) +		return; +	 +	if ( gKeyEventFilter.isShiftPressed() ) +	{ +		openPage( link, OPF_NEW_TAB | OPF_CONTENT_TREE ); +		follow_link = false; +	} +	else if ( gKeyEventFilter.isCtrlPressed() ) +	{ +		openPage( link, OPF_NEW_TAB | OPF_BACKGROUND ); +		follow_link = false; +	} +	else +		// If the openPage failed, we do not need to follow the link. +		follow_link = openPage( link, OPF_CONTENT_TREE | OPF_ADD2HISTORY ); +} + + +bool KCHMMainWindow::openPage( const QString & srcurl, unsigned int flags ) +{ +	QString p1, p2, url = srcurl; +	 +	if ( url == "/" ) +		url = m_chmFile->homeUrl(); + +	if ( LCHMUrlFactory::isRemoteURL (url, p1) ) +	{ +		switch ( appConfig.m_onExternalLinkClick ) +		{ +		case KCHMConfig::ACTION_DONT_OPEN: +			break; + +		case KCHMConfig::ACTION_ASK_USER: +	   		if ( QMessageBox::question(this, +				 i18n("%1 - remote link clicked - %2") . arg(APP_NAME) . arg(p1), +				 i18n("A remote link %1 will start the external program to open it.\n\nDo you want to continue?").arg( url ), +				 i18n("&Yes"), i18n("&No"), +				 QString::null, 0, 1 ) ) +					return false; +				 +			// no break! should continue to open. + +		case KCHMConfig::ACTION_ALWAYS_OPEN: +		{ +#if defined (USE_KDE) +			new KRun ( url ); +#else +			run_process( appConfig.m_QtBrowserPath, url ); +#endif +		} +		break; +		} + +		return false; // do not change the current page. +	} +		 +	// Filter the URLs which do not need to be opened at all by Qt version +	if ( LCHMUrlFactory::isJavascriptURL (url) ) +	{ +		QMessageBox::information( this,  +			i18n( "%1 - JavsScript link clicked") . arg(APP_NAME), +			i18n( "You have clicked a JavaScript link.\nTo prevent security-related issues JavaScript URLs are disabled in CHM files.") ); +		 +		return false; +	} + +	if ( LCHMUrlFactory::isNewChmURL (url, p1, p2) && p1 != m_chmFilename ) +	{ +   		if ( QMessageBox::question( this, +			i18n( "%1 - link to a new CHM file clicked"). arg(APP_NAME), +			i18n( "You have clicked a link, which leads to a new CHM file %1.\nThe current file will be closed.\n\nDo you want to continue?").arg( p1 ), +			i18n( "&Yes" ), i18n( "&No" ), +			QString::null, 0, 1 ) ) +				return false; + +		// Because chm file always contain relative link, and current filename is not changed, +		// we need to form a new path +		QFileInfo qfi( m_chmFilename ); +		QString newfilename = qfi.dirPath(true) + "/" + p1; +		 +		QStringList event_args; +		event_args.push_back( newfilename ); +		event_args.push_back( p2 ); // url +		 +		qApp->postEvent( this, new KCHMUserEvent( "loadAndOpen", event_args ) ); +		return false; +	} +	 +	KCHMViewWindow * vwnd = currentBrowser(); +	if ( flags & OPF_NEW_TAB ) +		vwnd = m_viewWindowMgr->addNewTab( !(flags & OPF_BACKGROUND) ); +	 +	// Store current page and position to add it to history if we change it +	int hist_scrollpos = currentBrowser()->getScrollbarPosition(); +	QString hist_url = currentBrowser()->getOpenedPage(); +	 +	if ( vwnd->openUrl (url) ) +	{ +		// Open all the tree items to show current item (if needed) +		if ( (flags & OPF_CONTENT_TREE) != 0 ) +			locateInContentTree( vwnd->getOpenedPage() ); +		 +		if ( flags & OPF_ADD2HISTORY ) +			currentBrowser()->addNavigationHistory( hist_url, hist_scrollpos ); +	} +	 +	return true; +} + + +void KCHMMainWindow::showEvent( QShowEvent * ) +{ +	if ( !m_FirstTimeShow ) +		return; + +	m_FirstTimeShow = false; +	 +	if ( !parseCmdLineArgs( ) ) +	{ +		if ( appConfig.m_LoadLatestFileOnStartup && appConfig.m_History.size() > 0 ) +		{ +			if ( loadChmFile ( appConfig.m_History[0] ) ) +				return; +		} +		 +		emit slotOpenMenuItemActivated(); +	} +} + +void KCHMMainWindow::setupToolbarsAndMenu( ) +{ +	// Create a 'file' toolbar +    QToolBar * toolbar = new QToolBar(this); +	 +	toolbar->setLabel( i18n( "File Operations") ); + +    QPixmap iconFileOpen (*gIconStorage.getToolbarPixmap(KCHMIconStorage::fileopen)); +    QToolButton * fileOpen = new QToolButton (iconFileOpen,  +				i18n( "Open File" ),  +				QString::null, +				this,  +				SLOT( slotOpenMenuItemActivated() ), +				toolbar); +	 +	QString fileOpenText = i18n( "Click this button to open an existing chm file." ); +	QWhatsThis::add( fileOpen, fileOpenText ); + +    QPixmap iconFilePrint (*gIconStorage.getToolbarPixmap(KCHMIconStorage::print)); +    QToolButton * filePrint	= new QToolButton (iconFilePrint, +				i18n( "Print File" ), +				QString::null, +				this, +				SLOT( slotPrintMenuItemActivated() ), +				toolbar); + +	QString filePrintText = i18n( "Click this button to print the current page"); +	QWhatsThis::add( filePrint, filePrintText ); + +	// Setup the menu +	KQPopupMenu * file = new KQPopupMenu( this ); +	menuBar()->insertItem( i18n( "&File"), file ); + +    int id; +	id = file->insertItem ( iconFileOpen, i18n( "&Open..."), this, SLOT( slotOpenMenuItemActivated() ), CTRL+Key_O ); +    file->setWhatsThis( id, fileOpenText ); + +	id = file->insertItem( iconFilePrint, i18n( "&Print..."), this, SLOT( slotPrintMenuItemActivated() ), CTRL+Key_P ); +    file->setWhatsThis( id, filePrintText ); + +    file->insertSeparator(); +	id = file->insertItem ( i18n( "E&xtract CHM content..."), this, SLOT( slotExtractCHM() ) ); +	file->setWhatsThis( id, i18n( "Click this button to extract the whole CHM file content into a specific directory") ); +	file->insertSeparator(); +	 +	m_menuHistory = new KQPopupMenu( file ); +	connect ( m_menuHistory, SIGNAL( activated(int) ), this, SLOT ( slotHistoryMenuItemActivated(int) )); +	 +	file->insertItem( i18n( "&Recent files"), m_menuHistory ); +	 +	file->insertSeparator(); +	file->insertItem( i18n( "&Quit"), qApp, SLOT( closeAllWindows() ), CTRL+Key_Q ); + +	KQPopupMenu * menu_edit = new KQPopupMenu( this ); +	menuBar()->insertItem( i18n( "&Edit"), menu_edit ); + +	menu_edit->insertItem ( i18n( "&Copy"), this, SLOT( slotBrowserCopy()), CTRL+Key_C ); +	menu_edit->insertItem ( i18n( "&Select all"), this, SLOT( slotBrowserSelectAll()), CTRL+Key_A ); + +    menu_edit->insertSeparator(); +	 +	// KCHMNavToolbar +	m_navToolbar = new KCHMNavToolbar( this ); +	 +	// KCHMSearchToolbar also adds 'view' menu +	m_searchToolbar = new KCHMSearchAndViewToolbar (this); +	 +	// m_bookmarkWindow adds 'Bookmarks' menu +	m_bookmarkWindow->createMenu( this ); +	 +	// m_viewWindowMgr creates 'Window' menu +	m_viewWindowMgr->createMenu( this ); +	 +	KQPopupMenu * settings = new KQPopupMenu( this ); +	menuBar()->insertItem( i18n( "&Settings"), settings ); +	settings->insertItem( i18n( "&Change settings..."), this, SLOT( slotChangeSettingsMenuItemActivated() )); + +#if defined(USE_KDE) +	QPopupMenu *help = helpMenu( m_aboutDlgMenuText ); +#else +    KQPopupMenu * help = new KQPopupMenu( this ); +	help->insertItem( i18n( "&About"), this, SLOT( slotAboutMenuItemActivated() ), Key_F1 ); +	help->insertItem( i18n( "About &Qt"), this, SLOT( slotAboutQtMenuItemActivated() )); +	help->insertSeparator(); +	help->insertItem( i18n( "What's &This"), this, SLOT(whatsThis()), SHIFT+Key_F1 ); +#endif +		 +	menuBar()->insertItem( i18n( "&Help"), help ); +	updateHistoryMenu(); +} + +void KCHMMainWindow::slotAddBookmark( ) +{ +	emit m_bookmarkWindow->onAddBookmarkPressed (); +} + +void KCHMMainWindow::setTextEncoding( const LCHMTextEncoding * encoding ) +{ +	m_chmFile->setCurrentEncoding( encoding ); +	m_searchToolbar->setChosenEncodingInMenu( encoding ); +	 +	// Because updateView() will call view->invalidate(), which clears the view->getOpenedPage(), +	// we have to make a copy of it. +	QString url = currentBrowser()->getOpenedPage(); +	 +	// Regenerate the content and index trees	 +	refreshCurrentBrowser(); +	 +	currentBrowser()->openUrl( url ); +} + +void KCHMMainWindow::closeChmFile( ) +{ +	// Prepare the settings +	if ( appConfig.m_HistoryStoreExtra ) +	{ +		m_currentSettings->m_activeencodinglcid = m_chmFile->currentEncoding()->winlcid; +		m_currentSettings->m_activetabsystem = m_tabWidget->currentPageIndex( ); +		m_currentSettings->m_activetabwindow = m_viewWindowMgr->currentPageIndex( ); +		 +		m_currentSettings->m_window_size_x = width(); +		m_currentSettings->m_window_size_y = height(); +		m_currentSettings->m_window_size_splitter = m_windowSplitter->sizes()[0]; +		 +		if ( m_searchWindow ) +			m_searchWindow->saveSettings (m_currentSettings->m_searchhistory); +				 +		m_bookmarkWindow->saveSettings( m_currentSettings->m_bookmarks ); + +		m_viewWindowMgr->saveSettings( m_currentSettings->m_viewwindows ); + +		m_currentSettings->saveSettings( ); +	} +	 +	appConfig.save(); +} + + +void KCHMMainWindow::closeEvent ( QCloseEvent * e ) +{ +	// Save the settings if we have something opened +	if ( m_chmFile ) +	{ +		closeChmFile( ); +		delete m_chmFile; +		m_chmFile = 0; +	} + +	QMainWindow::closeEvent ( e ); +} + +bool KCHMMainWindow::parseCmdLineArgs( ) +{ +	QString filename = QString::null, search_query = QString::null; +	QString search_index = QString::null, search_bookmark = QString::null; +	bool do_autotest = false; + +#if defined (USE_KDE) +	KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + +	if ( args->isSet("autotestmode") ) +		do_autotest = true; +	 +	if ( args->isSet("shortautotestmode") ) +		do_autotest = m_useShortAutotest = true; + +	search_query = args->getOption ("search"); +	search_index = args->getOption ("sindex"); +	 +	if ( args->count() > 0 ) +		filename = args->arg(0); +#else +	// argv[0] in Qt is still a program name +	for ( int i = 1; i < qApp->argc(); i++  ) +	{ +		if ( !strcmp (qApp->argv()[i], "--autotestmode") ) +			do_autotest = m_useShortAutotest = true; +		else if ( !strcmp (qApp->argv()[i], "--shortautotestmode") ) +			do_autotest = true; +		else if ( !strcmp (qApp->argv()[i], "--search") ) +			search_query = qApp->argv()[++i]; +		else if ( !strcmp (qApp->argv()[i], "--sindex") ) +			search_index = qApp->argv()[++i]; +		else if ( !strcmp (qApp->argv()[i], "-h") || !strcmp (qApp->argv()[i], "--help") ) +		{ +			fprintf (stderr, "Usage: %s [chmfile]\n", qApp->argv()[0]); +			exit (1); +		} +		else +			filename = qApp->argv()[i]; +	} +#endif + +	if ( !filename.isEmpty() ) +	{ +		if ( !loadChmFile( QString::fromLocal8Bit( filename )) ) +			return true; // skip the latest checks, but do not exit from the program + +		if ( !search_index.isEmpty() ) +		{ +			QStringList event_args; +			event_args.push_back( search_index ); +			qApp->postEvent( this, new KCHMUserEvent( "findInIndex", event_args ) ); +		} +		 +		if ( !search_query.isEmpty() )	 +		{ +			QStringList event_args; +			event_args.push_back( search_query ); +			qApp->postEvent( this, new KCHMUserEvent( "searchQuery", event_args ) ); +		} +		 +		if ( do_autotest ) +		{ +#if defined (ENABLE_AUTOTEST_SUPPORT) +			if ( filename.isEmpty() ) +				qFatal ("Could not use Auto Test mode without a chm file!"); + +			m_autoteststate = STATE_INITIAL; +			showMinimized (); +			runAutoTest(); +#else +			qFatal ("Auto Test mode support is not compiled in."); +#endif /* defined (ENABLE_AUTOTEST_SUPPORT) */ +		} +		return true; +	} +	 +	return false; +} + +void KCHMMainWindow::slotBrowserSelectAll( ) +{ +	currentBrowser()->clipSelectAll(); +} + +void KCHMMainWindow::slotBrowserCopy( ) +{ +	currentBrowser()->clipCopy(); +} + +void KCHMMainWindow::slotChangeSettingsMenuItemActivated() +{ +	KCHMSetupDialog dlg ( this ); +	 +	// Set up the parameters +	dlg.m_radioOnBeginOpenDialog->setChecked ( !appConfig.m_LoadLatestFileOnStartup ); +	dlg.m_radioOnBeginOpenLast->setChecked ( appConfig.m_LoadLatestFileOnStartup ); +	dlg.m_historySize->setValue ( appConfig.m_HistorySize ); +	dlg.m_rememberHistoryInfo->setChecked ( appConfig.m_HistoryStoreExtra ); +	 +	dlg.m_radioExtLinkOpenAlways->setChecked ( appConfig.m_onExternalLinkClick == KCHMConfig::ACTION_ALWAYS_OPEN ); +	dlg.m_radioExtLinkAsk->setChecked ( appConfig.m_onExternalLinkClick == KCHMConfig::ACTION_ASK_USER ); +	dlg.m_radioExtLinkOpenNever->setChecked ( appConfig.m_onExternalLinkClick == KCHMConfig::ACTION_DONT_OPEN ); +	 +	dlg.m_radioNewChmOpenAlways->setChecked ( appConfig.m_onNewChmClick == KCHMConfig::ACTION_ALWAYS_OPEN ); +	dlg.m_radioNewChmAsk->setChecked ( appConfig.m_onNewChmClick == KCHMConfig::ACTION_ASK_USER ); +	dlg.m_radioNewChmOpenNever->setChecked ( appConfig.m_onNewChmClick == KCHMConfig::ACTION_DONT_OPEN ); + +#if defined (USE_KDE) +	dlg.m_groupQtsettings->setEnabled ( false ); +	dlg.m_groupKDEsettings->setEnabled ( true ); +#else +	dlg.m_groupQtsettings->setEnabled ( true ); +	dlg.m_groupKDEsettings->setEnabled ( false ); +#endif + +	dlg.m_qtBrowserPath->setText ( appConfig.m_QtBrowserPath ); +	dlg.m_radioUseQtextBrowser->setChecked ( appConfig.m_kdeUseQTextBrowser ); +	dlg.m_radioUseKHTMLPart->setChecked ( !appConfig.m_kdeUseQTextBrowser ); +	 +	dlg.m_enableJS->setChecked ( appConfig.m_kdeEnableJS ); +	dlg.m_enablePlugins->setChecked ( appConfig.m_kdeEnablePlugins ); +	dlg.m_enableJava->setChecked ( appConfig.m_kdeEnableJava ); +	dlg.m_enableRefresh->setChecked ( appConfig.m_kdeEnableRefresh ); +	 +	dlg.m_advExternalProgramName->setText( appConfig.m_advExternalEditorPath ); +	dlg.m_advViewSourceExternal->setChecked ( !appConfig.m_advUseInternalEditor ); +	dlg.m_advViewSourceInternal->setChecked ( appConfig.m_advUseInternalEditor ); +	 +	// Search engine +	dlg.m_useSearchEngineInternal->setChecked( appConfig.m_useSearchEngine == KCHMConfig::SEARCH_USE_CHM ); +	dlg.m_useSearchEngineNew->setChecked( appConfig.m_useSearchEngine == KCHMConfig::SEARCH_USE_MINE ); +	 +	// Connect buddies +	dlg.m_labelUseSearchEngineInternal->setBuddy( dlg.m_useSearchEngineInternal ); +	dlg.m_labelUseSearchEngineNew->setBuddy( dlg.m_useSearchEngineNew ); +	 +	if ( dlg.exec() == QDialog::Accepted ) +	{ +		appConfig.m_LoadLatestFileOnStartup = dlg.m_radioOnBeginOpenLast->isChecked(); +		appConfig.m_HistorySize = dlg.m_historySize->value(); +		appConfig.m_HistoryStoreExtra = dlg.m_rememberHistoryInfo->isChecked(); + +		if ( dlg.m_radioExtLinkOpenAlways->isChecked () ) +			appConfig.m_onExternalLinkClick = KCHMConfig::ACTION_ALWAYS_OPEN; +		else if ( dlg.m_radioExtLinkAsk->isChecked () ) +			appConfig.m_onExternalLinkClick = KCHMConfig::ACTION_ASK_USER; +		else +			appConfig.m_onExternalLinkClick = KCHMConfig::ACTION_DONT_OPEN; + +		if ( dlg.m_radioNewChmOpenAlways->isChecked () ) +			appConfig.m_onNewChmClick = KCHMConfig::ACTION_ALWAYS_OPEN; +		else if ( dlg.m_radioNewChmAsk->isChecked () ) +			appConfig.m_onNewChmClick = KCHMConfig::ACTION_ASK_USER; +		else +			appConfig.m_onNewChmClick = KCHMConfig::ACTION_DONT_OPEN; + +		appConfig.m_QtBrowserPath = dlg.m_qtBrowserPath->text(); +		 +		// Check the changes +		bool need_restart = false; +		 +		if ( appConfig.m_kdeEnableJS != dlg.m_enableJS->isChecked() ) +		{ +			need_restart = true; +			appConfig.m_kdeEnableJS = dlg.m_enableJS->isChecked(); +		} +		 +		if ( appConfig.m_kdeEnablePlugins != dlg.m_enablePlugins->isChecked() ) +		{ +			need_restart = true; +			appConfig.m_kdeEnablePlugins = dlg.m_enablePlugins->isChecked(); +		} +		 +		if ( appConfig.m_kdeEnableJava != dlg.m_enableJava->isChecked() ) +		{ +			need_restart = true; +			appConfig.m_kdeEnableJava = dlg.m_enableJava->isChecked(); +		} +		 +		if ( appConfig.m_kdeEnableRefresh != dlg.m_enableRefresh->isChecked() ) +		{ +			need_restart = true; +			appConfig.m_kdeEnableRefresh = dlg.m_enableRefresh->isChecked(); +		} +		 +		if ( appConfig.m_kdeUseQTextBrowser != dlg.m_radioUseQtextBrowser->isChecked() ) +		{ +			need_restart = true; +			appConfig.m_kdeUseQTextBrowser = dlg.m_radioUseQtextBrowser->isChecked(); +		} +		 +		if ( dlg.m_useSearchEngineNew->isChecked()  +		&& appConfig.m_useSearchEngine == KCHMConfig::SEARCH_USE_CHM ) +		{ +			appConfig.m_useSearchEngine = KCHMConfig::SEARCH_USE_MINE; +			m_searchWindow->invalidate(); +		} +		 +		if ( dlg.m_useSearchEngineInternal->isChecked()  +		&& appConfig.m_useSearchEngine == KCHMConfig::SEARCH_USE_MINE ) +		{ +			appConfig.m_useSearchEngine = KCHMConfig::SEARCH_USE_CHM; +			m_searchWindow->invalidate(); +		} +					 +		appConfig.m_advExternalEditorPath = dlg.m_advExternalProgramName->text(); +		appConfig.m_advUseInternalEditor = dlg.m_advViewSourceExternal->isChecked(); +		appConfig.m_advUseInternalEditor = dlg.m_advViewSourceInternal->isChecked(); +		 +		appConfig.save(); +		 +		if ( need_restart ) +			QMessageBox::information(  +					this, +					APP_NAME, +					i18n( "Changing browser view options or search engine used\n" +							"requires restarting the application to take effect." )	); +	} +} + + +void KCHMMainWindow::setupSignals( ) +{ +#if defined(HAVE_SIGACTION) +	struct sigaction sa; +    memset ((char *)&sa, 0, sizeof(sa)); +	sigemptyset (&sa.sa_mask); +	sigaddset (&sa.sa_mask, SIGCHLD); + +#ifdef SA_RESTART +	sa.sa_flags = SA_RESTART; +#endif +	 +	sa.sa_handler = SIG_IGN; +	sigaction (SIGCHLD, &sa, (struct sigaction *)0); +#else /* !HAVE_SIGACTION */ +	signal (SIGCHLD, SIG_IGN); +#endif /* HAVE_SIGACTION */ +} + +void KCHMMainWindow::slotHistoryMenuItemActivated( int item ) +{ +	if ( item < 0 || item >= (signed) appConfig.m_History.size() ) +		qFatal ("KCHMMainWindow::slotHistoryMenuItemActivated: bad history menu id %d", item); +	 +	QString filename = appConfig.m_History[item]; +	 +	// remove it, so it will be added again at the history top, and will not shitf anything. +//	appConfig.m_History.remove ( appConfig.m_History.begin() + item); +	loadChmFile ( filename ); +} + +void KCHMMainWindow::updateHistoryMenu() +{ +	m_menuHistory->clear (); +	 +	for ( int i = appConfig.m_History.size() - 1; i >= 0; i-- ) +		m_menuHistory->insertItem( appConfig.m_History[i], i ); +} + +void KCHMMainWindow::slotActivateContentTab( ) +{ +	if ( m_tabContextPage != -1 )  +		m_tabWidget->setCurrentPage( m_tabContextPage ); +} + +void KCHMMainWindow::slotActivateIndexTab( ) +{ +	if ( m_tabIndexPage != -1 )  +		m_tabWidget->setCurrentPage( m_tabIndexPage ); +} + +void KCHMMainWindow::slotActivateSearchTab( ) +{ +	if ( m_tabSearchPage != -1 )  +		m_tabWidget->setCurrentPage( m_tabSearchPage ); +} + +void KCHMMainWindow::slotActivateBookmarkTab( ) +{ +	m_tabWidget->setCurrentPage( m_tabBookmarkPage ); +} + +void KCHMMainWindow::showOrHideContextWindow( int tabindex ) +{ +	if ( tabindex == -1 ) +	{ +		if ( m_contentsWindow ) +		{ +			m_tabWidget->removePage (m_contentsWindow); +			delete m_contentsWindow; +			m_contentsWindow = 0; +		} +	} +	else +	{ +		if ( !m_contentsWindow ) +		{ +			m_contentsWindow = new KCHMContentsWindow( m_tabWidget ); +			 +			// Handle clicking on m_contentsWindow element +			connect( m_contentsWindow,  +					 SIGNAL( clicked( QListViewItem* ) ),  +					 this,  +					 SLOT( slotOnTreeClicked( QListViewItem* ) ) ); +			 +			connect( m_contentsWindow,  +					 SIGNAL( doubleClicked ( QListViewItem *, const QPoint &, int ) ),  +					 this,  +					 SLOT( slotOnTreeDoubleClicked ( QListViewItem *, const QPoint &, int ) ) ); +			 +			m_tabWidget->insertTab (m_contentsWindow, i18n( "Contents" ), tabindex); +		} +	} +} + +void KCHMMainWindow::showOrHideIndexWindow( int tabindex ) +{ +	// Test whether to show/invalidate the index window +	if ( tabindex == -1 ) +	{ +		if ( m_indexWindow ) +		{ +			m_tabWidget->removePage (m_indexWindow); +			delete m_indexWindow; +			m_indexWindow = 0; +		} +	} +	else +	{ +		if ( !m_indexWindow ) +		{ +			m_indexWindow = new KCHMIndexWindow (m_tabWidget); +			m_tabWidget->insertTab (m_indexWindow, i18n( "Index" ), tabindex); +		} +		else +			m_indexWindow->invalidate(); +	} +} + +void KCHMMainWindow::showOrHideSearchWindow( int tabindex ) +{ +	if ( tabindex == -1 ) +	{ +		if ( m_searchWindow ) +		{ +			m_tabWidget->removePage (m_searchWindow); +			delete m_searchWindow; +			m_searchWindow = 0; +		} +	} +	else +	{ +		if ( !m_searchWindow ) +		{ +			m_searchWindow = new KCHMSearchWindow (m_tabWidget); +			m_tabWidget->insertTab (m_searchWindow, i18n( "Search" ), tabindex); +		} +		else +			m_searchWindow->invalidate(); +	} +} + +void KCHMMainWindow::slotEnableFullScreenMode( bool enable ) +{ +	if ( enable ) +	{ +		if ( !isFullScreen() ) +		{ +			showFullScreen (); +			menuBar()->hide(); +			statusBar()->hide(); +		} +	} +	else +	{ +		if ( isFullScreen() ) +		{ +			showNormal (); +			menuBar()->show(); +			statusBar()->show(); +		} +	} +} + +void KCHMMainWindow::slotShowContentsWindow( bool show ) +{ +	if ( show ) +		m_tabWidget->show(); +	else +		m_tabWidget->hide(); +} + +void KCHMMainWindow::slotToggleFullScreenMode( ) +{ +	slotEnableFullScreenMode( !isFullScreen() ); +} + +void KCHMMainWindow::slotLocateInContentWindow( ) +{ +	// There may be no content tab at all +	if ( !m_contentsWindow  || m_tabContextPage == -1 ) +		return; +	 +	// Activate a content tab +	m_tabWidget->setCurrentPage( m_tabContextPage ); +	 +	if ( m_contentsWindow ) +	{ +		// Open all the tree items to show current item (if needed) +		KCHMIndTocItem * treeitem = m_contentsWindow->getTreeItem( currentBrowser()->getOpenedPage() ); +	 +		if ( treeitem ) +		{ +			KCHMIndTocItem * itemparent = treeitem; +			 +			while ( (itemparent = (KCHMIndTocItem*) itemparent->parent()) != 0 ) +				itemparent->setOpen(true); +			 +			m_contentsWindow->setCurrentItem (treeitem); +			m_contentsWindow->ensureItemVisible (treeitem); +		} +		else +			statusBar()->message( i18n( "Could not locate opened topic in content window"), 2000 ); +	} +} + +void KCHMMainWindow::slotExtractCHM( ) +{ +	QStringList files; +	 +#if defined (USE_KDE) +	QString outdir = KFileDialog::getExistingDirectory ( +			QString::null, +			this, +			i18n("Choose a directory to store CHM content") ); +#else +	QString outdir = QFileDialog::getExistingDirectory ( +			QString::null, +			this, +			0, +			i18n("Choose a directory to store CHM content"), +			TRUE ); +#endif +	 +	if ( outdir.isEmpty() ) +		return; +	 +	outdir += "/"; +	 +	// Enumerate all the files in archive +	if ( !m_chmFile || !m_chmFile->enumerateFiles( &files ) ) +		return; + +	KQProgressModalDialog progress( i18n("Extracting CHM content"), i18n("Extracting files..."), i18n("Abort"), files.size(), this ); +	 +	for ( unsigned int i = 0; i < files.size(); i++ ) +	{ +		progress.setProgress( i ); +		 +		if ( (i % 3) == 0 ) +		{ +			qApp->processEvents(); + +			if ( progress.wasCancelled() ) +				break; +		} + +		// Extract the file +		QByteArray buf; +		 +		if ( m_chmFile->getFileContentAsBinary( &buf, files[i] ) ) +		{ +			// Split filename to get the list of subdirectories +			QStringList dirs = QStringList::split( '/', files[i] ); + +			// Walk through the list of subdirectories, and create them if needed +			// dirlevel is used to detect extra .. and prevent overwriting files +			// outside the directory (like creating the file images/../../../../../etc/passwd +			unsigned int i, dirlevel = 0; +			QStringList dirlist; +				 +			for ( i = 0; i < dirs.size() - 1; i++ ) +			{ +				// Skip .. which lead too far above +				if ( dirs[i] == ".." ) +				{ +					if ( dirlevel > 0 ) +					{ +						dirlevel--; +						dirlist.pop_back(); +					} +				} +				else +				{ +					dirlist.push_back( dirs[i] ); +					 +					QDir dir ( outdir + dirlist.join( "/" ) ); +					if ( !dir.exists() ) +					{ +						if ( !dir.mkdir( dir.path() ) ) +							qWarning( "Could not create subdir %s\n", dir.path().ascii() ); +					} +				} +			} +			 +			QString filename = outdir + dirlist.join( "/" ) + "/" + dirs[i]; +			QFile wf( filename ); +			if ( !wf.open( IO_WriteOnly ) ) +			{ +					qWarning( "Could not write file %s\n", filename.ascii() ); +					continue; +			} +			 +			wf. writeBlock( buf ); +			wf.close(); +		} +		else +			qWarning( "Could not get file %s\n", files[i].ascii() ); +	} +	 +	progress.setProgress( files.size() ); +} + +KCHMViewWindow * KCHMMainWindow::currentBrowser( ) const +{ +	return m_viewWindowMgr->current(); +} + +void KCHMMainWindow::slotOpenPageInNewTab( ) +{ +	openPage( currentBrowser()->getNewTabLink(), OPF_NEW_TAB | OPF_CONTENT_TREE ); +} + +void KCHMMainWindow::slotOpenPageInNewBackgroundTab( ) +{ +	openPage( currentBrowser()->getNewTabLink(), OPF_NEW_TAB | OPF_BACKGROUND ); +} + +void KCHMMainWindow::slotBrowserChanged( KCHMViewWindow * newbrowser ) +{ +	locateInContentTree( newbrowser->getOpenedPage() ); +} + +void KCHMMainWindow::locateInContentTree( const QString & url ) +{ +	if ( !m_contentsWindow ) +		return; +	 +	KCHMIndTocItem * treeitem = m_contentsWindow->getTreeItem( url ); +	 +	if ( treeitem ) +	{ +		KCHMIndTocItem * itemparent = treeitem; +		while ( (itemparent = (KCHMIndTocItem*) itemparent->parent()) != 0 ) +			itemparent->setOpen(true); +			 +		m_contentsWindow->setCurrentItem (treeitem); +		m_contentsWindow->ensureItemVisible (treeitem); +	} +} + +void KCHMMainWindow::slotOnTreeDoubleClicked( QListViewItem * item, const QPoint &, int ) +{ +	// Open/close only existing item which have children +	if ( !item || item->childCount() == 0 ) +		return; +	 +	item->setOpen( !item->isOpen() ); +	item->repaint(); +} + +bool KCHMMainWindow::event( QEvent * e ) +{ +	if ( e->type() == QEvent::User ) +		return handleUserEvent( (KCHMUserEvent*) e ); +	 +	return QWidget::event( e ); +} + +bool KCHMMainWindow::handleUserEvent( const KCHMUserEvent * event ) +{ +	if ( event->m_action == "loadAndOpen" ) +	{ +		if ( event->m_args.size() != 1 && event->m_args.size() != 2 ) +			qFatal("handleUserEvent: event loadAndOpen must receive 1 or 2 args"); +		 +		QString chmfile = event->m_args[0]; +		QString openurl = event->m_args.size() > 1 ? event->m_args[1] : "/"; +				 +		return loadChmFile( chmfile, false ) && openPage( openurl ); +	} +	else if ( event->m_action == "openPage" ) +	{ +		if ( event->m_args.size() != 1 ) +			qFatal("handleUserEvent: event openPage must receive 1 arg"); +		 +		return openPage( event->m_args[0] ); +	} +	else if ( event->m_action == "findInIndex" ) +	{ +		if ( event->m_args.size() != 1 ) +			qFatal( "handleUserEvent: event searchQuery must receive 1 arg" ); +		 +		if ( m_tabIndexPage == -1 ) +			return false; + +		slotActivateIndexTab(); +		m_indexWindow->search( event->m_args[0] ); +		return true; +	} +	else if ( event->m_action == "searchQuery" ) +	{ +		if ( event->m_args.size() != 1 ) +			qFatal( "handleUserEvent: event searchQuery must receive 1 arg" ); +		 +		if ( m_tabSearchPage == -1 ) +			return false; + +		slotActivateSearchTab(); +		m_searchWindow->execSearchQueryInGui( event->m_args[0] ); +		return true; +	} +	else +		qWarning( "Unknown user event received: %s", event->m_action.ascii() ); +	 +	return false; +} + + +#if defined (ENABLE_AUTOTEST_SUPPORT) +void KCHMMainWindow::runAutoTest() +{ +	KCHMIndTocItem * item; + +	switch (m_autoteststate) +	{ +	case STATE_INITIAL: +		if ( m_contentsWindow && !m_useShortAutotest ) +		{ +			m_autotestlistiterator = QListViewItemIterator (m_contentsWindow); +			m_autoteststate = STATE_CONTENTS_OPENNEXTPAGE; +		} +		else +			m_autoteststate = STATE_OPEN_INDEX; +		 +		QTimer::singleShot (500, this, SLOT(runAutoTest()) ); +		break; // allow to finish the initialization sequence +		 +	case STATE_CONTENTS_OPENNEXTPAGE: +		if ( (item = (KCHMIndTocItem *) m_autotestlistiterator.current()) != 0 ) +		{ +			openPage( item->getUrl(), OPF_CONTENT_TREE | OPF_ADD2HISTORY ); +			m_autotestlistiterator++; +		} +		else +			m_autoteststate = STATE_OPEN_INDEX; +		 +		QTimer::singleShot (50, this, SLOT(runAutoTest()) ); +		break; + +	case STATE_OPEN_INDEX: +		if ( m_indexWindow ) +			m_tabWidget->setCurrentPage (1); +		 +		m_autoteststate = STATE_SHUTDOWN; +		QTimer::singleShot (500, this, SLOT(runAutoTest()) ); +		break; + +	case STATE_SHUTDOWN: +		qApp->quit(); +		break; +		 +	default: +		break; +	} +} +#endif /* defined (ENABLE_AUTOTEST_SUPPORT) */ + + +//TODO: KDE: xmlgui +//TODO: Search result highlighting  | 
