00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <qcursor.h>
00024 #include <qsplitter.h>
00025 #include <qiconview.h>
00026 #include <qlabel.h>
00027 #include <qvbox.h>
00028
00029 #include <assert.h>
00030
00031 #include "koshell_shell.h"
00032 #include "koshellsettings.h"
00033
00034 #include <kapplication.h>
00035 #include <ktempfile.h>
00036 #include <kfiledialog.h>
00037 #include <klocale.h>
00038 #include <kdebug.h>
00039 #include <kiconloader.h>
00040 #include <kkeydialog.h>
00041 #include <kstandarddirs.h>
00042 #include <klibloader.h>
00043 #include <kpopupmenu.h>
00044 #include <kservice.h>
00045 #include <kmessagebox.h>
00046 #include <krecentdocument.h>
00047 #include <kparts/partmanager.h>
00048 #include <kaction.h>
00049 #include <kdeversion.h>
00050 #include <kaboutdata.h>
00051
00052 #include <KoQueryTrader.h>
00053 #include <KoDocumentInfo.h>
00054 #include <KoDocument.h>
00055 #include <KoView.h>
00056 #include <KoPartSelectDia.h>
00057 #include <KoFilterManager.h>
00058 #include <kiconloader.h>
00059
00060 KoShellWindow::KoShellWindow()
00061 : KoMainWindow( KGlobal::instance() )
00062 {
00063 m_activePage = m_lstPages.end();
00064
00065 m_pLayout = new QSplitter( centralWidget() );
00066
00067
00068 m_pSidebar = new IconSidePane( m_pLayout );
00069 m_pSidebar->setSizePolicy( QSizePolicy( QSizePolicy::Maximum,
00070 QSizePolicy::Preferred ) );
00071 m_pSidebar->setActionCollection( actionCollection() );
00072 m_grpFile = m_pSidebar->insertGroup(i18n("Components"), false, this, SLOT( slotSidebar_Part(int )));
00073 m_grpDocuments = m_pSidebar->insertGroup(i18n("Documents"), true, this, SLOT(slotSidebar_Document(int)));
00074 m_pLayout->setResizeMode(m_pSidebar,QSplitter::FollowSizeHint);
00075
00076
00077 m_pFrame = new KTabWidget( m_pLayout );
00078 m_pFrame->setSizePolicy( QSizePolicy( QSizePolicy::Minimum,
00079 QSizePolicy::Preferred ) );
00080 m_pFrame->setTabPosition( KTabWidget::Bottom );
00081
00082 m_tabCloseButton = new QToolButton( m_pFrame );
00083 connect( m_tabCloseButton, SIGNAL( clicked() ),
00084 this, SLOT( slotFileClose() ) );
00085 m_tabCloseButton->setIconSet( SmallIconSet( "tab_remove" ) );
00086 m_tabCloseButton->adjustSize();
00087 QToolTip::add(m_tabCloseButton, i18n("Close"));
00088 m_pFrame->setCornerWidget( m_tabCloseButton, BottomRight );
00089 m_tabCloseButton->hide();
00090
00091 QValueList<KoDocumentEntry> lstComponents = KoDocumentEntry::query(false,QString());
00092 QValueList<KoDocumentEntry>::Iterator it = lstComponents.begin();
00093 int id = 0;
00094
00095 for( ; it != lstComponents.end(); ++it )
00096 {
00097 KService* service = (*it).service();
00098 if ( !service->genericName().isEmpty() )
00099 {
00100 id = m_pSidebar->insertItem(m_grpFile, service->icon(), service->genericName());
00101 }
00102 else
00103 {
00104 continue;
00105 }
00106
00107 m_mapComponents[ id++ ] = *it;
00108 }
00109
00110 QValueList<int> list;
00111 list.append( KoShellSettings::sidebarWidth() );
00112 list.append( this->width() - KoShellSettings::sidebarWidth() );
00113 m_pLayout->setSizes( list );
00114
00115 connect( this, SIGNAL( documentSaved() ),
00116 this, SLOT( slotNewDocumentName() ) );
00117
00118 connect( m_pFrame, SIGNAL( currentChanged( QWidget* ) ),
00119 this, SLOT( slotUpdatePart( QWidget* ) ) );
00120 connect( m_pFrame, SIGNAL( contextMenu(QWidget * ,const QPoint &)), this, SLOT( tab_contextMenu(QWidget * ,const QPoint &)) );
00121
00122 m_client = new KoShellGUIClient( this );
00123 createShellGUI();
00124 }
00125
00126 KoShellWindow::~KoShellWindow()
00127 {
00128
00129
00130
00131
00132
00133 partManager()->setActivePart(0);
00134
00135
00136 QValueList<Page>::ConstIterator it = m_lstPages.begin();
00137 for (; it != m_lstPages.end(); ++it )
00138 {
00139 (*it).m_pDoc->removeShell( this );
00140 delete (*it).m_pView;
00141 if ( (*it).m_pDoc->viewCount() == 0 )
00142 delete (*it).m_pDoc;
00143 }
00144 m_lstPages.clear();
00145
00146 setRootDocumentDirect( 0L, QPtrList<KoView>() );
00147 saveSettings();
00148 }
00149
00150 bool KoShellWindow::openDocumentInternal( const KURL &url, KoDocument* )
00151 {
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167 KMimeType::Ptr mimeType = KMimeType::findByURL( url );
00168 m_documentEntry = KoDocumentEntry::queryByMimeType( mimeType->name().latin1() );
00169
00170 KTempFile* tmpFile = 0;
00171 KURL tmpUrl( url );
00172
00173 if ( m_documentEntry.isEmpty() ) {
00174 tmpFile = new KTempFile;
00175
00176 KoFilterManager *manager = new KoFilterManager( url.path() );
00177 QCString mimetype;
00178 KoFilter::ConversionStatus status = manager->exp0rt( tmpFile->name(), mimetype );
00179 delete manager;
00180
00181 if ( status != KoFilter::OK || mimetype.isEmpty() ) {
00182 tmpFile->unlink();
00183 delete tmpFile;
00184 return false;
00185 }
00186
00187
00188
00189 m_documentEntry = KoDocumentEntry::queryByMimeType( mimetype );
00190 if ( m_documentEntry.isEmpty() ) {
00191 tmpFile->unlink();
00192 delete tmpFile;
00193 return false;
00194 }
00195
00196
00197 tmpUrl.setPath( tmpFile->name() );
00198 }
00199
00200 recentAction()->addURL( url );
00201
00202 KoDocument* newdoc = m_documentEntry.createDoc();
00203
00204 connect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int)));
00205 connect(newdoc, SIGNAL(completed()), this, SLOT(slotKSLoadCompleted()));
00206 connect(newdoc, SIGNAL(canceled( const QString & )), this, SLOT(slotKSLoadCanceled( const QString & )));
00207 newdoc->addShell( this );
00208 bool openRet = (!isImporting ()) ? newdoc->openURL(tmpUrl) : newdoc->import(tmpUrl);
00209 if ( !newdoc || !openRet )
00210 {
00211 newdoc->removeShell(this);
00212 delete newdoc;
00213 if ( tmpFile ) {
00214 tmpFile->unlink();
00215 delete tmpFile;
00216 }
00217 return false;
00218 }
00219
00220 if ( tmpFile ) {
00221
00222
00223
00224
00225
00226
00227
00228 newdoc->setMimeType( mimeType->name().latin1() );
00229 newdoc->setOutputMimeType( mimeType->name().latin1() );
00230
00231
00232
00233 newdoc->setConfirmNonNativeSave(true,true);
00234 newdoc->setConfirmNonNativeSave(false,true);
00235
00236
00237 newdoc->setFile( url.path() );
00238
00239
00240 newdoc->setURL( url );
00241
00242
00243 updateCaption();
00244
00245 tmpFile->unlink();
00246 delete tmpFile;
00247 }
00248 return true;
00249 }
00250
00251 void KoShellWindow::slotSidebarItemClicked( QIconViewItem *item )
00252 {
00253
00254 if( item != 0 )
00255 {
00256 int index = item->index();
00257
00258
00259 m_documentEntry = m_mapComponents[ index ];
00260 KoDocument *doc = m_documentEntry.createDoc();
00261 if (doc)
00262 {
00263
00264
00265 if ( doc->showEmbedInitDialog( this ) )
00266 {
00267 partManager()->addPart( doc, false );
00268 setRootDocument( doc );
00269 }
00270 else
00271 delete doc;
00272 }
00273 }
00274 }
00275
00276
00277 void KoShellWindow::slotKSLoadCompleted()
00278 {
00279 KoDocument* newdoc = (KoDocument *)(sender());
00280
00281
00282
00283
00284 if (isImporting()) newdoc->resetURL ();
00285
00286 partManager()->addPart( newdoc, false );
00287 setRootDocument( newdoc );
00288 disconnect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int)));
00289 disconnect(newdoc, SIGNAL(completed()), this, SLOT(slotKSLoadCompleted()));
00290 disconnect(newdoc, SIGNAL(canceled( const QString & )), this, SLOT(slotKSLoadCanceled( const QString & )));
00291 }
00292
00293 void KoShellWindow::slotKSLoadCanceled( const QString & errMsg )
00294 {
00295 KMessageBox::error( this, errMsg );
00296
00297
00298
00299 KoDocument* newdoc = (KoDocument *)(sender());
00300 disconnect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int)));
00301 disconnect(newdoc, SIGNAL(completed()), this, SLOT(slotKSLoadCompleted()));
00302 disconnect(newdoc, SIGNAL(canceled( const QString & )), this, SLOT(slotKSLoadCanceled( const QString & )));
00303 }
00304
00305 void KoShellWindow::saveAll()
00306 {
00307 KoView *currentView = (*m_activePage).m_pView;
00308 for (QValueList<Page>::iterator it=m_lstPages.begin(); it != m_lstPages.end(); ++it)
00309 {
00310 if ( (*it).m_pDoc->isModified() )
00311 {
00312 m_pFrame->showPage( (*it).m_pView );
00313 (*it).m_pView->shell()->slotFileSave();
00314 if ( (*it).m_pDoc->isModified() )
00315 break;
00316 }
00317 }
00318 m_pFrame->showPage( currentView );
00319 }
00320
00321 void KoShellWindow::setRootDocument( KoDocument * doc )
00322 {
00323 kdDebug() << "KoShellWindow::setRootDocument this=" << this << " doc=" << doc << endl;
00324
00325
00326
00327
00328
00329 if ( doc )
00330 {
00331 if ( !doc->shells().contains( this ) )
00332 doc->addShell( this );
00333
00334 KoView *v = doc->createView(this);
00335 QPtrList<KoView> views;
00336 views.append(v);
00337 setRootDocumentDirect( doc, views );
00338
00339 v->setGeometry( 0, 0, m_pFrame->width(), m_pFrame->height() );
00340 v->setPartManager( partManager() );
00341 m_pFrame->addTab( v, KGlobal::iconLoader()->loadIcon( m_documentEntry.service()->icon(), KIcon::Small ), i18n("Untitled") );
00342
00343
00344 Page page;
00345 page.m_pDoc = doc;
00346 page.m_pView = v;
00347
00348 page.m_id = m_pSidebar->insertItem( m_grpDocuments,
00349 m_documentEntry.service()->icon(),
00350 i18n("Untitled"));
00351 m_lstPages.append( page );
00352 v->show();
00353
00354 switchToPage( m_lstPages.fromLast() );
00355 mnuSaveAll->setEnabled(true);
00356 } else
00357 {
00358 setRootDocumentDirect( 0L, QPtrList<KoView>() );
00359 m_activePage = m_lstPages.end();
00360 KoMainWindow::updateCaption();
00361 }
00362 }
00363
00364 void KoShellWindow::slotNewDocumentName()
00365 {
00366 updateCaption();
00367 }
00368
00369 void KoShellWindow::updateCaption()
00370 {
00371
00372 KoMainWindow::updateCaption();
00373
00374
00375 QValueList<Page>::Iterator it = m_lstPages.begin();
00376 for( ; it != m_lstPages.end() ; ++it )
00377 {
00378 if ( (*it).m_pDoc == rootDocument() )
00379 {
00380
00381
00382 QString name;
00383 if ( rootDocument()->documentInfo() )
00384 {
00385 name = rootDocument()->documentInfo()->title();
00386 }
00387 if ( name.isEmpty() )
00388
00389 name = rootDocument()->url().fileName();
00390
00391 if ( !name.isEmpty() )
00392 {
00393 if ( name.length() > 20 )
00394 {
00395 name.truncate( 17 );
00396 name += "...";
00397 }
00398 m_pFrame->changeTab( m_pFrame->currentPage(), name );
00399 m_pSidebar->renameItem(m_grpDocuments, (*m_activePage).m_id, name);
00400 }
00401
00402 return;
00403 }
00404 }
00405 }
00406
00407
00408 void KoShellWindow::slotSidebar_Part(int _item)
00409 {
00410
00411 kapp->setOverrideCursor( QCursor(Qt::WaitCursor) );
00412 m_documentEntry = m_mapComponents[ _item ];
00413 kdDebug() << m_documentEntry.service() << endl;
00414 kdDebug() << m_documentEntry.name() << endl;
00415 KoDocument *doc = m_documentEntry.createDoc();
00416 kapp->restoreOverrideCursor();
00417 if (doc)
00418 {
00419 if ( doc->showEmbedInitDialog( this ) )
00420 {
00421 partManager()->addPart( doc, false );
00422 setRootDocument( doc );
00423 m_tabCloseButton->show();
00424 }
00425 else
00426 delete doc;
00427 }
00428 }
00429
00430 void KoShellWindow::slotSidebar_Document(int _item)
00431 {
00432
00433 if ( m_activePage != m_lstPages.end() &&
00434 (*m_activePage).m_id == _item )
00435 return;
00436
00437 QValueList<Page>::Iterator it = m_lstPages.begin();
00438 while( it != m_lstPages.end() )
00439 {
00440 if ( (*it).m_id == _item )
00441 {
00442 switchToPage( it );
00443 return;
00444 }
00445 ++it;
00446 }
00447 }
00448
00449 void KoShellWindow::slotShowSidebar()
00450 {
00451 if( m_pSidebar->isShown() )
00452 {
00453 m_pSidebar->hide();
00454 m_pComponentsLabel->hide();
00455 }
00456 else
00457 {
00458 m_pSidebar->show();
00459 m_pComponentsLabel->show();
00460 }
00461 }
00462
00463 void KoShellWindow::slotUpdatePart( QWidget* widget )
00464 {
00465 KoView* v = dynamic_cast<KoView*>(widget);
00466 if ( v != 0 )
00467 {
00468 QValueList<Page>::Iterator it = m_lstPages.begin();
00469 for( ; it != m_lstPages.end(); ++it )
00470 {
00471 if( (*it).m_pView == v )
00472 switchToPage(it);
00473 }
00474 }
00475 }
00476
00477 void KoShellWindow::switchToPage( QValueList<Page>::Iterator it )
00478 {
00479
00480 m_activePage = it;
00481 KoView *v = (*m_activePage).m_pView;
00482
00483 kdDebug() << " setting active part to " << (*m_activePage).m_pDoc << endl;
00484
00485 partManager()->setActivePart( (*m_activePage).m_pDoc, v );
00486
00487 QPtrList<KoView> views;
00488 views.append(v);
00489 setRootDocumentDirect( (*m_activePage).m_pDoc, views );
00490
00491 m_pSidebar->group(m_grpDocuments)->setSelected((*m_activePage).m_id,true);
00492
00493 m_pFrame->showPage( v );
00494
00495 updateCaption();
00496 v->setFocus();
00497
00498 partSpecificHelpAction->setEnabled(true);
00499 partSpecificHelpAction->setText(i18n("%1 Handbook").arg((*m_activePage).m_pDoc->instance()->aboutData()->programName()));
00500 }
00501
00502 void KoShellWindow::slotFileNew()
00503 {
00504 m_documentEntry = KoPartSelectDia::selectPart( this );
00505 if ( m_documentEntry.isEmpty() )
00506 return;
00507 KoDocument* newdoc = m_documentEntry.createDoc();
00508 if ( !newdoc )
00509 return;
00510 if ( !newdoc->showEmbedInitDialog( this ) )
00511 {
00512 delete newdoc;
00513 return;
00514 }
00515
00516 partManager()->addPart( newdoc, false );
00517 setRootDocument( newdoc );
00518 m_tabCloseButton->show();
00519 }
00520
00521 void KoShellWindow::slotFileOpen()
00522 {
00523 KFileDialog *dialog=new KFileDialog(QString::null, QString::null, 0L, "file dialog", true);
00524 if (!isImporting())
00525 dialog->setCaption( i18n("Open Document") );
00526 else
00527 dialog->setCaption( i18n("Import Document") );
00528 dialog->setMimeFilter( KoFilterManager::mimeFilter() );
00529
00530 KURL url;
00531 if(dialog->exec()==QDialog::Accepted) {
00532 url=dialog->selectedURL();
00533 recentAction()->addURL( url );
00534 if ( url.isLocalFile() )
00535 KRecentDocument::add(url.path(-1));
00536 else
00537 KRecentDocument::add(url.url(-1), true);
00538 }
00539 else
00540 return;
00541
00542 delete dialog;
00543 if ( url.isEmpty() )
00544 return;
00545
00546 (void) openDocumentInternal( url );
00547 m_tabCloseButton->show();
00548 }
00549
00550 void KoShellWindow::slotFileClose()
00551 {
00552
00553
00554
00555 if ( m_lstPages.count() == 0 )
00556 close();
00557 else
00558 closeDocument();
00559
00560 if ( m_pFrame->count() == 0 )
00561 m_tabCloseButton->hide();
00562 }
00563
00564 void KoShellWindow::closeDocument()
00565 {
00566
00567 assert( m_activePage != m_lstPages.end() );
00568 assert( rootDocument() == (*m_activePage).m_pDoc );
00569
00570
00571 kdDebug() << "KoShellWindow::closeDocument calling standard queryClose" << endl;
00572 if ( KoMainWindow::queryClose() )
00573 {
00574 kdDebug() << "Ok for closing document" << endl;
00575 m_pSidebar->removeItem(m_grpDocuments, (*m_activePage).m_id );
00576 (*m_activePage).m_pDoc->removeShell(this);
00577 Page oldPage = (*m_activePage);
00578 m_lstPages.remove( m_activePage );
00579 m_activePage = m_lstPages.end();
00580 m_pSidebar->group(m_grpDocuments)->setSelected((*m_activePage).m_id, true);
00581
00582 kdDebug() << "m_lstPages has " << m_lstPages.count() << " documents" << endl;
00583 if ( m_lstPages.count() > 0 )
00584 {
00585 kdDebug() << "Activate the document behind" << endl;
00586 switchToPage( m_lstPages.fromLast() );
00587 }
00588 else
00589 {
00590 kdDebug() << "Revert to initial state (no docs)" << endl;
00591 setRootDocument( 0L );
00592 partManager()->setActivePart( 0L, 0L );
00593 mnuSaveAll->setEnabled(false);
00594 partSpecificHelpAction->setEnabled(false);
00595 partSpecificHelpAction->setText(i18n("Part Handbook"));
00596 }
00597
00598
00599
00600
00601 delete oldPage.m_pView;
00602 if ( oldPage.m_pDoc->viewCount() <= 1 )
00603 delete oldPage.m_pDoc;
00604
00605 }
00606 kdDebug() << "m_lstPages has " << m_lstPages.count() << " documents" << endl;
00607 }
00608
00609 bool KoShellWindow::queryClose()
00610 {
00611
00612 QPtrList<KoView> currentViews;
00613 KoDocument * currentDoc = 0L;
00614 bool ok = true;
00615 if (m_activePage != m_lstPages.end())
00616 {
00617 currentDoc = (*m_activePage).m_pDoc;
00618 currentViews.append((*m_activePage).m_pView);
00619
00620
00621
00622 QValueList<Page>::Iterator it = m_lstPages.begin();
00623 for( ; it != m_lstPages.end(); ++it )
00624 {
00625
00626
00627 setRootDocumentDirect( (*it).m_pDoc, QPtrList<KoView>() );
00628
00629 if ( !KoMainWindow::queryClose() )
00630 {
00631 ok = false;
00632 break;
00633 }
00634 }
00635
00636
00637 setRootDocumentDirect( currentDoc, currentViews );
00638 }
00639 return ok;
00640 }
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651 void KoShellWindow::saveSettings()
00652 {
00653 KoShellSettings::setSidebarWidth( m_pLayout->sizes().first() );
00654 KoShellSettings::writeConfig();
00655 }
00656
00657 QString KoShellWindow::configFile() const
00658 {
00659
00660 return QString::null;
00661 }
00662
00663 void KoShellWindow::tab_contextMenu(QWidget * w,const QPoint &p)
00664 {
00665 KPopupMenu menu;
00666 KIconLoader il;
00667 int const mnuSave = menu.insertItem( il.loadIconSet( "filesave", KIcon::Small ), i18n("Save") );
00668 int const mnuClose = menu.insertItem( il.loadIcon( "fileclose", KIcon::Small ), i18n("Close") );
00669
00670 int tabnr = m_pFrame->indexOf( w );
00671 Page page = m_lstPages[tabnr];
00672
00673 if ( !page.m_pDoc->isModified() )
00674 menu.setItemEnabled( mnuSave, false );
00675
00676
00677 int const choice = menu.exec(p);
00678
00679 if( choice == mnuClose )
00680 {
00681 const int index = m_pFrame->currentPageIndex();
00682 m_pFrame->setCurrentPage( tabnr );
00683 slotFileClose();
00684 if ( index > m_pFrame->currentPageIndex() )
00685 m_pFrame->setCurrentPage(index-1);
00686 else
00687 m_pFrame->setCurrentPage(index);
00688 }
00689 else if ( choice == mnuSave )
00690 {
00691 page.m_pView->shell()->slotFileSave();
00692 }
00693 }
00694
00695 void KoShellWindow::slotConfigureKeys()
00696 {
00697 KoView *view = rootView();
00698 KKeyDialog dlg( this );
00699 dlg.insert( actionCollection() );
00700 if ( view )
00701 dlg.insert( view->actionCollection() );
00702 if ( rootDocument() )
00703 dlg.insert( rootDocument()->actionCollection() );
00704 dlg.configure();
00705 }
00706
00707 void KoShellWindow::createShellGUI( bool )
00708 {
00709 guiFactory()->addClient( m_client );
00710 }
00711
00712 void KoShellWindow::showPartSpecificHelp()
00713 {
00714 if((m_activePage == m_lstPages.end()) || ((*m_activePage).m_pDoc == 0))
00715 return;
00716
00717 kapp->invokeHelp("", (*m_activePage).m_pDoc->instance()->aboutData()->appName(), "");
00718 }
00719
00720
00722 KoShellGUIClient::KoShellGUIClient( KoShellWindow *window ) : KXMLGUIClient()
00723 {
00724 setXMLFile( "koshellui.rc", true, true );
00725 window->mnuSaveAll = new KAction( i18n("Save All"), 0, window, SLOT( saveAll() ), actionCollection(), "save_all" );
00726 window->mnuSaveAll->setEnabled(false);
00727 window->partSpecificHelpAction = new KAction(i18n("Part Handbook"), "contents", 0, window, SLOT(showPartSpecificHelp()),
00728 actionCollection(), "partSpecificHelp");
00729 window->partSpecificHelpAction->setEnabled(false);
00730 }
00731
00732 #include "koshell_shell.moc"