lib Library API Documentation

koMainWindow.cc

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