koshell

koshell_shell.cpp
1/* This file is part of the KDE project
2 Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3 Copyright (C) 1999 Simon Hausmann <hausmann@kde.org>
4 Copyright (C) 2000-2005 David Faure <faure@kde.org>
5 Copyright (C) 2005, 2006 Sven Lüppken <sven@kde.org>
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21*/
22
23#include <tqcursor.h>
24#include <tqsplitter.h>
25#include <tqiconview.h>
26#include <tqlabel.h>
27#include <tqvbox.h>
28
29#include <assert.h>
30
31#include "koshell_shell.h"
32#include "koshellsettings.h"
33
34#include <tdeapplication.h>
35#include <tdetempfile.h>
36#include <tdefiledialog.h>
37#include <tdelocale.h>
38#include <kdebug.h>
39#include <kiconloader.h>
40#include <kkeydialog.h>
41#include <kstandarddirs.h>
42#include <klibloader.h>
43#include <tdepopupmenu.h>
44#include <kservice.h>
45#include <tdemessagebox.h>
46#include <tderecentdocument.h>
47#include <tdeparts/partmanager.h>
48#include <tdeaction.h>
49#include <tdeaboutdata.h>
50
51#include <KoQueryTrader.h>
52#include <KoDocumentInfo.h>
53#include <KoDocument.h>
54#include <KoView.h>
55#include <KoPartSelectDia.h>
56#include <KoFilterManager.h>
57#include <kiconloader.h>
58
59KoShellWindow::KoShellWindow()
60 : KoMainWindow( TDEGlobal::instance() )
61{
62 m_activePage = m_lstPages.end();
63
64 m_pLayout = new TQSplitter( centralWidget() );
65
66 // Setup the sidebar
67 m_pSidebar = new IconSidePane( m_pLayout );
68 m_pSidebar->setSizePolicy( TQSizePolicy( TQSizePolicy::Maximum,
69 TQSizePolicy::Preferred ) );
70 m_pSidebar->setActionCollection( actionCollection() );
71 m_grpFile = m_pSidebar->insertGroup(i18n("Components"), false, this, TQ_SLOT( slotSidebar_Part(int )));
72 m_grpDocuments = m_pSidebar->insertGroup(i18n("Documents"), true, this, TQ_SLOT(slotSidebar_Document(int)));
73 m_pLayout->setResizeMode(m_pSidebar,TQSplitter::FollowSizeHint);
74
75 // Setup the tabbar
76 m_pFrame = new KTabWidget( m_pLayout );
77 m_pFrame->setSizePolicy( TQSizePolicy( TQSizePolicy::Minimum,
78 TQSizePolicy::Preferred ) );
79 m_pFrame->setTabPosition( KTabWidget::Bottom );
80
81 m_tabCloseButton = new TQToolButton( m_pFrame );
82 connect( m_tabCloseButton, TQ_SIGNAL( clicked() ),
83 this, TQ_SLOT( slotFileClose() ) );
84 m_tabCloseButton->setIconSet( SmallIconSet( "tab_remove" ) );
85 m_tabCloseButton->adjustSize();
86 TQToolTip::add(m_tabCloseButton, i18n("Close"));
87 m_pFrame->setCornerWidget( m_tabCloseButton, BottomRight );
88 m_tabCloseButton->hide();
89
90 TQValueList<KoDocumentEntry> lstComponents = KoDocumentEntry::query(false,TQString());
91 TQValueList<KoDocumentEntry>::Iterator it = lstComponents.begin();
92 int id = 0;
93 // Get all available components
94 for( ; it != lstComponents.end(); ++it )
95 {
96 KService* service = (*it).service();
97 if ( !service->genericName().isEmpty() )
98 {
99 id = m_pSidebar->insertItem(m_grpFile, service->icon(), service->genericName());
100 }
101 else
102 {
103 continue;
104 }
105
106 m_mapComponents[ id++ ] = *it;
107 }
108
109 TQValueList<int> list;
110 list.append( KoShellSettings::sidebarWidth() );
111 list.append( this->width() - KoShellSettings::sidebarWidth() );
112 m_pLayout->setSizes( list );
113
114 connect( this, TQ_SIGNAL( documentSaved() ),
115 this, TQ_SLOT( slotNewDocumentName() ) );
116
117 connect( m_pFrame, TQ_SIGNAL( currentChanged( TQWidget* ) ),
118 this, TQ_SLOT( slotUpdatePart( TQWidget* ) ) );
119 connect( m_pFrame, TQ_SIGNAL( contextMenu(TQWidget * ,const TQPoint &)), this, TQ_SLOT( tab_contextMenu(TQWidget * ,const TQPoint &)) );
120
121 m_client = new KoShellGUIClient( this );
122 createShellGUI();
123}
124
125KoShellWindow::~KoShellWindow()
126{
127 //kdDebug() << "KoShellWindow::~KoShellWindow()" << endl;
128
129 // Set the active part to 0 (as we do in ~KoMainWindow, but this is too
130 // late for KoShell, it gets activePartChanged signals delivered to a dead
131 // KoShellWindow object).
132 partManager()->setActivePart(0);
133
134 // Destroy all documents - queryClose has made sure we saved them first
135 TQValueList<Page>::ConstIterator it = m_lstPages.begin();
136 for (; it != m_lstPages.end(); ++it )
137 {
138 (*it).m_pDoc->removeShell( this );
139 delete (*it).m_pView;
140 if ( (*it).m_pDoc->viewCount() == 0 )
141 delete (*it).m_pDoc;
142 }
143 m_lstPages.clear();
144
145 setRootDocumentDirect( 0L, TQPtrList<KoView>() ); // prevent our parent destructor from doing stupid things
146 saveSettings(); // Now save our settings before exiting
147}
148
149bool KoShellWindow::openDocumentInternal( const KURL &url, KoDocument* )
150{
151 // Here we have to distinguish two cases: The passed URL has a native
152 // KOffice mimetype. Then we query the trader and create the document.
153 // The file is loaded and everyone's happy.
154 // The second case is a non-native file. Here we have to create a
155 // filter manager, ask it to convert the file to the "closest" available
156 // KOffice part and open the temporary file.
157
158 /*if (!TDEIO::NetAccess::exists(url,true,0) )
159 {
160 KMessageBox::error(0L, i18n("The file %1 doesn't exist.").arg(url.url()) );
161 recentAction()->removeURL(url); //remove the file from the recent-opened-file-list
162 saveRecentFiles();
163 return false;
164 }*/
165
166 KMimeType::Ptr mimeType = KMimeType::findByURL( url );
167 m_documentEntry = KoDocumentEntry::queryByMimeType( mimeType->name().latin1() );
168
169 KTempFile* tmpFile = 0;
170 KURL tmpUrl( url ); // we might have to load a converted temp. file
171
172 if ( m_documentEntry.isEmpty() ) { // non-native
173 tmpFile = new KTempFile;
174
175 KoFilterManager *manager = new KoFilterManager( url.path() );
176 TQCString mimetype; // an empty mimetype means, that the "nearest"
177 KoFilter::ConversionStatus status = manager->exp0rt( tmpFile->name(), mimetype ); // KOffice part will be chosen
178 delete manager;
179
180 if ( status != KoFilter::OK || mimetype.isEmpty() ) {
181 tmpFile->unlink();
182 delete tmpFile;
183 return false;
184 }
185
186 // If the conversion was successful we get the mimetype of the
187 // chosen KOffice part back.
188 m_documentEntry = KoDocumentEntry::queryByMimeType( mimetype );
189 if ( m_documentEntry.isEmpty() ) {
190 tmpFile->unlink();
191 delete tmpFile;
192 return false;
193 }
194
195 // Open the temporary file
196 tmpUrl.setPath( tmpFile->name() );
197 }
198
199 recentAction()->addURL( url );
200
201 KoDocument* newdoc = m_documentEntry.createDoc();
202 if ( !newdoc ) {
203 if ( tmpFile ) {
204 tmpFile->unlink();
205 delete tmpFile;
206 }
207 return false;
208 }
209
210 connect(newdoc, TQ_SIGNAL(sigProgress(int)), this, TQ_SLOT(slotProgress(int)));
211 connect(newdoc, TQ_SIGNAL(completed()), this, TQ_SLOT(slotKSLoadCompleted()));
212 connect(newdoc, TQ_SIGNAL(canceled( const TQString & )), this, TQ_SLOT(slotKSLoadCanceled( const TQString & )));
213 newdoc->addShell( this ); // used by openURL
214 bool openRet = (!isImporting ()) ? newdoc->openURL(tmpUrl) : newdoc->import(tmpUrl);
215 if ( !openRet )
216 {
217 newdoc->removeShell(this);
218 delete newdoc;
219 if ( tmpFile ) {
220 tmpFile->unlink();
221 delete tmpFile;
222 }
223 return false;
224 }
225
226 if ( tmpFile ) {
227 //if the loaded file has been a temporary file
228 //we need to correct a few document settings
229 //see description of bug #77574 for additional information
230
231 //correct (output) mime type: we need to set it to the non-native format
232 //to make sure the user knows about saving to a non-native mime type
233 //setConfirmNonNativeSave is set to true below
234 newdoc->setMimeType( mimeType->name().latin1() );
235 newdoc->setOutputMimeType( mimeType->name().latin1() );
236
237 //the next time the user saves the document he should be warned
238 //because of mime type settings done above;
239 newdoc->setConfirmNonNativeSave(true,true); //exporting,warn_on
240 newdoc->setConfirmNonNativeSave(false,true); //save/save as,warn_on
241
242 //correct document file (should point to URL)
243 newdoc->setFile( url.path() );
244
245 //correct document URL
246 newdoc->setURL( url );
247
248 //update caption to represent the correct URL in the window titlebar
249 updateCaption();
250
251 tmpFile->unlink();
252 delete tmpFile;
253 }
254 return true;
255}
256
257void KoShellWindow::slotSidebarItemClicked( TQIconViewItem *item )
258{
259 //kdDebug() << "slotSidebarItemClicked called!" << endl;
260 if( item != 0 )
261 {
262 int index = item->index();
263
264 // Create new document from a KoDocumentEntry
265 m_documentEntry = m_mapComponents[ index ];
266 KoDocument *doc = m_documentEntry.createDoc();
267 if (doc)
268 {
269 // koshell isn't starting, but this is like starting a new app:
270 // offer both "open existing file" and "open new file".
271 if ( doc->showEmbedInitDialog( this ) )
272 {
273 partManager()->addPart( doc, false );
274 setRootDocument( doc );
275 }
276 else
277 delete doc;
278 }
279 }
280}
281
282// Separate from openDocument to handle async loading (remote URLs)
283void KoShellWindow::slotKSLoadCompleted()
284{
285 KoDocument* newdoc = (KoDocument *)(sender());
286
287 // KoDocument::import() calls resetURL() too late...
288 // ...setRootDocument will show the URL...
289 // So let's stop this from happening and the user will never know :)
290 if (isImporting()) newdoc->resetURL ();
291
292 partManager()->addPart( newdoc, false );
293 setRootDocument( newdoc );
294 disconnect(newdoc, TQ_SIGNAL(sigProgress(int)), this, TQ_SLOT(slotProgress(int)));
295 disconnect(newdoc, TQ_SIGNAL(completed()), this, TQ_SLOT(slotKSLoadCompleted()));
296 disconnect(newdoc, TQ_SIGNAL(canceled( const TQString & )), this, TQ_SLOT(slotKSLoadCanceled( const TQString & )));
297}
298
299void KoShellWindow::slotKSLoadCanceled( const TQString & errMsg )
300{
301 KMessageBox::error( this, errMsg );
302 // ... can't delete the document, it's the one who emitted the signal...
303 // ###### FIXME: This can be done in 3.0 with deleteLater, I assume (Werner)
304
305 KoDocument* newdoc = (KoDocument *)(sender());
306 disconnect(newdoc, TQ_SIGNAL(sigProgress(int)), this, TQ_SLOT(slotProgress(int)));
307 disconnect(newdoc, TQ_SIGNAL(completed()), this, TQ_SLOT(slotKSLoadCompleted()));
308 disconnect(newdoc, TQ_SIGNAL(canceled( const TQString & )), this, TQ_SLOT(slotKSLoadCanceled( const TQString & )));
309}
310
311void KoShellWindow::saveAll()
312{
313 KoView *currentView = (*m_activePage).m_pView;
314 for (TQValueList<Page>::iterator it=m_lstPages.begin(); it != m_lstPages.end(); ++it)
315 {
316 if ( (*it).m_pDoc->isModified() )
317 {
318 m_pFrame->showPage( (*it).m_pView );
319 (*it).m_pView->shell()->slotFileSave();
320 if ( (*it).m_pDoc->isModified() )
321 break;
322 }
323 }
324 m_pFrame->showPage( currentView );
325}
326
327void KoShellWindow::setRootDocument( KoDocument * doc )
328{
329 kdDebug() << "KoShellWindow::setRootDocument this=" << this << " doc=" << doc << endl;
330 // We do things quite differently from KoMainWindow::setRootDocument
331 // This one is called with doc != 0 when a new doc is created
332 // and with 0L after they have all been removed.
333 // We use setRootDocumentDirect to switch the 'root doc' known by KoMainWindow.
334
335 if ( doc )
336 {
337 if ( !doc->shells().contains( this ) )
338 doc->addShell( this );
339
340 KoView *v = doc->createView(this);
341 TQPtrList<KoView> views;
342 views.append(v);
343 setRootDocumentDirect( doc, views );
344
345 v->setGeometry( 0, 0, m_pFrame->width(), m_pFrame->height() );
346 v->setPartManager( partManager() );
347 m_pFrame->addTab( v, TDEGlobal::iconLoader()->loadIcon( m_documentEntry.service()->icon(), TDEIcon::Small ), i18n("Untitled") );
348
349 // Create a new page for this doc
350 Page page;
351 page.m_pDoc = doc;
352 page.m_pView = v;
353 // insert the new document in the sidebar
354 page.m_id = m_pSidebar->insertItem( m_grpDocuments,
355 m_documentEntry.service()->icon(),
356 i18n("Untitled"));
357 m_lstPages.append( page );
358 v->show();
359
360 switchToPage( m_lstPages.fromLast() );
361 mnuSaveAll->setEnabled(true);
362 } else
363 {
364 setRootDocumentDirect( 0L, TQPtrList<KoView>() );
365 m_activePage = m_lstPages.end();
366 KoMainWindow::updateCaption();
367 }
368}
369
370void KoShellWindow::slotNewDocumentName()
371{
372 updateCaption();
373}
374
375void KoShellWindow::updateCaption()
376{
377 //kdDebug() << "KoShellWindow::updateCaption() rootDoc=" << rootDocument() << endl;
378 KoMainWindow::updateCaption();
379 // Let's take this opportunity for setting a correct name for the icon
380 // in koolbar
381 TQValueList<Page>::Iterator it = m_lstPages.begin();
382 for( ; it != m_lstPages.end() ; ++it )
383 {
384 if ( (*it).m_pDoc == rootDocument() )
385 {
386 //kdDebug() << "updateCaption called for " << rootDocument() << endl;
387 // Get caption from document info (title(), in about page)
388 TQString name;
389 if ( rootDocument()->documentInfo() )
390 {
391 name = rootDocument()->documentInfo()->title();
392 }
393 if ( name.isEmpty() )
394 // Fall back to document URL
395 name = rootDocument()->url().fileName();
396
397 if ( !name.isEmpty() ) // else keep Untitled
398 {
399 if ( name.length() > 20 )
400 {
401 name.truncate( 17 );
402 name += "...";
403 }
404 m_pFrame->changeTab( m_pFrame->currentPage(), name );
405 m_pSidebar->renameItem(m_grpDocuments, (*m_activePage).m_id, name); //remove the document from the sidebar
406 }
407
408 return;
409 }
410 }
411}
412
413
414void KoShellWindow::slotSidebar_Part(int _item)
415{
416 //kdDebug() << "Component part choosed:" << _item << endl;
417 kapp->setOverrideCursor( TQCursor(TQt::WaitCursor) );
418 m_documentEntry = m_mapComponents[ _item ];
419 kdDebug() << m_documentEntry.service() << endl;
420 kdDebug() << m_documentEntry.name() << endl;
421 KoDocument *doc = m_documentEntry.createDoc();
422 kapp->restoreOverrideCursor();
423 if (doc)
424 {
425 if ( doc->showEmbedInitDialog( this ) )
426 {
427 partManager()->addPart( doc, false );
428 setRootDocument( doc );
429 m_tabCloseButton->show();
430 }
431 else
432 delete doc;
433 }
434}
435
436void KoShellWindow::slotSidebar_Document(int _item)
437{
438 // Switch to an existing document
439 if ( m_activePage != m_lstPages.end() &&
440 (*m_activePage).m_id == _item )
441 return;
442
443 TQValueList<Page>::Iterator it = m_lstPages.begin();
444 while( it != m_lstPages.end() )
445 {
446 if ( (*it).m_id == _item )
447 {
448 switchToPage( it );
449 return;
450 }
451 ++it;
452 }
453}
454
455void KoShellWindow::slotShowSidebar()
456{
457 if( m_pSidebar->isShown() )
458 {
459 m_pSidebar->hide();
460 m_pComponentsLabel->hide();
461 }
462 else
463 {
464 m_pSidebar->show();
465 m_pComponentsLabel->show();
466 }
467}
468
469void KoShellWindow::slotUpdatePart( TQWidget* widget )
470{
471 KoView* v = dynamic_cast<KoView*>(widget);
472 if ( v != 0 )
473 {
474 TQValueList<Page>::Iterator it = m_lstPages.begin();
475 for( ; it != m_lstPages.end(); ++it )
476 {
477 if( (*it).m_pView == v )
478 switchToPage(it);
479 }
480 }
481}
482
483void KoShellWindow::switchToPage( TQValueList<Page>::Iterator it )
484{
485 // Select new active page (view)
486 m_activePage = it;
487 KoView *v = (*m_activePage).m_pView;
488
489 kdDebug() << " setting active part to " << (*m_activePage).m_pDoc << endl;
490 // Make it active (GUI etc.)
491 partManager()->setActivePart( (*m_activePage).m_pDoc, v );
492 // Change current document
493 TQPtrList<KoView> views;
494 views.append(v);
495 setRootDocumentDirect( (*m_activePage).m_pDoc, views );
496 // Select the item in the sidebar
497 m_pSidebar->group(m_grpDocuments)->setSelected((*m_activePage).m_id,true);
498 // Raise the new page
499 m_pFrame->showPage( v );
500 // Fix caption and set focus to the new view
501 updateCaption();
502 v->setFocus();
503
504 partSpecificHelpAction->setEnabled(true);
505 partSpecificHelpAction->setText(i18n("%1 Handbook").arg((*m_activePage).m_pDoc->instance()->aboutData()->programName()));
506}
507
508void KoShellWindow::slotFileNew()
509{
510 m_documentEntry = KoPartSelectDia::selectPart( this );
511 if ( m_documentEntry.isEmpty() )
512 return;
513 KoDocument* newdoc = m_documentEntry.createDoc();
514 if ( !newdoc )
515 return;
516 if ( !newdoc->showEmbedInitDialog( this ) )
517 {
518 delete newdoc;
519 return;
520 }
521
522 partManager()->addPart( newdoc, false );
523 setRootDocument( newdoc );
524 m_tabCloseButton->show();
525}
526
527void KoShellWindow::slotFileOpen()
528{
529 KFileDialog *dialog=new KFileDialog(TQString(), TQString(), 0L, "file dialog", true);
530 if (!isImporting())
531 dialog->setCaption( i18n("Open Document") );
532 else
533 dialog->setCaption( i18n("Import Document") );
534 dialog->setMimeFilter( KoFilterManager::mimeFilter() );
535
536 KURL url;
537 if(dialog->exec()==TQDialog::Accepted) {
538 url=dialog->selectedURL();
539 recentAction()->addURL( url );
540 if ( url.isLocalFile() )
541 TDERecentDocument::add(url.path(-1));
542 else
543 TDERecentDocument::add(url.url(-1), true);
544 }
545 else
546 return;
547
548 delete dialog;
549 if ( url.isEmpty() )
550 return;
551
552 (void) openDocumentInternal( url );
553 m_tabCloseButton->show();
554}
555
556void KoShellWindow::slotFileClose()
557{
558 // reimplemented to avoid closing the window when we have docs opened
559
560 // No docs at all ?
561 if ( m_lstPages.count() == 0 )
562 close(); // close window
563 else
564 closeDocument(); // close only doc
565
566 if ( m_pFrame->count() == 0 )
567 m_tabCloseButton->hide();
568}
569
570void KoShellWindow::closeDocument()
571{
572 // Set the root document to the current one - so that queryClose acts on it
573 assert( m_activePage != m_lstPages.end() );
574 assert( rootDocument() == (*m_activePage).m_pDoc );
575
576 // First do the standard queryClose
577 kdDebug() << "KoShellWindow::closeDocument calling standard queryClose" << endl;
578 if ( KoMainWindow::queryClose() )
579 {
580 kdDebug() << "Ok for closing document" << endl;
581 m_pSidebar->removeItem(m_grpDocuments, (*m_activePage).m_id ); //remove the document from the sidebar
582 (*m_activePage).m_pDoc->removeShell(this);
583 Page oldPage = (*m_activePage); // make a copy of the struct
584 m_lstPages.remove( m_activePage );
585 m_activePage = m_lstPages.end(); // no active page right now
586 m_pSidebar->group(m_grpDocuments)->setSelected((*m_activePage).m_id, true); //select the new document in the sidebar
587
588 kdDebug() << "m_lstPages has " << m_lstPages.count() << " documents" << endl;
589 if ( m_lstPages.count() > 0 )
590 {
591 kdDebug() << "Activate the document behind" << endl;
592 switchToPage( m_lstPages.fromLast() );
593 }
594 else
595 {
596 kdDebug() << "Revert to initial state (no docs)" << endl;
597 setRootDocument( 0L );
598 partManager()->setActivePart( 0L, 0L );
599 mnuSaveAll->setEnabled(false);
600 partSpecificHelpAction->setEnabled(false);
601 partSpecificHelpAction->setText(i18n("Part Handbook"));
602 }
603
604 // Now delete the old view and page
605 // Don't do it before, because setActivePart will call slotActivePartChanged,
606 // which needs the old view (to unplug it and its plugins)
607 delete oldPage.m_pView;
608 if ( oldPage.m_pDoc->viewCount() <= 1 )
609 delete oldPage.m_pDoc;
610
611 }
612 kdDebug() << "m_lstPages has " << m_lstPages.count() << " documents" << endl;
613}
614
615bool KoShellWindow::queryClose()
616{
617 // Save current doc and views
618 TQPtrList<KoView> currentViews;
619 KoDocument * currentDoc = 0L;
620 bool ok = true;
621 if (m_activePage != m_lstPages.end())
622 {
623 currentDoc = (*m_activePage).m_pDoc;
624 currentViews.append((*m_activePage).m_pView);
625
626 // This one is called by slotFileQuit and by the X button.
627 // We have to check for unsaved docs...
628 TQValueList<Page>::Iterator it = m_lstPages.begin();
629 for( ; it != m_lstPages.end(); ++it )
630 {
631 // This is quite a HACK
632 // We should ask ourselves, to get a better dialog box
633 setRootDocumentDirect( (*it).m_pDoc, TQPtrList<KoView>() );
634 // Test if we can close this doc
635 if ( !KoMainWindow::queryClose() )
636 {
637 ok = false; // No
638 break; // abort
639 }
640 }
641
642 // Restore current doc and views
643 setRootDocumentDirect( currentDoc, currentViews );
644 }
645 return ok;
646}
647
648/*
649// Should this be an additional action in the File menu ?
650bool KoShellWindow::saveAllPages()
651{
652 // TODO
653 return false;
654}
655*/
656
657void KoShellWindow::saveSettings()
658{
659 KoShellSettings::setSidebarWidth( m_pLayout->sizes().first() );
660 KoShellSettings::writeConfig();
661}
662
663TQString KoShellWindow::configFile() const
664{
665 //return readConfigFile( locate( "data", "koshell/koshell_shell.rc" ) );
666 return TQString(); // use UI standards only for now
667}
668
669void KoShellWindow::tab_contextMenu(TQWidget * w,const TQPoint &p)
670{
671 TDEPopupMenu menu;
672 TDEIconLoader il;
673 int const mnuSave = menu.insertItem( il.loadIconSet( "document-save", TDEIcon::Small ), i18n("Save") );
674 int const mnuClose = menu.insertItem( il.loadIcon( "window-close", TDEIcon::Small ), i18n("Close") );
675
676 int tabnr = m_pFrame->indexOf( w );
677 Page page = m_lstPages[tabnr];
678 // disable save if there's nothing to save
679 if ( !page.m_pDoc->isModified() )
680 menu.setItemEnabled( mnuSave, false );
681
682 // show menu
683 int const choice = menu.exec(p);
684
685 if( choice == mnuClose )
686 {
687 const int index = m_pFrame->currentPageIndex();
688 m_pFrame->setCurrentPage( tabnr );
689 slotFileClose();
690 if ( index > m_pFrame->currentPageIndex() )
691 m_pFrame->setCurrentPage(index-1);
692 else
693 m_pFrame->setCurrentPage(index);
694 }
695 else if ( choice == mnuSave )
696 {
697 page.m_pView->shell()->slotFileSave();
698 }
699}
700
701void KoShellWindow::slotConfigureKeys()
702{
703 KoView *view = rootView();
704 KKeyDialog dlg( this );
705 dlg.insert( actionCollection() );
706 if ( view )
707 dlg.insert( view->actionCollection() );
708 if ( rootDocument() )
709 dlg.insert( rootDocument()->actionCollection() );
710 dlg.configure();
711}
712
713void KoShellWindow::createShellGUI( bool )
714{
715 guiFactory()->addClient( m_client );
716}
717
718void KoShellWindow::showPartSpecificHelp()
719{
720 if((m_activePage == m_lstPages.end()) || ((*m_activePage).m_pDoc == 0))
721 return;
722
723 kapp->invokeHelp("", (*m_activePage).m_pDoc->instance()->aboutData()->appName(), "");
724}
725
726
728KoShellGUIClient::KoShellGUIClient( KoShellWindow *window ) : KXMLGUIClient()
729{
730 setXMLFile( "koshellui.rc", true, true );
731 window->mnuSaveAll = new TDEAction( i18n("Save All"), 0, window, TQ_SLOT( saveAll() ), actionCollection(), "save_all" );
732 window->mnuSaveAll->setEnabled(false);
733 window->partSpecificHelpAction = new TDEAction(i18n("Part Handbook"), "contents", 0, window, TQ_SLOT(showPartSpecificHelp()),
734 actionCollection(), "partSpecificHelp");
735 window->partSpecificHelpAction->setEnabled(false);
736}
737
738#include "koshell_shell.moc"