/*************************************************************************** * 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 #include #include #include #include #include #include "kde-qt.h" #include #include #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 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 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 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 = 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 = tqApp->argv()[i]; } #endif if ( !filename.isEmpty() ) { if ( !loadChmFile( TQString::fromLocal8Bit( 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 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_radioUseKHTMLPart->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