F:/KPlato/koffice/libs/kofficecore/KoMainWindow.cpp

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

Généré le Wed Nov 22 23:41:03 2006 pour KPlato par  doxygen 1.5.1-p1