/*
**************************************************************************
                                 description
                             --------------------
    copyright            : (C) 2000-2006 by Andreas Zehender
    email                : zehender@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.                                   *
*                                                                        *
**************************************************************************/

#include <klocale.h>
#include <khelpmenu.h>
#include <ktoolbar.h>
#include <kstandardaction.h>
#include <kaction.h>
#include <kstatusbar.h>
#include <kfiledialog.h>
#include <kmessagebox.h>
#include <kiconloader.h>
#include <kedittoolbar.h>
#include <kshortcutsdialog.h>
#include <kmenu.h>
#include <qtimer.h>
//Added by qt3to4:
#include <QShowEvent>
#include <QMenuItem>
#include "pmshell.h"
#include "pmpart.h"
#include "pmfactory.h"
#include "pmsettingsdialog.h"
#include "pmdefaults.h"
#include "pmdockwidget.h"

#include "pmviewfactory.h"
#include "pmviewbase.h"
#include "pmunknownview.h"
#include "pmviewlayoutmanager.h"
#include <kactionmenu.h>
#include <ktoggleaction.h>
#include <krecentfilesaction.h>
#include <kactioncollection.h>
//#define KPM_WITH_OBJECT_LIBRARY

const int c_statusBarInfo = 0;
const int c_statusBarControlPoints = 1;

PMShell::PMShell( const KUrl& url )
      : PMDockMainWindow( 0 )
{
   setPluginLoadingMode( DoNotLoadPlugins );
   setComponentData( PMFactory::componentData( ), false );

   m_pPart = new PMPart( this, this, true, this );
   m_pPart->setReadWrite( ); // read-write mode
   m_viewNumber = 0;

   if (!initialGeometrySet())
      resize(800,600);

   setupActions( );

   restoreOptions( );

   setupView( );
   setXMLFile( "kpovmodelershell.rc" );
   createGUI( m_pPart );

   //guiFactory( )->addClient( m_pPart );
   m_pStatusBar = statusBar( );
   m_pStatusBar->insertItem( " ", c_statusBarInfo, 1 );
   m_pStatusBar->insertItem( "" , c_statusBarControlPoints );

	setAutoSaveSettings( "MainWindow", true );

   if( !url.isEmpty( ) )
      openUrl( url );

   setCaption( url.prettyUrl( ) );
   connect( m_pPart, SIGNAL( modified( ) ), SLOT( slotModified( ) ) );
   connect( m_pPart, SIGNAL( controlPointMessage( const QString& ) ),
            SLOT( slotControlPointMsg( const QString& ) ) );
}

PMShell::~PMShell( )
{
	kDebug(PMArea) << "pmshell desctructor";
	delete m_pPart;
	m_pPart = 0;
}

void PMShell::setupActions( )
{
//   m_helpMenu = new KHelpMenu( this, PMFactory::aboutData( ), true,
//                               actionCollection( ) );

   KStandardAction::openNew( this, SLOT( slotFileNew( ) ), actionCollection( ) );
   KStandardAction::open( this, SLOT( slotFileOpen( ) ), actionCollection( ) );
   m_pRecent = KStandardAction::openRecent( this, SLOT( slotOpenRecent( const KUrl& ) ),
                                       actionCollection( ) );
   KStandardAction::save( this, SLOT( slotFileSave( ) ), actionCollection( ) );
   KStandardAction::saveAs( this, SLOT( slotFileSaveAs( ) ), actionCollection( ) );

   KStandardAction::revert( this, SLOT( slotFileRevert( ) ), actionCollection( ) );
   KStandardAction::print( this, SLOT( slotFilePrint( ) ), actionCollection( ) );

   KStandardAction::close( this, SLOT( slotFileClose( ) ), actionCollection( ) );
   KStandardAction::quit( this, SLOT( close( ) ), actionCollection( ) );

   m_pPathAction = actionCollection()->add<KToggleAction>( "options_show_path" );
   m_pPathAction->setText( i18n( "Show &Path" ) );
   connect( m_pPathAction, SIGNAL( triggered( ) ), this, SLOT( slotShowPath( ) ) );
   m_pPathAction->setCheckedState( KGuiItem( i18n( "Hide &Path" ) ) );

   m_pStatusbarAction = KStandardAction::showStatusbar( this, SLOT( slotShowStatusbar( ) ),
                                                   actionCollection( ) );

   KStandardAction::saveOptions( this, SLOT( saveOptions( ) ), actionCollection( ) );

   KStandardAction::keyBindings( this, SLOT( slotConfigureKeys( ) ),
                            actionCollection( ) );
   KStandardAction::configureToolbars( this, SLOT( slotConfigureToolbars( ) ),
                                  actionCollection( ) );
   KStandardAction::preferences( this, SLOT( slotSettings( ) ), actionCollection( ) );

   m_pNewTopViewAction = actionCollection()->addAction( "view_new_topview" );
   m_pNewTopViewAction->setText( i18n( "New Top View" ) );
   connect( m_pNewTopViewAction, SIGNAL( triggered( ) ), this, SLOT( slotNewTopView( ) ) );
   m_pNewBottomViewAction = actionCollection()->addAction( "view_new_bottomview" );
   m_pNewBottomViewAction->setText( i18n ( "New Bottom View" ) );
   connect( m_pNewBottomViewAction, SIGNAL( triggered( ) ), this, SLOT( slotNewBottomView( ) ) );
   m_pNewLeftViewAction = actionCollection()->addAction( "view_new_leftview" );
   m_pNewLeftViewAction->setText( i18n( "New Left View" ) );
   connect( m_pNewLeftViewAction, SIGNAL( triggered( ) ), this, SLOT( slotNewLeftView( ) ) );
   m_pNewRightViewAction = actionCollection()->addAction( "view_new_rightview" );
   m_pNewRightViewAction->setText( i18n( "New Right View" ) );
   connect( m_pNewRightViewAction, SIGNAL( triggered( ) ), this, SLOT( slotNewRightView( ) ) );
   m_pNewFrontViewAction = actionCollection()->addAction( "view_new_frontview" );
   m_pNewFrontViewAction->setText( i18n( "New Front View" ) );
   connect( m_pNewFrontViewAction, SIGNAL( triggered( ) ), this, SLOT( slotNewRightView( ) ) );
   m_pNewBackViewAction = actionCollection()->addAction( "view_new_backview" );
   m_pNewBackViewAction->setText( i18n( "New Back View" ) );
   connect( m_pNewBackViewAction, SIGNAL( triggered( ) ), this, SLOT( slotNewBackView( ) ) );
   m_pNewCameraViewAction = actionCollection()->addAction( "view_new_cameraview" );
   m_pNewCameraViewAction->setText( i18n( "New Camera View" ) );
   connect( m_pNewCameraViewAction, SIGNAL( triggered( ) ), this, SLOT( slotNewCameraView( ) ) );
   m_pNewTreeViewAction = actionCollection()->addAction( "view_new_treeview" );
   m_pNewTreeViewAction->setText( i18n( "New Object Tree" ) );
   connect( m_pNewTreeViewAction, SIGNAL( triggered( ) ), this, SLOT( slotNewTreeView( ) ) );
   m_pNewDialogViewAction = actionCollection()->addAction( "view_new_dialogview" );
   m_pNewDialogViewAction->setText( i18n( "New Properties View" ) );
   connect( m_pNewDialogViewAction, SIGNAL( triggered( ) ), this, SLOT( slotNewDialogView( ) ) );

#ifdef KPM_WITH_OBJECT_LIBRARY
   m_pNewLibraryBrowserAction = actionCollection()->addAction( "view_new_librarybrowser" );
   m_pNewLibraryBrowserAction->setText( i18n( "New Library Browser" ) );
   connect( m_pNewLibraryBrowserAction, SIGNAL( triggered( ) ), this, SLOT( slotNewLibraryBrowserView( ) ) );
#endif

   // Creating the view layouts menu
   m_pViewLayoutsAction = actionCollection()->add<KActionMenu>( "view_layouts_menu" );
   m_pViewLayoutsAction->setText( i18n( "View Layouts" ) );
   KMenu* menu = m_pViewLayoutsAction->menu( );
   connect( menu, SIGNAL( aboutToShow( ) ), SLOT( slotViewsMenuAboutToShow( ) ) );
   PMViewLayoutManager::theManager( )->fillPopupMenu( menu );
   connect( menu, SIGNAL( triggered( QAction* ) ), SLOT( slotSelectedLayout( QAction* ) ) );

   m_pSaveViewLayoutAction = actionCollection()->addAction( "save_view_layout" );
   m_pSaveViewLayoutAction->setText( i18n( "Save View Layout..." ) );
   connect( m_pSaveViewLayoutAction, SIGNAL( triggered( ) ), this, SLOT( slotSaveViewLayout( ) ) );
}

void PMShell::setupView( )
{
   PMViewLayoutManager::theManager( )->displayDefaultLayout( this );
}


PMDockWidget* PMShell::createView( const QString& t, PMViewOptions* o,
                                   bool initPosition )
{
   PMDockWidget* dock = 0;
   PMViewBase* contents = 0;

   PMViewTypeFactory* factory =
      PMViewFactory::theFactory( )->viewFactory( t );

   m_viewNumber++;
   QString name = QString( "View (%1)" ).arg( m_viewNumber );

   if( factory )
   {
      QString desc;
      // Create the appropriate dock widget
      if( o )
         desc = factory->description( o );
      else
         desc = factory->description( );

      dock = createDockWidget( SmallIcon( factory->iconName( ) ), 0L,
                               desc, desc );
      contents = factory->newInstance( dock, m_pPart );
      if( o )
         contents->restoreViewConfig( o );
   }
   else
   {
      // unknown view type
      dock = createDockWidget( SmallIcon( "unknown" ), 0L,
                               i18n( "Unknown" ), i18n( "Unknown" ) );
      contents = new PMUnknownView( t, dock );
   }

   dock->setWidget( contents );
   connect( dock, SIGNAL( headerCloseButtonClicked( ) ),
            SLOT( slotDockWidgetClosed( ) ) );

   if( initPosition )
   {
      dock->resize( 300, 400 );
      dock->manualDock( 0, PMDockWidget::DockDesktop, 50,
                        mapToGlobal( QPoint( 50, 50 ) ) );
   }
   return dock;
}

/*
PMDockWidget* PMShell::createTreeView( )
{
   PMDockWidget* dock = 0;
   m_numTreeViews++;
   QString name = QString( "Object Tree (%1)" ).arg( m_numTreeViews );
   dock = createDockWidget( name, SmallIcon( "pmtreeview" ),
                            0L, i18n( "Object Tree" ), i18n( "Object Tree" ) );
   dock->setDockSite( PMDockWidget::DockFullSite );
   PMTreeView* tv = new PMTreeView( m_pPart, dock );
   dock->setWidget( tv );

   connect( dock, SIGNAL( headerCloseButtonClicked( ) ),
            SLOT( slotDockWidgetClosed( ) ) );

   return dock;
}

PMDockWidget* PMShell::createDialogView( )
{
   PMDockWidget* dock = 0;
   m_numDialogViews++;
   QString name = QString( "Object Properties (%1)" ).arg( m_numDialogViews );
   dock = createDockWidget( name, SmallIcon( "pmdialogview" ),
                            0L, i18n( "Object Properties" ), i18n( "Object Properties" ) );
   dock->setDockSite( PMDockWidget::DockFullSite );
   PMDialogView* dv = new PMDialogView( m_pPart, dock );
   dock->setWidget( dv );

   connect( dock, SIGNAL( headerCloseButtonClicked( ) ),
            SLOT( slotDockWidgetClosed( ) ) );

   return dock;
}

PMDockWidget* PMShell::create3DView( PMGLView::PMViewType t )
{
   PMDockWidget* dock = 0;
   m_numGLViews++;
   QString name = QString( "3D View (%1)" ).arg( m_numGLViews );
   dock = createDockWidget( name, SmallIcon( "pmglview" ),
                            0L, i18n( "3D View" ), i18n( "3D View" ) );
   dock->setDockSite( PMDockWidget::DockFullSite );
   PMGLView* vgl = new PMGLView( m_pPart, t, dock );
   dock->setWidget( vgl );
   connect( vgl, SIGNAL( viewTypeChanged( const QString& ) ),
            dock, SLOT( slotSetCaption( const QString& ) ) );
   dock->slotSetCaption( PMGLView::viewTypeAsString( t ) );

   connect( dock, SIGNAL( headerCloseButtonClicked( ) ),
            SLOT( slotDockWidgetClosed( ) ) );

   return dock;
}
*/

void PMShell::slotNewGraphicalView( PMGLView::PMViewType t )
{
   PMGLViewOptions* o = new PMGLViewOptions( t );
   createView( "glview", o );
   delete o;
}

void PMShell::slotNewTopView( )
{
   slotNewGraphicalView( PMGLView::PMViewNegY );
}

void PMShell::slotNewBottomView( )
{
   slotNewGraphicalView( PMGLView::PMViewPosY );
}

void PMShell::slotNewLeftView( )
{
   slotNewGraphicalView( PMGLView::PMViewPosX );
}

void PMShell::slotNewRightView( )
{
   slotNewGraphicalView( PMGLView::PMViewNegX );
}

void PMShell::slotNewFrontView( )
{
   slotNewGraphicalView( PMGLView::PMViewPosZ );
}

void PMShell::slotNewBackView( )
{
   slotNewGraphicalView( PMGLView::PMViewNegZ );
}

void PMShell::slotNewCameraView( )
{
   slotNewGraphicalView( PMGLView::PMViewCamera );
}

void PMShell::slotNewDialogView( )
{
   createView( "dialogview" );
}

void PMShell::slotNewTreeView( )
{
   createView( "treeview" );
}

void PMShell::slotNewLibraryBrowserView( )
{
   createView( "librarybrowserview" );
}

void PMShell::slotDockWidgetClosed( )
{
   QObject* o = sender( );
   if( o && o->inherits( "PMDockWidget" ) )
   {
      if( !m_objectsToDelete.contains( o ) )
      {
         m_objectsToDelete.append( o );
         QTimer::singleShot( 0, this, SLOT( slotDeleteClosedObjects( ) ) );
      }
   }
}

void PMShell::slotDeleteClosedObjects( )
{
	foreach(QObject* o, m_objectsToDelete) delete o;
   m_objectsToDelete.clear( );
}

void PMShell::openUrl( const KUrl& url )
{
   m_pRecent->addUrl( url );

   if( !m_pPart->isModified( ) && m_pPart->url( ).isEmpty( ) )
   {
      m_pPart->openUrl( url );
      setCaption( m_pPart->url( ).prettyUrl( ) );
   }
   else
   {
      PMShell *shell = new PMShell( );
      shell->show( );
      shell->openUrl( url );
   }
}

void PMShell::slotOpenRecent( const KUrl& url )
{
   m_openRecentURL = url;
   QTimer::singleShot( 0, this, SLOT( slotOpenRecentTimer( ) ) );
}

void PMShell::slotOpenRecentTimer( )
{
   openUrl( m_openRecentURL );
}

void PMShell::slotFileNew( )
{
   if( !m_pPart->isModified( ) && m_pPart->url( ).isEmpty( ) )
   {
      m_pPart->newDocument( );
      setCaption( );
   }
   else
   {
      PMShell *shell = new PMShell( );
      shell->show( );
   }
}

void PMShell::slotFileOpen( )
{
   KUrl url = KFileDialog::getOpenUrl(
      KUrl(), QString( "*.kpm|" ) + i18n( "Povray Modeler Files (*.kpm)" )
      + "\n*|" + i18n( "All Files" ) );

   if( !url.isEmpty( ) )
      openUrl( url );
}

void PMShell::slotFileSave( )
{
	m_pPart->slotAboutToSave( );

   if( m_pPart->isModified( ) )
   {
      if( !m_pPart->url( ).isEmpty( ) &&
          m_pPart->isReadWrite( ) )
         m_pPart->saveAs( m_pPart->url( ) );
      else
         saveAs( );
      setCaption( m_pPart->url( ).prettyUrl( ) );
   }
   else
      emit statusMsg( i18n( "No changes need to be saved" ) );
}

void PMShell::slotFileSaveAs( )
{
	m_pPart->slotAboutToSave( );
	saveAs( );
}

void PMShell::saveAs( )
{
	KUrl url;
   KFileDialog dlg( url, QString( "*.kpm|" ) + i18n( "Povray Modeler Files (*.kpm)" ) +
						  QString( "\n*|" ) + i18n( "All Files" ),
						  0);
   dlg.setCaption( i18n( "Save As" ) );
   dlg.setOperationMode( KFileDialog::Saving );
   dlg.exec( );

   url = dlg.selectedUrl( );

   if( !url.isEmpty( ) )
   {
      if( dlg.currentFilter( ) == QString( "*.kpm" ) )
         if( QFileInfo( url.path( ) ).completeSuffix( ).isEmpty( ) )
            url.setPath( url.path( ) + ".kpm" );

      if( overwriteURL( url ) )
      {
         m_pRecent->addUrl( url );
         if( m_pPart->saveAs( url ) )
            setCaption( url.prettyUrl( ) );
         else
            KMessageBox::sorry( this, i18n( "Could not save the file." ) );
      }
   }
}

void PMShell::slotFileRevert( )
{
   KUrl url = m_pPart->url( );

   if( !url.isEmpty( ) )
      m_pPart->openUrl( url );
//   else
//    slotFileNew( );
}

void PMShell::slotFilePrint( )
{
   //TODO
   //   m_pPart->slotPrint( );
}

void PMShell::slotFileNewWindow( )
{
   PMShell* shell = new PMShell;
   shell->show( );
}

void PMShell::slotFileClose( )
{
   if( m_pPart->closeUrl( ) )
   {
      m_pPart->closeDocument( );
      m_pPart->newDocument( );
      setCaption( );
   }
}

void PMShell::slotShowToolbar( )
{
   if( toolBar( )->isVisible ( ) )
      toolBar( )->hide( );
   else
      toolBar( )->show( );
}

void PMShell::slotShowStatusbar( )
{
   if( statusBar( )->isVisible ( ) )
      statusBar( )->hide( );
   else
      statusBar( )->show( );
}

void PMShell::slotShowPath( )
{
   setCaption( m_pPart->url( ).prettyUrl( ) );
}

void PMShell::slotConfigureKeys( )
{
   KShortcutsDialog kd;
   kd.addCollection( m_pPart->actionCollection( ) );
   kd.addCollection( actionCollection( ) );
   kd.configure( true );
   //KShortcutsDialog::configure( actionCollection( ) );
}

void PMShell::slotSettings( )
{
   PMSettingsDialog dlg( m_pPart );
   dlg.exec( );
}

void PMShell::slotConfigureToolbars( )
{
   saveMainWindowSettings( KGlobal::config( )->group( "Appearance" ) );
   KEditToolBar dlg( factory( ) );
   connect( &dlg, SIGNAL( newToolbarConfig( ) ),
            this, SLOT( slotNewToolbarConfig( ) ) );
   dlg.exec( );
}

void PMShell::slotNewToolbarConfig( )
{
   createGUI( 0 );
   createShellGUI( false );
   createGUI( m_pPart );
   applyMainWindowSettings( KGlobal::config( )->group( "Appearance" ) );
}

void PMShell::updateGUI( )
{
   saveMainWindowSettings( KGlobal::config( )->group( "Appearance" ) );
   createGUI( 0 );
   createShellGUI( false );
   createGUI( m_pPart );
   applyMainWindowSettings( KGlobal::config( )->group( "Appearance" ) );
}

void PMShell::saveOptions( )
{
   kDebug( PMArea ) << "Saving configuration";

   KConfigGroup config( KGlobal::config( ), "Appearance" );

   // set group
   config.writeEntry( "ShowStatusbar", m_pStatusbarAction->isChecked( ) );
   m_pRecent->saveEntries( config );

   if( m_pPart )
       m_pPart->saveConfig( KGlobal::config().data() );

   config.sync( );
}

void PMShell::restoreOptions( )
{
   KConfigGroup config( KGlobal::config( ), "Appearance" );

   bool showStatusbar = config.readEntry<bool>( "ShowStatusbar", true );

   m_pStatusbarAction->blockSignals( true );
   m_pStatusbarAction->setChecked( showStatusbar );
   m_pStatusbarAction->blockSignals( false );

   if( showStatusbar )
      statusBar( )->show( );
   else
      statusBar( )->hide( );

   m_pRecent->loadEntries( config );
}

void PMShell::setCaption( const QString& caption )
{
   QString tmp;

   if( caption.isEmpty( ) )
      tmp = i18n( "unknown" );
   else
   {
      if( !m_pPathAction->isChecked( ) )
         tmp = caption.right( caption.length( ) - caption.lastIndexOf( '/' ) - 1 );
      else
         tmp = caption;
   }

   KXmlGuiWindow::setCaption( tmp, m_pPart->isModified( ) );
}

void PMShell::statusMsg( const QString& text )
{
   m_pStatusBar->showMessage( text, 5000 );
}

bool PMShell::queryClose( )
{
   saveOptions( );
   return m_pPart->closeUrl( );
}

void PMShell::showEvent( QShowEvent* ){
   activateDock( );
}

void PMShell::slotModified( )
{
   setCaption( m_pPart->url( ).prettyUrl( ) );
}

void PMShell::slotControlPointMsg( const QString& msg )
{
   if( msg.isEmpty( ) )
      m_pStatusBar->changeItem( msg, c_statusBarControlPoints );
   else
      m_pStatusBar->changeItem( QString( " " ) + msg + QString( " " ),
                                c_statusBarControlPoints );
}

bool PMShell::overwriteURL( const KUrl& u )
{
   int query = KMessageBox::Continue;

   if( u.isLocalFile( ) )
   {
      QFileInfo info;
      QString name( u.path( ) );
      info.setFile( name );
      if( info.exists( ) )
         query = KMessageBox::warningContinueCancel( 0, i18n( "A file with this name already exists.\nDo you want to overwrite it?" ), QString::null, KGuiItem( i18n( "Overwrite" ) ) );
   }
   return ( query == KMessageBox::Continue );
}

void PMShell::slotSelectedLayout( QAction* action )
{
   PMViewLayoutManager::theManager( )->displayLayout( action->data( ).toInt( ), this );
}

void PMShell::slotSaveViewLayout( )
{
   PMSaveViewLayoutDialog dlg( this );
   dlg.exec( );
}

void PMShell::slotViewsMenuAboutToShow( )
{
   KMenu* menu = m_pViewLayoutsAction->menu( );

   PMViewLayoutManager::theManager( )->fillPopupMenu( menu );
}

#include "pmshell.moc"
