lib

KoMainWindow.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
00003    Copyright (C) 2000-2006 David Faure <faure@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "KoMainWindow.h"
00022 #include "KoDocument.h"
00023 #include "KoView.h"
00024 #include "KoFilterManager.h"
00025 #include "KoDocumentInfo.h"
00026 #include "KoDocumentInfoDlg.h"
00027 #include "KoQueryTrader.h"
00028 #include "KoMainWindowIface.h"
00029 #include "KoFrame.h"
00030 #include "KoFileDialog.h"
00031 #include "Koversiondialog.h"
00032 #include "kkbdaccessextensions.h"
00033 #include "KoSpeaker.h"
00034 
00035 #include <kprinter.h>
00036 #include <kdeversion.h>
00037 #include <kstdaction.h>
00038 #include <kapplication.h>
00039 #include <kmessagebox.h>
00040 #include <kstandarddirs.h>
00041 #include <kio/netaccess.h>
00042 #include <kkeydialog.h>
00043 #include <kedittoolbar.h>
00044 #include <kprogress.h>
00045 #include <kpushbutton.h>
00046 #include <kdebug.h>
00047 #include <ktempfile.h>
00048 #include <krecentdocument.h>
00049 #include <kparts/partmanager.h>
00050 #include <kparts/plugin.h>
00051 #include <kparts/event.h>
00052 #include <klocale.h>
00053 #include <kstatusbar.h>
00054 #include <kglobalsettings.h>
00055 #include <ksharedptr.h>
00056 
00057 #include <qobjectlist.h>
00058 
00059 #include <unistd.h>
00060 #include <stdlib.h>
00061 
00062 class KoPartManager : public KParts::PartManager
00063 {
00064 public:
00065   KoPartManager( QWidget * parent, const char * name = 0L )
00066     : KParts::PartManager( parent, name )
00067   {
00068       setSelectionPolicy( KParts::PartManager::TriState );
00069       setAllowNestedParts( true );
00070       setIgnoreScrollBars( true );
00071       // Allow right-click on embedded objects (without activating them)
00072       // But beware: this means right-click on parent, from embedded object,
00073       // doesn't make the parent active first...
00074       setActivationButtonMask( Qt::LeftButton | Qt::MidButton );
00075   }
00076   virtual bool eventFilter( QObject *obj, QEvent *ev )
00077   {
00078     if ( !obj->isWidgetType() || ::qt_cast<KoFrame *>( obj ) )
00079       return false;
00080     return KParts::PartManager::eventFilter( obj, ev );
00081   }
00082 };
00083 
00084 class KoMainWindowPrivate
00085 {
00086 public:
00087   KoMainWindowPrivate()
00088   {
00089     m_rootDoc = 0L;
00090     m_docToOpen = 0L;
00091     m_manager = 0L;
00092     bMainWindowGUIBuilt = false;
00093     m_forQuit=false;
00094     m_splitted=false;
00095     m_activePart = 0L;
00096     m_activeView = 0L;
00097     m_splitter=0L;
00098     m_orientation=0L;
00099     m_removeView=0L;
00100     m_toolbarList.setAutoDelete( true );
00101     m_firstTime=true;
00102     m_progress=0L;
00103     m_paDocInfo = 0;
00104     m_paSave = 0;
00105     m_paSaveAs = 0;
00106     m_paPrint = 0;
00107     m_paPrintPreview = 0;
00108     statusBarLabel = 0L;
00109     m_dcopObject = 0;
00110     m_sendfile = 0;
00111     m_paCloseFile = 0L;
00112     m_reloadfile = 0L;
00113     m_versionsfile = 0L;
00114     m_importFile = 0;
00115     m_exportFile = 0;
00116     m_isImporting = false;
00117     m_isExporting = false;
00118     m_windowSizeDirty = false;
00119     m_lastExportSpecialOutputFlag = 0;
00120 
00121     // TTS accessibility enhancement (only if KDE 3.4 or later and KTTSD daemon is installed.)
00122     if (KoSpeaker::isKttsdInstalled()) {
00123         if (kospeaker)
00124             m_koSpeaker = kospeaker;
00125         else
00126             m_koSpeaker = new KoSpeaker();
00127     } else
00128         m_koSpeaker = 0;
00129   }
00130   ~KoMainWindowPrivate()
00131   {
00132     delete m_dcopObject;
00133   }
00134 
00135   KoDocument *m_rootDoc;
00136   KoDocument *m_docToOpen;
00137   QPtrList<KoView> m_rootViews;
00138   KParts::PartManager *m_manager;
00139 
00140   KParts::Part *m_activePart;
00141   KoView *m_activeView;
00142 
00143   QLabel * statusBarLabel;
00144   KProgress *m_progress;
00145 
00146   QPtrList<KAction> m_splitViewActionList;
00147   // This additional list is needed, because we don't plug
00148   // the first list, when an embedded view gets activated (Werner)
00149   QPtrList<KAction> m_veryHackyActionList;
00150   QSplitter *m_splitter;
00151   KSelectAction *m_orientation;
00152   KAction *m_removeView;
00153   KoMainWindowIface *m_dcopObject;
00154 
00155   QPtrList <KAction> m_toolbarList;
00156 
00157   bool bMainWindowGUIBuilt;
00158   bool m_splitted;
00159   bool m_forQuit;
00160   bool m_firstTime;
00161   bool m_windowSizeDirty;
00162 
00163   KAction *m_paDocInfo;
00164   KAction *m_paSave;
00165   KAction *m_paSaveAs;
00166   KAction *m_paPrint;
00167   KAction *m_paPrintPreview;
00168   KAction *m_sendfile;
00169   KAction *m_paCloseFile;
00170   KAction *m_reloadfile;
00171   KAction *m_versionsfile;
00172   KAction *m_importFile;
00173   KAction *m_exportFile;
00174 
00175   bool m_isImporting;
00176   bool m_isExporting;
00177 
00178   KURL m_lastExportURL;
00179   QCString m_lastExportFormat;
00180   int m_lastExportSpecialOutputFlag;
00181 
00182   KSharedPtr<KoSpeaker> m_koSpeaker;
00183 };
00184 
00185 KoMainWindow::KoMainWindow( KInstance *instance, const char* name )
00186     : KParts::MainWindow( name )
00187 {
00188     setStandardToolBarMenuEnabled(true); // should there be a check for >= 3.1 ?
00189     Q_ASSERT(instance);
00190     d = new KoMainWindowPrivate;
00191 
00192     d->m_manager = new KoPartManager( this );
00193 
00194     connect( d->m_manager, SIGNAL( activePartChanged( KParts::Part * ) ),
00195              this, SLOT( slotActivePartChanged( KParts::Part * ) ) );
00196 
00197     if ( instance )
00198         setInstance( instance, false ); // don't load plugins! we don't want
00199     // the part's plugins with this shell, even though we are using the
00200     // part's instance! (Simon)
00201 
00202     QString doc;
00203     QStringList allFiles = KGlobal::dirs()->findAllResources( "data", "koffice/koffice_shell.rc" );
00204     setXMLFile( findMostRecentXMLFile( allFiles, doc ) );
00205     setLocalXMLFile( locateLocal( "data", "koffice/koffice_shell.rc" ) );
00206 
00207     KStdAction::openNew( this, SLOT( slotFileNew() ), actionCollection(), "file_new" );
00208     KStdAction::open( this, SLOT( slotFileOpen() ), actionCollection(), "file_open" );
00209     m_recent = KStdAction::openRecent( this, SLOT(slotFileOpenRecent(const KURL&)), actionCollection() );
00210     d->m_paSave = KStdAction::save( this, SLOT( slotFileSave() ), actionCollection(), "file_save" );
00211     d->m_paSaveAs = KStdAction::saveAs( this, SLOT( slotFileSaveAs() ), actionCollection(), "file_save_as" );
00212     d->m_paPrint = KStdAction::print( this, SLOT( slotFilePrint() ), actionCollection(), "file_print" );
00213     d->m_paPrintPreview = KStdAction::printPreview( this, SLOT( slotFilePrintPreview() ), actionCollection(), "file_print_preview" );
00214     d->m_sendfile = KStdAction::mail( this, SLOT( slotEmailFile() ), actionCollection(), "file_send_file");
00215 
00216     d->m_paCloseFile = KStdAction::close( this, SLOT( slotFileClose() ), actionCollection(), "file_close" );
00217     KStdAction::quit( this, SLOT( slotFileQuit() ), actionCollection(), "file_quit" );
00218 
00219     d->m_reloadfile = new KAction( i18n( "Reload"), 0,
00220                     this, SLOT( slotReloadFile() ),
00221                     actionCollection(), "file_reload_file");
00222 
00223     d->m_versionsfile = new KAction( i18n( "Versions..."), 0,
00224                     this, SLOT( slotVersionsFile() ),
00225                     actionCollection(), "file_versions_file");
00226 
00227     d->m_importFile = new KAction( i18n( "I&mport..." ), 0, // clashing accel key :(
00228                     this, SLOT( slotImportFile() ),
00229                     actionCollection(), "file_import_file");
00230     d->m_exportFile = new KAction( i18n( "E&xport..." ), 0,
00231                     this, SLOT( slotExportFile() ),
00232                     actionCollection(), "file_export_file");
00233 
00234     /* The following entry opens the document information dialog.  Since the action is named so it
00235         intends to show data this entry should not have a trailing ellipses (...).  */
00236     d->m_paDocInfo = new KAction( i18n( "&Document Information" ), "documentinfo", 0,
00237                         this, SLOT( slotDocumentInfo() ),
00238                         actionCollection(), "file_documentinfo" );
00239 
00240     KStdAction::keyBindings( this, SLOT( slotConfigureKeys() ), actionCollection() );
00241     KStdAction::configureToolbars( this, SLOT( slotConfigureToolbars() ), actionCollection() );
00242 
00243     d->m_paDocInfo->setEnabled( false );
00244     d->m_paSaveAs->setEnabled( false );
00245     d->m_reloadfile->setEnabled( false );
00246     d->m_versionsfile->setEnabled( false );
00247     d->m_importFile->setEnabled( true );  // always enabled like File --> Open
00248     d->m_exportFile->setEnabled( false );
00249     d->m_paSave->setEnabled( false );
00250     d->m_paPrint->setEnabled( false );
00251     d->m_paPrintPreview->setEnabled( false );
00252     d->m_sendfile->setEnabled( false);
00253     d->m_paCloseFile->setEnabled( false);
00254 
00255     d->m_splitter=new QSplitter(Qt::Vertical, this, "mw-splitter");
00256     setCentralWidget( d->m_splitter );
00257     // Keyboard accessibility enhancements.
00258     new KKbdAccessExtensions(this, "mw-panelSizer");
00259     // set up the action "list" for "Close all Views" (hacky :) (Werner)
00260     d->m_veryHackyActionList.append(
00261         new KAction(i18n("&Close All Views"), "fileclose",
00262                     "ctrl+shift+w", this, SLOT(slotCloseAllViews()),
00263                     actionCollection(), "view_closeallviews") );
00264 
00265     // set up the action list for the splitter stuff
00266     d->m_splitViewActionList.append(new KAction(i18n("&Split View"), "view_split", 0,
00267         this, SLOT(slotSplitView()),
00268         actionCollection(), "view_split"));
00269     d->m_removeView=new KAction(i18n("&Remove View"), "view_remove", 0,
00270         this, SLOT(slotRemoveView()),
00271         actionCollection(), "view_rm_splitter");
00272     d->m_splitViewActionList.append(d->m_removeView);
00273     d->m_removeView->setEnabled(false);
00274     d->m_orientation=new KSelectAction(i18n("Splitter &Orientation"), "view_orientation", 0,
00275         this, SLOT(slotSetOrientation()),
00276         actionCollection(), "view_splitter_orientation");
00277     QStringList items;
00278     items << i18n("&Vertical")
00279           << i18n("&Horizontal");
00280     d->m_orientation->setItems(items);
00281     d->m_orientation->setCurrentItem(static_cast<int>(d->m_splitter->orientation()));
00282     d->m_splitViewActionList.append(d->m_orientation);
00283     d->m_splitViewActionList.append(new KActionSeparator(this));
00284 
00285     // Load list of recent files
00286     KConfig * config = instance ? instance->config() : KGlobal::config();
00287     m_recent->loadEntries( config );
00288 
00289     createShellGUI();
00290     d->bMainWindowGUIBuilt = true;
00291 
00292     if ( !initialGeometrySet() )
00293     {
00294         // Default size
00295         const int deskWidth = KGlobalSettings::desktopGeometry(this).width();
00296         if (deskWidth > 1100) // very big desktop ?
00297             resize( 1000, 800 );
00298         if (deskWidth > 850) // big desktop ?
00299             resize( 800, 600 );
00300         else // small (800x600, 640x480) desktop
00301             resize( 600, 400 );
00302     }
00303 
00304     // Saved size
00305     config->setGroup( "MainWindow" );
00306     //kdDebug(30003) << "KoMainWindow::restoreWindowSize" << endl;
00307     restoreWindowSize( config );
00308 }
00309 
00310 KoMainWindow::~KoMainWindow()
00311 {
00312     // The doc and view might still exist (this is the case when closing the window)
00313     if (d->m_rootDoc)
00314         d->m_rootDoc->removeShell(this);
00315 
00316     if (d->m_docToOpen) {
00317       d->m_docToOpen->removeShell(this);
00318       delete d->m_docToOpen;
00319     }
00320 
00321     // safety first ;)
00322     d->m_manager->setActivePart(0);
00323 
00324     if(d->m_rootViews.findRef(d->m_activeView)==-1) {
00325         delete d->m_activeView;
00326         d->m_activeView=0L;
00327     }
00328     d->m_rootViews.setAutoDelete( true );
00329     d->m_rootViews.clear();
00330 
00331     // We have to check if this was a root document.
00332     // -> We aren't allowed to delete the (embedded) document!
00333     // This has to be checked from queryClose, too :)
00334     if ( d->m_rootDoc && d->m_rootDoc->viewCount() == 0 &&
00335          !d->m_rootDoc->isEmbedded())
00336     {
00337         //kdDebug(30003) << "Destructor. No more views, deleting old doc " << d->m_rootDoc << endl;
00338         delete d->m_rootDoc;
00339     }
00340 
00341     delete d->m_manager;
00342     delete d;
00343 }
00344 
00345 void KoMainWindow::setRootDocument( KoDocument *doc )
00346 {
00347   if ( d->m_rootDoc == doc )
00348     return;
00349 
00350   if (d->m_docToOpen && d->m_docToOpen != doc) {
00351     d->m_docToOpen->removeShell(this);
00352     delete d->m_docToOpen;
00353     d->m_docToOpen = 0;
00354   } else {
00355     d->m_docToOpen = 0;
00356   }
00357 
00358   //kdDebug(30003) <<  "KoMainWindow::setRootDocument this = " << this << " doc = " << doc << endl;
00359   QPtrList<KoView> oldRootViews = d->m_rootViews;
00360   d->m_rootViews.clear();
00361   KoDocument *oldRootDoc = d->m_rootDoc;
00362 
00363   if ( oldRootDoc )
00364     oldRootDoc->removeShell( this );
00365 
00366   d->m_rootDoc = doc;
00367 
00368   if ( doc )
00369   {
00370     doc->setSelectable( false );
00371     //d->m_manager->addPart( doc, false ); // done by KoView::setPartManager
00372     d->m_rootViews.append( doc->createView( d->m_splitter, "view" /*not unique, but better than unnamed*/ ) );
00373     d->m_rootViews.current()->setPartManager( d->m_manager );
00374 
00375     d->m_rootViews.current()->show();
00376     // The addShell has been done already if using openURL
00377     if ( !d->m_rootDoc->shells().contains( this ) )
00378         d->m_rootDoc->addShell( this );
00379     d->m_removeView->setEnabled(false);
00380     d->m_orientation->setEnabled(false);
00381   }
00382 
00383   bool enable = d->m_rootDoc != 0 ? true : false;
00384   d->m_paDocInfo->setEnabled( enable );
00385   d->m_paSave->setEnabled( enable );
00386   d->m_paSaveAs->setEnabled( enable );
00387   d->m_importFile->setEnabled( enable );
00388   d->m_exportFile->setEnabled( enable );
00389   d->m_paPrint->setEnabled( enable );
00390   d->m_paPrintPreview->setEnabled( enable );
00391   d->m_sendfile->setEnabled( enable);
00392   d->m_paCloseFile->setEnabled( enable);
00393   updateCaption();
00394 
00395   d->m_manager->setActivePart( d->m_rootDoc, d->m_rootViews.current() );
00396 
00397   oldRootViews.setAutoDelete( true );
00398   oldRootViews.clear();
00399 
00400   if ( oldRootDoc && oldRootDoc->viewCount() == 0 )
00401   {
00402     //kdDebug(30003) << "No more views, deleting old doc " << oldRootDoc << endl;
00403     delete oldRootDoc;
00404   }
00405 }
00406 
00407 void KoMainWindow::updateReloadFileAction(KoDocument *doc)
00408 {
00409     d->m_reloadfile->setEnabled( doc && !doc->url().isEmpty() );
00410 }
00411 
00412 void KoMainWindow::updateVersionsFileAction(KoDocument *doc)
00413 {
00414     //TODO activate it just when we save it in oasis file format
00415     d->m_versionsfile->setEnabled( doc && !doc->url().isEmpty()&&doc->isModified());
00416 }
00417 
00418 
00419 void KoMainWindow::setRootDocumentDirect( KoDocument *doc, const QPtrList<KoView> & views )
00420 {
00421   d->m_rootDoc = doc;
00422   d->m_rootViews = views;
00423   bool enable = d->m_rootDoc != 0 ? true : false;
00424   d->m_paDocInfo->setEnabled( enable );
00425   d->m_paSave->setEnabled( enable );
00426   d->m_paSaveAs->setEnabled( enable );
00427   d->m_exportFile->setEnabled( enable );
00428   d->m_paPrint->setEnabled( enable );
00429   d->m_paPrintPreview->setEnabled( enable );
00430   d->m_sendfile->setEnabled( enable);
00431   d->m_paCloseFile->setEnabled( enable );
00432 }
00433 
00434 void KoMainWindow::addRecentURL( const KURL& url )
00435 {
00436     kdDebug(30003) << "KoMainWindow::addRecentURL url=" << url.prettyURL() << endl;
00437     // Add entry to recent documents list
00438     // (call coming from KoDocument because it must work with cmd line, template dlg, file/open, etc.)
00439     if ( !url.isEmpty() )
00440     {
00441         bool ok = true;
00442         if ( url.isLocalFile() )
00443         {
00444             QString path = url.path( -1 );
00445             QStringList tmpDirs = KGlobal::dirs()->resourceDirs( "tmp" );
00446             for ( QStringList::Iterator it = tmpDirs.begin() ; ok && it != tmpDirs.end() ; ++it )
00447                 if ( path.contains( *it ) )
00448                     ok = false; // it's in the tmp resource
00449             if ( ok )
00450                 KRecentDocument::add(path);
00451         }
00452         else
00453             KRecentDocument::add(url.url(-1), true);
00454 
00455         if ( ok )
00456             m_recent->addURL( url );
00457         saveRecentFiles();
00458     }
00459 }
00460 
00461 void KoMainWindow::saveRecentFiles()
00462 {
00463     // Save list of recent files
00464     KConfig * config = instance() ? instance()->config() : KGlobal::config();
00465     kdDebug(30003) << this << " Saving recent files list into config. instance()=" << instance() << endl;
00466     m_recent->saveEntries( config );
00467     config->sync();
00468     if (KMainWindow::memberList)
00469     {
00470         // Tell all windows to reload their list, after saving
00471         // Doesn't work multi-process, but it's a start
00472         KMainWindow *window = KMainWindow::memberList->first();
00473         for (; window; window = KMainWindow::memberList->next())
00474             static_cast<KoMainWindow *>(window)->reloadRecentFileList();
00475     }
00476 }
00477 
00478 void KoMainWindow::reloadRecentFileList()
00479 {
00480     KConfig * config = instance() ? instance()->config() : KGlobal::config();
00481     m_recent->loadEntries( config );
00482 }
00483 
00484 KoDocument* KoMainWindow::createDoc() const
00485 {
00486     KoDocumentEntry entry = KoDocumentEntry( KoDocument::readNativeService() );
00487     return entry.createDoc();
00488 }
00489 
00490 void KoMainWindow::updateCaption()
00491 {
00492   //kdDebug(30003) << "KoMainWindow::updateCaption()" << endl;
00493   if ( !d->m_rootDoc )
00494     setCaption(QString::null);
00495   else if ( rootDocument()->isCurrent() )
00496   {
00497       QString caption;
00498       // Get caption from document info (title(), in about page)
00499       if ( rootDocument()->documentInfo() )
00500       {
00501           KoDocumentInfoPage * page = rootDocument()->documentInfo()->page( QString::fromLatin1("about") );
00502           if (page)
00503               caption = static_cast<KoDocumentInfoAbout *>(page)->title();
00504       }
00505       const QString url = rootDocument()->url().prettyURL( 0, KURL::StripFileProtocol );
00506       if ( !caption.isEmpty() && !url.isEmpty() )
00507           caption = QString( "%1 - %2" ).arg( caption ).arg( url );
00508       else if ( caption.isEmpty() )
00509           caption = url;
00510 
00511       setCaption( caption, rootDocument()->isModified() );
00512       if ( !rootDocument()->url().fileName(false).isEmpty() )
00513         d->m_paSave->setToolTip( i18n("Save as %1").arg(rootDocument()->url().fileName(false)) );
00514       else
00515         d->m_paSave->setToolTip( i18n("Save") );
00516   }
00517 }
00518 
00519 void KoMainWindow::updateCaption( QString caption, bool mod )
00520 {
00521   //kdDebug(30003)<<"KoMainWindow::updateCaption("<<caption<<","<<mod<<")"<<endl;
00522   setCaption( caption, mod );
00523 }
00524 
00525 KoDocument *KoMainWindow::rootDocument() const
00526 {
00527     return d->m_rootDoc;
00528 }
00529 
00530 KoView *KoMainWindow::rootView() const
00531 {
00532   if(d->m_rootViews.find(d->m_activeView)!=-1)
00533     return d->m_activeView;
00534   return d->m_rootViews.first();
00535 }
00536 
00537 KParts::PartManager *KoMainWindow::partManager()
00538 {
00539   return d->m_manager;
00540 }
00541 
00542 bool KoMainWindow::openDocument( const KURL & url )
00543 {
00544     if ( !KIO::NetAccess::exists(url,true,0) )
00545     {
00546         KMessageBox::error(0L, i18n("The file %1 does not exist.").arg(url.url()) );
00547         m_recent->removeURL(url); //remove the file from the recent-opened-file-list
00548         saveRecentFiles();
00549         return false;
00550     }
00551     return  openDocumentInternal( url );
00552 }
00553 
00554 // (not virtual)
00555 bool KoMainWindow::openDocument( KoDocument *newdoc, const KURL & url )
00556 {
00557     if (!KIO::NetAccess::exists(url,true,0) )
00558     {
00559         if (!newdoc->checkAutoSaveFile())
00560         {
00561           newdoc->initEmpty(); //create an emtpy document
00562         }
00563 
00564         setRootDocument( newdoc );
00565         newdoc->setURL(url);
00566         QString mime = KMimeType::findByURL(url)->name();
00567         if ( mime.isEmpty() || mime == KMimeType::defaultMimeType() )
00568             mime = newdoc->nativeFormatMimeType();
00569         if ( url.isLocalFile() ) // workaround for kde<=3.3 kparts bug, fixed for 3.4
00570             newdoc->setFile(url.path());
00571         newdoc->setMimeTypeAfterLoading( mime );
00572         updateCaption();
00573         return true;
00574     }
00575     return openDocumentInternal( url, newdoc );
00576 }
00577 
00578 // ## If you modify anything here, please check KoShellWindow::openDocumentInternal
00579 bool KoMainWindow::openDocumentInternal( const KURL & url, KoDocument *newdoc )
00580 {
00581     //kdDebug(30003) << "KoMainWindow::openDocument " << url.url() << endl;
00582 
00583     if ( !newdoc )
00584         newdoc = createDoc();
00585     if ( !newdoc )
00586         return false;
00587 
00588     d->m_firstTime=true;
00589     connect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int)));
00590     connect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted()));
00591     connect(newdoc, SIGNAL(canceled( const QString & )), this, SLOT(slotLoadCanceled( const QString & )));
00592     newdoc->addShell( this ); // used by openURL
00593     bool openRet = (!isImporting ()) ? newdoc->openURL(url) : newdoc->import(url);
00594     if(!openRet)
00595     {
00596         newdoc->removeShell(this);
00597         delete newdoc;
00598         return false;
00599     }
00600     updateReloadFileAction(newdoc);
00601     updateVersionsFileAction( newdoc );
00602     return true;
00603 }
00604 
00605 // Separate from openDocument to handle async loading (remote URLs)
00606 void KoMainWindow::slotLoadCompleted()
00607 {
00608     kdDebug(30003) << "KoMainWindow::slotLoadCompleted" << endl;
00609     KoDocument* doc = rootDocument();
00610     KoDocument* newdoc = (KoDocument *)(sender());
00611 
00612     if ( doc && doc->isEmpty() && !doc->isEmbedded() )
00613     {
00614         // Replace current empty document
00615         setRootDocument( newdoc );
00616     }
00617     else if ( doc && !doc->isEmpty() )
00618     {
00619         // Open in a new shell
00620         // (Note : could create the shell first and the doc next for this
00621         // particular case, that would give a better user feedback...)
00622         KoMainWindow *s = new KoMainWindow( newdoc->instance() );
00623         s->show();
00624         newdoc->removeShell( this );
00625         s->setRootDocument( newdoc );
00626     }
00627     else
00628     {
00629         // We had no document, set the new one
00630        setRootDocument( newdoc );
00631     }
00632     disconnect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int)));
00633     disconnect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted()));
00634     disconnect(newdoc, SIGNAL(canceled( const QString & )), this, SLOT(slotLoadCanceled( const QString & )));
00635 }
00636 
00637 void KoMainWindow::slotLoadCanceled( const QString & errMsg )
00638 {
00639     kdDebug(30003) << "KoMainWindow::slotLoadCanceled" << endl;
00640     if ( !errMsg.isEmpty() ) // empty when canceled by user
00641         KMessageBox::error( this, errMsg );
00642     // ... can't delete the document, it's the one who emitted the signal...
00643 
00644     KoDocument* newdoc = (KoDocument *)(sender());
00645     disconnect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int)));
00646     disconnect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted()));
00647     disconnect(newdoc, SIGNAL(canceled( const QString & )), this, SLOT(slotLoadCanceled( const QString & )));
00648 
00649     newdoc->removeShell(this);
00650     delete newdoc;
00651 }
00652 
00653 void KoMainWindow::slotSaveCanceled( const QString &errMsg )
00654 {
00655     kdDebug(30003) << "KoMainWindow::slotSaveCanceled" << endl;
00656     if ( !errMsg.isEmpty() ) // empty when canceled by user
00657         KMessageBox::error( this, errMsg );
00658     slotSaveCompleted();
00659 }
00660 
00661 void KoMainWindow::slotSaveCompleted()
00662 {
00663     kdDebug(30003) << "KoMainWindow::slotSaveCompleted" << endl;
00664     KoDocument* pDoc = (KoDocument *)(sender());
00665     disconnect(pDoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int)));
00666     disconnect(pDoc, SIGNAL(completed()), this, SLOT(slotSaveCompleted()));
00667     disconnect(pDoc, SIGNAL(canceled( const QString & )),
00668                this, SLOT(slotSaveCanceled( const QString & )));
00669 }
00670 
00671 // returns true if we should save, false otherwise.
00672 bool KoMainWindow::exportConfirmation( const QCString &outputFormat )
00673 {
00674     if (!rootDocument()->wantExportConfirmation()) return true;
00675     KMimeType::Ptr mime = KMimeType::mimeType( outputFormat );
00676 
00677     const bool neverHeardOfIt = ( mime->name() == KMimeType::defaultMimeType() );
00678     QString comment = neverHeardOfIt ?
00679                       i18n( "%1 (unknown file type)" ).arg( outputFormat )
00680                       : mime->comment();
00681 
00682     // Warn the user
00683     int ret;
00684     if (!isExporting ()) // File --> Save
00685     {
00686         ret = KMessageBox::warningContinueCancel
00687               (
00688                   this,
00689                   i18n( "<qt>Saving as a %1 may result in some loss of formatting."
00690                         "<p>Do you still want to save in this format?</qt>" )
00691                   .arg( QString( "<b>%1</b>" ).arg( comment ) ), // in case we want to remove the bold later
00692                   i18n( "Confirm Save" ),
00693                   KStdGuiItem::save (),
00694                   "NonNativeSaveConfirmation",
00695                   true
00696                   );
00697     }
00698     else // File --> Export
00699     {
00700         ret = KMessageBox::warningContinueCancel
00701               (
00702                   this,
00703                   i18n( "<qt>Exporting as a %1 may result in some loss of formatting."
00704                         "<p>Do you still want to export to this format?</qt>" )
00705                   .arg( QString( "<b>%1</b>" ).arg( comment ) ), // in case we want to remove the bold later
00706                   i18n( "Confirm Export" ),
00707                   i18n ("Export"),
00708                   "NonNativeExportConfirmation", // different to the one used for Save (above)
00709                   true
00710                   );
00711     }
00712 
00713     return (ret == KMessageBox::Continue);
00714 }
00715 
00716 bool KoMainWindow::saveDocument( bool saveas, bool silent )
00717 {
00718     KoDocument* pDoc = rootDocument();
00719     if(!pDoc)
00720         return true;
00721 
00722     bool reset_url;
00723     if ( pDoc->url().isEmpty() )
00724     {
00725         emit saveDialogShown();
00726         reset_url = true;
00727         saveas = true;
00728     }
00729     else
00730         reset_url = false;
00731 
00732     connect(pDoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int)));
00733     connect(pDoc, SIGNAL(completed()), this, SLOT(slotSaveCompleted()));
00734     connect(pDoc, SIGNAL(canceled( const QString & )),
00735             this, SLOT(slotSaveCanceled( const QString & )));
00736 
00737     KURL oldURL = pDoc->url();
00738     QString oldFile = pDoc->file();
00739     QCString _native_format = pDoc->nativeFormatMimeType();
00740     QCString oldOutputFormat = pDoc->outputMimeType();
00741     int oldSpecialOutputFlag = pDoc->specialOutputFlag();
00742     KURL suggestedURL = pDoc->url();
00743 
00744     QStringList mimeFilter = KoFilterManager::mimeFilter( _native_format, KoFilterManager::Export, pDoc->extraNativeMimeTypes() );
00745     if (mimeFilter.findIndex (oldOutputFormat) < 0 && !isExporting())
00746     {
00747         kdDebug(30003) << "KoMainWindow::saveDocument no export filter for '" << oldOutputFormat << "'" << endl;
00748 
00749         // --- don't setOutputMimeType in case the user cancels the Save As
00750         // dialog and then tries to just plain Save ---
00751 
00752         // suggest a different filename extension (yes, we fortunately don't all live in a world of magic :))
00753         QString suggestedFilename = suggestedURL.fileName ();
00754         if ( !suggestedFilename.isEmpty () ) // ".kwd" looks strange for a name
00755         {
00756             int c = suggestedFilename.findRev ('.');
00757 
00758             KMimeType::Ptr mime = KMimeType::mimeType( _native_format );
00759             QString ext = mime->property( "X-KDE-NativeExtension" ).toString();
00760             if (!ext.isEmpty ())
00761             {
00762                 if (c < 0)
00763                     suggestedFilename += ext;
00764                 else
00765                     suggestedFilename = suggestedFilename.left (c) + ext;
00766             }
00767             else  // current filename extension wrong anyway
00768             {
00769                 if (c > 0)
00770                 {
00771                     // this assumes that a . signifies an extension, not just a .
00772                     suggestedFilename = suggestedFilename.left (c);
00773                 }
00774             }
00775 
00776             suggestedURL.setFileName (suggestedFilename);
00777         }
00778 
00779         // force the user to choose outputMimeType
00780         saveas = true;
00781     }
00782 
00783     bool ret = false;
00784 
00785     if ( pDoc->url().isEmpty() || saveas )
00786     {
00787         // if you're just File/Save As'ing to change filter options you
00788         // don't want to be reminded about overwriting files etc.
00789         bool justChangingFilterOptions = false;
00790 
00791         KoFileDialog *dialog = new KoFileDialog( (isExporting() && !d->m_lastExportURL.isEmpty() )? d->m_lastExportURL.url () : suggestedURL.url (),
00792                                                 QString::null, this, "file dialog", true);
00793 
00794         if (!isExporting())
00795             dialog->setCaption( i18n("Save Document As") );
00796         else
00797             dialog->setCaption( i18n("Export Document As") );
00798 
00799         dialog->setOperationMode( KFileDialog::Saving );
00800         dialog->setSpecialMimeFilter( mimeFilter,
00801                                       isExporting() ? d->m_lastExportFormat : pDoc->mimeType(),
00802                                       isExporting() ? d->m_lastExportSpecialOutputFlag : oldSpecialOutputFlag,
00803                                       _native_format,
00804                                       pDoc->supportedSpecialFormats() );
00805 
00806         KURL newURL;
00807         QCString outputFormat = _native_format;
00808         int specialOutputFlag = 0;
00809         bool bOk;
00810         do {
00811             bOk=true;
00812             if(dialog->exec()==QDialog::Accepted) {
00813                 newURL=dialog->selectedURL();
00814                 outputFormat=dialog->currentMimeFilter().latin1();
00815                 specialOutputFlag = dialog->specialEntrySelected();
00816                 kdDebug(30003) << "KoMainWindow::saveDocument outputFormat = " << outputFormat << endl;
00817 
00818                 if (!isExporting())
00819                     justChangingFilterOptions = (newURL == pDoc->url()) &&
00820                                                 (outputFormat == pDoc->mimeType()) &&
00821                                                 (specialOutputFlag == oldSpecialOutputFlag);
00822                 else
00823                     justChangingFilterOptions = (newURL == d->m_lastExportURL) &&
00824                                                 (outputFormat == d->m_lastExportFormat) &&
00825                                                 (specialOutputFlag == d->m_lastExportSpecialOutputFlag);
00826             }
00827             else
00828             {
00829                 bOk = false;
00830                 break;
00831             }
00832 
00833             if ( newURL.isEmpty() )
00834             {
00835                 bOk = false;
00836                 break;
00837             }
00838 
00839             // this file exists and we are not just clicking "Save As" to change filter options
00840             // => ask for confirmation
00841             if ( KIO::NetAccess::exists( newURL, false /*will write*/, this ) && !justChangingFilterOptions )
00842             {
00843                 bOk = KMessageBox::questionYesNo( this,
00844                                                   i18n("A document with this name already exists.\n"\
00845                                                        "Do you want to overwrite it?"),
00846                                                   i18n("Warning") ) == KMessageBox::Yes;
00847             }
00848         } while ( !bOk );
00849 
00850         delete dialog;
00851 
00852         if (bOk)
00853         {
00854             bool wantToSave = true;
00855 
00856             // don't change this line unless you know what you're doing :)
00857             if (!justChangingFilterOptions || pDoc->confirmNonNativeSave (isExporting ())) {
00858                 if ( !pDoc->isNativeFormat( outputFormat ) )
00859                         wantToSave = exportConfirmation( outputFormat );
00860             }
00861 
00862             if (wantToSave)
00863             {
00864                 //
00865                 // Note:
00866                 // If the user is stupid enough to Export to the current URL,
00867                 // we do _not_ change this operation into a Save As.  Reasons
00868                 // follow:
00869                 //
00870                 // 1. A check like "isExporting() && oldURL == newURL"
00871                 //    doesn't _always_ work on case-insensitive filesystems
00872                 //    and inconsistent behaviour is bad.
00873                 // 2. It is probably not a good idea to change pDoc->mimeType
00874                 //    and friends because the next time the user File/Save's,
00875                 //    (not Save As) they won't be expecting that they are
00876                 //    using their File/Export settings
00877                 //
00878                 // As a bad side-effect of this, the modified flag will not
00879                 // be updated and it is possible that what is currently on
00880                 // their screen is not what is stored on disk (through loss
00881                 // of formatting).  But if you are dumb enough to change
00882                 // mimetype but not the filename, then arguably, _you_ are
00883                 // the "bug" :)
00884                 //
00885                 // - Clarence
00886                 //
00887 
00888 
00889                 pDoc->setOutputMimeType( outputFormat, specialOutputFlag );
00890                 if (!isExporting ())   // Save As
00891                 {
00892                     ret = pDoc->saveAs( newURL );
00893 
00894                     if (ret)
00895                     {
00896                         kdDebug(30003) << "Successful Save As!" << endl;
00897                         addRecentURL( newURL );
00898                     }
00899                     else
00900                     {
00901                         kdDebug(30003) << "Failed Save As!" << endl;
00902                         pDoc->setURL( oldURL ), pDoc->setFile( oldFile );
00903                         pDoc->setOutputMimeType( oldOutputFormat, oldSpecialOutputFlag );
00904                     }
00905                 }
00906                 else    // Export
00907                 {
00908                     ret = pDoc->exp0rt( newURL );
00909 
00910                     if (ret)
00911                     {
00912                         // a few file dialog convenience things
00913                         d->m_lastExportURL = newURL;
00914                         d->m_lastExportFormat = outputFormat;
00915                         d->m_lastExportSpecialOutputFlag = specialOutputFlag;
00916                     }
00917 
00918                     // always restore output format
00919                     pDoc->setOutputMimeType( oldOutputFormat, oldSpecialOutputFlag );
00920                 }
00921 
00922                 if (silent) // don't let the document change the window caption
00923                   pDoc->setTitleModified();
00924             }   // if (wantToSave)  {
00925             else
00926                 ret = false;
00927         }   // if (bOk) {
00928         else
00929             ret = false;
00930     }
00931     else {  // saving
00932         bool needConfirm = pDoc->confirmNonNativeSave( false ) &&
00933                            !pDoc->isNativeFormat( oldOutputFormat );
00934         if (!needConfirm ||
00935                (needConfirm && exportConfirmation( oldOutputFormat /* not so old :) */ ))
00936            )
00937         {
00938             // be sure pDoc has the correct outputMimeType!
00939             ret = pDoc->save();
00940 
00941             if (!ret)
00942             {
00943                 kdDebug(30003) << "Failed Save!" << endl;
00944                 pDoc->setURL( oldURL ), pDoc->setFile( oldFile );
00945             }
00946         }
00947         else
00948             ret = false;
00949     }
00950 
00951 // Now that there's a File/Export option, this is no longer necessary.
00952 // If you continue to use File/Save to export to a foreign format,
00953 // this signals your intention to continue working in a foreign format.
00954 // You have already been warned by the DoNotAskAgain exportConfirmation
00955 // about losing formatting when you first saved so don't set modified
00956 // here or else it will be reported as a bug by some MSOffice user.
00957 // You have been warned!  Do not click DoNotAskAgain!!!
00958 #if 0
00959     if (ret && !isExporting())
00960     {
00961         // When exporting to a non-native format, we don't reset modified.
00962         // This way the user will be reminded to save it again in the native format,
00963         // if he/she doesn't want to lose formatting.
00964         if ( wasModified && pDoc->outputMimeType() != _native_format )
00965             pDoc->setModified( true );
00966     }
00967 #endif
00968 
00969     if (!ret && reset_url)
00970         pDoc->resetURL(); //clean the suggested filename as the save dialog was rejected
00971     return ret;
00972 }
00973 
00974 void KoMainWindow::closeEvent(QCloseEvent *e) {
00975     if(queryClose()) {
00976         saveWindowSettings();
00977         setRootDocument(0L);
00978         KParts::MainWindow::closeEvent(e);
00979     }
00980 }
00981 
00982 void KoMainWindow::saveWindowSettings()
00983 {
00984     if (d->m_windowSizeDirty && rootDocument())
00985     {
00986         // Save window size into the config file of our instance
00987         instance()->config()->setGroup( "MainWindow" );
00988         //kdDebug(30003) << "KoMainWindow::saveWindowSettings" << endl;
00989         saveWindowSize( instance()->config() );
00990         d->m_windowSizeDirty = false;
00991         // Save toolbar position into the config file of the app, under the doc's instance name
00992         //kdDebug(30003) << "KoMainWindow::closeEvent -> saveMainWindowSettings rootdoc's instance=" << rootDocument()->instance()->instanceName() << endl;
00993         saveMainWindowSettings( KGlobal::config(), rootDocument()->instance()->instanceName() );
00994         KGlobal::config()->sync();
00995         resetAutoSaveSettings(); // Don't let KMainWindow override the good stuff we wrote down
00996     }
00997 }
00998 
00999 void KoMainWindow::resizeEvent( QResizeEvent * e )
01000 {
01001     d->m_windowSizeDirty = true;
01002     KParts::MainWindow::resizeEvent( e );
01003 }
01004 
01005 bool KoMainWindow::queryClose()
01006 {
01007     if ( rootDocument() == 0 )
01008         return true;
01009     //kdDebug(30003) << "KoMainWindow::queryClose() viewcount=" << rootDocument()->viewCount()
01010     //               << " shellcount=" << rootDocument()->shellCount() << endl;
01011     if ( !d->m_forQuit && rootDocument()->shellCount() > 1 )
01012         // there are more open, and we are closing just one, so no problem for closing
01013         return true;
01014 
01015     // see DTOR for a descr. of the test
01016     if ( d->m_rootDoc->isEmbedded() )
01017         return true;
01018 
01019     // main doc + internally stored child documents
01020     if ( d->m_rootDoc->isModified() )
01021     {
01022         QString name;
01023         if ( rootDocument()->documentInfo() )
01024         {
01025             name = rootDocument()->documentInfo()->title();
01026         }
01027         if ( name.isEmpty() )
01028             name = rootDocument()->url().fileName();
01029 
01030         if ( name.isEmpty() )
01031             name = i18n( "Untitled" );
01032 
01033         int res = KMessageBox::warningYesNoCancel( this,
01034                         i18n( "<p>The document <b>'%1'</b> has been modified.</p><p>Do you want to save it?</p>" ).arg(name),
01035                         QString::null,
01036                         KStdGuiItem::save(),
01037                         KStdGuiItem::discard());
01038 
01039         switch(res) {
01040             case KMessageBox::Yes : {
01041                 d->m_rootDoc->setDoNotSaveExtDoc(); // external docs are saved later
01042                 bool isNative = ( d->m_rootDoc->outputMimeType() == d->m_rootDoc->nativeFormatMimeType() );
01043                 if (! saveDocument( !isNative ) )
01044                     return false;
01045                 break;
01046             }
01047             case KMessageBox::No :
01048                 rootDocument()->removeAutoSaveFiles();
01049                 rootDocument()->setModified( false ); // Now when queryClose() is called by closeEvent it won't do anything.
01050                 break;
01051             default : // case KMessageBox::Cancel :
01052                 return false;
01053         }
01054     }
01055 
01056     if ( d->m_rootDoc->queryCloseExternalChildren() == KMessageBox::Cancel )
01057     {
01058         return false;
01059     }
01060 
01061     return true;
01062 }
01063 
01064 // Helper method for slotFileNew and slotFileClose
01065 void KoMainWindow::chooseNewDocument( int /*KoDocument::InitDocFlags*/ initDocFlags )
01066 {
01067     KoDocument* doc = rootDocument();
01068     KoDocument *newdoc = createDoc();
01069 
01070     if ( !newdoc )
01071         return;
01072 
01073     //FIXME: This needs to be handled differently
01074     connect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int)));
01075     disconnect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int)));
01076 
01077     if ( ( !doc  && ( initDocFlags == KoDocument::InitDocFileNew ) ) || ( doc && !doc->isEmpty() ) )
01078     {
01079         KoMainWindow *s = new KoMainWindow( newdoc->instance() );
01080         s->show();
01081         newdoc->addShell( s );
01082         newdoc->showStartUpWidget( s, true /*Always show widget*/ );
01083         return;
01084     }
01085 
01086     if( doc ) {
01087         setRootDocument( 0 );
01088         delete d->m_rootDoc;
01089         d->m_rootDoc = 0;
01090     }
01091 
01092     newdoc->addShell( this );
01093     newdoc->showStartUpWidget( this, true /*Always show widget*/ );
01094 }
01095 
01096 void KoMainWindow::slotFileNew()
01097 {
01098     chooseNewDocument( KoDocument::InitDocFileNew );
01099 }
01100 
01101 void KoMainWindow::slotFileOpen()
01102 {
01103     KFileDialog *dialog = new KFileDialog(":OpenDialog", QString::null, this, "file dialog", true);
01104     if (!isImporting())
01105         dialog->setCaption( i18n("Open Document") );
01106     else
01107         dialog->setCaption( i18n("Import Document") );
01108 
01109     // The few lines below need to be kept in sync with KoTemplateChooseDia::setupFileDialog
01110     const QStringList mimeFilter = KoFilterManager::mimeFilter( KoDocument::readNativeFormatMimeType(),
01111                                                                 KoFilterManager::Import,
01112                                                                 KoDocument::readExtraNativeMimeTypes() );
01113     dialog->setMimeFilter( mimeFilter );
01114     if(dialog->exec()!=QDialog::Accepted) {
01115         delete dialog;
01116         return;
01117     }
01118     KURL url( dialog->selectedURL() );
01119     delete dialog;
01120 
01121     if ( url.isEmpty() )
01122         return;
01123 
01124     (void) openDocument( url );
01125 }
01126 
01127 void KoMainWindow::slotFileOpenRecent( const KURL & url )
01128 {
01129     (void) openDocument( url );
01130 }
01131 
01132 void KoMainWindow::slotFileSave()
01133 {
01134     if ( saveDocument() )
01135         emit documentSaved();
01136 }
01137 
01138 void KoMainWindow::slotFileSaveAs()
01139 {
01140     if ( saveDocument( true ) )
01141         emit documentSaved();
01142 }
01143 
01144 void KoMainWindow::slotDocumentInfo()
01145 {
01146   if ( !rootDocument() )
01147     return;
01148 
01149   KoDocumentInfo *docInfo = rootDocument()->documentInfo();
01150 
01151   if ( !docInfo )
01152     return;
01153 
01154   KoDocumentInfoDlg *dlg = new KoDocumentInfoDlg( docInfo, this, "documentInfoDlg" );
01155   if ( dlg->exec() )
01156   {
01157     dlg->save();
01158     rootDocument()->setModified( true );
01159     rootDocument()->setTitleModified();
01160   }
01161 
01162   delete dlg;
01163 }
01164 
01165 void KoMainWindow::slotFileClose()
01166 {
01167     if (queryClose())
01168     {
01169         saveWindowSettings();
01170         setRootDocument( 0 ); // don't delete this shell when deleting the document
01171         delete d->m_rootDoc;
01172         d->m_rootDoc = 0;
01173         chooseNewDocument( KoDocument::InitDocFileClose );
01174     }
01175 }
01176 
01177 void KoMainWindow::slotFileQuit()
01178 {
01179     close();
01180 }
01181 
01182 void KoMainWindow::print(bool quick) {
01183     if ( !rootView() )
01184     {
01185         kdDebug(30003) << "KoMainWindow::slotFilePrint : No root view!" << endl;
01186         return;
01187     }
01188 
01189     KPrinter printer( true /*, QPrinter::HighResolution*/ );
01190     QString title = rootView()->koDocument()->documentInfo()->title();
01191     QString fileName = rootView()->koDocument()->url().fileName();
01192 
01193     // strip off the native extension (I don't want foobar.kwd.ps when printing into a file)
01194     KMimeType::Ptr mime = KMimeType::mimeType( rootView()->koDocument()->outputMimeType() );
01195     if ( mime ) {
01196         QString extension = mime->property( "X-KDE-NativeExtension" ).toString();
01197 
01198         if ( fileName.endsWith( extension ) )
01199             fileName.truncate( fileName.length() - extension.length() );
01200     }
01201 
01202     if ( title.isEmpty() )
01203         title = fileName;
01204     printer.setDocName( title );
01205     printer.setDocFileName( fileName );
01206     printer.setDocDirectory( rootView()->koDocument()->url().directory() );
01207 
01208     // ### TODO: apply global koffice settings here
01209 
01210     rootView()->setupPrinter( printer );
01211 
01212     if ( quick ||  printer.setup( this ) )
01213         rootView()->print( printer );
01214 }
01215 
01216 
01217 void KoMainWindow::slotFilePrint()
01218 {
01219     print(false);
01220 }
01221 
01222 void KoMainWindow::slotFilePrintPreview()
01223 {
01224     if ( !rootView() )
01225     {
01226         kdWarning() << "KoMainWindow::slotFilePrint : No root view!" << endl;
01227         return;
01228     }
01229     KPrinter printer( false );
01230     KTempFile tmpFile;
01231     // The temp file is deleted by KoPrintPreview
01232 
01233     // This line has to be before setupPrinter to let the apps decide what to
01234     // print and what not (if they want to :)
01235     printer.setFromTo( printer.minPage(), printer.maxPage() );
01236     printer.setPreviewOnly( true );
01237     rootView()->setupPrinter( printer );
01238 
01239     QString oldFileName = printer.outputFileName();
01240     printer.setOutputFileName( tmpFile.name() );
01241     int oldNumCopies = printer.numCopies();
01242     printer.setNumCopies( 1 );
01243     // Disable kdeprint's own preview, we'd get two. This shows that KPrinter needs
01244     // a "don't use the previous settings" mode. The current way is really too much of a hack.
01245     QString oldKDEPreview = printer.option( "kde-preview" );
01246     printer.setOption( "kde-preview", "0" );
01247 
01248     rootView()->print(printer);
01249     //KoPrintPreview::preview(this, "KoPrintPreviewDialog", tmpFile.name());
01250 
01251     // Restore previous values
01252     printer.setOutputFileName( oldFileName );
01253     printer.setNumCopies( oldNumCopies );
01254     printer.setOption( "kde-preview", oldKDEPreview );
01255 }
01256 
01257 void KoMainWindow::slotConfigureKeys()
01258 {
01259     guiFactory()->configureShortcuts();
01260 }
01261 
01262 void KoMainWindow::slotConfigureToolbars()
01263 {
01264     if (rootDocument())
01265         saveMainWindowSettings( KGlobal::config(), rootDocument()->instance()->instanceName() );
01266     KEditToolbar edit(factory(), this);
01267     connect(&edit,SIGNAL(newToolbarConfig()),this,SLOT(slotNewToolbarConfig()));
01268     (void) edit.exec();
01269 }
01270 
01271 void KoMainWindow::slotNewToolbarConfig()
01272 {
01273   if (rootDocument())
01274       applyMainWindowSettings( KGlobal::config(), rootDocument()->instance()->instanceName() );
01275   KXMLGUIFactory *factory = guiFactory();
01276 
01277   // Check if there's an active view
01278   if( !d->m_activeView )
01279       return;
01280 
01281   // This gets plugged in even for embedded views
01282   factory->plugActionList(d->m_activeView, "view_closeallviews",
01283                           d->m_veryHackyActionList);
01284 
01285   // This one only for root views
01286   if(d->m_rootViews.findRef(d->m_activeView)!=-1)
01287     factory->plugActionList(d->m_activeView, "view_split",
01288                             d->m_splitViewActionList );
01289   plugActionList( "toolbarlist", d->m_toolbarList );
01290 }
01291 
01292 void KoMainWindow::slotToolbarToggled( bool toggle )
01293 {
01294   //kdDebug(30003) << "KoMainWindow::slotToolbarToggled " << sender()->name() << " toggle=" << true << endl;
01295   // The action (sender) and the toolbar have the same name
01296   KToolBar * bar = toolBar( sender()->name() );
01297   if (bar)
01298   {
01299     if (toggle)
01300       bar->show();
01301     else
01302       bar->hide();
01303 
01304     if (rootDocument())
01305         saveMainWindowSettings( KGlobal::config(), rootDocument()->instance()->instanceName() );
01306   }
01307   else
01308     kdWarning(30003) << "slotToolbarToggled : Toolbar " << sender()->name() << " not found!" << endl;
01309 }
01310 
01311 bool KoMainWindow::toolbarIsVisible(const char *tbName)
01312 {
01313     QWidget *tb = toolBar( tbName);
01314     return !tb->isHidden();
01315 }
01316 
01317 void KoMainWindow::showToolbar( const char * tbName, bool shown )
01318 {
01319     QWidget * tb = toolBar( tbName );
01320     if ( !tb )
01321     {
01322         kdWarning(30003) << "KoMainWindow: toolbar " << tbName << " not found." << endl;
01323         return;
01324     }
01325     if ( shown )
01326         tb->show();
01327     else
01328         tb->hide();
01329 
01330     // Update the action appropriately
01331     QPtrListIterator<KAction> it( d->m_toolbarList );
01332     for ( ; it.current() ; ++it )
01333         if ( !strcmp( it.current()->name(), tbName ) )
01334         {
01335             //kdDebug(30003) << "KoMainWindow::showToolbar setChecked " << shown << endl;
01336             static_cast<KToggleAction *>(it.current())->setChecked( shown );
01337             break;
01338         }
01339 }
01340 
01341 void KoMainWindow::slotSplitView() {
01342     d->m_splitted=true;
01343     d->m_rootViews.append(d->m_rootDoc->createView(d->m_splitter, "splitted-view"));
01344     d->m_rootViews.current()->show();
01345     d->m_rootViews.current()->setPartManager( d->m_manager );
01346     d->m_manager->setActivePart( d->m_rootDoc, d->m_rootViews.current() );
01347     d->m_removeView->setEnabled(true);
01348     d->m_orientation->setEnabled(true);
01349 }
01350 
01351 void KoMainWindow::slotCloseAllViews() {
01352 
01353     // Attention: Very touchy code... you know what you're doing? Goooood :)
01354     d->m_forQuit=true;
01355     if(queryClose()) {
01356         // In case the document is embedded we close all open "extra-shells"
01357         if(d->m_rootDoc && d->m_rootDoc->isEmbedded()) {
01358             hide();
01359             d->m_rootDoc->removeShell(this);
01360             QPtrListIterator<KoMainWindow> it(d->m_rootDoc->shells());
01361             while (it.current()) {
01362                 it.current()->hide();
01363                 delete it.current(); // this updates the lists' current pointer and thus
01364                                      // the iterator (the shell dtor calls removeShell)
01365             d->m_rootDoc=0;
01366             }
01367         }
01368         // not embedded -> destroy the document and all shells/views ;)
01369         else
01370             setRootDocument( 0L );
01371         close();  // close this window (and quit the app if necessary)
01372     }
01373     d->m_forQuit=false;
01374 }
01375 
01376 void KoMainWindow::slotRemoveView() {
01377     KoView *view;
01378     if(d->m_rootViews.findRef(d->m_activeView)!=-1)
01379         view=d->m_rootViews.current();
01380     else
01381         view=d->m_rootViews.first();
01382     view->hide();
01383     if ( !d->m_rootViews.removeRef(view) )
01384         kdWarning() << "view not found in d->m_rootViews!" << endl;
01385 
01386     if(d->m_rootViews.count()==1)
01387     {
01388         d->m_removeView->setEnabled(false);
01389         d->m_orientation->setEnabled(false);
01390     }
01391     // Prevent the view's destroyed() signal from triggering GUI rebuilding (too early)
01392     d->m_manager->setActivePart( 0, 0 );
01393 
01394     delete view;
01395     view=0L;
01396 
01397     d->m_rootViews.first()->setPartManager( d->m_manager );
01398     d->m_manager->setActivePart( d->m_rootDoc, d->m_rootViews.first() );
01399 
01400     if(d->m_rootViews.count()==1)
01401         d->m_splitted=false;
01402 }
01403 
01404 void KoMainWindow::slotSetOrientation() {
01405     d->m_splitter->setOrientation(static_cast<Qt::Orientation>
01406                                   (d->m_orientation->currentItem()));
01407 }
01408 
01409 void KoMainWindow::slotProgress(int value) {
01410     //kdDebug(30003) << "KoMainWindow::slotProgress " << value << endl;
01411     if(value==-1) {
01412         if ( d->m_progress )
01413         {
01414             statusBar()->removeWidget(d->m_progress);
01415             delete d->m_progress;
01416             d->m_progress=0L;
01417         }
01418         d->m_firstTime=true;
01419         return;
01420     }
01421     if(d->m_firstTime)
01422     {
01423         // The statusbar might not even be created yet.
01424         // So check for that first, and create it if necessary
01425         QObjectList *l = queryList( "QStatusBar" );
01426         if ( !l || !l->first() ) {
01427             statusBar()->show();
01428             QApplication::sendPostedEvents( this, QEvent::ChildInserted );
01429             setUpLayout();
01430         }
01431         delete l;
01432 
01433         if ( d->m_progress )
01434         {
01435             statusBar()->removeWidget(d->m_progress);
01436             delete d->m_progress;
01437             d->m_progress=0L;
01438         }
01439         statusBar()->setMaximumHeight(statusBar()->height());
01440         d->m_progress=new KProgress(statusBar());
01441         //d->m_progress->setMaximumHeight(statusBar()->height());
01442         statusBar()->addWidget( d->m_progress, 0, true );
01443         d->m_progress->show();
01444         d->m_firstTime=false;
01445     }
01446     d->m_progress->setProgress(value);
01447     kapp->processEvents();
01448 }
01449 
01450 
01451 void KoMainWindow::slotActivePartChanged( KParts::Part *newPart )
01452 {
01453 
01454   // This looks very much like KParts::MainWindow::createGUI, but we have
01455   // to reimplement it because it works with an active part, whereas we work
01456   // with an active view _and_ an active part, depending for what.
01457   // Both are KXMLGUIClients, but e.g. the plugin query needs a QObject.
01458   //kdDebug(30003) <<  "KoMainWindow::slotActivePartChanged( Part * newPart) newPart = " << newPart << endl;
01459   //kdDebug(30003) <<  "current active part is " << d->m_activePart << endl;
01460 
01461   if ( d->m_activePart && d->m_activePart == newPart && !d->m_splitted )
01462   {
01463     //kdDebug(30003) << "no need to change the GUI" << endl;
01464     return;
01465   }
01466 
01467   KXMLGUIFactory *factory = guiFactory();
01468 
01469   setUpdatesEnabled( false );
01470 
01471   if ( d->m_activeView )
01472   {
01473     KParts::GUIActivateEvent ev( false );
01474     QApplication::sendEvent( d->m_activePart, &ev );
01475     QApplication::sendEvent( d->m_activeView, &ev );
01476 
01477 
01478     factory->removeClient( d->m_activeView );
01479 
01480     unplugActionList( "toolbarlist" );
01481     d->m_toolbarList.clear(); // deletes the actions
01482   }
01483 
01484   if ( !d->bMainWindowGUIBuilt )
01485   {
01486     // Load mainwindow plugins
01487     KParts::Plugin::loadPlugins( this, this, instance(), true );
01488     createShellGUI();
01489   }
01490 
01491   if ( newPart && d->m_manager->activeWidget() && d->m_manager->activeWidget()->inherits( "KoView" ) )
01492   {
01493     d->m_activeView = (KoView *)d->m_manager->activeWidget();
01494     d->m_activePart = newPart;
01495     //kdDebug(30003) <<  "new active part is " << d->m_activePart << endl;
01496 
01497     factory->addClient( d->m_activeView );
01498 
01499 
01500     // This gets plugged in even for embedded views
01501     factory->plugActionList(d->m_activeView, "view_closeallviews",
01502                             d->m_veryHackyActionList);
01503     // This one only for root views
01504     if(d->m_rootViews.findRef(d->m_activeView)!=-1)
01505         factory->plugActionList(d->m_activeView, "view_split", d->m_splitViewActionList );
01506 
01507     // Position and show toolbars according to user's preference
01508     setAutoSaveSettings( newPart->instance()->instanceName(), false );
01509 
01510     // Create and plug toolbar list for Settings menu
01511     //QPtrListIterator<KToolBar> it = toolBarIterator();
01512     QPtrList<QWidget> toolBarList = factory->containers( "ToolBar" );
01513     QPtrListIterator<QWidget> it( toolBarList );
01514     for ( ; it.current() ; ++it )
01515     {
01516       if ( it.current()->inherits("KToolBar") )
01517       {
01518           KToolBar * tb = static_cast<KToolBar *>(it.current());
01519           KToggleAction * act = new KToggleAction( i18n("Show %1 Toolbar").arg( tb->text() ), 0,
01520                                                actionCollection(), tb->name() );
01521       act->setCheckedState(i18n("Hide %1 Toolbar").arg( tb->text() ));
01522       connect( act, SIGNAL( toggled( bool ) ), this, SLOT( slotToolbarToggled( bool ) ) );
01523           act->setChecked ( !tb->isHidden() );
01524           d->m_toolbarList.append( act );
01525       }
01526       else
01527           kdWarning(30003) << "Toolbar list contains a " << it.current()->className() << " which is not a toolbar!" << endl;
01528     }
01529     plugActionList( "toolbarlist", d->m_toolbarList );
01530 
01531     // Send the GUIActivateEvent only now, since it might show/hide toolbars too
01532     // (and this has priority over applyMainWindowSettings)
01533     KParts::GUIActivateEvent ev( true );
01534     QApplication::sendEvent( d->m_activePart, &ev );
01535     QApplication::sendEvent( d->m_activeView, &ev );
01536   }
01537   else
01538   {
01539     d->m_activeView = 0L;
01540     d->m_activePart = 0L;
01541   }
01542   setUpdatesEnabled( true );
01543 }
01544 
01545 QLabel * KoMainWindow::statusBarLabel()
01546 {
01547   if ( !d->statusBarLabel )
01548   {
01549     d->statusBarLabel = new QLabel( statusBar() );
01550     statusBar()->addWidget( d->statusBarLabel, 1, true );
01551   }
01552   return d->statusBarLabel;
01553 }
01554 
01555 void KoMainWindow::setMaxRecentItems(uint _number)
01556 {
01557         m_recent->setMaxItems( _number );
01558 }
01559 
01560 DCOPObject * KoMainWindow::dcopObject()
01561 {
01562     if ( !d->m_dcopObject )
01563     {
01564         d->m_dcopObject = new KoMainWindowIface( this );
01565     }
01566 
01567     return d->m_dcopObject;
01568 }
01569 
01570 void KoMainWindow::slotEmailFile()
01571 {
01572     if (!rootDocument())
01573         return;
01574 
01575     // Subject = Document file name
01576     // Attachment = The current file
01577     // Message Body = The current document in HTML export? <-- This may be an option.
01578     QString theSubject;
01579     QStringList urls;
01580     QString fileURL;
01581     if (rootDocument()->url ().isEmpty () ||
01582         rootDocument()->isModified())
01583     {
01584         //Save the file as a temporary file
01585         bool const tmp_modified = rootDocument()->isModified();
01586         KURL const tmp_url = rootDocument()->url();
01587         QCString const tmp_mimetype = rootDocument()->outputMimeType();
01588         KTempFile tmpfile; //TODO: The temorary file should be deleted when the mail program is closed
01589         KURL u;
01590         u.setPath(tmpfile.name());
01591         rootDocument()->setURL(u);
01592         rootDocument()->setModified(true);
01593         rootDocument()->setOutputMimeType(rootDocument()->nativeFormatMimeType());
01594 
01595         saveDocument(false, true);
01596 
01597         fileURL = tmpfile.name();
01598         theSubject = i18n("Document");
01599         urls.append( fileURL );
01600 
01601         rootDocument()->setURL(tmp_url);
01602         rootDocument()->setModified(tmp_modified);
01603         rootDocument()->setOutputMimeType(tmp_mimetype);
01604     }
01605     else
01606     {
01607         fileURL = rootDocument()->url().url();
01608         theSubject = i18n("Document - %1").arg(rootDocument()->url().fileName(false));
01609         urls.append( fileURL );
01610     }
01611 
01612     kdDebug(30003) << "(" << fileURL <<")" << endl;
01613 
01614     if (!fileURL.isEmpty())
01615     {
01616         kapp->invokeMailer(QString::null, QString::null, QString::null, theSubject,
01617                             QString::null, //body
01618                             QString::null,
01619                             urls); // attachments
01620     }
01621 }
01622 
01623 void KoMainWindow::slotVersionsFile()
01624 {
01625     KoVersionDialog *dlg = new KoVersionDialog(  this );
01626     dlg->exec();
01627     delete dlg;
01628 }
01629 
01630 void KoMainWindow::slotReloadFile()
01631 {
01632     KoDocument* pDoc = rootDocument();
01633     if(!pDoc || pDoc->url().isEmpty() || !pDoc->isModified())
01634         return;
01635 
01636     bool bOk = KMessageBox::questionYesNo( this,
01637                                       i18n("You will lose all your changes!\n"
01638                                            "Do you want to continue?"),
01639                                       i18n("Warning") ) == KMessageBox::Yes;
01640     if ( !bOk )
01641         return;
01642 
01643     KURL url = pDoc->url();
01644     if ( pDoc && !pDoc->isEmpty() )
01645     {
01646         setRootDocument( 0L ); // don't delete this shell when deleting the document
01647         delete d->m_rootDoc;
01648         d->m_rootDoc = 0L;
01649     }
01650     openDocument( url );
01651     return;
01652 
01653 }
01654 
01655 void KoMainWindow::slotImportFile()
01656 {
01657     kdDebug(30003) << "slotImportFile()" << endl;
01658 
01659     d->m_isImporting = true;
01660     slotFileOpen();
01661     d->m_isImporting = false;
01662 }
01663 
01664 void KoMainWindow::slotExportFile()
01665 {
01666     kdDebug(30003) << "slotExportFile()" << endl;
01667 
01668     d->m_isExporting = true;
01669     slotFileSaveAs();
01670     d->m_isExporting = false;
01671 }
01672 
01673 bool KoMainWindow::isImporting() const
01674 {
01675     return d->m_isImporting;
01676 }
01677 
01678 bool KoMainWindow::isExporting() const
01679 {
01680     return d->m_isExporting;
01681 }
01682 
01683 void KoMainWindow::setDocToOpen( KoDocument *doc )
01684 {
01685   d->m_docToOpen = doc;
01686 }
01687 
01688 #include <KoMainWindow.moc>
KDE Home | KDE Accessibility Home | Description of Access Keys