/***************************************************************************
 *   Copyright (C) 2004, 2005 Thomas Nagy                                  *
 *   tnagy2^8@yahoo.fr                                                     *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License version 2        *
 *   as published by the Free Software Foundation (see COPYING)            *
 *                                                                         *
 *   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.                          *
 ***************************************************************************/

#include <qdragobject.h>
#include <qpainter.h>
#include <qwidgetstack.h>
#include <qtoolbutton.h>

#include <kstatusbar.h>
#include <kdebug.h>
#include <kglobal.h>
#include <ktip.h>
#include <kparts/part.h>
#include <kparts/partmanager.h>
#include <klineedit.h>
#include <kurl.h>
#include <kurldrag.h>
#include <kurlrequesterdlg.h>
#include <kconfig.h>
#include <kconfigdialog.h>
#include <kaboutdata.h>
#include <kfiledialog.h>
#include <kactionclasses.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kdeversion.h>
#include <kmenubar.h>
#include <kkeydialog.h>
#include <ktabwidget.h>
#include <kedittoolbar.h>
#include <kstdaccel.h>
#include <kaction.h>
#include <kstdaction.h>
#include <kedittoolbar.h>

#include "settings.h"
#include "prefs-base.h"
#include "KDissertPart.h"
#include "KDissertView.h"
#include "TextProperties.h"
#include "MiscProperties.h"
#include "KDissert.h"


KDissert::KDissert(KMdi::MdiMode mode)
	: KMdiMainFrm( 0, "KDissert", mode )
{
	resize( 800, 600 ); // start at 800x600 the first time

	setManagedDockPositionModeEnabled(true);
	setStandardMDIMenuEnabled(false);

	m_manager = new KParts::PartManager(this);
	connect(m_manager, SIGNAL(activePartChanged(KParts::Part*)),
			this, SLOT(createGUI(KParts::Part*)) );

	//dockManager->setReadDockConfigMode(KDockManager::RestoreAllDockwidgets);

#if KDE_IS_VERSION(3, 3, 0)
	setToolviewStyle( KMdi::TextAndIcon );
	tabWidget()->setHoverCloseButton( false );
#endif

	dockManager->finishReadDockConfig();
	setMenuForSDIModeSysButtons( menuBar() );
	setManagedDockPositionModeEnabled(true); 

	// accept dnd
	setAcceptDrops(true);

	// then, setup our actions
	setupActions();

	//createShellGUI( true );

	// and a status bar
	statusBar()->show();

	connect( this, SIGNAL( viewActivated( KMdiChildView * ) ), this, SLOT( currentChanged( KMdiChildView * ) ) );

	m_miscproperties = new MiscProperties(this, "misc_infos");
	m_miscproperties->setIcon( SmallIcon("attach") );
	m_miscproperties->setCaption( i18n("Attachments") );
	m_misctoolview = addToolWindow( m_miscproperties, KDockWidget::DockBottom, getMainDockWidget(), 20 );
	
	m_textproperties = new TextProperties(this, "properties");
	m_textproperties->setIcon( SmallIcon("pencil") );
	m_textproperties->setCaption( i18n("Item Text") );
	m_textpropertiestoolview = addToolWindow( m_textproperties, KDockWidget::DockBottom, getMainDockWidget(), 20 );

	m_treeviewstack = new QWidgetStack(this, "treeview_stack");
	m_treeviewstack->setIcon( SmallIcon("kdissert") );
	m_treeviewstack->setCaption( i18n("Tree View") );
	m_lframe = new QFrame(m_treeviewstack);
	m_treeviewstack->addWidget( m_lframe );
	m_listtoolview = addToolWindow( m_treeviewstack, KDockWidget::DockLeft, getMainDockWidget(), 30 );

	/*
	m_navigationstack = new QWidgetStack(this, "nav_stack");
	m_navigationstack->setIcon( SmallIcon("goto") );
	m_navigationstack->setCaption( i18n("Navigation") );
	m_cframe = new QFrame(m_navigationstack);
	m_navigationstack->addWidget( m_cframe );
	m_navtoolview = addToolWindow( m_navigationstack, KDockWidget::DockLeft, getMainDockWidget(), 30 );
	*/
	
#if KDE_IS_VERSION(3, 3, 0)
	QToolButton *but = new QToolButton(tabWidget());
	but->setIconSet(SmallIcon("tab_remove"));
	but->adjustSize();
	but->hide();
	connect(but, SIGNAL(clicked()), actionCollection()->action( "file_close" ), SIGNAL(activated()));
	tabWidget()->setCornerWidget(but, TopRight);
#endif

	// Apply the saved mainwindow settings, if any, and ask the mainwindow
	// to automatically save settings if changed: window size, toolbar
	// position, icon size, etc.
	setAutoSaveSettings();

	KConfig *cfg = new KConfig("kdissert_dockposrc");
	if (cfg->readNumEntry("kdissert_main_dock_settings", 0) == 1) manager()->readConfig(cfg);
	cfg->writeEntry("kdissert_main_dock_settings", 1);
	delete cfg;
	
	//changeCaption(QString::null);
	showTipOnStart();
}

KDissert::~KDissert()
{
	KConfig *cfg = new KConfig("kdissert_dockposrc");
	manager()->writeConfig(cfg);
	delete cfg;
}

void KDissert::setupActions()
{
	setXMLFile("kdissertui.rc");

	KStdAction::openNew(this, SLOT(slotFileNew()), actionCollection());
	KStdAction::open(this, SLOT(slotFileOpen()), actionCollection());

	m_openRecentAction = KStdAction::openRecent(this, SLOT(openURL(const KURL&)), actionCollection());
	m_openRecentAction->setWhatsThis( i18n("Opens recently opened file.") );
	m_openRecentAction->loadEntries( kapp->config(), "RecentFiles" );

	KStdAction::tipOfDay( this, SLOT( showTip() ), actionCollection() 
			)->setWhatsThis(i18n("This shows useful tips on the use of this application."));

	KStdAction::close(this, SLOT(slotFileClose()), actionCollection());
	KStdAction::quit(this, SLOT(slotFileQuit()), actionCollection());

	m_toolbarAction = KStdAction::showToolbar(this, SLOT(optionsShowToolbar()), actionCollection());
	m_statusbarAction = KStdAction::showStatusbar(this, SLOT(optionsShowStatusbar()), actionCollection());

	KStdAction::keyBindings(this, SLOT(optionsConfigureKeys()), actionCollection());
	KStdAction::configureToolbars(this, SLOT(optionsConfigureToolbars()), actionCollection());
	KStdAction::preferences(this, SLOT(optionsPreferences()), actionCollection());


	new KAction( i18n("Focus on Text Panel"), "F2", this, SLOT(slotFocusOnTPanel()), actionCollection(), "kdissert_focustpanel");
	new KAction( i18n("Focus on Map"), "F3", this, SLOT(slotFocusOnMap()), actionCollection(), "kdissert_focusmap");
	//    new KAction( i18n("Focus on Attachement Panel"), "F3", this, SLOT(slotFocusOnAPanel()), actionCollection(), "kdissert_focusapanel");

	/* new KAction(i18n("&Add Link..."), 0, this,
			SLOT(slotLinkAdd()), actionCollection(), "link_add");
	new KAction(i18n("&Remove Link"), 0, this,
			SLOT(slotLinkRemove()), actionCollection(), "link_remove");
	new KAction(i18n("Open Link"), 0, this,
			SLOT(slotLinkOpen()), actionCollection(), "link_open");
	new KAction(i18n("&Modify Link..."), 0, this,
			SLOT(slotLinkModify()), actionCollection(), "link_modify");
	new KAction(i18n("&Copy Link Location"), 0, this,
			SLOT(slotLinkCopy()), actionCollection(), "link_copy");
*/
	createGUI( NULL );
}

void KDissert::showTip() 
{
	KTipDialog::showTip(this,QString::null,true);
}

void KDissert::showTipOnStart()
{
	KTipDialog::showTip(this);
}

void KDissert::slotFileNew()
{
	KDissertView *view = new KDissertView(this);
	m_manager->addPart( view->part() );

	connect(view->part(), SIGNAL(itemSelected(DDataItem*, bool)), m_textproperties, SLOT(setCurrentItem(DDataItem*, bool)));
	connect(view->part(), SIGNAL(itemChanged(int)), m_textproperties, SLOT(itemChanged(int)) );
	connect(view->part(), SIGNAL(itemSelected(DDataItem*, bool)), m_miscproperties, SLOT(setCurrentItem(DDataItem*, bool)));
	connect(view, SIGNAL(newCaption(const QString &)), this, SLOT(setCaption(const QString &)));

	addWindow( view );

	m_treeviewstack->addWidget( view->m_lwidget );
	//m_navigationstack->addWidget( view->m_cwidget );
	m_views += view;

	connect(view->part(), SIGNAL(accessed(const KURL&)), this, SLOT(slotFileOpened(const KURL&)) );

	currentChanged( view );
}

void KDissert::slotFileOpened(const KURL & url)
{
	m_openRecentAction->addURL(url);
	m_openRecentAction->saveEntries( kapp->config(), "RecentFiles" );
	//statusBar()->message(i18n("The project was saved")+" "+url.prettyURL(), 5000);
}

void KDissert::slotFileOpen()
{
	KURL url = KFileDialog::getOpenURL(QString::null,
			i18n("*.kdi|kdissert Project (*.kdi)") +"\n"+
			i18n("*.mm|Freemind Files (*.mm)") +"\n"+
			i18n("*.kno|Knowit Files (*.kno)") ,
			NULL, i18n("Open Mindmap Project"));

	if (url.isEmpty())
		return;

	openURL(url);
}

void KDissert::openURL(const KURL & url)
{
	// check if the url is not already opened first
	QValueList<KDissertView*>::iterator it  = m_views.begin();
	QValueList<KDissertView*>::iterator end = m_views.end();
	for (; it != end; ++it)
	{
		KDissertView *view = *it;
		if (view->part()->url() == url)
		{
			activateView(view);
			return;
		}
	}

	KDissertView *view = new KDissertView(this);
	m_manager->addPart( view->part() );

	connect(view->part(), SIGNAL(itemSelected(DDataItem*, bool)), m_textproperties, SLOT(setCurrentItem(DDataItem*, bool)));
	connect(view->part(), SIGNAL(itemChanged(int)), m_textproperties, SLOT(itemChanged(int)) );
	connect(view->part(), SIGNAL(itemSelected(DDataItem*, bool)), m_miscproperties, SLOT(setCurrentItem(DDataItem*, bool)));
	connect(view->part(), SIGNAL(accessed(const KURL&)), this, SLOT(slotFileOpened(const KURL&)) );
	connect(view, SIGNAL(newCaption(const QString &)), this, SLOT(setCaption(const QString &)));

	addWindow( view );

	// add the tree view to the widget stack
	m_treeviewstack->addWidget( view->m_lwidget );
	//m_navigationstack->addWidget( view->m_cwidget );
	m_views += view;

	view->part()->openURL(url);
	currentChanged( view );
}

void KDissert::currentChanged( KMdiChildView *current )
{
	//kdWarning()<<"current view changed"<<endl;
	if (!current)
	{
		m_manager->setActivePart(NULL);
		m_treeviewstack->raiseWidget( m_lframe );
		return;
	}

	// switch to the corresponding document
	if ( m_views.contains( (KDissertView*) current ) )
	{
		KDissertView *view = (KDissertView*) current;
		view->updateCaption();
		m_manager->setActivePart( view->part() );

		/*	if (view->part()->url().isValid())
			{
			m_openRecentAction->addURL(view->part()->url());
			}*/

		m_treeviewstack->raiseWidget( view->m_lwidget );
	}
}

void KDissert::slotFileClose()
{
	requestClose( activeWindow() );
}

bool KDissert::requestClose(KMdiChildView* v)
{
	//    kdWarning()<<"closing view"<<v<<endl;
	//    if (view == NULL)
	//	return;

	if (v == NULL)
	{
		if ( m_views.count() == 1)
		{
			KDissertView *view = m_views[0];
			if (view->part()->queryClose())
			{
				m_manager->removePart( view->part() );

				//m_navigationstack->removeWidget( view->m_cwidget );
				//m_navigationstack->raiseWidget( m_cframe );
				
				m_treeviewstack->removeWidget( view->m_lwidget );
				m_treeviewstack->raiseWidget( m_lframe );

				closeWindow( view );
				m_views.clear();
				return true;
			}
			return false;
		}
		return true;
	}

	// TODO : warning : we are using only KDissertView parts for the moment
	// what will happen if we load other kind of parts ? (ita)
	KDissertView *view = (KDissertView*) v;
	if ( m_views.contains( view ) )
	{
		if ( view->part()->queryClose() )
		{
			m_views.remove( view );
			m_manager->removePart( view->part() );
			m_treeviewstack->removeWidget( view->m_lwidget );
			//m_navigationstack->removeWidget( view->m_cwidget );

			closeWindow( view );
			return true;
		}
		return false;
	}
	return true;
}

void KDissert::slotFileQuit()
{
	close();
}

void KDissert::optionsShowToolbar()
{
	if (m_toolbarAction->isChecked()) toolBar()->show();
	else toolBar()->hide();
}

void KDissert::optionsShowStatusbar()
{
	if (m_statusbarAction->isChecked()) statusBar()->show();
	else statusBar()->hide();
}

void KDissert::optionsConfigureKeys()
{
	//KKeyDialog::configure(actionCollection());
	KKeyDialog dlg( false, this );
	QPtrList<KXMLGUIClient> clients = guiFactory()->clients();

	for( QPtrListIterator<KXMLGUIClient> it( clients ); it.current(); ++it )
		dlg.insert ( (*it)->actionCollection(), (*it)->instance()->aboutData()->programName() );

	dlg.configure();

	for (unsigned int i=0; i<m_views.count(); i++)
	{
		m_views[i]->part()->reloadXML();
	}
}

void KDissert::optionsConfigureToolbars()
{
	KEditToolbar dlg(guiFactory());
	if (dlg.exec())
	{
		createGUI( m_manager->activePart() );
	}
}

void KDissert::optionsPreferences()
{
	// The preference dialog is derived from prefs-base.ui which is subclassed into Prefs
	//
	// compare the names of the widgets in the .ui file 
	// to the names of the variables in the .kcfg file
	if (KConfigDialog::showDialog("settings"))
		return;	

	KConfigDialog *dialog = new KConfigDialog(this, "settings", Settings::self(), KDialogBase::Swallow);
	dialog->addPage(new Prefs_base(), i18n("General"), "package_settings");
	connect(dialog, SIGNAL(settingsChanged()), this, SLOT(settingsChanged()));
	dialog->show();
}

void KDissert::settingsChanged()
{
	// tell the truth to our documents
	QValueList<KDissertView*>::iterator it  = m_views.begin();
	QValueList<KDissertView*>::iterator end = m_views.end();
	for (; it != end; ++it)
	{
		KDissertView *view = *it;
		view->part()->settingsChanged();
	} 
}

void KDissert::dragEnterEvent(QDragEnterEvent *event)
{
	// accept uri drops only
	event->accept(KURLDrag::canDecode(event));
}

void KDissert::dropEvent(QDropEvent *event)
{
	KURL::List urls;

	// see if we can decode a URI.. if not, just ignore it
	if (KURLDrag::decode(event, urls) && !urls.isEmpty())
	{
		// okay, we have a URI.. process it
		const KURL &url = urls.first();

		// load in the file
		openURL(url);
	}
}

bool KDissert::queryClose()
{
	QValueList<KDissertView*>::iterator it;

	// check if we can close all documents
	for (it = m_views.begin(); it != m_views.end(); ++it)
	{
		// kdWarning()<<"searching for the part"<<endl;
		KDissertView *view = *it;
		if (!view->part()->queryClose())
		{
			return false;
		}
	}

	// and now close the documents
	for (it = m_views.begin(); it != m_views.end(); ++it)
	{
		// now close all views
		KDissertView *view = *it;

		m_manager->removePart( view->part() );
		closeWindow( view );
	}

	m_openRecentAction->saveEntries( kapp->config(), "RecentFiles" );

	return true;
}

void KDissert::slotFocusOnTPanel()
{
	m_textproperties->summaryedit->setFocus();
}

void KDissert::slotFocusOnMap()
{
	KDissertView* v = (KDissertView*) activeWindow();
	if (!v) return;

	v->part()->widget()->setFocus();
}

void KDissert::slotSetStatusBarText(const QString & mes)
{
	statusBar()->message(mes, 5000); 
}

#include "KDissert.moc"
 
 
 
