You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kchmviewer/src/kchmmainwindow.cpp

1299 lines
36 KiB

/***************************************************************************
* 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 "tde-tqt.h"
#include <tqaccel.h>
#include <tqevent.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_impl.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 TQSplitter(this);
m_tabWidget = new KTQTabWidget( 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 );
TQValueList<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) */
TQAccel * accel = new TQAccel( this );
accel->connectItem ( accel->insertItem ( Key_F11 ), this, TQT_SLOT ( slotToggleFullScreenMode() ) );
accel->connectItem ( accel->insertItem ( CTRL + Key_1), this, TQT_SLOT ( slotActivateContentTab() ) );
accel->connectItem ( accel->insertItem ( CTRL + Key_2), this, TQT_SLOT ( slotActivateIndexTab() ) );
accel->connectItem ( accel->insertItem ( CTRL + Key_3), this, TQT_SLOT ( slotActivateSearchTab() ) );
accel->connectItem ( accel->insertItem ( CTRL + Key_4), this, TQT_SLOT ( slotActivateBookmarkTab() ) );
accel->connectItem ( accel->insertItem ( Key_F3 ), m_searchToolbar, TQT_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)
TQString fn = KFileDialog::getOpenFileName( appConfig.m_lastOpenedDir, i18n("*.chm|Compressed Help Manual (*.chm)"), this);
#else
TQString fn = TQFileDialog::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 TQString &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
TQDir qd;
qd.setPath (fileName);
m_chmFilename = qd.absPath();
// TQt's 'dirname' does not work well
TQFileInfo 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
TQValueList<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
{
TQMessageBox mbox(
i18n("%1 - failed to load the chm file") . arg(APP_NAME),
i18n("Unable to load the chm file %1") . arg(fileName),
TQMessageBox::Critical,
TQMessageBox::Ok,
TQMessageBox::NoButton,
TQMessageBox::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()
{
TQString caption = i18n( "About %1" ) . arg(APP_NAME);
TQString text = m_aboutDlgMenuText;
// It is quite funny that the argument order differs
#if defined (USE_KDE)
KMessageBox::about( this, text, caption );
#else
TQMessageBox::about( this, caption, text );
#endif
}
void KCHMMainWindow::slotAboutQtMenuItemActivated()
{
TQMessageBox::aboutTQt( this, APP_NAME);
}
void KCHMMainWindow::refreshCurrentBrowser( )
{
TQString 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 = (TQString) APP_NAME + " - " + title;
#endif
setCaption ( title );
currentBrowser()->invalidate();
if ( m_contentsWindow )
m_contentsWindow->refillTableOfContents();
}
void KCHMMainWindow::slotOnTreeClicked( TQListViewItem * item )
{
bool unused;
if ( !item )
return;
KCHMIndTocItem * treeitem = (KCHMIndTocItem*) item;
slotLinkClicked( treeitem->getUrl(), unused );
}
void KCHMMainWindow::slotLinkClicked ( const TQString & 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 TQString & srcurl, unsigned int flags )
{
TQString 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 ( TQMessageBox::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"),
TQString(), 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_TQtBrowserPath, url );
#endif
}
break;
}
return false; // do not change the current page.
}
// Filter the URLs which do not need to be opened at all by TQt version
if ( LCHMUrlFactory::isJavascriptURL (url) )
{
TQMessageBox::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 ( TQMessageBox::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" ),
TQString(), 0, 1 ) )
return false;
// Because chm file always contain relative link, and current filename is not changed,
// we need to form a new path
TQFileInfo qfi( m_chmFilename );
TQString newfilename = qfi.dirPath(true) + "/" + p1;
TQStringList event_args;
event_args.push_back( newfilename );
event_args.push_back( p2 ); // url
tqApp->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();
TQString 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( TQShowEvent * )
{
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
TQToolBar * toolbar = new TQToolBar(this);
toolbar->setLabel( i18n( "File Operations") );
TQPixmap iconFileOpen (*gIconStorage.getToolbarPixmap(KCHMIconStorage::fileopen));
TQToolButton * fileOpen = new TQToolButton (iconFileOpen,
i18n( "Open File" ),
TQString(),
this,
TQT_SLOT( slotOpenMenuItemActivated() ),
toolbar);
TQString fileOpenText = i18n( "Click this button to open an existing chm file." );
TQWhatsThis::add( fileOpen, fileOpenText );
TQPixmap iconFilePrint (*gIconStorage.getToolbarPixmap(KCHMIconStorage::print));
TQToolButton * filePrint = new TQToolButton (iconFilePrint,
i18n( "Print File" ),
TQString(),
this,
TQT_SLOT( slotPrintMenuItemActivated() ),
toolbar);
TQString filePrintText = i18n( "Click this button to print the current page");
TQWhatsThis::add( filePrint, filePrintText );
// Setup the menu
KTQPopupMenu * file = new KTQPopupMenu( this );
menuBar()->insertItem( i18n( "&File"), file );
int id;
id = file->insertItem ( iconFileOpen, i18n( "&Open..."), this, TQT_SLOT( slotOpenMenuItemActivated() ), CTRL+Key_O );
file->TQMenuData::setWhatsThis( id, fileOpenText );
id = file->insertItem( iconFilePrint, i18n( "&Print..."), this, TQT_SLOT( slotPrintMenuItemActivated() ), CTRL+Key_P );
file->TQMenuData::setWhatsThis( id, filePrintText );
file->insertSeparator();
id = file->insertItem ( i18n( "E&xtract CHM content..."), this, TQT_SLOT( slotExtractCHM() ) );
file->TQMenuData::setWhatsThis( id, i18n( "Click this button to extract the whole CHM file content into a specific directory") );
file->insertSeparator();
m_menuHistory = new KTQPopupMenu( file );
connect ( m_menuHistory, TQT_SIGNAL( activated(int) ), this, TQT_SLOT ( slotHistoryMenuItemActivated(int) ));
file->insertItem( i18n( "&Recent files"), m_menuHistory );
file->insertSeparator();
file->insertItem( i18n( "&Quit"), tqApp, TQT_SLOT( closeAllWindows() ), CTRL+Key_Q );
KTQPopupMenu * menu_edit = new KTQPopupMenu( this );
menuBar()->insertItem( i18n( "&Edit"), menu_edit );
menu_edit->insertItem ( i18n( "&Copy"), this, TQT_SLOT( slotBrowserCopy()), CTRL+Key_C );
menu_edit->insertItem ( i18n( "&Select all"), this, TQT_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 );
KTQPopupMenu * settings = new KTQPopupMenu( this );
menuBar()->insertItem( i18n( "&Settings"), settings );
settings->insertItem( i18n( "&Change settings..."), this, TQT_SLOT( slotChangeSettingsMenuItemActivated() ));
#if defined(USE_KDE)
TQPopupMenu *help = helpMenu( m_aboutDlgMenuText );
#else
KTQPopupMenu * help = new KTQPopupMenu( this );
help->insertItem( i18n( "&About"), this, TQT_SLOT( slotAboutMenuItemActivated() ), Key_F1 );
help->insertItem( i18n( "About &TQt"), this, TQT_SLOT( slotAboutQtMenuItemActivated() ));
help->insertSeparator();
help->insertItem( i18n( "What's &This"), this, TQT_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.
TQString 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 ( TQCloseEvent * e )
{
// Save the settings if we have something opened
if ( m_chmFile )
{
closeChmFile( );
delete m_chmFile;
m_chmFile = 0;
}
TQMainWindow::closeEvent ( e );
}
bool KCHMMainWindow::parseCmdLineArgs( )
{
TQString filename = TQString(), search_query = TQString();
TQString search_index = TQString(), search_bookmark = TQString();
bool do_autotest = false;
#if defined (USE_KDE)
TDECmdLineArgs *args = TDECmdLineArgs::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 = TQString::fromLocal8Bit(args->arg(0));
#else
// argv[0] in TQt is still a program name
for ( int i = 1; i < tqApp->argc(); i++ )
{
if ( !strcmp (tqApp->argv()[i], "--autotestmode") )
do_autotest = m_useShortAutotest = true;
else if ( !strcmp (tqApp->argv()[i], "--shortautotestmode") )
do_autotest = true;
else if ( !strcmp (tqApp->argv()[i], "--search") )
search_query = tqApp->argv()[++i];
else if ( !strcmp (tqApp->argv()[i], "--sindex") )
search_index = tqApp->argv()[++i];
else if ( !strcmp (tqApp->argv()[i], "-h") || !strcmp (tqApp->argv()[i], "--help") )
{
fprintf (stderr, "Usage: %s [chmfile]\n", tqApp->argv()[0]);
exit (1);
}
else
filename = TQSTring::fromLocal8Bit(tqApp->argv()[i]);
}
#endif
if ( !filename.isEmpty() )
{
if ( !loadChmFile( filename ) )
return true; // skip the latest checks, but do not exit from the program
if ( !search_index.isEmpty() )
{
TQStringList event_args;
event_args.push_back( search_index );
tqApp->postEvent( this, new KCHMUserEvent( "findInIndex", event_args ) );
}
if ( !search_query.isEmpty() )
{
TQStringList event_args;
event_args.push_back( search_query );
tqApp->postEvent( this, new KCHMUserEvent( "searchQuery", event_args ) );
}
if ( do_autotest )
{
#if defined (ENABLE_AUTOTEST_SUPPORT)
if ( filename.isEmpty() )
tqFatal ("Could not use Auto Test mode without a chm file!");
m_autoteststate = STATE_INITIAL;
showMinimized ();
runAutoTest();
#else
tqFatal ("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_impl 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_TQtBrowserPath );
dlg.m_radioUseQtextBrowser->setChecked ( appConfig.m_kdeUseTQTextBrowser );
dlg.m_radioUseTDEHTMLPart->setChecked ( !appConfig.m_kdeUseTQTextBrowser );
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() == TQDialog::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_TQtBrowserPath = 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_kdeUseTQTextBrowser != dlg.m_radioUseQtextBrowser->isChecked() )
{
need_restart = true;
appConfig.m_kdeUseTQTextBrowser = 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 )
TQMessageBox::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() )
tqFatal ("KCHMMainWindow::slotHistoryMenuItemActivated: bad history menu id %d", item);
TQString 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,
TQT_SIGNAL( clicked( TQListViewItem* ) ),
this,
TQT_SLOT( slotOnTreeClicked( TQListViewItem* ) ) );
connect( m_contentsWindow,
TQT_SIGNAL( doubleClicked ( TQListViewItem *, const TQPoint &, int ) ),
this,
TQT_SLOT( slotOnTreeDoubleClicked ( TQListViewItem *, const TQPoint &, 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( )
{
TQStringList files;
#if defined (USE_KDE)
TQString outdir = KFileDialog::getExistingDirectory (
TQString(),
this,
i18n("Choose a directory to store CHM content") );
#else
TQString outdir = TQFileDialog::getExistingDirectory (
TQString(),
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;
KTQProgressModalDialog 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 )
{
tqApp->processEvents();
if ( progress.wasCancelled() )
break;
}
// Extract the file
TQByteArray buf;
if ( m_chmFile->getFileContentAsBinary( &buf, files[i] ) )
{
// Split filename to get the list of subdirectories
TQStringList dirs = TQStringList::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;
TQStringList 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] );
TQDir dir ( outdir + dirlist.join( "/" ) );
if ( !dir.exists() )
{
if ( !dir.mkdir( dir.path() ) )
tqWarning( "Could not create subdir %s\n", dir.path().ascii() );
}
}
}
TQString filename = outdir + dirlist.join( "/" ) + "/" + dirs[i];
TQFile wf( filename );
if ( !wf.open( IO_WriteOnly ) )
{
tqWarning( "Could not write file %s\n", filename.ascii() );
continue;
}
wf. writeBlock( buf );
wf.close();
}
else
tqWarning( "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 TQString & 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( TQListViewItem * item, const TQPoint &, int )
{
// Open/close only existing item which have children
if ( !item || item->childCount() == 0 )
return;
item->setOpen( !item->isOpen() );
item->repaint();
}
bool KCHMMainWindow::event( TQEvent * e )
{
if ( e->type() == TQEvent::User )
return handleUserEvent( (KCHMUserEvent*) e );
return TQWidget::event( e );
}
bool KCHMMainWindow::handleUserEvent( const KCHMUserEvent * event )
{
if ( event->m_action == "loadAndOpen" )
{
if ( event->m_args.size() != 1 && event->m_args.size() != 2 )
tqFatal("handleUserEvent: event loadAndOpen must receive 1 or 2 args");
TQString chmfile = event->m_args[0];
TQString 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 )
tqFatal("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 )
tqFatal( "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 )
tqFatal( "handleUserEvent: event searchQuery must receive 1 arg" );
if ( m_tabSearchPage == -1 )
return false;
slotActivateSearchTab();
m_searchWindow->execSearchQueryInGui( event->m_args[0] );
return true;
}
else
tqWarning( "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 = TQListViewItemIterator (m_contentsWindow);
m_autoteststate = STATE_CONTENTS_OPENNEXTPAGE;
}
else
m_autoteststate = STATE_OPEN_INDEX;
TQTimer::singleShot (500, this, TQT_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;
TQTimer::singleShot (50, this, TQT_SLOT(runAutoTest()) );
break;
case STATE_OPEN_INDEX:
if ( m_indexWindow )
m_tabWidget->setCurrentPage (1);
m_autoteststate = STATE_SHUTDOWN;
TQTimer::singleShot (500, this, TQT_SLOT(runAutoTest()) );
break;
case STATE_SHUTDOWN:
tqApp->quit();
break;
default:
break;
}
}
#endif /* defined (ENABLE_AUTOTEST_SUPPORT) */
//TODO: KDE: xmlgui
//TODO: Search result highlighting