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