You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1702 lines
58 KiB
1702 lines
58 KiB
/* This file is part of the KDE project
|
|
Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
|
|
Copyright (C) 2000-2006 David Faure <faure@kde.org>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "KoMainWindow.h"
|
|
#include "KoDocument.h"
|
|
#include "KoView.h"
|
|
#include "KoFilterManager.h"
|
|
#include "KoDocumentInfo.h"
|
|
#include "KoDocumentInfoDlg.h"
|
|
#include "KoQueryTrader.h"
|
|
#include "KoMainWindowIface.h"
|
|
#include "KoFrame.h"
|
|
#include "KoFileDialog.h"
|
|
#include "Koversiondialog.h"
|
|
#include "kkbdaccessextensions.h"
|
|
#include "KoSpeaker.h"
|
|
|
|
#include <tdeaboutdata.h>
|
|
#include <kprinter.h>
|
|
#include <tdeversion.h>
|
|
#include <kstdaction.h>
|
|
#include <tdeapplication.h>
|
|
#include <tdemessagebox.h>
|
|
#include <kstandarddirs.h>
|
|
#include <tdeio/netaccess.h>
|
|
#include <kkeydialog.h>
|
|
#include <kedittoolbar.h>
|
|
#include <kprogress.h>
|
|
#include <kpushbutton.h>
|
|
#include <kdebug.h>
|
|
#include <tdetempfile.h>
|
|
#include <tderecentdocument.h>
|
|
#include <tdeparts/partmanager.h>
|
|
#include <tdeparts/plugin.h>
|
|
#include <tdeparts/event.h>
|
|
#include <tdelocale.h>
|
|
#include <kstatusbar.h>
|
|
#include <tdeglobalsettings.h>
|
|
#include <ksharedptr.h>
|
|
|
|
#include <tqobjectlist.h>
|
|
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
|
|
class KoPartManager : public KParts::PartManager
|
|
{
|
|
public:
|
|
KoPartManager( TQWidget * parent, const char * name = 0L )
|
|
: KParts::PartManager( parent, name )
|
|
{
|
|
setSelectionPolicy( KParts::PartManager::TriState );
|
|
setAllowNestedParts( true );
|
|
setIgnoreScrollBars( true );
|
|
// Allow right-click on embedded objects (without activating them)
|
|
// But beware: this means right-click on parent, from embedded object,
|
|
// doesn't make the parent active first...
|
|
setActivationButtonMask( Qt::LeftButton | Qt::MidButton );
|
|
}
|
|
virtual bool eventFilter( TQObject *obj, TQEvent *ev )
|
|
{
|
|
if ( !obj->isWidgetType() || ::tqqt_cast<KoFrame *>( obj ) )
|
|
return false;
|
|
return KParts::PartManager::eventFilter( obj, ev );
|
|
}
|
|
};
|
|
|
|
class KoMainWindowPrivate
|
|
{
|
|
public:
|
|
KoMainWindowPrivate()
|
|
{
|
|
m_rootDoc = 0L;
|
|
m_docToOpen = 0L;
|
|
m_manager = 0L;
|
|
bMainWindowGUIBuilt = false;
|
|
m_forQuit=false;
|
|
m_splitted=false;
|
|
m_activePart = 0L;
|
|
m_activeView = 0L;
|
|
m_splitter=0L;
|
|
m_orientation=0L;
|
|
m_removeView=0L;
|
|
m_toolbarList.setAutoDelete( true );
|
|
m_firstTime=true;
|
|
m_progress=0L;
|
|
m_paDocInfo = 0;
|
|
m_paSave = 0;
|
|
m_paSaveAs = 0;
|
|
m_paPrint = 0;
|
|
m_paPrintPreview = 0;
|
|
statusBarLabel = 0L;
|
|
m_dcopObject = 0;
|
|
m_sendfile = 0;
|
|
m_paCloseFile = 0L;
|
|
m_reloadfile = 0L;
|
|
m_versionsfile = 0L;
|
|
m_importFile = 0;
|
|
m_exportFile = 0;
|
|
m_isImporting = false;
|
|
m_isExporting = false;
|
|
m_windowSizeDirty = false;
|
|
m_lastExportSpecialOutputFlag = 0;
|
|
|
|
// TTS accessibility enhancement (only if KDE 3.4 or later and KTTSD daemon is installed.)
|
|
if (KoSpeaker::isKttsdInstalled()) {
|
|
if (kospeaker)
|
|
m_koSpeaker = kospeaker;
|
|
else
|
|
m_koSpeaker = new KoSpeaker();
|
|
} else
|
|
m_koSpeaker = 0;
|
|
}
|
|
~KoMainWindowPrivate()
|
|
{
|
|
delete m_dcopObject;
|
|
}
|
|
|
|
KoDocument *m_rootDoc;
|
|
KoDocument *m_docToOpen;
|
|
TQPtrList<KoView> m_rootViews;
|
|
KParts::PartManager *m_manager;
|
|
|
|
KParts::Part *m_activePart;
|
|
KoView *m_activeView;
|
|
|
|
TQLabel * statusBarLabel;
|
|
KProgress *m_progress;
|
|
|
|
TQPtrList<TDEAction> m_splitViewActionList;
|
|
// This additional list is needed, because we don't plug
|
|
// the first list, when an embedded view gets activated (Werner)
|
|
TQPtrList<TDEAction> m_veryHackyActionList;
|
|
TQSplitter *m_splitter;
|
|
TDESelectAction *m_orientation;
|
|
TDEAction *m_removeView;
|
|
KoMainWindowIface *m_dcopObject;
|
|
|
|
TQPtrList <TDEAction> m_toolbarList;
|
|
|
|
bool bMainWindowGUIBuilt;
|
|
bool m_splitted;
|
|
bool m_forQuit;
|
|
bool m_firstTime;
|
|
bool m_windowSizeDirty;
|
|
|
|
TDEAction *m_paDocInfo;
|
|
TDEAction *m_paSave;
|
|
TDEAction *m_paSaveAs;
|
|
TDEAction *m_paPrint;
|
|
TDEAction *m_paPrintPreview;
|
|
TDEAction *m_sendfile;
|
|
TDEAction *m_paCloseFile;
|
|
TDEAction *m_reloadfile;
|
|
TDEAction *m_versionsfile;
|
|
TDEAction *m_importFile;
|
|
TDEAction *m_exportFile;
|
|
|
|
bool m_isImporting;
|
|
bool m_isExporting;
|
|
|
|
KURL m_lastExportURL;
|
|
TQCString m_lastExportFormat;
|
|
int m_lastExportSpecialOutputFlag;
|
|
|
|
TDESharedPtr<KoSpeaker> m_koSpeaker;
|
|
};
|
|
|
|
KoMainWindow::KoMainWindow( TDEInstance *instance, const char* name )
|
|
: KParts::MainWindow( name )
|
|
{
|
|
setStandardToolBarMenuEnabled(true); // should there be a check for >= 3.1 ?
|
|
Q_ASSERT(instance);
|
|
d = new KoMainWindowPrivate;
|
|
|
|
d->m_manager = new KoPartManager( this );
|
|
|
|
connect( d->m_manager, TQT_SIGNAL( activePartChanged( KParts::Part * ) ),
|
|
TQT_TQOBJECT(this), TQT_SLOT( slotActivePartChanged( KParts::Part * ) ) );
|
|
|
|
if ( instance )
|
|
setInstance( instance, false ); // don't load plugins! we don't want
|
|
// the part's plugins with this shell, even though we are using the
|
|
// part's instance! (Simon)
|
|
|
|
TQString doc;
|
|
TQStringList allFiles = TDEGlobal::dirs()->findAllResources( "data", "koffice/koffice_shell.rc" );
|
|
setXMLFile( findMostRecentXMLFile( allFiles, doc ) );
|
|
setLocalXMLFile( locateLocal( "data", "koffice/koffice_shell.rc" ) );
|
|
|
|
KStdAction::openNew( TQT_TQOBJECT(this), TQT_SLOT( slotFileNew() ), actionCollection(), "file_new" );
|
|
KStdAction::open( TQT_TQOBJECT(this), TQT_SLOT( slotFileOpen() ), actionCollection(), "file_open" );
|
|
m_recent = KStdAction::openRecent( TQT_TQOBJECT(this), TQT_SLOT(slotFileOpenRecent(const KURL&)), actionCollection() );
|
|
d->m_paSave = KStdAction::save( TQT_TQOBJECT(this), TQT_SLOT( slotFileSave() ), actionCollection(), "file_save" );
|
|
d->m_paSaveAs = KStdAction::saveAs( TQT_TQOBJECT(this), TQT_SLOT( slotFileSaveAs() ), actionCollection(), "file_save_as" );
|
|
d->m_paPrint = KStdAction::print( TQT_TQOBJECT(this), TQT_SLOT( slotFilePrint() ), actionCollection(), "file_print" );
|
|
d->m_paPrintPreview = KStdAction::printPreview( TQT_TQOBJECT(this), TQT_SLOT( slotFilePrintPreview() ), actionCollection(), "file_print_preview" );
|
|
d->m_sendfile = KStdAction::mail( TQT_TQOBJECT(this), TQT_SLOT( slotEmailFile() ), actionCollection(), "file_send_file");
|
|
|
|
d->m_paCloseFile = KStdAction::close( TQT_TQOBJECT(this), TQT_SLOT( slotFileClose() ), actionCollection(), "file_close" );
|
|
KStdAction::quit( TQT_TQOBJECT(this), TQT_SLOT( slotFileQuit() ), actionCollection(), "file_quit" );
|
|
|
|
d->m_reloadfile = new TDEAction( i18n( "Reload"), 0,
|
|
TQT_TQOBJECT(this), TQT_SLOT( slotReloadFile() ),
|
|
actionCollection(), "file_reload_file");
|
|
|
|
d->m_versionsfile = new TDEAction( i18n( "Versions..."), 0,
|
|
TQT_TQOBJECT(this), TQT_SLOT( slotVersionsFile() ),
|
|
actionCollection(), "file_versions_file");
|
|
|
|
d->m_importFile = new TDEAction( i18n( "I&mport..." ), 0, // clashing accel key :(
|
|
TQT_TQOBJECT(this), TQT_SLOT( slotImportFile() ),
|
|
actionCollection(), "file_import_file");
|
|
d->m_exportFile = new TDEAction( i18n( "E&xport..." ), 0,
|
|
TQT_TQOBJECT(this), TQT_SLOT( slotExportFile() ),
|
|
actionCollection(), "file_export_file");
|
|
|
|
/* The following entry opens the document information dialog. Since the action is named so it
|
|
intends to show data this entry should not have a trailing ellipses (...). */
|
|
d->m_paDocInfo = new TDEAction( i18n( "&Document Information" ), "documentinfo", 0,
|
|
TQT_TQOBJECT(this), TQT_SLOT( slotDocumentInfo() ),
|
|
actionCollection(), "file_documentinfo" );
|
|
|
|
KStdAction::keyBindings( TQT_TQOBJECT(this), TQT_SLOT( slotConfigureKeys() ), actionCollection() );
|
|
KStdAction::configureToolbars( TQT_TQOBJECT(this), TQT_SLOT( slotConfigureToolbars() ), actionCollection() );
|
|
|
|
d->m_paDocInfo->setEnabled( false );
|
|
d->m_paSaveAs->setEnabled( false );
|
|
d->m_reloadfile->setEnabled( false );
|
|
d->m_versionsfile->setEnabled( false );
|
|
d->m_importFile->setEnabled( true ); // always enabled like File --> Open
|
|
d->m_exportFile->setEnabled( false );
|
|
d->m_paSave->setEnabled( false );
|
|
d->m_paPrint->setEnabled( false );
|
|
d->m_paPrintPreview->setEnabled( false );
|
|
d->m_sendfile->setEnabled( false);
|
|
d->m_paCloseFile->setEnabled( false);
|
|
|
|
d->m_splitter=new TQSplitter(Qt::Vertical, this, "mw-splitter");
|
|
setCentralWidget( d->m_splitter );
|
|
// Keyboard accessibility enhancements.
|
|
new KKbdAccessExtensions(this, "mw-panelSizer");
|
|
// set up the action "list" for "Close all Views" (hacky :) (Werner)
|
|
d->m_veryHackyActionList.append(
|
|
new TDEAction(i18n("&Close All Views"), "fileclose",
|
|
"ctrl+shift+w", TQT_TQOBJECT(this), TQT_SLOT(slotCloseAllViews()),
|
|
actionCollection(), "view_closeallviews") );
|
|
|
|
// set up the action list for the splitter stuff
|
|
d->m_splitViewActionList.append(new TDEAction(i18n("&Split View"), "view_split", 0,
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotSplitView()),
|
|
actionCollection(), "view_split"));
|
|
d->m_removeView=new TDEAction(i18n("&Remove View"), "view_remove", 0,
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotRemoveView()),
|
|
actionCollection(), "view_rm_splitter");
|
|
d->m_splitViewActionList.append(d->m_removeView);
|
|
d->m_removeView->setEnabled(false);
|
|
d->m_orientation=new TDESelectAction(i18n("Splitter &Orientation"), "view_orientation", 0,
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotSetOrientation()),
|
|
actionCollection(), "view_splitter_orientation");
|
|
TQStringList items;
|
|
items << i18n("&Vertical")
|
|
<< i18n("&Horizontal");
|
|
d->m_orientation->setItems(items);
|
|
d->m_orientation->setCurrentItem(static_cast<int>(d->m_splitter->orientation()));
|
|
d->m_splitViewActionList.append(d->m_orientation);
|
|
d->m_splitViewActionList.append(new TDEActionSeparator(TQT_TQOBJECT(this)));
|
|
|
|
// Load list of recent files
|
|
TDEConfig * config = instance ? instance->config() : TDEGlobal::config();
|
|
m_recent->loadEntries( config );
|
|
|
|
createShellGUI();
|
|
d->bMainWindowGUIBuilt = true;
|
|
|
|
if ( !initialGeometrySet() )
|
|
{
|
|
// Default size
|
|
const int deskWidth = TDEGlobalSettings::desktopGeometry(this).width();
|
|
if (deskWidth > 1100) // very big desktop ?
|
|
resize( 1000, 800 );
|
|
if (deskWidth > 850) // big desktop ?
|
|
resize( 800, 600 );
|
|
else // small (800x600, 640x480) desktop
|
|
resize( 600, 400 );
|
|
}
|
|
|
|
// Saved size
|
|
config->setGroup( "MainWindow" );
|
|
//kdDebug(30003) << "KoMainWindow::restoreWindowSize" << endl;
|
|
restoreWindowSize( config );
|
|
}
|
|
|
|
KoMainWindow::~KoMainWindow()
|
|
{
|
|
// The doc and view might still exist (this is the case when closing the window)
|
|
if (d->m_rootDoc)
|
|
d->m_rootDoc->removeShell(this);
|
|
|
|
if (d->m_docToOpen) {
|
|
d->m_docToOpen->removeShell(this);
|
|
delete d->m_docToOpen;
|
|
}
|
|
|
|
// safety first ;)
|
|
d->m_manager->setActivePart(0);
|
|
|
|
if(d->m_rootViews.findRef(d->m_activeView)==-1) {
|
|
delete d->m_activeView;
|
|
d->m_activeView=0L;
|
|
}
|
|
d->m_rootViews.setAutoDelete( true );
|
|
d->m_rootViews.clear();
|
|
|
|
// We have to check if this was a root document.
|
|
// -> We aren't allowed to delete the (embedded) document!
|
|
// This has to be checked from queryClose, too :)
|
|
if ( d->m_rootDoc && d->m_rootDoc->viewCount() == 0 &&
|
|
!d->m_rootDoc->isEmbedded())
|
|
{
|
|
//kdDebug(30003) << "Destructor. No more views, deleting old doc " << d->m_rootDoc << endl;
|
|
delete d->m_rootDoc;
|
|
}
|
|
|
|
delete d->m_manager;
|
|
delete d;
|
|
}
|
|
|
|
void KoMainWindow::setRootDocument( KoDocument *doc )
|
|
{
|
|
if ( d->m_rootDoc == doc )
|
|
return;
|
|
|
|
if (d->m_docToOpen && d->m_docToOpen != doc) {
|
|
d->m_docToOpen->removeShell(this);
|
|
delete d->m_docToOpen;
|
|
d->m_docToOpen = 0;
|
|
} else {
|
|
d->m_docToOpen = 0;
|
|
}
|
|
|
|
//kdDebug(30003) << "KoMainWindow::setRootDocument this = " << this << " doc = " << doc << endl;
|
|
TQPtrList<KoView> oldRootViews = d->m_rootViews;
|
|
d->m_rootViews.clear();
|
|
KoDocument *oldRootDoc = d->m_rootDoc;
|
|
|
|
if ( oldRootDoc )
|
|
oldRootDoc->removeShell( this );
|
|
|
|
d->m_rootDoc = doc;
|
|
|
|
if ( doc )
|
|
{
|
|
doc->setSelectable( false );
|
|
//d->m_manager->addPart( doc, false ); // done by KoView::setPartManager
|
|
d->m_rootViews.append( doc->createView( d->m_splitter, "view" /*not unique, but better than unnamed*/ ) );
|
|
d->m_rootViews.current()->setPartManager( d->m_manager );
|
|
|
|
d->m_rootViews.current()->show();
|
|
// The addShell has been done already if using openURL
|
|
if ( !d->m_rootDoc->shells().contains( this ) )
|
|
d->m_rootDoc->addShell( this );
|
|
d->m_removeView->setEnabled(false);
|
|
d->m_orientation->setEnabled(false);
|
|
}
|
|
|
|
bool enable = d->m_rootDoc != 0 ? true : false;
|
|
d->m_paDocInfo->setEnabled( enable );
|
|
d->m_paSave->setEnabled( enable );
|
|
d->m_paSaveAs->setEnabled( enable );
|
|
d->m_importFile->setEnabled( enable );
|
|
d->m_exportFile->setEnabled( enable );
|
|
d->m_paPrint->setEnabled( enable );
|
|
d->m_paPrintPreview->setEnabled( enable );
|
|
d->m_sendfile->setEnabled( enable);
|
|
d->m_paCloseFile->setEnabled( enable);
|
|
updateCaption();
|
|
|
|
d->m_manager->setActivePart( d->m_rootDoc, d->m_rootViews.current() );
|
|
|
|
oldRootViews.setAutoDelete( true );
|
|
oldRootViews.clear();
|
|
|
|
if ( oldRootDoc && oldRootDoc->viewCount() == 0 )
|
|
{
|
|
//kdDebug(30003) << "No more views, deleting old doc " << oldRootDoc << endl;
|
|
delete oldRootDoc;
|
|
}
|
|
}
|
|
|
|
void KoMainWindow::updateReloadFileAction(KoDocument *doc)
|
|
{
|
|
d->m_reloadfile->setEnabled( doc && !doc->url().isEmpty() );
|
|
}
|
|
|
|
void KoMainWindow::updateVersionsFileAction(KoDocument *doc)
|
|
{
|
|
//TODO activate it just when we save it in oasis file format
|
|
d->m_versionsfile->setEnabled( doc && !doc->url().isEmpty()&&doc->isModified());
|
|
}
|
|
|
|
|
|
void KoMainWindow::setRootDocumentDirect( KoDocument *doc, const TQPtrList<KoView> & views )
|
|
{
|
|
d->m_rootDoc = doc;
|
|
d->m_rootViews = views;
|
|
bool enable = d->m_rootDoc != 0 ? true : false;
|
|
d->m_paDocInfo->setEnabled( enable );
|
|
d->m_paSave->setEnabled( enable );
|
|
d->m_paSaveAs->setEnabled( enable );
|
|
d->m_exportFile->setEnabled( enable );
|
|
d->m_paPrint->setEnabled( enable );
|
|
d->m_paPrintPreview->setEnabled( enable );
|
|
d->m_sendfile->setEnabled( enable);
|
|
d->m_paCloseFile->setEnabled( enable );
|
|
}
|
|
|
|
void KoMainWindow::addRecentURL( const KURL& url )
|
|
{
|
|
kdDebug(30003) << "KoMainWindow::addRecentURL url=" << url.prettyURL() << endl;
|
|
// Add entry to recent documents list
|
|
// (call coming from KoDocument because it must work with cmd line, template dlg, file/open, etc.)
|
|
if ( !url.isEmpty() )
|
|
{
|
|
bool ok = true;
|
|
if ( url.isLocalFile() )
|
|
{
|
|
TQString path = url.path( -1 );
|
|
TQStringList tmpDirs = TDEGlobal::dirs()->resourceDirs( "tmp" );
|
|
for ( TQStringList::Iterator it = tmpDirs.begin() ; ok && it != tmpDirs.end() ; ++it )
|
|
if ( path.contains( *it ) )
|
|
ok = false; // it's in the tmp resource
|
|
if ( ok )
|
|
TDERecentDocument::add(path);
|
|
}
|
|
else
|
|
TDERecentDocument::add(url.url(-1), true);
|
|
|
|
if ( ok )
|
|
m_recent->addURL( url );
|
|
saveRecentFiles();
|
|
}
|
|
}
|
|
|
|
void KoMainWindow::saveRecentFiles()
|
|
{
|
|
// Save list of recent files
|
|
TDEConfig * config = instance() ? instance()->config() : TDEGlobal::config();
|
|
kdDebug(30003) << this << " Saving recent files list into config. instance()=" << instance() << endl;
|
|
m_recent->saveEntries( config );
|
|
config->sync();
|
|
if (TDEMainWindow::memberList)
|
|
{
|
|
// Tell all windows to reload their list, after saving
|
|
// Doesn't work multi-process, but it's a start
|
|
TDEMainWindow *window = TDEMainWindow::memberList->first();
|
|
for (; window; window = TDEMainWindow::memberList->next())
|
|
static_cast<KoMainWindow *>(window)->reloadRecentFileList();
|
|
}
|
|
}
|
|
|
|
void KoMainWindow::reloadRecentFileList()
|
|
{
|
|
TDEConfig * config = instance() ? instance()->config() : TDEGlobal::config();
|
|
m_recent->loadEntries( config );
|
|
}
|
|
|
|
KoDocument* KoMainWindow::createDoc() const
|
|
{
|
|
KoDocumentEntry entry = KoDocumentEntry( KoDocument::readNativeService() );
|
|
return entry.createDoc();
|
|
}
|
|
|
|
void KoMainWindow::updateCaption()
|
|
{
|
|
//kdDebug(30003) << "KoMainWindow::updateCaption()" << endl;
|
|
if ( !d->m_rootDoc )
|
|
setCaption(TQString());
|
|
else if ( rootDocument()->isCurrent() )
|
|
{
|
|
TQString caption;
|
|
// Get caption from document info (title(), in about page)
|
|
if ( rootDocument()->documentInfo() )
|
|
{
|
|
KoDocumentInfoPage * page = rootDocument()->documentInfo()->page( TQString::fromLatin1("about") );
|
|
if (page)
|
|
caption = static_cast<KoDocumentInfoAbout *>(page)->title();
|
|
}
|
|
const TQString url = rootDocument()->url().prettyURL( 0, KURL::StripFileProtocol );
|
|
if ( !caption.isEmpty() && !url.isEmpty() )
|
|
caption = TQString( "%1 - %2" ).arg( caption ).arg( url );
|
|
else if ( caption.isEmpty() )
|
|
caption = url;
|
|
|
|
setCaption( caption, rootDocument()->isModified() );
|
|
if ( !rootDocument()->url().fileName(false).isEmpty() )
|
|
d->m_paSave->setToolTip( i18n("Save as %1").arg(rootDocument()->url().fileName(false)) );
|
|
else
|
|
d->m_paSave->setToolTip( i18n("Save") );
|
|
}
|
|
}
|
|
|
|
void KoMainWindow::updateCaption( TQString caption, bool mod )
|
|
{
|
|
//kdDebug(30003)<<"KoMainWindow::updateCaption("<<caption<<","<<mod<<")"<<endl;
|
|
setCaption( caption, mod );
|
|
}
|
|
|
|
KoDocument *KoMainWindow::rootDocument() const
|
|
{
|
|
return d->m_rootDoc;
|
|
}
|
|
|
|
KoView *KoMainWindow::rootView() const
|
|
{
|
|
if(d->m_rootViews.find(d->m_activeView)!=-1)
|
|
return d->m_activeView;
|
|
return d->m_rootViews.first();
|
|
}
|
|
|
|
KParts::PartManager *KoMainWindow::partManager()
|
|
{
|
|
return d->m_manager;
|
|
}
|
|
|
|
bool KoMainWindow::openDocument( const KURL & url )
|
|
{
|
|
if ( !TDEIO::NetAccess::exists(url,true,0) )
|
|
{
|
|
KMessageBox::error(0L, i18n("The file %1 does not exist.").arg(url.url()) );
|
|
m_recent->removeURL(url); //remove the file from the recent-opened-file-list
|
|
saveRecentFiles();
|
|
return false;
|
|
}
|
|
return openDocumentInternal( url );
|
|
}
|
|
|
|
// (not virtual)
|
|
bool KoMainWindow::openDocument( KoDocument *newdoc, const KURL & url )
|
|
{
|
|
if (!TDEIO::NetAccess::exists(url,true,0) )
|
|
{
|
|
if (!newdoc->checkAutoSaveFile())
|
|
{
|
|
newdoc->initEmpty(); //create an emtpy document
|
|
}
|
|
|
|
setRootDocument( newdoc );
|
|
newdoc->setURL(url);
|
|
TQString mime = KMimeType::findByURL(url)->name();
|
|
if ( mime.isEmpty() || mime == KMimeType::defaultMimeType() )
|
|
mime = newdoc->nativeFormatMimeType();
|
|
if ( url.isLocalFile() ) // workaround for kde<=3.3 tdeparts bug, fixed for 3.4
|
|
newdoc->setFile(url.path());
|
|
newdoc->setMimeTypeAfterLoading( mime );
|
|
updateCaption();
|
|
return true;
|
|
}
|
|
return openDocumentInternal( url, newdoc );
|
|
}
|
|
|
|
// ## If you modify anything here, please check KoShellWindow::openDocumentInternal
|
|
bool KoMainWindow::openDocumentInternal( const KURL & url, KoDocument *newdoc )
|
|
{
|
|
//kdDebug(30003) << "KoMainWindow::openDocument " << url.url() << endl;
|
|
|
|
if ( !newdoc )
|
|
newdoc = createDoc();
|
|
if ( !newdoc )
|
|
return false;
|
|
|
|
d->m_firstTime=true;
|
|
connect(newdoc, TQT_SIGNAL(sigProgress(int)), TQT_TQOBJECT(this), TQT_SLOT(slotProgress(int)));
|
|
connect(newdoc, TQT_SIGNAL(completed()), TQT_TQOBJECT(this), TQT_SLOT(slotLoadCompleted()));
|
|
connect(newdoc, TQT_SIGNAL(canceled( const TQString & )), TQT_TQOBJECT(this), TQT_SLOT(slotLoadCanceled( const TQString & )));
|
|
newdoc->addShell( this ); // used by openURL
|
|
bool openRet = (!isImporting ()) ? newdoc->openURL(url) : newdoc->import(url);
|
|
if(!openRet)
|
|
{
|
|
newdoc->removeShell(this);
|
|
delete newdoc;
|
|
return false;
|
|
}
|
|
updateReloadFileAction(newdoc);
|
|
updateVersionsFileAction( newdoc );
|
|
return true;
|
|
}
|
|
|
|
// Separate from openDocument to handle async loading (remote URLs)
|
|
void KoMainWindow::slotLoadCompleted()
|
|
{
|
|
kdDebug(30003) << "KoMainWindow::slotLoadCompleted" << endl;
|
|
KoDocument* doc = rootDocument();
|
|
KoDocument* newdoc = (KoDocument *)(sender());
|
|
|
|
if ( doc && doc->isEmpty() && !doc->isEmbedded() )
|
|
{
|
|
// Replace current empty document
|
|
setRootDocument( newdoc );
|
|
}
|
|
else if ( doc && !doc->isEmpty() )
|
|
{
|
|
// Open in a new shell
|
|
// (Note : could create the shell first and the doc next for this
|
|
// particular case, that would give a better user feedback...)
|
|
KoMainWindow *s = new KoMainWindow( newdoc->instance() );
|
|
s->show();
|
|
newdoc->removeShell( this );
|
|
s->setRootDocument( newdoc );
|
|
}
|
|
else
|
|
{
|
|
// We had no document, set the new one
|
|
setRootDocument( newdoc );
|
|
}
|
|
disconnect(newdoc, TQT_SIGNAL(sigProgress(int)), TQT_TQOBJECT(this), TQT_SLOT(slotProgress(int)));
|
|
disconnect(newdoc, TQT_SIGNAL(completed()), TQT_TQOBJECT(this), TQT_SLOT(slotLoadCompleted()));
|
|
disconnect(newdoc, TQT_SIGNAL(canceled( const TQString & )), TQT_TQOBJECT(this), TQT_SLOT(slotLoadCanceled( const TQString & )));
|
|
}
|
|
|
|
void KoMainWindow::slotLoadCanceled( const TQString & errMsg )
|
|
{
|
|
kdDebug(30003) << "KoMainWindow::slotLoadCanceled" << endl;
|
|
if ( !errMsg.isEmpty() ) // empty when canceled by user
|
|
KMessageBox::error( this, errMsg );
|
|
// ... can't delete the document, it's the one who emitted the signal...
|
|
|
|
KoDocument* newdoc = (KoDocument *)(sender());
|
|
disconnect(newdoc, TQT_SIGNAL(sigProgress(int)), TQT_TQOBJECT(this), TQT_SLOT(slotProgress(int)));
|
|
disconnect(newdoc, TQT_SIGNAL(completed()), TQT_TQOBJECT(this), TQT_SLOT(slotLoadCompleted()));
|
|
disconnect(newdoc, TQT_SIGNAL(canceled( const TQString & )), TQT_TQOBJECT(this), TQT_SLOT(slotLoadCanceled( const TQString & )));
|
|
|
|
newdoc->removeShell(this);
|
|
delete newdoc;
|
|
}
|
|
|
|
void KoMainWindow::slotSaveCanceled( const TQString &errMsg )
|
|
{
|
|
kdDebug(30003) << "KoMainWindow::slotSaveCanceled" << endl;
|
|
if ( !errMsg.isEmpty() ) // empty when canceled by user
|
|
KMessageBox::error( this, errMsg );
|
|
slotSaveCompleted();
|
|
}
|
|
|
|
void KoMainWindow::slotSaveCompleted()
|
|
{
|
|
kdDebug(30003) << "KoMainWindow::slotSaveCompleted" << endl;
|
|
KoDocument* pDoc = (KoDocument *)(sender());
|
|
disconnect(pDoc, TQT_SIGNAL(sigProgress(int)), TQT_TQOBJECT(this), TQT_SLOT(slotProgress(int)));
|
|
disconnect(pDoc, TQT_SIGNAL(completed()), TQT_TQOBJECT(this), TQT_SLOT(slotSaveCompleted()));
|
|
disconnect(pDoc, TQT_SIGNAL(canceled( const TQString & )),
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotSaveCanceled( const TQString & )));
|
|
}
|
|
|
|
// returns true if we should save, false otherwise.
|
|
bool KoMainWindow::exportConfirmation( const TQCString &outputFormat )
|
|
{
|
|
if (!rootDocument()->wantExportConfirmation()) return true;
|
|
KMimeType::Ptr mime = KMimeType::mimeType( outputFormat );
|
|
|
|
const bool neverHeardOfIt = ( mime->name() == KMimeType::defaultMimeType() );
|
|
TQString comment = neverHeardOfIt ?
|
|
i18n( "%1 (unknown file type)" ).arg( outputFormat.data() )
|
|
: mime->comment();
|
|
|
|
// Warn the user
|
|
int ret;
|
|
if (!isExporting ()) // File --> Save
|
|
{
|
|
ret = KMessageBox::warningContinueCancel
|
|
(
|
|
this,
|
|
i18n( "<qt>Saving as a %1 may result in some loss of formatting."
|
|
"<p>Do you still want to save in this format?</qt>" )
|
|
.arg( TQString( "<b>%1</b>" ).arg( comment ) ), // in case we want to remove the bold later
|
|
i18n( "Confirm Save" ),
|
|
KStdGuiItem::save (),
|
|
"NonNativeSaveConfirmation",
|
|
true
|
|
);
|
|
}
|
|
else // File --> Export
|
|
{
|
|
ret = KMessageBox::warningContinueCancel
|
|
(
|
|
this,
|
|
i18n( "<qt>Exporting as a %1 may result in some loss of formatting."
|
|
"<p>Do you still want to export to this format?</qt>" )
|
|
.arg( TQString( "<b>%1</b>" ).arg( comment ) ), // in case we want to remove the bold later
|
|
i18n( "Confirm Export" ),
|
|
i18n ("Export"),
|
|
"NonNativeExportConfirmation", // different to the one used for Save (above)
|
|
true
|
|
);
|
|
}
|
|
|
|
return (ret == KMessageBox::Continue);
|
|
}
|
|
|
|
bool KoMainWindow::saveDocument( bool saveas, bool silent )
|
|
{
|
|
KoDocument* pDoc = rootDocument();
|
|
if(!pDoc)
|
|
return true;
|
|
|
|
bool reset_url;
|
|
if ( pDoc->url().isEmpty() )
|
|
{
|
|
emit saveDialogShown();
|
|
reset_url = true;
|
|
saveas = true;
|
|
}
|
|
else
|
|
reset_url = false;
|
|
|
|
connect(pDoc, TQT_SIGNAL(sigProgress(int)), TQT_TQOBJECT(this), TQT_SLOT(slotProgress(int)));
|
|
connect(pDoc, TQT_SIGNAL(completed()), TQT_TQOBJECT(this), TQT_SLOT(slotSaveCompleted()));
|
|
connect(pDoc, TQT_SIGNAL(canceled( const TQString & )),
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotSaveCanceled( const TQString & )));
|
|
|
|
KURL oldURL = pDoc->url();
|
|
TQString oldFile = pDoc->file();
|
|
TQCString _native_format = pDoc->nativeFormatMimeType();
|
|
TQCString oldOutputFormat = pDoc->outputMimeType();
|
|
int oldSpecialOutputFlag = pDoc->specialOutputFlag();
|
|
KURL suggestedURL = pDoc->url();
|
|
|
|
TQStringList mimeFilter = KoFilterManager::mimeFilter( _native_format, KoFilterManager::Export, pDoc->extraNativeMimeTypes() );
|
|
if (mimeFilter.findIndex (oldOutputFormat) < 0 && !isExporting())
|
|
{
|
|
kdDebug(30003) << "KoMainWindow::saveDocument no export filter for '" << oldOutputFormat << "'" << endl;
|
|
|
|
// --- don't setOutputMimeType in case the user cancels the Save As
|
|
// dialog and then tries to just plain Save ---
|
|
|
|
// suggest a different filename extension (yes, we fortunately don't all live in a world of magic :))
|
|
TQString suggestedFilename = suggestedURL.fileName ();
|
|
if ( !suggestedFilename.isEmpty () ) // ".kwd" looks strange for a name
|
|
{
|
|
int c = suggestedFilename.findRev ('.');
|
|
|
|
KMimeType::Ptr mime = KMimeType::mimeType( _native_format );
|
|
TQString ext = mime->property( "X-TDE-NativeExtension" ).toString();
|
|
if (!ext.isEmpty ())
|
|
{
|
|
if (c < 0)
|
|
suggestedFilename += ext;
|
|
else
|
|
suggestedFilename = suggestedFilename.left (c) + ext;
|
|
}
|
|
else // current filename extension wrong anyway
|
|
{
|
|
if (c > 0)
|
|
{
|
|
// this assumes that a . signifies an extension, not just a .
|
|
suggestedFilename = suggestedFilename.left (c);
|
|
}
|
|
}
|
|
|
|
suggestedURL.setFileName (suggestedFilename);
|
|
}
|
|
|
|
// force the user to choose outputMimeType
|
|
saveas = true;
|
|
}
|
|
|
|
bool ret = false;
|
|
|
|
if ( pDoc->url().isEmpty() || saveas )
|
|
{
|
|
// if you're just File/Save As'ing to change filter options you
|
|
// don't want to be reminded about overwriting files etc.
|
|
bool justChangingFilterOptions = false;
|
|
|
|
KoFileDialog *dialog = new KoFileDialog( (isExporting() && !d->m_lastExportURL.isEmpty() )? d->m_lastExportURL.url () : suggestedURL.url (),
|
|
TQString(), this, "file dialog", true);
|
|
|
|
if (!isExporting())
|
|
dialog->setCaption( i18n("Save Document As") );
|
|
else
|
|
dialog->setCaption( i18n("Export Document As") );
|
|
|
|
dialog->setOperationMode( KFileDialog::Saving );
|
|
dialog->setSpecialMimeFilter( mimeFilter,
|
|
isExporting() ? d->m_lastExportFormat : pDoc->mimeType(),
|
|
isExporting() ? d->m_lastExportSpecialOutputFlag : oldSpecialOutputFlag,
|
|
_native_format,
|
|
pDoc->supportedSpecialFormats() );
|
|
|
|
KURL newURL;
|
|
TQCString outputFormat = _native_format;
|
|
int specialOutputFlag = 0;
|
|
bool bOk;
|
|
do {
|
|
bOk=true;
|
|
if(dialog->exec()==TQDialog::Accepted) {
|
|
newURL=dialog->selectedURL();
|
|
outputFormat=dialog->currentMimeFilter().latin1();
|
|
specialOutputFlag = dialog->specialEntrySelected();
|
|
kdDebug(30003) << "KoMainWindow::saveDocument outputFormat = " << outputFormat << endl;
|
|
|
|
if (!isExporting())
|
|
justChangingFilterOptions = (newURL == pDoc->url()) &&
|
|
(outputFormat == pDoc->mimeType()) &&
|
|
(specialOutputFlag == oldSpecialOutputFlag);
|
|
else
|
|
justChangingFilterOptions = (newURL == d->m_lastExportURL) &&
|
|
(outputFormat == d->m_lastExportFormat) &&
|
|
(specialOutputFlag == d->m_lastExportSpecialOutputFlag);
|
|
}
|
|
else
|
|
{
|
|
bOk = false;
|
|
break;
|
|
}
|
|
|
|
if ( newURL.isEmpty() )
|
|
{
|
|
bOk = false;
|
|
break;
|
|
}
|
|
|
|
// adjust URL before doing checks on whether the file exists.
|
|
if ( specialOutputFlag == KoDocument::SaveAsDirectoryStore ) {
|
|
TQString fileName = newURL.fileName();
|
|
if ( fileName != "content.xml" ) {
|
|
newURL.addPath( "content.xml" );
|
|
}
|
|
}
|
|
|
|
// this file exists and we are not just clicking "Save As" to change filter options
|
|
// => ask for confirmation
|
|
if ( TDEIO::NetAccess::exists( newURL, false /*will write*/, this ) && !justChangingFilterOptions )
|
|
{
|
|
bOk = KMessageBox::questionYesNo( this,
|
|
i18n("A document with this name already exists.\n"\
|
|
"Do you want to overwrite it?"),
|
|
i18n("Warning") ) == KMessageBox::Yes;
|
|
}
|
|
} while ( !bOk );
|
|
|
|
delete dialog;
|
|
|
|
if (bOk)
|
|
{
|
|
bool wantToSave = true;
|
|
|
|
// don't change this line unless you know what you're doing :)
|
|
if (!justChangingFilterOptions || pDoc->confirmNonNativeSave (isExporting ())) {
|
|
if ( !pDoc->isNativeFormat( outputFormat ) )
|
|
wantToSave = exportConfirmation( outputFormat );
|
|
}
|
|
|
|
if (wantToSave)
|
|
{
|
|
//
|
|
// Note:
|
|
// If the user is stupid enough to Export to the current URL,
|
|
// we do _not_ change this operation into a Save As. Reasons
|
|
// follow:
|
|
//
|
|
// 1. A check like "isExporting() && oldURL == newURL"
|
|
// doesn't _always_ work on case-insensitive filesystems
|
|
// and inconsistent behaviour is bad.
|
|
// 2. It is probably not a good idea to change pDoc->mimeType
|
|
// and friends because the next time the user File/Save's,
|
|
// (not Save As) they won't be expecting that they are
|
|
// using their File/Export settings
|
|
//
|
|
// As a bad side-effect of TQT_TQOBJECT(this), the modified flag will not
|
|
// be updated and it is possible that what is currently on
|
|
// their screen is not what is stored on disk (through loss
|
|
// of formatting). But if you are dumb enough to change
|
|
// mimetype but not the filename, then arguably, _you_ are
|
|
// the "bug" :)
|
|
//
|
|
// - Clarence
|
|
//
|
|
|
|
|
|
pDoc->setOutputMimeType( outputFormat, specialOutputFlag );
|
|
if (!isExporting ()) // Save As
|
|
{
|
|
ret = pDoc->saveAs( newURL );
|
|
|
|
if (ret)
|
|
{
|
|
kdDebug(30003) << "Successful Save As!" << endl;
|
|
addRecentURL( newURL );
|
|
}
|
|
else
|
|
{
|
|
kdDebug(30003) << "Failed Save As!" << endl;
|
|
pDoc->setURL( oldURL ), pDoc->setFile( oldFile );
|
|
pDoc->setOutputMimeType( oldOutputFormat, oldSpecialOutputFlag );
|
|
}
|
|
}
|
|
else // Export
|
|
{
|
|
ret = pDoc->exp0rt( newURL );
|
|
|
|
if (ret)
|
|
{
|
|
// a few file dialog convenience things
|
|
d->m_lastExportURL = newURL;
|
|
d->m_lastExportFormat = outputFormat;
|
|
d->m_lastExportSpecialOutputFlag = specialOutputFlag;
|
|
}
|
|
|
|
// always restore output format
|
|
pDoc->setOutputMimeType( oldOutputFormat, oldSpecialOutputFlag );
|
|
}
|
|
} // if (wantToSave)
|
|
else
|
|
ret = false;
|
|
} // if (bOk)
|
|
else
|
|
ret = false;
|
|
}
|
|
else { // saving
|
|
bool needConfirm = pDoc->confirmNonNativeSave( false ) &&
|
|
!pDoc->isNativeFormat( oldOutputFormat );
|
|
if (!needConfirm ||
|
|
(needConfirm && exportConfirmation( oldOutputFormat /* not so old :) */ ))
|
|
)
|
|
{
|
|
// be sure pDoc has the correct outputMimeType!
|
|
ret = pDoc->save();
|
|
|
|
if (!ret)
|
|
{
|
|
kdDebug(30003) << "Failed Save!" << endl;
|
|
pDoc->setURL( oldURL ), pDoc->setFile( oldFile );
|
|
}
|
|
}
|
|
else
|
|
ret = false;
|
|
}
|
|
|
|
// Now that there's a File/Export option, this is no longer necessary.
|
|
// If you continue to use File/Save to export to a foreign format,
|
|
// this signals your intention to continue working in a foreign format.
|
|
// You have already been warned by the DoNotAskAgain exportConfirmation
|
|
// about losing formatting when you first saved so don't set modified
|
|
// here or else it will be reported as a bug by some MSOffice user.
|
|
// You have been warned! Do not click DoNotAskAgain!!!
|
|
#if 0
|
|
if (ret && !isExporting())
|
|
{
|
|
// When exporting to a non-native format, we don't reset modified.
|
|
// This way the user will be reminded to save it again in the native format,
|
|
// if he/she doesn't want to lose formatting.
|
|
if ( wasModified && pDoc->outputMimeType() != _native_format )
|
|
pDoc->setModified( true );
|
|
}
|
|
#endif
|
|
|
|
if (!ret && reset_url)
|
|
pDoc->resetURL(); //clean the suggested filename as the save dialog was rejected
|
|
else if (! silent) // don't let the document change the window caption
|
|
pDoc->setTitleModified();
|
|
return ret;
|
|
}
|
|
|
|
void KoMainWindow::closeEvent(TQCloseEvent *e) {
|
|
if(queryClose()) {
|
|
saveWindowSettings();
|
|
setRootDocument(0L);
|
|
KParts::MainWindow::closeEvent(e);
|
|
}
|
|
}
|
|
|
|
void KoMainWindow::saveWindowSettings()
|
|
{
|
|
if (d->m_windowSizeDirty && rootDocument())
|
|
{
|
|
// Save window size into the config file of our instance
|
|
instance()->config()->setGroup( "MainWindow" );
|
|
//kdDebug(30003) << "KoMainWindow::saveWindowSettings" << endl;
|
|
saveWindowSize( instance()->config() );
|
|
d->m_windowSizeDirty = false;
|
|
// Save toolbar position into the config file of the app, under the doc's instance name
|
|
//kdDebug(30003) << "KoMainWindow::closeEvent -> saveMainWindowSettings rootdoc's instance=" << rootDocument()->instance()->instanceName() << endl;
|
|
saveMainWindowSettings( TDEGlobal::config(), rootDocument()->instance()->instanceName() );
|
|
TDEGlobal::config()->sync();
|
|
resetAutoSaveSettings(); // Don't let TDEMainWindow override the good stuff we wrote down
|
|
}
|
|
}
|
|
|
|
void KoMainWindow::resizeEvent( TQResizeEvent * e )
|
|
{
|
|
d->m_windowSizeDirty = true;
|
|
KParts::MainWindow::resizeEvent( e );
|
|
}
|
|
|
|
bool KoMainWindow::queryClose()
|
|
{
|
|
if ( rootDocument() == 0 )
|
|
return true;
|
|
//kdDebug(30003) << "KoMainWindow::queryClose() viewcount=" << rootDocument()->viewCount()
|
|
// << " shellcount=" << rootDocument()->shellCount() << endl;
|
|
if ( !d->m_forQuit && rootDocument()->shellCount() > 1 )
|
|
// there are more open, and we are closing just one, so no problem for closing
|
|
return true;
|
|
|
|
// see DTOR for a descr. of the test
|
|
if ( d->m_rootDoc->isEmbedded() )
|
|
return true;
|
|
|
|
// main doc + internally stored child documents
|
|
if ( d->m_rootDoc->isModified() )
|
|
{
|
|
TQString name;
|
|
if ( rootDocument()->documentInfo() )
|
|
{
|
|
name = rootDocument()->documentInfo()->title();
|
|
}
|
|
if ( name.isEmpty() )
|
|
name = rootDocument()->url().fileName();
|
|
|
|
if ( name.isEmpty() )
|
|
name = i18n( "Untitled" );
|
|
|
|
int res = KMessageBox::warningYesNoCancel( this,
|
|
i18n( "<p>The document <b>'%1'</b> has been modified.</p><p>Do you want to save it?</p>" ).arg(name),
|
|
TQString(),
|
|
KStdGuiItem::save(),
|
|
KStdGuiItem::discard());
|
|
|
|
switch(res) {
|
|
case KMessageBox::Yes : {
|
|
d->m_rootDoc->setDoNotSaveExtDoc(); // external docs are saved later
|
|
bool isNative = ( d->m_rootDoc->outputMimeType() == d->m_rootDoc->nativeFormatMimeType() );
|
|
if (! saveDocument( !isNative ) )
|
|
return false;
|
|
break;
|
|
}
|
|
case KMessageBox::No :
|
|
rootDocument()->removeAutoSaveFiles();
|
|
rootDocument()->setModified( false ); // Now when queryClose() is called by closeEvent it won't do anything.
|
|
break;
|
|
default : // case KMessageBox::Cancel :
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if ( d->m_rootDoc->queryCloseExternalChildren() == KMessageBox::Cancel )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Helper method for slotFileNew and slotFileClose
|
|
void KoMainWindow::chooseNewDocument( int /*KoDocument::InitDocFlags*/ initDocFlags )
|
|
{
|
|
KoDocument* doc = rootDocument();
|
|
KoDocument *newdoc = createDoc();
|
|
|
|
if ( !newdoc )
|
|
return;
|
|
|
|
//FIXME: This needs to be handled differently
|
|
connect(newdoc, TQT_SIGNAL(sigProgress(int)), TQT_TQOBJECT(this), TQT_SLOT(slotProgress(int)));
|
|
disconnect(newdoc, TQT_SIGNAL(sigProgress(int)), TQT_TQOBJECT(this), TQT_SLOT(slotProgress(int)));
|
|
|
|
if ( ( !doc && ( initDocFlags == KoDocument::InitDocFileNew ) ) || ( doc && !doc->isEmpty() ) )
|
|
{
|
|
KoMainWindow *s = new KoMainWindow( newdoc->instance() );
|
|
s->show();
|
|
newdoc->addShell( s );
|
|
newdoc->showStartUpWidget( s, true /*Always show widget*/ );
|
|
return;
|
|
}
|
|
|
|
if( doc ) {
|
|
setRootDocument( 0 );
|
|
delete d->m_rootDoc;
|
|
d->m_rootDoc = 0;
|
|
}
|
|
|
|
newdoc->addShell( this );
|
|
newdoc->showStartUpWidget( this, true /*Always show widget*/ );
|
|
}
|
|
|
|
void KoMainWindow::slotFileNew()
|
|
{
|
|
chooseNewDocument( KoDocument::InitDocFileNew );
|
|
}
|
|
|
|
void KoMainWindow::slotFileOpen()
|
|
{
|
|
KFileDialog *dialog = new KFileDialog(":OpenDialog", TQString(), this, "file dialog", true);
|
|
if (!isImporting())
|
|
dialog->setCaption( i18n("Open Document") );
|
|
else
|
|
dialog->setCaption( i18n("Import Document") );
|
|
|
|
// The few lines below need to be kept in sync with KoTemplateChooseDia::setupFileDialog
|
|
const TQStringList mimeFilter = KoFilterManager::mimeFilter( KoDocument::readNativeFormatMimeType(),
|
|
KoFilterManager::Import,
|
|
KoDocument::readExtraNativeMimeTypes() );
|
|
dialog->setMimeFilter( mimeFilter );
|
|
if(dialog->exec()!=TQDialog::Accepted) {
|
|
delete dialog;
|
|
return;
|
|
}
|
|
KURL url( dialog->selectedURL() );
|
|
delete dialog;
|
|
|
|
if ( url.isEmpty() )
|
|
return;
|
|
|
|
(void) openDocument( url );
|
|
}
|
|
|
|
void KoMainWindow::slotFileOpenRecent( const KURL & url )
|
|
{
|
|
(void) openDocument( url );
|
|
}
|
|
|
|
void KoMainWindow::slotFileSave()
|
|
{
|
|
if ( saveDocument() )
|
|
emit documentSaved();
|
|
}
|
|
|
|
void KoMainWindow::slotFileSaveAs()
|
|
{
|
|
if ( saveDocument( true ) )
|
|
emit documentSaved();
|
|
}
|
|
|
|
void KoMainWindow::slotDocumentInfo()
|
|
{
|
|
if ( !rootDocument() )
|
|
return;
|
|
|
|
KoDocumentInfo *docInfo = rootDocument()->documentInfo();
|
|
|
|
if ( !docInfo )
|
|
return;
|
|
|
|
KoDocumentInfoDlg *dlg = new KoDocumentInfoDlg( docInfo, this, "documentInfoDlg" );
|
|
if ( dlg->exec() )
|
|
{
|
|
dlg->save();
|
|
rootDocument()->setModified( true );
|
|
rootDocument()->setTitleModified();
|
|
}
|
|
|
|
delete dlg;
|
|
}
|
|
|
|
void KoMainWindow::slotFileClose()
|
|
{
|
|
if (queryClose())
|
|
{
|
|
saveWindowSettings();
|
|
setRootDocument( 0 ); // don't delete this shell when deleting the document
|
|
delete d->m_rootDoc;
|
|
d->m_rootDoc = 0;
|
|
chooseNewDocument( KoDocument::InitDocFileClose );
|
|
}
|
|
}
|
|
|
|
void KoMainWindow::slotFileQuit()
|
|
{
|
|
close();
|
|
}
|
|
|
|
void KoMainWindow::print(bool quick) {
|
|
if ( !rootView() )
|
|
{
|
|
kdDebug(30003) << "KoMainWindow::slotFilePrint : No root view!" << endl;
|
|
return;
|
|
}
|
|
|
|
KPrinter printer( true /*, TQPrinter::HighResolution*/ );
|
|
TQString title = rootView()->koDocument()->documentInfo()->title();
|
|
TQString fileName = rootView()->koDocument()->url().fileName();
|
|
|
|
// strip off the native extension (I don't want foobar.kwd.ps when printing into a file)
|
|
KMimeType::Ptr mime = KMimeType::mimeType( rootView()->koDocument()->outputMimeType() );
|
|
if ( mime ) {
|
|
TQString extension = mime->property( "X-TDE-NativeExtension" ).toString();
|
|
|
|
if ( fileName.endsWith( extension ) )
|
|
fileName.truncate( fileName.length() - extension.length() );
|
|
}
|
|
|
|
if ( title.isEmpty() )
|
|
title = fileName;
|
|
if ( title.isEmpty() ) {
|
|
// #139905 - breaks message freeze though
|
|
//const TQString programName = instance()->aboutData() ? instance()->aboutData()->programName() : instance()->instanceName();
|
|
//title = i18n("%1 unsaved document (%2)").arg(programName).arg(TDEGlobal::locale()->formatDate(TQDate::currentDate(), true/*short*/));
|
|
}
|
|
printer.setDocName( title );
|
|
printer.setDocFileName( fileName );
|
|
printer.setDocDirectory( rootView()->koDocument()->url().directory() );
|
|
|
|
// ### TODO: apply global koffice settings here
|
|
|
|
rootView()->setupPrinter( printer );
|
|
|
|
if ( quick || printer.setup( this ) )
|
|
rootView()->print( printer );
|
|
}
|
|
|
|
|
|
void KoMainWindow::slotFilePrint()
|
|
{
|
|
print(false);
|
|
}
|
|
|
|
void KoMainWindow::slotFilePrintPreview()
|
|
{
|
|
if ( !rootView() )
|
|
{
|
|
kdWarning() << "KoMainWindow::slotFilePrint : No root view!" << endl;
|
|
return;
|
|
}
|
|
KPrinter printer( false );
|
|
KTempFile tmpFile;
|
|
// The temp file is deleted by KoPrintPreview
|
|
|
|
// This line has to be before setupPrinter to let the apps decide what to
|
|
// print and what not (if they want to :)
|
|
printer.setFromTo( printer.minPage(), printer.maxPage() );
|
|
printer.setPreviewOnly( true );
|
|
rootView()->setupPrinter( printer );
|
|
|
|
TQString oldFileName = printer.outputFileName();
|
|
printer.setOutputFileName( tmpFile.name() );
|
|
int oldNumCopies = printer.numCopies();
|
|
printer.setNumCopies( 1 );
|
|
// Disable tdeprint's own preview, we'd get two. This shows that KPrinter needs
|
|
// a "don't use the previous settings" mode. The current way is really too much of a hack.
|
|
TQString oldKDEPreview = printer.option( "kde-preview" );
|
|
printer.setOption( "kde-preview", "0" );
|
|
|
|
rootView()->print(printer);
|
|
//KoPrintPreview::preview(this, "KoPrintPreviewDialog", tmpFile.name());
|
|
|
|
// Restore previous values
|
|
printer.setOutputFileName( oldFileName );
|
|
printer.setNumCopies( oldNumCopies );
|
|
printer.setOption( "kde-preview", oldKDEPreview );
|
|
}
|
|
|
|
void KoMainWindow::slotConfigureKeys()
|
|
{
|
|
guiFactory()->configureShortcuts();
|
|
}
|
|
|
|
void KoMainWindow::slotConfigureToolbars()
|
|
{
|
|
if (rootDocument())
|
|
saveMainWindowSettings( TDEGlobal::config(), rootDocument()->instance()->instanceName() );
|
|
KEditToolbar edit(factory(), this);
|
|
connect(&edit,TQT_SIGNAL(newToolbarConfig()),this,TQT_SLOT(slotNewToolbarConfig()));
|
|
(void) edit.exec();
|
|
}
|
|
|
|
void KoMainWindow::slotNewToolbarConfig()
|
|
{
|
|
if (rootDocument())
|
|
applyMainWindowSettings( TDEGlobal::config(), rootDocument()->instance()->instanceName() );
|
|
KXMLGUIFactory *factory = guiFactory();
|
|
|
|
// Check if there's an active view
|
|
if( !d->m_activeView )
|
|
return;
|
|
|
|
// This gets plugged in even for embedded views
|
|
factory->plugActionList(d->m_activeView, "view_closeallviews",
|
|
d->m_veryHackyActionList);
|
|
|
|
// This one only for root views
|
|
if(d->m_rootViews.findRef(d->m_activeView)!=-1)
|
|
factory->plugActionList(d->m_activeView, "view_split",
|
|
d->m_splitViewActionList );
|
|
plugActionList( "toolbarlist", d->m_toolbarList );
|
|
}
|
|
|
|
void KoMainWindow::slotToolbarToggled( bool toggle )
|
|
{
|
|
//kdDebug(30003) << "KoMainWindow::slotToolbarToggled " << sender()->name() << " toggle=" << true << endl;
|
|
// The action (sender) and the toolbar have the same name
|
|
TDEToolBar * bar = toolBar( TQT_TQOBJECT(const_cast<TQT_BASE_OBJECT_NAME*>(sender()))->name() );
|
|
if (bar)
|
|
{
|
|
if (toggle)
|
|
bar->show();
|
|
else
|
|
bar->hide();
|
|
|
|
if (rootDocument())
|
|
saveMainWindowSettings( TDEGlobal::config(), rootDocument()->instance()->instanceName() );
|
|
}
|
|
else
|
|
kdWarning(30003) << "slotToolbarToggled : Toolbar " << TQT_TQOBJECT(const_cast<TQT_BASE_OBJECT_NAME*>(sender()))->name() << " not found!" << endl;
|
|
}
|
|
|
|
bool KoMainWindow::toolbarIsVisible(const char *tbName)
|
|
{
|
|
TQWidget *tb = toolBar( tbName);
|
|
return !tb->isHidden();
|
|
}
|
|
|
|
void KoMainWindow::showToolbar( const char * tbName, bool shown )
|
|
{
|
|
TQWidget * tb = toolBar( tbName );
|
|
if ( !tb )
|
|
{
|
|
kdWarning(30003) << "KoMainWindow: toolbar " << tbName << " not found." << endl;
|
|
return;
|
|
}
|
|
if ( shown )
|
|
tb->show();
|
|
else
|
|
tb->hide();
|
|
|
|
// Update the action appropriately
|
|
TQPtrListIterator<TDEAction> it( d->m_toolbarList );
|
|
for ( ; it.current() ; ++it )
|
|
if ( !strcmp( it.current()->name(), tbName ) )
|
|
{
|
|
//kdDebug(30003) << "KoMainWindow::showToolbar setChecked " << shown << endl;
|
|
static_cast<TDEToggleAction *>(it.current())->setChecked( shown );
|
|
break;
|
|
}
|
|
}
|
|
|
|
void KoMainWindow::slotSplitView() {
|
|
d->m_splitted=true;
|
|
d->m_rootViews.append(d->m_rootDoc->createView(d->m_splitter, "splitted-view"));
|
|
d->m_rootViews.current()->show();
|
|
d->m_rootViews.current()->setPartManager( d->m_manager );
|
|
d->m_manager->setActivePart( d->m_rootDoc, d->m_rootViews.current() );
|
|
d->m_removeView->setEnabled(true);
|
|
d->m_orientation->setEnabled(true);
|
|
}
|
|
|
|
void KoMainWindow::slotCloseAllViews() {
|
|
|
|
// Attention: Very touchy code... you know what you're doing? Goooood :)
|
|
d->m_forQuit=true;
|
|
if(queryClose()) {
|
|
// In case the document is embedded we close all open "extra-shells"
|
|
if(d->m_rootDoc && d->m_rootDoc->isEmbedded()) {
|
|
hide();
|
|
d->m_rootDoc->removeShell(this);
|
|
TQPtrListIterator<KoMainWindow> it(d->m_rootDoc->shells());
|
|
while (it.current()) {
|
|
it.current()->hide();
|
|
delete it.current(); // this updates the lists' current pointer and thus
|
|
// the iterator (the shell dtor calls removeShell)
|
|
d->m_rootDoc=0;
|
|
}
|
|
}
|
|
// not embedded -> destroy the document and all shells/views ;)
|
|
else
|
|
setRootDocument( 0L );
|
|
close(); // close this window (and quit the app if necessary)
|
|
}
|
|
d->m_forQuit=false;
|
|
}
|
|
|
|
void KoMainWindow::slotRemoveView() {
|
|
KoView *view;
|
|
if(d->m_rootViews.findRef(d->m_activeView)!=-1)
|
|
view=d->m_rootViews.current();
|
|
else
|
|
view=d->m_rootViews.first();
|
|
view->hide();
|
|
if ( !d->m_rootViews.removeRef(view) )
|
|
kdWarning() << "view not found in d->m_rootViews!" << endl;
|
|
|
|
if(d->m_rootViews.count()==1)
|
|
{
|
|
d->m_removeView->setEnabled(false);
|
|
d->m_orientation->setEnabled(false);
|
|
}
|
|
// Prevent the view's destroyed() signal from triggering GUI rebuilding (too early)
|
|
d->m_manager->setActivePart( 0, 0 );
|
|
|
|
delete view;
|
|
view=0L;
|
|
|
|
d->m_rootViews.first()->setPartManager( d->m_manager );
|
|
d->m_manager->setActivePart( d->m_rootDoc, d->m_rootViews.first() );
|
|
|
|
if(d->m_rootViews.count()==1)
|
|
d->m_splitted=false;
|
|
}
|
|
|
|
void KoMainWindow::slotSetOrientation() {
|
|
d->m_splitter->setOrientation(static_cast<Qt::Orientation>
|
|
(d->m_orientation->currentItem()));
|
|
}
|
|
|
|
void KoMainWindow::slotProgress(int value) {
|
|
//kdDebug(30003) << "KoMainWindow::slotProgress " << value << endl;
|
|
if(value==-1) {
|
|
if ( d->m_progress )
|
|
{
|
|
statusBar()->removeWidget(d->m_progress);
|
|
delete d->m_progress;
|
|
d->m_progress=0L;
|
|
}
|
|
d->m_firstTime=true;
|
|
return;
|
|
}
|
|
if(d->m_firstTime)
|
|
{
|
|
// The statusbar might not even be created yet.
|
|
// So check for that first, and create it if necessary
|
|
TQObjectList *l = queryList( "TQStatusBar" );
|
|
if ( !l || !l->first() ) {
|
|
statusBar()->show();
|
|
TQApplication::sendPostedEvents( TQT_TQOBJECT(this), TQEvent::ChildInserted );
|
|
setUpLayout();
|
|
}
|
|
delete l;
|
|
|
|
if ( d->m_progress )
|
|
{
|
|
statusBar()->removeWidget(d->m_progress);
|
|
delete d->m_progress;
|
|
d->m_progress=0L;
|
|
}
|
|
statusBar()->setMaximumHeight(statusBar()->height());
|
|
d->m_progress=new KProgress(statusBar());
|
|
//d->m_progress->setMaximumHeight(statusBar()->height());
|
|
statusBar()->addWidget( d->m_progress, 0, true );
|
|
d->m_progress->show();
|
|
d->m_firstTime=false;
|
|
}
|
|
d->m_progress->setProgress(value);
|
|
kapp->processEvents();
|
|
}
|
|
|
|
|
|
void KoMainWindow::slotActivePartChanged( KParts::Part *newPart )
|
|
{
|
|
|
|
// This looks very much like KParts::MainWindow::createGUI, but we have
|
|
// to reimplement it because it works with an active part, whereas we work
|
|
// with an active view _and_ an active part, depending for what.
|
|
// Both are KXMLGUIClients, but e.g. the plugin query needs a TQObject.
|
|
//kdDebug(30003) << "KoMainWindow::slotActivePartChanged( Part * newPart) newPart = " << newPart << endl;
|
|
//kdDebug(30003) << "current active part is " << d->m_activePart << endl;
|
|
|
|
if ( d->m_activePart && d->m_activePart == newPart && !d->m_splitted )
|
|
{
|
|
//kdDebug(30003) << "no need to change the GUI" << endl;
|
|
return;
|
|
}
|
|
|
|
KXMLGUIFactory *factory = guiFactory();
|
|
|
|
setUpdatesEnabled( false );
|
|
|
|
if ( d->m_activeView )
|
|
{
|
|
KParts::GUIActivateEvent ev( false );
|
|
TQApplication::sendEvent( d->m_activePart, &ev );
|
|
TQApplication::sendEvent( d->m_activeView, &ev );
|
|
|
|
|
|
factory->removeClient( d->m_activeView );
|
|
|
|
unplugActionList( "toolbarlist" );
|
|
d->m_toolbarList.clear(); // deletes the actions
|
|
}
|
|
|
|
if ( !d->bMainWindowGUIBuilt )
|
|
{
|
|
// Load mainwindow plugins
|
|
KParts::Plugin::loadPlugins( TQT_TQOBJECT(this), this, instance(), true );
|
|
createShellGUI();
|
|
}
|
|
|
|
if ( newPart && d->m_manager->activeWidget() && d->m_manager->activeWidget()->inherits( "KoView" ) )
|
|
{
|
|
d->m_activeView = (KoView *)d->m_manager->activeWidget();
|
|
d->m_activePart = newPart;
|
|
//kdDebug(30003) << "new active part is " << d->m_activePart << endl;
|
|
|
|
factory->addClient( d->m_activeView );
|
|
|
|
|
|
// This gets plugged in even for embedded views
|
|
factory->plugActionList(d->m_activeView, "view_closeallviews",
|
|
d->m_veryHackyActionList);
|
|
// This one only for root views
|
|
if(d->m_rootViews.findRef(d->m_activeView)!=-1)
|
|
factory->plugActionList(d->m_activeView, "view_split", d->m_splitViewActionList );
|
|
|
|
// Position and show toolbars according to user's preference
|
|
setAutoSaveSettings( newPart->instance()->instanceName(), false );
|
|
|
|
// Create and plug toolbar list for Settings menu
|
|
//TQPtrListIterator<TDEToolBar> it = toolBarIterator();
|
|
TQPtrList<TQWidget> toolBarList = factory->containers( "ToolBar" );
|
|
TQPtrListIterator<TQWidget> it( toolBarList );
|
|
for ( ; it.current() ; ++it )
|
|
{
|
|
if ( it.current()->inherits("TDEToolBar") )
|
|
{
|
|
TDEToolBar * tb = static_cast<TDEToolBar *>(it.current());
|
|
TDEToggleAction * act = new TDEToggleAction( i18n("Show %1 Toolbar").arg( tb->text() ), 0,
|
|
actionCollection(), tb->name() );
|
|
act->setCheckedState(i18n("Hide %1 Toolbar").arg( tb->text() ));
|
|
connect( act, TQT_SIGNAL( toggled( bool ) ), TQT_TQOBJECT(this), TQT_SLOT( slotToolbarToggled( bool ) ) );
|
|
act->setChecked ( !tb->isHidden() );
|
|
d->m_toolbarList.append( act );
|
|
}
|
|
else
|
|
kdWarning(30003) << "Toolbar list contains a " << it.current()->className() << " which is not a toolbar!" << endl;
|
|
}
|
|
plugActionList( "toolbarlist", d->m_toolbarList );
|
|
|
|
// Send the GUIActivateEvent only now, since it might show/hide toolbars too
|
|
// (and this has priority over applyMainWindowSettings)
|
|
KParts::GUIActivateEvent ev( true );
|
|
TQApplication::sendEvent( d->m_activePart, &ev );
|
|
TQApplication::sendEvent( d->m_activeView, &ev );
|
|
}
|
|
else
|
|
{
|
|
d->m_activeView = 0L;
|
|
d->m_activePart = 0L;
|
|
}
|
|
setUpdatesEnabled( true );
|
|
}
|
|
|
|
TQLabel * KoMainWindow::statusBarLabel()
|
|
{
|
|
if ( !d->statusBarLabel )
|
|
{
|
|
d->statusBarLabel = new TQLabel( statusBar() );
|
|
statusBar()->addWidget( d->statusBarLabel, 1, true );
|
|
}
|
|
return d->statusBarLabel;
|
|
}
|
|
|
|
void KoMainWindow::setMaxRecentItems(uint _number)
|
|
{
|
|
m_recent->setMaxItems( _number );
|
|
}
|
|
|
|
DCOPObject * KoMainWindow::dcopObject()
|
|
{
|
|
if ( !d->m_dcopObject )
|
|
{
|
|
d->m_dcopObject = new KoMainWindowIface( this );
|
|
}
|
|
|
|
return d->m_dcopObject;
|
|
}
|
|
|
|
void KoMainWindow::slotEmailFile()
|
|
{
|
|
if (!rootDocument())
|
|
return;
|
|
|
|
// Subject = Document file name
|
|
// Attachment = The current file
|
|
// Message Body = The current document in HTML export? <-- This may be an option.
|
|
TQString theSubject;
|
|
TQStringList urls;
|
|
TQString fileURL;
|
|
if (rootDocument()->url ().isEmpty () ||
|
|
rootDocument()->isModified())
|
|
{
|
|
//Save the file as a temporary file
|
|
bool const tmp_modified = rootDocument()->isModified();
|
|
KURL const tmp_url = rootDocument()->url();
|
|
TQCString const tmp_mimetype = rootDocument()->outputMimeType();
|
|
KTempFile tmpfile; //TODO: The temorary file should be deleted when the mail program is closed
|
|
KURL u;
|
|
u.setPath(tmpfile.name());
|
|
rootDocument()->setURL(u);
|
|
rootDocument()->setModified(true);
|
|
rootDocument()->setOutputMimeType(rootDocument()->nativeFormatMimeType());
|
|
|
|
saveDocument(false, true);
|
|
|
|
fileURL = tmpfile.name();
|
|
theSubject = i18n("Document");
|
|
urls.append( fileURL );
|
|
|
|
rootDocument()->setURL(tmp_url);
|
|
rootDocument()->setModified(tmp_modified);
|
|
rootDocument()->setOutputMimeType(tmp_mimetype);
|
|
}
|
|
else
|
|
{
|
|
fileURL = rootDocument()->url().url();
|
|
theSubject = i18n("Document - %1").arg(rootDocument()->url().fileName(false));
|
|
urls.append( fileURL );
|
|
}
|
|
|
|
kdDebug(30003) << "(" << fileURL <<")" << endl;
|
|
|
|
if (!fileURL.isEmpty())
|
|
{
|
|
kapp->invokeMailer(TQString(), TQString(), TQString(), theSubject,
|
|
TQString(), //body
|
|
TQString(),
|
|
urls); // attachments
|
|
}
|
|
}
|
|
|
|
void KoMainWindow::slotVersionsFile()
|
|
{
|
|
KoVersionDialog *dlg = new KoVersionDialog( this );
|
|
dlg->exec();
|
|
delete dlg;
|
|
}
|
|
|
|
void KoMainWindow::slotReloadFile()
|
|
{
|
|
KoDocument* pDoc = rootDocument();
|
|
if(!pDoc || pDoc->url().isEmpty() || !pDoc->isModified())
|
|
return;
|
|
|
|
bool bOk = KMessageBox::questionYesNo( this,
|
|
i18n("You will lose all your changes!\n"
|
|
"Do you want to continue?"),
|
|
i18n("Warning") ) == KMessageBox::Yes;
|
|
if ( !bOk )
|
|
return;
|
|
|
|
KURL url = pDoc->url();
|
|
if ( pDoc && !pDoc->isEmpty() )
|
|
{
|
|
setRootDocument( 0L ); // don't delete this shell when deleting the document
|
|
delete d->m_rootDoc;
|
|
d->m_rootDoc = 0L;
|
|
}
|
|
openDocument( url );
|
|
return;
|
|
|
|
}
|
|
|
|
void KoMainWindow::slotImportFile()
|
|
{
|
|
kdDebug(30003) << "slotImportFile()" << endl;
|
|
|
|
d->m_isImporting = true;
|
|
slotFileOpen();
|
|
d->m_isImporting = false;
|
|
}
|
|
|
|
void KoMainWindow::slotExportFile()
|
|
{
|
|
kdDebug(30003) << "slotExportFile()" << endl;
|
|
|
|
d->m_isExporting = true;
|
|
slotFileSaveAs();
|
|
d->m_isExporting = false;
|
|
}
|
|
|
|
bool KoMainWindow::isImporting() const
|
|
{
|
|
return d->m_isImporting;
|
|
}
|
|
|
|
bool KoMainWindow::isExporting() const
|
|
{
|
|
return d->m_isExporting;
|
|
}
|
|
|
|
void KoMainWindow::setDocToOpen( KoDocument *doc )
|
|
{
|
|
d->m_docToOpen = doc;
|
|
}
|
|
|
|
#include <KoMainWindow.moc>
|