/* This file is part of the KDE project
   Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
   Copyright (C) 1999 Simon Hausmann <hausmann@kde.org>
   Copyright (C) 2000-2005 David Faure <faure@kde.org>
   Copyright (C) 2005, 2006 Sven Lüppken <sven@kde.org>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This program 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
    General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/

#include <tqcursor.h>
#include <tqsplitter.h>
#include <tqiconview.h>
#include <tqlabel.h>
#include <tqvbox.h>

#include <assert.h>

#include "koshell_shell.h"
#include "koshellsettings.h"

#include <tdeapplication.h>
#include <tdetempfile.h>
#include <tdefiledialog.h>
#include <tdelocale.h>
#include <kdebug.h>
#include <kiconloader.h>
#include <kkeydialog.h>
#include <kstandarddirs.h>
#include <klibloader.h>
#include <tdepopupmenu.h>
#include <kservice.h>
#include <tdemessagebox.h>
#include <tderecentdocument.h>
#include <tdeparts/partmanager.h>
#include <tdeaction.h>
#include <tdeaboutdata.h>

#include <KoQueryTrader.h>
#include <KoDocumentInfo.h>
#include <KoDocument.h>
#include <KoView.h>
#include <KoPartSelectDia.h>
#include <KoFilterManager.h>
#include <kiconloader.h>

KoShellWindow::KoShellWindow()
 : KoMainWindow( TDEGlobal::instance() )
{
  m_activePage = m_lstPages.end();

  m_pLayout = new TQSplitter( centralWidget() );

  // Setup the sidebar
  m_pSidebar = new IconSidePane( m_pLayout );
  m_pSidebar->setSizePolicy( TQSizePolicy( TQSizePolicy::Maximum,
                             TQSizePolicy::Preferred ) );
  m_pSidebar->setActionCollection( actionCollection() );
  m_grpFile = m_pSidebar->insertGroup(i18n("Components"), false, this, TQ_SLOT( slotSidebar_Part(int )));
  m_grpDocuments = m_pSidebar->insertGroup(i18n("Documents"), true, this, TQ_SLOT(slotSidebar_Document(int)));
  m_pLayout->setResizeMode(m_pSidebar,TQSplitter::FollowSizeHint);

  // Setup the tabbar
  m_pFrame = new KTabWidget( m_pLayout );
  m_pFrame->setSizePolicy( TQSizePolicy( TQSizePolicy::Minimum,
                            TQSizePolicy::Preferred ) );
  m_pFrame->setTabPosition( KTabWidget::Bottom );

  m_tabCloseButton = new TQToolButton( m_pFrame );
  connect( m_tabCloseButton, TQ_SIGNAL( clicked() ),
           this, TQ_SLOT( slotFileClose() ) );
  m_tabCloseButton->setIconSet( SmallIconSet( "tab_remove" ) );
  m_tabCloseButton->adjustSize();
  TQToolTip::add(m_tabCloseButton, i18n("Close"));
  m_pFrame->setCornerWidget( m_tabCloseButton, BottomRight );
  m_tabCloseButton->hide();

  TQValueList<KoDocumentEntry> lstComponents = KoDocumentEntry::query(false,TQString());
  TQValueList<KoDocumentEntry>::Iterator it = lstComponents.begin();
  int id = 0;
  // Get all available components
  for( ; it != lstComponents.end(); ++it )
  {
      KService* service = (*it).service();
      if ( !service->genericName().isEmpty() )
      {
          id = m_pSidebar->insertItem(m_grpFile, service->icon(), service->genericName());
      }
      else
      {
          continue;
      }

      m_mapComponents[ id++ ] = *it;
  }

  TQValueList<int> list;
  list.append( KoShellSettings::sidebarWidth() );
  list.append( this->width() - KoShellSettings::sidebarWidth() );
  m_pLayout->setSizes( list );

  connect( this, TQ_SIGNAL( documentSaved() ),
           this, TQ_SLOT( slotNewDocumentName() ) );

  connect( m_pFrame, TQ_SIGNAL( currentChanged( TQWidget* ) ),
           this, TQ_SLOT( slotUpdatePart( TQWidget* ) ) );
  connect( m_pFrame, TQ_SIGNAL( contextMenu(TQWidget * ,const TQPoint &)), this, TQ_SLOT( tab_contextMenu(TQWidget * ,const TQPoint &)) );

  m_client = new KoShellGUIClient( this );
  createShellGUI();
}

KoShellWindow::~KoShellWindow()
{
  //kdDebug() << "KoShellWindow::~KoShellWindow()" << endl;

  // Set the active part to 0 (as we do in ~KoMainWindow, but this is too
  // late for KoShell, it gets activePartChanged signals delivered to a dead
  // KoShellWindow object).
  partManager()->setActivePart(0);

  // Destroy all documents - queryClose has made sure we saved them first
  TQValueList<Page>::ConstIterator it = m_lstPages.begin();
  for (; it != m_lstPages.end(); ++it )
  {
    (*it).m_pDoc->removeShell( this );
    delete (*it).m_pView;
    if ( (*it).m_pDoc->viewCount() == 0 )
      delete (*it).m_pDoc;
  }
  m_lstPages.clear();

  setRootDocumentDirect( 0L, TQPtrList<KoView>() ); // prevent our parent destructor from doing stupid things
  saveSettings(); // Now save our settings before exiting
}

bool KoShellWindow::openDocumentInternal( const KURL &url, KoDocument* )
{
  // Here we have to distinguish two cases: The passed URL has a native
  // KOffice mimetype. Then we query the trader and create the document.
  // The file is loaded and everyone's happy.
  // The second case is a non-native file. Here we have to create a
  // filter manager, ask it to convert the file to the "closest" available
  // KOffice part and open the temporary file.
  
  /*if (!TDEIO::NetAccess::exists(url,true,0) )
  {
    KMessageBox::error(0L, i18n("The file %1 doesn't exist.").arg(url.url()) );
    recentAction()->removeURL(url); //remove the file from the recent-opened-file-list
    saveRecentFiles();
    return false;
  }*/
  
  KMimeType::Ptr mimeType = KMimeType::findByURL( url );
  m_documentEntry = KoDocumentEntry::queryByMimeType( mimeType->name().latin1() );

  KTempFile* tmpFile = 0;
  KURL tmpUrl( url );  // we might have to load a converted temp. file

  if ( m_documentEntry.isEmpty() ) { // non-native
    tmpFile = new KTempFile;

    KoFilterManager *manager = new KoFilterManager( url.path() );
    TQCString mimetype;                                               // an empty mimetype means, that the "nearest"
    KoFilter::ConversionStatus status = manager->exp0rt( tmpFile->name(), mimetype ); // KOffice part will be chosen
    delete manager;

    if ( status != KoFilter::OK || mimetype.isEmpty() ) {
      tmpFile->unlink();
      delete tmpFile;
      return false;
    }

    // If the conversion was successful we get the mimetype of the
    // chosen KOffice part back.
    m_documentEntry = KoDocumentEntry::queryByMimeType( mimetype );
    if ( m_documentEntry.isEmpty() ) {
      tmpFile->unlink();
      delete tmpFile;
      return false;
    }

    // Open the temporary file
    tmpUrl.setPath( tmpFile->name() );
  }

  recentAction()->addURL( url );

  KoDocument* newdoc = m_documentEntry.createDoc();
  if ( !newdoc ) {
      if ( tmpFile ) {
        tmpFile->unlink();
        delete tmpFile;
      }
      return false;
  }

  connect(newdoc, TQ_SIGNAL(sigProgress(int)), this, TQ_SLOT(slotProgress(int)));
  connect(newdoc, TQ_SIGNAL(completed()), this, TQ_SLOT(slotKSLoadCompleted()));
  connect(newdoc, TQ_SIGNAL(canceled( const TQString & )), this, TQ_SLOT(slotKSLoadCanceled( const TQString & )));
  newdoc->addShell( this ); // used by openURL
  bool openRet = (!isImporting ()) ? newdoc->openURL(tmpUrl) : newdoc->import(tmpUrl);
  if ( !openRet )
  {
      newdoc->removeShell(this);
      delete newdoc;
      if ( tmpFile ) {
        tmpFile->unlink();
        delete tmpFile;
      }
      return false;
  }

  if ( tmpFile ) {
    //if the loaded file has been a temporary file
    //we need to correct a few document settings
    //see description of bug #77574 for additional information

    //correct (output) mime type: we need to set it to the non-native format
    //to make sure the user knows about saving to a non-native mime type
    //setConfirmNonNativeSave is set to true below
    newdoc->setMimeType( mimeType->name().latin1() );
    newdoc->setOutputMimeType( mimeType->name().latin1() );

    //the next time the user saves the document he should be warned
    //because of mime type settings done above;
    newdoc->setConfirmNonNativeSave(true,true); //exporting,warn_on
    newdoc->setConfirmNonNativeSave(false,true); //save/save as,warn_on

    //correct document file (should point to URL)
    newdoc->setFile( url.path() );

    //correct document URL
    newdoc->setURL( url );

    //update caption to represent the correct URL in the window titlebar
    updateCaption();

    tmpFile->unlink();
    delete tmpFile;
  }
  return true;
}

void KoShellWindow::slotSidebarItemClicked( TQIconViewItem *item )
{
  //kdDebug() << "slotSidebarItemClicked called!" << endl;
  if( item != 0 )
  {
    int index = item->index();
  
    // Create new document from a KoDocumentEntry
    m_documentEntry = m_mapComponents[ index ];
    KoDocument *doc = m_documentEntry.createDoc();
    if (doc)
    {
        // koshell isn't starting, but this is like starting a new app:
        // offer both "open existing file" and "open new file".
        if ( doc->showEmbedInitDialog( this ) )
        {
            partManager()->addPart( doc, false );
            setRootDocument( doc );
        }
        else
            delete doc;
    }
  }
}

// Separate from openDocument to handle async loading (remote URLs)
void KoShellWindow::slotKSLoadCompleted()
{
    KoDocument* newdoc = (KoDocument *)(sender());

    // KoDocument::import() calls resetURL() too late...
    // ...setRootDocument will show the URL...
    // So let's stop this from happening and the user will never know :)
    if (isImporting()) newdoc->resetURL ();

    partManager()->addPart( newdoc, false );
    setRootDocument( newdoc );
    disconnect(newdoc, TQ_SIGNAL(sigProgress(int)), this, TQ_SLOT(slotProgress(int)));
    disconnect(newdoc, TQ_SIGNAL(completed()), this, TQ_SLOT(slotKSLoadCompleted()));
    disconnect(newdoc, TQ_SIGNAL(canceled( const TQString & )), this, TQ_SLOT(slotKSLoadCanceled( const TQString & )));
}

void KoShellWindow::slotKSLoadCanceled( const TQString & errMsg )
{
    KMessageBox::error( this, errMsg );
    // ... can't delete the document, it's the one who emitted the signal...
    // ###### FIXME: This can be done in 3.0 with deleteLater, I assume (Werner)

    KoDocument* newdoc = (KoDocument *)(sender());
    disconnect(newdoc, TQ_SIGNAL(sigProgress(int)), this, TQ_SLOT(slotProgress(int)));
    disconnect(newdoc, TQ_SIGNAL(completed()), this, TQ_SLOT(slotKSLoadCompleted()));
    disconnect(newdoc, TQ_SIGNAL(canceled( const TQString & )), this, TQ_SLOT(slotKSLoadCanceled( const TQString & )));
}

void KoShellWindow::saveAll()
{
  KoView *currentView = (*m_activePage).m_pView;
  for (TQValueList<Page>::iterator it=m_lstPages.begin(); it != m_lstPages.end(); ++it)
  {
    if ( (*it).m_pDoc->isModified() )
    {
      m_pFrame->showPage( (*it).m_pView );
      (*it).m_pView->shell()->slotFileSave();
      if ( (*it).m_pDoc->isModified() )
        break;
    }
  }
  m_pFrame->showPage( currentView );
}

void KoShellWindow::setRootDocument( KoDocument * doc )
{
  kdDebug() << "KoShellWindow::setRootDocument this=" << this << " doc=" << doc << endl;
  // We do things quite differently from KoMainWindow::setRootDocument
  // This one is called with doc != 0 when a new doc is created
  // and with 0L after they have all been removed.
  // We use setRootDocumentDirect to switch the 'root doc' known by KoMainWindow.

  if ( doc )
  {
    if ( !doc->shells().contains( this ) )
        doc->addShell( this );

    KoView *v = doc->createView(this);
    TQPtrList<KoView> views;
    views.append(v);
    setRootDocumentDirect( doc, views );
    
    v->setGeometry( 0, 0, m_pFrame->width(), m_pFrame->height() );
    v->setPartManager( partManager() );
    m_pFrame->addTab( v, TDEGlobal::iconLoader()->loadIcon( m_documentEntry.service()->icon(), TDEIcon::Small ), i18n("Untitled") );
    
    // Create a new page for this doc
    Page page;
    page.m_pDoc = doc;
    page.m_pView = v;
    // insert the new document in the sidebar
    page.m_id = m_pSidebar->insertItem( m_grpDocuments,
                                       m_documentEntry.service()->icon(),
                                       i18n("Untitled"));
    m_lstPages.append( page );
    v->show();

    switchToPage( m_lstPages.fromLast() );
    mnuSaveAll->setEnabled(true);
  } else
  {
    setRootDocumentDirect( 0L, TQPtrList<KoView>() );
    m_activePage = m_lstPages.end();
    KoMainWindow::updateCaption();
  }
}

void KoShellWindow::slotNewDocumentName()
{
	updateCaption();
}

void KoShellWindow::updateCaption()
{
    //kdDebug() << "KoShellWindow::updateCaption() rootDoc=" << rootDocument() << endl;
    KoMainWindow::updateCaption();
    // Let's take this opportunity for setting a correct name for the icon
    // in koolbar
    TQValueList<Page>::Iterator it = m_lstPages.begin();
    for( ; it != m_lstPages.end() ; ++it )
    {
      if ( (*it).m_pDoc == rootDocument() )
      {
        //kdDebug() << "updateCaption called for " << rootDocument() << endl;
        // Get caption from document info (title(), in about page)
        TQString name;
        if ( rootDocument()->documentInfo() )
        {
            name = rootDocument()->documentInfo()->title();
        }
        if ( name.isEmpty() )
            // Fall back to document URL
            name = rootDocument()->url().fileName();

        if ( !name.isEmpty() ) // else keep Untitled
        {
          if ( name.length() > 20 )
          {
            name.truncate( 17 );
            name += "...";
          }
          m_pFrame->changeTab( m_pFrame->currentPage(), name );
          m_pSidebar->renameItem(m_grpDocuments, (*m_activePage).m_id, name); //remove the document from the sidebar
        }

        return;
      }
    }
}


void KoShellWindow::slotSidebar_Part(int _item)
{
  //kdDebug() << "Component part choosed:" << _item << endl;
  kapp->setOverrideCursor( TQCursor(TQt::WaitCursor) );
  m_documentEntry = m_mapComponents[ _item ];
  kdDebug() << m_documentEntry.service() << endl;
  kdDebug() << m_documentEntry.name() << endl;
  KoDocument *doc = m_documentEntry.createDoc();
  kapp->restoreOverrideCursor();
  if (doc)
  {
    if ( doc->showEmbedInitDialog( this ) )
    {
      partManager()->addPart( doc, false );
      setRootDocument( doc );
      m_tabCloseButton->show();
    }
    else
      delete doc;
  }
}

void KoShellWindow::slotSidebar_Document(int _item)
{
    // Switch to an existing document
  if ( m_activePage != m_lstPages.end() &&
       (*m_activePage).m_id == _item )
    return;
    
  TQValueList<Page>::Iterator it = m_lstPages.begin();
  while( it != m_lstPages.end() )
  {
    if ( (*it).m_id == _item )
    {
      switchToPage( it );
      return;
    }
    ++it;
  }
}

void KoShellWindow::slotShowSidebar()
{
  if( m_pSidebar->isShown() )
  {
    m_pSidebar->hide();
    m_pComponentsLabel->hide();
  }
  else
  {
    m_pSidebar->show();
    m_pComponentsLabel->show();
  }
}

void KoShellWindow::slotUpdatePart( TQWidget* widget )
{
  KoView* v = dynamic_cast<KoView*>(widget);
  if ( v != 0 ) 
  {
    TQValueList<Page>::Iterator it = m_lstPages.begin();
    for( ; it != m_lstPages.end(); ++it )
    {
      if( (*it).m_pView == v )
        switchToPage(it);
    }
  }
}

void KoShellWindow::switchToPage( TQValueList<Page>::Iterator it )
{
  // Select new active page (view)
  m_activePage = it;
  KoView *v = (*m_activePage).m_pView;

  kdDebug() << " setting active part to " << (*m_activePage).m_pDoc << endl;
  // Make it active (GUI etc.)
  partManager()->setActivePart( (*m_activePage).m_pDoc, v );
  // Change current document
  TQPtrList<KoView> views;
  views.append(v);
  setRootDocumentDirect( (*m_activePage).m_pDoc, views );
  // Select the item in the sidebar
  m_pSidebar->group(m_grpDocuments)->setSelected((*m_activePage).m_id,true);
  // Raise the new page
  m_pFrame->showPage( v );
  // Fix caption and set focus to the new view
  updateCaption();
  v->setFocus();

  partSpecificHelpAction->setEnabled(true);
  partSpecificHelpAction->setText(i18n("%1 Handbook").arg((*m_activePage).m_pDoc->instance()->aboutData()->programName()));
}

void KoShellWindow::slotFileNew()
{
    m_documentEntry = KoPartSelectDia::selectPart( this );
    if ( m_documentEntry.isEmpty() )
      return;
    KoDocument* newdoc = m_documentEntry.createDoc();
    if ( !newdoc )
        return;
    if ( !newdoc->showEmbedInitDialog( this ) )
    {
      delete newdoc;
      return;
    }

    partManager()->addPart( newdoc, false );
    setRootDocument( newdoc );
    m_tabCloseButton->show();
}

void KoShellWindow::slotFileOpen()
{
    KFileDialog *dialog=new KFileDialog(TQString(), TQString(), 0L, "file dialog", true);
    if (!isImporting())
        dialog->setCaption( i18n("Open Document") );
    else
        dialog->setCaption( i18n("Import Document") );
    dialog->setMimeFilter( KoFilterManager::mimeFilter() );

    KURL url;
    if(dialog->exec()==TQDialog::Accepted) {
        url=dialog->selectedURL();
        recentAction()->addURL( url );
        if ( url.isLocalFile() )
            TDERecentDocument::add(url.path(-1));
        else
            TDERecentDocument::add(url.url(-1), true);
    }
    else
        return;

    delete dialog;
    if ( url.isEmpty() )
        return;

    (void) openDocumentInternal( url );
    m_tabCloseButton->show();
}

void KoShellWindow::slotFileClose()
{
  // reimplemented to avoid closing the window when we have docs opened

  // No docs at all ?
  if ( m_lstPages.count() == 0 )
    close(); // close window
  else
    closeDocument(); // close only doc

  if ( m_pFrame->count() == 0 )
    m_tabCloseButton->hide();
}

void KoShellWindow::closeDocument()
{
  // Set the root document to the current one - so that queryClose acts on it
  assert( m_activePage != m_lstPages.end() );
  assert( rootDocument() == (*m_activePage).m_pDoc );

  // First do the standard queryClose
  kdDebug() << "KoShellWindow::closeDocument calling standard queryClose" << endl;
  if ( KoMainWindow::queryClose() )
  {
    kdDebug() << "Ok for closing document" << endl;
    m_pSidebar->removeItem(m_grpDocuments, (*m_activePage).m_id ); //remove the document from the sidebar
    (*m_activePage).m_pDoc->removeShell(this);
    Page oldPage = (*m_activePage); // make a copy of the struct
    m_lstPages.remove( m_activePage );
    m_activePage = m_lstPages.end(); // no active page right now
    m_pSidebar->group(m_grpDocuments)->setSelected((*m_activePage).m_id, true); //select the new document in the sidebar

    kdDebug() << "m_lstPages has " << m_lstPages.count() << " documents" << endl;
    if ( m_lstPages.count() > 0 )
    {
      kdDebug() << "Activate the document behind" << endl;
      switchToPage( m_lstPages.fromLast() );
    }
    else
    {
      kdDebug() << "Revert to initial state (no docs)" << endl;
      setRootDocument( 0L );
      partManager()->setActivePart( 0L, 0L );
      mnuSaveAll->setEnabled(false);
      partSpecificHelpAction->setEnabled(false);
      partSpecificHelpAction->setText(i18n("Part Handbook"));
    }

    // Now delete the old view and page
    // Don't do it before, because setActivePart will call slotActivePartChanged,
    // which needs the old view (to unplug it and its plugins)
    delete oldPage.m_pView;
    if ( oldPage.m_pDoc->viewCount() <= 1 )
      delete oldPage.m_pDoc;

  }
  kdDebug() << "m_lstPages has " << m_lstPages.count() << " documents" << endl;
}

bool KoShellWindow::queryClose()
{
  // Save current doc and views
  TQPtrList<KoView> currentViews;
  KoDocument * currentDoc = 0L;
  bool ok = true;
  if (m_activePage != m_lstPages.end())
  {
      currentDoc = (*m_activePage).m_pDoc;
      currentViews.append((*m_activePage).m_pView);

      // This one is called by slotFileQuit and by the X button.
      // We have to check for unsaved docs...
      TQValueList<Page>::Iterator it = m_lstPages.begin();
      for( ; it != m_lstPages.end(); ++it )
      {
          // This is quite a HACK
          // We should ask ourselves, to get a better dialog box
          setRootDocumentDirect( (*it).m_pDoc, TQPtrList<KoView>() );
          // Test if we can close this doc
          if ( !KoMainWindow::queryClose() )
          {
              ok = false; // No
              break; // abort
          }
      }

  // Restore current doc and views
  setRootDocumentDirect( currentDoc, currentViews );
  }
  return ok;
}

/*
// Should this be an additional action in the File menu ?
bool KoShellWindow::saveAllPages()
{
  // TODO
  return false;
}
*/

void KoShellWindow::saveSettings()
{
  KoShellSettings::setSidebarWidth( m_pLayout->sizes().first() );
  KoShellSettings::writeConfig();
}

TQString KoShellWindow::configFile() const
{
  //return readConfigFile( locate( "data", "koshell/koshell_shell.rc" ) );
  return TQString(); // use UI standards only for now
}

void KoShellWindow::tab_contextMenu(TQWidget * w,const TQPoint &p)
{
  TDEPopupMenu menu;
  TDEIconLoader il;
  int const mnuSave = menu.insertItem( il.loadIconSet( "document-save", TDEIcon::Small ), i18n("Save") );
  int const mnuClose = menu.insertItem( il.loadIcon( "window-close", TDEIcon::Small ), i18n("Close") );
  
  int tabnr = m_pFrame->indexOf( w );
  Page page = m_lstPages[tabnr];
  // disable save if there's nothing to save
  if ( !page.m_pDoc->isModified() )
    menu.setItemEnabled( mnuSave, false );
  
  // show menu
  int const choice = menu.exec(p);

  if( choice == mnuClose )
  {
    const int index = m_pFrame->currentPageIndex();
    m_pFrame->setCurrentPage( tabnr );
    slotFileClose();
    if ( index > m_pFrame->currentPageIndex() )
      m_pFrame->setCurrentPage(index-1);
    else
      m_pFrame->setCurrentPage(index);
  }
  else if ( choice == mnuSave )
  {
      page.m_pView->shell()->slotFileSave();
  }
}

void KoShellWindow::slotConfigureKeys()
{
  KoView *view = rootView();
  KKeyDialog dlg( this );
  dlg.insert( actionCollection() );
  if ( view )
     dlg.insert( view->actionCollection() );
  if ( rootDocument() )
    dlg.insert( rootDocument()->actionCollection() );
  dlg.configure();
}

void KoShellWindow::createShellGUI( bool  )
{
	guiFactory()->addClient( m_client );
}

void KoShellWindow::showPartSpecificHelp()
{
  if((m_activePage == m_lstPages.end()) || ((*m_activePage).m_pDoc == 0))
    return;

  kapp->invokeHelp("", (*m_activePage).m_pDoc->instance()->aboutData()->appName(), "");
}


///////////////////
KoShellGUIClient::KoShellGUIClient( KoShellWindow *window ) : KXMLGUIClient()
{
  setXMLFile( "koshellui.rc", true, true );
  window->mnuSaveAll = new TDEAction( i18n("Save All"), 0, window, TQ_SLOT( saveAll() ), actionCollection(), "save_all" );
  window->mnuSaveAll->setEnabled(false);
  window->partSpecificHelpAction = new TDEAction(i18n("Part Handbook"), "contents", 0, window, TQ_SLOT(showPartSpecificHelp()),
                                               actionCollection(), "partSpecificHelp");
  window->partSpecificHelpAction->setEnabled(false);
}

#include "koshell_shell.moc"
