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 if ( !newdoc ) {
00204 if ( tmpFile ) {
00205 tmpFile->unlink();
00206 delete tmpFile;
00207 }
00208 return false;
00209 }
00210
00211 connect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int)));
00212 connect(newdoc, SIGNAL(completed()), this, SLOT(slotKSLoadCompleted()));
00213 connect(newdoc, SIGNAL(canceled( const QString & )), this, SLOT(slotKSLoadCanceled( const QString & )));
00214 newdoc->addShell( this );
00215 bool openRet = (!isImporting ()) ? newdoc->openURL(tmpUrl) : newdoc->import(tmpUrl);
00216 if ( !openRet )
00217 {
00218 newdoc->removeShell(this);
00219 delete newdoc;
00220 if ( tmpFile ) {
00221 tmpFile->unlink();
00222 delete tmpFile;
00223 }
00224 return false;
00225 }
00226
00227 if ( tmpFile ) {
00228
00229
00230
00231
00232
00233
00234
00235 newdoc->setMimeType( mimeType->name().latin1() );
00236 newdoc->setOutputMimeType( mimeType->name().latin1() );
00237
00238
00239
00240 newdoc->setConfirmNonNativeSave(true,true);
00241 newdoc->setConfirmNonNativeSave(false,true);
00242
00243
00244 newdoc->setFile( url.path() );
00245
00246
00247 newdoc->setURL( url );
00248
00249
00250 updateCaption();
00251
00252 tmpFile->unlink();
00253 delete tmpFile;
00254 }
00255 return true;
00256 }
00257
00258 void KoShellWindow::slotSidebarItemClicked( QIconViewItem *item )
00259 {
00260
00261 if( item != 0 )
00262 {
00263 int index = item->index();
00264
00265
00266 m_documentEntry = m_mapComponents[ index ];
00267 KoDocument *doc = m_documentEntry.createDoc();
00268 if (doc)
00269 {
00270
00271
00272 if ( doc->showEmbedInitDialog( this ) )
00273 {
00274 partManager()->addPart( doc, false );
00275 setRootDocument( doc );
00276 }
00277 else
00278 delete doc;
00279 }
00280 }
00281 }
00282
00283
00284 void KoShellWindow::slotKSLoadCompleted()
00285 {
00286 KoDocument* newdoc = (KoDocument *)(sender());
00287
00288
00289
00290
00291 if (isImporting()) newdoc->resetURL ();
00292
00293 partManager()->addPart( newdoc, false );
00294 setRootDocument( newdoc );
00295 disconnect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int)));
00296 disconnect(newdoc, SIGNAL(completed()), this, SLOT(slotKSLoadCompleted()));
00297 disconnect(newdoc, SIGNAL(canceled( const QString & )), this, SLOT(slotKSLoadCanceled( const QString & )));
00298 }
00299
00300 void KoShellWindow::slotKSLoadCanceled( const QString & errMsg )
00301 {
00302 KMessageBox::error( this, errMsg );
00303
00304
00305
00306 KoDocument* newdoc = (KoDocument *)(sender());
00307 disconnect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int)));
00308 disconnect(newdoc, SIGNAL(completed()), this, SLOT(slotKSLoadCompleted()));
00309 disconnect(newdoc, SIGNAL(canceled( const QString & )), this, SLOT(slotKSLoadCanceled( const QString & )));
00310 }
00311
00312 void KoShellWindow::saveAll()
00313 {
00314 KoView *currentView = (*m_activePage).m_pView;
00315 for (QValueList<Page>::iterator it=m_lstPages.begin(); it != m_lstPages.end(); ++it)
00316 {
00317 if ( (*it).m_pDoc->isModified() )
00318 {
00319 m_pFrame->showPage( (*it).m_pView );
00320 (*it).m_pView->shell()->slotFileSave();
00321 if ( (*it).m_pDoc->isModified() )
00322 break;
00323 }
00324 }
00325 m_pFrame->showPage( currentView );
00326 }
00327
00328 void KoShellWindow::setRootDocument( KoDocument * doc )
00329 {
00330 kdDebug() << "KoShellWindow::setRootDocument this=" << this << " doc=" << doc << endl;
00331
00332
00333
00334
00335
00336 if ( doc )
00337 {
00338 if ( !doc->shells().contains( this ) )
00339 doc->addShell( this );
00340
00341 KoView *v = doc->createView(this);
00342 QPtrList<KoView> views;
00343 views.append(v);
00344 setRootDocumentDirect( doc, views );
00345
00346 v->setGeometry( 0, 0, m_pFrame->width(), m_pFrame->height() );
00347 v->setPartManager( partManager() );
00348 m_pFrame->addTab( v, KGlobal::iconLoader()->loadIcon( m_documentEntry.service()->icon(), KIcon::Small ), i18n("Untitled") );
00349
00350
00351 Page page;
00352 page.m_pDoc = doc;
00353 page.m_pView = v;
00354
00355 page.m_id = m_pSidebar->insertItem( m_grpDocuments,
00356 m_documentEntry.service()->icon(),
00357 i18n("Untitled"));
00358 m_lstPages.append( page );
00359 v->show();
00360
00361 switchToPage( m_lstPages.fromLast() );
00362 mnuSaveAll->setEnabled(true);
00363 } else
00364 {
00365 setRootDocumentDirect( 0L, QPtrList<KoView>() );
00366 m_activePage = m_lstPages.end();
00367 KoMainWindow::updateCaption();
00368 }
00369 }
00370
00371 void KoShellWindow::slotNewDocumentName()
00372 {
00373 updateCaption();
00374 }
00375
00376 void KoShellWindow::updateCaption()
00377 {
00378
00379 KoMainWindow::updateCaption();
00380
00381
00382 QValueList<Page>::Iterator it = m_lstPages.begin();
00383 for( ; it != m_lstPages.end() ; ++it )
00384 {
00385 if ( (*it).m_pDoc == rootDocument() )
00386 {
00387
00388
00389 QString name;
00390 if ( rootDocument()->documentInfo() )
00391 {
00392 name = rootDocument()->documentInfo()->title();
00393 }
00394 if ( name.isEmpty() )
00395
00396 name = rootDocument()->url().fileName();
00397
00398 if ( !name.isEmpty() )
00399 {
00400 if ( name.length() > 20 )
00401 {
00402 name.truncate( 17 );
00403 name += "...";
00404 }
00405 m_pFrame->changeTab( m_pFrame->currentPage(), name );
00406 m_pSidebar->renameItem(m_grpDocuments, (*m_activePage).m_id, name);
00407 }
00408
00409 return;
00410 }
00411 }
00412 }
00413
00414
00415 void KoShellWindow::slotSidebar_Part(int _item)
00416 {
00417
00418 kapp->setOverrideCursor( QCursor(Qt::WaitCursor) );
00419 m_documentEntry = m_mapComponents[ _item ];
00420 kdDebug() << m_documentEntry.service() << endl;
00421 kdDebug() << m_documentEntry.name() << endl;
00422 KoDocument *doc = m_documentEntry.createDoc();
00423 kapp->restoreOverrideCursor();
00424 if (doc)
00425 {
00426 if ( doc->showEmbedInitDialog( this ) )
00427 {
00428 partManager()->addPart( doc, false );
00429 setRootDocument( doc );
00430 m_tabCloseButton->show();
00431 }
00432 else
00433 delete doc;
00434 }
00435 }
00436
00437 void KoShellWindow::slotSidebar_Document(int _item)
00438 {
00439
00440 if ( m_activePage != m_lstPages.end() &&
00441 (*m_activePage).m_id == _item )
00442 return;
00443
00444 QValueList<Page>::Iterator it = m_lstPages.begin();
00445 while( it != m_lstPages.end() )
00446 {
00447 if ( (*it).m_id == _item )
00448 {
00449 switchToPage( it );
00450 return;
00451 }
00452 ++it;
00453 }
00454 }
00455
00456 void KoShellWindow::slotShowSidebar()
00457 {
00458 if( m_pSidebar->isShown() )
00459 {
00460 m_pSidebar->hide();
00461 m_pComponentsLabel->hide();
00462 }
00463 else
00464 {
00465 m_pSidebar->show();
00466 m_pComponentsLabel->show();
00467 }
00468 }
00469
00470 void KoShellWindow::slotUpdatePart( QWidget* widget )
00471 {
00472 KoView* v = dynamic_cast<KoView*>(widget);
00473 if ( v != 0 )
00474 {
00475 QValueList<Page>::Iterator it = m_lstPages.begin();
00476 for( ; it != m_lstPages.end(); ++it )
00477 {
00478 if( (*it).m_pView == v )
00479 switchToPage(it);
00480 }
00481 }
00482 }
00483
00484 void KoShellWindow::switchToPage( QValueList<Page>::Iterator it )
00485 {
00486
00487 m_activePage = it;
00488 KoView *v = (*m_activePage).m_pView;
00489
00490 kdDebug() << " setting active part to " << (*m_activePage).m_pDoc << endl;
00491
00492 partManager()->setActivePart( (*m_activePage).m_pDoc, v );
00493
00494 QPtrList<KoView> views;
00495 views.append(v);
00496 setRootDocumentDirect( (*m_activePage).m_pDoc, views );
00497
00498 m_pSidebar->group(m_grpDocuments)->setSelected((*m_activePage).m_id,true);
00499
00500 m_pFrame->showPage( v );
00501
00502 updateCaption();
00503 v->setFocus();
00504
00505 partSpecificHelpAction->setEnabled(true);
00506 partSpecificHelpAction->setText(i18n("%1 Handbook").arg((*m_activePage).m_pDoc->instance()->aboutData()->programName()));
00507 }
00508
00509 void KoShellWindow::slotFileNew()
00510 {
00511 m_documentEntry = KoPartSelectDia::selectPart( this );
00512 if ( m_documentEntry.isEmpty() )
00513 return;
00514 KoDocument* newdoc = m_documentEntry.createDoc();
00515 if ( !newdoc )
00516 return;
00517 if ( !newdoc->showEmbedInitDialog( this ) )
00518 {
00519 delete newdoc;
00520 return;
00521 }
00522
00523 partManager()->addPart( newdoc, false );
00524 setRootDocument( newdoc );
00525 m_tabCloseButton->show();
00526 }
00527
00528 void KoShellWindow::slotFileOpen()
00529 {
00530 KFileDialog *dialog=new KFileDialog(QString::null, QString::null, 0L, "file dialog", true);
00531 if (!isImporting())
00532 dialog->setCaption( i18n("Open Document") );
00533 else
00534 dialog->setCaption( i18n("Import Document") );
00535 dialog->setMimeFilter( KoFilterManager::mimeFilter() );
00536
00537 KURL url;
00538 if(dialog->exec()==QDialog::Accepted) {
00539 url=dialog->selectedURL();
00540 recentAction()->addURL( url );
00541 if ( url.isLocalFile() )
00542 KRecentDocument::add(url.path(-1));
00543 else
00544 KRecentDocument::add(url.url(-1), true);
00545 }
00546 else
00547 return;
00548
00549 delete dialog;
00550 if ( url.isEmpty() )
00551 return;
00552
00553 (void) openDocumentInternal( url );
00554 m_tabCloseButton->show();
00555 }
00556
00557 void KoShellWindow::slotFileClose()
00558 {
00559
00560
00561
00562 if ( m_lstPages.count() == 0 )
00563 close();
00564 else
00565 closeDocument();
00566
00567 if ( m_pFrame->count() == 0 )
00568 m_tabCloseButton->hide();
00569 }
00570
00571 void KoShellWindow::closeDocument()
00572 {
00573
00574 assert( m_activePage != m_lstPages.end() );
00575 assert( rootDocument() == (*m_activePage).m_pDoc );
00576
00577
00578 kdDebug() << "KoShellWindow::closeDocument calling standard queryClose" << endl;
00579 if ( KoMainWindow::queryClose() )
00580 {
00581 kdDebug() << "Ok for closing document" << endl;
00582 m_pSidebar->removeItem(m_grpDocuments, (*m_activePage).m_id );
00583 (*m_activePage).m_pDoc->removeShell(this);
00584 Page oldPage = (*m_activePage);
00585 m_lstPages.remove( m_activePage );
00586 m_activePage = m_lstPages.end();
00587 m_pSidebar->group(m_grpDocuments)->setSelected((*m_activePage).m_id, true);
00588
00589 kdDebug() << "m_lstPages has " << m_lstPages.count() << " documents" << endl;
00590 if ( m_lstPages.count() > 0 )
00591 {
00592 kdDebug() << "Activate the document behind" << endl;
00593 switchToPage( m_lstPages.fromLast() );
00594 }
00595 else
00596 {
00597 kdDebug() << "Revert to initial state (no docs)" << endl;
00598 setRootDocument( 0L );
00599 partManager()->setActivePart( 0L, 0L );
00600 mnuSaveAll->setEnabled(false);
00601 partSpecificHelpAction->setEnabled(false);
00602 partSpecificHelpAction->setText(i18n("Part Handbook"));
00603 }
00604
00605
00606
00607
00608 delete oldPage.m_pView;
00609 if ( oldPage.m_pDoc->viewCount() <= 1 )
00610 delete oldPage.m_pDoc;
00611
00612 }
00613 kdDebug() << "m_lstPages has " << m_lstPages.count() << " documents" << endl;
00614 }
00615
00616 bool KoShellWindow::queryClose()
00617 {
00618
00619 QPtrList<KoView> currentViews;
00620 KoDocument * currentDoc = 0L;
00621 bool ok = true;
00622 if (m_activePage != m_lstPages.end())
00623 {
00624 currentDoc = (*m_activePage).m_pDoc;
00625 currentViews.append((*m_activePage).m_pView);
00626
00627
00628
00629 QValueList<Page>::Iterator it = m_lstPages.begin();
00630 for( ; it != m_lstPages.end(); ++it )
00631 {
00632
00633
00634 setRootDocumentDirect( (*it).m_pDoc, QPtrList<KoView>() );
00635
00636 if ( !KoMainWindow::queryClose() )
00637 {
00638 ok = false;
00639 break;
00640 }
00641 }
00642
00643
00644 setRootDocumentDirect( currentDoc, currentViews );
00645 }
00646 return ok;
00647 }
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658 void KoShellWindow::saveSettings()
00659 {
00660 KoShellSettings::setSidebarWidth( m_pLayout->sizes().first() );
00661 KoShellSettings::writeConfig();
00662 }
00663
00664 QString KoShellWindow::configFile() const
00665 {
00666
00667 return QString::null;
00668 }
00669
00670 void KoShellWindow::tab_contextMenu(QWidget * w,const QPoint &p)
00671 {
00672 KPopupMenu menu;
00673 KIconLoader il;
00674 int const mnuSave = menu.insertItem( il.loadIconSet( "filesave", KIcon::Small ), i18n("Save") );
00675 int const mnuClose = menu.insertItem( il.loadIcon( "fileclose", KIcon::Small ), i18n("Close") );
00676
00677 int tabnr = m_pFrame->indexOf( w );
00678 Page page = m_lstPages[tabnr];
00679
00680 if ( !page.m_pDoc->isModified() )
00681 menu.setItemEnabled( mnuSave, false );
00682
00683
00684 int const choice = menu.exec(p);
00685
00686 if( choice == mnuClose )
00687 {
00688 const int index = m_pFrame->currentPageIndex();
00689 m_pFrame->setCurrentPage( tabnr );
00690 slotFileClose();
00691 if ( index > m_pFrame->currentPageIndex() )
00692 m_pFrame->setCurrentPage(index-1);
00693 else
00694 m_pFrame->setCurrentPage(index);
00695 }
00696 else if ( choice == mnuSave )
00697 {
00698 page.m_pView->shell()->slotFileSave();
00699 }
00700 }
00701
00702 void KoShellWindow::slotConfigureKeys()
00703 {
00704 KoView *view = rootView();
00705 KKeyDialog dlg( this );
00706 dlg.insert( actionCollection() );
00707 if ( view )
00708 dlg.insert( view->actionCollection() );
00709 if ( rootDocument() )
00710 dlg.insert( rootDocument()->actionCollection() );
00711 dlg.configure();
00712 }
00713
00714 void KoShellWindow::createShellGUI( bool )
00715 {
00716 guiFactory()->addClient( m_client );
00717 }
00718
00719 void KoShellWindow::showPartSpecificHelp()
00720 {
00721 if((m_activePage == m_lstPages.end()) || ((*m_activePage).m_pDoc == 0))
00722 return;
00723
00724 kapp->invokeHelp("", (*m_activePage).m_pDoc->instance()->aboutData()->appName(), "");
00725 }
00726
00727
00729 KoShellGUIClient::KoShellGUIClient( KoShellWindow *window ) : KXMLGUIClient()
00730 {
00731 setXMLFile( "koshellui.rc", true, true );
00732 window->mnuSaveAll = new KAction( i18n("Save All"), 0, window, SLOT( saveAll() ), actionCollection(), "save_all" );
00733 window->mnuSaveAll->setEnabled(false);
00734 window->partSpecificHelpAction = new KAction(i18n("Part Handbook"), "contents", 0, window, SLOT(showPartSpecificHelp()),
00735 actionCollection(), "partSpecificHelp");
00736 window->partSpecificHelpAction->setEnabled(false);
00737 }
00738
00739 #include "koshell_shell.moc"