diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 4aed2c8219774f5d797760606b8489a92ddc5163 (patch) | |
tree | 3f8c130f7d269626bf6a9447407ef6c35954426a /kate/app | |
download | tdebase-4aed2c8219774f5d797760606b8489a92ddc5163.tar.gz tdebase-4aed2c8219774f5d797760606b8489a92ddc5163.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kate/app')
53 files changed, 14972 insertions, 0 deletions
diff --git a/kate/app/Makefile.am b/kate/app/Makefile.am new file mode 100644 index 000000000..6175f3203 --- /dev/null +++ b/kate/app/Makefile.am @@ -0,0 +1,29 @@ +lib_LTLIBRARIES = libkateinterfaces.la +bin_PROGRAMS = +kdeinit_LTLIBRARIES = kate.la kwrite.la + +libkateinterfaces_la_SOURCES = kateapp.cpp kateconfigdialog.cpp kateconfigplugindialogpage.cpp \ + kateconsole.cpp katedocmanager.cpp katefilelist.cpp katefileselector.cpp \ + katemainwindow.cpp katepluginmanager.cpp \ + kateviewmanager.cpp kateviewspace.cpp \ + katemainwindowiface.skel katemainwindowiface.cpp kategrepdialog.cpp \ + katemailfilesdialog.cpp kbookmarkhandler.cpp \ + katedocmanageriface.skel kateappIface.cpp kateappIface.skel katedocmanageriface.cpp \ + kateexternaltools.cpp katesavemodifieddialog.cpp kateviewspacecontainer.cpp \ + katemwmodonhddialog.cpp katesession.cpp katemdi.cpp katetabwidget.cpp + +libkateinterfaces_la_LIBADD = ../interfaces/libkateinterfacesprivate.la $(LIB_KUTILS) ../utils/libkateutils.la + +libkateinterfaces_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) -no-undefined + +kate_la_SOURCES = katemain.cpp +kate_la_LIBADD = libkateinterfaces.la +kate_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) -module -avoid-version + +kwrite_la_SOURCES = kwritemain.cpp +kwrite_la_LIBADD = -lkatepartinterfaces ../utils/libkateutils.la +kwrite_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) -module -avoid-version + +METASOURCES = AUTO + +INCLUDES= -I../interfaces -I$(srcdir)/../lib $(all_includes) diff --git a/kate/app/kateapp.cpp b/kate/app/kateapp.cpp new file mode 100644 index 000000000..00b58b8b5 --- /dev/null +++ b/kate/app/kateapp.cpp @@ -0,0 +1,399 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kateapp.h" +#include "kateapp.moc" + +#include "katedocmanager.h" +#include "katepluginmanager.h" +#include "kateviewmanager.h" +#include "kateappIface.h" +#include "katesession.h" +#include "katemainwindow.h" + +#include "../interfaces/application.h" + +#include <kdeversion.h> +#include <kcmdlineargs.h> +#include <dcopclient.h> +#include <kconfig.h> +#include <kwin.h> +#include <ktip.h> +#include <kdebug.h> +#include <klibloader.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <ksimpleconfig.h> +#include <kstartupinfo.h> + +#include <qfile.h> +#include <qtimer.h> +#include <qdir.h> +#include <qtextcodec.h> + +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> + +KateApp::KateApp (KCmdLineArgs *args) + : KApplication () + , m_args (args) + , m_shouldExit (false) +{ + // Don't handle DCOP requests yet + dcopClient()->suspend(); + + // insert right translations for the katepart + KGlobal::locale()->insertCatalogue("katepart"); + + // some global default + Kate::Document::setFileChangedDialogsActivated (true); + + // application interface + m_application = new Kate::Application (this); + + // doc + project man + m_docManager = new KateDocManager (this); + + // init all normal plugins + m_pluginManager = new KatePluginManager (this); + + // session manager up + m_sessionManager = new KateSessionManager (this); + + // application dcop interface + m_obj = new KateAppDCOPIface (this); + + kdDebug()<<"Setting KATE_PID: '"<<getpid()<<"'"<<endl; + ::setenv( "KATE_PID", QString("%1").arg(getpid()).latin1(), 1 ); + + // handle restore different + if (isRestored()) + { + restoreKate (); + } + else + { + // let us handle our command line args and co ;) + // we can exit here if session chooser decides + if (!startupKate ()) + { + m_shouldExit = true; + return; + } + } + + // Ok. We are ready for DCOP requests. + dcopClient()->resume(); +} + +KateApp::~KateApp () +{ + // cu dcop interface + delete m_obj; + + // cu plugin manager + delete m_pluginManager; + + // delete this now, or we crash + delete m_docManager; +} + +KateApp *KateApp::self () +{ + return (KateApp *) kapp; +} + +Kate::Application *KateApp::application () +{ + return m_application; +} + +/** + * Has always been the Kate Versioning Scheme: + * KDE X.Y.Z contains Kate X-1.Y.Z + */ +QString KateApp::kateVersion (bool fullVersion) +{ + return fullVersion ? QString ("%1.%2.%3").arg(KDE::versionMajor() - 1).arg(KDE::versionMinor()).arg(KDE::versionRelease()) + : QString ("%1.%2").arg(KDE::versionMajor() - 1).arg(KDE::versionMinor()); +} + +void KateApp::restoreKate () +{ + // restore the nice files ;) we need it + Kate::Document::setOpenErrorDialogsActivated (false); + + // activate again correct session!!! + sessionConfig()->setGroup("General"); + QString lastSession (sessionConfig()->readEntry ("Last Session", "default.katesession")); + sessionManager()->activateSession (new KateSession (sessionManager(), lastSession, ""), false, false, false); + + m_docManager->restoreDocumentList (sessionConfig()); + + Kate::Document::setOpenErrorDialogsActivated (true); + + // restore all windows ;) + for (int n=1; KMainWindow::canBeRestored(n); n++) + newMainWindow(sessionConfig(), QString ("%1").arg(n)); + + // oh, no mainwindow, create one, should not happen, but make sure ;) + if (mainWindows() == 0) + newMainWindow (); + + // Do not notify about start there: this makes kicker crazy and kate go to a wrong desktop. + // KStartupInfo::setNewStartupId( activeMainWindow(), startupId()); +} + +bool KateApp::startupKate () +{ + // user specified session to open + if (m_args->isSet ("start")) + { + sessionManager()->activateSession (sessionManager()->giveSession (QString::fromLocal8Bit(m_args->getOption("start"))), false, false); + } + else + { + // let the user choose session if possible + if (!sessionManager()->chooseSession ()) + { + // we will exit kate now, notify the rest of the world we are done + KStartupInfo::appStarted (startupId()); + return false; + } + } + + // oh, no mainwindow, create one, should not happen, but make sure ;) + if (mainWindows() == 0) + newMainWindow (); + + // notify about start + KStartupInfo::setNewStartupId( activeMainWindow(), startupId()); + + QTextCodec *codec = m_args->isSet("encoding") ? QTextCodec::codecForName(m_args->getOption("encoding")) : 0; + + bool tempfileSet = KCmdLineArgs::isTempFileSet(); + + Kate::Document::setOpenErrorDialogsActivated (false); + uint id = 0; + for (int z=0; z<m_args->count(); z++) + { + // this file is no local dir, open it, else warn + bool noDir = !m_args->url(z).isLocalFile() || !QDir (m_args->url(z).path()).exists(); + + if (noDir) + { + // open a normal file + if (codec) + id = activeMainWindow()->viewManager()->openURL( m_args->url(z), codec->name(), false, tempfileSet ); + else + id = activeMainWindow()->viewManager()->openURL( m_args->url(z), QString::null, false, tempfileSet ); + } + else + KMessageBox::sorry( activeMainWindow(), + i18n("The file '%1' could not be opened: it is not a normal file, it is a folder.").arg(m_args->url(z).url()) ); + } + + Kate::Document::setOpenErrorDialogsActivated (true); + + // handle stdin input + if( m_args->isSet( "stdin" ) ) + { + QTextIStream input(stdin); + + // set chosen codec + if (codec) + input.setCodec (codec); + + QString line; + QString text; + + do + { + line = input.readLine(); + text.append( line + "\n" ); + } while( !line.isNull() ); + + openInput (text); + } + else if ( id ) + activeMainWindow()->viewManager()->activateView( id ); + + if ( activeMainWindow()->viewManager()->viewCount () == 0 ) + activeMainWindow()->viewManager()->activateView(m_docManager->firstDocument()->documentNumber()); + + int line = 0; + int column = 0; + bool nav = false; + + if (m_args->isSet ("line")) + { + line = m_args->getOption ("line").toInt(); + nav = true; + } + + if (m_args->isSet ("column")) + { + column = m_args->getOption ("column").toInt(); + nav = true; + } + + if (nav) + activeMainWindow()->viewManager()->activeView ()->setCursorPosition (line, column); + + // show the nice tips + KTipDialog::showTip(activeMainWindow()); + + return true; +} + +void KateApp::shutdownKate (KateMainWindow *win) +{ + if (!win->queryClose_internal()) + return; + + sessionManager()->saveActiveSession(true, true); + + // detach the dcopClient + dcopClient()->detach(); + + // cu main windows + while (!m_mainWindows.isEmpty()) + delete m_mainWindows[0]; + + quit (); +} + +KatePluginManager *KateApp::pluginManager() +{ + return m_pluginManager; +} + +KateDocManager *KateApp::documentManager () +{ + return m_docManager; +} + +KateSessionManager *KateApp::sessionManager () +{ + return m_sessionManager; +} + +bool KateApp::openURL (const KURL &url, const QString &encoding, bool isTempFile) +{ + KateMainWindow *mainWindow = activeMainWindow (); + + if (!mainWindow) + return false; + + QTextCodec *codec = encoding.isEmpty() ? 0 : QTextCodec::codecForName(encoding.latin1()); + + kdDebug () << "OPEN URL "<< encoding << endl; + + // this file is no local dir, open it, else warn + bool noDir = !url.isLocalFile() || !QDir (url.path()).exists(); + + if (noDir) + { + // open a normal file + if (codec) + mainWindow->viewManager()->openURL( url, codec->name(), true, isTempFile ); + else + mainWindow->viewManager()->openURL( url, QString::null, true, isTempFile ); + } + else + KMessageBox::sorry( mainWindow, + i18n("The file '%1' could not be opened: it is not a normal file, it is a folder.").arg(url.url()) ); + + return true; +} + +bool KateApp::setCursor (int line, int column) +{ + KateMainWindow *mainWindow = activeMainWindow (); + + if (!mainWindow) + return false; + + mainWindow->viewManager()->activeView ()->setCursorPosition (line, column); + + return true; +} + +bool KateApp::openInput (const QString &text) +{ + activeMainWindow()->viewManager()->openURL( "", "", true ); + + if (!activeMainWindow()->viewManager()->activeView ()) + return false; + + activeMainWindow()->viewManager()->activeView ()->getDoc()->setText (text); + + return true; +} + +KateMainWindow *KateApp::newMainWindow (KConfig *sconfig, const QString &sgroup) +{ + KateMainWindow *mainWindow = new KateMainWindow (sconfig, sgroup); + m_mainWindows.push_back (mainWindow); + + if ((mainWindows() > 1) && m_mainWindows[m_mainWindows.count()-2]->viewManager()->activeView()) + mainWindow->viewManager()->activateView ( m_mainWindows[m_mainWindows.count()-2]->viewManager()->activeView()->getDoc()->documentNumber() ); + else if ((mainWindows() > 1) && (m_docManager->documents() > 0)) + mainWindow->viewManager()->activateView ( (m_docManager->document(m_docManager->documents()-1))->documentNumber() ); + else if ((mainWindows() > 1) && (m_docManager->documents() < 1)) + mainWindow->viewManager()->openURL ( KURL() ); + + mainWindow->show (); + + return mainWindow; +} + +void KateApp::removeMainWindow (KateMainWindow *mainWindow) +{ + m_mainWindows.remove (mainWindow); +} + +KateMainWindow *KateApp::activeMainWindow () +{ + if (m_mainWindows.isEmpty()) + return 0; + + int n = m_mainWindows.findIndex ((KateMainWindow *)activeWindow()); + + if (n < 0) + n=0; + + return m_mainWindows[n]; +} + +uint KateApp::mainWindows () const +{ + return m_mainWindows.size(); +} + +KateMainWindow *KateApp::mainWindow (uint n) +{ + if (n < m_mainWindows.size()) + return m_mainWindows[n]; + + return 0; +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kate/app/kateapp.h b/kate/app/kateapp.h new file mode 100644 index 000000000..ff1d9d967 --- /dev/null +++ b/kate/app/kateapp.h @@ -0,0 +1,243 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __KATE_APP_H__ +#define __KATE_APP_H__ + +#include "katemain.h" + +#include <kapplication.h> + +#include <qvaluelist.h> + +class KateSessionManager; +class KateAppDCOPIface; + +namespace Kate { + class Application; +} + +class KCmdLineArgs; + +/** + * Kate Application + * This class represents the core kate application object + */ +class KDE_EXPORT KateApp : public KApplication +{ + Q_OBJECT + + /** + * constructors & accessor to app object + plugin interface for it + */ + public: + /** + * application constructor + * @param args parsed command line args + */ + KateApp (KCmdLineArgs *args); + + /** + * application destructor + */ + ~KateApp (); + + /** + * static accessor to avoid casting ;) + * @return app instance + */ + static KateApp *self (); + + /** + * accessor to the Kate::Application plugin interface + * @return application plugin interface + */ + Kate::Application *application (); + + /** + * Returns the current Kate version (X.Y) or (X.Y.Z) + * @param fullVersion should full version be returned? + * @return Kate version + */ + static QString kateVersion (bool fullVersion = true); + + /** + * kate init + */ + private: + /** + * restore a old kate session + */ + void restoreKate (); + + /** + * try to start kate + * @return success, if false, kate should exit + */ + bool startupKate (); + + /** + * kate shutdown + */ + public: + /** + * shutdown kate application + * @param win mainwindow which is used for dialogs + */ + void shutdownKate (KateMainWindow *win); + + /** + * application should exit + * @return should we exit? + */ + bool shouldExit () { return m_shouldExit; } + + /** + * other accessors for global unique instances + */ + public: + /** + * accessor to plugin manager + * @return plugin manager instance + */ + KatePluginManager *pluginManager(); + + /** + * accessor to document manager + * @return document manager instance + */ + KateDocManager *documentManager (); + + /** + * accessor to session manager + * @return session manager instance + */ + KateSessionManager *sessionManager (); + + /** + * window management + */ + public: + /** + * create a new main window, use given config if any for restore + * @param sconfig session config object + * @param sgroup session group for this window + * @return new constructed main window + */ + KateMainWindow *newMainWindow (KConfig *sconfig = 0, const QString &sgroup = ""); + + /** + * removes the mainwindow given, DOES NOT DELETE IT + * @param mainWindow window to remove + */ + void removeMainWindow (KateMainWindow *mainWindow); + + /** + * give back current active main window + * can only be 0 at app start or exit + * @return current active main window + */ + KateMainWindow *activeMainWindow (); + + /** + * give back number of existing main windows + * @return number of main windows + */ + uint mainWindows () const; + + /** + * give back the window you want + * @param n window index + * @return requested main window + */ + KateMainWindow *mainWindow (uint n); + + /** + * some stuff for the dcop API + */ + public: + /** + * open url with given encoding + * used by kate if --use given + * @param url filename + * @param encoding encoding name + * @param isTempFile if set to true and the file is a local file, it will be deleted when the document is closed. + * @return success + */ + bool openURL (const KURL &url, const QString &encoding, bool isTempFile ); + + /** + * position cursor in current active view + * @param line line to set + * @param column column to set + * @return success + */ + bool setCursor (int line, int column); + + /** + * helper to handle stdin input + * open a new document/view, fill it with the text given + * @param text text to fill in the new doc/view + * @return success + */ + bool openInput (const QString &text); + + private: + /** + * kate's command line args + */ + KCmdLineArgs *m_args; + + /** + * plugin interface + */ + Kate::Application *m_application; + + /** + * document manager + */ + KateDocManager *m_docManager; + + /** + * plugin manager + */ + KatePluginManager *m_pluginManager; + + /** + * session manager + */ + KateSessionManager *m_sessionManager; + + /** + * known main windows + */ + QValueList<KateMainWindow*> m_mainWindows; + + /** + * dcop interface + */ + KateAppDCOPIface *m_obj; + + /** + * should exit flag + */ + bool m_shouldExit; +}; + +#endif diff --git a/kate/app/kateappIface.cpp b/kate/app/kateappIface.cpp new file mode 100644 index 000000000..b70be960a --- /dev/null +++ b/kate/app/kateappIface.cpp @@ -0,0 +1,104 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kateappIface.h" + +#include "kateapp.h" +#include "katesession.h" +#include "katedocmanager.h" +#include "katemainwindow.h" + +KateAppDCOPIface::KateAppDCOPIface (KateApp *app) : DCOPObject ("KateApplication") + , m_app (app) +{ +} + +DCOPRef KateAppDCOPIface::documentManager () +{ + return DCOPRef (m_app->documentManager()->dcopObject ()); +} + +DCOPRef KateAppDCOPIface::activeMainWindow () +{ + KateMainWindow *win = m_app->activeMainWindow(); + + if (win) + return DCOPRef (win->dcopObject ()); + + return DCOPRef (); +} + +uint KateAppDCOPIface::activeMainWindowNumber () +{ + KateMainWindow *win = m_app->activeMainWindow(); + + if (win) + return win->mainWindowNumber (); + + return 0; +} + + +uint KateAppDCOPIface::mainWindows () +{ + return m_app->mainWindows (); +} + +DCOPRef KateAppDCOPIface::mainWindow (uint n) +{ + KateMainWindow *win = m_app->mainWindow(n); + + if (win) + return DCOPRef (win->dcopObject ()); + + return DCOPRef (); +} + +bool KateAppDCOPIface::openURL (KURL url, QString encoding) +{ + return m_app->openURL (url, encoding, false); +} + +bool KateAppDCOPIface::openURL (KURL url, QString encoding, bool isTempFile) +{ + return m_app->openURL (url, encoding, isTempFile); +} + +bool KateAppDCOPIface::setCursor (int line, int column) +{ + return m_app->setCursor (line, column); +} + +bool KateAppDCOPIface::openInput (QString text) +{ + return m_app->openInput (text); +} + +bool KateAppDCOPIface::activateSession (QString session) +{ + m_app->sessionManager()->activateSession (m_app->sessionManager()->giveSession (session)); + + return true; +} + +const QString & KateAppDCOPIface::session() const +{ + return m_app->sessionManager()->activeSession()->sessionName(); +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kate/app/kateappIface.h b/kate/app/kateappIface.h new file mode 100644 index 000000000..577c36e41 --- /dev/null +++ b/kate/app/kateappIface.h @@ -0,0 +1,94 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _kateapp_Iface_h_ +#define _kateapp_Iface_h_ + +#include <dcopobject.h> +#include <dcopref.h> +#include <kurl.h> + +class KateApp; + +class KateAppDCOPIface : public DCOPObject +{ + K_DCOP + + public: + KateAppDCOPIface (KateApp *app); + + k_dcop: + DCOPRef documentManager (); + + DCOPRef activeMainWindow (); + + uint activeMainWindowNumber (); + + uint mainWindows (); + DCOPRef mainWindow (uint n = 0); + + /** + * open a file with given url and encoding + * will get view created + * @param url url of the file + * @param encoding encoding name + * @return success + */ + bool openURL (KURL url, QString encoding); + + /** + * Like the above, but adds an option to let the documentManager know + * if the file should be deleted when closed. + * @p isTempFile should be set to true with the --tempfile option set ONLY, + * files opened with this set to true will be deleted when closed. + */ + bool openURL(KURL url, QString encoding, bool isTempFile); + + /** + * set cursor of active view in active main window + * @param line line for cursor + * @param column column for cursor + * @return success + */ + bool setCursor (int line, int column); + + /** + * helper to handle stdin input + * open a new document/view, fill it with the text given + * @param text text to fill in the new doc/view + * @return success + */ + bool openInput (QString text); + + /** + * activate a given session + * @param session session name + * @return success + */ + bool activateSession (QString session); + + /** + * @return the name of the active session + */ + const QString & session() const; + + private: + KateApp *m_app; +}; + +#endif diff --git a/kate/app/kateconfigdialog.cpp b/kate/app/kateconfigdialog.cpp new file mode 100644 index 000000000..62d86054b --- /dev/null +++ b/kate/app/kateconfigdialog.cpp @@ -0,0 +1,441 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kateconfigdialog.h" +#include "kateconfigdialog.moc" + +#include "katemainwindow.h" + +#include "kateconsole.h" +#include "katedocmanager.h" +#include "katepluginmanager.h" +#include "kateconfigplugindialogpage.h" +#include "kateviewmanager.h" +#include "kateapp.h" +#include "katefileselector.h" +#include "katefilelist.h" +#include "kateexternaltools.h" + +#include <qbuttongroup.h> +#include <qcheckbox.h> +#include <qhbox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qpushbutton.h> +#include <qradiobutton.h> +#include <qspinbox.h> +#include <qvbox.h> +#include <qwhatsthis.h> +#include <qcombobox.h> + +#include <kinstance.h> +#include <kdebug.h> +#include <kdialogbase.h> +#include <kglobalaccel.h> +#include <kglobal.h> +#include <kglobalsettings.h> +#include <kiconloader.h> +#include <kkeydialog.h> +#include <klistbox.h> +#include <klocale.h> +#include <ksimpleconfig.h> +#include <kstdaction.h> +#include <kstandarddirs.h> +#include <kwin.h> +#include <kseparator.h> + +KateConfigDialog::KateConfigDialog ( KateMainWindow *parent, Kate::View *view ) + : KDialogBase ( KDialogBase::TreeList, + i18n("Configure"), + KDialogBase::Ok | KDialogBase::Apply|KDialogBase::Cancel | KDialogBase::Help, + KDialogBase::Ok, + parent, + "configdialog" ) +{ + KConfig *config = KateApp::self()->config(); + + KWin::setIcons( winId(), KateApp::self()->icon(), KateApp::self()->miniIcon() ); + + actionButton( KDialogBase::Apply)->setEnabled( false ); + + mainWindow = parent; + + setMinimumSize(600,400); + + v = view; + + pluginPages.setAutoDelete (false); + editorPages.setAutoDelete (false); + + QStringList path; + + setShowIconsInTreeList(true); + + path.clear(); + path << i18n("Application"); + setFolderIcon (path, SmallIcon("kate", KIcon::SizeSmall)); + + path.clear(); + + //BEGIN General page + path << i18n("Application") << i18n("General"); + QFrame* frGeneral = addPage(path, i18n("General Options"), BarIcon("gohome", KIcon::SizeSmall)); + + QVBoxLayout *lo = new QVBoxLayout( frGeneral ); + lo->setSpacing(KDialog::spacingHint()); + config->setGroup("General"); + + // GROUP with the one below: "Appearance" + QButtonGroup *bgStartup = new QButtonGroup( 1, Qt::Horizontal, i18n("&Appearance"), frGeneral ); + lo->addWidget( bgStartup ); + + // show full path in title + config->setGroup("General"); + cb_fullPath = new QCheckBox( i18n("&Show full path in title"), bgStartup); + cb_fullPath->setChecked( mainWindow->viewManager()->getShowFullPath() ); + QWhatsThis::add(cb_fullPath,i18n("If this option is checked, the full document path will be shown in the window caption.")); + connect( cb_fullPath, SIGNAL( toggled( bool ) ), this, SLOT( slotChanged() ) ); + + + // GROUP with the one below: "Behavior" + bgStartup = new QButtonGroup( 1, Qt::Horizontal, i18n("&Behavior"), frGeneral ); + lo->addWidget( bgStartup ); + + // sync the konsole ? + cb_syncKonsole = new QCheckBox(bgStartup); + cb_syncKonsole->setText(i18n("Sync &terminal emulator with active document")); + cb_syncKonsole->setChecked(parent->syncKonsole); + QWhatsThis::add( cb_syncKonsole, i18n( + "If this is checked, the built in Konsole will <code>cd</code> to the directory " + "of the active document when started and whenever the active document changes, " + "if the document is a local file.") ); + connect( cb_syncKonsole, SIGNAL( toggled( bool ) ), this, SLOT( slotChanged() ) ); + + // modified files notification + cb_modNotifications = new QCheckBox( + i18n("Wa&rn about files modified by foreign processes"), bgStartup ); + cb_modNotifications->setChecked( parent->modNotification ); + QWhatsThis::add( cb_modNotifications, i18n( + "If enabled, when Kate receives focus you will be asked what to do with " + "files that have been modified on the hard disk. If not enabled, you will " + "be asked what to do with a file that has been modified on the hard disk only " + "when that file gains focus inside Kate.") ); + connect( cb_modNotifications, SIGNAL( toggled( bool ) ), + this, SLOT( slotChanged() ) ); + + // GROUP with the one below: "Meta-informations" + bgStartup = new QButtonGroup( 1, Qt::Horizontal, i18n("Meta-Information"), frGeneral ); + lo->addWidget( bgStartup ); + + // save meta infos + cb_saveMetaInfos = new QCheckBox( bgStartup ); + cb_saveMetaInfos->setText(i18n("Keep &meta-information past sessions")); + cb_saveMetaInfos->setChecked(KateDocManager::self()->getSaveMetaInfos()); + QWhatsThis::add(cb_saveMetaInfos, i18n( + "Check this if you want document configuration like for example " + "bookmarks to be saved past editor sessions. The configuration will be " + "restored if the document has not changed when reopened.")); + connect( cb_saveMetaInfos, SIGNAL( toggled( bool ) ), this, SLOT( slotChanged() ) ); + + // meta infos days + QHBox *hbDmf = new QHBox( bgStartup ); + hbDmf->setEnabled(KateDocManager::self()->getSaveMetaInfos()); + QLabel *lDmf = new QLabel( i18n("&Delete unused meta-information after:"), hbDmf ); + sb_daysMetaInfos = new QSpinBox( 0, 180, 1, hbDmf ); + sb_daysMetaInfos->setSpecialValueText(i18n("(never)")); + sb_daysMetaInfos->setSuffix(i18n(" day(s)")); + sb_daysMetaInfos->setValue( KateDocManager::self()->getDaysMetaInfos() ); + lDmf->setBuddy( sb_daysMetaInfos ); + connect( cb_saveMetaInfos, SIGNAL( toggled( bool ) ), hbDmf, SLOT( setEnabled( bool ) ) ); + connect( sb_daysMetaInfos, SIGNAL( valueChanged ( int ) ), this, SLOT( slotChanged() ) ); + + lo->addStretch(1); // :-] works correct without autoadd + //END General page + + path.clear(); + + //BEGIN Session page + path << i18n("Application") << i18n("Sessions"); + QFrame* frSessions = addPage(path, i18n("Session Management"), BarIcon("history", KIcon::SizeSmall)); + + lo = new QVBoxLayout( frSessions ); + lo->setSpacing(KDialog::spacingHint()); + + // GROUP with the one below: "Startup" + bgStartup = new QButtonGroup( 1, Qt::Horizontal, i18n("Elements of Sessions"), frSessions ); + lo->addWidget( bgStartup ); + + // restore view config + cb_restoreVC = new QCheckBox( bgStartup ); + cb_restoreVC->setText(i18n("Include &window configuration")); + config->setGroup("General"); + cb_restoreVC->setChecked( config->readBoolEntry("Restore Window Configuration", true) ); + QWhatsThis::add(cb_restoreVC, i18n( + "Check this if you want all your views and frames restored each time you open Kate")); + connect( cb_restoreVC, SIGNAL( toggled( bool ) ), this, SLOT( slotChanged() ) ); + + QRadioButton *rb1, *rb2, *rb3; + + sessions_start = new QButtonGroup( 1, Qt::Horizontal, i18n("Behavior on Application Startup"), frSessions ); + lo->add (sessions_start); + + sessions_start->setRadioButtonExclusive( true ); + sessions_start->insert( rb1=new QRadioButton( i18n("&Start new session"), sessions_start ), 0 ); + sessions_start->insert( rb2=new QRadioButton( i18n("&Load last-used session"), sessions_start ), 1 ); + sessions_start->insert( rb3=new QRadioButton( i18n("&Manually choose a session"), sessions_start ), 2 ); + + config->setGroup("General"); + QString sesStart (config->readEntry ("Startup Session", "manual")); + if (sesStart == "new") + sessions_start->setButton (0); + else if (sesStart == "last") + sessions_start->setButton (1); + else + sessions_start->setButton (2); + + connect(rb1, SIGNAL(toggled(bool)), this, SLOT(slotChanged())); + connect(rb2, SIGNAL(toggled(bool)), this, SLOT(slotChanged())); + connect(rb3, SIGNAL(toggled(bool)), this, SLOT(slotChanged())); + + sessions_exit = new QButtonGroup( 1, Qt::Horizontal, i18n("Behavior on Application Exit or Session Switch"), frSessions ); + lo->add (sessions_exit); + + sessions_exit->setRadioButtonExclusive( true ); + sessions_exit->insert( rb1=new QRadioButton( i18n("&Do not save session"), sessions_exit ), 0 ); + sessions_exit->insert( rb2=new QRadioButton( i18n("&Save session"), sessions_exit ), 1 ); + sessions_exit->insert( rb3=new QRadioButton( i18n("&Ask user"), sessions_exit ), 2 ); + + config->setGroup("General"); + QString sesExit (config->readEntry ("Session Exit", "save")); + if (sesExit == "discard") + sessions_exit->setButton (0); + else if (sesExit == "save") + sessions_exit->setButton (1); + else + sessions_exit->setButton (2); + + connect(rb1, SIGNAL(toggled(bool)), this, SLOT(slotChanged())); + connect(rb2, SIGNAL(toggled(bool)), this, SLOT(slotChanged())); + connect(rb3, SIGNAL(toggled(bool)), this, SLOT(slotChanged())); + + lo->addStretch(1); // :-] works correct without autoadd + //END Session page + + path.clear(); + + // file selector page + path << i18n("Application") << i18n("File Selector"); + + QVBox *page = addVBoxPage( path, i18n("File Selector Settings"), + BarIcon("fileopen", KIcon::SizeSmall) ); + fileSelConfigPage = new KFSConfigPage( page, "file selector config page", + mainWindow->fileselector ); + connect( fileSelConfigPage, SIGNAL( changed() ), this, SLOT( slotChanged() ) ); + path.clear(); + + path << i18n("Application") << i18n("Document List"); + page = addVBoxPage( path, i18n("Document List Settings"), + BarIcon("view_text", KIcon::SizeSmall) ); + filelistConfigPage = new KFLConfigPage( page, "file list config page", + mainWindow->filelist ); + connect( filelistConfigPage, SIGNAL( changed() ), this, SLOT( slotChanged() ) ); + path.clear(); + + path << i18n("Application") << i18n("Plugins"); + /*QVBox **/page=addVBoxPage(path,i18n("Plugin Manager"), + BarIcon("connect_established",KIcon::SizeSmall)); + KateConfigPluginPage *configPluginPage = new KateConfigPluginPage(page, this); + connect( configPluginPage, SIGNAL( changed() ), this, SLOT( slotChanged() ) ); + + // Tools->External Tools menu + path.clear(); + path << i18n("Application") << i18n("External Tools"); + page = addVBoxPage( path, i18n("External Tools"), + BarIcon("configure", KIcon::SizeSmall) ); + configExternalToolsPage = new KateExternalToolsConfigWidget(page, "external tools config page"); + connect( configExternalToolsPage, SIGNAL(changed()), this, SLOT(slotChanged()) ); + + // editor widgets from kwrite/kwdialog + path.clear(); + path << i18n("Editor"); + setFolderIcon (path, SmallIcon("edit", KIcon::SizeSmall)); + + for (uint i = 0; i < KTextEditor::configInterfaceExtension (v->document())->configPages (); i++) + { + path.clear(); + path << i18n("Editor") << KTextEditor::configInterfaceExtension (v->document())->configPageName (i); + /*QVBox **/page = addVBoxPage(path, KTextEditor::configInterfaceExtension (v->document())->configPageFullName (i), + KTextEditor::configInterfaceExtension (v->document())->configPagePixmap(i, KIcon::SizeSmall) ); + + KTextEditor::ConfigPage *cPage = KTextEditor::configInterfaceExtension (v->document())->configPage(i, page); + connect( cPage, SIGNAL( changed() ), this, SLOT( slotChanged() ) ); + editorPages.append (cPage); + } + + KatePluginList &pluginList (KatePluginManager::self()->pluginList()); + for (unsigned int i=0; i < pluginList.size(); ++i) + { + if ( pluginList[i].load + && Kate::pluginConfigInterfaceExtension(pluginList[i].plugin) ) + addPluginPage (pluginList[i].plugin); + } + + enableButtonSeparator(true); + dataChanged = false; + unfoldTreeList (); +} + +KateConfigDialog::~KateConfigDialog() +{ +} + +void KateConfigDialog::addPluginPage (Kate::Plugin *plugin) +{ + if (!Kate::pluginConfigInterfaceExtension(plugin)) + return; + + for (uint i=0; i<Kate::pluginConfigInterfaceExtension(plugin)->configPages(); i++) + { + QStringList path; + path.clear(); + path << i18n("Application")<<i18n("Plugins") << Kate::pluginConfigInterfaceExtension(plugin)->configPageName(i); + QVBox *page=addVBoxPage(path, Kate::pluginConfigInterfaceExtension(plugin)->configPageFullName(i), Kate::pluginConfigInterfaceExtension(plugin)->configPagePixmap(i, KIcon::SizeSmall)); + + PluginPageListItem *info=new PluginPageListItem; + info->plugin = plugin; + info->page = Kate::pluginConfigInterfaceExtension(plugin)->configPage (i, page); + connect( info->page, SIGNAL( changed() ), this, SLOT( slotChanged() ) ); + pluginPages.append(info); + } +} + +void KateConfigDialog::removePluginPage (Kate::Plugin *plugin) +{ + if (!Kate::pluginConfigInterfaceExtension(plugin)) + return; + + for (uint i=0; i<pluginPages.count(); i++) + { + if ( pluginPages.at(i)->plugin == plugin ) + { + QWidget *w = pluginPages.at(i)->page->parentWidget(); + delete pluginPages.at(i)->page; + delete w; + pluginPages.remove(pluginPages.at(i)); + i--; + } + } +} + +void KateConfigDialog::slotOk() +{ + slotApply(); + accept(); +} + +void KateConfigDialog::slotApply() +{ + KConfig *config = KateApp::self()->config(); + + // if data changed apply the kate app stuff + if( dataChanged ) + { + config->setGroup("General"); + + config->writeEntry("Restore Window Configuration", cb_restoreVC->isChecked()); + + int bu = sessions_start->id (sessions_start->selected()); + + if (bu == 0) + config->writeEntry ("Startup Session", "new"); + else if (bu == 1) + config->writeEntry ("Startup Session", "last"); + else + config->writeEntry ("Startup Session", "manual"); + + bu = sessions_exit->id (sessions_exit->selected()); + + if (bu == 0) + config->writeEntry ("Session Exit", "discard"); + else if (bu == 1) + config->writeEntry ("Session Exit", "save"); + else + config->writeEntry ("Session Exit", "ask"); + + config->writeEntry("Save Meta Infos", cb_saveMetaInfos->isChecked()); + KateDocManager::self()->setSaveMetaInfos(cb_saveMetaInfos->isChecked()); + + config->writeEntry("Days Meta Infos", sb_daysMetaInfos->value() ); + KateDocManager::self()->setDaysMetaInfos(sb_daysMetaInfos->value()); + + config->writeEntry("Modified Notification", cb_modNotifications->isChecked()); + mainWindow->modNotification = cb_modNotifications->isChecked(); + + mainWindow->syncKonsole = cb_syncKonsole->isChecked(); + + fileSelConfigPage->apply(); + + filelistConfigPage->apply(); + + configExternalToolsPage->apply(); + KateExternalToolsCommand::self()->reload(); + for (uint i=0; i < KateApp::self()->mainWindows(); i++) + { + KateMainWindow *win = KateApp::self()->mainWindow (i); + win->externalTools->reload(); + } + //mainWindow->externalTools->reload(); + + mainWindow->viewManager()->setShowFullPath( cb_fullPath->isChecked() ); // hm, stored 2 places :( + + mainWindow->saveOptions (); + + // save plugin config !! + KateApp::self()->pluginManager()->writeConfig (); + } + + // + // editor config ! (the apply() methode will check the changed state internally) + // + for (uint i=0; i<editorPages.count(); i++) + { + editorPages.at(i)->apply(); + } + + v->getDoc()->writeConfig(config); + + // + // plugins config ! (the apply() methode SHOULD check the changed state internally) + // + for (uint i=0; i<pluginPages.count(); i++) + { + pluginPages.at(i)->page->apply(); + } + + config->sync(); + + dataChanged = false; + actionButton( KDialogBase::Apply)->setEnabled( false ); +} + +void KateConfigDialog::slotChanged() +{ + dataChanged = true; + actionButton( KDialogBase::Apply)->setEnabled( true ); +} diff --git a/kate/app/kateconfigdialog.h b/kate/app/kateconfigdialog.h new file mode 100644 index 000000000..3fb523b61 --- /dev/null +++ b/kate/app/kateconfigdialog.h @@ -0,0 +1,82 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __kate_configdialog_h__ +#define __kate_configdialog_h__ + +#include "katemain.h" + +#include "../interfaces/plugin.h" +#include "../interfaces/pluginconfiginterface.h" +#include "../interfaces/pluginconfiginterfaceextension.h" + +#include <kate/document.h> +#include <ktexteditor/configinterfaceextension.h> + +#include <kdialogbase.h> + +class QCheckBox; +class QSpinBox; +class QButtonGroup; + +struct PluginPageListItem +{ + Kate::Plugin *plugin; + Kate::PluginConfigPage *page; +}; + +class KateConfigDialog : public KDialogBase +{ + Q_OBJECT + + public: + KateConfigDialog (KateMainWindow *parent, Kate::View *view); + ~KateConfigDialog (); + + public: + void addPluginPage (Kate::Plugin *plugin); + void removePluginPage (Kate::Plugin *plugin); + + protected slots: + void slotOk(); + void slotApply(); + void slotChanged(); + + private: + KateMainWindow *mainWindow; + + Kate::View* v; + bool dataChanged; + + QCheckBox *cb_fullPath; + QCheckBox *cb_syncKonsole; + QCheckBox *cb_modNotifications; + QCheckBox *cb_saveMetaInfos; + QSpinBox *sb_daysMetaInfos; + QCheckBox* cb_restoreVC; + QButtonGroup *sessions_start; + QButtonGroup *sessions_exit; + Kate::ConfigPage *fileSelConfigPage; + Kate::ConfigPage *filelistConfigPage; + Kate::ConfigPage *configExternalToolsPage; + QPtrList<PluginPageListItem> pluginPages; + QPtrList<KTextEditor::ConfigPage> editorPages; +}; + +#endif diff --git a/kate/app/kateconfigplugindialogpage.cpp b/kate/app/kateconfigplugindialogpage.cpp new file mode 100644 index 000000000..7269d5f5b --- /dev/null +++ b/kate/app/kateconfigplugindialogpage.cpp @@ -0,0 +1,121 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kateconfigplugindialogpage.h" +#include "kateconfigplugindialogpage.moc" + +#include "katepluginmanager.h" +#include "kateconfigdialog.h" +#include <klistbox.h> +#include "kateapp.h" +#include <qstringlist.h> +#include <qhbox.h> +#include <qlabel.h> +#include <klocale.h> +#include <qpushbutton.h> +#include <qtooltip.h> +#include <kiconloader.h> +#include <qwhatsthis.h> + +class KatePluginListItem : public QCheckListItem +{ + public: + KatePluginListItem(bool checked, KatePluginInfo *info, QListView *parent); + KatePluginInfo *info() const { return mInfo; } + + protected: + void stateChange(bool); + + private: + KatePluginInfo *mInfo; + bool silentStateChange; +}; + +KatePluginListItem::KatePluginListItem(bool checked, KatePluginInfo *info, QListView *parent) + : QCheckListItem(parent, info->service->name(), CheckBox) + , mInfo(info) + , silentStateChange(false) +{ + silentStateChange = true; + setOn(checked); + silentStateChange = false; +} + +void KatePluginListItem::stateChange(bool b) +{ + if(!silentStateChange) + static_cast<KatePluginListView *>(listView())->stateChanged(this, b); +} + +KatePluginListView::KatePluginListView(QWidget *parent, const char *name) + : KListView(parent, name) +{ +} + +void KatePluginListView::stateChanged(KatePluginListItem *item, bool b) +{ + emit stateChange(item, b); +} + +KateConfigPluginPage::KateConfigPluginPage(QWidget *parent, KateConfigDialog *dialog):QVBox(parent) +{ + myDialog=dialog; + + KatePluginListView* listView = new KatePluginListView(this); + listView->addColumn(i18n("Name")); + listView->addColumn(i18n("Comment")); + QWhatsThis::add(listView,i18n("Here you can see all available Kate plugins. Those with a check mark are loaded, and will be loaded again the next time Kate is started.")); + + connect(listView, SIGNAL(stateChange(KatePluginListItem *, bool)), this, SLOT(stateChange(KatePluginListItem *, bool))); + + KatePluginList &pluginList (KatePluginManager::self()->pluginList()); + for (unsigned int i=0; i < pluginList.size(); ++i) + { + KatePluginListItem *item = new KatePluginListItem(pluginList[i].load, &pluginList[i], listView); + item->setText(0, pluginList[i].service->name()); + item->setText(1, pluginList[i].service->comment()); + } +} + + void KateConfigPluginPage::stateChange(KatePluginListItem *item, bool b) +{ + if(b) + loadPlugin(item); + else + unloadPlugin(item); + + emit changed(); +} + +void KateConfigPluginPage::loadPlugin (KatePluginListItem *item) +{ + KatePluginManager::self()->loadPlugin (item->info()); + KatePluginManager::self()->enablePluginGUI (item->info()); + myDialog->addPluginPage (item->info()->plugin); + + item->setOn(true); +} + +void KateConfigPluginPage::unloadPlugin (KatePluginListItem *item) +{ + myDialog->removePluginPage (item->info()->plugin); + KatePluginManager::self()->unloadPlugin (item->info()); + + item->setOn(false); +} diff --git a/kate/app/kateconfigplugindialogpage.h b/kate/app/kateconfigplugindialogpage.h new file mode 100644 index 000000000..f65da880b --- /dev/null +++ b/kate/app/kateconfigplugindialogpage.h @@ -0,0 +1,69 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __KATE_CONFIGPLUGINDIALOGPAGE_H__ +#define __KATE_CONFIGPLUGINDIALOGPAGE_H__ + +#include "katemain.h" +#include "katepluginmanager.h" + +#include <klistview.h> + +#include <qvbox.h> + +class KatePluginListItem; + +class KatePluginListView : public KListView +{ + Q_OBJECT + + friend class KatePluginListItem; + + public: + KatePluginListView (QWidget *parent = 0, const char *name = 0); + + signals: + void stateChange(KatePluginListItem *, bool); + + private: + void stateChanged(KatePluginListItem *, bool); +}; + +class KateConfigPluginPage: public QVBox +{ + Q_OBJECT + + public: + KateConfigPluginPage(QWidget *parent, class KateConfigDialog *dialog); + ~KateConfigPluginPage(){;}; + + private: + class KateConfigDialog *myDialog; + + signals: + void changed(); + + private slots: + void stateChange(KatePluginListItem *, bool); + + void loadPlugin (KatePluginListItem *); + void unloadPlugin (KatePluginListItem *); +}; + +#endif diff --git a/kate/app/kateconsole.cpp b/kate/app/kateconsole.cpp new file mode 100644 index 000000000..5220859b2 --- /dev/null +++ b/kate/app/kateconsole.cpp @@ -0,0 +1,143 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2002 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kateconsole.h" +#include "kateconsole.moc" + +#include "katemain.h" +#include "katemdi.h" +#include "katemainwindow.h" +#include "kateviewmanager.h" + +#include <kate/view.h> +#include <kate/document.h> + +#include <kde_terminal_interface.h> + +#include <kparts/part.h> + +#include <kurl.h> +#include <klibloader.h> +#include <klocale.h> +#include <kdebug.h> +#include <kmessagebox.h> + +KateConsole::KateConsole (KateMainWindow *mw, KateMDI::ToolView* parent) + : QVBox (parent) + , m_part (0) + , m_mw (mw) + , m_toolView (parent) +{ +} + +KateConsole::~KateConsole () +{ + if (m_part) + disconnect ( m_part, SIGNAL(destroyed()), this, SLOT(slotDestroyed()) ); +} + +void KateConsole::loadConsoleIfNeeded() +{ + if (m_part) return; + + if (!topLevelWidget() || !parentWidget()) return; + if (!topLevelWidget() || !isVisibleTo(topLevelWidget())) return; + + KLibFactory *factory = KLibLoader::self()->factory("libkonsolepart"); + + if (!factory) return; + + m_part = static_cast<KParts::ReadOnlyPart *>(factory->create(this,"libkonsolepart", "KParts::ReadOnlyPart")); + + if (!m_part) return; + + setFocusProxy(m_part->widget()); + + KGlobal::locale()->insertCatalogue("konsole"); + + m_part->widget()->show(); + + connect ( m_part, SIGNAL(destroyed()), this, SLOT(slotDestroyed()) ); + + if (m_mw->viewManager()->activeView()) + if (m_mw->viewManager()->activeView()->getDoc()->url().isValid()) + cd(KURL( m_mw->viewManager()->activeView()->getDoc()->url().path() )); +} + +void KateConsole::slotDestroyed () +{ + m_part = 0; + + // hide the dockwidget + if (parentWidget()) + { + m_mw->hideToolView (m_toolView); + m_mw->centralWidget()->setFocus (); + } +} + +void KateConsole::showEvent(QShowEvent *) +{ + if (m_part) return; + + loadConsoleIfNeeded(); +} + +void KateConsole::cd (const KURL &url) +{ + loadConsoleIfNeeded(); + + if (!m_part) return; + + m_part->openURL (url); +} + +void KateConsole::sendInput( const QString& text ) +{ + loadConsoleIfNeeded(); + + if (!m_part) return; + + TerminalInterface *t = static_cast<TerminalInterface*>( m_part->qt_cast( "TerminalInterface" ) ); + + if (!t) return; + + t->sendInput (text); +} + +void KateConsole::slotPipeToConsole () +{ + if (KMessageBox::warningContinueCancel + (m_mw + , i18n ("Do you really want to pipe the text to the console? This will execute any contained commands with your user rights.") + , i18n ("Pipe to Console?") + , i18n("Pipe to Console"), "Pipe To Console Warning") != KMessageBox::Continue) + return; + + Kate::View *v = m_mw->viewManager()->activeView(); + + if (!v) + return; + + if (v->getDoc()->hasSelection ()) + sendInput (v->getDoc()->selection()); + else + sendInput (v->getDoc()->text()); +} diff --git a/kate/app/kateconsole.h b/kate/app/kateconsole.h new file mode 100644 index 000000000..1750df11d --- /dev/null +++ b/kate/app/kateconsole.h @@ -0,0 +1,116 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2002 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __KATE_CONSOLE_H__ +#define __KATE_CONSOLE_H__ + +#include "katemain.h" + +#include <kurl.h> + +#include <qvbox.h> + +namespace KParts { + class ReadOnlyPart; +} + +namespace KateMDI { + class ToolView; +} + +class KateMainWindow; + +/** + * KateConsole + * This class is used for the internal terminal emulator + * It uses internally the konsole part, thx to konsole devs :) + */ +class KateConsole : public QVBox +{ + Q_OBJECT + + public: + /** + * construct us + * @param mw main window + * @param parent toolview + */ + KateConsole (KateMainWindow *mw, KateMDI::ToolView* parent); + + /** + * destruct us + */ + ~KateConsole (); + + /** + * cd to dir + * @param url given dir + */ + void cd (const KURL &url); + + /** + * send given text to console + * @param text commands for console + */ + void sendInput( const QString& text ); + + public slots: + /** + * pipe current document to console + */ + void slotPipeToConsole (); + + private slots: + /** + * the konsole exited ;) + * handle that, hide the dock + */ + void slotDestroyed (); + + /** + * construct console if needed + */ + void loadConsoleIfNeeded(); + + protected: + /** + * the konsole get shown + * @param ev show event + */ + void showEvent(QShowEvent *ev); + + private: + /** + * console part + */ + KParts::ReadOnlyPart *m_part; + + /** + * main window of this console + */ + KateMainWindow *m_mw; + + /** + * toolview for this console + */ + KateMDI::ToolView *m_toolView; +}; + +#endif diff --git a/kate/app/katedocmanager.cpp b/kate/app/katedocmanager.cpp new file mode 100644 index 000000000..fe6491f78 --- /dev/null +++ b/kate/app/katedocmanager.cpp @@ -0,0 +1,611 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "katedocmanager.h" +#include "katedocmanager.moc" +#include "kateapp.h" +#include "katemainwindow.h" +#include "kateviewmanager.h" +#include "katedocmanageriface.h" +#include "kateexternaltools.h" +#include "kateviewspacecontainer.h" + +#include <kate/view.h> + +#include <ktexteditor/encodinginterface.h> + +#include <kparts/factory.h> + +#include <klocale.h> +#include <kdebug.h> +#include <kconfig.h> +#include <klibloader.h> +#include <kmdcodec.h> +#include <kmessagebox.h> +#include <kencodingfiledialog.h> +#include <kio/job.h> +#include <kwin.h> + +#include <qdatetime.h> +#include <qtextcodec.h> +#include <qprogressdialog.h> + +KateDocManager::KateDocManager (QObject *parent) + : QObject (parent) + , m_saveMetaInfos(true) + , m_daysMetaInfos(0) +{ + m_factory = (KParts::Factory *) KLibLoader::self()->factory ("libkatepart"); + + m_documentManager = new Kate::DocumentManager (this); + m_docList.setAutoDelete(true); + m_docDict.setAutoDelete(false); + m_docInfos.setAutoDelete(true); + + m_dcop = new KateDocManagerDCOPIface (this); + + m_metaInfos = new KConfig("metainfos", false, false, "appdata"); + + createDoc (); +} + +KateDocManager::~KateDocManager () +{ + // save config + if (!m_docList.isEmpty()) + m_docList.at(0)->writeConfig(KateApp::self()->config()); + + if (m_saveMetaInfos) + { + // saving meta-infos when file is saved is not enough, we need to do it once more at the end + for (Kate::Document *doc = m_docList.first(); doc; doc = m_docList.next()) + saveMetaInfos(doc); + + // purge saved filesessions + if (m_daysMetaInfos > 0) + { + QStringList groups = m_metaInfos->groupList(); + QDateTime *def = new QDateTime(QDate(1970, 1, 1)); + for (QStringList::Iterator it = groups.begin(); it != groups.end(); ++it) + { + m_metaInfos->setGroup(*it); + QDateTime last = m_metaInfos->readDateTimeEntry("Time", def); + if (last.daysTo(QDateTime::currentDateTime()) > m_daysMetaInfos) + m_metaInfos->deleteGroup(*it); + } + delete def; + } + } + + delete m_dcop; + delete m_metaInfos; +} + +KateDocManager *KateDocManager::self () +{ + return KateApp::self()->documentManager (); +} + +Kate::Document *KateDocManager::createDoc () +{ + KTextEditor::Document *doc = (KTextEditor::Document *) m_factory->createPart (0, "", this, "", "KTextEditor::Document"); + + m_docList.append((Kate::Document *)doc); + m_docDict.insert (doc->documentNumber(), (Kate::Document *)doc); + m_docInfos.insert (doc, new KateDocumentInfo ()); + + if (m_docList.count() < 2) + ((Kate::Document *)doc)->readConfig(KateApp::self()->config()); + + emit documentCreated ((Kate::Document *)doc); + emit m_documentManager->documentCreated ((Kate::Document *)doc); + + connect(doc,SIGNAL(modifiedOnDisc(Kate::Document *, bool, unsigned char)),this,SLOT(slotModifiedOnDisc(Kate::Document *, bool, unsigned char))); + return (Kate::Document *)doc; +} + +void KateDocManager::deleteDoc (Kate::Document *doc) +{ + uint id = doc->documentNumber(); + uint activeId = 0; + if (m_currentDoc) + activeId = m_currentDoc->documentNumber (); + + if (m_docList.count() < 2) + doc->writeConfig(KateApp::self()->config()); + + m_docInfos.remove (doc); + m_docDict.remove (id); + m_docList.remove (doc); + + emit documentDeleted (id); + emit m_documentManager->documentDeleted (id); + + // ohh, current doc was deleted + if (activeId == id) + { + // special case of documentChanged, no longer any doc here ! + m_currentDoc = 0; + + emit documentChanged (); + emit m_documentManager->documentChanged (); + } +} + +Kate::Document *KateDocManager::document (uint n) +{ + return m_docList.at(n); +} + +Kate::Document *KateDocManager::activeDocument () +{ + return m_currentDoc; +} + +void KateDocManager::setActiveDocument (Kate::Document *doc) +{ + if (!doc) + return; + + if (m_currentDoc && (m_currentDoc->documentNumber() == doc->documentNumber())) + return; + + m_currentDoc = doc; + + emit documentChanged (); + emit m_documentManager->documentChanged (); +} + +Kate::Document *KateDocManager::firstDocument () +{ + return m_docList.first(); +} + +Kate::Document *KateDocManager::nextDocument () +{ + return m_docList.next(); +} + +Kate::Document *KateDocManager::documentWithID (uint id) +{ + return m_docDict[id]; +} + +const KateDocumentInfo *KateDocManager::documentInfo (Kate::Document *doc) +{ + return m_docInfos[doc]; +} + +int KateDocManager::findDocument (Kate::Document *doc) +{ + return m_docList.find (doc); +} + +uint KateDocManager::documents () +{ + return m_docList.count (); +} + +int KateDocManager::findDocument ( KURL url ) +{ + QPtrListIterator<Kate::Document> it(m_docList); + + for (; it.current(); ++it) + { + if ( it.current()->url() == url) + return it.current()->documentNumber(); + } + return -1; +} + +Kate::Document *KateDocManager::findDocumentByUrl( KURL url ) +{ + for (QPtrListIterator<Kate::Document> it(m_docList); it.current(); ++it) + { + if ( it.current()->url() == url) + return it.current(); + } + + return 0L; +} + +bool KateDocManager::isOpen(KURL url) +{ + // return just if we found some document with this url + return findDocumentByUrl (url) != 0; +} + +Kate::Document *KateDocManager::openURL (const KURL& url,const QString &encoding, uint *id, bool isTempFile) +{ + // special handling if still only the first initial doc is there + if (!documentList().isEmpty() && (documentList().count() == 1) && (!documentList().at(0)->isModified() && documentList().at(0)->url().isEmpty())) + { + Kate::Document* doc = documentList().getFirst(); + + doc->setEncoding(encoding); + + if (!loadMetaInfos(doc, url)) + doc->openURL (url); + + if (id) + *id=doc->documentNumber(); + + if ( isTempFile && !url.isEmpty() && url.isLocalFile() ) + { + QFileInfo fi( url.path() ); + if ( fi.exists() ) + { + m_tempFiles[ doc->documentNumber() ] = qMakePair(url, fi.lastModified()); + kdDebug(13001)<<"temporary file will be deleted after use unless modified: "<<url.prettyURL()<<endl; + } + } + + connect(doc, SIGNAL(modStateChanged(Kate::Document *)), this, SLOT(slotModChanged(Kate::Document *))); + + emit initialDocumentReplaced(); + + return doc; + } + + Kate::Document *doc = findDocumentByUrl (url); + if ( !doc ) + { + doc = (Kate::Document *)createDoc (); + + doc->setEncoding(encoding.isNull() ? Kate::Document::defaultEncoding() : encoding); + + if (!loadMetaInfos(doc, url)) + doc->openURL (url); + } + + if (id) + *id=doc->documentNumber(); + + if ( isTempFile && !url.isEmpty() && url.isLocalFile() ) + { + QFileInfo fi( url.path() ); + if ( fi.exists() ) + { + m_tempFiles[ doc->documentNumber() ] = qMakePair(url, fi.lastModified()); + kdDebug(13001)<<"temporary file will be deleted after use unless modified: "<<url.prettyURL()<<endl; + } + } + + return doc; +} + +bool KateDocManager::closeDocument(class Kate::Document *doc,bool closeURL) +{ + if (!doc) return false; + + saveMetaInfos(doc); + if (closeURL) + if (!doc->closeURL()) return false; + + QPtrList<Kate::View> closeList; + uint documentNumber = doc->documentNumber(); + + for (uint i=0; i < KateApp::self()->mainWindows (); i++ ) + { + KateApp::self()->mainWindow(i)->viewManager()->closeViews(documentNumber); + } + + if ( closeURL && m_tempFiles.contains( documentNumber ) ) + { + QFileInfo fi( m_tempFiles[ documentNumber ].first.path() ); + if ( fi.lastModified() <= m_tempFiles[ documentNumber ].second /*|| + KMessageBox::questionYesNo( KateApp::self()->activeMainWindow(), + i18n("The supposedly temporary file %1 has been modified. " + "Do you want to delete it anyway?").arg(m_tempFiles[ documentNumber ].first.prettyURL()), + i18n("Delete File?") ) == KMessageBox::Yes*/ ) + { + KIO::del( m_tempFiles[ documentNumber ].first, false, false ); + kdDebug(13001)<<"Deleted temporary file "<<m_tempFiles[ documentNumber ].first<<endl; + m_tempFiles.remove( documentNumber ); + } + else + kdWarning(13001)<<"The supposedly temporary file "<<m_tempFiles[ documentNumber ].first.prettyURL()<<" have been modified since loaded, and has not been deleted."<<endl; + } + + deleteDoc (doc); + + // never ever empty the whole document list + if (m_docList.isEmpty()) + createDoc (); + + return true; +} + +bool KateDocManager::closeDocument(uint n) +{ + return closeDocument(document(n)); +} + +bool KateDocManager::closeDocumentWithID(uint id) +{ + return closeDocument(documentWithID(id)); +} + +bool KateDocManager::closeAllDocuments(bool closeURL) +{ + bool res = true; + + QPtrList<Kate::Document> docs = m_docList; + + for (uint i=0; i < KateApp::self()->mainWindows (); i++ ) + { + KateApp::self()->mainWindow(i)->viewManager()->setViewActivationBlocked(true); + } + + while (!docs.isEmpty() && res) + if (! closeDocument(docs.at(0),closeURL) ) + res = false; + else + docs.remove ((uint)0); + + for (uint i=0; i < KateApp::self()->mainWindows (); i++ ) + { + KateApp::self()->mainWindow(i)->viewManager()->setViewActivationBlocked(false); + + for (uint s=0; s < KateApp::self()->mainWindow(i)->viewManager()->containers()->count(); s++) + KateApp::self()->mainWindow(i)->viewManager()->containers()->at(s)->activateView (m_docList.at(0)->documentNumber()); + } + + return res; +} + +QPtrList<Kate::Document> KateDocManager::modifiedDocumentList() { + QPtrList<Kate::Document> modified; + for (QPtrListIterator<Kate::Document> it(m_docList); it.current(); ++it) { + Kate::Document *doc = it.current(); + if (doc->isModified()) { + modified.append(doc); + } + } + return modified; +} + + +bool KateDocManager::queryCloseDocuments(KateMainWindow *w) +{ + uint docCount = m_docList.count(); + for (QPtrListIterator<Kate::Document> it(m_docList); it.current(); ++it) + { + Kate::Document *doc = it.current(); + + if (doc->url().isEmpty() && doc->isModified()) + { + int msgres=KMessageBox::warningYesNoCancel( w, + i18n("<p>The document '%1' has been modified, but not saved." + "<p>Do you want to save your changes or discard them?").arg( doc->docName() ), + i18n("Close Document"), KStdGuiItem::save(), KStdGuiItem::discard() ); + + if (msgres==KMessageBox::Cancel) + return false; + + if (msgres==KMessageBox::Yes) + { + KEncodingFileDialog::Result r=KEncodingFileDialog::getSaveURLAndEncoding( + KTextEditor::encodingInterface(doc)->encoding(),QString::null,QString::null,w,i18n("Save As")); + + doc->setEncoding( r.encoding ); + + if (!r.URLs.isEmpty()) + { + KURL tmp = r.URLs.first(); + + if ( !doc->saveAs( tmp ) ) + return false; + } + else + return false; + } + } + else + { + if (!doc->queryClose()) + return false; + } + } + + // document count changed while queryClose, abort and notify user + if (m_docList.count() > docCount) + { + KMessageBox::information (w, + i18n ("New file opened while trying to close Kate, closing aborted."), + i18n ("Closing Aborted")); + return false; + } + + return true; +} + + +void KateDocManager::saveAll() +{ + for (QPtrListIterator<Kate::Document> it(m_docList); it.current(); ++it) + if ( it.current()->isModified() && it.current()->views().count() ) + ((Kate::View*)it.current()->views().first())->save(); +} + +void KateDocManager::saveDocumentList (KConfig* config) +{ + QString prevGrp=config->group(); + config->setGroup ("Open Documents"); + QString grp = config->group(); + + config->writeEntry ("Count", m_docList.count()); + + int i=0; + for ( Kate::Document *doc = m_docList.first(); doc; doc = m_docList.next() ) + { + config->setGroup(QString("Document %1").arg(i)); + doc->writeSessionConfig(config); + config->setGroup(grp); + + i++; + } + + config->setGroup(prevGrp); +} + +void KateDocManager::restoreDocumentList (KConfig* config) +{ + QString prevGrp=config->group(); + config->setGroup ("Open Documents"); + QString grp = config->group(); + + unsigned int count = config->readUnsignedNumEntry("Count", 0); + + if (count == 0) + { + config->setGroup(prevGrp); + return; + } + + QProgressDialog *pd = new QProgressDialog( + i18n("Reopening files from the last session..."), + QString::null, + count, + 0, + "openprog"); + + KWin::setOnDesktop(pd->winId(), KWin::currentDesktop()); + pd->setCaption (KateApp::self()->makeStdCaption(i18n("Starting Up"))); + + bool first = true; + for (unsigned int i=0; i < count; i++) + { + config->setGroup(QString("Document %1").arg(i)); + Kate::Document *doc = 0; + + if (first) + { + first = false; + doc = document (0); + } + else + doc = createDoc (); + + doc->readSessionConfig(config); + config->setGroup (grp); + + pd->setProgress(pd->progress()+1); + KateApp::self()->processEvents(); + } + + delete pd; + + config->setGroup(prevGrp); +} + +void KateDocManager::slotModifiedOnDisc (Kate::Document *doc, bool b, unsigned char reason) +{ + if (m_docInfos[doc]) + { + m_docInfos[doc]->modifiedOnDisc = b; + m_docInfos[doc]->modifiedOnDiscReason = reason; + } +} + +void KateDocManager::slotModChanged(Kate::Document *doc) +{ + saveMetaInfos(doc); +} + +/** + * Load file and file' meta-informations iif the MD5 didn't change since last time. + */ +bool KateDocManager::loadMetaInfos(Kate::Document *doc, const KURL &url) +{ + if (!m_saveMetaInfos) + return false; + + if (!m_metaInfos->hasGroup(url.prettyURL())) + return false; + + QCString md5; + bool ok = true; + + if (computeUrlMD5(url, md5)) + { + m_metaInfos->setGroup(url.prettyURL()); + QString old_md5 = m_metaInfos->readEntry("MD5"); + + if ((const char *)md5 == old_md5) + doc->readSessionConfig(m_metaInfos); + else + { + m_metaInfos->deleteGroup(url.prettyURL()); + ok = false; + } + + m_metaInfos->sync(); + } + + return ok && doc->url() == url; +} + +/** + * Save file' meta-informations iif doc is in 'unmodified' state + */ +void KateDocManager::saveMetaInfos(Kate::Document *doc) +{ + QCString md5; + + if (!m_saveMetaInfos) + return; + + if (doc->isModified()) + { +// kdDebug (13020) << "DOC MODIFIED: no meta data saved" << endl; + return; + } + + if (computeUrlMD5(doc->url(), md5)) + { + m_metaInfos->setGroup(doc->url().prettyURL()); + doc->writeSessionConfig(m_metaInfos); + m_metaInfos->writeEntry("MD5", (const char *)md5); + m_metaInfos->writeEntry("Time", QDateTime::currentDateTime()); + m_metaInfos->sync(); + } +} + +bool KateDocManager::computeUrlMD5(const KURL &url, QCString &result) +{ + QFile f(url.path()); + + if (f.open(IO_ReadOnly)) + { + KMD5 md5; + + if (!md5.update(f)) + return false; + + md5.hexDigest(result); + f.close(); + } + else + return false; + + return true; +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kate/app/katedocmanager.h b/kate/app/katedocmanager.h new file mode 100644 index 000000000..8d302687b --- /dev/null +++ b/kate/app/katedocmanager.h @@ -0,0 +1,156 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __KATE_DOCMANAGER_H__ +#define __KATE_DOCMANAGER_H__ + +#include "katemain.h" +#include "../interfaces/documentmanager.h" + +#include <kate/document.h> + +#include <qguardedptr.h> +#include <qptrlist.h> +#include <qobject.h> +#include <qptrdict.h> +#include <qintdict.h> +#include <qmap.h> +#include <qpair.h> + +namespace KParts { class Factory; } + +class KConfig; +class DCOPObject; + +class KateDocumentInfo +{ + public: + KateDocumentInfo () + : modifiedOnDisc (false), + modifiedOnDiscReason (0) + { + } + + bool modifiedOnDisc; + unsigned char modifiedOnDiscReason; +}; + +typedef QPair<KURL,QDateTime> TPair; + +class KateDocManager : public QObject +{ + Q_OBJECT + + public: + KateDocManager (QObject *parent); + ~KateDocManager (); + + static KateDocManager *self (); + + Kate::DocumentManager *documentManager () { return m_documentManager; }; + + Kate::Document *createDoc (); + void deleteDoc (Kate::Document *doc); + + Kate::Document *document (uint n); + + Kate::Document *activeDocument (); + void setActiveDocument (Kate::Document *doc); + + Kate::Document *firstDocument (); + Kate::Document *nextDocument (); + + // search document with right documentNumber() + Kate::Document *documentWithID (uint id); + + const KateDocumentInfo *documentInfo (Kate::Document *doc); + + int findDocument (Kate::Document *doc); + /** Returns the documentNumber of the doc with url URL or -1 if no such doc is found */ + int findDocument (KURL url); + // Anders: The above is not currently stable ? + Kate::Document *findDocumentByUrl( KURL url ); + + bool isOpen(KURL url); + + uint documents (); + + QPtrList<Kate::Document> &documentList () { return m_docList; }; + + Kate::Document *openURL(const KURL&,const QString &encoding=QString::null,uint *id =0,bool isTempFile=false); + + bool closeDocument(class Kate::Document *,bool closeURL=true); + bool closeDocument(uint); + bool closeDocumentWithID(uint); + bool closeAllDocuments(bool closeURL=true); + + QPtrList<Kate::Document> modifiedDocumentList(); + bool queryCloseDocuments(KateMainWindow *w); + + void saveDocumentList (class KConfig *config); + void restoreDocumentList (class KConfig *config); + + DCOPObject *dcopObject () { return m_dcop; }; + + inline bool getSaveMetaInfos() { return m_saveMetaInfos; }; + inline void setSaveMetaInfos(bool b) { m_saveMetaInfos = b; }; + + inline int getDaysMetaInfos() { return m_daysMetaInfos; }; + inline void setDaysMetaInfos(int i) { m_daysMetaInfos = i; }; + + public slots: + /** + * saves all documents that has at least one view. + * documents with no views are ignored :P + */ + void saveAll(); + + signals: + void documentCreated (Kate::Document *doc); + void documentDeleted (uint documentNumber); + void documentChanged (); + void initialDocumentReplaced (); + + private slots: + void slotModifiedOnDisc (Kate::Document *doc, bool b, unsigned char reason); + void slotModChanged(Kate::Document *doc); + + private: + bool loadMetaInfos(Kate::Document *doc, const KURL &url); + void saveMetaInfos(Kate::Document *doc); + bool computeUrlMD5(const KURL &url, QCString &result); + + Kate::DocumentManager *m_documentManager; + QPtrList<Kate::Document> m_docList; + QIntDict<Kate::Document> m_docDict; + QPtrDict<KateDocumentInfo> m_docInfos; + QMap<uint,TPair> m_tempFiles; + QGuardedPtr<Kate::Document> m_currentDoc; + KConfig *m_metaInfos; + bool m_saveMetaInfos; + int m_daysMetaInfos; + + DCOPObject *m_dcop; + + KParts::Factory *m_factory; + +}; + +#endif +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kate/app/katedocmanageriface.cpp b/kate/app/katedocmanageriface.cpp new file mode 100644 index 000000000..9c2eabc03 --- /dev/null +++ b/kate/app/katedocmanageriface.cpp @@ -0,0 +1,131 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Ian Reinhart Geiser <geiseri@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "katedocmanageriface.h" + +#include "katedocmanager.h" + +#include <kdebug.h> + +KateDocManagerDCOPIface::KateDocManagerDCOPIface (KateDocManager *dm) : DCOPObject ("KateDocumentManager"), m_dm (dm) +{ + +} + +// bit more error save than the forcing c cast ;() +DCOPRef KateDocManagerDCOPIface::document (uint n) +{ + Kate::Document *doc = m_dm->document(n); + + if (!doc) + return DCOPRef (); + + DCOPObject *obj = static_cast<DCOPObject*>(doc->qt_cast("DCOPObject")); + + if (!obj) + return DCOPRef (); + + return DCOPRef (obj); +} + +DCOPRef KateDocManagerDCOPIface::activeDocument () +{ + Kate::Document *doc = m_dm->activeDocument(); + + if (!doc) + return DCOPRef (); + + DCOPObject *obj = static_cast<DCOPObject*>(doc->qt_cast("DCOPObject")); + + if (!obj) + return DCOPRef (); + + return DCOPRef (obj); +} + +uint KateDocManagerDCOPIface::activeDocumentNumber () +{ + Kate::Document *doc = m_dm->activeDocument(); + + if (doc) + return doc->documentNumber (); + + return 0; +} + +DCOPRef KateDocManagerDCOPIface::documentWithID (uint id) +{ + Kate::Document *doc = m_dm->documentWithID (id); + + if (!doc) + return DCOPRef (); + + DCOPObject *obj = static_cast<DCOPObject*>(doc->qt_cast("DCOPObject")); + + if (!obj) + return DCOPRef (); + + return DCOPRef (obj); +} + +DCOPRef KateDocManagerDCOPIface::openURL (KURL url, QString encoding) +{ + Kate::Document *doc = m_dm->openURL (url, encoding); + + if (!doc) + return DCOPRef (); + + DCOPObject *obj = static_cast<DCOPObject*>(doc->qt_cast("DCOPObject")); + + if (!obj) + return DCOPRef (); + + return DCOPRef (obj); +} + +bool KateDocManagerDCOPIface::closeDocument(uint n) +{ + return m_dm->closeDocument(n); +} + +bool KateDocManagerDCOPIface::closeDocumentWithID(uint id) +{ + return m_dm->closeDocumentWithID (id); +} + +bool KateDocManagerDCOPIface::closeAllDocuments() +{ + return m_dm->closeAllDocuments(); +} + +bool KateDocManagerDCOPIface::isOpen(KURL url) +{ + return m_dm->isOpen (url); +} + +uint KateDocManagerDCOPIface::documents () +{ + return m_dm->documents(); +} + +int KateDocManagerDCOPIface::findDocument (KURL url) +{ + return m_dm->findDocument (url); +} + + diff --git a/kate/app/katedocmanageriface.h b/kate/app/katedocmanageriface.h new file mode 100644 index 000000000..7a2cb5506 --- /dev/null +++ b/kate/app/katedocmanageriface.h @@ -0,0 +1,62 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Ian Reinhart Geiser <geiseri@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _katedocmanager_Iface_h_ +#define _katedocmanager_Iface_h_ + +#include <dcopobject.h> +#include <dcopref.h> + +#include <kurl.h> + +class KateDocManager; + +class KateDocManagerDCOPIface : public DCOPObject +{ + K_DCOP + + public: + KateDocManagerDCOPIface (KateDocManager *dm); + + k_dcop: + DCOPRef document (uint n); + + DCOPRef activeDocument (); + + uint activeDocumentNumber (); + + DCOPRef documentWithID (uint id); + + int findDocument (KURL url); + + bool isOpen (KURL url); + + uint documents (); + + DCOPRef openURL (KURL url, QString encoding); + + bool closeDocument (uint n); + + bool closeDocumentWithID (uint id); + + bool closeAllDocuments (); + + private: + KateDocManager *m_dm; +}; +#endif diff --git a/kate/app/kateexternaltools.cpp b/kate/app/kateexternaltools.cpp new file mode 100644 index 000000000..50c07709b --- /dev/null +++ b/kate/app/kateexternaltools.cpp @@ -0,0 +1,873 @@ +/* + This file is part of the Kate text editor of the KDE project. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + --- + Copyright (C) 2004, Anders Lund <anders@alweb.dk> +*/ +// TODO +// Icons +// Direct shortcut setting +//BEGIN Includes +#include "kateexternaltools.h" +#include "kateexternaltools.moc" +#include "katedocmanager.h" +#include "kateviewmanager.h" +#include "kateapp.h" + +#include "katemainwindow.h" + +#include <kate/view.h> +#include <kate/document.h> + +#include <klistbox.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <kmimetypechooser.h> +#include <kconfig.h> +#include <krun.h> +#include <kicondialog.h> +#include <kpopupmenu.h> +#include <kdebug.h> + +#include <qbitmap.h> +#include <qcombobox.h> +#include <qfile.h> +#include <qpushbutton.h> +#include <qlineedit.h> +#include <qlayout.h> +#include <qlabel.h> +#include <qlistbox.h> +#include <qmap.h> +#include <qregexp.h> +#include <qtextedit.h> +#include <qtoolbutton.h> +#include <qwhatsthis.h> + +#include <stdlib.h> +#include <unistd.h> +//END Includes + +KateExternalToolsCommand *KateExternalToolsCommand::s_self=0; + +//BEGIN KateExternalTool +KateExternalTool::KateExternalTool( const QString &name, + const QString &command, + const QString &icon, + const QString &tryexec, + const QStringList &mimetypes, + const QString &acname, + const QString &cmdname, + int save ) + : name ( name ), + command ( command ), + icon ( icon ), + tryexec ( tryexec ), + mimetypes ( mimetypes ), + acname ( acname ), + cmdname ( cmdname ), + save ( save ) +{ + //if ( ! tryexec.isEmpty() ) + hasexec = checkExec(); +} + +bool KateExternalTool::checkExec() +{ + // if tryexec is empty, it is the first word of command + if ( tryexec.isEmpty() ) + tryexec = command.section( " ", 0, 0, QString::SectionSkipEmpty ); + + // NOTE this code is modified taken from kdesktopfile.cpp, from KDesktopFile::tryExec() + if (!tryexec.isEmpty()) { + if (tryexec[0] == '/') { + if (::access(QFile::encodeName(tryexec), R_OK | X_OK)) + return false; + + m_exec = tryexec; + } else { + // !!! Sergey A. Sukiyazov <corwin@micom.don.ru> !!! + // Environment PATH may contain filenames in 8bit locale cpecified + // encoding (Like a filenames). + QStringList dirs = QStringList::split(':', QFile::decodeName(::getenv("PATH"))); + QStringList::Iterator it(dirs.begin()); + bool match = false; + for (; it != dirs.end(); ++it) + { + QString fName = *it + "/" + tryexec; + if (::access(QFile::encodeName(fName), R_OK | X_OK) == 0) + { + match = true; + m_exec = fName; + break; + } + } + // didn't match at all + if (!match) + return false; + } + return true; + } + return false; +} + +bool KateExternalTool::valid( const QString &mt ) const +{ + return mimetypes.isEmpty() || mimetypes.contains( mt ); +} +//END KateExternalTool + +//BEGIN KateExternalToolsCommand +KateExternalToolsCommand::KateExternalToolsCommand() : Kate::Command() { + m_inited=false; + reload(); +} + +QStringList KateExternalToolsCommand::cmds () { + return m_list; +} + +KateExternalToolsCommand *KateExternalToolsCommand::self () { + if (s_self) return s_self; + s_self=new KateExternalToolsCommand; + return s_self; +} + +void KateExternalToolsCommand::reload () { + m_list.clear(); + m_map.clear(); + + KConfig config("externaltools", false, false, "appdata"); + config.setGroup("Global"); + QStringList tools = config.readListEntry("tools"); + + + for( QStringList::Iterator it = tools.begin(); it != tools.end(); ++it ) + { + if ( *it == "---" ) + continue; + + + config.setGroup( *it ); + + KateExternalTool t = KateExternalTool( + config.readEntry( "name", "" ), + config.readEntry( "command", ""), + config.readEntry( "icon", ""), + config.readEntry( "executable", ""), + config.readListEntry( "mimetypes" ), + config.readEntry( "acname", "" ), + config.readEntry( "cmdname", "" ) ); + // FIXME test for a command name first! + if ( t.hasexec && (!t.cmdname.isEmpty())) { + m_list.append("exttool-"+t.cmdname); + m_map.insert("exttool-"+t.cmdname,t.acname); + } + } + if (m_inited) { + Kate::Document::unregisterCommand(this); + Kate::Document::registerCommand(this); + } + else m_inited=true; +} + +bool KateExternalToolsCommand::exec (Kate::View *view, const QString &cmd, QString &) { + QWidget *wv=dynamic_cast<QWidget*>(view); + if (!wv) { +// kdDebug(13001)<<"KateExternalToolsCommand::exec: Could not get view widget"<<endl; + return false; + } + KateMDI::MainWindow *dmw=dynamic_cast<KateMDI::MainWindow*>(wv->topLevelWidget()); + if (!dmw) { +// kdDebug(13001)<<"KateExternalToolsCommand::exec: Could not get main window"<<endl; + return false; + } +// kdDebug(13001)<<"cmd="<<cmd.stripWhiteSpace()<<endl; + QString actionName=m_map[cmd.stripWhiteSpace()]; + if (actionName.isEmpty()) return false; +// kdDebug(13001)<<"actionName is not empty:"<<actionName<<endl; + KateExternalToolsMenuAction *a= + dynamic_cast<KateExternalToolsMenuAction*>(dmw->action("tools_external")); + if (!a) return false; +// kdDebug(13001)<<"trying to find action"<<endl; + KAction *a1=a->actionCollection()->action(actionName.utf8()); + if (!a1) return false; +// kdDebug(13001)<<"activating action"<<endl; + a1->activate(); + return true; +} + +bool KateExternalToolsCommand::help (Kate::View *, const QString &, QString &) { + return false; +} +//END KateExternalToolsCommand + +//BEGIN KateExternalToolAction +KateExternalToolAction::KateExternalToolAction( QObject *parent, + const char *name, KateExternalTool *t) + : KAction( parent, name ), + tool ( t ) +{ + setText( t->name ); + if ( ! t->icon.isEmpty() ) + setIconSet( SmallIconSet( t->icon ) ); + + connect( this ,SIGNAL(activated()), this, SLOT(slotRun()) ); +} + +bool KateExternalToolAction::expandMacro( const QString &str, QStringList &ret ) +{ + KateMainWindow *mw = (KateMainWindow*)parent()->parent(); + + Kate::View *view = mw->viewManager()->activeView(); + if ( ! view ) return false; + + + if ( str == "URL" ) + ret += mw->activeDocumentUrl().url(); + else if ( str == "directory" ) // directory of current doc + ret += mw->activeDocumentUrl().directory(); + else if ( str == "filename" ) + ret += mw->activeDocumentUrl().fileName(); + else if ( str == "line" ) // cursor line of current doc + ret += QString::number( view->cursorLine() ); + else if ( str == "col" ) // cursor col of current doc + ret += QString::number( view->cursorColumn() ); + else if ( str == "selection" ) // selection of current doc if any + ret += view->getDoc()->selection(); + else if ( str == "text" ) // text of current doc + ret += view->getDoc()->text(); + else if ( str == "URLs" ) { + for( Kate::Document *doc = KateDocManager::self()->firstDocument(); doc; doc = KateDocManager::self()->nextDocument() ) + if ( ! doc->url().isEmpty() ) + ret += doc->url().url(); + } else + return false; + return true; +} + +KateExternalToolAction::~KateExternalToolAction() { + delete(tool); +} + +void KateExternalToolAction::slotRun() +{ + // expand the macros in command if any, + // and construct a command with an absolute path + QString cmd = tool->command; + + if ( ! expandMacrosShellQuote( cmd ) ) + { + KMessageBox::sorry( (KateMainWindow*)parent()->parent(), + i18n("Failed to expand the command '%1'.").arg( cmd ), + i18n( "Kate External Tools") ); + return; + } + kdDebug(13001)<<"externaltools: Running command: "<<cmd<<endl; + + // save documents if requested + KateMainWindow *mw = (KateMainWindow*)parent()->parent(); + if ( tool->save == 1 ) + mw->viewManager()->activeView()->document()->save(); + else if ( tool->save == 2 ) + mw->actionCollection()->action("file_save_all")->activate(); + + KRun::runCommand( cmd, tool->tryexec, tool->icon ); +} +//END KateExternalToolAction + +//BEGIN KateExternalToolsMenuAction +KateExternalToolsMenuAction::KateExternalToolsMenuAction( const QString &text, + QObject *parent, + const char* name, + KateMainWindow *mw ) + : KActionMenu( text, parent, name ), + mainwindow( mw ) +{ + + m_actionCollection = new KActionCollection( mainwindow ); + + connect(KateDocManager::self(),SIGNAL(documentChanged()),this,SLOT(slotDocumentChanged())); + + reload(); +} + +void KateExternalToolsMenuAction::reload() +{ + m_actionCollection->clear (); + popupMenu()->clear(); + + // load all the tools, and create a action for each of them + KConfig *config = new KConfig( "externaltools", false, false, "appdata" ); + config->setGroup( "Global" ); + QStringList tools = config->readListEntry( "tools" ); + + // if there are tools that are present but not explicitly removed, + // add them to the end of the list + config->setReadDefaults( true ); + QStringList dtools = config->readListEntry( "tools" ); + int gver = config->readNumEntry( "version", 1 ); + config->setReadDefaults( false ); + + int ver = config->readNumEntry( "version" ); + if ( ver <= gver ) + { + QStringList removed = config->readListEntry( "removed" ); + bool sepadded = false; + for (QStringList::iterator itg = dtools.begin(); itg != dtools.end(); ++itg ) + { + if ( ! tools.contains( *itg ) && + ! removed.contains( *itg ) ) + { + if ( ! sepadded ) + { + tools << "---"; + sepadded = true; + } + tools << *itg; + } + } + + config->writeEntry( "tools", tools ); + config->sync(); + config->writeEntry( "version", gver ); + } + + for( QStringList::Iterator it = tools.begin(); it != tools.end(); ++it ) + { + if ( *it == "---" ) + { + popupMenu()->insertSeparator(); + // a separator + continue; + } + + config->setGroup( *it ); + + KateExternalTool *t = new KateExternalTool( + config->readEntry( "name", "" ), + config->readEntry( "command", ""), + config->readEntry( "icon", ""), + config->readEntry( "executable", ""), + config->readListEntry( "mimetypes" ), + config->readEntry( "acname", "" ), + config->readEntry( "cmdname", "" ), + config->readNumEntry( "save", 0 ) ); + + if ( t->hasexec ) + insert( new KateExternalToolAction( m_actionCollection, t->acname.ascii(), t ) ); + } + + m_actionCollection->readShortcutSettings( "Shortcuts", config ); + slotDocumentChanged(); + delete config; +} + +void KateExternalToolsMenuAction::slotDocumentChanged() +{ + // try to enable/disable to match current mime type + Kate::DocumentExt *de = documentExt( KateDocManager::self()->activeDocument() ); + if ( de ) + { + QString mt = de->mimeType(); + QStringList l; + bool b; + + KActionPtrList actions = m_actionCollection->actions(); + for (KActionPtrList::iterator it = actions.begin(); it != actions.end(); ++it ) + { + KateExternalToolAction *action = dynamic_cast<KateExternalToolAction*>(*it); + if ( action ) + { + l = action->tool->mimetypes; + b = ( ! l.count() || l.contains( mt ) ); + action->setEnabled( b ); + } + } + } +} +//END KateExternalToolsMenuAction + +//BEGIN ToolItem +/** + * This is a QListBoxItem, that has a KateExternalTool. The text is the Name + * of the tool. + */ +class ToolItem : public QListBoxPixmap +{ + public: + ToolItem( QListBox *lb, const QPixmap &icon, KateExternalTool *tool ) + : QListBoxPixmap( lb, icon, tool->name ), + tool ( tool ) + {;} + + ~ToolItem() {}; + + KateExternalTool *tool; +}; +//END ToolItem + +//BEGIN KateExternalToolServiceEditor +KateExternalToolServiceEditor::KateExternalToolServiceEditor( KateExternalTool *tool, + QWidget *parent, const char *name ) + : KDialogBase( parent, name, true, i18n("Edit External Tool"), KDialogBase::Ok|KDialogBase::Cancel ), + tool( tool ) +{ + // create a entry for each property + // fill in the values from the service if available + QWidget *w = new QWidget( this ); + setMainWidget( w ); + QGridLayout *lo = new QGridLayout( w ); + lo->setSpacing( KDialogBase::spacingHint() ); + + QLabel *l; + + leName = new QLineEdit( w ); + lo->addWidget( leName, 1, 2 ); + l = new QLabel( leName, i18n("&Label:"), w ); + l->setAlignment( l->alignment()|Qt::AlignRight ); + lo->addWidget( l, 1, 1 ); + if ( tool ) leName->setText( tool->name ); + QWhatsThis::add( leName, i18n( + "The name will be displayed in the 'Tools->External' menu") ); + + btnIcon = new KIconButton( w ); + btnIcon->setIconSize( KIcon::SizeSmall ); + lo->addWidget( btnIcon, 1, 3 ); + if ( tool && !tool->icon.isEmpty() ) + btnIcon->setIcon( tool->icon ); + + teCommand = new QTextEdit( w ); + lo->addMultiCellWidget( teCommand, 2, 2, 2, 3 ); + l = new QLabel( teCommand, i18n("S&cript:"), w ); + l->setAlignment( Qt::AlignTop|Qt::AlignRight ); + lo->addWidget( l, 2, 1 ); + if ( tool ) teCommand->setText( tool->command ); + QWhatsThis::add( teCommand, i18n( + "<p>The script to execute to invoke the tool. The script is passed " + "to /bin/sh for execution. The following macros " + "will be expanded:</p>" + "<ul><li><code>%URL</code> - the URL of the current document." + "<li><code>%URLs</code> - a list of the URLs of all open documents." + "<li><code>%directory</code> - the URL of the directory containing " + "the current document." + "<li><code>%filename</code> - the filename of the current document." + "<li><code>%line</code> - the current line of the text cursor in the " + "current view." + "<li><code>%column</code> - the column of the text cursor in the " + "current view." + "<li><code>%selection</code> - the selected text in the current view." + "<li><code>%text</code> - the text of the current document.</ul>" ) ); + + + leExecutable = new QLineEdit( w ); + lo->addMultiCellWidget( leExecutable, 3, 3, 2, 3 ); + l = new QLabel( leExecutable, i18n("&Executable:"), w ); + l->setAlignment( l->alignment()|Qt::AlignRight ); + lo->addWidget( l, 3, 1 ); + if ( tool ) leExecutable->setText( tool->tryexec ); + QWhatsThis::add( leExecutable, i18n( + "The executable used by the command. This is used to check if a tool " + "should be displayed; if not set, the first word of <em>command</em> " + "will be used.") ); + + leMimetypes = new QLineEdit( w ); + lo->addWidget( leMimetypes, 4, 2 ); + l = new QLabel( leMimetypes, i18n("&Mime types:"), w ); + l->setAlignment( l->alignment()|Qt::AlignRight ); + lo->addWidget( l, 4, 1 ); + if ( tool ) leMimetypes->setText( tool->mimetypes.join("; ") ); + QWhatsThis::add( leMimetypes, i18n( + "A semicolon-separated list of mime types for which this tool should " + "be available; if this is left empty, the tool is always available. " + "To choose from known mimetypes, press the button on the right.") ); + + QToolButton *btnMTW = new QToolButton(w); + lo->addWidget( btnMTW, 4, 3 ); + btnMTW->setIconSet(QIconSet(SmallIcon("wizard"))); + connect(btnMTW, SIGNAL(clicked()), this, SLOT(showMTDlg())); + QWhatsThis::add( btnMTW, i18n( + "Click for a dialog that can help you creating a list of mimetypes.") ); + + cmbSave = new QComboBox(w); + lo->addMultiCellWidget( cmbSave, 5, 5, 2, 3 ); + l = new QLabel( cmbSave, i18n("&Save:"), w ); + l->setAlignment( l->alignment()|Qt::AlignRight ); + lo->addWidget( l, 5, 1 ); + QStringList sl; + sl << i18n("None") << i18n("Current Document") << i18n("All Documents"); + cmbSave->insertStringList( sl ); + if ( tool ) cmbSave->setCurrentItem( tool->save ); + QWhatsThis::add( cmbSave, i18n( + "You can elect to save the current or all [modified] documents prior to " + "running the command. This is helpful if you want to pass URLs to " + "an application like, for example, an FTP client.") ); + + + leCmdLine = new QLineEdit( w ); + lo->addMultiCellWidget( leCmdLine, 6, 6, 2, 3 ); + l = new QLabel( leCmdLine, i18n("&Command line name:"), w ); + l->setAlignment( l->alignment()|Qt::AlignRight ); + lo->addWidget( l, 6, 1 ); + if ( tool ) leCmdLine->setText( tool->cmdname ); + QWhatsThis::add( leCmdLine, i18n( + "If you specify a name here, you can invoke the command from the view " + "command lines with exttool-the_name_you_specified_here. " + "Please do not use spaces or tabs in the name.")); + +} + +void KateExternalToolServiceEditor::slotOk() +{ + if ( leName->text().isEmpty() || + teCommand->text().isEmpty() ) + { + KMessageBox::information( this, i18n("You must specify at least a name and a command") ); + return; + } + + KDialogBase::slotOk(); +} + +void KateExternalToolServiceEditor::showMTDlg() +{ + QString text = i18n("Select the MimeTypes for which to enable this tool."); + QStringList list = QStringList::split( QRegExp("\\s*;\\s*"), leMimetypes->text() ); + KMimeTypeChooserDialog d( i18n("Select Mime Types"), text, list, "text", this ); + if ( d.exec() == KDialogBase::Accepted ) { + leMimetypes->setText( d.chooser()->mimeTypes().join(";") ); + } +} +//END KateExternalToolServiceEditor + +//BEGIN KateExternalToolsConfigWidget +KateExternalToolsConfigWidget::KateExternalToolsConfigWidget( QWidget *parent, const char* name ) + : Kate::ConfigPage( parent, name ), + m_changed( false ) +{ + QGridLayout *lo = new QGridLayout( this, 5, 5, 0, KDialog::spacingHint() ); + + lbTools = new KListBox( this ); + lo->addMultiCellWidget( lbTools, 1, 4, 0, 3 ); + connect( lbTools, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged()) ); + + btnNew = new QPushButton( i18n("&New..."), this ); + lo->addWidget( btnNew, 5, 0 ); + connect( btnNew, SIGNAL(clicked()), this, SLOT(slotNew()) ); + + btnRemove = new QPushButton( i18n("&Remove"), this ); + lo->addWidget( btnRemove, 5, 2 ); + connect( btnRemove, SIGNAL(clicked()), this, SLOT(slotRemove()) ); + + btnEdit = new QPushButton( i18n("&Edit..."), this ); + lo->addWidget( btnEdit, 5, 1 ); + connect( btnEdit, SIGNAL(clicked()), this, SLOT(slotEdit()) ); + + QPushButton *b = new QPushButton( i18n("Insert &Separator"), this ); + lo->addWidget( b, 5, 3 ); + connect( b, SIGNAL(clicked()), this, SLOT(slotInsertSeparator()) ); + + btnMoveUp = new QPushButton( SmallIconSet("up"), "", this ); + lo->addWidget( btnMoveUp, 2, 4 ); + connect( btnMoveUp, SIGNAL(clicked()), this, SLOT(slotMoveUp()) ); + + btnMoveDwn = new QPushButton( SmallIconSet("down"), "", this ); + lo->addWidget( btnMoveDwn, 3, 4 ); + connect( btnMoveDwn, SIGNAL(clicked()), this, SLOT(slotMoveDown()) ); + + connect( lbTools, SIGNAL( doubleClicked ( QListBoxItem * ) ), this, SLOT( slotEdit() ) ); + + lo->setRowStretch( 1, 1 ); + lo->setRowStretch( 4, 1 ); + lo->setColStretch( 0, 1 ); + lo->setColStretch( 1, 1 ); + lo->setColStretch( 2, 1 ); + + + QWhatsThis::add( lbTools, i18n( + "This list shows all the configured tools, represented by their menu text.") ); + + config = new KConfig("externaltools", false, false, "appdata"); + reload(); + slotSelectionChanged(); +} + +KateExternalToolsConfigWidget::~KateExternalToolsConfigWidget() +{ + delete config; +} + +void KateExternalToolsConfigWidget::reload() +{ + //m_tools.clear(); + lbTools->clear(); + + // load the files from a KConfig + config->setGroup( "Global" ); + QStringList tools = config->readListEntry("tools"); + + for( QStringList::Iterator it = tools.begin(); it != tools.end(); ++it ) + { + if ( *it == "---" ) + { + new QListBoxText( lbTools, "---" ); + } + else + { + config->setGroup( *it ); + + KateExternalTool *t = new KateExternalTool( + config->readEntry( "name", "" ), + config->readEntry( "command", ""), + config->readEntry( "icon", ""), + config->readEntry( "executable", ""), + config->readListEntry( "mimetypes" ), + config->readEntry( "acname" ), + config->readEntry( "cmdname"), + config->readNumEntry( "save", 0 ) ); + + if ( t->hasexec ) // we only show tools that are also in the menu. + new ToolItem( lbTools, t->icon.isEmpty() ? blankIcon() : SmallIcon( t->icon ), t ); + } + } + m_changed = false; +} + +QPixmap KateExternalToolsConfigWidget::blankIcon() +{ + QPixmap pm( KIcon::SizeSmall, KIcon::SizeSmall ); + pm.fill(); + pm.setMask( pm.createHeuristicMask() ); + return pm; +} + +void KateExternalToolsConfigWidget::apply() +{ + if ( ! m_changed ) + return; + m_changed = false; + + // save a new list + // save each item + QStringList tools; + for ( uint i = 0; i < lbTools->count(); i++ ) + { + if ( lbTools->text( i ) == "---" ) + { + tools << "---"; + continue; + } + KateExternalTool *t = ((ToolItem*)lbTools->item( i ))->tool; +// kdDebug(13001)<<"adding tool: "<<t->name<<endl; + tools << t->acname; + + config->setGroup( t->acname ); + config->writeEntry( "name", t->name ); + config->writeEntry( "command", t->command ); + config->writeEntry( "icon", t->icon ); + config->writeEntry( "executable", t->tryexec ); + config->writeEntry( "mimetypes", t->mimetypes ); + config->writeEntry( "acname", t->acname ); + config->writeEntry( "cmdname", t->cmdname ); + config->writeEntry( "save", t->save ); + } + + config->setGroup("Global"); + config->writeEntry( "tools", tools ); + + // if any tools was removed, try to delete their groups, and + // add the group names to the list of removed items. + if ( m_removed.count() ) + { + for ( QStringList::iterator it = m_removed.begin(); it != m_removed.end(); ++it ) + { + if ( config->hasGroup( *it ) ) + config->deleteGroup( *it ); + } + QStringList removed = config->readListEntry( "removed" ); + removed += m_removed; + + // clean up the list of removed items, so that it does not contain + // non-existing groups (we can't remove groups from a non-owned global file). + config->sync(); + QStringList::iterator it1 = removed.begin(); + while( it1 != removed.end() ) + { + if ( ! config->hasGroup( *it1 ) ) + it1 = removed.remove( it1 ); + else + ++it1; + } + config->writeEntry( "removed", removed ); + } + + config->sync(); +} + +void KateExternalToolsConfigWidget::slotSelectionChanged() +{ + // update button state + bool hs = lbTools->selectedItem() != 0; + btnEdit->setEnabled( hs && dynamic_cast<ToolItem*>(lbTools->selectedItem()) ); + btnRemove->setEnabled( hs ); + btnMoveUp->setEnabled( ( lbTools->currentItem() > 0 ) && hs ); + btnMoveDwn->setEnabled( ( lbTools->currentItem() < (int)lbTools->count()-1 )&&hs ); +} + +void KateExternalToolsConfigWidget::slotNew() +{ + // display a editor, and if it is OK'd, create a new tool and + // create a listbox item for it + KateExternalToolServiceEditor editor( 0, this ); + + if ( editor.exec() ) + { + KateExternalTool *t = new KateExternalTool( + editor.leName->text(), + editor.teCommand->text(), + editor.btnIcon->icon(), + editor.leExecutable->text(), + QStringList::split( QRegExp("\\s*;\\s*"), editor.leMimetypes->text() ) ); + + // This is sticky, it does not change again, so that shortcuts sticks + // TODO check for dups + t->acname = "externaltool_" + QString(t->name).replace( QRegExp("\\W+"), "" ); + + new ToolItem ( lbTools, t->icon.isEmpty() ? blankIcon() : SmallIcon( t->icon ), t ); + + slotChanged(); + m_changed = true; + } +} + +void KateExternalToolsConfigWidget::slotRemove() +{ + // add the tool action name to a list of removed items, + // remove the current listbox item + if ( lbTools->currentItem() > -1 ) { + ToolItem *i = dynamic_cast<ToolItem*>(lbTools->selectedItem()); + if ( i ) + m_removed << i->tool->acname; + + lbTools->removeItem( lbTools->currentItem() ); + slotChanged(); + m_changed = true; + } +} + +void KateExternalToolsConfigWidget::slotEdit() +{ + if( !dynamic_cast<ToolItem*>(lbTools->selectedItem()) ) return; + // show the item in an editor + KateExternalTool *t = ((ToolItem*)lbTools->selectedItem())->tool; + KateExternalToolServiceEditor editor( t, this); + config->setGroup( "Editor" ); + editor.resize( config->readSizeEntry( "Size" ) ); + if ( editor.exec() /*== KDialogBase::Ok*/ ) + { + + bool elementChanged = ( ( editor.btnIcon->icon() != t->icon ) || (editor.leName->text() != t->name ) ) ; + + t->name = editor.leName->text(); + t->cmdname = editor.leCmdLine->text(); + t->command = editor.teCommand->text(); + t->icon = editor.btnIcon->icon(); + t->tryexec = editor.leExecutable->text(); + t->mimetypes = QStringList::split( QRegExp("\\s*;\\s*"), editor.leMimetypes->text() ); + t->save = editor.cmbSave->currentItem(); + + //if the icon has changed or name changed, I have to renew the listbox item :S + if ( elementChanged ) + { + int idx = lbTools->index( lbTools->selectedItem() ); + lbTools->removeItem( idx ); + lbTools->insertItem( new ToolItem( 0, t->icon.isEmpty() ? blankIcon() : SmallIcon( t->icon ), t ), idx ); + } + + slotChanged(); + m_changed = true; + } + + config->setGroup( "Editor" ); + config->writeEntry( "Size", editor.size() ); + config->sync(); +} + +void KateExternalToolsConfigWidget::slotInsertSeparator() +{ + lbTools->insertItem( "---", lbTools->currentItem()+1 ); + slotChanged(); + m_changed = true; +} + +void KateExternalToolsConfigWidget::slotMoveUp() +{ + // move the current item in the listbox upwards if possible + QListBoxItem *item = lbTools->selectedItem(); + if ( ! item ) return; + + int idx = lbTools->index( item ); + + if ( idx < 1 ) return; + + if ( dynamic_cast<ToolItem*>(item) ) + { + KateExternalTool *tool = ((ToolItem*)item)->tool; + lbTools->removeItem( idx ); + lbTools->insertItem( new ToolItem( 0, tool->icon.isEmpty() ? blankIcon() : SmallIcon( tool->icon ), tool ), idx-1 ); + } + else // a separator! + { + lbTools->removeItem( idx ); + lbTools->insertItem( new QListBoxText( 0, "---" ), idx-1 ); + } + + lbTools->setCurrentItem( idx - 1 ); + slotSelectionChanged(); + slotChanged(); + m_changed = true; +} + +void KateExternalToolsConfigWidget::slotMoveDown() +{ + // move the current item in the listbox downwards if possible + QListBoxItem *item = lbTools->selectedItem(); + if ( ! item ) return; + + uint idx = lbTools->index( item ); + + if ( idx > lbTools->count()-1 ) return; + + if ( dynamic_cast<ToolItem*>(item) ) + { + KateExternalTool *tool = ((ToolItem*)item)->tool; + lbTools->removeItem( idx ); + lbTools->insertItem( new ToolItem( 0, tool->icon.isEmpty() ? blankIcon() : SmallIcon( tool->icon ), tool ), idx+1 ); + } + else // a separator! + { + lbTools->removeItem( idx ); + lbTools->insertItem( new QListBoxText( 0, "---" ), idx+1 ); + } + + lbTools->setCurrentItem( idx+1 ); + slotSelectionChanged(); + slotChanged(); + m_changed = true; +} +//END KateExternalToolsConfigWidget +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kate/app/kateexternaltools.h b/kate/app/kateexternaltools.h new file mode 100644 index 000000000..4a5ecdacc --- /dev/null +++ b/kate/app/kateexternaltools.h @@ -0,0 +1,229 @@ +/* + This file is part of the Kate text editor of the KDE project. + It describes a "external tools" action for kate and provides a dialog + page to configure that. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + --- + Copyright (C) 2004, Anders Lund <anders@alweb.dk> +*/ + +#ifndef _KATE_EXTERNAL_TOOLS_H_ +#define _KATE_EXTERNAL_TOOLS_H_ + +#include <kaction.h> +#include <kdialogbase.h> +#include <kate/document.h> +#include <kmacroexpander.h> +#include <qpixmap.h> + +/** + * The external tools action + * This action creates a menu, in which each item will launch a process + * with the provided arguments, which may include the following macros: + * - %URLS: the URLs of all open documents. + * - %URL: The URL of the active document. + * - %filedir: The directory of the current document, if that is a local file. + * - %selection: The selection of the active document. + * - %text: The text of the active document. + * - %line: The line number of the cursor in the active view. + * - %column: The column of the cursor in the active view. + * + * Each item has the following properties: + * - Name: The friendly text for the menu + * - Exec: The command to execute, including arguments. + * - TryExec: the name of the executable, if not available, the + * item will not be displayed. + * - MimeTypes: An optional list of mimetypes. The item will be disabled or + * hidden if the current file is not of one of the indicated types. + * + */ +class KateExternalToolsMenuAction : public KActionMenu +{ + friend class KateExternalToolAction; + + Q_OBJECT + public: + KateExternalToolsMenuAction( const QString &text=QString::null, QObject *parent=0, const char* name=0, class KateMainWindow *mw=0 ); + ~KateExternalToolsMenuAction() {}; + + /** + * This will load all the confiured services. + */ + void reload(); + + class KActionCollection *actionCollection() { return m_actionCollection; } + + private slots: + void slotDocumentChanged(); + + private: + class KActionCollection *m_actionCollection; + class KateMainWindow *mainwindow; // for the actions to access view/doc managers +}; + +/** + * This Action contains a KateExternalTool + */ +class KateExternalToolAction : public KAction, public KWordMacroExpander +{ + Q_OBJECT + public: + KateExternalToolAction( QObject *parent, const char *name, class KateExternalTool *t ); + ~KateExternalToolAction(); + protected: + virtual bool expandMacro( const QString &str, QStringList &ret ); + + private slots: + void slotRun(); + + public: + class KateExternalTool *tool; +}; + +/** + * This class defines a single external tool. + */ +class KateExternalTool +{ + public: + KateExternalTool( const QString &name=QString::null, + const QString &command=QString::null, + const QString &icon=QString::null, + const QString &tryexec=QString::null, + const QStringList &mimetypes=QStringList(), + const QString &acname=QString::null, + const QString &cmdname=QString::null, + int save=0 ); + ~KateExternalTool() {}; + + QString name; ///< The name used in the menu. + QString command; ///< The command to execute. + QString icon; ///< the icon to use in the menu. + QString tryexec; ///< The name or path of the executable. + QStringList mimetypes; ///< Optional list of mimetypes for which this action is valid. + bool hasexec; ///< This is set by the constructor by calling checkExec(), if a value is present. + QString acname; ///< The name for the action. This is generated first time the action is is created. + QString cmdname; ///< The name for the commandline. + int save; ///< We can save documents prior to activating the tool command: 0 = nothing, 1 = current document, 2 = all documents. + + /** + * @return true if mimetypes is empty, or the @p mimetype matches. + */ + bool valid( const QString &mimetype ) const; + /** + * @return true if "tryexec" exists and has the executable bit set, or is + * empty. + * This is run at least once, and the tool is disabled if it fails. + */ + bool checkExec(); + + private: + QString m_exec; ///< The fully qualified path of the executable. +}; + +/** + * The config widget. + * The config widget allows the user to view a list of services of the type + * "Kate/ExternalTool" and add, remove or edit them. + */ +class KateExternalToolsConfigWidget : public Kate::ConfigPage +{ + Q_OBJECT + public: + KateExternalToolsConfigWidget( QWidget *parent, const char* name); + virtual ~KateExternalToolsConfigWidget(); + + virtual void apply(); + virtual void reload(); + virtual void reset() { reload(); } // sigh + virtual void defaults() { reload(); } // double sigh + + private slots: + void slotNew(); + void slotEdit(); + void slotRemove(); + void slotInsertSeparator(); + + void slotMoveUp(); + void slotMoveDown(); + + void slotSelectionChanged(); + + private: + QPixmap blankIcon(); + + QStringList m_removed; + + class KListBox *lbTools; + class QPushButton *btnNew, *btnRemove, *btnEdit, *btnMoveUp, *btnMoveDwn; + + class KConfig *config; + + bool m_changed; +}; + +/** + * A Singleton class for invoking external tools with the view command line + */ + class KateExternalToolsCommand : public Kate::Command { + public: + KateExternalToolsCommand (); + virtual ~KateExternalToolsCommand () {}; + static KateExternalToolsCommand *self(); + void reload(); + public: + virtual QStringList cmds (); + virtual bool exec (Kate::View *view, const QString &cmd, QString &msg); + virtual bool help (Kate::View *view, const QString &cmd, QString &msg); + private: + static KateExternalToolsCommand *s_self; + QStringList m_list; + QMap<QString,QString> m_map; + bool m_inited; + }; + +/** + * A Dialog to edit a single KateExternalTool object + */ +class KateExternalToolServiceEditor : public KDialogBase +{ + Q_OBJECT + + public: + + KateExternalToolServiceEditor( KateExternalTool *tool=0, + QWidget *parent=0, const char *name=0 ); + + class QLineEdit *leName, *leExecutable, *leMimetypes,*leCmdLine; + class QTextEdit *teCommand; + class KIconButton *btnIcon; + class QComboBox *cmbSave; + + private slots: + /** + * Run when the OK button is clicked, to ensure critical values are provided + */ + void slotOk(); + /** + * show a mimetype chooser dialog + */ + void showMTDlg(); + + private: + KateExternalTool *tool; +}; +#endif //_KATE_EXTERNAL_TOOLS_H_ diff --git a/kate/app/katefilelist.cpp b/kate/app/katefilelist.cpp new file mode 100644 index 000000000..8c350d45a --- /dev/null +++ b/kate/app/katefilelist.cpp @@ -0,0 +1,652 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +//BEGIN Includes +#include "katefilelist.h" +#include "katefilelist.moc" + +#include "katedocmanager.h" +#include "kateviewmanager.h" +#include "katemainwindow.h" + +#include <qapplication.h> +#include <qpainter.h> +#include <qpopupmenu.h> +#include <qheader.h> +#include <qcolor.h> +#include <qcheckbox.h> +#include <qhbox.h> +#include <qlayout.h> +#include <qgroupbox.h> +#include <qlabel.h> +#include <qwhatsthis.h> + +#include <kiconloader.h> +#include <kconfig.h> +#include <klocale.h> +#include <kglobalsettings.h> +#include <kpassivepopup.h> +#include <kdebug.h> +#include <kapplication.h> +#include <kstringhandler.h> +#include <kcolorbutton.h> +#include <kdialog.h> +//END Includes + +//BEGIN ToolTip +class ToolTip : public QToolTip +{ + public: + ToolTip( QWidget *parent, KateFileList *lv ) + : QToolTip( parent ), + m_listView( lv ) + { + } + virtual ~ToolTip() {}; + + void maybeTip( const QPoint &pos ) + { + QListViewItem *i = m_listView->itemAt( pos ); + if ( ! i ) return; + + KateFileListItem *item = ((KateFileListItem*)i); + if ( ! item ) return; + + tip( m_listView->itemRect( i ), m_listView->tooltip( item, 0 ) ); + + } + + private: + KateFileList *m_listView; +}; + +//END ToolTip + +//BEGIN KateFileList +KateFileList::KateFileList (KateMainWindow *main, + KateViewManager *_viewManager, + QWidget * parent, const char * name ) + : KListView (parent, name) + , m_sort( KateFileList::sortByID ) +{ + m_main = main; + m_tooltip = new ToolTip( viewport(), this ); + + // default colors + m_viewShade = QColor( 51, 204, 255 ); + m_editShade = QColor( 255, 102, 153 ); + m_enableBgShading = false; + + setFocusPolicy ( QWidget::NoFocus ); + + viewManager = _viewManager; + + header()->hide(); + addColumn("Document Name"); + + setSelectionMode( QListView::Single ); + setSorting( 0, true ); + setShowToolTips( false ); + + setupActions (); + + for (uint i = 0; i < KateDocManager::self()->documents(); i++) + { + slotDocumentCreated (KateDocManager::self()->document(i)); + slotModChanged (KateDocManager::self()->document(i)); + } + + connect(KateDocManager::self(),SIGNAL(documentCreated(Kate::Document *)), + this,SLOT(slotDocumentCreated(Kate::Document *))); + connect(KateDocManager::self(),SIGNAL(documentDeleted(uint)), + this,SLOT(slotDocumentDeleted(uint))); + + // don't Honour KDE single/double click setting, this files are already open, + // no need for hassle of considering double-click + connect(this,SIGNAL(selectionChanged(QListViewItem *)), + this,SLOT(slotActivateView(QListViewItem *))); + connect(viewManager,SIGNAL(viewChanged()), this,SLOT(slotViewChanged())); + connect(this,SIGNAL(contextMenuRequested( QListViewItem *, const QPoint &, int )), + this,SLOT(slotMenu ( QListViewItem *, const QPoint &, int ))); +} + +KateFileList::~KateFileList () +{ + delete m_tooltip; +} + +void KateFileList::setupActions () +{ + windowNext = KStdAction::back(this, SLOT(slotPrevDocument()), m_main->actionCollection()); + windowPrev = KStdAction::forward(this, SLOT(slotNextDocument()), m_main->actionCollection()); + sortAction = new KSelectAction( i18n("Sort &By"), 0, + m_main->actionCollection(), "filelist_sortby" ); + QStringList l; + l << i18n("Opening Order") << i18n("Document Name") << i18n("URL"); + sortAction->setItems( l ); + connect( sortAction, SIGNAL(activated(int)), this, SLOT(setSortType(int)) ); +} + +void KateFileList::updateActions () +{ + windowNext->setEnabled(KateDocManager::self()->documents() > 1); + windowPrev->setEnabled(KateDocManager::self()->documents() > 1); +} + +void KateFileList::keyPressEvent(QKeyEvent *e) { + if ( ( e->key() == Key_Return ) || ( e->key() == Key_Enter ) ) + { + e->accept(); + slotActivateView( currentItem() ); + } + else + { + KListView::keyPressEvent(e); + } +} + +// Protect single mode selection: don't let them +// leftclick outside items. +// ### if we get to accept keyboard navigation, set focus before +// returning +void KateFileList::contentsMousePressEvent( QMouseEvent *e ) +{ + if ( ! itemAt( contentsToViewport( e->pos() ) ) ) + return; + + KListView::contentsMousePressEvent( e ); +} + +void KateFileList::resizeEvent( QResizeEvent *e ) +{ + KListView::resizeEvent( e ); + + // ### We may want to actually calculate the widest field, + // since it's not automatically scrinked. If I add support for + // tree or marks, the changes of the required width will vary + // a lot with opening/closing of files and display changes for + // the mark branches. + int w = viewport()->width(); + if ( columnWidth( 0 ) < w ) + setColumnWidth( 0, w ); +} + +void KateFileList::slotNextDocument() +{ + if ( ! currentItem() || childCount() == 0 ) + return; + + // ### more checking once more item types are added + + if ( currentItem()->nextSibling() ) + viewManager->activateView( ((KateFileListItem*)currentItem()->nextSibling())->documentNumber() ); + else + viewManager->activateView( ((KateFileListItem *)firstChild())->documentNumber() ); +} + +void KateFileList::slotPrevDocument() +{ + if ( ! currentItem() || childCount() == 0 ) + return; + + // ### more checking once more item types are added + + if ( currentItem()->itemAbove() ) + viewManager->activateView( ((KateFileListItem*)currentItem()->itemAbove())->documentNumber() ); + else + viewManager->activateView( ((KateFileListItem *)lastItem())->documentNumber() ); +} + +void KateFileList::slotDocumentCreated (Kate::Document *doc) +{ + new KateFileListItem( this, doc/*, doc->documentNumber()*/ ); + connect(doc,SIGNAL(modStateChanged(Kate::Document *)),this,SLOT(slotModChanged(Kate::Document *))); + connect(doc,SIGNAL(nameChanged(Kate::Document *)),this,SLOT(slotNameChanged(Kate::Document *))); + connect(doc,SIGNAL(modifiedOnDisc(Kate::Document *, bool, unsigned char)),this,SLOT(slotModifiedOnDisc(Kate::Document *, bool, unsigned char))); + + sort(); + updateActions (); +} + +void KateFileList::slotDocumentDeleted (uint documentNumber) +{ + QListViewItem * item = firstChild(); + while( item ) { + if ( ((KateFileListItem *)item)->documentNumber() == documentNumber ) + { +// m_viewHistory.removeRef( (KateFileListItem *)item ); +// m_editHistory.removeRef( (KateFileListItem *)item ); + + removeItem( item ); + + break; + } + item = item->nextSibling(); + } + + updateActions (); +} + +void KateFileList::slotActivateView( QListViewItem *item ) +{ + if ( ! item || item->rtti() != RTTI_KateFileListItem ) + return; + + viewManager->activateView( ((KateFileListItem *)item)->documentNumber() ); +} + +void KateFileList::slotModChanged (Kate::Document *doc) +{ + if (!doc) return; + + QListViewItem * item = firstChild(); + while( item ) + { + if ( ((KateFileListItem *)item)->documentNumber() == doc->documentNumber() ) + break; + + item = item->nextSibling(); + } + + if ( ((KateFileListItem *)item)->document()->isModified() ) + { + m_editHistory.removeRef( (KateFileListItem *)item ); + m_editHistory.prepend( (KateFileListItem *)item ); + + for ( uint i=0; i < m_editHistory.count(); i++ ) + { + m_editHistory.at( i )->setEditHistPos( i+1 ); + repaintItem( m_editHistory.at( i ) ); + } + } + else + repaintItem( item ); +} + +void KateFileList::slotModifiedOnDisc (Kate::Document *doc, bool, unsigned char) +{ + slotModChanged( doc ); +} + +void KateFileList::slotNameChanged (Kate::Document *doc) +{ + if (!doc) return; + + // ### using nextSibling to *only* look at toplevel items. + // child items could be marks for example + QListViewItem * item = firstChild(); + while( item ) { + if ( ((KateFileListItem*)item)->document() == doc ) + { + item->setText( 0, doc->docName() ); + repaintItem( item ); + break; + } + item = item->nextSibling(); + } + updateSort(); +} + +void KateFileList::slotViewChanged () +{ + if (!viewManager->activeView()) return; + + Kate::View *view = viewManager->activeView(); + uint dn = view->getDoc()->documentNumber(); + + QListViewItem * i = firstChild(); + while( i ) { + if ( ((KateFileListItem *)i)->documentNumber() == dn ) + { + break; + } + i = i->nextSibling(); + } + + if ( ! i ) + return; + + KateFileListItem *item = (KateFileListItem*)i; + setCurrentItem( item ); + + // ### During load of file lists, all the loaded views gets active. + // Do something to avoid shading them -- maybe not creating views, just + // open the documents??? + + +// int p = 0; +// if ( m_viewHistory.count() ) +// { +// int p = m_viewHistory.findRef( item ); // only repaint items that needs it +// } + + m_viewHistory.removeRef( item ); + m_viewHistory.prepend( item ); + + for ( uint i=0; i < m_viewHistory.count(); i++ ) + { + m_viewHistory.at( i )->setViewHistPos( i+1 ); + repaintItem( m_viewHistory.at( i ) ); + } + +} + +void KateFileList::slotMenu ( QListViewItem *item, const QPoint &p, int /*col*/ ) +{ + if (!item) + return; + + QPopupMenu *menu = (QPopupMenu*) ((viewManager->mainWindow())->factory()->container("filelist_popup", viewManager->mainWindow())); + + if (menu) + menu->exec(p); +} + +QString KateFileList::tooltip( QListViewItem *item, int ) +{ + KateFileListItem *i = ((KateFileListItem*)item); + if ( ! i ) return QString::null; + + QString str; + const KateDocumentInfo *info = KateDocManager::self()->documentInfo(i->document()); + + if (info && info->modifiedOnDisc) + { + if (info->modifiedOnDiscReason == 1) + str += i18n("<b>This file was changed (modified) on disk by another program.</b><br />"); + else if (info->modifiedOnDiscReason == 2) + str += i18n("<b>This file was changed (created) on disk by another program.</b><br />"); + else if (info->modifiedOnDiscReason == 3) + str += i18n("<b>This file was changed (deleted) on disk by another program.</b><br />"); + } + + str += i->document()->url().prettyURL(); + return str; +} + + +void KateFileList::setSortType (int s) +{ + m_sort = s; + updateSort (); +} + +void KateFileList::updateSort () +{ + sort (); +} + +void KateFileList::readConfig( KConfig *config, const QString &group ) +{ + QString oldgroup = config->group(); + config->setGroup( group ); + + setSortType( config->readNumEntry( "Sort Type", sortByID ) ); + m_viewShade = config->readColorEntry( "View Shade", &m_viewShade ); + m_editShade = config->readColorEntry( "Edit Shade", &m_editShade ); + m_enableBgShading = config->readBoolEntry( "Shading Enabled", &m_enableBgShading ); + + sortAction->setCurrentItem( sortType() ); + + config->setGroup( oldgroup ); +} + +void KateFileList::writeConfig( KConfig *config, const QString &group ) +{ + QString oldgroup = config->group(); + config->setGroup( group ); + + config->writeEntry( "Sort Type", m_sort ); + config->writeEntry( "View Shade", m_viewShade ); + config->writeEntry( "Edit Shade", m_editShade ); + config->writeEntry( "Shading Enabled", m_enableBgShading ); + + config->setGroup( oldgroup ); +} + +void KateFileList::takeItem( QListViewItem *item ) +{ + if ( item->rtti() == RTTI_KateFileListItem ) + { + m_editHistory.removeRef( (KateFileListItem*)item ); + m_viewHistory.removeRef( (KateFileListItem*)item ); + } + QListView::takeItem( item ); +} +//END KateFileList + +//BEGIN KateFileListItem +KateFileListItem::KateFileListItem( QListView* lv, + Kate::Document *_doc ) + : QListViewItem( lv, _doc->docName() ), + doc( _doc ), + m_viewhistpos( 0 ), + m_edithistpos( 0 ), + m_docNumber( _doc->documentNumber() ) +{ +} + +KateFileListItem::~KateFileListItem() +{ +} + +const QPixmap *KateFileListItem::pixmap ( int column ) const +{ + if ( column == 0) { + static QPixmap noPm = SmallIcon ("null"); + static QPixmap modPm = SmallIcon("modified"); + static QPixmap discPm = SmallIcon("modonhd"); + static QPixmap modmodPm = SmallIcon("modmod"); + + const KateDocumentInfo *info = KateDocManager::self()->documentInfo(doc); + + if (info && info->modifiedOnDisc) + return doc->isModified() ? &modmodPm : &discPm; + else + return doc->isModified() ? &modPm : &noPm; + } + + return 0; +} + +void KateFileListItem::paintCell( QPainter *painter, const QColorGroup & cg, int column, int width, int align ) +{ + KateFileList *fl = (KateFileList*)listView(); + if ( ! fl ) return; + + if ( column == 0 ) + { + QColorGroup cgNew = cg; + + // replace the base color with a different shading if necessary... + if ( fl->shadingEnabled() && m_viewhistpos > 1 ) + { + QColor b( cg.base() ); + + QColor shade = fl->viewShade(); + QColor eshade = fl->editShade(); + int hc = fl->histCount(); + // If this file is in the edit history, blend in the eshade + // color. The blend is weighted by the position in the editing history + if ( fl->shadingEnabled() && m_edithistpos > 0 ) + { + int ec = fl->editHistCount(); + int v = hc-m_viewhistpos; + int e = ec-m_edithistpos+1; + e = e*e; + int n = QMAX(v + e, 1); + shade.setRgb( + ((shade.red()*v) + (eshade.red()*e))/n, + ((shade.green()*v) + (eshade.green()*e))/n, + ((shade.blue()*v) + (eshade.blue()*e))/n + ); + } + // blend in the shade color. + // max transperancy < .5, latest is most colored. + float t = (0.5/hc)*(hc-m_viewhistpos+1); + b.setRgb( + (int)((b.red()*(1-t)) + (shade.red()*t)), + (int)((b.green()*(1-t)) + (shade.green()*t)), + (int)((b.blue()*(1-t)) + (shade.blue()*t)) + ); + + cgNew.setColor(QColorGroup::Base, b); + } + + QListViewItem::paintCell( painter, cgNew, column, width, align ); + } + else + QListViewItem::paintCell( painter, cg, column, width, align ); +} + +int KateFileListItem::compare ( QListViewItem * i, int col, bool ascending ) const +{ + if ( i->rtti() == RTTI_KateFileListItem ) + { + switch( ((KateFileList*)listView())->sortType() ) + { + case KateFileList::sortByID: + { + + int d = (int)doc->documentNumber() - ((KateFileListItem*)i)->documentNumber(); + return ascending ? d : -d; + break; + } + case KateFileList::sortByURL: + return doc->url().prettyURL().compare( ((KateFileListItem*)i)->document()->url().prettyURL() ); + break; + default: + return QListViewItem::compare( i, col, ascending ); + } + } + return 0; +} +//END KateFileListItem + +//BEGIN KFLConfigPage +KFLConfigPage::KFLConfigPage( QWidget* parent, const char *name, KateFileList *fl ) + : Kate::ConfigPage( parent, name ), + m_filelist( fl ), + m_changed( false ) +{ + QVBoxLayout *lo1 = new QVBoxLayout( this ); + int spacing = KDialog::spacingHint(); + lo1->setSpacing( spacing ); + + QGroupBox *gb = new QGroupBox( 1, Qt::Horizontal, i18n("Background Shading"), this ); + lo1->addWidget( gb ); + + QWidget *g = new QWidget( gb ); + QGridLayout *lo = new QGridLayout( g, 2, 2 ); + lo->setSpacing( KDialog::spacingHint() ); + cbEnableShading = new QCheckBox( i18n("&Enable background shading"), g ); + lo->addMultiCellWidget( cbEnableShading, 1, 1, 0, 1 ); + + kcbViewShade = new KColorButton( g ); + lViewShade = new QLabel( kcbViewShade, i18n("&Viewed documents' shade:"), g ); + lo->addWidget( lViewShade, 2, 0 ); + lo->addWidget( kcbViewShade, 2, 1 ); + + kcbEditShade = new KColorButton( g ); + lEditShade = new QLabel( kcbEditShade, i18n("&Modified documents' shade:"), g ); + lo->addWidget( lEditShade, 3, 0 ); + lo->addWidget( kcbEditShade, 3, 1 ); + + // sorting + QHBox *hbSorting = new QHBox( this ); + lo1->addWidget( hbSorting ); + lSort = new QLabel( i18n("&Sort by:"), hbSorting ); + cmbSort = new QComboBox( hbSorting ); + lSort->setBuddy( cmbSort ); + QStringList l; + l << i18n("Opening Order") << i18n("Document Name") << i18n("URL"); + cmbSort->insertStringList( l ); + + lo1->insertStretch( -1, 10 ); + + QWhatsThis::add( cbEnableShading, i18n( + "When background shading is enabled, documents that have been viewed " + "or edited within the current session will have a shaded background. " + "The most recent documents have the strongest shade.") ); + QWhatsThis::add( kcbViewShade, i18n( + "Set the color for shading viewed documents.") ); + QWhatsThis::add( kcbEditShade, i18n( + "Set the color for modified documents. This color is blended into " + "the color for viewed files. The most recently edited documents get " + "most of this color.") ); + + QWhatsThis::add( cmbSort, i18n( + "Set the sorting method for the documents.") ); + + reload(); + + slotEnableChanged(); + connect( cbEnableShading, SIGNAL(toggled(bool)), this, SLOT(slotMyChanged()) ); + connect( cbEnableShading, SIGNAL(toggled(bool)), this, SLOT(slotEnableChanged()) ); + connect( kcbViewShade, SIGNAL(changed(const QColor&)), this, SLOT(slotMyChanged()) ); + connect( kcbEditShade, SIGNAL(changed(const QColor&)), this, SLOT(slotMyChanged()) ); + connect( cmbSort, SIGNAL(activated(int)), this, SLOT(slotMyChanged()) ); +} + +void KFLConfigPage::apply() +{ + if ( ! m_changed ) + return; + m_changed = false; + + // Change settings in the filelist + m_filelist->m_viewShade = kcbViewShade->color(); + m_filelist->m_editShade = kcbEditShade->color(); + m_filelist->m_enableBgShading = cbEnableShading->isChecked(); + m_filelist->setSortType( cmbSort->currentItem() ); + // repaint the affected items + m_filelist->triggerUpdate(); +} + +void KFLConfigPage::reload() +{ + // read in from config file + KConfig *config = kapp->config(); + config->setGroup( "Filelist" ); + cbEnableShading->setChecked( config->readBoolEntry("Shading Enabled", &m_filelist->m_enableBgShading ) ); + kcbViewShade->setColor( config->readColorEntry("View Shade", &m_filelist->m_viewShade ) ); + kcbEditShade->setColor( config->readColorEntry("Edit Shade", &m_filelist->m_editShade ) ); + cmbSort->setCurrentItem( m_filelist->sortType() ); + m_changed = false; +} + +void KFLConfigPage::slotEnableChanged() +{ + kcbViewShade->setEnabled( cbEnableShading->isChecked() ); + kcbEditShade->setEnabled( cbEnableShading->isChecked() ); + lViewShade->setEnabled( cbEnableShading->isChecked() ); + lEditShade->setEnabled( cbEnableShading->isChecked() ); +} + +void KFLConfigPage::slotMyChanged() +{ + m_changed = true; + slotChanged(); +} + +//END KFLConfigPage + + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kate/app/katefilelist.h b/kate/app/katefilelist.h new file mode 100644 index 000000000..7615eb63d --- /dev/null +++ b/kate/app/katefilelist.h @@ -0,0 +1,191 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __KATE_FILELIST_H__ +#define __KATE_FILELIST_H__ + +#include "katemain.h" + +#include <kate/document.h> + +#include <klistview.h> + +#include <qtooltip.h> +#include <qcolor.h> +#include <qptrlist.h> + +#define RTTI_KateFileListItem 1001 + +class KateMainWindow; + +class KAction; +class KSelectAction; + +class KateFileListItem : public QListViewItem +{ + public: + KateFileListItem( QListView *lv, + Kate::Document *doc ); + ~KateFileListItem(); + + inline uint documentNumber () { return m_docNumber; } + inline Kate::Document * document() { return doc; } + + int rtti() const { return RTTI_KateFileListItem; } + + /** + * Sets the view history position. + */ + void setViewHistPos( int p ) { m_viewhistpos = p; } + /** + * Sets the edit history position. + */ + void setEditHistPos( int p ) { m_edithistpos = p; } + + protected: + virtual const QPixmap *pixmap ( int column ) const; + void paintCell( QPainter *painter, const QColorGroup & cg, int column, int width, int align ); + /** + * Reimplemented so we can sort by a number of different document properties. + */ + int compare ( QListViewItem * i, int col, bool ascending ) const; + + private: + Kate::Document *doc; + int m_viewhistpos; ///< this gets set by the list as needed + int m_edithistpos; ///< this gets set by the list as needed + uint m_docNumber; +}; + +class KateFileList : public KListView +{ + Q_OBJECT + + friend class KFLConfigPage; + + public: + KateFileList (KateMainWindow *main, KateViewManager *_viewManager, QWidget * parent = 0, const char * name = 0 ); + ~KateFileList (); + + int sortType () const { return m_sort; }; + void updateSort (); + + enum sorting { + sortByID = 0, + sortByName = 1, + sortByURL = 2 + }; + + QString tooltip( QListViewItem *item, int ); + + uint histCount() const { return m_viewHistory.count(); } + uint editHistCount() const { return m_editHistory.count(); } + QColor editShade() const { return m_editShade; } + QColor viewShade() const { return m_viewShade; } + bool shadingEnabled() { return m_enableBgShading; } + + void readConfig( class KConfig *config, const QString &group ); + void writeConfig( class KConfig *config, const QString &group ); + + /** + * reimplemented to remove the item from the history stacks + */ + void takeItem( QListViewItem * ); + + public slots: + void setSortType (int s); + void slotNextDocument(); + void slotPrevDocument(); + + private slots: + void slotDocumentCreated (Kate::Document *doc); + void slotDocumentDeleted (uint documentNumber); + void slotActivateView( QListViewItem *item ); + void slotModChanged (Kate::Document *doc); + void slotModifiedOnDisc (Kate::Document *doc, bool b, unsigned char reason); + void slotNameChanged (Kate::Document *doc); + void slotViewChanged (); + void slotMenu ( QListViewItem *item, const QPoint &p, int col ); + + protected: + virtual void keyPressEvent( QKeyEvent *e ); + /** + * Reimplemented to force Single mode for real: + * don't let a mouse click outside items deselect. + */ + virtual void contentsMousePressEvent( QMouseEvent *e ); + /** + * Reimplemented to make sure the first (and only) column is at least + * the width of the viewport + */ + virtual void resizeEvent( QResizeEvent *e ); + + private: + void setupActions (); + void updateActions (); + + private: + KateMainWindow *m_main; + KateViewManager *viewManager; + + int m_sort; + bool notify; + + KAction* windowNext; + KAction* windowPrev; + KSelectAction* sortAction; + + QPtrList<KateFileListItem> m_viewHistory; + QPtrList<KateFileListItem> m_editHistory; + + QColor m_viewShade, m_editShade; + bool m_enableBgShading; + + class ToolTip *m_tooltip; +}; + +class KFLConfigPage : public Kate::ConfigPage { + Q_OBJECT + public: + KFLConfigPage( QWidget* parent=0, const char *name=0, KateFileList *fl=0 ); + virtual ~KFLConfigPage() {}; + + virtual void apply(); + virtual void reload(); + + public slots: + void slotEnableChanged(); + + private slots: + void slotMyChanged(); + + private: + class QCheckBox *cbEnableShading; + class KColorButton *kcbViewShade, *kcbEditShade; + class QLabel *lEditShade, *lViewShade, *lSort; + class QComboBox *cmbSort; + KateFileList *m_filelist; + + bool m_changed; +}; + + +#endif +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kate/app/katefileselector.cpp b/kate/app/katefileselector.cpp new file mode 100644 index 000000000..bdc39fc9a --- /dev/null +++ b/kate/app/katefileselector.cpp @@ -0,0 +1,722 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +//BEGIN Includes +#include "katefileselector.h" +#include "katefileselector.moc" + +#include "katemainwindow.h" +#include "kateviewmanager.h" +#include "kbookmarkhandler.h" + +#include "kactionselector.h" + +#include <qlayout.h> +#include <qtoolbutton.h> +#include <qhbox.h> +#include <qvbox.h> +#include <qlabel.h> +#include <qstrlist.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qapplication.h> +#include <qlistbox.h> +#include <qscrollbar.h> +#include <qspinbox.h> +#include <qgroupbox.h> +#include <qcheckbox.h> +#include <qregexp.h> +#include <qdockarea.h> +#include <qtimer.h> +#include <qdir.h> + +#include <kapplication.h> +#include <kiconloader.h> +#include <kurlcombobox.h> +#include <kurlcompletion.h> +#include <kprotocolinfo.h> +#include <kdiroperator.h> +#include <kconfig.h> +#include <klocale.h> +#include <kcombobox.h> +#include <kaction.h> +#include <kmessagebox.h> +#include <ktoolbarbutton.h> +#include <qtoolbar.h> +#include <kpopupmenu.h> +#include <kdialog.h> +#include <kdebug.h> +//END Includes + +//BEGIN Toolbar + // from kfiledialog.cpp - avoid qt warning in STDERR (~/.xsessionerrors) +static void silenceQToolBar(QtMsgType, const char *){} + +// helper classes to be able to have a toolbar without move handle +KateFileSelectorToolBar::KateFileSelectorToolBar(QWidget *parent) + : KToolBar( parent, "Kate FileSelector Toolbar", true ) +{ + setMinimumWidth(10); +} + +KateFileSelectorToolBar::~KateFileSelectorToolBar(){} + +void KateFileSelectorToolBar::setMovingEnabled( bool) +{ + KToolBar::setMovingEnabled(false); +} + + +KateFileSelectorToolBarParent::KateFileSelectorToolBarParent(QWidget *parent) + :QFrame(parent),m_tb(0){} +KateFileSelectorToolBarParent::~KateFileSelectorToolBarParent(){} +void KateFileSelectorToolBarParent::setToolBar(KateFileSelectorToolBar *tb) +{ + m_tb=tb; +} + +void KateFileSelectorToolBarParent::resizeEvent ( QResizeEvent * ) +{ + if (m_tb) + { + setMinimumHeight(m_tb->sizeHint().height()); + m_tb->resize(width(),height()); + } +} +//END + +//BEGIN Constructor/destructor + +KateFileSelector::KateFileSelector( KateMainWindow *mainWindow, + KateViewManager *viewManager, + QWidget * parent, const char * name ) + : QVBox (parent, name), + mainwin(mainWindow), + viewmanager(viewManager) +{ + mActionCollection = new KActionCollection( this ); + + QtMsgHandler oldHandler = qInstallMsgHandler( silenceQToolBar ); + + KateFileSelectorToolBarParent *tbp=new KateFileSelectorToolBarParent(this); + toolbar = new KateFileSelectorToolBar(tbp); + tbp->setToolBar(toolbar); + toolbar->setMovingEnabled(false); + toolbar->setFlat(true); + qInstallMsgHandler( oldHandler ); + + cmbPath = new KURLComboBox( KURLComboBox::Directories, true, this, "path combo" ); + cmbPath->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed )); + KURLCompletion* cmpl = new KURLCompletion(KURLCompletion::DirCompletion); + cmbPath->setCompletionObject( cmpl ); + cmbPath->setAutoDeleteCompletionObject( true ); + cmbPath->listBox()->installEventFilter( this ); + + dir = new KDirOperator(KURL(), this, "operator"); + dir->setView(KFile::/* Simple */Detail); + dir->view()->setSelectionMode(KFile::Extended); + connect ( dir, SIGNAL( viewChanged(KFileView *) ), + this, SLOT( selectorViewChanged(KFileView *) ) ); + setStretchFactor(dir, 2); + + KActionCollection *coll = dir->actionCollection(); + // some shortcuts of diroperator that clashes with Kate + coll->action( "delete" )->setShortcut( KShortcut( ALT + Key_Delete ) ); + coll->action( "reload" )->setShortcut( KShortcut( ALT + Key_F5 ) ); + coll->action( "back" )->setShortcut( KShortcut( ALT + SHIFT + Key_Left ) ); + coll->action( "forward" )->setShortcut( KShortcut( ALT + SHIFT + Key_Right ) ); + // some consistency - reset up for dir too + coll->action( "up" )->setShortcut( KShortcut( ALT + SHIFT + Key_Up ) ); + coll->action( "home" )->setShortcut( KShortcut( CTRL + ALT + Key_Home ) ); + + // bookmarks action! + KActionMenu *acmBookmarks = new KActionMenu( i18n("Bookmarks"), "bookmark", + mActionCollection, "bookmarks" ); + acmBookmarks->setDelayed( false ); + bookmarkHandler = new KBookmarkHandler( this, acmBookmarks->popupMenu() ); + QHBox* filterBox = new QHBox(this); + + btnFilter = new QToolButton( filterBox ); + btnFilter->setIconSet( SmallIconSet("filter" ) ); + btnFilter->setToggleButton( true ); + filter = new KHistoryCombo( true, filterBox, "filter"); + filter->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed )); + filterBox->setStretchFactor(filter, 2); + connect( btnFilter, SIGNAL( clicked() ), this, SLOT( btnFilterClick() ) ); + + connect( filter, SIGNAL( activated(const QString&) ), + SLOT( slotFilterChange(const QString&) ) ); + connect( filter, SIGNAL( returnPressed(const QString&) ), + filter, SLOT( addToHistory(const QString&) ) ); + + // kaction for the dir sync method + acSyncDir = new KAction( i18n("Current Document Folder"), "curfiledir", 0, + this, SLOT( setActiveDocumentDir() ), mActionCollection, "sync_dir" ); + toolbar->setIconText( KToolBar::IconOnly ); + toolbar->setIconSize( 16 ); + toolbar->setEnableContextMenu( false ); + + connect( cmbPath, SIGNAL( urlActivated( const KURL& )), + this, SLOT( cmbPathActivated( const KURL& ) )); + connect( cmbPath, SIGNAL( returnPressed( const QString& )), + this, SLOT( cmbPathReturnPressed( const QString& ) )); + connect(dir, SIGNAL(urlEntered(const KURL&)), + this, SLOT(dirUrlEntered(const KURL&)) ); + + connect(dir, SIGNAL(finishedLoading()), + this, SLOT(dirFinishedLoading()) ); + + // enable dir sync button if current doc has a valid URL + connect ( viewmanager, SIGNAL( viewChanged() ), + this, SLOT( kateViewChanged() ) ); + + // Connect the bookmark handler + connect( bookmarkHandler, SIGNAL( openURL( const QString& )), + this, SLOT( setDir( const QString& ) ) ); + + waitingUrl = QString::null; + + // whatsthis help + QWhatsThis::add( cmbPath, + i18n("<p>Here you can enter a path for a folder to display." + "<p>To go to a folder previously entered, press the arrow on " + "the right and choose one. <p>The entry has folder " + "completion. Right-click to choose how completion should behave.") ); + QWhatsThis::add( filter, + i18n("<p>Here you can enter a name filter to limit which files are displayed." + "<p>To clear the filter, toggle off the filter button to the left." + "<p>To reapply the last filter used, toggle on the filter button." ) ); + QWhatsThis::add( btnFilter, + i18n("<p>This button clears the name filter when toggled off, or " + "reapplies the last filter used when toggled on.") ); + +} + +KateFileSelector::~KateFileSelector() +{ +} +//END Constroctor/Destrctor + +//BEGIN Public Methods + +void KateFileSelector::readConfig(KConfig *config, const QString & name) +{ + dir->setViewConfig( config, name + ":view" ); + dir->readConfig(config, name + ":dir"); + dir->setView( KFile::Default ); + dir->view()->setSelectionMode(KFile::Extended); + config->setGroup( name ); + + // set up the toolbar + setupToolbar( config ); + + cmbPath->setMaxItems( config->readNumEntry( "pathcombo history len", 9 ) ); + cmbPath->setURLs( config->readPathListEntry( "dir history" ) ); + // if we restore history + if ( config->readBoolEntry( "restore location", true ) || kapp->isRestored() ) { + QString loc( config->readPathEntry( "location" ) ); + if ( ! loc.isEmpty() ) { +// waitingDir = loc; +// QTimer::singleShot(0, this, SLOT(initialDirChangeHack())); + setDir( loc ); + } + } + + // else is automatic, as cmpPath->setURL is called when a location is entered. + + filter->setMaxCount( config->readNumEntry( "filter history len", 9 ) ); + filter->setHistoryItems( config->readListEntry("filter history"), true ); + lastFilter = config->readEntry( "last filter" ); + QString flt(""); + if ( config->readBoolEntry( "restore last filter", true ) || kapp->isRestored() ) + flt = config->readEntry("current filter"); + filter->lineEdit()->setText( flt ); + slotFilterChange( flt ); + + autoSyncEvents = config->readNumEntry( "AutoSyncEvents", 0 ); +} + +void KateFileSelector::initialDirChangeHack() +{ + setDir( waitingDir ); +} + +void KateFileSelector::setupToolbar( KConfig *config ) +{ + toolbar->clear(); + QStringList tbactions = config->readListEntry( "toolbar actions", ',' ); + if ( tbactions.isEmpty() ) { + // reasonable collection for default toolbar + tbactions << "up" << "back" << "forward" << "home" << + "short view" << "detailed view" << + "bookmarks" << "sync_dir"; + } + KAction *ac; + for ( QStringList::Iterator it=tbactions.begin(); it != tbactions.end(); ++it ) { + if ( *it == "bookmarks" || *it == "sync_dir" ) + ac = mActionCollection->action( (*it).latin1() ); + else + ac = dir->actionCollection()->action( (*it).latin1() ); + if ( ac ) + ac->plug( toolbar ); + } +} + +void KateFileSelector::writeConfig(KConfig *config, const QString & name) +{ + dir->writeConfig(config,name + ":dir"); + + config->setGroup( name ); + config->writeEntry( "pathcombo history len", cmbPath->maxItems() ); + QStringList l; + for (int i = 0; i < cmbPath->count(); i++) { + l.append( cmbPath->text( i ) ); + } + config->writePathEntry( "dir history", l ); + config->writePathEntry( "location", cmbPath->currentText() ); + + config->writeEntry( "filter history len", filter->maxCount() ); + config->writeEntry( "filter history", filter->historyItems() ); + config->writeEntry( "current filter", filter->currentText() ); + config->writeEntry( "last filter", lastFilter ); + config->writeEntry( "AutoSyncEvents", autoSyncEvents ); +} + +void KateFileSelector::setView(KFile::FileView view) +{ + dir->setView(view); + dir->view()->setSelectionMode(KFile::Extended); +} + +//END Public Methods + +//BEGIN Public Slots + +void KateFileSelector::slotFilterChange( const QString & nf ) +{ + QString f = nf.stripWhiteSpace(); + bool empty = f.isEmpty() || f == "*"; + QToolTip::remove( btnFilter ); + if ( empty ) { + dir->clearFilter(); + filter->lineEdit()->setText( QString::null ); + QToolTip::add( btnFilter, + QString( i18n("Apply last filter (\"%1\")") ).arg( lastFilter ) ); + } + else { + dir->setNameFilter( f ); + lastFilter = f; + QToolTip::add( btnFilter, i18n("Clear filter") ); + } + btnFilter->setOn( !empty ); + dir->updateDir(); + // this will be never true after the filter has been used;) + btnFilter->setEnabled( !( empty && lastFilter.isEmpty() ) ); + +} + +bool kateFileSelectorIsReadable ( const KURL& url ) +{ + if ( !url.isLocalFile() ) + return true; // what else can we say? + + QDir dir (url.path()); + return dir.exists (); +} + +void KateFileSelector::setDir( KURL u ) +{ + KURL newurl; + + if ( !u.isValid() ) + newurl.setPath( QDir::homeDirPath() ); + else + newurl = u; + + QString pathstr = newurl.path(+1); + newurl.setPath(pathstr); + + if ( !kateFileSelectorIsReadable ( newurl ) ) + newurl.cd(QString::fromLatin1("..")); + + if ( !kateFileSelectorIsReadable (newurl) ) + newurl.setPath( QDir::homeDirPath() ); + + dir->setURL(newurl, true); +} + +//END Public Slots + +//BEGIN Private Slots + +void KateFileSelector::cmbPathActivated( const KURL& u ) +{ + cmbPathReturnPressed( u.url() ); +} + +void KateFileSelector::cmbPathReturnPressed( const QString& u ) +{ + KURL typedURL( u ); + if ( typedURL.hasPass() ) + typedURL.setPass( QString::null ); + + QStringList urls = cmbPath->urls(); + urls.remove( typedURL.url() ); + urls.prepend( typedURL.url() ); + cmbPath->setURLs( urls, KURLComboBox::RemoveBottom ); + dir->setFocus(); + dir->setURL( KURL(u), true ); +} + +void KateFileSelector::dirUrlEntered( const KURL& u ) +{ + cmbPath->setURL( u ); +} + +void KateFileSelector::dirFinishedLoading() +{ +} + + +/* + When the button in the filter box toggles: + If off: + If the name filer is anything but "" or "*", reset it. + If on: + Set last filter. +*/ +void KateFileSelector::btnFilterClick() +{ + if ( !btnFilter->isOn() ) { + slotFilterChange( QString::null ); + } + else { + filter->lineEdit()->setText( lastFilter ); + slotFilterChange( lastFilter ); + } +} + +//FIXME crash on shutdown +void KateFileSelector::setActiveDocumentDir() +{ +// kdDebug(13001)<<"KateFileSelector::setActiveDocumentDir()"<<endl; + KURL u = mainwin->activeDocumentUrl(); +// kdDebug(13001)<<"URL: "<<u.prettyURL()<<endl; + if (!u.isEmpty()) + setDir( u.upURL() ); +// kdDebug(13001)<<"... setActiveDocumentDir() DONE!"<<endl; +} + +void KateFileSelector::kateViewChanged() +{ + if ( autoSyncEvents & DocumentChanged ) + { +// kdDebug(13001)<<"KateFileSelector::do a sync ()"<<endl; + // if visible, sync + if ( isVisible() ) { + setActiveDocumentDir(); + waitingUrl = QString::null; + } + // else set waiting url + else { + KURL u = mainwin->activeDocumentUrl(); + if (!u.isEmpty()) + waitingUrl = u.directory(); + } + } + + // TODO: make sure the button is disabled if the directory is unreadable, eg + // the document URL has protocol http + acSyncDir->setEnabled( ! mainwin->activeDocumentUrl().directory().isEmpty() ); +} + +void KateFileSelector::selectorViewChanged( KFileView * newView ) +{ + newView->setSelectionMode(KFile::Extended); +} + +//END Private Slots + +//BEGIN Protected + +void KateFileSelector::focusInEvent( QFocusEvent * ) +{ + dir->setFocus(); +} + +void KateFileSelector::showEvent( QShowEvent * ) +{ + // sync if we should + if ( autoSyncEvents & GotVisible ) { +// kdDebug(13001)<<"syncing fs on show"<<endl; + setActiveDocumentDir(); + waitingUrl = QString::null; + } + // else, if we have a waiting URL set it + else if ( ! waitingUrl.isEmpty() ) { + setDir( waitingUrl ); + waitingUrl = QString::null; + } +} + +bool KateFileSelector::eventFilter( QObject* o, QEvent *e ) +{ + /* + This is rather unfortunate, but: + QComboBox does not support setting the size of the listbox to something + reasonable. Even using listbox->setVariableWidth() does not yield a + satisfying result, something is wrong with the handling of the sizehint. + And the popup is rather useless, if the paths are only partly visible. + */ + QListBox *lb = cmbPath->listBox(); + if ( o == lb && e->type() == QEvent::Show ) { + int add = lb->height() < lb->contentsHeight() ? lb->verticalScrollBar()->width() : 0; + int w = QMIN( mainwin->width(), lb->contentsWidth() + add ); + lb->resize( w, lb->height() ); + // TODO - move the listbox to a suitable place if nessecary + // TODO - decide if it is worth caching the size while untill the contents + // are changed. + } + // TODO - same thing for the completion popup? + return QWidget::eventFilter( o, e ); +} + +//END Protected + +//BEGIN ACtionLBItem +/* + QListboxItem that can store and return a string, + used for the toolbar action selector. +*/ +class ActionLBItem : public QListBoxPixmap { + public: + ActionLBItem( QListBox *lb=0, + const QPixmap &pm = QPixmap(), + const QString &text=QString::null, + const QString &str=QString::null ) : + QListBoxPixmap( lb, pm, text ), + _str(str) {}; + QString idstring() { return _str; }; + private: + QString _str; +}; +//END ActionLBItem + +//BEGIN KFSConfigPage +//////////////////////////////////////////////////////////////////////////////// +// KFSConfigPage implementation +//////////////////////////////////////////////////////////////////////////////// +KFSConfigPage::KFSConfigPage( QWidget *parent, const char *name, KateFileSelector *kfs ) + : Kate::ConfigPage( parent, name ), + fileSelector( kfs ), + m_changed( false ) +{ + QVBoxLayout *lo = new QVBoxLayout( this ); + int spacing = KDialog::spacingHint(); + lo->setSpacing( spacing ); + + // Toolbar - a lot for a little... + QGroupBox *gbToolbar = new QGroupBox( 1, Qt::Vertical, i18n("Toolbar"), this ); + acSel = new KActionSelector( gbToolbar ); + acSel->setAvailableLabel( i18n("A&vailable actions:") ); + acSel->setSelectedLabel( i18n("S&elected actions:") ); + lo->addWidget( gbToolbar ); + connect( acSel, SIGNAL( added( QListBoxItem * ) ), this, SLOT( slotMyChanged() ) ); + connect( acSel, SIGNAL( removed( QListBoxItem * ) ), this, SLOT( slotMyChanged() ) ); + connect( acSel, SIGNAL( movedUp( QListBoxItem * ) ), this, SLOT( slotMyChanged() ) ); + connect( acSel, SIGNAL( movedDown( QListBoxItem * ) ), this, SLOT( slotMyChanged() ) ); + + // Sync + QGroupBox *gbSync = new QGroupBox( 1, Qt::Horizontal, i18n("Auto Synchronization"), this ); + cbSyncActive = new QCheckBox( i18n("When a docu&ment becomes active"), gbSync ); + cbSyncShow = new QCheckBox( i18n("When the file selector becomes visible"), gbSync ); + lo->addWidget( gbSync ); + connect( cbSyncActive, SIGNAL( toggled( bool ) ), this, SLOT( slotMyChanged() ) ); + connect( cbSyncShow, SIGNAL( toggled( bool ) ), this, SLOT( slotMyChanged() ) ); + + // Histories + QHBox *hbPathHist = new QHBox ( this ); + QLabel *lbPathHist = new QLabel( i18n("Remember &locations:"), hbPathHist ); + sbPathHistLength = new QSpinBox( hbPathHist ); + lbPathHist->setBuddy( sbPathHistLength ); + lo->addWidget( hbPathHist ); + connect( sbPathHistLength, SIGNAL( valueChanged ( int ) ), this, SLOT( slotMyChanged() ) ); + + QHBox *hbFilterHist = new QHBox ( this ); + QLabel *lbFilterHist = new QLabel( i18n("Remember &filters:"), hbFilterHist ); + sbFilterHistLength = new QSpinBox( hbFilterHist ); + lbFilterHist->setBuddy( sbFilterHistLength ); + lo->addWidget( hbFilterHist ); + connect( sbFilterHistLength, SIGNAL( valueChanged ( int ) ), this, SLOT( slotMyChanged() ) ); + + // Session + QGroupBox *gbSession = new QGroupBox( 1, Qt::Horizontal, i18n("Session"), this ); + cbSesLocation = new QCheckBox( i18n("Restore loca&tion"), gbSession ); + cbSesFilter = new QCheckBox( i18n("Restore last f&ilter"), gbSession ); + lo->addWidget( gbSession ); + connect( cbSesLocation, SIGNAL( toggled( bool ) ), this, SLOT( slotMyChanged() ) ); + connect( cbSesFilter, SIGNAL( toggled( bool ) ), this, SLOT( slotMyChanged() ) ); + + // make it look nice + lo->addStretch( 1 ); + + // be helpfull + /* + QWhatsThis::add( lbAvailableActions, i18n( + "<p>Available actions for the toolbar. To add an action, select it here " + "and press the add (<strong>-></strong>) button" ) ); + QWhatsThis::add( lbUsedActions, i18n( + "<p>Actions used in the toolbar. To remove an action, select it and " + "press the remove (<strong><-</strong>) button." + "<p>To change the order of the actions, use the Up and Down buttons to " + "move the selected action.") ); + */ + QString lhwt( i18n( + "<p>Decides how many locations to keep in the history of the location " + "combo box.") ); + QWhatsThis::add( lbPathHist, lhwt ); + QWhatsThis::add( sbPathHistLength, lhwt ); + QString fhwt( i18n( + "<p>Decides how many filters to keep in the history of the filter " + "combo box.") ); + QWhatsThis::add( lbFilterHist, fhwt ); + QWhatsThis::add( sbFilterHistLength, fhwt ); + QString synwt( i18n( + "<p>These options allow you to have the File Selector automatically " + "change location to the folder of the active document on certain " + "events." + "<p>Auto synchronization is <em>lazy</em>, meaning it will not take " + "effect until the file selector is visible." + "<p>None of these are enabled by default, but you can always sync the " + "location by pressing the sync button in the toolbar.") ); + QWhatsThis::add( gbSync, synwt ); + QWhatsThis::add( cbSesLocation, i18n( + "<p>If this option is enabled (default), the location will be restored " + "when you start Kate.<p><strong>Note</strong> that if the session is " + "handled by the KDE session manager, the location is always restored.") ); + QWhatsThis::add( cbSesFilter, i18n( + "<p>If this option is enabled (default), the current filter will be " + "restored when you start Kate.<p><strong>Note</strong> that if the " + "session is handled by the KDE session manager, the filter is always " + "restored." + "<p><strong>Note</strong> that some of the autosync settings may " + "override the restored location if on.") ); + + init(); + +} + +void KFSConfigPage::apply() +{ + if ( ! m_changed ) + return; + + m_changed = false; + + KConfig *config = kapp->config(); + config->setGroup( "fileselector" ); + // toolbar + QStringList l; + QListBoxItem *item = acSel->selectedListBox()->firstItem(); + ActionLBItem *aItem; + while ( item ) + { + aItem = (ActionLBItem*)item; + if ( aItem ) + { + l << aItem->idstring(); + } + item = item->next(); + } + config->writeEntry( "toolbar actions", l ); + fileSelector->setupToolbar( config ); + // sync + int s = 0; + if ( cbSyncActive->isChecked() ) + s |= KateFileSelector::DocumentChanged; + if ( cbSyncShow->isChecked() ) + s |= KateFileSelector::GotVisible; + fileSelector->autoSyncEvents = s; + + // histories + fileSelector->cmbPath->setMaxItems( sbPathHistLength->value() ); + fileSelector->filter->setMaxCount( sbFilterHistLength->value() ); + // session - theese are read/written directly to the app config, + // as they are not needed during operation. + config->writeEntry( "restore location", cbSesLocation->isChecked() ); + config->writeEntry( "restore last filter", cbSesFilter->isChecked() ); +} + +void KFSConfigPage::reload() +{ + // hmm, what is this supposed to do, actually?? + init(); + m_changed = false; +} +void KFSConfigPage::init() +{ + KConfig *config = kapp->config(); + config->setGroup( "fileselector" ); + // toolbar + QStringList l = config->readListEntry( "toolbar actions", ',' ); + if ( l.isEmpty() ) // default toolbar + l << "up" << "back" << "forward" << "home" << + "short view" << "detailed view" << + "bookmarks" << "sync_dir"; + + // actions from diroperator + two of our own + QStringList allActions; + allActions << "up" << "back" << "forward" << "home" << + "reload" << "mkdir" << "delete" << + "short view" << "detailed view" /*<< "view menu" << + "show hidden" << "properties"*/ << + "bookmarks" << "sync_dir"; + QRegExp re("&(?=[^&])"); + KAction *ac; + QListBox *lb; + for ( QStringList::Iterator it=allActions.begin(); it != allActions.end(); ++it ) { + lb = l.contains( *it ) ? acSel->selectedListBox() : acSel->availableListBox(); + if ( *it == "bookmarks" || *it == "sync_dir" ) + ac = fileSelector->actionCollection()->action( (*it).latin1() ); + else + ac = fileSelector->dirOperator()->actionCollection()->action( (*it).latin1() ); + if ( ac ) + new ActionLBItem( lb, SmallIcon( ac->icon() ), ac->text().replace( re, "" ), *it ); + } + + // sync + int s = fileSelector->autoSyncEvents; + cbSyncActive->setChecked( s & KateFileSelector::DocumentChanged ); + cbSyncShow->setChecked( s & KateFileSelector::GotVisible ); + // histories + sbPathHistLength->setValue( fileSelector->cmbPath->maxItems() ); + sbFilterHistLength->setValue( fileSelector->filter->maxCount() ); + // session + cbSesLocation->setChecked( config->readBoolEntry( "restore location", true ) ); + cbSesFilter->setChecked( config->readBoolEntry( "restore last filter", true ) ); +} + +void KFSConfigPage::slotMyChanged() +{ + m_changed = true; + slotChanged(); +} +//END KFSConfigPage +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kate/app/katefileselector.h b/kate/app/katefileselector.h new file mode 100644 index 000000000..0bab4c257 --- /dev/null +++ b/kate/app/katefileselector.h @@ -0,0 +1,172 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __KATE_FILESELECTOR_H__ +#define __KATE_FILESELECTOR_H__ + +#include "katemain.h" +#include "katedocmanager.h" +#include <kate/document.h> + +#include <qvbox.h> +#include <kfile.h> +#include <kurl.h> +#include <ktoolbar.h> +#include <qframe.h> + +class KateMainWindow; +class KateViewManager; +class KActionCollection; +class KActionSelector; +class KFileView; + +/* + The kate file selector presents a directory view, in which the default action is + to open the activated file. + Additinally, a toolbar for managing the kdiroperator widget + sync that to + the directory of the current file is available, as well as a filter widget + allowing to filter the displayed files using a name filter. +*/ + +/* I think this fix for not moving toolbars is better */ +class KateFileSelectorToolBar: public KToolBar +{ + Q_OBJECT +public: + KateFileSelectorToolBar(QWidget *parent); + virtual ~KateFileSelectorToolBar(); + + virtual void setMovingEnabled( bool b ); +}; + +class KateFileSelectorToolBarParent: public QFrame +{ + Q_OBJECT +public: + KateFileSelectorToolBarParent(QWidget *parent); + ~KateFileSelectorToolBarParent(); + void setToolBar(KateFileSelectorToolBar *tb); +private: + KateFileSelectorToolBar *m_tb; +protected: + virtual void resizeEvent ( QResizeEvent * ); +}; + +class KateFileSelector : public QVBox +{ + Q_OBJECT + + friend class KFSConfigPage; + + public: + /* When to sync to current document directory */ + enum AutoSyncEvent { DocumentChanged=1, GotVisible=2 }; + + KateFileSelector( KateMainWindow *mainWindow=0, KateViewManager *viewManager=0, + QWidget * parent = 0, const char * name = 0 ); + ~KateFileSelector(); + + void readConfig( KConfig *, const QString & ); + void writeConfig( KConfig *, const QString & ); + void setupToolbar( KConfig * ); + void setView( KFile::FileView ); + KDirOperator *dirOperator(){ return dir; } + KActionCollection *actionCollection() { return mActionCollection; }; + + public slots: + void slotFilterChange(const QString&); + void setDir(KURL); + void setDir( const QString& url ) { setDir( KURL( url ) ); }; + void kateViewChanged(); + void selectorViewChanged( KFileView * ); + + private slots: + void cmbPathActivated( const KURL& u ); + void cmbPathReturnPressed( const QString& u ); + void dirUrlEntered( const KURL& u ); + void dirFinishedLoading(); + void setActiveDocumentDir(); + void btnFilterClick(); + + protected: + void focusInEvent( QFocusEvent * ); + void showEvent( QShowEvent * ); + bool eventFilter( QObject *, QEvent * ); + void initialDirChangeHack(); + + private: + class KateFileSelectorToolBar *toolbar; + KActionCollection *mActionCollection; + class KBookmarkHandler *bookmarkHandler; + KURLComboBox *cmbPath; + KDirOperator * dir; + class KAction *acSyncDir; + KHistoryCombo * filter; + class QToolButton *btnFilter; + + KateMainWindow *mainwin; + KateViewManager *viewmanager; + + QString lastFilter; + int autoSyncEvents; // enabled autosync events + QString waitingUrl; // maybe display when we gets visible + QString waitingDir; +}; + +/* TODO anders + KFSFilterHelper + A popup widget presenting a listbox with checkable items + representing the mime types available in the current directory, and + providing a name filter based on those. +*/ + +/* + Config page for file selector. + Allows for configuring the toolbar, the history length + of the path and file filter combos, and how to handle + user closed session. +*/ +class KFSConfigPage : public Kate::ConfigPage { + Q_OBJECT + public: + KFSConfigPage( QWidget* parent=0, const char *name=0, KateFileSelector *kfs=0); + virtual ~KFSConfigPage() {}; + + virtual void apply(); + virtual void reload(); + + private slots: + void slotMyChanged(); + + private: + void init(); + + KateFileSelector *fileSelector; + KActionSelector *acSel; + class QSpinBox *sbPathHistLength, *sbFilterHistLength; + class QCheckBox *cbSyncActive, *cbSyncShow; + class QCheckBox *cbSesLocation, *cbSesFilter; + + bool m_changed; +}; + + +#endif //__KATE_FILESELECTOR_H__ +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kate/app/kategrepdialog.cpp b/kate/app/kategrepdialog.cpp new file mode 100644 index 000000000..8816862de --- /dev/null +++ b/kate/app/kategrepdialog.cpp @@ -0,0 +1,544 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001, 2004 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kategrepdialog.h" +#include "katemainwindow.h" + +#include <qobject.h> +#include <qlayout.h> +#include <qlabel.h> +#include <qcheckbox.h> +#include <qevent.h> +#include <qlistbox.h> +#include <qregexp.h> +#include <qwhatsthis.h> +#include <qcursor.h> + +#include <kapplication.h> +#include <kaccelmanager.h> +#include <kbuttonbox.h> +#include <kfiledialog.h> +#include <kprocess.h> +#include <kapplication.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <kpushbutton.h> +#include <kurlrequester.h> +#include <kurlcompletion.h> +#include <kcombobox.h> +#include <klineedit.h> + +const char *template_desc[] = { + "normal", + "assignment", + "->MEMBER(", + "class::MEMBER(", + "OBJECT->member(", + 0 +}; + +const char *strTemplate[] = { + "%s", + "\\<%s\\>[\t ]*=[^=]", + "\\->[\\t ]*\\<%s\\>[\\t ]*(", + "[a-z0-9_$]\\+[\\t ]*::[\\t ]*\\<%s\\>[\\t ]*(", + "\\<%s\\>[\\t ]*\\->[\\t ]*[a-z0-9_$]\\+[\\t ]*(", + 0 +}; + + +GrepTool::GrepTool(QWidget *parent, const char *name) + : QWidget(parent, name/*, false*/), m_fixFocus(true), childproc(0) +{ + setCaption(i18n("Find in Files")); + config = KGlobal::config(); + config->setGroup("GrepTool"); + lastSearchItems = config->readListEntry("LastSearchItems"); + lastSearchPaths = config->readListEntry("LastSearchPaths"); + lastSearchFiles = config->readListEntry("LastSearchFiles"); + + if( lastSearchFiles.isEmpty() ) + { + // if there are no entries, most probably the first Kate start. + // Initialize with default values. + lastSearchFiles << "*.h,*.hxx,*.cpp,*.cc,*.C,*.cxx,*.idl,*.c" + << "*.cpp,*.cc,*.C,*.cxx,*.c" + << "*.h,*.hxx,*.idl" + << "*"; + } + + QGridLayout *layout = new QGridLayout(this, 6, 3, 4, 4); + layout->setColStretch(0, 10); + layout->addColSpacing(1, 10); + layout->setColStretch(1, 0); + layout->setColStretch(2, 1); + layout->setRowStretch(1, 0); + layout->setRowStretch(2, 10); + layout->setRowStretch(4, 0); + + QGridLayout *loInput = new QGridLayout(4, 2, 4); + layout->addLayout(loInput, 0, 0); + loInput->setColStretch(0, 0); + loInput->setColStretch(1, 20); + + QLabel *lPattern = new QLabel(i18n("Pattern:"), this); + lPattern->setFixedSize(lPattern->sizeHint()); + loInput->addWidget(lPattern, 0, 0, AlignRight | AlignVCenter); + + QBoxLayout *loPattern = new QHBoxLayout( 4 ); + loInput->addLayout( loPattern, 0, 1 ); + cmbPattern = new KComboBox(true, this); + cmbPattern->setDuplicatesEnabled(false); + cmbPattern->insertStringList(lastSearchItems); + cmbPattern->setEditText(QString::null); + cmbPattern->setInsertionPolicy(QComboBox::NoInsertion); + lPattern->setBuddy(cmbPattern); + cmbPattern->setFocus(); + cmbPattern->setMinimumSize(cmbPattern->sizeHint()); + loPattern->addWidget( cmbPattern ); + + cbCasesensitive = new QCheckBox(i18n("Case sensitive"), this); + cbCasesensitive->setMinimumWidth(cbCasesensitive->sizeHint().width()); + cbCasesensitive->setChecked(config->readBoolEntry("CaseSensitive", true)); + loPattern->addWidget(cbCasesensitive); + + cbRegex = new QCheckBox( i18n("Regular expression"), this ); + cbRegex->setMinimumWidth( cbRegex->sizeHint().width() ); + cbRegex->setChecked( config->readBoolEntry( "Regex", true ) ); + loPattern->addWidget( cbRegex ); + loPattern->setStretchFactor( cmbPattern, 100 ); + + QLabel *lTemplate = new QLabel(i18n("Template:"), this); + lTemplate->setFixedSize(lTemplate->sizeHint()); + loInput->addWidget(lTemplate, 1, 0, AlignRight | AlignVCenter); + + QBoxLayout *loTemplate = new QHBoxLayout(4); + loInput->addLayout(loTemplate, 1, 1); + + leTemplate = new KLineEdit(this); + lTemplate->setBuddy(leTemplate); + leTemplate->setText(strTemplate[0]); + leTemplate->setMinimumSize(leTemplate->sizeHint()); + loTemplate->addWidget(leTemplate); + + KComboBox *cmbTemplate = new KComboBox(false, this); + cmbTemplate->insertStrList(template_desc); + cmbTemplate->adjustSize(); + cmbTemplate->setFixedSize(cmbTemplate->size()); + loTemplate->addWidget(cmbTemplate); + + QLabel *lFiles = new QLabel(i18n("Files:"), this); + lFiles->setFixedSize(lFiles->sizeHint()); + loInput->addWidget(lFiles, 2, 0, AlignRight | AlignVCenter); + + cmbFiles = new KComboBox(true, this); + lFiles->setBuddy(cmbFiles->focusProxy()); + cmbFiles->setMinimumSize(cmbFiles->sizeHint()); + cmbFiles->setInsertionPolicy(QComboBox::NoInsertion); + cmbFiles->setDuplicatesEnabled(false); + cmbFiles->insertStringList(lastSearchFiles); + loInput->addWidget(cmbFiles, 2, 1); + + QLabel *lDir = new QLabel(i18n("Folder:"), this); + lDir->setFixedSize(lDir->sizeHint()); + loInput->addWidget(lDir, 3, 0, AlignRight | AlignVCenter); + + QBoxLayout *loDir = new QHBoxLayout(3); + loInput->addLayout(loDir, 3, 1); + + KComboBox* cmbUrl = new KComboBox(true, this); + cmbUrl->setMinimumWidth(80); // make sure that 800x600 res works + cmbUrl->setDuplicatesEnabled(false); + cmbUrl->setInsertionPolicy(QComboBox::NoInsertion); + cmbDir = new KURLRequester( cmbUrl, this, "dir combo" ); + cmbDir->completionObject()->setMode(KURLCompletion::DirCompletion); + cmbDir->comboBox()->insertStringList(lastSearchPaths); + cmbDir->setMode( KFile::Directory|KFile::LocalOnly ); + loDir->addWidget(cmbDir, 1); + lDir->setBuddy(cmbDir); + + cbRecursive = new QCheckBox(i18n("Recursive"), this); + cbRecursive->setMinimumWidth(cbRecursive->sizeHint().width()); + cbRecursive->setChecked(config->readBoolEntry("Recursive", true)); + loDir->addWidget(cbRecursive); + + KButtonBox *actionbox = new KButtonBox(this, Qt::Vertical); + layout->addWidget(actionbox, 0, 2); + actionbox->addStretch(); + btnSearch = static_cast<KPushButton*>(actionbox->addButton(KGuiItem(i18n("Find"),"find"))); + btnSearch->setDefault(true); + btnClear = static_cast<KPushButton*>(actionbox->addButton( KStdGuiItem::clear() )); + actionbox->addStretch(); + actionbox->layout(); + + lbResult = new QListBox(this); + QFontMetrics rb_fm(lbResult->fontMetrics()); + layout->addMultiCellWidget(lbResult, 2, 2, 0, 2); + + layout->activate(); + + KAcceleratorManager::manage( this ); + + QWhatsThis::add(lPattern, + i18n("<p>Enter the expression you want to search for here." + "<p>If 'regular expression' is unchecked, any non-space letters in your " + "expression will be escaped with a backslash character." + "<p>Possible meta characters are:<br>" + "<b>.</b> - Matches any character<br>" + "<b>^</b> - Matches the beginning of a line<br>" + "<b>$</b> - Matches the end of a line<br>" + "<b>\\<</b> - Matches the beginning of a word<br>" + "<b>\\></b> - Matches the end of a word" + "<p>The following repetition operators exist:<br>" + "<b>?</b> - The preceding item is matched at most once<br>" + "<b>*</b> - The preceding item is matched zero or more times<br>" + "<b>+</b> - The preceding item is matched one or more times<br>" + "<b>{<i>n</i>}</b> - The preceding item is matched exactly <i>n</i> times<br>" + "<b>{<i>n</i>,}</b> - The preceding item is matched <i>n</i> or more times<br>" + "<b>{,<i>n</i>}</b> - The preceding item is matched at most <i>n</i> times<br>" + "<b>{<i>n</i>,<i>m</i>}</b> - The preceding item is matched at least <i>n</i>, " + "but at most <i>m</i> times." + "<p>Furthermore, backreferences to bracketed subexpressions are available " + "via the notation <code>\\#</code>." + "<p>See the grep(1) documentation for the full documentation." + )); + QWhatsThis::add(lFiles, + i18n("Enter the file name pattern of the files to search here.\n" + "You may give several patterns separated by commas.")); + QWhatsThis::add(lTemplate, + i18n("You can choose a template for the pattern from the combo box\n" + "and edit it here. The string %s in the template is replaced\n" + "by the pattern input field, resulting in the regular expression\n" + "to search for.")); + QWhatsThis::add(lDir, + i18n("Enter the folder which contains the files in which you want to search.")); + QWhatsThis::add(cbRecursive, + i18n("Check this box to search in all subfolders.")); + QWhatsThis::add(cbCasesensitive, + i18n("If this option is enabled (the default), the search will be case sensitive.")); + QWhatsThis::add( cbRegex, i18n( + "<p>If this is enabled, your pattern will be passed unmodified to " + "<em>grep(1)</em>. Otherwise, all characters that are not letters will be " + "escaped using a backslash character to prevent grep from interpreting " + "them as part of the expression.") ); + QWhatsThis::add(lbResult, + i18n("The results of the grep run are listed here. Select a\n" + "filename/line number combination and press Enter or doubleclick\n" + "on the item to show the respective line in the editor.")); + + // event filter, do something relevant for RETURN + cmbPattern->installEventFilter( this ); + leTemplate->installEventFilter( this ); + cmbFiles->installEventFilter( this ); + cmbDir->comboBox()->installEventFilter( this ); + + connect( cmbTemplate, SIGNAL(activated(int)), + SLOT(templateActivated(int)) ); + connect( lbResult, SIGNAL(selected(const QString&)), + SLOT(itemSelected(const QString&)) ); + connect( btnSearch, SIGNAL(clicked()), + SLOT(slotSearch()) ); + connect( btnClear, SIGNAL(clicked()), + SLOT(slotClear()) ); + connect( cmbPattern->lineEdit(), SIGNAL(textChanged ( const QString & )), + SLOT( patternTextChanged( const QString & ))); + + patternTextChanged( cmbPattern->lineEdit()->text()); +} + + +GrepTool::~GrepTool() +{ + delete childproc; +} + +void GrepTool::patternTextChanged( const QString & _text) +{ + btnSearch->setEnabled( !_text.isEmpty() ); +} + +void GrepTool::templateActivated(int index) +{ + leTemplate->setText(strTemplate[index]); +} + +void GrepTool::itemSelected(const QString& item) +{ + int pos; + QString filename, linenumber; + + QString str = item; + if ( (pos = str.find(':')) != -1) + { + filename = str.left(pos); + str = str.mid(pos+1); + if ( (pos = str.find(':')) != -1) + { + filename = m_workingDir + QDir::separator() + filename; + linenumber = str.left(pos); + emit itemSelected(filename,linenumber.toInt()-1); + } + } +} + +void GrepTool::processOutput() +{ + int pos; + while ( (pos = buf.find('\n')) != -1) + { + QString item = buf.mid(2,pos-2); + if (!item.isEmpty()) + lbResult->insertItem(item); + buf = buf.mid(pos+1); + } + kapp->processEvents(); +} + +void GrepTool::slotSearch() +{ + if ( cmbPattern->currentText().isEmpty() ) + { + cmbPattern->setFocus(); + return; + } + + if ( cmbDir->url().isEmpty() || ! QDir(cmbDir->url()).exists() ) + { + cmbDir->setFocus(); + KMessageBox::information( this, i18n( + "You must enter an existing local folder in the 'Folder' entry."), + i18n("Invalid Folder"), "Kate grep tool: invalid folder" ); + return; + } + + if ( ! leTemplate->text().contains("%s") ) + { + leTemplate->setFocus(); + return; + } + + if ( childproc && childproc->isRunning() ) + { + childproc->kill(); + return; + } + + slotClear (); + + m_workingDir = cmbDir->url(); + + QString s = cmbPattern->currentText(); + if ( ! cbRegex->isChecked() ) + s.replace( QRegExp( "([^\\w'()<>])" ), "\\\\1" ); + QString pattern = leTemplate->text(); + pattern.replace( "%s", s ); + + childproc = new KProcess(); + childproc->setWorkingDirectory( m_workingDir ); + *childproc << "find" << "."; + if (!cbRecursive->isChecked()) + *childproc << "-maxdepth" << "1"; + if (!cmbFiles->currentText().isEmpty() ) + { + QStringList files = QStringList::split ( ",", cmbFiles->currentText(), FALSE ); + *childproc << "("; + bool first = true; + for ( QStringList::Iterator it = files.begin(); it != files.end(); ++it ) + { + if (!first) + *childproc << "-o"; + *childproc << "-name" << (*it); + first = false; + } + *childproc << ")"; + } + *childproc << "-exec" << "grep"; + if (!cbCasesensitive->isChecked()) + *childproc << "-i"; + *childproc << "-n" << "-e" << pattern << "{}"; + *childproc << "/dev/null"; //trick to have grep always display the filename + *childproc << ";"; + + connect( childproc, SIGNAL(processExited(KProcess *)), + SLOT(childExited()) ); + connect( childproc, SIGNAL(receivedStdout(KProcess *, char *, int)), + SLOT(receivedOutput(KProcess *, char *, int)) ); + connect( childproc, SIGNAL(receivedStderr(KProcess *, char *, int)), + SLOT(receivedErrOutput(KProcess *, char *, int)) ); + + // actually it should be checked whether the process was started successfully + lbResult->setCursor( QCursor(Qt::WaitCursor) ); + btnClear->setEnabled( false ); + btnSearch->setGuiItem( KGuiItem(i18n("Cancel"), "button_cancel")); + childproc->start(KProcess::NotifyOnExit, KProcess::AllOutput); +} + +void GrepTool::slotSearchFor(const QString &pattern) +{ + slotClear(); + cmbPattern->setEditText(pattern); + slotSearch(); +} + +void GrepTool::finish() +{ + btnSearch->setEnabled( !cmbPattern->lineEdit()->text().isEmpty() ); + + buf += '\n'; + processOutput(); + delete childproc; + childproc = 0; + + config->setGroup("GrepTool"); + + QString cmbText = cmbPattern->currentText(); + bool itemsRemoved = lastSearchItems.remove(cmbText) > 0; + lastSearchItems.prepend(cmbText); + if (itemsRemoved) + { + cmbPattern->removeItem(cmbPattern->currentItem()); + } + cmbPattern->insertItem(cmbText, 0); + cmbPattern->setCurrentItem(0); + if (lastSearchItems.count() > 10) { + lastSearchItems.pop_back(); + cmbPattern->removeItem(cmbPattern->count() - 1); + } + config->writeEntry("LastSearchItems", lastSearchItems); + + + cmbText = cmbDir->url(); + itemsRemoved = lastSearchPaths.remove(cmbText) > 0; + lastSearchPaths.prepend(cmbText); + if (itemsRemoved) + { + cmbDir->comboBox()->removeItem(cmbDir->comboBox()->currentItem()); + } + cmbDir->comboBox()->insertItem(cmbText, 0); + cmbDir->comboBox()->setCurrentItem(0); + if (lastSearchPaths.count() > 10) + { + lastSearchPaths.pop_back(); + cmbDir->comboBox()->removeItem(cmbDir->comboBox()->count() - 1); + } + config->writeEntry("LastSearchPaths", lastSearchPaths); + + + cmbText = cmbFiles->currentText(); + itemsRemoved = lastSearchFiles.remove(cmbText) > 0; + lastSearchFiles.prepend(cmbText); + if (itemsRemoved) + { + cmbFiles->removeItem(cmbFiles->currentItem()); + } + cmbFiles->insertItem(cmbText, 0); + cmbFiles->setCurrentItem(0); + if (lastSearchFiles.count() > 10) { + lastSearchFiles.pop_back(); + cmbFiles->removeItem(cmbFiles->count() - 1); + } + config->writeEntry("LastSearchFiles", lastSearchFiles); + + config->writeEntry("Recursive", cbRecursive->isChecked()); + config->writeEntry("CaseSensitive", cbCasesensitive->isChecked()); + config->writeEntry("Regex", cbRegex->isChecked()); +} + +void GrepTool::slotCancel() +{ + finish(); +} + +void GrepTool::childExited() +{ +// int status = childproc->exitStatus(); + lbResult->unsetCursor(); + btnClear->setEnabled( true ); + btnSearch->setGuiItem( KGuiItem(i18n("Find"), "find") ); + + if ( ! errbuf.isEmpty() ) + { + KMessageBox::information( parentWidget(), i18n("<strong>Error:</strong><p>") + errbuf, i18n("Grep Tool Error") ); + errbuf.truncate(0); + } + else + finish(); +} + +void GrepTool::receivedOutput(KProcess */*proc*/, char *buffer, int buflen) +{ + buf += QCString(buffer, buflen+1); + processOutput(); +} + +void GrepTool::receivedErrOutput(KProcess */*proc*/, char *buffer, int buflen) +{ + errbuf += QCString( buffer, buflen + 1 ); +} + +void GrepTool::slotClear() +{ + finish(); + lbResult->clear(); +} + +void GrepTool::updateDirName(const QString &dir) +{ + if (m_lastUpdatedDir != dir) + { + setDirName (dir); + m_lastUpdatedDir = dir; + } +} + +void GrepTool::setDirName(const QString &dir){ + cmbDir->setURL(dir); +} + +bool GrepTool::eventFilter( QObject *o, QEvent *e ) +{ + if ( e->type() == QEvent::KeyPress && ( + ((QKeyEvent*)e)->key() == Qt::Key_Return || + ((QKeyEvent*)e)->key() == Qt::Key_Enter ) ) + { + slotSearch(); + return true; + } + + return QWidget::eventFilter( o, e ); +} + +void GrepTool::focusInEvent ( QFocusEvent * ev ) +{ + QWidget::focusInEvent(ev); + if (m_fixFocus) { + m_fixFocus = false; + cmbPattern->setFocus(); + } +} + +void GrepTool::showEvent( QShowEvent * ev ) +{ + QWidget::showEvent(ev); + m_fixFocus = true; +} + +#include "kategrepdialog.moc" diff --git a/kate/app/kategrepdialog.h b/kate/app/kategrepdialog.h new file mode 100644 index 000000000..5ed3b2b69 --- /dev/null +++ b/kate/app/kategrepdialog.h @@ -0,0 +1,97 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _GREPDIALOG_H_ +#define _GREPDIALOG_H_ + +#include <kdialog.h> +#include <qstringlist.h> + +class QLineEdit; +class KComboBox; +class QCheckBox; +class QListBox; +class KPushButton; +class QLabel; +class KProcess; +class KConfig; +class KURLRequester; +class QEvent; + +class GrepTool : public QWidget +{ + Q_OBJECT + +public: + GrepTool(QWidget *parent, const char *name=0); + ~GrepTool(); + + // only updates if the dir you give to it differs from the last one given to it ! + void updateDirName(const QString &); + + void setDirName(const QString &); + + +signals: + void itemSelected(const QString &abs_filename, int line); + +public slots: + void slotSearchFor(const QString &pattern); + +protected: + bool eventFilter( QObject *, QEvent * ); + void focusInEvent ( QFocusEvent * ); + void showEvent( QShowEvent * ); + bool m_fixFocus; + +private slots: + void templateActivated(int index); + void childExited(); + void receivedOutput(KProcess *proc, char *buffer, int buflen); + void receivedErrOutput(KProcess *proc, char *buffer, int buflen); + void itemSelected(const QString&); + void slotSearch(); + void slotCancel(); + void slotClear(); + void patternTextChanged( const QString &); +private: + void processOutput(); + void finish(); + + QLineEdit *leTemplate; + KComboBox *cmbFiles, *cmbPattern; + KURLRequester *cmbDir; + QCheckBox *cbRecursive; + QCheckBox *cbCasesensitive, *cbRegex; + QListBox *lbResult; + KPushButton *btnSearch, *btnClear; + KProcess *childproc; + QString buf; + QString errbuf; + KConfig* config; + QStringList lastSearchItems; + QStringList lastSearchPaths; + QStringList lastSearchFiles; + QString m_lastUpdatedDir; + QString m_workingDir; +}; + + +#endif diff --git a/kate/app/katemailfilesdialog.cpp b/kate/app/katemailfilesdialog.cpp new file mode 100644 index 000000000..03bd497df --- /dev/null +++ b/kate/app/katemailfilesdialog.cpp @@ -0,0 +1,112 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "katemailfilesdialog.h" +#include "katemainwindow.h" +#include "kateviewmanager.h" +#include "katedocmanager.h" + +#include <klistview.h> +#include <klocale.h> +#include <kurl.h> + +#include <qevent.h> +#include <qlabel.h> +#include <qstringlist.h> +#include <qvbox.h> + +/* a private check list item, that can store a Kate::Document*. */ +class KateDocCheckItem : public QCheckListItem { + public: + KateDocCheckItem( QListView *parent, const QString& text, Kate::Document *d ) + : QCheckListItem( parent, text, QCheckListItem::CheckBox ), mdoc(d) {}; + Kate::Document *doc() { return mdoc; }; + private: + Kate::Document *mdoc; +}; + +/////////////////////////////////////////////////////////////////////////// +// KateMailDialog implementation +/////////////////////////////////////////////////////////////////////////// +KateMailDialog::KateMailDialog( QWidget *parent, KateMainWindow *mainwin ) + : KDialogBase( parent, "kate mail dialog", true, i18n("Email Files"), + Ok|Cancel|User1, Ok, false, + KGuiItem( i18n("&Show All Documents >>") ) ), + mainWindow( mainwin ) +{ + setButtonGuiItem( KDialogBase::Ok, KGuiItem( i18n("&Mail..."), "mail_send") ); + mw = makeVBoxMainWidget(); + mw->installEventFilter( this ); + + lInfo = new QLabel( i18n( + "<p>Press <strong>Mail...</strong> to email the current document." + "<p>To select more documents to send, press <strong>Show All Documents >></strong>."), mw ); + // TODO avoid untill needed - later + list = new KListView( mw ); + list->addColumn( i18n("Name") ); + list->addColumn( i18n("URL") ); + Kate::Document *currentDoc = mainWindow->viewManager()->activeView()->getDoc(); + uint n = KateDocManager::self()->documents(); + uint i = 0; + QCheckListItem *item; + while ( i < n ) { + Kate::Document *doc = KateDocManager::self()->document( i ); + if ( doc ) { + item = new KateDocCheckItem( list, doc->docName(), doc ); + item->setText( 1, doc->url().prettyURL() ); + if ( doc == currentDoc ) { + item->setOn( true ); + item->setSelected( true ); + } + } + i++; + } + list->hide(); + connect( this, SIGNAL(user1Clicked()), this, SLOT(slotShowButton()) ); + mw->setMinimumSize( lInfo->sizeHint() ); +} + +QPtrList<Kate::Document> KateMailDialog::selectedDocs() +{ + QPtrList<Kate::Document> l; + QListViewItem *item = list->firstChild(); + while ( item ) { + if ( ((KateDocCheckItem*)item)->isOn() ) + l.append( ((KateDocCheckItem*)item)->doc() ); + item = item->nextSibling(); + } + return l; +} + +void KateMailDialog::slotShowButton() +{ + if ( list->isVisible() ) { + setButtonText( User1, i18n("&Show All Documents >>") ); + list->hide(); + } + else { + list->show(); + setButtonText( User1, i18n("&Hide Document List <<") ); + lInfo->setText( i18n("Press <strong>Mail...</strong> to send selected documents") ); + + } + mw->setMinimumSize( QSize( lInfo->sizeHint().width(), mw->sizeHint().height()) ); + setMinimumSize( calculateSize( mw->minimumSize().width(), mw->sizeHint().height() ) ); + resize( width(), minimumHeight() ); +} +#include "katemailfilesdialog.moc" diff --git a/kate/app/katemailfilesdialog.h b/kate/app/katemailfilesdialog.h new file mode 100644 index 000000000..906cd99fa --- /dev/null +++ b/kate/app/katemailfilesdialog.h @@ -0,0 +1,59 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _KATE_MAILFILES_DIALOG_H_ +#define _KATE_MAILFILES_DIALOG_H_ + +#include <kate/document.h> + +#include <kdialogbase.h> +#include <kurl.h> +#include <qptrlist.h> + +class QString; +class QStringList; +class KateMainWindow; + +/** + This is a dialog for choosing which of the open files to mail. + The current file is selected by default, the dialog can be expanded + to display all the files if required. + +*/ +class KateMailDialog : public KDialogBase { + Q_OBJECT + public: + KateMailDialog( QWidget *parent=0, + KateMainWindow *mainwin=0 ); + ~KateMailDialog() {}; + + /** + @return a list of the selected docs. + */ + QPtrList<Kate::Document> selectedDocs(); + private slots: + void slotShowButton(); + private: + class KListView *list; + class QLabel *lInfo; + KateMainWindow *mainWindow; + class QVBox *mw; + +}; + +#endif // _KATE_MAILFILES_DIALOG_H_ diff --git a/kate/app/katemain.cpp b/kate/app/katemain.cpp new file mode 100644 index 000000000..892f49271 --- /dev/null +++ b/kate/app/katemain.cpp @@ -0,0 +1,256 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kateapp.h" + +#include <kstandarddirs.h> +#include <klocale.h> +#include <kcmdlineargs.h> +#include <kaboutdata.h> +#include <kglobal.h> +#include <kconfig.h> +#include <kinstance.h> +#include <kstartupinfo.h> +#include <dcopclient.h> +#include <dcopref.h> +#include <kdebug.h> + +#include <qtextcodec.h> + +#include <stdlib.h> + +static KCmdLineOptions options[] = +{ + { "s", 0 , 0 }, + { "start <name>", I18N_NOOP("Start Kate with a given session"), 0 }, + { "u", 0, 0 }, + { "use", I18N_NOOP("Use a already running kate instance (if possible)"), 0 }, + { "p", 0, 0 }, + { "pid <pid>", I18N_NOOP("Only try to reuse kate instance with this pid"), 0 }, + { "e", 0, 0 }, + { "encoding <name>", I18N_NOOP("Set encoding for the file to open"), 0 }, + { "l", 0, 0 }, + { "line <line>", I18N_NOOP("Navigate to this line"), 0 }, + { "c", 0, 0 }, + { "column <column>", I18N_NOOP("Navigate to this column"), 0 }, + { "i", 0, 0 }, + { "stdin", I18N_NOOP("Read the contents of stdin"), 0 }, + { "+[URL]", I18N_NOOP("Document to open"), 0 }, + KCmdLineLastOption +}; + +extern "C" KDE_EXPORT int kdemain( int argc, char **argv ) +{ + // here we go, construct the Kate version + QString kateVersion = KateApp::kateVersion(); + + KAboutData aboutData ("kate", I18N_NOOP("Kate"), kateVersion.latin1(), + I18N_NOOP( "Kate - Advanced Text Editor" ), KAboutData::License_LGPL_V2, + I18N_NOOP( "(c) 2000-2005 The Kate Authors" ), 0, "http://kate.kde.org"); + + aboutData.addAuthor ("Christoph Cullmann", I18N_NOOP("Maintainer"), "cullmann@kde.org", "http://www.babylon2k.de"); + aboutData.addAuthor ("Anders Lund", I18N_NOOP("Core Developer"), "anders@alweb.dk", "http://www.alweb.dk"); + aboutData.addAuthor ("Joseph Wenninger", I18N_NOOP("Core Developer"), "jowenn@kde.org","http://stud3.tuwien.ac.at/~e9925371"); + aboutData.addAuthor ("Hamish Rodda",I18N_NOOP("Core Developer"), "rodda@kde.org"); + aboutData.addAuthor ("Waldo Bastian", I18N_NOOP( "The cool buffersystem" ), "bastian@kde.org" ); + aboutData.addAuthor ("Charles Samuels", I18N_NOOP("The Editing Commands"), "charles@kde.org"); + aboutData.addAuthor ("Matt Newell", I18N_NOOP("Testing, ..."), "newellm@proaxis.com"); + aboutData.addAuthor ("Michael Bartl", I18N_NOOP("Former Core Developer"), "michael.bartl1@chello.at"); + aboutData.addAuthor ("Michael McCallum", I18N_NOOP("Core Developer"), "gholam@xtra.co.nz"); + aboutData.addAuthor ("Jochen Wilhemly", I18N_NOOP( "KWrite Author" ), "digisnap@cs.tu-berlin.de" ); + aboutData.addAuthor ("Michael Koch",I18N_NOOP("KWrite port to KParts"), "koch@kde.org"); + aboutData.addAuthor ("Christian Gebauer", 0, "gebauer@kde.org" ); + aboutData.addAuthor ("Simon Hausmann", 0, "hausmann@kde.org" ); + aboutData.addAuthor ("Glen Parker",I18N_NOOP("KWrite Undo History, Kspell integration"), "glenebob@nwlink.com"); + aboutData.addAuthor ("Scott Manson",I18N_NOOP("KWrite XML Syntax highlighting support"), "sdmanson@alltel.net"); + aboutData.addAuthor ("John Firebaugh",I18N_NOOP("Patches and more"), "jfirebaugh@kde.org"); + aboutData.addAuthor ("Dominik Haumann", I18N_NOOP("Developer & Highlight wizard"), "dhdev@gmx.de"); + + aboutData.addCredit ("Matteo Merli",I18N_NOOP("Highlighting for RPM Spec-Files, Perl, Diff and more"), "merlim@libero.it"); + aboutData.addCredit ("Rocky Scaletta",I18N_NOOP("Highlighting for VHDL"), "rocky@purdue.edu"); + aboutData.addCredit ("Yury Lebedev",I18N_NOOP("Highlighting for SQL"),""); + aboutData.addCredit ("Chris Ross",I18N_NOOP("Highlighting for Ferite"),""); + aboutData.addCredit ("Nick Roux",I18N_NOOP("Highlighting for ILERPG"),""); + aboutData.addCredit ("Carsten Niehaus", I18N_NOOP("Highlighting for LaTeX"),""); + aboutData.addCredit ("Per Wigren", I18N_NOOP("Highlighting for Makefiles, Python"),""); + aboutData.addCredit ("Jan Fritz", I18N_NOOP("Highlighting for Python"),""); + aboutData.addCredit ("Daniel Naber","",""); + aboutData.addCredit ("Roland Pabel",I18N_NOOP("Highlighting for Scheme"),""); + aboutData.addCredit ("Cristi Dumitrescu",I18N_NOOP("PHP Keyword/Datatype list"),""); + aboutData.addCredit ("Carsten Pfeiffer", I18N_NOOP("Very nice help"), ""); + aboutData.addCredit (I18N_NOOP("All people who have contributed and I have forgotten to mention"),"",""); + + aboutData.setTranslator(I18N_NOOP2("NAME OF TRANSLATORS","Your names"), I18N_NOOP2("EMAIL OF TRANSLATORS","Your emails")); + + // command line args init and co + KCmdLineArgs::init (argc, argv, &aboutData); + KCmdLineArgs::addCmdLineOptions (options); + KCmdLineArgs::addTempFileOption(); + KateApp::addCmdLineOptions (); + + // get our command line args ;) + KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); + + // now, first try to contact running kate instance if needed + if ( args->isSet("use") || (::getenv("KATE_PID")!=0) ) + { + DCOPClient client; + client.attach (); + + // get all attached clients ;) + QCStringList allClients = client.registeredApplications(); + + // search for a kate app client, use the first found + QCString kateApp; + + if ( args->isSet("start") ) + { + for (unsigned int i=0; i < allClients.count(); i++) + { + if (allClients[i] == "kate" || allClients[i].left(5) == "kate-") + { + DCOPRef ref( allClients[i], "KateApplication" ); + QString s = ref.call( "session" ); + if ( QString(args->getOption("start")) == s ) + { + kateApp = allClients[i]; + break; + } + } + } + } + else if ( (args->isSet("pid")) || (::getenv("KATE_PID") !=0 ) ) + { + QCString tryApp; + if ( args->isSet("pid") ) + tryApp = args->getOption("pid"); + else + tryApp = ::getenv("KATE_PID"); + + if ( client.isApplicationRegistered( tryApp.prepend("kate-") ) ) + kateApp = tryApp; + } + else + { + for (unsigned int i=0; i < allClients.count(); ++i) + { + if (allClients[i] == "kate" || allClients[i].left(5) == "kate-") + { + kateApp = allClients[i]; + break; + } + } + } + + // found a matching kate client ;) + if (!kateApp.isEmpty()) + { + kdDebug () << "kate app: " << kateApp << endl; + // make kdeinit happy + client.registerAs( "kate" ); + + DCOPRef kRef (kateApp, "KateApplication"); + + if (args->isSet ("start")) + kRef.call( "activateSession", QString (args->getOption("start")) ); + + QString enc = args->isSet("encoding") ? args->getOption("encoding") : QCString(""); + + bool tempfileSet = KCmdLineArgs::isTempFileSet(); + + for (int z=0; z<args->count(); z++) + kRef.call( "openURL", args->url(z), enc, tempfileSet ); + + if( args->isSet( "stdin" ) ) + { + QTextIStream input(stdin); + + // set chosen codec + QTextCodec *codec = args->isSet("encoding") ? QTextCodec::codecForName(args->getOption("encoding")) : 0; + + if (codec) + input.setCodec (codec); + + QString line; + QString text; + + do + { + line = input.readLine(); + text.append( line + "\n" ); + } while( !line.isNull() ); + + kRef.call( "openInput", text ); + } + + int line = 0; + int column = 0; + bool nav = false; + + if (args->isSet ("line")) + { + line = args->getOption ("line").toInt(); + nav = true; + } + + if (args->isSet ("column")) + { + column = args->getOption ("column").toInt(); + nav = true; + } + + if (nav) + kRef.call( "setCursor", line, column ); + + // since the user tried to open a document, let us assume [s]he + // wants to see that document. + // ### what to do about the infamous focus stealing prevention? + uint mwn = kRef.call("activeMainWindowNumber"); + QCString smwn; + DCOPRef wRef( kateApp, QCString( "__KateMainWindow#") + smwn.setNum(mwn) ); + if ( wRef.call("minimized") ) + { + if ( wRef.call( "maximized" ) ) + wRef.call( "maximize" ); + else + wRef.call("restore"); + } + wRef.call( "raise" ); + + // stop startup notification + KStartupInfo::appStarted( ); + + return 0; + } + } + + // construct the real kate app object ;) + KateApp app (args); + + // app execution should already end :) + if (app.shouldExit()) + { + return 0; + } + + // execute ourself ;) + return app.exec(); +} + +// kate: space-indent on; indent-width 2; replace-tabs on; mixed-indent off; diff --git a/kate/app/katemain.h b/kate/app/katemain.h new file mode 100644 index 000000000..7d2f65da9 --- /dev/null +++ b/kate/app/katemain.h @@ -0,0 +1,70 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __KATE_MAIN_H__ +#define __KATE_MAIN_H__ + +#include <config.h> + +class QComboBox; +class QDateTime; +class QEvent; +class QFileInfo; +class QGridLayout; +class QLabel; +class QListBox; +class QObject; +class QPixmap; +class QVBoxLayout; +class QString; +class QWidgetStack; + +class KAction; +class KActionMenu; +class KConfig; +class KDirOperator; +class KEditToolbar; +class KFileViewItem; +class KHistoryCombo; +class KLineEdit; +class KListBox; +class KProcess; +class KPushButton; +class KRecentFilesAction; +class KSelectAction; +class KStatusBar; +class KToggleAction; +class KURL; +class KURLComboBox; + +class KateApp; +class KateConfigDlg; +class KateConsole; +class KateDocManager; +class KateFileList; +class KateFileSelector; +class KateMainWindow; +class KatePluginIface; +class KatePluginManager; +class KateSidebar; +class KateViewManager; +class KateViewSpace; + +#endif diff --git a/kate/app/katemainwindow.cpp b/kate/app/katemainwindow.cpp new file mode 100644 index 000000000..772f63339 --- /dev/null +++ b/kate/app/katemainwindow.cpp @@ -0,0 +1,854 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +//BEGIN Includes +#include "katemainwindow.h" +#include "katemainwindow.moc" + +#include "kateconfigdialog.h" +#include "kateconsole.h" +#include "katedocmanager.h" +#include "katepluginmanager.h" +#include "kateconfigplugindialogpage.h" +#include "kateviewmanager.h" +#include "kateapp.h" +#include "katefileselector.h" +#include "katefilelist.h" +#include "kategrepdialog.h" +#include "katemailfilesdialog.h" +#include "katemainwindowiface.h" +#include "kateexternaltools.h" +#include "katesavemodifieddialog.h" +#include "katemwmodonhddialog.h" +#include "katesession.h" +#include "katetabwidget.h" + +#include "../interfaces/mainwindow.h" +#include "../interfaces/toolviewmanager.h" + +#include <dcopclient.h> +#include <kinstance.h> +#include <kaboutdata.h> +#include <kaction.h> +#include <kcmdlineargs.h> +#include <kdebug.h> +#include <kdialogbase.h> +#include <kdiroperator.h> +#include <kdockwidget.h> +#include <kedittoolbar.h> +#include <kfiledialog.h> +#include <kglobalaccel.h> +#include <kglobal.h> +#include <kglobalsettings.h> +#include <kiconloader.h> +#include <kkeydialog.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kmimetype.h> +#include <kopenwith.h> +#include <kpopupmenu.h> +#include <ksimpleconfig.h> +#include <kstatusbar.h> +#include <kstdaction.h> +#include <kstandarddirs.h> +#include <ktrader.h> +#include <kuniqueapplication.h> +#include <kurldrag.h> +#include <kdesktopfile.h> +#include <khelpmenu.h> +#include <kmultitabbar.h> +#include <ktip.h> +#include <kmenubar.h> +#include <kstringhandler.h> +#include <qlayout.h> +#include <qptrvector.h> + +#include <assert.h> +#include <unistd.h> +//END + +uint KateMainWindow::uniqueID = 1; + +KateMainWindow::KateMainWindow (KConfig *sconfig, const QString &sgroup) + : KateMDI::MainWindow (0,(QString("__KateMainWindow#%1").arg(uniqueID)).latin1()) +{ + // first the very important id + myID = uniqueID; + uniqueID++; + + m_modignore = false; + + console = 0; + greptool = 0; + + // here we go, set some usable default sizes + if (!initialGeometrySet()) + { + int scnum = QApplication::desktop()->screenNumber(parentWidget()); + QRect desk = QApplication::desktop()->screenGeometry(scnum); + + QSize size; + + // try to load size + if (sconfig) + { + sconfig->setGroup (sgroup); + size.setWidth (sconfig->readNumEntry( QString::fromLatin1("Width %1").arg(desk.width()), 0 )); + size.setHeight (sconfig->readNumEntry( QString::fromLatin1("Height %1").arg(desk.height()), 0 )); + } + + // if thats fails, try to reuse size + if (size.isEmpty()) + { + // first try to reuse size known from current or last created main window ;=) + if (KateApp::self()->mainWindows () > 0) + { + KateMainWindow *win = KateApp::self()->activeMainWindow (); + + if (!win) + win = KateApp::self()->mainWindow (KateApp::self()->mainWindows ()-1); + + size = win->size(); + } + else // now fallback to hard defaults ;) + { + // first try global app config + KateApp::self()->config()->setGroup ("MainWindow"); + size.setWidth (KateApp::self()->config()->readNumEntry( QString::fromLatin1("Width %1").arg(desk.width()), 0 )); + size.setHeight (KateApp::self()->config()->readNumEntry( QString::fromLatin1("Height %1").arg(desk.height()), 0 )); + + if (size.isEmpty()) + size = QSize (kMin (700, desk.width()), kMin(480, desk.height())); + } + + resize (size); + } + } + + // start session restore if needed + startRestore (sconfig, sgroup); + + m_mainWindow = new Kate::MainWindow (this); + m_toolViewManager = new Kate::ToolViewManager (this); + + m_dcop = new KateMainWindowDCOPIface (this); + + // setup the most important widgets + setupMainWindow(); + + // setup the actions + setupActions(); + + setStandardToolBarMenuEnabled( true ); + setXMLFile( "kateui.rc" ); + createShellGUI ( true ); + + KatePluginManager::self()->enableAllPluginsGUI (this); + + if ( KateApp::self()->authorize("shell_access") ) + Kate::Document::registerCommand(KateExternalToolsCommand::self()); + + // connect documents menu aboutToshow + documentMenu = (QPopupMenu*)factory()->container("documents", this); + connect(documentMenu, SIGNAL(aboutToShow()), this, SLOT(documentMenuAboutToShow())); + + // caption update + for (uint i = 0; i < KateDocManager::self()->documents(); i++) + slotDocumentCreated (KateDocManager::self()->document(i)); + + connect(KateDocManager::self(),SIGNAL(documentCreated(Kate::Document *)),this,SLOT(slotDocumentCreated(Kate::Document *))); + + readOptions(); + + if (sconfig) + m_viewManager->restoreViewConfiguration (sconfig, sgroup); + + finishRestore (); + + setAcceptDrops(true); +} + +KateMainWindow::~KateMainWindow() +{ + // first, save our fallback window size ;) + KateApp::self()->config()->setGroup ("MainWindow"); + saveWindowSize (KateApp::self()->config()); + + // save other options ;=) + saveOptions(); + + KateApp::self()->removeMainWindow (this); + + KatePluginManager::self()->disableAllPluginsGUI (this); + + delete m_dcop; +} + +void KateMainWindow::setupMainWindow () +{ + setToolViewStyle( KMultiTabBar::KDEV3ICON ); + + m_tabWidget = new KateTabWidget (centralWidget()); + + m_viewManager = new KateViewManager (this); + + KateMDI::ToolView *ft = createToolView("kate_filelist", KMultiTabBar::Left, SmallIcon("kmultiple"), i18n("Documents")); + filelist = new KateFileList (this, m_viewManager, ft, "filelist"); + filelist->readConfig(KateApp::self()->config(), "Filelist"); + + KateMDI::ToolView *t = createToolView("kate_fileselector", KMultiTabBar::Left, SmallIcon("fileopen"), i18n("Filesystem Browser")); + fileselector = new KateFileSelector( this, m_viewManager, t, "operator"); + connect(fileselector->dirOperator(),SIGNAL(fileSelected(const KFileItem*)),this,SLOT(fileSelected(const KFileItem*))); + + // ONLY ALLOW SHELL ACCESS IF ALLOWED ;) + if (KateApp::self()->authorize("shell_access")) + { + t = createToolView("kate_greptool", KMultiTabBar::Bottom, SmallIcon("filefind"), i18n("Find in Files") ); + greptool = new GrepTool( t, "greptool" ); + connect(greptool, SIGNAL(itemSelected(const QString &,int)), this, SLOT(slotGrepToolItemSelected(const QString &,int))); + connect(t,SIGNAL(visibleChanged(bool)),this, SLOT(updateGrepDir (bool))); + // WARNING HACK - anders: showing the greptool seems to make the menu accels work + greptool->show(); + + t = createToolView("kate_console", KMultiTabBar::Bottom, SmallIcon("konsole"), i18n("Terminal")); + console = new KateConsole (this, t); + } + + // make per default the filelist visible, if we are in session restore, katemdi will skip this ;) + showToolView (ft); +} + +void KateMainWindow::setupActions() +{ + KAction *a; + + KStdAction::openNew( m_viewManager, SLOT( slotDocumentNew() ), actionCollection(), "file_new" )->setWhatsThis(i18n("Create a new document")); + KStdAction::open( m_viewManager, SLOT( slotDocumentOpen() ), actionCollection(), "file_open" )->setWhatsThis(i18n("Open an existing document for editing")); + + fileOpenRecent = KStdAction::openRecent (m_viewManager, SLOT(openURL (const KURL&)), actionCollection()); + fileOpenRecent->setWhatsThis(i18n("This lists files which you have opened recently, and allows you to easily open them again.")); + + a=new KAction( i18n("Save A&ll"),"save_all", CTRL+Key_L, KateDocManager::self(), SLOT( saveAll() ), actionCollection(), "file_save_all" ); + a->setWhatsThis(i18n("Save all open, modified documents to disk.")); + + KStdAction::close( m_viewManager, SLOT( slotDocumentClose() ), actionCollection(), "file_close" )->setWhatsThis(i18n("Close the current document.")); + + a=new KAction( i18n( "Clos&e All" ), 0, this, SLOT( slotDocumentCloseAll() ), actionCollection(), "file_close_all" ); + a->setWhatsThis(i18n("Close all open documents.")); + + KStdAction::mail( this, SLOT(slotMail()), actionCollection() )->setWhatsThis(i18n("Send one or more of the open documents as email attachments.")); + + KStdAction::quit( this, SLOT( slotFileQuit() ), actionCollection(), "file_quit" )->setWhatsThis(i18n("Close this window")); + + a=new KAction(i18n("&New Window"), "window_new", 0, this, SLOT(newWindow()), actionCollection(), "view_new_view"); + a->setWhatsThis(i18n("Create a new Kate view (a new window with the same document list).")); + + if ( KateApp::self()->authorize("shell_access") ) + { + externalTools = new KateExternalToolsMenuAction( i18n("External Tools"), actionCollection(), "tools_external", this ); + externalTools->setWhatsThis( i18n("Launch external helper applications") ); + } + + KToggleAction* showFullScreenAction = KStdAction::fullScreen( 0, 0, actionCollection(),this); + connect( showFullScreenAction,SIGNAL(toggled(bool)), this,SLOT(slotFullScreen(bool))); + + documentOpenWith = new KActionMenu(i18n("Open W&ith"), actionCollection(), "file_open_with"); + documentOpenWith->setWhatsThis(i18n("Open the current document using another application registered for its file type, or an application of your choice.")); + connect(documentOpenWith->popupMenu(), SIGNAL(aboutToShow()), this, SLOT(mSlotFixOpenWithMenu())); + connect(documentOpenWith->popupMenu(), SIGNAL(activated(int)), this, SLOT(slotOpenWithMenuAction(int))); + + a=KStdAction::keyBindings(this, SLOT(editKeys()), actionCollection()); + a->setWhatsThis(i18n("Configure the application's keyboard shortcut assignments.")); + + a=KStdAction::configureToolbars(this, SLOT(slotEditToolbars()), actionCollection()); + a->setWhatsThis(i18n("Configure which items should appear in the toolbar(s).")); + + KAction* settingsConfigure = KStdAction::preferences(this, SLOT(slotConfigure()), actionCollection(), "settings_configure"); + settingsConfigure->setWhatsThis(i18n("Configure various aspects of this application and the editing component.")); + + // pipe to terminal action + if (KateApp::self()->authorize("shell_access")) + new KAction(i18n("&Pipe to Console"), "pipe", 0, console, SLOT(slotPipeToConsole()), actionCollection(), "tools_pipe_to_terminal"); + + // tip of the day :-) + KStdAction::tipOfDay( this, SLOT( tipOfTheDay() ), actionCollection() )->setWhatsThis(i18n("This shows useful tips on the use of this application.")); + + if (KatePluginManager::self()->pluginList().count() > 0) + { + a=new KAction(i18n("&Plugins Handbook"), 0, this, SLOT(pluginHelp()), actionCollection(), "help_plugins_contents"); + a->setWhatsThis(i18n("This shows help files for various available plugins.")); + } + + connect(m_viewManager,SIGNAL(viewChanged()),this,SLOT(slotWindowActivated())); + connect(m_viewManager,SIGNAL(viewChanged()),this,SLOT(slotUpdateOpenWith())); + + slotWindowActivated (); + + // session actions + new KAction(i18n("Menu entry Session->New", "&New"), "filenew", 0, KateSessionManager::self(), SLOT(sessionNew()), actionCollection(), "sessions_new"); + new KAction(i18n("&Open..."), "fileopen", 0, KateSessionManager::self(), SLOT(sessionOpen()), actionCollection(), "sessions_open"); + new KAction(i18n("&Save"), "filesave", 0, KateSessionManager::self(), SLOT(sessionSave()), actionCollection(), "sessions_save"); + new KAction(i18n("Save &As..."), "filesaveas", 0, KateSessionManager::self(), SLOT(sessionSaveAs()), actionCollection(), "sessions_save_as"); + new KAction(i18n("&Manage..."), "view_choose", 0, KateSessionManager::self(), SLOT(sessionManage()), actionCollection(), "sessions_manage"); + + // quick open menu ;) + new KateSessionsAction (i18n("&Quick Open"), actionCollection(), "sessions_list"); +} + +KateTabWidget *KateMainWindow::tabWidget () +{ + return m_tabWidget; +} + +void KateMainWindow::slotDocumentCloseAll() { + if (queryClose_internal()) + KateDocManager::self()->closeAllDocuments(false); +} + +bool KateMainWindow::queryClose_internal() { + uint documentCount=KateDocManager::self()->documents(); + + if ( ! showModOnDiskPrompt() ) + return false; + + QPtrList<Kate::Document> modifiedDocuments=KateDocManager::self()->modifiedDocumentList(); + bool shutdown=(modifiedDocuments.count()==0); + + if (!shutdown) { + shutdown=KateSaveModifiedDialog::queryClose(this,modifiedDocuments); + } + + if ( KateDocManager::self()->documents() > documentCount ) { + KMessageBox::information (this, + i18n ("New file opened while trying to close Kate, closing aborted."), + i18n ("Closing Aborted")); + shutdown=false; + } + + return shutdown; +} + +/** + * queryClose(), take care that after the last mainwindow the stuff is closed + */ +bool KateMainWindow::queryClose() +{ + // session saving, can we close all views ? + // just test, not close them actually + if (KateApp::self()->sessionSaving()) + { + return queryClose_internal (); + } + + // normal closing of window + // allow to close all windows until the last without restrictions + if ( KateApp::self()->mainWindows () > 1 ) + return true; + + // last one: check if we can close all documents, try run + // and save docs if we really close down ! + if ( queryClose_internal () ) + { + KateApp::self()->sessionManager()->saveActiveSession(true, true); + + // detach the dcopClient + KateApp::self()->dcopClient()->detach(); + + return true; + } + + return false; +} + +void KateMainWindow::newWindow () +{ + KateApp::self()->newMainWindow (); +} + +void KateMainWindow::slotEditToolbars() +{ + saveMainWindowSettings( KateApp::self()->config(), "MainWindow" ); + KEditToolbar dlg( factory() ); + connect( &dlg, SIGNAL(newToolbarConfig()), this, SLOT(slotNewToolbarConfig()) ); + dlg.exec(); +} + +void KateMainWindow::slotNewToolbarConfig() +{ + applyMainWindowSettings( KateApp::self()->config(), "MainWindow" ); +} + +void KateMainWindow::slotFileQuit() +{ + KateApp::self()->shutdownKate (this); +} + +void KateMainWindow::readOptions () +{ + KConfig *config = KateApp::self()->config (); + + config->setGroup("General"); + syncKonsole = config->readBoolEntry("Sync Konsole", true); + modNotification = config->readBoolEntry("Modified Notification", false); + KateDocManager::self()->setSaveMetaInfos(config->readBoolEntry("Save Meta Infos", true)); + KateDocManager::self()->setDaysMetaInfos(config->readNumEntry("Days Meta Infos", 30)); + + m_viewManager->setShowFullPath(config->readBoolEntry("Show Full Path in Title", false)); + + fileOpenRecent->loadEntries(config, "Recent Files"); + + fileselector->readConfig(config, "fileselector"); +} + +void KateMainWindow::saveOptions () +{ + KConfig *config = KateApp::self()->config (); + + config->setGroup("General"); + + if (console) + config->writeEntry("Show Console", console->isVisible()); + else + config->writeEntry("Show Console", false); + + config->writeEntry("Save Meta Infos", KateDocManager::self()->getSaveMetaInfos()); + + config->writeEntry("Days Meta Infos", KateDocManager::self()->getDaysMetaInfos()); + + config->writeEntry("Show Full Path in Title", m_viewManager->getShowFullPath()); + + config->writeEntry("Sync Konsole", syncKonsole); + + fileOpenRecent->saveEntries(config, "Recent Files"); + + fileselector->writeConfig(config, "fileselector"); + + filelist->writeConfig(config, "Filelist"); +} + +void KateMainWindow::slotWindowActivated () +{ + if (m_viewManager->activeView()) + { + if (console && syncKonsole) + { + static QString path; + QString newPath = m_viewManager->activeView()->getDoc()->url().directory(); + + if ( newPath != path ) + { + path = newPath; + console->cd (KURL( path )); + } + } + + updateCaption (m_viewManager->activeView()->getDoc()); + } + + // update proxy + centralWidget()->setFocusProxy (m_viewManager->activeView()); +} + +void KateMainWindow::slotUpdateOpenWith() +{ + if (m_viewManager->activeView()) + documentOpenWith->setEnabled(!m_viewManager->activeView()->document()->url().isEmpty()); + else + documentOpenWith->setEnabled(false); +} + +void KateMainWindow::documentMenuAboutToShow() +{ + // remove documents + while (documentMenu->count() > 3) + documentMenu->removeItemAt (3); + + QListViewItem * item = filelist->firstChild(); + while( item ) { + // would it be saner to use the screen width as a limit that some random number?? + QString name = KStringHandler::rsqueeze( ((KateFileListItem *)item)->document()->docName(), 150 ); + Kate::Document* doc = ((KateFileListItem *)item)->document(); + documentMenu->insertItem ( + doc->isModified() ? i18n("'document name [*]', [*] means modified", "%1 [*]").arg(name) : name, + m_viewManager, SLOT (activateView (int)), 0, + ((KateFileListItem *)item)->documentNumber () ); + + item = item->nextSibling(); + } + if (m_viewManager->activeView()) + documentMenu->setItemChecked ( m_viewManager->activeView()->getDoc()->documentNumber(), true); +} + +void KateMainWindow::slotGrepToolItemSelected(const QString &filename,int linenumber) +{ + KURL fileURL; + fileURL.setPath( filename ); + m_viewManager->openURL( fileURL ); + if ( m_viewManager->activeView() == 0 ) return; + m_viewManager->activeView()->gotoLineNumber( linenumber ); + raise(); + setActiveWindow(); +} + +void KateMainWindow::dragEnterEvent( QDragEnterEvent *event ) +{ + event->accept(KURLDrag::canDecode(event)); +} + +void KateMainWindow::dropEvent( QDropEvent *event ) +{ + slotDropEvent(event); +} + +void KateMainWindow::slotDropEvent( QDropEvent * event ) +{ + KURL::List textlist; + if (!KURLDrag::decode(event, textlist)) return; + + for (KURL::List::Iterator i=textlist.begin(); i != textlist.end(); ++i) + { + m_viewManager->openURL (*i); + } +} + +void KateMainWindow::editKeys() +{ + 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.insert( externalTools->actionCollection(), i18n("External Tools") ); + + dlg.configure(); + + QPtrList<Kate::Document> l=KateDocManager::self()->documentList(); + for (uint i=0;i<l.count();i++) { +// kdDebug(13001)<<"reloading Keysettings for document "<<i<<endl; + l.at(i)->reloadXML(); + QPtrList<class KTextEditor::View> l1=l.at(i)->views ();//KTextEditor::Document + for (uint i1=0;i1<l1.count();i1++) { + l1.at(i1)->reloadXML(); +// kdDebug(13001)<<"reloading Keysettings for view "<<i<<"/"<<i1<<endl; + } + } + + externalTools->actionCollection()->writeShortcutSettings( "Shortcuts", new KConfig("externaltools", false, false, "appdata") ); +} + +void KateMainWindow::openURL (const QString &name) +{ + m_viewManager->openURL (KURL(name)); +} + +void KateMainWindow::slotConfigure() +{ + if (!m_viewManager->activeView()) + return; + + KateConfigDialog* dlg = new KateConfigDialog (this, m_viewManager->activeView()); + dlg->exec(); + + delete dlg; +} + +KURL KateMainWindow::activeDocumentUrl() +{ + // anders: i make this one safe, as it may be called during + // startup (by the file selector) + Kate::View *v = m_viewManager->activeView(); + if ( v ) + return v->getDoc()->url(); + return KURL(); +} + +void KateMainWindow::fileSelected(const KFileItem * /*file*/) +{ + const KFileItemList *list=fileselector->dirOperator()->selectedItems(); + KFileItem *tmp; + for (KFileItemListIterator it(*list); (tmp = it.current()); ++it) + { + m_viewManager->openURL(tmp->url()); + fileselector->dirOperator()->view()->setSelected(tmp,false); + } +} + +// TODO make this work +void KateMainWindow::mSlotFixOpenWithMenu() +{ + //kdDebug(13001)<<"13000"<<"fixing open with menu"<<endl; + documentOpenWith->popupMenu()->clear(); + // get a list of appropriate services. + KMimeType::Ptr mime = KMimeType::findByURL( m_viewManager->activeView()->getDoc()->url() ); + //kdDebug(13001)<<"13000"<<"url: "<<m_viewManager->activeView()->getDoc()->url().prettyURL()<<"mime type: "<<mime->name()<<endl; + // some checking goes here... + KTrader::OfferList offers = KTrader::self()->query(mime->name(), "Type == 'Application'"); + // for each one, insert a menu item... + for(KTrader::OfferList::Iterator it = offers.begin(); it != offers.end(); ++it) { + if ((*it)->name() == "Kate") continue; + documentOpenWith->popupMenu()->insertItem( SmallIcon( (*it)->icon() ), (*it)->name() ); + } + // append "Other..." to call the KDE "open with" dialog. + documentOpenWith->popupMenu()->insertItem(i18n("&Other...")); +} + +void KateMainWindow::slotOpenWithMenuAction(int idx) +{ + KURL::List list; + list.append( m_viewManager->activeView()->getDoc()->url() ); + QString appname = documentOpenWith->popupMenu()->text(idx); + + appname = appname.remove('&'); //Remove a possible accelerator ... otherwise the application might not get found. + if ( appname.compare(i18n("Other...")) == 0 ) { + // display "open with" dialog + KOpenWithDlg dlg(list); + if (dlg.exec()) + KRun::run(*dlg.service(), list); + return; + } + + QString qry = QString("((Type == 'Application') and (Name == '%1'))").arg( appname.latin1() ); + KMimeType::Ptr mime = KMimeType::findByURL( m_viewManager->activeView()->getDoc()->url() ); + KTrader::OfferList offers = KTrader::self()->query(mime->name(), qry); + + if (!offers.isEmpty()) { + KService::Ptr app = offers.first(); + KRun::run(*app, list); + } + else + KMessageBox::error(this, i18n("Application '%1' not found!").arg(appname.latin1()), i18n("Application Not Found!")); +} + +void KateMainWindow::pluginHelp() +{ + KateApp::self()->invokeHelp (QString::null, "kate-plugins"); +} + +void KateMainWindow::slotMail() +{ + KateMailDialog *d = new KateMailDialog(this, this); + if ( ! d->exec() ) + { + delete d; + return; + } + QPtrList<Kate::Document> attDocs = d->selectedDocs(); + delete d; + // Check that all selected files are saved (or shouldn't be) + QStringList urls; // to atthatch + Kate::Document *doc; + QPtrListIterator<Kate::Document> it(attDocs); + for ( ; it.current(); ++it ) { + doc = it.current(); + if (!doc) continue; + if ( doc->url().isEmpty() ) { + // unsaved document. back out unless it gets saved + int r = KMessageBox::questionYesNo( this, + i18n("<p>The current document has not been saved, and " + "cannot be attached to an email message." + "<p>Do you want to save it and proceed?"), + i18n("Cannot Send Unsaved File"),KStdGuiItem::saveAs(),KStdGuiItem::cancel() ); + if ( r == KMessageBox::Yes ) { + Kate::View *v = (Kate::View*)doc->views().first(); + int sr = v->saveAs(); + if ( sr == Kate::View::SAVE_OK ) { ; + } + else { + if ( sr != Kate::View::SAVE_CANCEL ) // ERROR or RETRY(?) + KMessageBox::sorry( this, i18n("The file could not be saved. Please check " + "if you have write permission.") ); + continue; + } + } + else + continue; + } + if ( doc->isModified() ) { + // warn that document is modified and offer to save it before proceeding. + int r = KMessageBox::warningYesNoCancel( this, + i18n("<p>The current file:<br><strong>%1</strong><br>has been " + "modified. Modifications will not be available in the attachment." + "<p>Do you want to save it before sending it?").arg(doc->url().prettyURL()), + i18n("Save Before Sending?"), KStdGuiItem::save(), i18n("Do Not Save") ); + switch ( r ) { + case KMessageBox::Cancel: + continue; + case KMessageBox::Yes: + doc->save(); + if ( doc->isModified() ) { // read-only docs ends here, if modified. Hmm. + KMessageBox::sorry( this, i18n("The file could not be saved. Please check " + "if you have write permission.") ); + continue; + } + break; + default: + break; + } + } + // finally call the mailer + urls << doc->url().url(); + } // check selected docs done + if ( ! urls.count() ) + return; + KateApp::self()->invokeMailer( QString::null, // to + QString::null, // cc + QString::null, // bcc + QString::null, // subject + QString::null, // body + QString::null, // msgfile + urls // urls to atthatch + ); +} +void KateMainWindow::tipOfTheDay() +{ + KTipDialog::showTip( /*0*/this, QString::null, true ); +} + +void KateMainWindow::slotFullScreen(bool t) +{ + if (t) + showFullScreen(); + else + showNormal(); +} + +void KateMainWindow::updateGrepDir (bool visible) +{ + // grepdlg gets hidden + if (!visible) + return; + + if ( m_viewManager->activeView() ) + { + if ( m_viewManager->activeView()->getDoc()->url().isLocalFile() ) + { + greptool->updateDirName( m_viewManager->activeView()->getDoc()->url().directory() ); + } + } +} + +bool KateMainWindow::event( QEvent *e ) +{ + uint type = e->type(); + if ( type == QEvent::WindowActivate && modNotification ) + { + showModOnDiskPrompt(); + } + return KateMDI::MainWindow::event( e ); +} + +bool KateMainWindow::showModOnDiskPrompt() +{ + Kate::Document *doc; + + DocVector list( KateDocManager::self()->documents() ); + uint cnt = 0; + for( doc = KateDocManager::self()->firstDocument(); doc; doc = KateDocManager::self()->nextDocument() ) + { + if ( KateDocManager::self()->documentInfo( doc )->modifiedOnDisc ) + { + list.insert( cnt, doc ); + cnt++; + } + } + + if ( cnt && !m_modignore ) + { + list.resize( cnt ); + KateMwModOnHdDialog mhdlg( list, this ); + m_modignore = true; + bool res = mhdlg.exec(); + m_modignore = false; + + return res; + } + return true; +} + +void KateMainWindow::slotDocumentCreated (Kate::Document *doc) +{ + connect(doc,SIGNAL(modStateChanged(Kate::Document *)),this,SLOT(updateCaption(Kate::Document *))); + connect(doc,SIGNAL(nameChanged(Kate::Document *)),this,SLOT(updateCaption(Kate::Document *))); + connect(doc,SIGNAL(nameChanged(Kate::Document *)),this,SLOT(slotUpdateOpenWith())); + + updateCaption (doc); +} + +void KateMainWindow::updateCaption (Kate::Document *doc) +{ + if (!m_viewManager->activeView()) + { + setCaption ("", false); + return; + } + + if (!(m_viewManager->activeView()->getDoc() == doc)) + return; + + QString c; + if (m_viewManager->activeView()->getDoc()->url().isEmpty() || (!m_viewManager->getShowFullPath())) + { + c = m_viewManager->activeView()->getDoc()->docName(); + } + else + { + c = m_viewManager->activeView()->getDoc()->url().prettyURL(); + } + + QString sessName = KateApp::self()->sessionManager()->activeSession()->sessionName(); + if ( !sessName.isEmpty() ) + sessName = QString("%1: ").arg( sessName ); + + setCaption( sessName + KStringHandler::lsqueeze(c,64), + m_viewManager->activeView()->getDoc()->isModified()); +} + +void KateMainWindow::saveProperties(KConfig *config) +{ + QString grp=config->group(); + + saveSession(config, grp); + m_viewManager->saveViewConfiguration (config, grp); + + config->setGroup(grp); +} + +void KateMainWindow::readProperties(KConfig *config) +{ + QString grp=config->group(); + + startRestore(config, grp); + finishRestore (); + m_viewManager->restoreViewConfiguration (config, grp); + + config->setGroup(grp); +} + +void KateMainWindow::saveGlobalProperties( KConfig* sessionConfig ) +{ + KateDocManager::self()->saveDocumentList (sessionConfig); + + sessionConfig->setGroup("General"); + sessionConfig->writeEntry ("Last Session", KateApp::self()->sessionManager()->activeSession()->sessionFileRelative()); +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kate/app/katemainwindow.h b/kate/app/katemainwindow.h new file mode 100644 index 000000000..d5a67f65b --- /dev/null +++ b/kate/app/katemainwindow.h @@ -0,0 +1,216 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __KATE_MAINWINDOW_H__ +#define __KATE_MAINWINDOW_H__ + +#include "katemain.h" +#include "katemdi.h" + +#include <kate/view.h> +#include <kate/document.h> + +#include <kparts/part.h> + +#include <kaction.h> + +class KateTabWidget; +class GrepTool; + +namespace Kate { + class MainWindow; + class ToolViewManager; +} + +class KFileItem; +class KRecentFilesAction; +class DCOPObject; + +class KateExternalToolsMenuAction; + +class KateMainWindow : public KateMDI::MainWindow, virtual public KParts::PartBase +{ + Q_OBJECT + + friend class KateConfigDialog; + friend class KateViewManager; + + public: + /** + * Construct the window and restore it's state from given config if any + * @param sconfig session config for this window, 0 if none + * @param sgroup session config group to use + */ + KateMainWindow (KConfig *sconfig, const QString &sgroup); + + /** + * Destruct the nice window + */ + ~KateMainWindow(); + + /** + * Accessor methodes for interface and child objects + */ + public: + Kate::MainWindow *mainWindow () { return m_mainWindow; } + Kate::ToolViewManager *toolViewManager () { return m_toolViewManager; } + + KateViewManager *viewManager () { return m_viewManager; } + + DCOPObject *dcopObject () { return m_dcop; } + + /** + * various methodes to get some little info out of this + */ + public: + /** Returns the URL of the current document. + * anders: I add this for use from the file selector. */ + KURL activeDocumentUrl(); + + uint mainWindowNumber () const { return myID; } + + /** + * Prompts the user for what to do with files that are modified on disk if any. + * This is optionally run when the window receives focus, and when the last + * window is closed. + * @return true if no documents are modified on disk, or all documents were + * handled by the dialog; otherwise (the dialog was canceled) false. + */ + bool showModOnDiskPrompt(); + + /** + * central tabwidget ;) + * @return tab widget + */ + KateTabWidget *tabWidget (); + + public: + void readProperties(KConfig *config); + void saveProperties(KConfig *config); + void saveGlobalProperties( KConfig* sessionConfig ); + + public: + bool queryClose_internal(); + + private: + void setupMainWindow(); + void setupActions(); + bool queryClose(); + + /** + * read some global options from katerc + */ + void readOptions(); + + /** + * save some global options to katerc + */ + void saveOptions(); + + void dragEnterEvent( QDragEnterEvent * ); + void dropEvent( QDropEvent * ); + + /** + * slots used for actions in the menus/toolbars + * or internal signal connections + */ + private slots: + void newWindow (); + + void slotConfigure(); + + void slotOpenWithMenuAction(int idx); + + void slotGrepToolItemSelected ( const QString &filename, int linenumber ); + void slotMail(); + + void slotFileQuit(); + void slotEditToolbars(); + void slotNewToolbarConfig(); + void slotWindowActivated (); + void slotUpdateOpenWith(); + void documentMenuAboutToShow(); + void slotDropEvent(QDropEvent *); + void editKeys(); + void mSlotFixOpenWithMenu(); + + void fileSelected(const KFileItem *file); + + void tipOfTheDay(); + + /* to update the caption */ + void slotDocumentCreated (Kate::Document *doc); + void updateCaption (Kate::Document *doc); + + void pluginHelp (); + void slotFullScreen(bool); + + public: + void openURL (const QString &name=0L); + + private slots: + void updateGrepDir (bool visible); + + protected: + bool event( QEvent * ); + + private slots: + void slotDocumentCloseAll(); + + private: + static uint uniqueID; + uint myID; + + Kate::MainWindow *m_mainWindow; + Kate::ToolViewManager *m_toolViewManager; + + bool syncKonsole; + bool modNotification; + + DCOPObject *m_dcop; + + // console + KateConsole *console; + + // management items + KateViewManager *m_viewManager; + + KRecentFilesAction *fileOpenRecent; + + KateFileList *filelist; + KateFileSelector *fileselector; + + KActionMenu* documentOpenWith; + + QPopupMenu *documentMenu; + + KToggleAction* settingsShowFilelist; + KToggleAction* settingsShowFileselector; + + KateExternalToolsMenuAction *externalTools; + GrepTool * greptool; + bool m_modignore, m_grrr; + + KateTabWidget *m_tabWidget; +}; + +#endif + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kate/app/katemainwindowiface.cpp b/kate/app/katemainwindowiface.cpp new file mode 100644 index 000000000..9a748ffc9 --- /dev/null +++ b/kate/app/katemainwindowiface.cpp @@ -0,0 +1,27 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Ian Reinhart Geiser <geiseri@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "katemainwindowiface.h" + +#include "katemainwindow.h" + +#include <kdebug.h> + +KateMainWindowDCOPIface::KateMainWindowDCOPIface (KateMainWindow *w) : DCOPObject ((QString("KateMainWindow#%1").arg(w->mainWindowNumber())).latin1()), m_w (w) +{ +} diff --git a/kate/app/katemainwindowiface.h b/kate/app/katemainwindowiface.h new file mode 100644 index 000000000..3292d1b15 --- /dev/null +++ b/kate/app/katemainwindowiface.h @@ -0,0 +1,41 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Ian Reinhart Geiser <geiseri@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _katemainwindow_Iface_h_ +#define _katemainwindow_Iface_h_ + +#include <dcopobject.h> +#include <dcopref.h> + +#include <kurl.h> + +class KateMainWindow; + +class KateMainWindowDCOPIface : public DCOPObject +{ + K_DCOP + + public: + KateMainWindowDCOPIface (KateMainWindow *w); + + k_dcop: + + private: + KateMainWindow *m_w; +}; +#endif diff --git a/kate/app/katemdi.cpp b/kate/app/katemdi.cpp new file mode 100644 index 000000000..fbe9be1e1 --- /dev/null +++ b/kate/app/katemdi.cpp @@ -0,0 +1,969 @@ +/* This file is part of the KDE libraries + Copyright (C) 2005 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2002, 2003 Joseph Wenninger <jowenn@kde.org> + + GUIClient partly based on ktoolbarhandler.cpp: Copyright (C) 2002 Simon Hausmann <hausmann@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "katemdi.h" +#include "katemdi.moc" + +#include <kaction.h> +#include <kdebug.h> +#include <kglobal.h> +#include <kglobalsettings.h> +#include <kapplication.h> +#include <klocale.h> +#include <kconfig.h> +#include <kiconloader.h> +#include <kpopupmenu.h> +#include <kmessagebox.h> + +#include <qvbox.h> +#include <qhbox.h> +#include <qevent.h> + +namespace KateMDI { + +//BEGIN SPLITTER + +Splitter::Splitter(Orientation o, QWidget* parent, const char* name) + : QSplitter(o, parent, name) +{ +} + +Splitter::~Splitter() +{ +} + +bool Splitter::isLastChild(QWidget* w) const +{ + return ( idAfter( w ) == 0 ); +} + +int Splitter::idAfter ( QWidget * w ) const +{ + return QSplitter::idAfter (w); +} + +//END SPLITTER + + +//BEGIN TOGGLETOOLVIEWACTION + +ToggleToolViewAction::ToggleToolViewAction ( const QString& text, const KShortcut& cut, ToolView *tv, + QObject* parent, const char* name ) + : KToggleAction(text,cut,parent,name) + , m_tv(tv) +{ + connect(this,SIGNAL(toggled(bool)),this,SLOT(slotToggled(bool))); + connect(m_tv,SIGNAL(visibleChanged(bool)),this,SLOT(visibleChanged(bool))); + + setChecked(m_tv->visible()); +} + +ToggleToolViewAction::~ToggleToolViewAction() +{ + unplugAll(); +} + +void ToggleToolViewAction::visibleChanged(bool) +{ + if (isChecked() != m_tv->visible()) + setChecked (m_tv->visible()); +} + +void ToggleToolViewAction::slotToggled(bool t) +{ + if (t) + { + m_tv->mainWindow()->showToolView (m_tv); + m_tv->setFocus (); + } + else + { + m_tv->mainWindow()->hideToolView (m_tv); + m_tv->mainWindow()->centralWidget()->setFocus (); + } +} + +//END TOGGLETOOLVIEWACTION + + +//BEGIN GUICLIENT + +static const char *actionListName = "kate_mdi_window_actions"; + +static const char *guiDescription = "" + "<!DOCTYPE kpartgui><kpartgui name=\"kate_mdi_window_actions\">" + "<MenuBar>" + " <Menu name=\"window\">" + " <ActionList name=\"%1\" />" + " </Menu>" + "</MenuBar>" + "</kpartgui>"; + +GUIClient::GUIClient ( MainWindow *mw ) + : QObject ( mw ) + , KXMLGUIClient ( mw ) + , m_mw (mw) +{ + connect( m_mw->guiFactory(), SIGNAL( clientAdded( KXMLGUIClient * ) ), + this, SLOT( clientAdded( KXMLGUIClient * ) ) ); + + if ( domDocument().documentElement().isNull() ) + { + QString completeDescription = QString::fromLatin1( guiDescription ) + .arg( actionListName ); + + setXML( completeDescription, false /*merge*/ ); + } + + if (actionCollection()->kaccel()==0) + actionCollection()->setWidget(m_mw); + + m_toolMenu = new KActionMenu(i18n("Tool &Views"),actionCollection(),"kate_mdi_toolview_menu"); + m_showSidebarsAction = new KToggleAction( i18n("Show Side&bars"), + CTRL|ALT|SHIFT|Key_F, actionCollection(), "kate_mdi_sidebar_visibility" ); + m_showSidebarsAction->setCheckedState(i18n("Hide Side&bars")); + m_showSidebarsAction->setChecked( m_mw->sidebarsVisible() ); + connect( m_showSidebarsAction, SIGNAL( toggled( bool ) ), + m_mw, SLOT( setSidebarsVisible( bool ) ) ); + + m_toolMenu->insert( m_showSidebarsAction ); + m_toolMenu->insert( new KActionSeparator( m_toolMenu ) ); + + // read shortcuts + actionCollection()->readShortcutSettings( "Shortcuts", kapp->config() ); +} + +GUIClient::~GUIClient() +{ +} + +void GUIClient::updateSidebarsVisibleAction() +{ + m_showSidebarsAction->setChecked( m_mw->sidebarsVisible() ); +} + +void GUIClient::registerToolView (ToolView *tv) +{ + QString aname = QString("kate_mdi_toolview_") + tv->id; + + // try to read the action shortcut + KShortcut sc; + KConfig *cfg = kapp->config(); + QString _grp = cfg->group(); + cfg->setGroup("Shortcuts"); + sc = KShortcut( cfg->readEntry( aname, "" ) ); + cfg->setGroup( _grp ); + + KToggleAction *a = new ToggleToolViewAction(i18n("Show %1").arg(tv->text), + sc,tv, actionCollection(), aname.latin1() ); + + a->setCheckedState(i18n("Hide %1").arg(tv->text)); + + m_toolViewActions.append(a); + m_toolMenu->insert(a); + + m_toolToAction.insert (tv, a); + + updateActions(); +} + +void GUIClient::unregisterToolView (ToolView *tv) +{ + KAction *a = m_toolToAction[tv]; + + if (!a) + return; + + m_toolViewActions.remove(a); + delete a; + + m_toolToAction.remove (tv); + + updateActions(); +} + +void GUIClient::clientAdded( KXMLGUIClient *client ) +{ + if ( client == this ) + updateActions(); +} + +void GUIClient::updateActions() +{ + if ( !factory() ) + return; + + unplugActionList( actionListName ); + + QPtrList<KAction> addList; + addList.append(m_toolMenu); + + plugActionList( actionListName, addList ); +} + +//END GUICLIENT + + +//BEGIN TOOLVIEW + +ToolView::ToolView (MainWindow *mainwin, Sidebar *sidebar, QWidget *parent) + : QVBox (parent) + , m_mainWin (mainwin) + , m_sidebar (sidebar) + , m_visible (false) + , persistent (false) +{ +} + +ToolView::~ToolView () +{ + m_mainWin->toolViewDeleted (this); +} + +void ToolView::setVisible (bool vis) +{ + if (m_visible == vis) + return; + + m_visible = vis; + emit visibleChanged (m_visible); +} + +bool ToolView::visible () const +{ + return m_visible; +} + +void ToolView::childEvent ( QChildEvent *ev ) +{ + // set the widget to be focus proxy if possible + if (ev->inserted() && ev->child() && ev->child()->qt_cast("QWidget")) + setFocusProxy ((QWidget *)(ev->child()->qt_cast("QWidget"))); + + QVBox::childEvent (ev); +} + +//END TOOLVIEW + + +//BEGIN SIDEBAR + +Sidebar::Sidebar (KMultiTabBar::KMultiTabBarPosition pos, MainWindow *mainwin, QWidget *parent) + : KMultiTabBar ((pos == KMultiTabBar::Top || pos == KMultiTabBar::Bottom) ? KMultiTabBar::Horizontal : KMultiTabBar::Vertical, parent) + , m_mainWin (mainwin) + , m_splitter (0) + , m_ownSplit (0) + , m_lastSize (0) +{ + setPosition( pos ); + hide (); +} + +Sidebar::~Sidebar () +{ +} + +void Sidebar::setSplitter (Splitter *sp) +{ + m_splitter = sp; + m_ownSplit = new Splitter ((position() == KMultiTabBar::Top || position() == KMultiTabBar::Bottom) ? Qt::Horizontal : Qt::Vertical, m_splitter); + m_ownSplit->setOpaqueResize( KGlobalSettings::opaqueResize() ); + m_ownSplit->setChildrenCollapsible( false ); + m_splitter->setResizeMode( m_ownSplit, QSplitter::KeepSize ); + m_ownSplit->hide (); +} + +ToolView *Sidebar::addWidget (const QPixmap &icon, const QString &text, ToolView *widget) +{ + static int id = 0; + + if (widget) + { + if (widget->sidebar() == this) + return widget; + + widget->sidebar()->removeWidget (widget); + } + + int newId = ++id; + + appendTab (icon, newId, text); + + if (!widget) + { + widget = new ToolView (m_mainWin, this, m_ownSplit); + widget->hide (); + widget->icon = icon; + widget->text = text; + } + else + { + widget->hide (); + widget->reparent (m_ownSplit, 0, QPoint()); + widget->m_sidebar = this; + } + + // save it's pos ;) + widget->persistent = false; + + m_idToWidget.insert (newId, widget); + m_widgetToId.insert (widget, newId); + m_toolviews.push_back (widget); + + show (); + + connect(tab(newId),SIGNAL(clicked(int)),this,SLOT(tabClicked(int))); + tab(newId)->installEventFilter(this); + + return widget; +} + +bool Sidebar::removeWidget (ToolView *widget) +{ + if (!m_widgetToId.contains(widget)) + return false; + + removeTab(m_widgetToId[widget]); + + m_idToWidget.remove (m_widgetToId[widget]); + m_widgetToId.remove (widget); + m_toolviews.remove (widget); + + bool anyVis = false; + QIntDictIterator<ToolView> it( m_idToWidget ); + for ( ; it.current(); ++it ) + { + if (!anyVis) + anyVis = it.current()->isVisible(); + } + + if (m_idToWidget.isEmpty()) + { + m_ownSplit->hide (); + hide (); + } + else if (!anyVis) + m_ownSplit->hide (); + + return true; +} + +bool Sidebar::showWidget (ToolView *widget) +{ + if (!m_widgetToId.contains(widget)) + return false; + + // hide other non-persistent views + QIntDictIterator<ToolView> it( m_idToWidget ); + for ( ; it.current(); ++it ) + if ((it.current() != widget) && !it.current()->persistent) + { + it.current()->hide(); + setTab (it.currentKey(), false); + it.current()->setVisible(false); + } + + setTab (m_widgetToId[widget], true); + + m_ownSplit->show (); + widget->show (); + + widget->setVisible (true); + + return true; +} + +bool Sidebar::hideWidget (ToolView *widget) +{ + if (!m_widgetToId.contains(widget)) + return false; + + bool anyVis = false; + + updateLastSize (); + + for ( QIntDictIterator<ToolView> it( m_idToWidget ); it.current(); ++it ) + { + if (it.current() == widget) + { + it.current()->hide(); + continue; + } + + if (!anyVis) + anyVis = it.current()->isVisible(); + } + + // lower tab + setTab (m_widgetToId[widget], false); + + if (!anyVis) + m_ownSplit->hide (); + + widget->setVisible (false); + + return true; +} + +void Sidebar::tabClicked(int i) +{ + ToolView *w = m_idToWidget[i]; + + if (!w) + return; + + if (isTabRaised(i)) + { + showWidget (w); + w->setFocus (); + } + else + { + hideWidget (w); + m_mainWin->centralWidget()->setFocus (); + } +} + +bool Sidebar::eventFilter(QObject *obj, QEvent *ev) +{ + if (ev->type()==QEvent::ContextMenu) + { + QContextMenuEvent *e = (QContextMenuEvent *) ev; + KMultiTabBarTab *bt = dynamic_cast<KMultiTabBarTab*>(obj); + if (bt) + { + kdDebug()<<"Request for popup"<<endl; + + m_popupButton = bt->id(); + + ToolView *w = m_idToWidget[m_popupButton]; + + if (w) + { + KPopupMenu *p = new KPopupMenu (this); + + p->insertTitle(SmallIcon("view_remove"), i18n("Behavior"), 50); + + p->insertItem(w->persistent ? SmallIconSet("window_nofullscreen") : SmallIconSet("window_fullscreen"), w->persistent ? i18n("Make Non-Persistent") : i18n("Make Persistent"), 10); + + p->insertTitle(SmallIcon("move"), i18n("Move To"), 51); + + if (position() != 0) + p->insertItem(SmallIconSet("back"), i18n("Left Sidebar"),0); + + if (position() != 1) + p->insertItem(SmallIconSet("forward"), i18n("Right Sidebar"),1); + + if (position() != 2) + p->insertItem(SmallIconSet("up"), i18n("Top Sidebar"),2); + + if (position() != 3) + p->insertItem(SmallIconSet("down"), i18n("Bottom Sidebar"),3); + + connect(p, SIGNAL(activated(int)), + this, SLOT(buttonPopupActivate(int))); + + p->exec(e->globalPos()); + delete p; + + return true; + } + } + } + + return false; +} + +void Sidebar::show() +{ + if (m_idToWidget.isEmpty() || !m_mainWin->sidebarsVisible() ) + return; + + KMultiTabBar::show( ); +} + +void Sidebar::buttonPopupActivate (int id) +{ + ToolView *w = m_idToWidget[m_popupButton]; + + if (!w) + return; + + // move ids + if (id < 4) + { + // move + show ;) + m_mainWin->moveToolView (w, (KMultiTabBar::KMultiTabBarPosition) id); + m_mainWin->showToolView (w); + } + + // toggle persistent + if (id == 10) + w->persistent = !w->persistent; +} + +void Sidebar::updateLastSize () +{ + QValueList<int> s = m_splitter->sizes (); + + int i = 0; + if ((position() == KMultiTabBar::Right || position() == KMultiTabBar::Bottom)) + i = 2; + + // little threshold + if (s[i] > 2) + m_lastSize = s[i]; +} + +class TmpToolViewSorter +{ + public: + ToolView *tv; + unsigned int pos; +}; + +void Sidebar::restoreSession (KConfig *config) +{ + // get the last correct placed toolview + unsigned int firstWrong = 0; + for ( ; firstWrong < m_toolviews.size(); ++firstWrong ) + { + ToolView *tv = m_toolviews[firstWrong]; + + unsigned int pos = config->readUnsignedNumEntry (QString ("Kate-MDI-ToolView-%1-Sidebar-Position").arg(tv->id), firstWrong); + + if (pos != firstWrong) + break; + } + + // we need to reshuffle, ahhh :( + if (firstWrong < m_toolviews.size()) + { + // first: collect the items to reshuffle + QValueList<TmpToolViewSorter> toSort; + for (unsigned int i=firstWrong; i < m_toolviews.size(); ++i) + { + TmpToolViewSorter s; + s.tv = m_toolviews[i]; + s.pos = config->readUnsignedNumEntry (QString ("Kate-MDI-ToolView-%1-Sidebar-Position").arg(m_toolviews[i]->id), i); + toSort.push_back (s); + } + + // now: sort the stuff we need to reshuffle + for (unsigned int m=0; m < toSort.size(); ++m) + for (unsigned int n=m+1; n < toSort.size(); ++n) + if (toSort[n].pos < toSort[m].pos) + { + TmpToolViewSorter tmp = toSort[n]; + toSort[n] = toSort[m]; + toSort[m] = tmp; + } + + // then: remove this items from the button bar + // do this backwards, to minimize the relayout efforts + for (int i=m_toolviews.size()-1; i >= (int)firstWrong; --i) + { + removeTab (m_widgetToId[m_toolviews[i]]); + } + + // insert the reshuffled things in order :) + for (unsigned int i=0; i < toSort.size(); ++i) + { + ToolView *tv = toSort[i].tv; + + m_toolviews[firstWrong+i] = tv; + + // readd the button + int newId = m_widgetToId[tv]; + appendTab (tv->icon, newId, tv->text); + connect(tab(newId),SIGNAL(clicked(int)),this,SLOT(tabClicked(int))); + tab(newId)->installEventFilter(this); + + // reshuffle in splitter + m_ownSplit->moveToLast (tv); + } + } + + // update last size if needed + updateLastSize (); + + // restore the own splitter sizes + QValueList<int> s = config->readIntListEntry (QString ("Kate-MDI-Sidebar-%1-Splitter").arg(position())); + m_ownSplit->setSizes (s); + + // show only correct toolviews, remember persistent values ;) + bool anyVis = false; + for ( unsigned int i=0; i < m_toolviews.size(); ++i ) + { + ToolView *tv = m_toolviews[i]; + + tv->persistent = config->readBoolEntry (QString ("Kate-MDI-ToolView-%1-Persistent").arg(tv->id), false); + tv->setVisible (config->readBoolEntry (QString ("Kate-MDI-ToolView-%1-Visible").arg(tv->id), false)); + + if (!anyVis) + anyVis = tv->visible(); + + setTab (m_widgetToId[tv],tv->visible()); + + if (tv->visible()) + tv->show(); + else + tv->hide (); + } + + if (anyVis) + m_ownSplit->show(); + else + m_ownSplit->hide(); +} + +void Sidebar::saveSession (KConfig *config) +{ + // store the own splitter sizes + QValueList<int> s = m_ownSplit->sizes(); + config->writeEntry (QString ("Kate-MDI-Sidebar-%1-Splitter").arg(position()), s); + + // store the data about all toolviews in this sidebar ;) + for ( unsigned int i=0; i < m_toolviews.size(); ++i ) + { + ToolView *tv = m_toolviews[i]; + + config->writeEntry (QString ("Kate-MDI-ToolView-%1-Position").arg(tv->id), tv->sidebar()->position()); + config->writeEntry (QString ("Kate-MDI-ToolView-%1-Sidebar-Position").arg(tv->id), i); + config->writeEntry (QString ("Kate-MDI-ToolView-%1-Visible").arg(tv->id), tv->visible()); + config->writeEntry (QString ("Kate-MDI-ToolView-%1-Persistent").arg(tv->id), tv->persistent); + } +} + +//END SIDEBAR + + +//BEGIN MAIN WINDOW + +MainWindow::MainWindow (QWidget* parentWidget, const char* name) + : KParts::MainWindow( parentWidget, name) + , m_sidebarsVisible(true) + , m_restoreConfig (0) + , m_guiClient (new GUIClient (this)) +{ + // init the internal widgets + QHBox *hb = new QHBox (this); + setCentralWidget(hb); + + m_sidebars[KMultiTabBar::Left] = new Sidebar (KMultiTabBar::Left, this, hb); + + m_hSplitter = new Splitter (Qt::Horizontal, hb); + m_hSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() ); + + m_sidebars[KMultiTabBar::Left]->setSplitter (m_hSplitter); + + QVBox *vb = new QVBox (m_hSplitter); + m_hSplitter->setCollapsible(vb, false); + + m_sidebars[KMultiTabBar::Top] = new Sidebar (KMultiTabBar::Top, this, vb); + + m_vSplitter = new Splitter (Qt::Vertical, vb); + m_vSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() ); + + m_sidebars[KMultiTabBar::Top]->setSplitter (m_vSplitter); + + m_centralWidget = new QVBox (m_vSplitter); + m_vSplitter->setCollapsible(m_centralWidget, false); + + m_sidebars[KMultiTabBar::Bottom] = new Sidebar (KMultiTabBar::Bottom, this, vb); + m_sidebars[KMultiTabBar::Bottom]->setSplitter (m_vSplitter); + + m_sidebars[KMultiTabBar::Right] = new Sidebar (KMultiTabBar::Right, this, hb); + m_sidebars[KMultiTabBar::Right]->setSplitter (m_hSplitter); +} + +MainWindow::~MainWindow () +{ + // cu toolviews + while (!m_toolviews.isEmpty()) + delete m_toolviews[0]; + + // seems like we really should delete this by hand ;) + delete m_centralWidget; + + for (unsigned int i=0; i < 4; ++i) + delete m_sidebars[i]; +} + +QWidget *MainWindow::centralWidget () const +{ + return m_centralWidget; +} + +ToolView *MainWindow::createToolView (const QString &identifier, KMultiTabBar::KMultiTabBarPosition pos, const QPixmap &icon, const QString &text) +{ + if (m_idToWidget[identifier]) + return 0; + + // try the restore config to figure out real pos + if (m_restoreConfig && m_restoreConfig->hasGroup (m_restoreGroup)) + { + m_restoreConfig->setGroup (m_restoreGroup); + pos = (KMultiTabBar::KMultiTabBarPosition) m_restoreConfig->readNumEntry (QString ("Kate-MDI-ToolView-%1-Position").arg(identifier), pos); + } + + ToolView *v = m_sidebars[pos]->addWidget (icon, text, 0); + v->id = identifier; + + m_idToWidget.insert (identifier, v); + m_toolviews.push_back (v); + + // register for menu stuff + m_guiClient->registerToolView (v); + + return v; +} + +ToolView *MainWindow::toolView (const QString &identifier) const +{ + return m_idToWidget[identifier]; +} + +void MainWindow::toolViewDeleted (ToolView *widget) +{ + if (!widget) + return; + + if (widget->mainWindow() != this) + return; + + // unregister from menu stuff + m_guiClient->unregisterToolView (widget); + + widget->sidebar()->removeWidget (widget); + + m_idToWidget.remove (widget->id); + m_toolviews.remove (widget); +} + +void MainWindow::setSidebarsVisible( bool visible ) +{ + m_sidebarsVisible = visible; + + m_sidebars[0]->setShown(visible); + m_sidebars[1]->setShown(visible); + m_sidebars[2]->setShown(visible); + m_sidebars[3]->setShown(visible); + + m_guiClient->updateSidebarsVisibleAction(); + + // show information message box, if the users hides the sidebars + if( !m_sidebarsVisible ) + { + KMessageBox::information( this, + i18n("<qt>You are about to hide the sidebars. With " + "hidden sidebars it is not possible to directly " + "access the tool views with the mouse anymore, " + "so if you need to access the sidebars again " + "invoke <b>Window > Tool Views > Show Sidebars</b> " + "in the menu. It is still possible to show/hide " + "the tool views with the assigned shortcuts.</qt>"), + QString::null, "Kate hide sidebars notification message" ); + } +} + +bool MainWindow::sidebarsVisible() const +{ + return m_sidebarsVisible; +} + +void MainWindow::setToolViewStyle (KMultiTabBar::KMultiTabBarStyle style) +{ + m_sidebars[0]->setStyle(style); + m_sidebars[1]->setStyle(style); + m_sidebars[2]->setStyle(style); + m_sidebars[3]->setStyle(style); +} + +KMultiTabBar::KMultiTabBarStyle MainWindow::toolViewStyle () const +{ + // all sidebars have the same style, so just take Top + return m_sidebars[KMultiTabBar::Top]->tabStyle(); +} + +bool MainWindow::moveToolView (ToolView *widget, KMultiTabBar::KMultiTabBarPosition pos) +{ + if (!widget || widget->mainWindow() != this) + return false; + + // try the restore config to figure out real pos + if (m_restoreConfig && m_restoreConfig->hasGroup (m_restoreGroup)) + { + m_restoreConfig->setGroup (m_restoreGroup); + pos = (KMultiTabBar::KMultiTabBarPosition) m_restoreConfig->readNumEntry (QString ("Kate-MDI-ToolView-%1-Position").arg(widget->id), pos); + } + + m_sidebars[pos]->addWidget (widget->icon, widget->text, widget); + + return true; +} + +bool MainWindow::showToolView (ToolView *widget) +{ + if (!widget || widget->mainWindow() != this) + return false; + + // skip this if happens during restoring, or we will just see flicker + if (m_restoreConfig && m_restoreConfig->hasGroup (m_restoreGroup)) + return true; + + return widget->sidebar()->showWidget (widget); +} + +bool MainWindow::hideToolView (ToolView *widget) +{ + if (!widget || widget->mainWindow() != this) + return false; + + // skip this if happens during restoring, or we will just see flicker + if (m_restoreConfig && m_restoreConfig->hasGroup (m_restoreGroup)) + return true; + + return widget->sidebar()->hideWidget (widget); +} + +void MainWindow::startRestore (KConfig *config, const QString &group) +{ + // first save this stuff + m_restoreConfig = config; + m_restoreGroup = group; + + if (!m_restoreConfig || !m_restoreConfig->hasGroup (m_restoreGroup)) + { + // set sane default sizes + QValueList<int> hs; + hs << 200 << 100 << 200; + QValueList<int> vs; + vs << 150 << 100 << 200; + + m_sidebars[0]->setLastSize (hs[0]); + m_sidebars[1]->setLastSize (hs[2]); + m_sidebars[2]->setLastSize (vs[0]); + m_sidebars[3]->setLastSize (vs[2]); + + m_hSplitter->setSizes(hs); + m_vSplitter->setSizes(vs); + return; + } + + // apply size once, to get sizes ready ;) + m_restoreConfig->setGroup (m_restoreGroup); + restoreWindowSize (m_restoreConfig); + + m_restoreConfig->setGroup (m_restoreGroup); + + // get main splitter sizes ;) + QValueList<int> hs = m_restoreConfig->readIntListEntry ("Kate-MDI-H-Splitter"); + QValueList<int> vs = m_restoreConfig->readIntListEntry ("Kate-MDI-V-Splitter"); + + m_sidebars[0]->setLastSize (hs[0]); + m_sidebars[1]->setLastSize (hs[2]); + m_sidebars[2]->setLastSize (vs[0]); + m_sidebars[3]->setLastSize (vs[2]); + + m_hSplitter->setSizes(hs); + m_vSplitter->setSizes(vs); + + setToolViewStyle( (KMultiTabBar::KMultiTabBarStyle)m_restoreConfig->readNumEntry ("Kate-MDI-Sidebar-Style", (int)toolViewStyle()) ); + + // after reading m_sidebarsVisible, update the GUI toggle action + m_sidebarsVisible = m_restoreConfig->readBoolEntry ("Kate-MDI-Sidebar-Visible", true ); + m_guiClient->updateSidebarsVisibleAction(); +} + +void MainWindow::finishRestore () +{ + if (!m_restoreConfig) + return; + + if (m_restoreConfig->hasGroup (m_restoreGroup)) + { + // apply all settings, like toolbar pos and more ;) + applyMainWindowSettings(m_restoreConfig, m_restoreGroup); + + // reshuffle toolviews only if needed + m_restoreConfig->setGroup (m_restoreGroup); + for ( unsigned int i=0; i < m_toolviews.size(); ++i ) + { + KMultiTabBar::KMultiTabBarPosition newPos = (KMultiTabBar::KMultiTabBarPosition) m_restoreConfig->readNumEntry (QString ("Kate-MDI-ToolView-%1-Position").arg(m_toolviews[i]->id), m_toolviews[i]->sidebar()->position()); + + if (m_toolviews[i]->sidebar()->position() != newPos) + { + moveToolView (m_toolviews[i], newPos); + } + } + + // restore the sidebars + m_restoreConfig->setGroup (m_restoreGroup); + for (unsigned int i=0; i < 4; ++i) + m_sidebars[i]->restoreSession (m_restoreConfig); + } + + // clear this stuff, we are done ;) + m_restoreConfig = 0; + m_restoreGroup = ""; +} + +void MainWindow::saveSession (KConfig *config, const QString &group) +{ + if (!config) + return; + + saveMainWindowSettings (config, group); + + config->setGroup (group); + + // save main splitter sizes ;) + QValueList<int> hs = m_hSplitter->sizes(); + QValueList<int> vs = m_vSplitter->sizes(); + + if (hs[0] <= 2 && !m_sidebars[0]->splitterVisible ()) + hs[0] = m_sidebars[0]->lastSize(); + if (hs[2] <= 2 && !m_sidebars[1]->splitterVisible ()) + hs[2] = m_sidebars[1]->lastSize(); + if (vs[0] <= 2 && !m_sidebars[2]->splitterVisible ()) + vs[0] = m_sidebars[2]->lastSize(); + if (vs[2] <= 2 && !m_sidebars[3]->splitterVisible ()) + vs[2] = m_sidebars[3]->lastSize(); + + config->writeEntry ("Kate-MDI-H-Splitter", hs); + config->writeEntry ("Kate-MDI-V-Splitter", vs); + + // save sidebar style + config->writeEntry ("Kate-MDI-Sidebar-Style", (int)toolViewStyle()); + config->writeEntry ("Kate-MDI-Sidebar-Visible", m_sidebarsVisible ); + + // save the sidebars + for (unsigned int i=0; i < 4; ++i) + m_sidebars[i]->saveSession (config); +} + +//END MAIN WINDOW + +} // namespace KateMDI + +// kate: space-indent on; indent-width 2; diff --git a/kate/app/katemdi.h b/kate/app/katemdi.h new file mode 100644 index 000000000..2aa6429bd --- /dev/null +++ b/kate/app/katemdi.h @@ -0,0 +1,442 @@ +/* This file is part of the KDE libraries + Copyright (C) 2005 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2002, 2003 Joseph Wenninger <jowenn@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __KATE_MDI_H__ +#define __KATE_MDI_H__ + +#include <kparts/mainwindow.h> + +#include <kmultitabbar.h> +#include <kxmlguiclient.h> +#include <kaction.h> + +#include <qdict.h> +#include <qintdict.h> +#include <qmap.h> +#include <qsplitter.h> +#include <qpixmap.h> +#include <qptrlist.h> + +namespace KateMDI { + + +/** This class is needed because QSplitter cant return an index for a widget. */ +class Splitter : public QSplitter +{ + Q_OBJECT + + public: + Splitter(Orientation o, QWidget* parent=0, const char* name=0); + ~Splitter(); + + /** Since there is supposed to be only 2 childs of a katesplitter, + * any child other than the last is the first. + * This method uses QSplitter::idAfter(widget) which + * returns 0 if there is no widget after this one. + * This results in an error if widget is not a child + * in this splitter */ + bool isLastChild(QWidget* w) const; + + int idAfter ( QWidget * w ) const; +}; + +class ToggleToolViewAction : public KToggleAction +{ + Q_OBJECT + + public: + ToggleToolViewAction ( const QString& text, const KShortcut& cut, + class ToolView *tv, QObject* parent = 0, const char* name = 0 ); + + virtual ~ToggleToolViewAction(); + + protected slots: + void slotToggled(bool); + void visibleChanged(bool); + + private: + ToolView *m_tv; +}; + +class GUIClient : public QObject, public KXMLGUIClient +{ + Q_OBJECT + + public: + GUIClient ( class MainWindow *mw ); + virtual ~GUIClient(); + + void registerToolView (ToolView *tv); + void unregisterToolView (ToolView *tv); + void updateSidebarsVisibleAction(); + + private slots: + void clientAdded( KXMLGUIClient *client ); + void updateActions(); + + private: + MainWindow *m_mw; + KToggleAction *m_showSidebarsAction; + QPtrList<KAction> m_toolViewActions; + QMap<ToolView*, KAction*> m_toolToAction; + KActionMenu *m_toolMenu; +}; + +class ToolView : public QVBox +{ + Q_OBJECT + + friend class Sidebar; + friend class MainWindow; + friend class GUIClient; + friend class ToggleToolViewAction; + + protected: + /** + * ToolView + * Objects of this clas represent a toolview in the mainwindow + * you should only add one widget as child to this toolview, it will + * be automatically set to be the focus proxy of the toolview + * @param mainwin main window for this toolview + * @param sidebar sidebar of this toolview + * @param parent parent widget, e.g. the splitter of one of the sidebars + */ + ToolView (class MainWindow *mainwin, class Sidebar *sidebar, QWidget *parent); + + public: + /** + * destuct me, this is allowed for all, will care itself that the toolview is removed + * from the mainwindow and sidebar + */ + virtual ~ToolView (); + + signals: + /** + * toolview hidden or shown + * @param bool is this toolview made visible? + */ + void visibleChanged (bool visible); + + /** + * some internal methodes needed by the main window and the sidebars + */ + protected: + MainWindow *mainWindow () { return m_mainWin; } + + Sidebar *sidebar () { return m_sidebar; } + + void setVisible (bool vis); + + public: + bool visible () const; + + protected: + void childEvent ( QChildEvent *ev ); + + private: + MainWindow *m_mainWin; + Sidebar *m_sidebar; + + /** + * unique id + */ + QString id; + + /** + * is visible in sidebar + */ + bool m_visible; + + /** + * is this view persistent? + */ + bool persistent; + + QPixmap icon; + QString text; +}; + +class Sidebar : public KMultiTabBar +{ + Q_OBJECT + + public: + Sidebar (KMultiTabBar::KMultiTabBarPosition pos, class MainWindow *mainwin, QWidget *parent); + virtual ~Sidebar (); + + void setSplitter (Splitter *sp); + + public: + ToolView *addWidget (const QPixmap &icon, const QString &text, ToolView *widget); + bool removeWidget (ToolView *widget); + + bool showWidget (ToolView *widget); + bool hideWidget (ToolView *widget); + + void setLastSize (int s) { m_lastSize = s; } + int lastSize () const { return m_lastSize; } + void updateLastSize (); + + bool splitterVisible () const { return m_ownSplit->isVisible(); } + + void restoreSession (); + + /** + * restore the current session config from given object, use current group + * @param config config object to use + */ + void restoreSession (KConfig *config); + + /** + * save the current session config to given object, use current group + * @param config config object to use + */ + void saveSession (KConfig *config); + + public slots: + // reimplemented, to block a show() call if we have no children or if + // all sidebars are forced hidden. + virtual void show(); + + private slots: + void tabClicked(int); + + protected: + bool eventFilter(QObject *obj, QEvent *ev); + + private slots: + void buttonPopupActivate (int id); + + private: + MainWindow *m_mainWin; + + KMultiTabBar::KMultiTabBarPosition m_pos; + Splitter *m_splitter; + KMultiTabBar *m_tabBar; + Splitter *m_ownSplit; + + QIntDict<ToolView> m_idToWidget; + QMap<ToolView*, int> m_widgetToId; + + /** + * list of all toolviews around in this sidebar + */ + QValueList<ToolView*> m_toolviews; + + int m_lastSize; + + int m_popupButton; +}; + +class MainWindow : public KParts::MainWindow +{ + Q_OBJECT + + friend class ToolView; + + // + // Constructor area + // + public: + /** + * Constructor + */ + MainWindow (QWidget* parentWidget = 0, const char* name = 0); + + /** + * Destructor + */ + virtual ~MainWindow (); + + // + // public interfaces + // + public: + /** + * central widget ;) + * use this as parent for your content + * this widget will get focus if a toolview is hidden + * @return central widget + */ + QWidget *centralWidget () const; + + /** + * add a given widget to the given sidebar if possible, name is very important + * @param identifier unique identifier for this toolview + * @param pos position for the toolview, if we are in session restore, this is only a preference + * @param icon icon to use for the toolview + * @param text text to use in addition to icon + * @return created toolview on success or 0 + */ + ToolView *createToolView (const QString &identifier, KMultiTabBar::KMultiTabBarPosition pos, const QPixmap &icon, const QString &text); + + /** + * give you handle to toolview for the given name, 0 if no toolview around + * @param identifier toolview name + * @return toolview if existing, else 0 + */ + ToolView *toolView (const QString &identifier) const; + + /** + * set the toolview's tabbar style. + * @param style the tabbar style. + */ + void setToolViewStyle (KMultiTabBar::KMultiTabBarStyle style); + + /** + * get the toolview's tabbar style. Call this before @p startRestore(), + * otherwise you overwrite the usersettings. + * @return toolview's tabbar style + */ + KMultiTabBar::KMultiTabBarStyle toolViewStyle () const; + + /** + * get the sidebars' visibility. + * @return false, if the sidebars' visibility is forced hidden, otherwise true + */ + bool sidebarsVisible() const; + + public slots: + /** + * set the sidebars' visibility to @p visible. If false, the sidebars + * are @e always hidden. Usually you do not have to call this because + * the user can set this in the menu. + * @param visible sidebars visibility + */ + void setSidebarsVisible( bool visible ); + + protected: + /** + * called by toolview destructor + * @param widget toolview which is destroyed + */ + void toolViewDeleted (ToolView *widget); + + /** + * modifiers for existing toolviews + */ + public: + /** + * move a toolview around + * @param widget toolview to move + * @param pos position to move too, during session restore, only preference + * @return success + */ + bool moveToolView (ToolView *widget, KMultiTabBar::KMultiTabBarPosition pos); + + /** + * show given toolview, discarded while session restore + * @param widget toolview to show + * @return success + */ + bool showToolView (ToolView *widget); + + /** + * hide given toolview, discarded while session restore + * @param widget toolview to hide + * @return success + */ + bool hideToolView (ToolView *widget); + + /** + * session saving and restore stuff + */ + public: + /** + * start the restore + * @param config config object to use + * @param group config group to use + */ + void startRestore (KConfig *config, const QString &group); + + /** + * finish the restore + */ + void finishRestore (); + + /** + * save the current session config to given object and group + * @param config config object to use + * @param group config group to use + */ + void saveSession (KConfig *config, const QString &group); + + /** + * internal data ;) + */ + private: + /** + * map identifiers to widgets + */ + QDict<ToolView> m_idToWidget; + + /** + * list of all toolviews around + */ + QValueList<ToolView*> m_toolviews; + + /** + * widget, which is the central part of the + * main window ;) + */ + QWidget *m_centralWidget; + + /** + * horizontal splitter + */ + Splitter *m_hSplitter; + + /** + * vertical splitter + */ + Splitter *m_vSplitter; + + /** + * sidebars for the four sides + */ + Sidebar *m_sidebars[4]; + + /** + * sidebars state. + */ + bool m_sidebarsVisible; + + /** + * config object for session restore, only valid between + * start and finish restore calls + */ + KConfig *m_restoreConfig; + + /** + * restore group + */ + QString m_restoreGroup; + + /** + * out guiclient + */ + GUIClient *m_guiClient; +}; + +} + +#endif + +// kate: space-indent on; indent-width 2; diff --git a/kate/app/katemwmodonhddialog.cpp b/kate/app/katemwmodonhddialog.cpp new file mode 100644 index 000000000..efbee3cb5 --- /dev/null +++ b/kate/app/katemwmodonhddialog.cpp @@ -0,0 +1,281 @@ +/* + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + --- + Copyright (C) 2004, Anders Lund <anders@alweb.dk> +*/ + +#include "katemwmodonhddialog.h" +#include "katemwmodonhddialog.moc" + +#include "katedocmanager.h" + +#include <kate/document.h> + +#include <kiconloader.h> +#include <klistview.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kprocio.h> +#include <krun.h> +#include <ktempfile.h> +#include <kpushbutton.h> + +#include <qlabel.h> +#include <qlistview.h> +#include <qlayout.h> +#include <qpushbutton.h> +#include <qwhatsthis.h> +#include <qvbox.h> + +class KateDocItem : public QCheckListItem +{ + public: + KateDocItem( Kate::Document *doc, const QString &status, KListView *lv ) + : QCheckListItem( lv, doc->url().prettyURL(), CheckBox ), + document( doc ) + { + setText( 1, status ); + if ( ! doc->isModified() ) + setOn( On ); + } + ~KateDocItem() {}; + + Kate::Document *document; +}; + + +KateMwModOnHdDialog::KateMwModOnHdDialog( DocVector docs, QWidget *parent, const char *name ) + : KDialogBase( parent, name, true, i18n("Documents Modified on Disk"), + User1|User2|User3, User3, false, + KGuiItem (i18n("&Ignore"), "fileclose"), + KGuiItem (i18n("&Overwrite"), "filesave"), + KGuiItem (i18n("&Reload"), "reload") ) +{ + setButtonWhatsThis( User1, i18n( + "Removes the modified flag from the selected documents and closes the " + "dialog if there are no more unhandled documents.") ); + setButtonWhatsThis( User2, i18n( + "Overwrite selected documents, discarding the disk changes and closes the " + "dialog if there are no more unhandled documents.") ); + setButtonWhatsThis( User3, i18n( + "Reloads the selected documents from disk and closes the dialog if there " + "are no more unhandled documents.") ); + + QVBox *w = makeVBoxMainWidget(); + w->setSpacing( KDialog::spacingHint() ); + + QHBox *lo1 = new QHBox( w ); + + // dialog text + QLabel *icon = new QLabel( lo1 ); + icon->setPixmap( DesktopIcon("messagebox_warning") ); + + QLabel *t = new QLabel( i18n( + "<qt>The documents listed below has changed on disk.<p>Select one " + "or more at the time and press an action button until the list is empty.</qt>"), lo1 ); + lo1->setStretchFactor( t, 1000 ); + + // document list + lvDocuments = new KListView( w ); + lvDocuments->addColumn( i18n("Filename") ); + lvDocuments->addColumn( i18n("Status on Disk") ); + lvDocuments->setSelectionMode( QListView::Single ); + + QStringList l; + l << "" << i18n("Modified") << i18n("Created") << i18n("Deleted"); + for ( uint i=0; i < docs.size(); i++ ) + new KateDocItem( docs[i], l[ (uint)KateDocManager::self()->documentInfo( docs[i] )->modifiedOnDiscReason ], lvDocuments ); + + connect( lvDocuments, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged()) ); + + // diff button + QHBox *lo2 = new QHBox ( w ); + QWidget *d = new QWidget (lo2); + lo2->setStretchFactor (d, 2); + btnDiff = new KPushButton( KGuiItem (i18n("&View Difference"), "edit"), lo2 ); + + QWhatsThis::add( btnDiff, i18n( + "Calculates the difference between the the editor contents and the disk " + "file for the selected document, and shows the difference with the " + "default application. Requires diff(1).") ); + connect( btnDiff, SIGNAL(clicked()), this, SLOT(slotDiff()) ); + + slotSelectionChanged(); + m_tmpfile = 0; +} + +KateMwModOnHdDialog::~KateMwModOnHdDialog() +{ +} + +void KateMwModOnHdDialog::slotUser1() +{ + handleSelected( Ignore ); +} + +void KateMwModOnHdDialog::slotUser2() +{ + handleSelected( Overwrite ); +} + +void KateMwModOnHdDialog::slotUser3() +{ + handleSelected( Reload ); +} + +void KateMwModOnHdDialog::handleSelected( int action ) +{ + // collect all items we can remove + QValueList<QListViewItem *> itemsToDelete; + for ( QListViewItemIterator it ( lvDocuments ); it.current(); ++it ) + { + KateDocItem *item = static_cast<KateDocItem *>(it.current()); + + if ( item->isOn() ) + { + int reason = (int)KateDocManager::self()->documentInfo( item->document )->modifiedOnDiscReason; + bool succes = true; + + Kate::DocumentExt *dext = documentExt( item->document ); + if ( ! dext ) continue; + + dext->setModifiedOnDisk( 0 ); + switch ( action ) + { + case Overwrite: + succes = item->document->save(); + if ( ! succes ) + { + KMessageBox::sorry( this, + i18n("Could not save the document \n'%1'"). + arg( item->document->url().prettyURL() ) ); + } + break; + + case Reload: + item->document->reloadFile(); + break; + + default: + break; + } + + if ( succes ) + itemsToDelete.append (item); + else + dext->setModifiedOnDisk( reason ); + } + } + + // remove the marked items + for (unsigned int i=0; i < itemsToDelete.count(); ++i) + delete itemsToDelete[i]; + + // any documents left unhandled? + if ( ! lvDocuments->childCount() ) + done( Ok ); +} + +void KateMwModOnHdDialog::slotSelectionChanged() +{ + // set the diff button enabled + btnDiff->setEnabled( lvDocuments->currentItem() && + KateDocManager::self()->documentInfo( ((KateDocItem*)lvDocuments->currentItem())->document )->modifiedOnDiscReason != 3 ); +} + +// ### the code below is slightly modified from kdelibs/kate/part/katedialogs, +// class KateModOnHdPrompt. +void KateMwModOnHdDialog::slotDiff() +{ + if ( m_tmpfile ) // we are allready somewhere in this process. + return; + + if ( ! lvDocuments->currentItem() ) + return; + + Kate::Document *doc = ((KateDocItem*)lvDocuments->currentItem())->document; + + // don't try o diff a deleted file + if ( KateDocManager::self()->documentInfo( doc )->modifiedOnDiscReason == 3 ) + return; + + // Start a KProcess that creates a diff + KProcIO *p = new KProcIO(); + p->setComm( KProcess::All ); + *p << "diff" << "-u" << "-" << doc->url().path(); + connect( p, SIGNAL(processExited(KProcess*)), this, SLOT(slotPDone(KProcess*)) ); + connect( p, SIGNAL(readReady(KProcIO*)), this, SLOT(slotPRead(KProcIO*)) ); + + setCursor( WaitCursor ); + + p->start( KProcess::NotifyOnExit, true ); + + uint lastln = doc->numLines(); + for ( uint l = 0; l < lastln; l++ ) + p->writeStdin( doc->textLine( l ), l < lastln ); + + p->closeWhenDone(); +} + +void KateMwModOnHdDialog::slotPRead( KProcIO *p) +{ + // create a file for the diff if we haven't one allready + if ( ! m_tmpfile ) + m_tmpfile = new KTempFile(); + // put all the data we have in it + QString stmp; + bool dataRead = false; + while ( p->readln( stmp, false ) > -1 ) { + *m_tmpfile->textStream() << stmp << endl; + dataRead = true; + } + + if (dataRead) + p->ackRead(); +} + +void KateMwModOnHdDialog::slotPDone( KProcess *p ) +{ + setCursor( ArrowCursor ); + if( ! m_tmpfile ) + { + // dominik: there were only whitespace changes, so that the diff returned by + // diff(1) has 0 bytes. So slotPRead() is never called, as there is + // no data, so that m_tmpfile was never created and thus is NULL. + // NOTE: would be nice, if we could produce a fake-diff, so that kompare + // tells us "The files are identical". Right now, we get an ugly + // "Could not parse diff output". + m_tmpfile = new KTempFile(); + } + m_tmpfile->close(); + + if ( ! p->normalExit() /*|| p->exitStatus()*/ ) + { + KMessageBox::sorry( this, + i18n("The diff command failed. Please make sure that " + "diff(1) is installed and in your PATH."), + i18n("Error Creating Diff") ); + delete m_tmpfile; + m_tmpfile = 0; + return; + } + + KRun::runURL( m_tmpfile->name(), "text/x-diff", true ); + delete m_tmpfile; + m_tmpfile = 0; +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kate/app/katemwmodonhddialog.h b/kate/app/katemwmodonhddialog.h new file mode 100644 index 000000000..86ecd252a --- /dev/null +++ b/kate/app/katemwmodonhddialog.h @@ -0,0 +1,61 @@ +/* + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + --- + Copyright (C) 2004, Anders Lund <anders@alweb.dk> +*/ + +#ifndef _KATE_MW_MODONHD_DIALOG_H_ +#define _KATE_MW_MODONHD_DIALOG_H_ + +#include <kdialogbase.h> +#include <qptrvector.h> +#include <kate/document.h> + +typedef QPtrVector<Kate::Document> DocVector; +class KProcIO; +class KProcess; +/** + * A dialog for handling multiple documents modified on disk + * from within KateMainWindow + */ +class KateMwModOnHdDialog : public KDialogBase +{ + Q_OBJECT + public: + KateMwModOnHdDialog( DocVector docs, QWidget *parent=0, const char *name=0 ); + ~KateMwModOnHdDialog(); + + protected slots: + void slotUser1(); + void slotUser2(); + void slotUser3(); + + private slots: + void slotDiff(); + void slotSelectionChanged(); + void slotPRead(KProcIO*); + void slotPDone(KProcess*); + + private: + enum Action { Ignore, Overwrite, Reload }; + void handleSelected( int action ); + class KListView *lvDocuments; + class QPushButton *btnDiff; + class KTempFile *m_tmpfile; +}; + +#endif // _KATE_MW_MODONHD_DIALOG_H_ +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kate/app/katepluginmanager.cpp b/kate/app/katepluginmanager.cpp new file mode 100644 index 000000000..e3390e6a2 --- /dev/null +++ b/kate/app/katepluginmanager.cpp @@ -0,0 +1,221 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "katepluginmanager.h" +#include "katepluginmanager.moc" + +#include "kateapp.h" +#include "katemainwindow.h" + +#include "../interfaces/application.h" + +#include <kconfig.h> +#include <qstringlist.h> +#include <kmessagebox.h> +#include <kdebug.h> +#include <qfile.h> + +KatePluginManager::KatePluginManager(QObject *parent) : QObject (parent) +{ + m_pluginManager = new Kate::PluginManager (this); + setupPluginList (); + + loadConfig (); + loadAllEnabledPlugins (); +} + +KatePluginManager::~KatePluginManager() +{ + // first write config + writeConfig (); + + // than unload the plugins + unloadAllPlugins (); +} + +KatePluginManager *KatePluginManager::self() +{ + return KateApp::self()->pluginManager (); +} + +void KatePluginManager::setupPluginList () +{ + QValueList<KService::Ptr> traderList= KTrader::self()->query("Kate/Plugin", "(not ('Kate/ProjectPlugin' in ServiceTypes)) and (not ('Kate/InitPlugin' in ServiceTypes))"); + + for(KTrader::OfferList::Iterator it(traderList.begin()); it != traderList.end(); ++it) + { + KService::Ptr ptr = (*it); + + QString pVersion = ptr->property("X-Kate-Version").toString(); + +// if ((pVersion >= "2.5") && (pVersion <= KateApp::kateVersion(false))) + if (pVersion == "2.5") + { + KatePluginInfo info; + + info.load = false; + info.service = ptr; + info.plugin = 0L; + + m_pluginList.push_back (info); + } + } +} + +void KatePluginManager::loadConfig () +{ + KateApp::self()->config()->setGroup("Kate Plugins"); + + for (unsigned int i=0; i < m_pluginList.size(); ++i) + m_pluginList[i].load = KateApp::self()->config()->readBoolEntry (m_pluginList[i].service->library(), false) || + KateApp::self()->config()->readBoolEntry (m_pluginList[i].service->property("X-Kate-PluginName").toString(),false); +} + +void KatePluginManager::writeConfig () +{ + KateApp::self()->config()->setGroup("Kate Plugins"); + + for (unsigned int i=0; i < m_pluginList.size(); ++i) + { + QString saveName=m_pluginList[i].service->property("X-Kate-PluginName").toString(); + + if (saveName.isEmpty()) + saveName = m_pluginList[i].service->library(); + + KateApp::self()->config()->writeEntry (saveName, m_pluginList[i].load); + } +} + +void KatePluginManager::loadAllEnabledPlugins () +{ + for (unsigned int i=0; i < m_pluginList.size(); ++i) + { + if (m_pluginList[i].load) + loadPlugin (&m_pluginList[i]); + else + unloadPlugin (&m_pluginList[i]); + } +} + +void KatePluginManager::unloadAllPlugins () +{ + for (unsigned int i=0; i < m_pluginList.size(); ++i) + { + if (m_pluginList[i].plugin) + unloadPlugin (&m_pluginList[i]); + } +} + +void KatePluginManager::enableAllPluginsGUI (KateMainWindow *win) +{ + for (unsigned int i=0; i < m_pluginList.size(); ++i) + { + if (m_pluginList[i].load) + enablePluginGUI (&m_pluginList[i], win); + } +} + +void KatePluginManager::disableAllPluginsGUI (KateMainWindow *win) +{ + for (unsigned int i=0; i < m_pluginList.size(); ++i) + { + if (m_pluginList[i].load) + disablePluginGUI (&m_pluginList[i], win); + } +} + +void KatePluginManager::loadPlugin (KatePluginInfo *item) +{ + QString pluginName=item->service->property("X-Kate-PluginName").toString(); + + if (pluginName.isEmpty()) + pluginName=item->service->library(); + + item->load = (item->plugin = Kate::createPlugin (QFile::encodeName(item->service->library()), Kate::application(), 0, pluginName)); +} + +void KatePluginManager::unloadPlugin (KatePluginInfo *item) +{ + disablePluginGUI (item); + if (item->plugin) delete item->plugin; + item->plugin = 0L; + item->load = false; +} + +void KatePluginManager::enablePluginGUI (KatePluginInfo *item, KateMainWindow *win) +{ + if (!item->plugin) return; + if (!Kate::pluginViewInterface(item->plugin)) return; + + Kate::pluginViewInterface(item->plugin)->addView(win->mainWindow()); +} + +void KatePluginManager::enablePluginGUI (KatePluginInfo *item) +{ + if (!item->plugin) return; + if (!Kate::pluginViewInterface(item->plugin)) return; + + for (uint i=0; i< KateApp::self()->mainWindows(); i++) + { + Kate::pluginViewInterface(item->plugin)->addView(KateApp::self()->mainWindow(i)->mainWindow()); + } +} + +void KatePluginManager::disablePluginGUI (KatePluginInfo *item, KateMainWindow *win) +{ + if (!item->plugin) return; + if (!Kate::pluginViewInterface(item->plugin)) return; + + Kate::pluginViewInterface(item->plugin)->removeView(win->mainWindow()); +} + +void KatePluginManager::disablePluginGUI (KatePluginInfo *item) +{ + if (!item->plugin) return; + if (!Kate::pluginViewInterface(item->plugin)) return; + + for (uint i=0; i< KateApp::self()->mainWindows(); i++) + { + Kate::pluginViewInterface(item->plugin)->removeView(KateApp::self()->mainWindow(i)->mainWindow()); + } +} + +Kate::Plugin *KatePluginManager::plugin(const QString &name) +{ + for (unsigned int i=0; i < m_pluginList.size(); ++i) + { + KatePluginInfo *info = &m_pluginList[i]; + QString pluginName=info->service->property("X-Kate-PluginName").toString(); + if (pluginName.isEmpty()) + pluginName=info->service->library(); + if (pluginName==name) + { + if (info->plugin) + return info->plugin; + else + break; + } + } + return 0; +} + +bool KatePluginManager::pluginAvailable(const QString &){return false;} +class Kate::Plugin *KatePluginManager::loadPlugin(const QString &,bool ){return 0;} +void KatePluginManager::unloadPlugin(const QString &,bool){;} diff --git a/kate/app/katepluginmanager.h b/kate/app/katepluginmanager.h new file mode 100644 index 000000000..76f9578b2 --- /dev/null +++ b/kate/app/katepluginmanager.h @@ -0,0 +1,90 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __KATE_PLUGINMANAGER_H__ +#define __KATE_PLUGINMANAGER_H__ + +#include "katemain.h" + +#include "../interfaces/plugin.h" +#include "../interfaces/pluginmanager.h" + +#include <ktrader.h> + +#include <qobject.h> +#include <qvaluelist.h> + +class KatePluginInfo +{ + public: + bool load; + KService::Ptr service; + Kate::Plugin *plugin; +}; + +typedef QValueList<KatePluginInfo> KatePluginList; + +class KatePluginManager : public QObject +{ + Q_OBJECT + + public: + KatePluginManager(QObject *parent); + ~KatePluginManager(); + + static KatePluginManager *self(); + + Kate::PluginManager *pluginManager () const { return m_pluginManager; }; + + void loadAllEnabledPlugins (); + void unloadAllPlugins (); + + void enableAllPluginsGUI (KateMainWindow *win); + void disableAllPluginsGUI (KateMainWindow *win); + + void loadConfig (); + void writeConfig (); + + void loadPlugin (KatePluginInfo *item); + void unloadPlugin (KatePluginInfo *item); + + void enablePluginGUI (KatePluginInfo *item, KateMainWindow *win); + void enablePluginGUI (KatePluginInfo *item); + + void disablePluginGUI (KatePluginInfo *item, KateMainWindow *win); + void disablePluginGUI (KatePluginInfo *item); + + inline KatePluginList & pluginList () { return m_pluginList; }; + + Kate::Plugin *plugin (const QString &name); + bool pluginAvailable (const QString &name); + + Kate::Plugin *loadPlugin (const QString &name, bool permanent=true); + void unloadPlugin (const QString &name, bool permanent=true); + + private: + Kate::PluginManager *m_pluginManager; + + void setupPluginList (); + + KatePluginList m_pluginList; +}; + +#endif diff --git a/kate/app/katesavemodifieddialog.cpp b/kate/app/katesavemodifieddialog.cpp new file mode 100644 index 000000000..51dc1ea61 --- /dev/null +++ b/kate/app/katesavemodifieddialog.cpp @@ -0,0 +1,226 @@ +/* This file is part of the KDE project + Copyright (C) 2004 Joseph Wenninger <jowenn@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "katesavemodifieddialog.h" +#include "katesavemodifieddialog.moc" + +#include <klocale.h> +#include <qlistview.h> +#include <klistview.h> +#include <kguiitem.h> +#include <kactivelabel.h> +#include <kstdguiitem.h> +#include <qvbox.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <kdebug.h> +#include <kencodingfiledialog.h> +#include <ktexteditor/encodinginterface.h> + +class AbstractKateSaveModifiedDialogCheckListItem:public QCheckListItem { +public: + AbstractKateSaveModifiedDialogCheckListItem(QListViewItem *parent,const QString& title, const QString& url):QCheckListItem(parent,title,QCheckListItem::CheckBox) { + setText(1,url); + setOn(true); + setState(InitialState); + } + virtual ~AbstractKateSaveModifiedDialogCheckListItem() { + } + virtual bool synchronousSave(QWidget *dialogParent)=0; + enum STATE{InitialState,SaveOKState,SaveFailedState}; + STATE state() const { return m_state;} + void setState(enum STATE state) { + m_state=state; + KIconLoader *loader = KGlobal::instance()->iconLoader(); + switch (state) { + case InitialState: + setPixmap(0,QPixmap()); + break; + case SaveOKState: + setPixmap(0,loader->loadIcon("ok",KIcon::NoGroup,height())); + break; + case SaveFailedState: + setPixmap(0,loader->loadIcon("cancel",KIcon::NoGroup,height())); + break; + } + } +private: + STATE m_state; +}; + +class KateSaveModifiedDocumentCheckListItem:public AbstractKateSaveModifiedDialogCheckListItem { +public: + KateSaveModifiedDocumentCheckListItem(QListViewItem *parent,Kate::Document *document):AbstractKateSaveModifiedDialogCheckListItem(parent,document->docName(),document->url().prettyURL()){ + m_document=document; + } + virtual ~KateSaveModifiedDocumentCheckListItem() { + } + virtual bool synchronousSave(QWidget *dialogParent) { + if (m_document->url().isEmpty() ) { + KEncodingFileDialog::Result r=KEncodingFileDialog::getSaveURLAndEncoding( + KTextEditor::encodingInterface(m_document)->encoding(),QString::null,QString::null,dialogParent,i18n("Save As (%1)").arg(m_document->docName())); + + m_document->setEncoding( r.encoding ); + if (!r.URLs.isEmpty()) { + KURL tmp = r.URLs.first(); + if ( !m_document->saveAs( tmp ) ) { + setState(SaveFailedState); + setText(1,m_document->url().prettyURL()); + return false; + } else { + bool sc=m_document->waitSaveComplete(); + setText(1,m_document->url().prettyURL()); + if (!sc) { + setState(SaveFailedState); + return false; + } else { + setState(SaveOKState); + return true; + } + } + } else { + setState(SaveFailedState); + return false; + } + } else { //document has an exising location + if ( !m_document->save() ) { + setState(SaveFailedState); + setText(1,m_document->url().prettyURL()); + return false; + } else { + bool sc=m_document->waitSaveComplete(); + setText(1,m_document->url().prettyURL()); + if (!sc) { + setState(SaveFailedState); + return false; + } else { + setState(SaveOKState); + return true; + } + } + + } + + return false; + + } +private: + Kate::Document *m_document; +}; + +KateSaveModifiedDialog::KateSaveModifiedDialog(QWidget *parent, QPtrList<Kate::Document> documents): + KDialogBase( parent, "KateSaveModifiedDialog", true, i18n("Save Documents"), Yes | No | Cancel) { + + KGuiItem saveItem=KStdGuiItem::save(); + saveItem.setText(i18n("&Save Selected")); + setButtonGuiItem(KDialogBase::Yes,saveItem); + + setButtonGuiItem(KDialogBase::No,KStdGuiItem::dontSave()); + + KGuiItem cancelItem=KStdGuiItem::cancel(); + cancelItem.setText(i18n("&Abort Closing")); + setButtonGuiItem(KDialogBase::Cancel,cancelItem); + + QVBox *box=makeVBoxMainWidget(); + new KActiveLabel(i18n("<qt>The following documents have been modified. Do you want to save them before closing?</qt>"),box); + m_list=new KListView(box); + m_list->addColumn(i18n("Title")); + m_list->addColumn(i18n("Location")); + m_list->setRootIsDecorated(true); + m_list->setResizeMode(QListView::LastColumn); + if (0) { + m_projectRoot=new QListViewItem(m_list,i18n("Projects")); + } else m_projectRoot=0; + if (documents.count()>0) { + m_documentRoot=new QListViewItem(m_list,i18n("Documents")); + const uint docCnt=documents.count(); + for (uint i=0;i<docCnt;i++) { + new KateSaveModifiedDocumentCheckListItem(m_documentRoot,documents.at(i)); + } + m_documentRoot->setOpen(true); + } else m_documentRoot=0; + //FIXME - Is this the best way? + connect(m_list, SIGNAL(clicked(QListViewItem *)), SLOT(slotItemSelected())); + connect(m_list, SIGNAL(doubleClicked(QListViewItem *)), SLOT(slotItemSelected())); + connect(m_list, SIGNAL(spacePressed(QListViewItem *)), SLOT(slotItemSelected())); + if(documents.count()>3) { //For 3 or less, it would be quicker just to tick or untick them yourself, so don't clutter the gui. + connect(new QPushButton(i18n("Se&lect All"),box),SIGNAL(clicked()),this,SLOT(slotSelectAll())); + } +} + +KateSaveModifiedDialog::~KateSaveModifiedDialog() { +} + +void KateSaveModifiedDialog::slotItemSelected() { + kdDebug(13001) << "slotItemSelected()" << endl; + + for(QListViewItem *it=m_documentRoot->firstChild();it;it=it->nextSibling()) { + if(((QCheckListItem*)it)->isOn()) { + enableButton(KDialogBase::Yes, true); + return; + } + } + enableButton(KDialogBase::Yes, false); +} + +static void selectItems(QListViewItem *root) { + if (!root) return; + for (QListViewItem *it=root->firstChild();it;it=it->nextSibling()) { + ((QCheckListItem*)it)->setOn(true); + } +} + +void KateSaveModifiedDialog::slotSelectAll() { + selectItems(m_documentRoot); + slotItemSelected(); +} + + +void KateSaveModifiedDialog::slotUser2() { + kdDebug(13001)<<"KateSaveModifiedDialog::slotYes()"<<endl; + if (doSave(m_documentRoot)) done(QDialog::Accepted); +} + +void KateSaveModifiedDialog::slotUser1() { + done(QDialog::Accepted); +} + +bool KateSaveModifiedDialog::doSave(QListViewItem *root) { + if (root) { + for (QListViewItem *it=root->firstChild();it;it=it->nextSibling()) { + AbstractKateSaveModifiedDialogCheckListItem *cit= (AbstractKateSaveModifiedDialogCheckListItem*)it; + if (cit->isOn() && (cit->state()!=AbstractKateSaveModifiedDialogCheckListItem::SaveOKState)) { + if (!cit->synchronousSave(this /*perhaps that should be the kate mainwindow*/)) { + KMessageBox::sorry( this, i18n("Data you requested to be saved could not be written. Please choose how you want to proceed.")); + return false; + } + } else if ((!cit->isOn()) && (cit->state()==AbstractKateSaveModifiedDialogCheckListItem::SaveFailedState)) { + cit->setState(AbstractKateSaveModifiedDialogCheckListItem::InitialState); + } + + } + } + return true; +} + +bool KateSaveModifiedDialog::queryClose(QWidget *parent,QPtrList<Kate::Document> documents) { + KateSaveModifiedDialog d(parent,documents); + return (d.exec()!=QDialog::Rejected); +} diff --git a/kate/app/katesavemodifieddialog.h b/kate/app/katesavemodifieddialog.h new file mode 100644 index 000000000..65817356b --- /dev/null +++ b/kate/app/katesavemodifieddialog.h @@ -0,0 +1,48 @@ +/* This file is part of the KDE project + Copyright (C) 2004 Joseph Wenninger <jowenn@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _KATE_SAVE_MODIFIED_DIALOG_ +#define _KATE_SAVE_MODIFIED_DIALOG_ + +#include <kdialogbase.h> +#include <kate/document.h> + +class QListViewItem; +class KListView; + +class KateSaveModifiedDialog: public KDialogBase { + Q_OBJECT +public: + KateSaveModifiedDialog(QWidget *parent, QPtrList<Kate::Document> documents); + virtual ~KateSaveModifiedDialog(); + static bool queryClose(QWidget *parent,QPtrList<Kate::Document> documents); +protected: + virtual void slotUser2(); + virtual void slotUser1(); + bool doSave(QListViewItem *root); +protected slots: + void slotSelectAll(); + void slotItemSelected(); + +private: + QListViewItem *m_projectRoot; + QListViewItem *m_documentRoot; + KListView *m_list; +}; + +#endif diff --git a/kate/app/katesession.cpp b/kate/app/katesession.cpp new file mode 100644 index 000000000..0d208c566 --- /dev/null +++ b/kate/app/katesession.cpp @@ -0,0 +1,920 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Christoph Cullmann <cullmann@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "katesession.h" +#include "katesession.moc" + +#include "kateapp.h" +#include "katemainwindow.h" +#include "katedocmanager.h" + +#include <kstandarddirs.h> +#include <klocale.h> +#include <kdebug.h> +#include <kdirwatch.h> +#include <klistview.h> +#include <kinputdialog.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <kmdcodec.h> +#include <kstdguiitem.h> +#include <kpushbutton.h> +#include <kpopupmenu.h> + +#include <qdir.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qvbox.h> +#include <qhbox.h> +#include <qcheckbox.h> +#include <qdatetime.h> +#include <qmap.h> + +#include <unistd.h> +#include <time.h> + +bool operator<( const KateSession::Ptr& a, const KateSession::Ptr& b ) +{ + return a->sessionName().lower() < b->sessionName().lower(); +} + +KateSession::KateSession (KateSessionManager *manager, const QString &fileName, const QString &name) + : m_sessionFileRel (fileName) + , m_sessionName (name) + , m_documents (0) + , m_manager (manager) + , m_readConfig (0) + , m_writeConfig (0) +{ + init (); +} + +void KateSession::init () +{ + // given file exists, use it to load some stuff ;) + if (!m_sessionFileRel.isEmpty() && KGlobal::dirs()->exists(sessionFile ())) + { + KSimpleConfig config (sessionFile (), true); + + if (m_sessionName.isEmpty()) + { + // get the name out of the file + if (m_sessionFileRel == "default.katesession") + m_sessionName = i18n("Default Session"); + else + { + config.setGroup ("General"); + m_sessionName = config.readEntry ("Name", i18n ("Unnamed Session")); + } + } + + // get the document count + config.setGroup ("Open Documents"); + m_documents = config.readUnsignedNumEntry("Count", 0); + + return; + } + + // filename not empty, create the file + // anders: When will this ever happen??? + if (!m_sessionFileRel.isEmpty()) + { + kdDebug(13001)<<"Kate::Session: initializing unexisting file!"<<endl; + // uhh, no name given + if (m_sessionName.isEmpty()) + { + if (m_sessionFileRel == "default.katesession") + m_sessionName = i18n("Default Session"); + else + m_sessionName = i18n("Session (%1)").arg(QTime::currentTime().toString(Qt::LocalDate)); + } + + // create the file, write name to it! + KSimpleConfig config (sessionFile ()); + config.setGroup ("General"); + config.writeEntry ("Name", m_sessionName); + + config.sync (); + } +} + +KateSession::~KateSession () +{ + delete m_readConfig; + delete m_writeConfig; +} + +QString KateSession::sessionFile () const +{ + return m_manager->sessionsDir() + "/" + m_sessionFileRel; +} + +bool KateSession::create (const QString &name, bool force) +{ + if (!force && (name.isEmpty() || !m_sessionFileRel.isEmpty())) + return false; + + delete m_writeConfig; + m_writeConfig = 0; + + delete m_readConfig; + m_readConfig = 0; + + m_sessionName = name; + + // get a usable filename + int s = time(0); + QCString tname; + while (true) + { + tname.setNum (s++); + KMD5 md5 (tname); + m_sessionFileRel = QString ("%1.katesession").arg (md5.hexDigest().data()); + + if (!KGlobal::dirs()->exists(sessionFile ())) + break; + } + + // create the file, write name to it! + KSimpleConfig config (sessionFile ()); + config.setGroup ("General"); + config.writeEntry ("Name", m_sessionName); + config.sync (); + + // reinit ourselfs ;) + init (); + + return true; +} + +bool KateSession::rename (const QString &name) +{ + if (name.isEmpty () || m_sessionFileRel.isEmpty() || m_sessionFileRel == "default.katesession") + return false; + + m_sessionName = name; + + KConfig config (sessionFile (), false, false); + config.setGroup ("General"); + config.writeEntry ("Name", m_sessionName); + config.sync (); + + return true; +} + +KConfig *KateSession::configRead () +{ + if (m_sessionFileRel.isEmpty()) + return 0; + + if (m_readConfig) + return m_readConfig; + + return m_readConfig = new KSimpleConfig (sessionFile (), true); +} + +KConfig *KateSession::configWrite () +{ + if (m_sessionFileRel.isEmpty()) + return 0; + + if (m_writeConfig) + return m_writeConfig; + + m_writeConfig = new KSimpleConfig (sessionFile ()); + m_writeConfig->setGroup ("General"); + m_writeConfig->writeEntry ("Name", m_sessionName); + + return m_writeConfig; +} + +KateSessionManager::KateSessionManager (QObject *parent) + : QObject (parent) + , m_sessionsDir (locateLocal( "data", "kate/sessions")) + , m_activeSession (new KateSession (this, "", "")) +{ + kdDebug() << "LOCAL SESSION DIR: " << m_sessionsDir << endl; + + // create dir if needed + KGlobal::dirs()->makeDir (m_sessionsDir); +} + +KateSessionManager::~KateSessionManager() +{ +} + +KateSessionManager *KateSessionManager::self() +{ + return KateApp::self()->sessionManager (); +} + +void KateSessionManager::dirty (const QString &) +{ + updateSessionList (); +} + +void KateSessionManager::updateSessionList () +{ + m_sessionList.clear (); + + // Let's get a list of all session we have atm + QDir dir (m_sessionsDir, "*.katesession"); + + bool foundDefault = false; + for (unsigned int i=0; i < dir.count(); ++i) + { + KateSession *session = new KateSession (this, dir[i], ""); + m_sessionList.append (session); + + kdDebug () << "FOUND SESSION: " << session->sessionName() << " FILE: " << session->sessionFile() << endl; + + if (!foundDefault && (dir[i] == "default.katesession")) + foundDefault = true; + } + + // add default session, if not there + if (!foundDefault) + m_sessionList.append (new KateSession (this, "default.katesession", i18n("Default Session"))); + + qHeapSort(m_sessionList); +} + +void KateSessionManager::activateSession (KateSession::Ptr session, bool closeLast, bool saveLast, bool loadNew) +{ + // don't reload. + // ### comparing the pointers directly is b0rk3d :( + if ( ! session->sessionName().isEmpty() && session->sessionName() == m_activeSession->sessionName() ) + return; + // try to close last session + if (closeLast) + { + if (KateApp::self()->activeMainWindow()) + { + if (!KateApp::self()->activeMainWindow()->queryClose_internal()) + return; + } + } + + // save last session or not? + if (saveLast) + saveActiveSession (true); + + // really close last + if (closeLast) + { + KateDocManager::self()->closeAllDocuments (); + } + + // set the new session + m_activeSession = session; + + if (loadNew) + { + // open the new session + Kate::Document::setOpenErrorDialogsActivated (false); + + KConfig *sc = activeSession()->configRead(); + + if (sc) + KateApp::self()->documentManager()->restoreDocumentList (sc); + + // if we have no session config object, try to load the default + // (anonymous/unnamed sessions) + if ( ! sc ) + sc = new KSimpleConfig( sessionsDir() + "/default.katesession" ); + + // window config + if (sc) + { + KConfig *c = KateApp::self()->config(); + c->setGroup("General"); + + if (c->readBoolEntry("Restore Window Configuration", true)) + { + // a new, named session, read settings of the default session. + if ( ! sc->hasGroup("Open MainWindows") ) + sc = new KSimpleConfig( sessionsDir() + "/default.katesession" ); + + sc->setGroup ("Open MainWindows"); + unsigned int wCount = sc->readUnsignedNumEntry("Count", 1); + + for (unsigned int i=0; i < wCount; ++i) + { + if (i >= KateApp::self()->mainWindows()) + { + KateApp::self()->newMainWindow(sc, QString ("MainWindow%1").arg(i)); + } + else + { + sc->setGroup(QString ("MainWindow%1").arg(i)); + KateApp::self()->mainWindow(i)->readProperties (sc); + } + } + + if (wCount > 0) + { + while (wCount < KateApp::self()->mainWindows()) + { + KateMainWindow *w = KateApp::self()->mainWindow(KateApp::self()->mainWindows()-1); + KateApp::self()->removeMainWindow (w); + delete w; + } + } + } + } + + Kate::Document::setOpenErrorDialogsActivated (true); + } +} + +KateSession::Ptr KateSessionManager::createSession (const QString &name) +{ + KateSession::Ptr s = new KateSession (this, "", ""); + s->create (name); + + return s; +} + +KateSession::Ptr KateSessionManager::giveSession (const QString &name) +{ + if (name.isEmpty()) + return new KateSession (this, "", ""); + + updateSessionList(); + + for (unsigned int i=0; i < m_sessionList.count(); ++i) + { + if (m_sessionList[i]->sessionName() == name) + return m_sessionList[i]; + } + + return createSession (name); +} + +bool KateSessionManager::saveActiveSession (bool tryAsk, bool rememberAsLast) +{ + if (tryAsk) + { + // app config + KConfig *c = KateApp::self()->config(); + c->setGroup("General"); + + QString sesExit (c->readEntry ("Session Exit", "save")); + + if (sesExit == "discard") + return true; + + if (sesExit == "ask") + { + KDialogBase* dlg = new KDialogBase(i18n ("Save Session?") + , KDialogBase::Yes | KDialogBase::No + , KDialogBase::Yes, KDialogBase::No + ); + + bool dontAgain = false; + int res = KMessageBox::createKMessageBox(dlg, QMessageBox::Question, + i18n("Save current session?"), QStringList(), + i18n("Do not ask again"), &dontAgain, KMessageBox::Notify); + + // remember to not ask again with right setting + if (dontAgain) + { + c->setGroup("General"); + + if (res == KDialogBase::No) + c->writeEntry ("Session Exit", "discard"); + else + c->writeEntry ("Session Exit", "save"); + } + + if (res == KDialogBase::No) + return true; + } + } + + KConfig *sc = activeSession()->configWrite(); + + if (!sc) + return false; + + KateDocManager::self()->saveDocumentList (sc); + + sc->setGroup ("Open MainWindows"); + sc->writeEntry ("Count", KateApp::self()->mainWindows ()); + + // save config for all windows around ;) + for (unsigned int i=0; i < KateApp::self()->mainWindows (); ++i ) + { + sc->setGroup(QString ("MainWindow%1").arg(i)); + KateApp::self()->mainWindow(i)->saveProperties (sc); + } + + sc->sync(); + + if (rememberAsLast) + { + KConfig *c = KateApp::self()->config(); + c->setGroup("General"); + c->writeEntry ("Last Session", activeSession()->sessionFileRelative()); + c->sync (); + } + + return true; +} + +bool KateSessionManager::chooseSession () +{ + bool success = true; + + // app config + KConfig *c = KateApp::self()->config(); + c->setGroup("General"); + + // get last used session, default to default session + QString lastSession (c->readEntry ("Last Session", "default.katesession")); + QString sesStart (c->readEntry ("Startup Session", "manual")); + + // uhh, just open last used session, show no chooser + if (sesStart == "last") + { + activateSession (new KateSession (this, lastSession, ""), false, false); + return success; + } + + // start with empty new session + if (sesStart == "new") + { + activateSession (new KateSession (this, "", ""), false, false); + return success; + } + + KateSessionChooser *chooser = new KateSessionChooser (0, lastSession); + + bool retry = true; + int res = 0; + while (retry) + { + res = chooser->exec (); + + switch (res) + { + case KateSessionChooser::resultOpen: + { + KateSession::Ptr s = chooser->selectedSession (); + + if (!s) + { + KMessageBox::error (chooser, i18n("No session selected to open."), i18n ("No Session Selected")); + break; + } + + activateSession (s, false, false); + retry = false; + break; + } + + // exit the app lateron + case KateSessionChooser::resultQuit: + success = false; + retry = false; + break; + + default: + activateSession (new KateSession (this, "", ""), false, false); + retry = false; + break; + } + } + + // write back our nice boolean :) + if (success && chooser->reopenLastSession ()) + { + c->setGroup("General"); + + if (res == KateSessionChooser::resultOpen) + c->writeEntry ("Startup Session", "last"); + else if (res == KateSessionChooser::resultNew) + c->writeEntry ("Startup Session", "new"); + + c->sync (); + } + + delete chooser; + + return success; +} + +void KateSessionManager::sessionNew () +{ + activateSession (new KateSession (this, "", "")); +} + +void KateSessionManager::sessionOpen () +{ + KateSessionOpenDialog *chooser = new KateSessionOpenDialog (0); + + int res = chooser->exec (); + + if (res == KateSessionOpenDialog::resultCancel) + { + delete chooser; + return; + } + + KateSession::Ptr s = chooser->selectedSession (); + + if (s) + activateSession (s); + + delete chooser; +} + +void KateSessionManager::sessionSave () +{ + // if the active session is valid, just save it :) + if (saveActiveSession ()) + return; + + bool ok = false; + QString name = KInputDialog::getText (i18n("Specify Name for Current Session"), i18n("Session name:"), "", &ok); + + if (!ok) + return; + + if (name.isEmpty()) + { + KMessageBox::error (0, i18n("To save a new session, you must specify a name."), i18n ("Missing Session Name")); + return; + } + + activeSession()->create (name); + saveActiveSession (); +} + +void KateSessionManager::sessionSaveAs () +{ + bool ok = false; + QString name = KInputDialog::getText (i18n("Specify New Name for Current Session"), i18n("Session name:"), "", &ok); + + if (!ok) + return; + + if (name.isEmpty()) + { + KMessageBox::error (0, i18n("To save a session, you must specify a name."), i18n ("Missing Session Name")); + return; + } + + activeSession()->create (name, true); + saveActiveSession (); +} + + +void KateSessionManager::sessionManage () +{ + KateSessionManageDialog *dlg = new KateSessionManageDialog (0); + + dlg->exec (); + + delete dlg; +} + +//BEGIN CHOOSER DIALOG + +class KateSessionChooserItem : public QListViewItem +{ + public: + KateSessionChooserItem (KListView *lv, KateSession::Ptr s) + : QListViewItem (lv, s->sessionName()) + , session (s) + { + QString docs; + docs.setNum (s->documents()); + setText (1, docs); + } + + KateSession::Ptr session; +}; + +KateSessionChooser::KateSessionChooser (QWidget *parent, const QString &lastSession) + : KDialogBase ( parent + , "" + , true + , i18n ("Session Chooser") + , KDialogBase::User1 | KDialogBase::User2 | KDialogBase::User3 + , KDialogBase::User2 + , true + , KStdGuiItem::quit () + , KGuiItem (i18n ("Open Session"), "fileopen") + , KGuiItem (i18n ("New Session"), "filenew") + ) +{ + QHBox *page = new QHBox (this); + page->setMinimumSize (400, 200); + setMainWidget(page); + + QHBox *hb = new QHBox (page); + hb->setSpacing (KDialog::spacingHint()); + + QLabel *label = new QLabel (hb); + label->setPixmap (UserIcon("sessionchooser")); + label->setFrameStyle (QFrame::Panel | QFrame::Sunken); + + QVBox *vb = new QVBox (hb); + vb->setSpacing (KDialog::spacingHint()); + + m_sessions = new KListView (vb); + m_sessions->addColumn (i18n("Session Name")); + m_sessions->addColumn (i18n("Open Documents")); + m_sessions->setResizeMode (QListView::AllColumns); + m_sessions->setSelectionMode (QListView::Single); + m_sessions->setAllColumnsShowFocus (true); + + connect (m_sessions, SIGNAL(selectionChanged()), this, SLOT(selectionChanged())); + connect (m_sessions, SIGNAL(doubleClicked(QListViewItem *, const QPoint &, int)), this, SLOT(slotUser2())); + + KateSessionList &slist (KateSessionManager::self()->sessionList()); + for (unsigned int i=0; i < slist.count(); ++i) + { + KateSessionChooserItem *item = new KateSessionChooserItem (m_sessions, slist[i]); + + if (slist[i]->sessionFileRelative() == lastSession) + m_sessions->setSelected (item, true); + } + + m_useLast = new QCheckBox (i18n ("&Always use this choice"), vb); + + setResult (resultNone); + + // trigger action update + selectionChanged (); +} + +KateSessionChooser::~KateSessionChooser () +{ +} + +KateSession::Ptr KateSessionChooser::selectedSession () +{ + KateSessionChooserItem *item = (KateSessionChooserItem *) m_sessions->selectedItem (); + + if (!item) + return 0; + + return item->session; +} + +bool KateSessionChooser::reopenLastSession () +{ + return m_useLast->isChecked (); +} + +void KateSessionChooser::slotUser2 () +{ + done (resultOpen); +} + +void KateSessionChooser::slotUser3 () +{ + done (resultNew); +} + +void KateSessionChooser::slotUser1 () +{ + done (resultQuit); +} + +void KateSessionChooser::selectionChanged () +{ + enableButton (KDialogBase::User2, m_sessions->selectedItem ()); +} + +//END CHOOSER DIALOG + +//BEGIN OPEN DIALOG + +KateSessionOpenDialog::KateSessionOpenDialog (QWidget *parent) + : KDialogBase ( parent + , "" + , true + , i18n ("Open Session") + , KDialogBase::User1 | KDialogBase::User2 + , KDialogBase::User2 + , false + , KStdGuiItem::cancel () + , KGuiItem( i18n("&Open"), "fileopen") + ) +{ + QHBox *page = new QHBox (this); + page->setMinimumSize (400, 200); + setMainWidget(page); + + QHBox *hb = new QHBox (page); + + QVBox *vb = new QVBox (hb); + + m_sessions = new KListView (vb); + m_sessions->addColumn (i18n("Session Name")); + m_sessions->addColumn (i18n("Open Documents")); + m_sessions->setResizeMode (QListView::AllColumns); + m_sessions->setSelectionMode (QListView::Single); + m_sessions->setAllColumnsShowFocus (true); + + connect (m_sessions, SIGNAL(doubleClicked(QListViewItem *, const QPoint &, int)), this, SLOT(slotUser2())); + + KateSessionList &slist (KateSessionManager::self()->sessionList()); + for (unsigned int i=0; i < slist.count(); ++i) + { + new KateSessionChooserItem (m_sessions, slist[i]); + } + + setResult (resultCancel); +} + +KateSessionOpenDialog::~KateSessionOpenDialog () +{ +} + +KateSession::Ptr KateSessionOpenDialog::selectedSession () +{ + KateSessionChooserItem *item = (KateSessionChooserItem *) m_sessions->selectedItem (); + + if (!item) + return 0; + + return item->session; +} + +void KateSessionOpenDialog::slotUser1 () +{ + done (resultCancel); +} + +void KateSessionOpenDialog::slotUser2 () +{ + done (resultOk); +} + +//END OPEN DIALOG + +//BEGIN MANAGE DIALOG + +KateSessionManageDialog::KateSessionManageDialog (QWidget *parent) + : KDialogBase ( parent + , "" + , true + , i18n ("Manage Sessions") + , KDialogBase::User1 + , KDialogBase::User1 + , false + , KStdGuiItem::close () + ) +{ + QHBox *page = new QHBox (this); + page->setMinimumSize (400, 200); + setMainWidget(page); + + QHBox *hb = new QHBox (page); + hb->setSpacing (KDialog::spacingHint()); + + m_sessions = new KListView (hb); + m_sessions->addColumn (i18n("Session Name")); + m_sessions->addColumn (i18n("Open Documents")); + m_sessions->setResizeMode (QListView::AllColumns); + m_sessions->setSelectionMode (QListView::Single); + m_sessions->setAllColumnsShowFocus (true); + + connect (m_sessions, SIGNAL(selectionChanged()), this, SLOT(selectionChanged())); + + updateSessionList (); + + QWidget *vb = new QWidget (hb); + QVBoxLayout *vbl = new QVBoxLayout (vb); + vbl->setSpacing (KDialog::spacingHint()); + + m_rename = new KPushButton (i18n("&Rename..."), vb); + connect (m_rename, SIGNAL(clicked()), this, SLOT(rename())); + vbl->addWidget (m_rename); + + m_del = new KPushButton (KStdGuiItem::del (), vb); + connect (m_del, SIGNAL(clicked()), this, SLOT(del())); + vbl->addWidget (m_del); + + vbl->addStretch (); + + // trigger action update + selectionChanged (); +} + +KateSessionManageDialog::~KateSessionManageDialog () +{ +} + +void KateSessionManageDialog::slotUser1 () +{ + done (0); +} + + +void KateSessionManageDialog::selectionChanged () +{ + KateSessionChooserItem *item = (KateSessionChooserItem *) m_sessions->selectedItem (); + + m_rename->setEnabled (item && item->session->sessionFileRelative() != "default.katesession"); + m_del->setEnabled (item && item->session->sessionFileRelative() != "default.katesession"); +} + +void KateSessionManageDialog::rename () +{ + KateSessionChooserItem *item = (KateSessionChooserItem *) m_sessions->selectedItem (); + + if (!item || item->session->sessionFileRelative() == "default.katesession") + return; + + bool ok = false; + QString name = KInputDialog::getText (i18n("Specify New Name for Session"), i18n("Session name:"), item->session->sessionName(), &ok); + + if (!ok) + return; + + if (name.isEmpty()) + { + KMessageBox::error (0, i18n("To save a session, you must specify a name."), i18n ("Missing Session Name")); + return; + } + + item->session->rename (name); + updateSessionList (); +} + +void KateSessionManageDialog::del () +{ + KateSessionChooserItem *item = (KateSessionChooserItem *) m_sessions->selectedItem (); + + if (!item || item->session->sessionFileRelative() == "default.katesession") + return; + + QFile::remove (item->session->sessionFile()); + KateSessionManager::self()->updateSessionList (); + updateSessionList (); +} + +void KateSessionManageDialog::updateSessionList () +{ + m_sessions->clear (); + + KateSessionList &slist (KateSessionManager::self()->sessionList()); + for (unsigned int i=0; i < slist.count(); ++i) + { + new KateSessionChooserItem (m_sessions, slist[i]); + } +} + +//END MANAGE DIALOG + + +KateSessionsAction::KateSessionsAction(const QString& text, QObject* parent, const char* name ) + : KActionMenu(text, parent, name) +{ + connect(popupMenu(),SIGNAL(aboutToShow()),this,SLOT(slotAboutToShow())); +} + +void KateSessionsAction::slotAboutToShow() +{ + popupMenu()->clear (); + + KateSessionList &slist (KateSessionManager::self()->sessionList()); + for (unsigned int i=0; i < slist.count(); ++i) + { + popupMenu()->insertItem ( + slist[i]->sessionName(), + this, SLOT (openSession (int)), 0, + i ); + } +} + +void KateSessionsAction::openSession (int i) +{ + KateSessionList &slist (KateSessionManager::self()->sessionList()); + + if ((uint)i >= slist.count()) + return; + + KateSessionManager::self()->activateSession(slist[(uint)i]); +} +// kate: space-indent on; indent-width 2; replace-tabs on; mixed-indent off; diff --git a/kate/app/katesession.h b/kate/app/katesession.h new file mode 100644 index 000000000..899daff53 --- /dev/null +++ b/kate/app/katesession.h @@ -0,0 +1,418 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Christoph Cullmann <cullmann@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __KATE_SESSION_H__ +#define __KATE_SESSION_H__ + +#include "katemain.h" + +#include <kdialogbase.h> +#include <ksimpleconfig.h> +#include <ksharedptr.h> +#include <kaction.h> + +#include <qobject.h> +#include <qvaluelist.h> + +class KateSessionManager; + +class KDirWatch; +class KListView; +class KPushButton; + +class QCheckBox; + +class KateSession : public KShared +{ + public: + /** + * Define a Shared-Pointer type + */ + typedef KSharedPtr<KateSession> Ptr; + + public: + /** + * create a session from given file + * @param fileName session filename, relative + * @param name session name + * @param manager pointer to the manager + */ + KateSession (KateSessionManager *manager, const QString &fileName, const QString &name); + + /** + * init the session object, after construction or create + */ + void init (); + + /** + * destruct me + */ + ~KateSession (); + + /** + * session filename, absolute, calculated out of relative filename + session dir + * @return absolute path to session file + */ + QString sessionFile () const; + + /** + * relative session filename + * @return relative filename for this session + */ + const QString &sessionFileRelative () const { return m_sessionFileRel; } + + /** + * session name + * @return name for this session + */ + const QString &sessionName () const { return m_sessionName; } + + /** + * is this a valid session? if not, don't use any session if this is + * the active one + */ + bool isNew () const { return m_sessionName.isEmpty(); } + + /** + * create the session file, if not existing + * @param name name for this session + * @param force force to create new file + * @return true if created, false if no creation needed + */ + bool create (const QString &name, bool force = false); + + /** + * rename this session + * @param name new name + * @return success + */ + bool rename (const QString &name); + + /** + * config to read + * on first access, will create the config object, delete will be done automagic + * return 0 if we have no file to read config from atm + * @return config to read from + */ + KConfig *configRead (); + + /** + * config to write + * on first access, will create the config object, delete will be done automagic + * return 0 if we have no file to write config to atm + * @return config to write from + */ + KConfig *configWrite (); + + /** + * count of documents in this session + * @return documents count + */ + unsigned int documents () const { return m_documents; } + + private: + /** + * session filename, in local location we can write to + * relative filename to the session dirs :) + */ + QString m_sessionFileRel; + + /** + * session name, extracted from the file, to display to the user + */ + QString m_sessionName; + + /** + * number of document of this session + */ + unsigned int m_documents; + + /** + * KateSessionMananger + */ + KateSessionManager *m_manager; + + /** + * simpleconfig to read from + */ + KSimpleConfig *m_readConfig; + + /** + * simpleconfig to write to + */ + KSimpleConfig *m_writeConfig; +}; + +typedef QValueList<KateSession::Ptr> KateSessionList; + +class KateSessionManager : public QObject +{ + Q_OBJECT + + public: + KateSessionManager(QObject *parent); + ~KateSessionManager(); + + /** + * allow access to this :) + * @return instance of the session manager + */ + static KateSessionManager *self(); + + /** + * allow access to the session list + * kept up to date by watching the dir + */ + inline KateSessionList & sessionList () { updateSessionList (); return m_sessionList; } + + /** + * activate a session + * first, it will look if a session with this name exists in list + * if yes, it will use this session, else it will create a new session file + * @param session session to activate + * @param closeLast try to close last session or not? + * @param saveLast try to save last session or not? + * @param loadNew load new session stuff? + */ + void activateSession (KateSession::Ptr session, bool closeLast = true, bool saveLast = true, bool loadNew = true); + + /** + * create a new session + * @param name session name + */ + KateSession::Ptr createSession (const QString &name); + + /** + * return session with given name + * if no existing session matches, create new one with this name + * @param name session name + */ + KateSession::Ptr giveSession (const QString &name); + + /** + * save current session + * for sessions without filename: save nothing + * @param tryAsk should we ask user if needed? + * @param rememberAsLast remember this session as last used? + * @return success + */ + bool saveActiveSession (bool tryAsk = false, bool rememberAsLast = false); + + /** + * return the current active session + * sessionFile == empty means we have no session around for this instance of kate + * @return session active atm + */ + inline KateSession::Ptr activeSession () { return m_activeSession; } + + /** + * session dir + * @return global session dir + */ + inline const QString &sessionsDir () const { return m_sessionsDir; } + + /** + * initial session chooser, on app start + * @return success, if false, app should exit + */ + bool chooseSession (); + + public slots: + /** + * try to start a new session + * asks user first for name + */ + void sessionNew (); + + /** + * try to open a existing session + */ + void sessionOpen (); + + /** + * try to save current session + */ + void sessionSave (); + + /** + * try to save as current session + */ + void sessionSaveAs (); + + /** + * show dialog to manage our sessions + */ + void sessionManage (); + + private slots: + void dirty (const QString &path); + + public: + /** + * trigger update of session list + */ + void updateSessionList (); + + private: + /** + * absolute path to dir in home dir where to store the sessions + */ + QString m_sessionsDir; + + /** + * list of current available sessions + */ + KateSessionList m_sessionList; + + /** + * current active session + */ + KateSession::Ptr m_activeSession; +}; + +class KateSessionChooser : public KDialogBase +{ + Q_OBJECT + + public: + KateSessionChooser (QWidget *parent, const QString &lastSession); + ~KateSessionChooser (); + + KateSession::Ptr selectedSession (); + + bool reopenLastSession (); + + enum { + resultQuit = QDialog::Rejected, + resultOpen, + resultNew, + resultNone + }; + + protected slots: + /** + * open session + */ + void slotUser1 (); + + /** + * new session + */ + void slotUser2 (); + + /** + * quit kate + */ + void slotUser3 (); + + /** + * selection has changed + */ + void selectionChanged (); + + private: + KListView *m_sessions; + QCheckBox *m_useLast; +}; + +class KateSessionOpenDialog : public KDialogBase +{ + Q_OBJECT + + public: + KateSessionOpenDialog (QWidget *parent); + ~KateSessionOpenDialog (); + + KateSession::Ptr selectedSession (); + + enum { + resultOk, + resultCancel + }; + + protected slots: + /** + * cancel pressed + */ + void slotUser1 (); + + /** + * ok pressed + */ + void slotUser2 (); + + private: + KListView *m_sessions; +}; + +class KateSessionManageDialog : public KDialogBase +{ + Q_OBJECT + + public: + KateSessionManageDialog (QWidget *parent); + ~KateSessionManageDialog (); + + protected slots: + /** + * close pressed + */ + void slotUser1 (); + + /** + * selection has changed + */ + void selectionChanged (); + + /** + * try to rename session + */ + void rename (); + + /** + * try to delete session + */ + void del (); + + private: + /** + * update our list + */ + void updateSessionList (); + + private: + KListView *m_sessions; + KPushButton *m_rename; + KPushButton *m_del; +}; + +class KateSessionsAction : public KActionMenu +{ + Q_OBJECT + + public: + KateSessionsAction(const QString& text, QObject* parent = 0, const char* name = 0); + ~KateSessionsAction (){;}; + + public slots: + void slotAboutToShow(); + + void openSession (int i); +}; + +#endif diff --git a/kate/app/katetabwidget.cpp b/kate/app/katetabwidget.cpp new file mode 100644 index 000000000..c24357be5 --- /dev/null +++ b/kate/app/katetabwidget.cpp @@ -0,0 +1,161 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2002,2003 Joseph Wenninger <jowenn@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "katetabwidget.h" +#include "katetabwidget.moc" + +#include <qtabbar.h> + +//BEGIN KateTabWidget + +KateTabWidget::KateTabWidget(QWidget* parent, const char* name) + : KTabWidget(parent,name) + , m_visibility (ShowWhenMoreThanOneTab) +{ + tabBar()->hide(); + + setHoverCloseButton(true); + + connect(this, SIGNAL(closeRequest(QWidget*)), this, SLOT(closeTab(QWidget*))); +} + +KateTabWidget::~KateTabWidget() +{ +} + +void KateTabWidget::closeTab(QWidget* w) +{ + w->close(); +} + +void KateTabWidget::addTab ( QWidget * child, const QString & label ) +{ + KTabWidget::addTab(child,label); + showPage(child); + maybeShow(); +} + +void KateTabWidget::addTab ( QWidget * child, const QIconSet & iconset, const QString & label ) +{ + KTabWidget::addTab(child,iconset,label); + showPage(child); + maybeShow(); +} + +void KateTabWidget::addTab ( QWidget * child, QTab * tab ) +{ + KTabWidget::addTab(child,tab); + showPage(child); + maybeShow(); +} + +void KateTabWidget::insertTab ( QWidget * child, const QString & label, int index) +{ + KTabWidget::insertTab(child,label,index); + showPage(child); + maybeShow(); + tabBar()->repaint(); +} + +void KateTabWidget::insertTab ( QWidget * child, const QIconSet & iconset, const QString & label, int index ) +{ + KTabWidget::insertTab(child,iconset,label,index); + showPage(child); + maybeShow(); + tabBar()->repaint(); +} + +void KateTabWidget::insertTab ( QWidget * child, QTab * tab, int index) +{ + KTabWidget::insertTab(child,tab,index); + showPage(child); + maybeShow(); + tabBar()->repaint(); +} + +void KateTabWidget::removePage ( QWidget * w ) +{ + KTabWidget::removePage(w); + maybeShow(); +} + +void KateTabWidget::maybeShow() +{ + switch (m_visibility) + { + case AlwaysShowTabs: + tabBar()->show(); + + // show/hide corner widgets + if (count() == 0) + setCornerWidgetVisibility(false); + else + setCornerWidgetVisibility(true); + + break; + + case ShowWhenMoreThanOneTab: + if (count()<2) tabBar()->hide(); + else tabBar()->show(); + + // show/hide corner widgets + if (count() < 2) + setCornerWidgetVisibility(false); + else + setCornerWidgetVisibility(true); + + break; + + case NeverShowTabs: + tabBar()->hide(); + break; + } +} + +void KateTabWidget::setCornerWidgetVisibility(bool visible) +{ + // there are two corner widgets: on TopLeft and on TopTight! + + if (cornerWidget(Qt::TopLeft) ) { + if (visible) + cornerWidget(Qt::TopLeft)->show(); + else + cornerWidget(Qt::TopLeft)->hide(); + } + + if (cornerWidget(Qt::TopRight) ) { + if (visible) + cornerWidget(Qt::TopRight)->show(); + else + cornerWidget(Qt::TopRight)->hide(); + } +} + +void KateTabWidget::setTabWidgetVisibility( TabWidgetVisibility visibility ) +{ + m_visibility = visibility; + maybeShow(); +} + +KateTabWidget::TabWidgetVisibility KateTabWidget::tabWidgetVisibility( ) const +{ + return m_visibility; +} + +//END KateTabWidget diff --git a/kate/app/katetabwidget.h b/kate/app/katetabwidget.h new file mode 100644 index 000000000..765f83fdb --- /dev/null +++ b/kate/app/katetabwidget.h @@ -0,0 +1,69 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2002,2003 Joseph Wenninger <jowenn@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __KATE_TABWIDGET_H__ +#define __KATE_TABWIDGET_H__ + +#include <ktabwidget.h> + +class KateTabWidget : public KTabWidget +{ + Q_OBJECT + + public: + enum TabWidgetVisibility { + AlwaysShowTabs = 0, + ShowWhenMoreThanOneTab = 1, + NeverShowTabs = 2 + }; + + public: + KateTabWidget(QWidget* parent, const char* name=0); + virtual ~KateTabWidget(); + + virtual void addTab ( QWidget * child, const QString & label ); + + virtual void addTab ( QWidget * child, const QIconSet & iconset, const QString & label ); + + virtual void addTab ( QWidget * child, QTab * tab ); + + virtual void insertTab ( QWidget * child, const QString & label, int index = -1 ); + + virtual void insertTab ( QWidget * child, const QIconSet & iconset, const QString & label, int index = -1 ); + + virtual void insertTab ( QWidget * child, QTab * tab, int index = -1 ); + + virtual void removePage ( QWidget * w ); + + TabWidgetVisibility tabWidgetVisibility() const; + + void setTabWidgetVisibility( TabWidgetVisibility ); + + private slots: + void closeTab(QWidget* w); + + private: + void maybeShow(); + void setCornerWidgetVisibility(bool visible); + + private: + TabWidgetVisibility m_visibility; +}; + +#endif diff --git a/kate/app/kateviewmanager.cpp b/kate/app/kateviewmanager.cpp new file mode 100644 index 000000000..39b6020ee --- /dev/null +++ b/kate/app/kateviewmanager.cpp @@ -0,0 +1,514 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +//BEGIN Includes +#include "kateviewmanager.h" +#include "kateviewmanager.moc" + +#include "katemainwindow.h" +#include "katedocmanager.h" +#include "kateviewspacecontainer.h" +#include "katetabwidget.h" + +#include <dcopclient.h> +#include <kaction.h> +#include <kcmdlineargs.h> +#include <kdebug.h> +#include <kdiroperator.h> +#include <kdockwidget.h> +#include <kencodingfiledialog.h> +#include <kiconloader.h> +#include <kglobal.h> +#include <klocale.h> +#include <ktoolbar.h> +#include <kmessagebox.h> +#include <ksimpleconfig.h> +#include <kstdaction.h> +#include <kstandarddirs.h> +#include <kglobalsettings.h> +#include <kstdaccel.h> + +#include <ktexteditor/encodinginterface.h> + +#include <qobjectlist.h> +#include <qstringlist.h> +#include <qfileinfo.h> +#include <qtoolbutton.h> +#include <qtooltip.h> +//END Includes + +KateViewManager::KateViewManager (KateMainWindow *parent) + : QObject (parent), + showFullPath(false), m_mainWindow(parent) +{ + // while init + m_init=true; + + // some stuff for the tabwidget + m_mainWindow->tabWidget()->setTabReorderingEnabled( true ); + + // important, set them up, as we use them in other methodes + setupActions (); + + guiMergedView=0; + + m_viewManager = new Kate::ViewManager (this); + m_currentContainer=0; + connect(m_mainWindow->tabWidget(),SIGNAL(currentChanged(QWidget*)),this,SLOT(tabChanged(QWidget*))); + slotNewTab(); + tabChanged(m_mainWindow->tabWidget()->currentPage()); + + // no memleaks + m_viewSpaceContainerList.setAutoDelete(true); + + // init done + m_init=false; +} + +KateViewManager::~KateViewManager () +{ + m_viewSpaceContainerList.setAutoDelete(false); +} + +void KateViewManager::setupActions () +{ + KAction *a; + + /** + * tabbing + */ + a=new KAction ( i18n("New Tab"),"tab_new", 0, this, SLOT(slotNewTab()), + m_mainWindow->actionCollection(), "view_new_tab" ); + + m_closeTab = new KAction ( i18n("Close Current Tab"),"tab_remove",0,this,SLOT(slotCloseTab()), + m_mainWindow->actionCollection(),"view_close_tab"); + + m_activateNextTab + = new KAction( i18n( "Activate Next Tab" ), + QApplication::reverseLayout() ? KStdAccel::tabPrev() : KStdAccel::tabNext(), + this, SLOT( activateNextTab() ), m_mainWindow->actionCollection(), "view_next_tab" ); + + m_activatePrevTab + = new KAction( i18n( "Activate Previous Tab" ), + QApplication::reverseLayout() ? KStdAccel::tabNext() : KStdAccel::tabPrev(), + this, SLOT( activatePrevTab() ), m_mainWindow->actionCollection(), "view_prev_tab" ); + + /** + * view splitting + */ + a=new KAction ( i18n("Split Ve&rtical"), "view_right", CTRL+SHIFT+Key_L, this, SLOT( + slotSplitViewSpaceVert() ), m_mainWindow->actionCollection(), "view_split_vert"); + + a->setWhatsThis(i18n("Split the currently active view vertically into two views.")); + + a=new KAction ( i18n("Split &Horizontal"), "view_bottom", CTRL+SHIFT+Key_T, this, SLOT( + slotSplitViewSpaceHoriz() ), m_mainWindow->actionCollection(), "view_split_horiz"); + + a->setWhatsThis(i18n("Split the currently active view horizontally into two views.")); + + m_closeView = new KAction ( i18n("Cl&ose Current View"), "view_remove", CTRL+SHIFT+Key_R, this, + SLOT( slotCloseCurrentViewSpace() ), m_mainWindow->actionCollection(), + "view_close_current_space" ); + + m_closeView->setWhatsThis(i18n("Close the currently active splitted view")); + + goNext=new KAction(i18n("Next View"),Key_F8,this, + SLOT(activateNextView()),m_mainWindow->actionCollection(),"go_next"); + + goNext->setWhatsThis(i18n("Make the next split view the active one.")); + + goPrev=new KAction(i18n("Previous View"),SHIFT+Key_F8, this, SLOT(activatePrevView()),m_mainWindow->actionCollection(),"go_prev"); + + goPrev->setWhatsThis(i18n("Make the previous split view the active one.")); + + /** + * buttons for tabbing + */ + QToolButton *b = new QToolButton( m_mainWindow->tabWidget() ); + connect( b, SIGNAL( clicked() ), + this, SLOT( slotNewTab() ) ); + b->setIconSet( SmallIcon( "tab_new" ) ); + b->adjustSize(); + QToolTip::add(b, i18n("Open a new tab")); + m_mainWindow->tabWidget()->setCornerWidget( b, TopLeft ); + + b = m_closeTabButton = new QToolButton( m_mainWindow->tabWidget() ); + connect( b, SIGNAL( clicked() ), + this, SLOT( slotCloseTab() ) ); + b->setIconSet( SmallIcon( "tab_remove" ) ); + b->adjustSize(); + QToolTip::add(b, i18n("Close the current tab")); + m_mainWindow->tabWidget()->setCornerWidget( b, TopRight ); +} + +void KateViewManager::updateViewSpaceActions () +{ + if (!m_currentContainer) return; + + m_closeView->setEnabled (m_currentContainer->viewSpaceCount() > 1); + goNext->setEnabled (m_currentContainer->viewSpaceCount() > 1); + goPrev->setEnabled (m_currentContainer->viewSpaceCount() > 1); +} + +void KateViewManager::tabChanged(QWidget* widget) { + KateViewSpaceContainer *container=static_cast<KateViewSpaceContainer*>(widget->qt_cast("KateViewSpaceContainer")); + Q_ASSERT(container); + m_currentContainer=container; + + if (container) { + container->reactivateActiveView(); + + } + + m_closeTab->setEnabled(m_mainWindow->tabWidget()->count() > 1); + m_activateNextTab->setEnabled(m_mainWindow->tabWidget()->count() > 1); + m_activatePrevTab->setEnabled(m_mainWindow->tabWidget()->count() > 1); + m_closeTabButton->setEnabled (m_mainWindow->tabWidget()->count() > 1); + + updateViewSpaceActions (); +} + +void KateViewManager::slotNewTab() +{ + uint documentNumber=0; + + if (m_currentContainer) + { + if (m_currentContainer->activeView()) + documentNumber = m_currentContainer->activeView()->getDoc()->documentNumber(); + } + + KateViewSpaceContainer *container=new KateViewSpaceContainer (m_mainWindow->tabWidget(), this); + m_viewSpaceContainerList.append(container); + m_mainWindow->tabWidget()->addTab (container, ""); + + connect(container,SIGNAL(viewChanged()),this,SIGNAL(viewChanged())); + connect(container,SIGNAL(viewChanged()),m_viewManager,SIGNAL(viewChanged())); + + if (!m_init) + { + container->activateView(documentNumber); + container->setShowFullPath(showFullPath); + m_mainWindow->slotWindowActivated (); + } +} + +void KateViewManager::slotCloseTab() +{ + if (m_viewSpaceContainerList.count() <= 1) return; + if (!m_currentContainer) return; + + int pos = m_viewSpaceContainerList.find (m_currentContainer); + + if (pos == -1) + return; + + if (guiMergedView) + m_mainWindow->guiFactory()->removeClient (guiMergedView ); + + m_viewSpaceContainerList.remove (pos); + + if ((uint)pos >= m_viewSpaceContainerList.count()) + pos = m_viewSpaceContainerList.count()-1; + + tabChanged(m_viewSpaceContainerList.at (pos)); +} + +void KateViewManager::activateNextTab() +{ + if( m_mainWindow->tabWidget()->count() <= 1 ) return; + + int iTab = m_mainWindow->tabWidget()->currentPageIndex(); + + iTab++; + + if( iTab == m_mainWindow->tabWidget()->count() ) + iTab = 0; + + m_mainWindow->tabWidget()->setCurrentPage( iTab ); +} + +void KateViewManager::activatePrevTab() +{ + if( m_mainWindow->tabWidget()->count() <= 1 ) return; + + int iTab = m_mainWindow->tabWidget()->currentPageIndex(); + + iTab--; + + if( iTab == -1 ) + iTab = m_mainWindow->tabWidget()->count() - 1; + + m_mainWindow->tabWidget()->setCurrentPage( iTab ); +} + +void KateViewManager::activateSpace (Kate::View* v) +{ + if (m_currentContainer) { + m_currentContainer->activateSpace(v); + } +} + +void KateViewManager::activateView ( Kate::View *view ) { + if (m_currentContainer) { + m_currentContainer->activateView(view); + } +} + +KateViewSpace* KateViewManager::activeViewSpace () +{ + if (m_currentContainer) { + return m_currentContainer->activeViewSpace(); + } + return 0L; +} + +Kate::View* KateViewManager::activeView () +{ + if (m_currentContainer) { + return m_currentContainer->activeView(); + } + return 0L; +} + +void KateViewManager::setActiveSpace ( KateViewSpace* vs ) +{ + if (m_currentContainer) { + m_currentContainer->setActiveSpace(vs); + } + +} + +void KateViewManager::setActiveView ( Kate::View* view ) +{ + if (m_currentContainer) { + m_currentContainer->setActiveView(view); + } + +} + + +void KateViewManager::activateView( uint documentNumber ) +{ + if (m_currentContainer) { + m_currentContainer->activateView(documentNumber); + } +} + +uint KateViewManager::viewCount () +{ + uint viewCount=0; + for (uint i=0;i<m_viewSpaceContainerList.count();i++) { + viewCount+=m_viewSpaceContainerList.at(i)->viewCount(); + } + return viewCount; + +} + +uint KateViewManager::viewSpaceCount () +{ + uint viewSpaceCount=0; + for (uint i=0;i<m_viewSpaceContainerList.count();i++) { + viewSpaceCount+=m_viewSpaceContainerList.at(i)->viewSpaceCount(); + } + return viewSpaceCount; +} + +void KateViewManager::setViewActivationBlocked (bool block) +{ + for (uint i=0;i<m_viewSpaceContainerList.count();i++) + m_viewSpaceContainerList.at(i)->m_blockViewCreationAndActivation=block; +} + +void KateViewManager::activateNextView() +{ + if (m_currentContainer) { + m_currentContainer->activateNextView(); + } +} + +void KateViewManager::activatePrevView() +{ + if (m_currentContainer) { + m_currentContainer->activatePrevView(); + } +} + +void KateViewManager::closeViews(uint documentNumber) +{ + for (uint i=0;i<m_viewSpaceContainerList.count();i++) { + m_viewSpaceContainerList.at(i)->closeViews(documentNumber); + } + tabChanged(m_currentContainer); +} + +void KateViewManager::slotDocumentNew () +{ + if (m_currentContainer) m_currentContainer->createView (); +} + +void KateViewManager::slotDocumentOpen () +{ + Kate::View *cv = activeView(); + + if (cv) { + KEncodingFileDialog::Result r=KEncodingFileDialog::getOpenURLsAndEncoding( + (cv ? KTextEditor::encodingInterface(cv->document())->encoding() : Kate::Document::defaultEncoding()), + (cv ? cv->document()->url().url() : QString::null), + QString::null,m_mainWindow,i18n("Open File")); + + uint lastID = 0; + for (KURL::List::Iterator i=r.URLs.begin(); i != r.URLs.end(); ++i) + lastID = openURL( *i, r.encoding, false ); + + if (lastID > 0) + activateView (lastID); + } +} + +void KateViewManager::slotDocumentClose () +{ + // no active view, do nothing + if (!activeView()) return; + + // prevent close document if only one view alive and the document of + // it is not modified and empty !!! + if ( (KateDocManager::self()->documents() == 1) + && !activeView()->getDoc()->isModified() + && activeView()->getDoc()->url().isEmpty() + && (activeView()->getDoc()->length() == 0) ) + { + activeView()->getDoc()->closeURL(); + return; + } + + // close document + KateDocManager::self()->closeDocument (activeView()->getDoc()); +} + +uint KateViewManager::openURL (const KURL &url, const QString& encoding, bool activate, bool isTempFile ) +{ + uint id = 0; + Kate::Document *doc = KateDocManager::self()->openURL (url, encoding, &id, isTempFile ); + + if (!doc->url().isEmpty()) + m_mainWindow->fileOpenRecent->addURL( doc->url() ); + + if (activate) + activateView( id ); + + return id; +} + +void KateViewManager::openURL (const KURL &url) +{ + openURL (url, QString::null); +} + +void KateViewManager::removeViewSpace (KateViewSpace *viewspace) +{ + if (m_currentContainer) { + m_currentContainer->removeViewSpace(viewspace); + } +} + +void KateViewManager::slotCloseCurrentViewSpace() +{ + if (m_currentContainer) { + m_currentContainer->slotCloseCurrentViewSpace(); + } +} + +void KateViewManager::slotSplitViewSpaceVert() +{ + if (m_currentContainer) { + m_currentContainer->slotSplitViewSpaceVert(); + } +} + +void KateViewManager::slotSplitViewSpaceHoriz() +{ + if (m_currentContainer) { + m_currentContainer->slotSplitViewSpaceHoriz(); + } +} + +void KateViewManager::setShowFullPath( bool enable ) +{ + showFullPath=enable; + for (uint i=0;i<m_viewSpaceContainerList.count();i++) { + m_viewSpaceContainerList.at(i)->setShowFullPath(enable); + } + m_mainWindow->slotWindowActivated (); + } + +/** + * session config functions + */ +// FIXME 3.0 - make those config goups more streamlined: "objN:objN..." +void KateViewManager::saveViewConfiguration(KConfig *config,const QString& grp) +{ + // Use the same group name for view configuration as usual for sessions. + // (When called by session manager grp is a 1-based index for the main window) + QString group = grp; + bool ok = false; + int n = group.toInt( &ok ); + if ( ok ) + group = QString( "MainWindow%1" ).arg( n-1 ); + + config->setGroup(group); + config->writeEntry("ViewSpaceContainers",m_viewSpaceContainerList.count()); + config->writeEntry("Active ViewSpaceContainer", m_mainWindow->tabWidget()->currentPageIndex()); + for (uint i=0;i<m_viewSpaceContainerList.count();i++) { + m_viewSpaceContainerList.at(i)->saveViewConfiguration(config,group+QString(":ViewSpaceContainer-%1:").arg(i)); + } +} + +void KateViewManager::restoreViewConfiguration (KConfig *config, const QString& grp) +{ + // Use the same group name for view configuration as usual for sessions. + // (When called by session manager grp is a 1-based index for the main window) + QString group = grp; + bool ok = false; + int n = group.toInt( &ok ); + if ( ok ) + group = QString( "MainWindow%1" ).arg( n-1 ); + + config->setGroup(group); + uint tabCount=config->readNumEntry("ViewSpaceContainers",0); + int activeOne=config->readNumEntry("Active ViewSpaceContainer",0); + if (tabCount==0) return; + m_viewSpaceContainerList.at(0)->restoreViewConfiguration(config,group+QString(":ViewSpaceContainer-0:")); + for (uint i=1;i<tabCount;i++) { + slotNewTab(); + m_viewSpaceContainerList.at(i)->restoreViewConfiguration(config,group+QString(":ViewSpaceContainer-%1:").arg(i)); + } + + if (activeOne != m_mainWindow->tabWidget()->currentPageIndex()) + m_mainWindow->tabWidget()->setCurrentPage (activeOne); + + updateViewSpaceActions(); +} + +KateMainWindow *KateViewManager::mainWindow() { + return m_mainWindow; +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kate/app/kateviewmanager.h b/kate/app/kateviewmanager.h new file mode 100644 index 000000000..6eb33e9f5 --- /dev/null +++ b/kate/app/kateviewmanager.h @@ -0,0 +1,154 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __KATE_VIEWMANAGER_H__ +#define __KATE_VIEWMANAGER_H__ + +#include "katemain.h" +#include "../interfaces/viewmanager.h" + +#include <kate/view.h> +#include <kate/document.h> +#include <qguardedptr.h> + +class KateMainWindow; +class KateViewSpaceContainer; + +class KConfig; +class KAction; + +class QToolButton; + +class KateViewManager : public QObject +{ + Q_OBJECT + + public: + KateViewManager (KateMainWindow *parent); + ~KateViewManager (); + + Kate::ViewManager *viewManager () const { return m_viewManager; }; + + KateViewSpaceContainer *activeContainer () { return m_currentContainer; } + + QPtrList<KateViewSpaceContainer> *containers() { return &m_viewSpaceContainerList; } + + void updateViewSpaceActions (); + + private: + /** + * create all actions needed for the view manager + */ + void setupActions (); + + public: + /* This will save the splitter configuration */ + void saveViewConfiguration(KConfig *config,const QString& group); + + /* restore it */ + void restoreViewConfiguration (KConfig *config,const QString& group); + + uint openURL (const KURL &url, const QString& encoding, bool activate = true, bool isTempFile=false); + + public slots: + void openURL (const KURL &url); + + private: + void removeViewSpace (KateViewSpace *viewspace); + + bool showFullPath; + + public: + Kate::View* activeView (); + KateViewSpace* activeViewSpace (); + + uint viewCount (); + uint viewSpaceCount (); + + void setViewActivationBlocked (bool block); + + public: + void closeViews(uint documentNumber); + KateMainWindow *mainWindow(); + + private slots: + void activateView ( Kate::View *view ); + void activateSpace ( Kate::View* v ); + + void tabChanged(QWidget*); + + public slots: + bool getShowFullPath() const { return showFullPath; } + + void activateView ( uint documentNumber ); + void activateView ( int documentNumber ) { activateView((uint) documentNumber); }; + + void slotDocumentNew (); + void slotDocumentOpen (); + void slotDocumentClose (); + + /** Splits the active viewspace horizontally */ + void slotSplitViewSpaceHoriz (); + /** Splits the active viewspace vertically */ + void slotSplitViewSpaceVert (); + + void slotNewTab(); + void slotCloseTab (); + void activateNextTab (); + void activatePrevTab (); + + void slotCloseCurrentViewSpace(); + + void setActiveSpace ( KateViewSpace* vs ); + void setActiveView ( Kate::View* view ); + + void setShowFullPath(bool enable); + + void activateNextView(); + void activatePrevView(); + + protected: + friend class KateViewSpaceContainer; + + QGuardedPtr<Kate::View> guiMergedView; + + signals: + void statusChanged (Kate::View *, int, int, int, bool, int, const QString &); + void statChanged (); + void viewChanged (); + + private: + Kate::ViewManager *m_viewManager; + QPtrList<KateViewSpaceContainer> m_viewSpaceContainerList; + KateViewSpaceContainer *m_currentContainer; + + KateMainWindow *m_mainWindow; + bool m_init; + + QToolButton *m_closeTabButton; + KAction *m_closeView; + KAction *m_closeTab; + KAction *m_activateNextTab; + KAction *m_activatePrevTab; + KAction *goNext; + KAction *goPrev; +}; + +#endif diff --git a/kate/app/kateviewspace.cpp b/kate/app/kateviewspace.cpp new file mode 100644 index 000000000..9efb155e4 --- /dev/null +++ b/kate/app/kateviewspace.cpp @@ -0,0 +1,422 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001, 2005 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kateviewspace.h" +#include "kateviewspace.moc" + +#include "katemainwindow.h" +#include "kateviewspacecontainer.h" +#include "katedocmanager.h" +#include "kateapp.h" +#include "katesession.h" + +#include <kiconloader.h> +#include <klocale.h> +#include <ksqueezedtextlabel.h> +#include <kconfig.h> +#include <kdebug.h> + +#include <qwidgetstack.h> +#include <qpainter.h> +#include <qlabel.h> +#include <qcursor.h> +#include <qpopupmenu.h> +#include <qpixmap.h> + +//BEGIN KVSSBSep +/* + "KateViewSpaceStatusBarSeparator" + A 2 px line to separate the statusbar from the view. + It is here to compensate for the lack of a frame in the view, + I think Kate looks very nice this way, as QScrollView with frame + looks slightly clumsy... + Slight 3D effect. I looked for suitable QStyle props or methods, + but found none, though maybe it should use QStyle::PM_DefaultFrameWidth + for height (TRY!). + It does look a bit funny with flat styles (Light, .Net) as is, + but there are on methods to paint panel lines separately. And, + those styles tends to look funny on their own, as a light line + in a 3D frame next to a light contents widget is not functional. + Also, QStatusBar is up to now completely ignorant to style. + -anders +*/ +class KVSSBSep : public QWidget { +public: + KVSSBSep( KateViewSpace *parent=0) : QWidget(parent) + { + setFixedHeight( 2 ); + } +protected: + void paintEvent( QPaintEvent *e ) + { + QPainter p( this ); + p.setPen( colorGroup().shadow() ); + p.drawLine( e->rect().left(), 0, e->rect().right(), 0 ); + p.setPen( ((KateViewSpace*)parentWidget())->isActiveSpace() ? colorGroup().light() : colorGroup().midlight() ); + p.drawLine( e->rect().left(), 1, e->rect().right(), 1 ); + } +}; +//END KVSSBSep + +//BEGIN KateViewSpace +KateViewSpace::KateViewSpace( KateViewSpaceContainer *viewManager, + QWidget* parent, const char* name ) + : QVBox(parent, name), + m_viewManager( viewManager ) +{ + mViewList.setAutoDelete(false); + + stack = new QWidgetStack( this ); + setStretchFactor(stack, 1); + stack->setFocus(); + //sep = new KVSSBSep( this ); + mStatusBar = new KateVSStatusBar(this); + mIsActiveSpace = false; + mViewCount = 0; + + setMinimumWidth (mStatusBar->minimumWidth()); + m_group = QString::null; +} + +KateViewSpace::~KateViewSpace() +{ +} + +void KateViewSpace::polish() +{ + mStatusBar->show(); +} + +void KateViewSpace::addView(Kate::View* v, bool show) +{ + // restore the config of this view if possible + if ( !m_group.isEmpty() ) + { + QString fn = v->getDoc()->url().prettyURL(); + if ( ! fn.isEmpty() ) + { + QString vgroup = QString("%1 %2").arg(m_group).arg(fn); + + KateSession::Ptr as = KateSessionManager::self()->activeSession (); + if ( as->configRead() && as->configRead()->hasGroup( vgroup ) ) + { + as->configRead()->setGroup( vgroup ); + v->readSessionConfig ( as->configRead() ); + } + } + } + + uint id = mViewList.count(); + stack->addWidget(v, id); + if (show) { + mViewList.append(v); + showView( v ); + } + else { + Kate::View* c = mViewList.current(); + mViewList.prepend( v ); + showView( c ); + } +} + +void KateViewSpace::removeView(Kate::View* v) +{ + disconnect( v->getDoc(), SIGNAL(modifiedChanged()), + mStatusBar, SLOT(modifiedChanged()) ); + + bool active = ( v == currentView() ); + + mViewList.remove (v); + stack->removeWidget (v); + + if ( ! active ) + return; + + if (currentView() != 0L) + showView(mViewList.current()); + else if (mViewList.count() > 0) + showView(mViewList.last()); +} + +bool KateViewSpace::showView(Kate::View* v) +{ + return showView( v->getDoc()->documentNumber() ); +} + +bool KateViewSpace::showView(uint documentNumber) +{ + QPtrListIterator<Kate::View> it (mViewList); + it.toLast(); + for( ; it.current(); --it ) { + if (((Kate::Document*)it.current()->getDoc())->documentNumber() == documentNumber) { + if ( currentView() ) + disconnect( currentView()->getDoc(), SIGNAL(modifiedChanged()), + mStatusBar, SLOT(modifiedChanged()) ); + + Kate::View* kv = it.current(); + connect( kv->getDoc(), SIGNAL(modifiedChanged()), + mStatusBar, SLOT(modifiedChanged()) ); + + mViewList.removeRef( kv ); + mViewList.append( kv ); + stack->raiseWidget( kv ); + kv->show(); + mStatusBar->modifiedChanged(); + return true; + } + } + return false; +} + + +Kate::View* KateViewSpace::currentView() +{ + if (mViewList.count() > 0) + return (Kate::View*)stack->visibleWidget(); + + return 0L; +} + +bool KateViewSpace::isActiveSpace() +{ + return mIsActiveSpace; +} + +void KateViewSpace::setActive( bool active, bool ) +{ + mIsActiveSpace = active; + + // change the statusbar palette and make sure it gets updated + QPalette pal( palette() ); + if ( ! active ) + { + pal.setColor( QColorGroup::Background, pal.active().mid() ); + pal.setColor( QColorGroup::Light, pal.active().midlight() ); + } + + mStatusBar->setPalette( pal ); + mStatusBar->update(); + //sep->update(); +} + +bool KateViewSpace::event( QEvent *e ) +{ + if ( e->type() == QEvent::PaletteChange ) + { + setActive( mIsActiveSpace ); + return true; + } + return QVBox::event( e ); +} + +void KateViewSpace::slotStatusChanged (Kate::View *view, int r, int c, int ovr, bool block, int mod, const QString &msg) +{ + if ((QWidgetStack *)view->parentWidget() != stack) + return; + mStatusBar->setStatus( r, c, ovr, block, mod, msg ); +} + +void KateViewSpace::saveConfig ( KConfig* config, int myIndex ,const QString& viewConfGrp) +{ +// kdDebug()<<"KateViewSpace::saveConfig("<<myIndex<<", "<<viewConfGrp<<") - currentView: "<<currentView()<<")"<<endl; + QString group = QString(viewConfGrp+"-ViewSpace %1").arg( myIndex ); + + config->setGroup (group); + config->writeEntry ("Count", mViewList.count()); + + if (currentView()) + config->writeEntry( "Active View", currentView()->getDoc()->url().prettyURL() ); + + // Save file list, includeing cursor position in this instance. + QPtrListIterator<Kate::View> it(mViewList); + + int idx = 0; + for (; it.current(); ++it) + { + if ( !it.current()->getDoc()->url().isEmpty() ) + { + config->setGroup( group ); + config->writeEntry( QString("View %1").arg( idx ), it.current()->getDoc()->url().prettyURL() ); + + // view config, group: "ViewSpace <n> url" + QString vgroup = QString("%1 %2").arg(group).arg(it.current()->getDoc()->url().prettyURL()); + config->setGroup( vgroup ); + it.current()->writeSessionConfig( config ); + } + + idx++; + } +} + +void KateViewSpace::modifiedOnDisc(Kate::Document *, bool, unsigned char) +{ + if ( currentView() ) + mStatusBar->updateMod( currentView()->getDoc()->isModified() ); +} + +void KateViewSpace::restoreConfig ( KateViewSpaceContainer *viewMan, KConfig* config, const QString &group ) +{ + config->setGroup (group); + QString fn = config->readEntry( "Active View" ); + + if ( !fn.isEmpty() ) + { + Kate::Document *doc = KateDocManager::self()->findDocumentByUrl (KURL(fn)); + + if (doc) + { + // view config, group: "ViewSpace <n> url" + QString vgroup = QString("%1 %2").arg(group).arg(fn); + config->setGroup( vgroup ); + + viewMan->createView (doc); + + Kate::View *v = viewMan->activeView (); + + if (v) + v->readSessionConfig( config ); + } + } + + if (mViewList.isEmpty()) + viewMan->createView (KateDocManager::self()->document(0)); + + m_group = group; // used for restroing view configs later +} +//END KateViewSpace + +//BEGIN KateVSStatusBar +KateVSStatusBar::KateVSStatusBar ( KateViewSpace *parent, const char *name ) + : KStatusBar( parent, name ), + m_viewSpace( parent ) +{ + m_lineColLabel = new QLabel( this ); + addWidget( m_lineColLabel, 0, false ); + m_lineColLabel->setAlignment( Qt::AlignCenter ); + m_lineColLabel->installEventFilter( this ); + + m_modifiedLabel = new QLabel( QString(" "), this ); + addWidget( m_modifiedLabel, 0, false ); + m_modifiedLabel->setAlignment( Qt::AlignCenter ); + m_modifiedLabel->installEventFilter( this ); + + m_insertModeLabel = new QLabel( i18n(" INS "), this ); + addWidget( m_insertModeLabel, 0, false ); + m_insertModeLabel->setAlignment( Qt::AlignCenter ); + m_insertModeLabel->installEventFilter( this ); + + m_selectModeLabel = new QLabel( i18n(" NORM "), this ); + addWidget( m_selectModeLabel, 0, false ); + m_selectModeLabel->setAlignment( Qt::AlignCenter ); + m_selectModeLabel->installEventFilter( this ); + + m_fileNameLabel=new KSqueezedTextLabel( this ); + addWidget( m_fileNameLabel, 1, true ); + m_fileNameLabel->setMinimumSize( 0, 0 ); + m_fileNameLabel->setSizePolicy(QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Fixed )); + m_fileNameLabel->setAlignment( /*Qt::AlignRight*/Qt::AlignLeft ); + m_fileNameLabel->installEventFilter( this ); + + installEventFilter( this ); + m_modPm = SmallIcon("modified"); + m_modDiscPm = SmallIcon("modonhd"); + m_modmodPm = SmallIcon("modmod"); + m_noPm = SmallIcon("null"); +} + +KateVSStatusBar::~KateVSStatusBar () +{ +} + +void KateVSStatusBar::setStatus( int r, int c, int ovr, bool block, int, const QString &msg ) +{ + m_lineColLabel->setText( + i18n(" Line: %1 Col: %2 ").arg(KGlobal::locale()->formatNumber(r+1, 0)) + .arg(KGlobal::locale()->formatNumber(c+1, 0)) ); + + if (ovr == 0) + m_insertModeLabel->setText( i18n(" R/O ") ); + else if (ovr == 1) + m_insertModeLabel->setText( i18n(" OVR ") ); + else if (ovr == 2) + m_insertModeLabel->setText( i18n(" INS ") ); + +// updateMod( mod ); + + m_selectModeLabel->setText( block ? i18n(" BLK ") : i18n(" NORM ") ); + + m_fileNameLabel->setText( msg ); +} + +void KateVSStatusBar::updateMod( bool mod ) +{ + Kate::View *v = m_viewSpace->currentView(); + if ( v ) + { + const KateDocumentInfo *info + = KateDocManager::self()->documentInfo ( v->getDoc() ); + + bool modOnHD = info && info->modifiedOnDisc; + + m_modifiedLabel->setPixmap( + mod ? + info && modOnHD ? + m_modmodPm : + m_modPm : + info && modOnHD ? + m_modDiscPm : + m_noPm + ); + } +} + +void KateVSStatusBar::modifiedChanged() +{ + Kate::View *v = m_viewSpace->currentView(); + if ( v ) + updateMod( v->getDoc()->isModified() ); +} + +void KateVSStatusBar::showMenu() +{ + KMainWindow* mainWindow = static_cast<KMainWindow*>( topLevelWidget() ); + QPopupMenu* menu = static_cast<QPopupMenu*>( mainWindow->factory()->container("viewspace_popup", mainWindow ) ); + + if (menu) + menu->exec(QCursor::pos()); +} + +bool KateVSStatusBar::eventFilter(QObject*,QEvent *e) +{ + if (e->type()==QEvent::MouseButtonPress) + { + if ( m_viewSpace->currentView() ) + m_viewSpace->currentView()->setFocus(); + + if ( ((QMouseEvent*)e)->button()==RightButton) + showMenu(); + + return true; + } + + return false; +} +//END KateVSStatusBar +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kate/app/kateviewspace.h b/kate/app/kateviewspace.h new file mode 100644 index 000000000..a07b5f6da --- /dev/null +++ b/kate/app/kateviewspace.h @@ -0,0 +1,121 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __KATE_VIEWSPACE_H__ +#define __KATE_VIEWSPACE_H__ + +#include "katemain.h" + +#include <kate/view.h> +#include <kate/document.h> + +#include <qptrlist.h> +#include <qwidget.h> +#include <qvbox.h> +#include <kstatusbar.h> + +class KVSSBSep; + +class KConfig; +class KSqueezedTextLabel; +class KateViewSpaceContainer; + +class KateVSStatusBar : public KStatusBar +{ + Q_OBJECT + + public: + KateVSStatusBar ( KateViewSpace *parent = 0L, const char *name = 0L ); + virtual ~KateVSStatusBar (); + + public slots: + void setStatus( int r, int c, int ovr, bool block, int mod, const QString &msg ); + void updateMod( bool ); + /** + * changed the modified icon according to document state. + * @since Kate 2.4 + */ + void modifiedChanged(); + + protected: + virtual bool eventFilter (QObject*,QEvent *); + virtual void showMenu (); + + private: + QLabel* m_lineColLabel; + QLabel* m_modifiedLabel; + QLabel* m_insertModeLabel; + QLabel* m_selectModeLabel; + KSqueezedTextLabel* m_fileNameLabel; + QPixmap m_modPm, m_modDiscPm, m_modmodPm, m_noPm; + class KateViewSpace *m_viewSpace; +}; + +class KateViewSpace : public QVBox +{ + friend class KateViewSpaceContainer; + friend class KateVSStatusBar; + + Q_OBJECT + + public: + KateViewSpace(KateViewSpaceContainer *, QWidget* parent=0, const char* name=0); + ~KateViewSpace(); + bool isActiveSpace(); + void setActive(bool b, bool showled=false); + QWidgetStack* stack; + void addView(Kate::View* v, bool show=true); + void removeView(Kate::View* v); + bool showView(Kate::View* v); + bool showView(uint docID); + Kate::View* currentView(); + int viewCount() const { return mViewList.count(); } + + void saveConfig (KConfig* config, int myIndex,const QString& viewConfGrp); + void restoreConfig ( class KateViewSpaceContainer *viewMan, KConfig* config, const QString &group ); + + + protected: + /** reimplemented to catch QEvent::PaletteChange, + since we use a modified palette for the statusbar */ + bool event( QEvent * ); + + private: + bool mIsActiveSpace; + KateVSStatusBar* mStatusBar; + QLabel* l; + QPixmap i_active; + QPixmap i_empty; + QPtrList<Kate::View> mViewList; + int mViewCount; + KVSSBSep *sep; + KateViewSpaceContainer *m_viewManager; + QString m_group; + + private slots: + void slotStatusChanged (Kate::View *view, int r, int c, int ovr, bool block, int mod, const QString &msg); + + public slots: + void polish(); + void modifiedOnDisc(Kate::Document *, bool, unsigned char); +}; + +#endif +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kate/app/kateviewspacecontainer.cpp b/kate/app/kateviewspacecontainer.cpp new file mode 100644 index 000000000..08a3bf6f6 --- /dev/null +++ b/kate/app/kateviewspacecontainer.cpp @@ -0,0 +1,758 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +//BEGIN Includes +#include "kateviewspacecontainer.h" +#include "kateviewspacecontainer.moc" + +#include "katetabwidget.h" +#include "katemainwindow.h" +#include "katedocmanager.h" +#include "kateviewmanager.h" +#include "kateviewspace.h" + +#include <dcopclient.h> +#include <kaction.h> +#include <kcmdlineargs.h> +#include <kdebug.h> +#include <kdiroperator.h> +#include <kdockwidget.h> +#include <kencodingfiledialog.h> +#include <kiconloader.h> +#include <kglobal.h> +#include <klocale.h> +#include <ktoolbar.h> +#include <kmessagebox.h> +#include <ksimpleconfig.h> +#include <kstdaction.h> +#include <kstandarddirs.h> +#include <kglobalsettings.h> +#include <kstringhandler.h> + +#include <ktexteditor/encodinginterface.h> + +#include <qlayout.h> +#include <qobjectlist.h> +#include <qstringlist.h> +#include <qvbox.h> +#include <qtimer.h> +#include <qfileinfo.h> + +//END Includes + +KateViewSpaceContainer::KateViewSpaceContainer (QWidget *parent, KateViewManager *viewManager) + : QVBox (parent) + , m_viewManager(viewManager) + , m_blockViewCreationAndActivation (false) + , m_activeViewRunning (false) + , m_pendingViewCreation(false) +{ + // no memleaks + m_viewList.setAutoDelete(true); + m_viewSpaceList.setAutoDelete(true); + + KateViewSpace* vs = new KateViewSpace( this, this ); + connect(this, SIGNAL(statusChanged(Kate::View *, int, int, int, bool, int, const QString&)), vs, SLOT(slotStatusChanged(Kate::View *, int, int, int, bool, int, const QString&))); + vs->setActive( true ); + m_viewSpaceList.append(vs); + connect( this, SIGNAL(viewChanged()), this, SLOT(slotViewChanged()) ); + connect(KateDocManager::self(), SIGNAL(initialDocumentReplaced()), this, SIGNAL(viewChanged())); + + connect(KateDocManager::self(),SIGNAL(documentCreated(Kate::Document *)),this,SLOT(documentCreated(Kate::Document *))); + connect(KateDocManager::self(),SIGNAL(documentDeleted(uint)),this,SLOT(documentDeleted(uint))); +} + +KateViewSpaceContainer::~KateViewSpaceContainer () +{ + m_viewList.setAutoDelete(false); + m_viewSpaceList.setAutoDelete(false); +} + +void KateViewSpaceContainer::documentCreated (Kate::Document *doc) +{ + if (m_blockViewCreationAndActivation) return; + + if (!activeView()) + activateView (doc->documentNumber()); +} + +void KateViewSpaceContainer::documentDeleted (uint) +{ + if (m_blockViewCreationAndActivation) return; + + // just for the case we close a document out of many and this was the active one + // if all docs are closed, this will be handled by the documentCreated + if (!activeView() && (KateDocManager::self()->documents() > 0)) + createView (KateDocManager::self()->document(KateDocManager::self()->documents()-1)); +} + +bool KateViewSpaceContainer::createView ( Kate::Document *doc ) +{ + if (m_blockViewCreationAndActivation) return false; + + // create doc + if (!doc) + doc = KateDocManager::self()->createDoc (); + + // create view + Kate::View *view = (Kate::View *) doc->createView (this, 0L); + + m_viewList.append (view); + + // disable settings dialog action + view->actionCollection()->remove (view->actionCollection()->action( "set_confdlg" )); + + // popup menu + view->installPopup ((QPopupMenu*)(mainWindow()->factory()->container("ktexteditor_popup", mainWindow())) ); + + connect(view->getDoc(),SIGNAL(nameChanged(Kate::Document *)),this,SLOT(statusMsg())); + connect(view,SIGNAL(cursorPositionChanged()),this,SLOT(statusMsg())); + connect(view,SIGNAL(newStatus()),this,SLOT(statusMsg())); + connect(view->getDoc(), SIGNAL(undoChanged()), this, SLOT(statusMsg())); + connect(view,SIGNAL(dropEventPass(QDropEvent *)), mainWindow(),SLOT(slotDropEvent(QDropEvent *))); + connect(view,SIGNAL(gotFocus(Kate::View *)),this,SLOT(activateSpace(Kate::View *))); + + activeViewSpace()->addView( view ); + activateView( view ); + connect( doc, SIGNAL(modifiedOnDisc(Kate::Document *, bool, unsigned char)), + activeViewSpace(), SLOT(modifiedOnDisc(Kate::Document *, bool, unsigned char)) ); + + return true; +} + +bool KateViewSpaceContainer::deleteView (Kate::View *view, bool delViewSpace) +{ + if (!view) return true; + + KateViewSpace *viewspace = (KateViewSpace *)view->parentWidget()->parentWidget(); + + viewspace->removeView (view); + + mainWindow()->guiFactory ()->removeClient (view); + + // remove view from list and memory !! + m_viewList.remove (view); + + if (delViewSpace) + if ( viewspace->viewCount() == 0 ) + removeViewSpace( viewspace ); + + return true; +} + +KateViewSpace* KateViewSpaceContainer::activeViewSpace () +{ + QPtrListIterator<KateViewSpace> it(m_viewSpaceList); + + for (; it.current(); ++it) + { + if ( it.current()->isActiveSpace() ) + return it.current(); + } + + if (m_viewSpaceList.count() > 0) + { + m_viewSpaceList.first()->setActive( true ); + return m_viewSpaceList.first(); + } + + return 0L; +} + +Kate::View* KateViewSpaceContainer::activeView () +{ + if (m_activeViewRunning) + return 0L; + + m_activeViewRunning = true; + + for (QPtrListIterator<Kate::View> it(m_viewList); it.current(); ++it) + { + if ( it.current()->isActive() ) + { + m_activeViewRunning = false; + return it.current(); + } + } + + // if we get to here, no view isActive() + // first, try to get one from activeViewSpace() + KateViewSpace* vs; + if ( (vs = activeViewSpace()) ) + { + if ( vs->currentView() ) + { + activateView (vs->currentView()); + + m_activeViewRunning = false; + return vs->currentView(); + } + } + + // last attempt: just pick first + if (m_viewList.count() > 0) + { + activateView (m_viewList.first()); + + m_activeViewRunning = false; + return m_viewList.first(); + } + + m_activeViewRunning = false; + + // no views exists! + return 0L; +} + +void KateViewSpaceContainer::setActiveSpace ( KateViewSpace* vs ) +{ + if (activeViewSpace()) + activeViewSpace()->setActive( false ); + + vs->setActive( true, viewSpaceCount() > 1 ); +} + +void KateViewSpaceContainer::setActiveView ( Kate::View* view ) +{ + if (activeView()) + activeView()->setActive( false ); + + view->setActive( true ); +} + +void KateViewSpaceContainer::activateSpace (Kate::View* v) +{ + if (!v) return; + + KateViewSpace* vs = (KateViewSpace*)v->parentWidget()->parentWidget(); + + if (!vs->isActiveSpace()) { + setActiveSpace (vs); + activateView(v); + } +} + +void KateViewSpaceContainer::reactivateActiveView() { + Kate::View *view=activeView(); + if (view) { + view->setActive(false); + activateView(view); + } else if (m_pendingViewCreation) { + m_pendingViewCreation=false; + disconnect(m_pendingDocument,SIGNAL(nameChanged(Kate::Document *)),this,SLOT(slotPendingDocumentNameChanged())); + createView(m_pendingDocument); + } +} + +void KateViewSpaceContainer::activateView ( Kate::View *view ) +{ + if (!view) return; + + if (!view->isActive()) + { + if ( !activeViewSpace()->showView (view) ) + { + // since it wasn't found, give'em a new one + createView ( view->getDoc() ); + return; + } + + setActiveView (view); + m_viewList.findRef (view); + + mainWindow()->toolBar ()->setUpdatesEnabled (false); + + if (m_viewManager->guiMergedView) + mainWindow()->guiFactory()->removeClient (m_viewManager->guiMergedView ); + + m_viewManager->guiMergedView = view; + + if (!m_blockViewCreationAndActivation) + mainWindow()->guiFactory ()->addClient( view ); + + mainWindow()->toolBar ()->setUpdatesEnabled (true); + + statusMsg(); + + emit viewChanged (); + } + + KateDocManager::self()->setActiveDocument(view->getDoc()); +} + +void KateViewSpaceContainer::activateView( uint documentNumber ) +{ + if ( activeViewSpace()->showView(documentNumber) ) { + activateView( activeViewSpace()->currentView() ); + } + else + { + QPtrListIterator<Kate::View> it(m_viewList); + for ( ;it.current(); ++it) + { + if ( it.current()->getDoc()->documentNumber() == documentNumber ) + { + createView( it.current()->getDoc() ); + return; + } + } + + Kate::Document *d = (Kate::Document *)KateDocManager::self()->documentWithID(documentNumber); + createView (d); + } +} + +uint KateViewSpaceContainer::viewCount () +{ + return m_viewList.count(); +} + +uint KateViewSpaceContainer::viewSpaceCount () +{ + return m_viewSpaceList.count(); +} + +void KateViewSpaceContainer::slotViewChanged() +{ + if ( activeView() && !activeView()->hasFocus()) + activeView()->setFocus(); +} + +void KateViewSpaceContainer::activateNextView() +{ + uint i = m_viewSpaceList.find (activeViewSpace())+1; + + if (i >= m_viewSpaceList.count()) + i=0; + + setActiveSpace (m_viewSpaceList.at(i)); + activateView(m_viewSpaceList.at(i)->currentView()); +} + +void KateViewSpaceContainer::activatePrevView() +{ + int i = m_viewSpaceList.find (activeViewSpace())-1; + + if (i < 0) + i=m_viewSpaceList.count()-1; + + setActiveSpace (m_viewSpaceList.at(i)); + activateView(m_viewSpaceList.at(i)->currentView()); +} + +void KateViewSpaceContainer::closeViews(uint documentNumber) +{ + QPtrList<Kate::View> closeList; + + for (uint z=0 ; z < m_viewList.count(); z++) + { + Kate::View* current = m_viewList.at(z); + if ( current->getDoc()->documentNumber() == documentNumber ) + { + closeList.append (current); + } + } + + while ( !closeList.isEmpty() ) + { + Kate::View *view = closeList.first(); + deleteView (view, true); + closeList.removeFirst(); + } + + if (m_blockViewCreationAndActivation) return; + QTimer::singleShot(0,this,SIGNAL(viewChanged())); + //emit m_viewManager->viewChanged (); +} + +void KateViewSpaceContainer::slotPendingDocumentNameChanged() { + QString c; + if (m_pendingDocument->url().isEmpty() || (!showFullPath)) + { + c = m_pendingDocument->docName(); + } + else + { + c = m_pendingDocument->url().prettyURL(); + } + setCaption(KStringHandler::lsqueeze(c,32)); +} + +void KateViewSpaceContainer::statusMsg () +{ + if (!activeView()) return; + + Kate::View* v = activeView(); + + bool readOnly = !v->getDoc()->isReadWrite(); + uint config = v->getDoc()->configFlags(); + + int ovr = 0; + if (readOnly) + ovr = 0; + else + { + if (config & Kate::Document::cfOvr) + { + ovr=1; + } + else + { + ovr=2; + } + } + + int mod = (int)v->getDoc()->isModified(); + bool block=v->getDoc()->blockSelectionMode(); + + QString c; + if (v->getDoc()->url().isEmpty() || (!showFullPath)) + { + c = v->getDoc()->docName(); + } + else + { + c = v->getDoc()->url().prettyURL(); + } + + m_viewManager->mainWindow()->tabWidget()->changeTab (this, KStringHandler::lsqueeze(c,32)); + emit statusChanged (v, v->cursorLine(), v->cursorColumn(), ovr,block, mod, KStringHandler::lsqueeze(c,64)); + emit statChanged (); +} + +void KateViewSpaceContainer::splitViewSpace( KateViewSpace* vs, + bool isHoriz, + bool atTop) +{ +// kdDebug(13001)<<"splitViewSpace()"<<endl; + + if (!activeView()) return; + if (!vs) vs = activeViewSpace(); + + bool isFirstTime = vs->parentWidget() == this; + + QValueList<int> psizes; + if ( ! isFirstTime ) + if ( QSplitter *ps = static_cast<QSplitter*>(vs->parentWidget()->qt_cast("QSplitter")) ) + psizes = ps->sizes(); + + Qt::Orientation o = isHoriz ? Qt::Vertical : Qt::Horizontal; + KateMDI::Splitter* s = new KateMDI::Splitter(o, vs->parentWidget()); + s->setOpaqueResize( KGlobalSettings::opaqueResize() ); + + if (! isFirstTime) { + // anders: make sure the split' viewspace is always + // correctly positioned. + // If viewSpace is the first child, the new splitter must be moveToFirst'd + if ( !((KateMDI::Splitter*)vs->parentWidget())->isLastChild( vs ) ) + ((KateMDI::Splitter*)s->parentWidget())->moveToFirst( s ); + } + vs->reparent( s, 0, QPoint(), true ); + KateViewSpace* vsNew = new KateViewSpace( this, s ); + + if (atTop) + s->moveToFirst( vsNew ); + + if (!isFirstTime) + if (QSplitter *ps = static_cast<QSplitter*>(s->parentWidget()->qt_cast("QSplitter")) ) + ps->setSizes( psizes ); + + s->show(); + + QValueList<int> sizes; + int space = 50;//isHoriz ? s->parentWidget()->height()/2 : s->parentWidget()->width()/2; + sizes << space << space; + s->setSizes( sizes ); + + connect(this, SIGNAL(statusChanged(Kate::View *, int, int, int, bool, int, const QString &)), vsNew, SLOT(slotStatusChanged(Kate::View *, int, int,int, bool, int, const QString &))); + m_viewSpaceList.append( vsNew ); + activeViewSpace()->setActive( false ); + vsNew->setActive( true, true ); + vsNew->show(); + + createView (activeView()->getDoc()); + + if (this == m_viewManager->activeContainer()) + m_viewManager->updateViewSpaceActions (); + +// kdDebug(13001)<<"splitViewSpace() - DONE!"<<endl; +} + +void KateViewSpaceContainer::removeViewSpace (KateViewSpace *viewspace) +{ + // abort if viewspace is 0 + if (!viewspace) return; + + // abort if this is the last viewspace + if (m_viewSpaceList.count() < 2) return; + + KateMDI::Splitter* p = (KateMDI::Splitter*)viewspace->parentWidget(); + + // find out if it is the first child for repositioning + // see below + bool pIsFirst = false; + + // save some size information + KateMDI::Splitter* pp=0L; + QValueList<int> ppsizes; + if (m_viewSpaceList.count() > 2 && p->parentWidget() != this) + { + pp = (KateMDI::Splitter*)p->parentWidget(); + ppsizes = pp->sizes(); + pIsFirst = !pp->isLastChild( p ); // simple logic, right- + } + + // Figure out where to put views that are still needed + KateViewSpace* next; + if (m_viewSpaceList.find(viewspace) == 0) + next = m_viewSpaceList.next(); + else + next = m_viewSpaceList.prev(); + + // Reparent views in viewspace that are last views, delete the rest. + int vsvc = viewspace->viewCount(); + while (vsvc > 0) + { + if (viewspace->currentView()) + { + Kate::View* v = viewspace->currentView(); + + if (v->isLastView()) + { + viewspace->removeView(v); + next->addView( v, false ); + } + else + { + deleteView( v, false ); + } + } + vsvc = viewspace->viewCount(); + } + + m_viewSpaceList.remove( viewspace ); + + // reparent the other sibling of the parent. + while (p->children ()) + { + QWidget* other = ((QWidget *)(( QPtrList<QObject>*)p->children())->first()); + + other->reparent( p->parentWidget(), 0, QPoint(), true ); + // We also need to find the right viewspace to become active + if (pIsFirst) + ((KateMDI::Splitter*)p->parentWidget())->moveToFirst( other ); + if ( other->isA("KateViewSpace") ) { + setActiveSpace( (KateViewSpace*)other ); + } + else { + QObjectList* l = other->queryList( "KateViewSpace" ); + if ( l->first() != 0 ) { // I REALLY hope so! + setActiveSpace( (KateViewSpace*)l->first() ); + } + delete l; + } + } + + delete p; + + if (!ppsizes.isEmpty()) + pp->setSizes( ppsizes ); + + // find the view that is now active. + Kate::View* v = activeViewSpace()->currentView(); + if ( v ) + activateView( v ); + + if (this == m_viewManager->activeContainer()) + m_viewManager->updateViewSpaceActions (); + + emit viewChanged(); +} + +void KateViewSpaceContainer::slotCloseCurrentViewSpace() +{ + removeViewSpace(activeViewSpace()); +} + +void KateViewSpaceContainer::setShowFullPath( bool enable ) +{ + showFullPath = enable; + statusMsg (); + //m_mainWindow->slotWindowActivated (); +} + +/** + * session config functions + */ + +void KateViewSpaceContainer::saveViewConfiguration(KConfig *config,const QString& group) +{ + bool weHaveSplittersAlive (viewSpaceCount() > 1); + + config->setGroup (group); //"View Configuration"); + config->writeEntry ("Splitters", weHaveSplittersAlive); + + // no splitters around + if (!weHaveSplittersAlive) + { + config->writeEntry("Active Viewspace", 0); + m_viewSpaceList.first()->saveConfig ( config, 0,group ); + + return; + } + + // I need the first splitter, the one which has this as parent. + KateMDI::Splitter* s; + QObjectList *l = queryList("KateMDI::Splitter", 0, false, false); + QObjectListIt it( *l ); + + if ( (s = (KateMDI::Splitter*)it.current()) != 0 ) + saveSplitterConfig( s, 0, config , group); + + delete l; +} + +void KateViewSpaceContainer::restoreViewConfiguration (KConfig *config, const QString& group) +{ + config->setGroup(group); + //config->setGroup ("View Configuration"); + + // no splitters around, ohhh :() + if (!config->readBoolEntry ("Splitters")) + { + // only add the new views needed, let the old stay, won't hurt if one around + m_viewSpaceList.first ()->restoreConfig (this, config, QString(group+"-ViewSpace 0")); + } + else + { + // send all views + their gui to **** ;) + for (uint i=0; i < m_viewList.count(); i++) + mainWindow()->guiFactory ()->removeClient (m_viewList.at(i)); + + m_viewList.clear (); + + // cu viewspaces + m_viewSpaceList.clear(); + + // call restoreSplitter for Splitter 0 + restoreSplitter( config, QString(group+"-Splitter 0"), this,group ); + } + + // finally, make the correct view active. + config->setGroup (group); +/* + KateViewSpace *vs = m_viewSpaceList.at( config->readNumEntry("Active ViewSpace") ); + if ( vs ) + activateSpace( vs->currentView() ); + */ +} + + +void KateViewSpaceContainer::saveSplitterConfig( KateMDI::Splitter* s, int idx, KConfig* config, const QString& viewConfGrp ) +{ + QString grp = QString(viewConfGrp+"-Splitter %1").arg(idx); + config->setGroup(grp); + + // Save sizes, orient, children for this splitter + config->writeEntry( "Sizes", s->sizes() ); + config->writeEntry( "Orientation", s->orientation() ); + + QStringList childList; + // a katesplitter has two children, of which one may be a KateSplitter. + const QObjectList* l = s->children(); + QObjectListIt it( *l ); + QObject* obj; + for (; it.current(); ++it) { + obj = it.current(); + QString n; // name for child list, see below + // For KateViewSpaces, ask them to save the file list. + if ( obj->isA("KateViewSpace") ) { + n = QString(viewConfGrp+"-ViewSpace %1").arg( m_viewSpaceList.find((KateViewSpace*)obj) ); + ((KateViewSpace*)obj)->saveConfig ( config, m_viewSpaceList.find((KateViewSpace*)obj), viewConfGrp); + // save active viewspace + if ( ((KateViewSpace*)obj)->isActiveSpace() ) { + config->setGroup(viewConfGrp); + config->writeEntry("Active Viewspace", m_viewSpaceList.find((KateViewSpace*)obj) ); + } + } + // For KateSplitters, recurse + else if ( obj->isA("KateMDI::Splitter") ) { + idx++; + saveSplitterConfig( (KateMDI::Splitter*)obj, idx, config,viewConfGrp); + n = QString(viewConfGrp+"-Splitter %1").arg( idx ); + } + // make sure list goes in right place! + if (!n.isEmpty()) { + if ( childList.count() > 0 && ! s->isLastChild( (QWidget*)obj ) ) + childList.prepend( n ); + else + childList.append( n ); + } + } + + // reset config group. + config->setGroup(grp); + config->writeEntry("Children", childList); +} + +void KateViewSpaceContainer::restoreSplitter( KConfig* config, const QString &group, QWidget* parent, const QString& viewConfGrp) +{ + config->setGroup( group ); + + KateMDI::Splitter* s = new KateMDI::Splitter((Qt::Orientation)config->readNumEntry("Orientation"), parent); + + QStringList children = config->readListEntry( "Children" ); + for (QStringList::Iterator it=children.begin(); it!=children.end(); ++it) + { + // for a viewspace, create it and open all documents therein. + if ( (*it).startsWith(viewConfGrp+"-ViewSpace") ) + { + KateViewSpace* vs = new KateViewSpace( this, s ); + + connect(this, SIGNAL(statusChanged(Kate::View *, int, int, int, bool, int, const QString &)), vs, SLOT(slotStatusChanged(Kate::View *, int, int, int, bool, int, const QString &))); + + if (m_viewSpaceList.isEmpty()) + vs->setActive (true); + + m_viewSpaceList.append( vs ); + + vs->show(); + setActiveSpace( vs ); + + vs->restoreConfig (this, config, *it); + } + else + { + // for a splitter, recurse. + restoreSplitter( config, QString(*it), s, viewConfGrp ); + } + } + + // set sizes + config->setGroup( group ); + s->setSizes( config->readIntListEntry("Sizes") ); + s->show(); +} + +KateMainWindow *KateViewSpaceContainer::mainWindow() { + return m_viewManager->mainWindow(); +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kate/app/kateviewspacecontainer.h b/kate/app/kateviewspacecontainer.h new file mode 100644 index 000000000..e8c64bd4e --- /dev/null +++ b/kate/app/kateviewspacecontainer.h @@ -0,0 +1,161 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __KATE_VIEWSPACE_CONTAINER_H__ +#define __KATE_VIEWSPACE_CONTAINER_H__ + +#include "katemain.h" +#include "../interfaces/viewmanager.h" + +#include <kate/view.h> +#include <kate/document.h> + +#include "katemdi.h" + +class KConfig; +class KateMainWindow; + +class KateViewSpaceContainer: public QVBox +{ + Q_OBJECT + + friend class KateViewSpace; + friend class KateVSStatusBar; + + public: + KateViewSpaceContainer (QWidget *parent, KateViewManager *viewManager); + + ~KateViewSpaceContainer (); + + inline QPtrList<Kate::View> &viewList () { return m_viewList; }; + + public: + /* This will save the splitter configuration */ + void saveViewConfiguration(KConfig *config,const QString& group); + + /* restore it */ + void restoreViewConfiguration (KConfig *config,const QString& group); + + private: + /** + * create and activate a new view for doc, if doc == 0, then + * create a new document + */ + bool createView ( Kate::Document *doc =0L ); + + bool deleteView ( Kate::View *view, bool delViewSpace = true); + + void moveViewtoSplit (Kate::View *view); + void moveViewtoStack (Kate::View *view); + + /* Save the configuration of a single splitter. + * If child splitters are found, it calls it self with those as the argument. + * If a viewspace child is found, it is asked to save its filelist. + */ + void saveSplitterConfig(KateMDI::Splitter* s, int idx=0, KConfig* config=0L, const QString& viewConfGrp=""); + + /** Restore a single splitter. + * This is all the work is done for @see saveSplitterConfig() + */ + void restoreSplitter ( KConfig* config, const QString &group, QWidget* parent , const QString& viewConfGrp); + + void removeViewSpace (KateViewSpace *viewspace); + + bool showFullPath; + + public: + Kate::View* activeView (); + KateViewSpace* activeViewSpace (); + + uint viewCount (); + uint viewSpaceCount (); + + bool isViewActivationBlocked(){return m_blockViewCreationAndActivation;}; + + public: + void closeViews(uint documentNumber); + KateMainWindow *mainWindow(); + friend class KateViewManager; + + private slots: + void activateView ( Kate::View *view ); + void activateSpace ( Kate::View* v ); + void slotViewChanged(); + void reactivateActiveView(); + void slotPendingDocumentNameChanged(); + + void documentCreated (Kate::Document *doc); + void documentDeleted (uint docNumber); + + public slots: + /* Splits a KateViewSpace into two. + * The operation is performed by creating a KateMDI::Splitter in the parent of the KateViewSpace to be split, + * which is then moved to that splitter. Then a new KateViewSpace is created and added to the splitter, + * and a KateView is created to populate the new viewspace. The new KateView is made the active one, + * because createView() does that. + * If no viewspace is provided, the result of activeViewSpace() is used. + * The isHoriz, true pr default, decides the orientation of the splitting action. + * If atTop is true, the new viewspace will be moved to the first position in the new splitter. + * If a newViewUrl is provided, the new view will show the document in that URL if any, otherwise + * the document of the current view in the viewspace to be split is used. + */ + void splitViewSpace( KateViewSpace* vs=0L, bool isHoriz=true, bool atTop=false ); + + bool getShowFullPath() const { return showFullPath; } + + void activateView ( uint documentNumber ); + void activateView ( int documentNumber ) { activateView((uint) documentNumber); }; + + /** Splits the active viewspace horizontally */ + void slotSplitViewSpaceHoriz () { splitViewSpace(); } + /** Splits the active viewspace vertically */ + void slotSplitViewSpaceVert () { splitViewSpace( 0L, false ); } + + void slotCloseCurrentViewSpace(); + + void statusMsg (); + + void setActiveSpace ( KateViewSpace* vs ); + void setActiveView ( Kate::View* view ); + + void setShowFullPath(bool enable); + + void activateNextView(); + void activatePrevView(); + + signals: + void statusChanged (Kate::View *, int, int, int, bool, int, const QString &); + void statChanged (); + void viewChanged (); + + private: + KateViewManager *m_viewManager; + QPtrList<KateViewSpace> m_viewSpaceList; + QPtrList<Kate::View> m_viewList; + + bool m_blockViewCreationAndActivation; + + bool m_activeViewRunning; + + bool m_pendingViewCreation; + QGuardedPtr<Kate::Document> m_pendingDocument; +}; + +#endif diff --git a/kate/app/kbookmarkhandler.cpp b/kate/app/kbookmarkhandler.cpp new file mode 100644 index 000000000..ada4d7a21 --- /dev/null +++ b/kate/app/kbookmarkhandler.cpp @@ -0,0 +1,98 @@ +/* This file is part of the KDE project + Copyright (C) xxxx KFile Authors + Copyright (C) 2002 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "katefileselector.h" + +#include <stdio.h> +#include <stdlib.h> + +#include <qtextstream.h> + +#include <kbookmarkimporter.h> +#include <kpopupmenu.h> +#include <ksavefile.h> +#include <kstandarddirs.h> +#include <kdiroperator.h> +#include <kaction.h> + +#include "kbookmarkhandler.h" +#include "kbookmarkhandler.moc" + + +KBookmarkHandler::KBookmarkHandler( KateFileSelector *parent, KPopupMenu* kpopupmenu ) + : QObject( parent, "KBookmarkHandler" ), + KBookmarkOwner(), + mParent( parent ), + m_menu( kpopupmenu ), + m_importStream( 0L ) +{ + if (!m_menu) + m_menu = new KPopupMenu( parent, "bookmark menu" ); + + QString file = locate( "data", "kate/fsbookmarks.xml" ); + if ( file.isEmpty() ) + file = locateLocal( "data", "kate/fsbookmarks.xml" ); + + KBookmarkManager *manager = KBookmarkManager::managerForFile( file, false); + manager->setUpdate( true ); + manager->setShowNSBookmarks( false ); + + m_bookmarkMenu = new KBookmarkMenu( manager, this, m_menu, 0, true ); +} + +KBookmarkHandler::~KBookmarkHandler() +{ + // delete m_bookmarkMenu; ### +} + +QString KBookmarkHandler::currentURL() const +{ + return mParent->dirOperator()->url().url(); +} + + +void KBookmarkHandler::slotNewBookmark( const QString& /*text*/, + const QCString& url, + const QString& additionalInfo ) +{ + *m_importStream << "<bookmark icon=\"" << KMimeType::iconForURL( KURL( url ) ); + *m_importStream << "\" href=\"" << QString::fromUtf8(url) << "\">\n"; + *m_importStream << "<title>" << (additionalInfo.isEmpty() ? QString::fromUtf8(url) : additionalInfo) << "</title>\n</bookmark>\n"; +} + +void KBookmarkHandler::slotNewFolder( const QString& text, bool /*open*/, + const QString& /*additionalInfo*/ ) +{ + *m_importStream << "<folder icon=\"bookmark_folder\">\n<title=\""; + *m_importStream << text << "\">\n"; +} + +void KBookmarkHandler::newSeparator() +{ + *m_importStream << "<separator/>\n"; +} + +void KBookmarkHandler::endFolder() +{ + *m_importStream << "</folder>\n"; +} + +void KBookmarkHandler::virtual_hook( int id, void* data ) +{ KBookmarkOwner::virtual_hook( id, data ); } + diff --git a/kate/app/kbookmarkhandler.h b/kate/app/kbookmarkhandler.h new file mode 100644 index 000000000..15697e283 --- /dev/null +++ b/kate/app/kbookmarkhandler.h @@ -0,0 +1,72 @@ +/* This file is part of the KDE project + Copyright (C) xxxx KFile Authors + Copyright (C) 2002 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _KBOOKMARKHANDLER_H_ +#define _KBOOKMARKHANDLER_H_ + +#include <kbookmarkmanager.h> +#include <kbookmarkmenu.h> + +class KateFileSelector; + +class KActionMenu; + +class QTextStream; +class KPopupMenu; + +class KBookmarkHandler : public QObject, public KBookmarkOwner +{ + Q_OBJECT + +public: + KBookmarkHandler( KateFileSelector *parent, KPopupMenu *kpopupmenu=0 ); + ~KBookmarkHandler(); + + // KBookmarkOwner interface: + virtual void openBookmarkURL( const QString& url ) { emit openURL( url ); } + virtual QString currentURL() const; + + KPopupMenu *menu() const { return m_menu; } + +signals: + void openURL( const QString& url ); + +private slots: + void slotNewBookmark( const QString& text, const QCString& url, + const QString& additionalInfo ); + void slotNewFolder( const QString& text, bool open, + const QString& additionalInfo ); + void newSeparator(); + void endFolder(); + +protected: + virtual void virtual_hook( int id, void* data ); + +private: + KateFileSelector *mParent; + KPopupMenu *m_menu; + KBookmarkMenu *m_bookmarkMenu; + + QTextStream *m_importStream; + + //class KBookmarkHandlerPrivate *d; +}; + + +#endif // _KBOOKMARKHANDLER_H_ diff --git a/kate/app/kwritemain.cpp b/kate/app/kwritemain.cpp new file mode 100644 index 000000000..5dab9340d --- /dev/null +++ b/kate/app/kwritemain.cpp @@ -0,0 +1,712 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kwritemain.h" +#include "kwritemain.moc" + +#include <kate/document.h> +#include <kate/view.h> + +#include <ktexteditor/configinterface.h> +#include <ktexteditor/sessionconfiginterface.h> +#include <ktexteditor/viewcursorinterface.h> +#include <ktexteditor/printinterface.h> +#include <ktexteditor/encodinginterface.h> +#include <ktexteditor/editorchooser.h> +#include <ktexteditor/popupmenuinterface.h> + +#include <kio/netaccess.h> + +#include <kdeversion.h> +#include <dcopclient.h> +#include <kurldrag.h> +#include <kencodingfiledialog.h> +#include <kdiroperator.h> +#include <kiconloader.h> +#include <kaboutdata.h> +#include <kstatusbar.h> +#include <kstdaction.h> +#include <kaction.h> +#include <kdebug.h> +#include <kglobal.h> +#include <kapplication.h> +#include <klocale.h> +#include <kurl.h> +#include <kconfig.h> +#include <kcmdlineargs.h> +#include <kmessagebox.h> +#include <kkeydialog.h> +#include <kedittoolbar.h> +#include <kparts/event.h> +#include <kmenubar.h> + +#include <qdropsite.h> +#include <qdragobject.h> +#include <qvbox.h> +#include <qtextcodec.h> +#include <qlayout.h> + +// StatusBar field IDs +#define KWRITE_ID_GEN 1 + +QPtrList<KTextEditor::Document> KWrite::docList; +QPtrList<KWrite> KWrite::winList; + +KWrite::KWrite (KTextEditor::Document *doc) + : m_view(0), + m_recentFiles(0), + m_paShowPath(0), + m_paShowStatusBar(0) +{ + if ( !doc ) + { + if ( !(doc = KTextEditor::EditorChooser::createDocument(0,"KTextEditor::Document")) ) + { + KMessageBox::error(this, i18n("A KDE text-editor component could not be found;\n" + "please check your KDE installation.")); + kapp->exit(1); + } + + docList.append(doc); + } + + m_view = doc->createView (this, 0L); + + setCentralWidget(m_view); + + setupActions(); + setupStatusBar(); + + setAcceptDrops(true); + + connect(m_view,SIGNAL(newStatus()),this,SLOT(newCaption())); + connect(m_view,SIGNAL(viewStatusMsg(const QString &)),this,SLOT(newStatus(const QString &))); + connect(m_view->document(),SIGNAL(fileNameChanged()),this,SLOT(newCaption())); + connect(m_view->document(),SIGNAL(fileNameChanged()),this,SLOT(slotFileNameChanged())); + connect(m_view,SIGNAL(dropEventPass(QDropEvent *)),this,SLOT(slotDropEvent(QDropEvent *))); + + setXMLFile( "kwriteui.rc" ); + createShellGUI( true ); + guiFactory()->addClient( m_view ); + + // install a working kate part popup dialog thingy + if (static_cast<Kate::View*>(m_view->qt_cast("Kate::View"))) + static_cast<Kate::View*>(m_view->qt_cast("Kate::View"))->installPopup ((QPopupMenu*)(factory()->container("ktexteditor_popup", this)) ); + + // init with more usefull size, stolen from konq :) + if (!initialGeometrySet()) + resize( QSize(700, 480).expandedTo(minimumSizeHint())); + + // call it as last thing, must be sure everything is already set up ;) + setAutoSaveSettings (); + + readConfig (); + + winList.append (this); + + show (); +} + +KWrite::~KWrite() +{ + winList.remove (this); + + if (m_view->document()->views().count() == 1) + { + docList.remove(m_view->document()); + delete m_view->document(); + } + + kapp->config()->sync (); +} + +void KWrite::setupActions() +{ + KStdAction::close( this, SLOT(slotFlush()), actionCollection(), "file_close" )->setWhatsThis(i18n("Use this to close the current document")); + + // setup File menu + KStdAction::print(this, SLOT(printDlg()), actionCollection())->setWhatsThis(i18n("Use this command to print the current document")); + KStdAction::openNew( this, SLOT(slotNew()), actionCollection(), "file_new" )->setWhatsThis(i18n("Use this command to create a new document")); + KStdAction::open( this, SLOT( slotOpen() ), actionCollection(), "file_open" )->setWhatsThis(i18n("Use this command to open an existing document for editing")); + + m_recentFiles = KStdAction::openRecent(this, SLOT(slotOpen(const KURL&)), + actionCollection()); + m_recentFiles->setWhatsThis(i18n("This lists files which you have opened recently, and allows you to easily open them again.")); + + KAction *a=new KAction(i18n("&New Window"), "window_new", 0, this, SLOT(newView()), + actionCollection(), "view_new_view"); + a->setWhatsThis(i18n("Create another view containing the current document")); + + a=new KAction(i18n("Choose Editor..."),0,this,SLOT(changeEditor()), + actionCollection(),"settings_choose_editor"); + a->setWhatsThis(i18n("Override the system wide setting for the default editing component")); + + KStdAction::quit(this, SLOT(close()), actionCollection())->setWhatsThis(i18n("Close the current document view")); + + // setup Settings menu + setStandardToolBarMenuEnabled(true); + + m_paShowStatusBar = KStdAction::showStatusbar(this, SLOT(toggleStatusBar()), actionCollection(), "settings_show_statusbar"); + m_paShowStatusBar->setWhatsThis(i18n("Use this command to show or hide the view's statusbar")); + + m_paShowPath = new KToggleAction(i18n("Sho&w Path"), 0, this, SLOT(newCaption()), + actionCollection(), "set_showPath"); + m_paShowPath->setCheckedState(i18n("Hide Path")); + m_paShowPath->setWhatsThis(i18n("Show the complete document path in the window caption")); + a=KStdAction::keyBindings(this, SLOT(editKeys()), actionCollection()); + a->setWhatsThis(i18n("Configure the application's keyboard shortcut assignments.")); + + a=KStdAction::configureToolbars(this, SLOT(editToolbars()), actionCollection()); + a->setWhatsThis(i18n("Configure which items should appear in the toolbar(s).")); +} + +void KWrite::setupStatusBar() +{ + statusBar()->insertItem("", KWRITE_ID_GEN); +} + +// load on url +void KWrite::loadURL(const KURL &url) +{ + m_view->document()->openURL(url); +} + +// is closing the window wanted by user ? +bool KWrite::queryClose() +{ + if (m_view->document()->views().count() > 1) + return true; + + if (m_view->document()->queryClose()) + { + writeConfig(); + + return true; + } + + return false; +} + +void KWrite::changeEditor() +{ + KWriteEditorChooser choose(this); + choose.exec(); +} + +void KWrite::slotFlush () +{ + m_view->document()->closeURL(); +} + +void KWrite::slotNew() +{ + new KWrite(); +} + +void KWrite::slotOpen() +{ + if (KTextEditor::encodingInterface(m_view->document())) + { + KEncodingFileDialog::Result r=KEncodingFileDialog::getOpenURLsAndEncoding( + KTextEditor::encodingInterface(m_view->document())->encoding(), + m_view->document()->url().url(),QString::null,this,i18n("Open File")); + + for (KURL::List::Iterator i=r.URLs.begin(); i != r.URLs.end(); ++i) + { + encoding = r.encoding; + slotOpen ( *i ); + } + } + else + { + KURL::List l=KFileDialog::getOpenURLs(m_view->document()->url().url(),QString::null,this,QString::null); + for (KURL::List::Iterator i=l.begin(); i != l.end(); ++i) + { + slotOpen ( *i ); + } + } +} + +void KWrite::slotOpen( const KURL& url ) +{ + if (url.isEmpty()) return; + + if (!KIO::NetAccess::exists(url, true, this)) + { + KMessageBox::error (this, i18n("The given file could not be read, check if it exists or if it is readable for the current user.")); + return; + } + + if (m_view->document()->isModified() || !m_view->document()->url().isEmpty()) + { + KWrite *t = new KWrite(); + if (KTextEditor::encodingInterface(t->m_view->document())) KTextEditor::encodingInterface(t->m_view->document())->setEncoding(encoding); + t->loadURL(url); + } + else + { + if (KTextEditor::encodingInterface(m_view->document())) KTextEditor::encodingInterface(m_view->document())->setEncoding(encoding); + loadURL(url); + } +} + +void KWrite::slotFileNameChanged() +{ + if ( ! m_view->document()->url().isEmpty() ) + m_recentFiles->addURL( m_view->document()->url() ); +} + +void KWrite::newView() +{ + new KWrite(m_view->document()); +} + +void KWrite::toggleStatusBar() +{ + if( m_paShowStatusBar->isChecked() ) + statusBar()->show(); + else + statusBar()->hide(); +} + +void KWrite::editKeys() +{ + KKeyDialog dlg; + dlg.insert(actionCollection()); + if( m_view ) + dlg.insert(m_view->actionCollection()); + dlg.configure(); +} + +void KWrite::editToolbars() +{ + saveMainWindowSettings( kapp->config(), "MainWindow" ); + KEditToolbar *dlg = new KEditToolbar(guiFactory()); + connect( dlg, SIGNAL(newToolbarConfig()), this, SLOT(slotNewToolbarConfig()) ); + dlg->exec(); + delete dlg; +} + +void KWrite::slotNewToolbarConfig() +{ + applyMainWindowSettings( kapp->config(), "MainWindow" ); +} + + +void KWrite::printNow() +{ + KTextEditor::printInterface(m_view->document())->print (); +} + +void KWrite::printDlg() +{ + KTextEditor::printInterface(m_view->document())->printDialog (); +} + +void KWrite::newStatus(const QString &msg) +{ + newCaption(); + + statusBar()->changeItem(msg,KWRITE_ID_GEN); +} + +void KWrite::newCaption() +{ + if (m_view->document()->url().isEmpty()) { + setCaption(i18n("Untitled"),m_view->document()->isModified()); + } + else + { + QString c; + if (!m_paShowPath->isChecked()) + { + c = m_view->document()->url().fileName(); + + //File name shouldn't be too long - Maciek + if (c.length() > 64) + c = c.left(64) + "..."; + } + else + { + c = m_view->document()->url().prettyURL(); + + //File name shouldn't be too long - Maciek + if (c.length() > 64) + c = "..." + c.right(64); + } + + setCaption (c, m_view->document()->isModified()); + } +} + +void KWrite::dragEnterEvent( QDragEnterEvent *event ) +{ + event->accept(KURLDrag::canDecode(event)); +} + +void KWrite::dropEvent( QDropEvent *event ) +{ + slotDropEvent(event); +} + +void KWrite::slotDropEvent( QDropEvent *event ) +{ + KURL::List textlist; + + if (!KURLDrag::decode(event, textlist)) + return; + + for (KURL::List::Iterator i=textlist.begin(); i != textlist.end(); ++i) + slotOpen (*i); +} + +void KWrite::slotEnableActions( bool enable ) +{ + QValueList<KAction *> actions = actionCollection()->actions(); + QValueList<KAction *>::ConstIterator it = actions.begin(); + QValueList<KAction *>::ConstIterator end = actions.end(); + + for (; it != end; ++it ) + (*it)->setEnabled( enable ); + + actions = m_view->actionCollection()->actions(); + it = actions.begin(); + end = actions.end(); + + for (; it != end; ++it ) + (*it)->setEnabled( enable ); +} + +//common config +void KWrite::readConfig(KConfig *config) +{ + config->setGroup("General Options"); + + m_paShowStatusBar->setChecked( config->readBoolEntry("ShowStatusBar") ); + m_paShowPath->setChecked( config->readBoolEntry("ShowPath") ); + + m_recentFiles->loadEntries(config, "Recent Files"); + + if (m_view && KTextEditor::configInterface(m_view->document())) + KTextEditor::configInterface(m_view->document())->readConfig(config); + + if( m_paShowStatusBar->isChecked() ) + statusBar()->show(); + else + statusBar()->hide(); +} + +void KWrite::writeConfig(KConfig *config) +{ + config->setGroup("General Options"); + + config->writeEntry("ShowStatusBar",m_paShowStatusBar->isChecked()); + config->writeEntry("ShowPath",m_paShowPath->isChecked()); + + m_recentFiles->saveEntries(config, "Recent Files"); + + if (m_view && KTextEditor::configInterface(m_view->document())) + KTextEditor::configInterface(m_view->document())->writeConfig(config); + + config->sync (); +} + +//config file +void KWrite::readConfig() +{ + KConfig *config = kapp->config(); + readConfig(config); +} + +void KWrite::writeConfig() +{ + KConfig *config = kapp->config(); + writeConfig(config); +} + +// session management +void KWrite::restore(KConfig *config, int n) +{ + readPropertiesInternal(config, n); +} + +void KWrite::readProperties(KConfig *config) +{ + readConfig(config); + + if (KTextEditor::sessionConfigInterface(m_view)) + KTextEditor::sessionConfigInterface(m_view)->readSessionConfig(config); +} + +void KWrite::saveProperties(KConfig *config) +{ + writeConfig(config); + config->writeEntry("DocumentNumber",docList.find(m_view->document()) + 1); + + if (KTextEditor::sessionConfigInterface(m_view)) + KTextEditor::sessionConfigInterface(m_view)->writeSessionConfig(config); +} + +void KWrite::saveGlobalProperties(KConfig *config) //save documents +{ + config->setGroup("Number"); + config->writeEntry("NumberOfDocuments",docList.count()); + + for (uint z = 1; z <= docList.count(); z++) + { + QString buf = QString("Document %1").arg(z); + config->setGroup(buf); + + KTextEditor::Document *doc = docList.at(z - 1); + + if (KTextEditor::configInterface(doc)) + KTextEditor::configInterface(doc)->writeSessionConfig(config); + } + + for (uint z = 1; z <= winList.count(); z++) + { + QString buf = QString("Window %1").arg(z); + config->setGroup(buf); + + config->writeEntry("DocumentNumber",docList.find(winList.at(z-1)->view()->document()) + 1); + } +} + +//restore session +void KWrite::restore() +{ + KConfig *config = kapp->sessionConfig(); + + if (!config) + return; + + int docs, windows; + QString buf; + KTextEditor::Document *doc; + KWrite *t; + + config->setGroup("Number"); + docs = config->readNumEntry("NumberOfDocuments"); + windows = config->readNumEntry("NumberOfWindows"); + + for (int z = 1; z <= docs; z++) + { + buf = QString("Document %1").arg(z); + config->setGroup(buf); + doc=KTextEditor::EditorChooser::createDocument(0,"KTextEditor::Document"); + + if (KTextEditor::configInterface(doc)) + KTextEditor::configInterface(doc)->readSessionConfig(config); + docList.append(doc); + } + + for (int z = 1; z <= windows; z++) + { + buf = QString("Window %1").arg(z); + config->setGroup(buf); + t = new KWrite(docList.at(config->readNumEntry("DocumentNumber") - 1)); + t->restore(config,z); + } +} + +static KCmdLineOptions options[] = +{ + { "stdin", I18N_NOOP("Read the contents of stdin"), 0}, + { "encoding <argument>", I18N_NOOP("Set encoding for the file to open"), 0 }, + { "line <argument>", I18N_NOOP("Navigate to this line"), 0 }, + { "column <argument>", I18N_NOOP("Navigate to this column"), 0 }, + { "+[URL]", I18N_NOOP("Document to open"), 0 }, + KCmdLineLastOption +}; + +extern "C" KDE_EXPORT int kdemain(int argc, char **argv) +{ + Kate::Document::setFileChangedDialogsActivated (true); + + KLocale::setMainCatalogue("kate"); //lukas: set this to have the kwritepart translated using kate message catalog + + // here we go, construct the KWrite version + QString kWriteVersion = QString ("%1.%2.%3").arg(KDE::versionMajor() + 1).arg(KDE::versionMinor()).arg(KDE::versionRelease()); + + KAboutData aboutData ( "kwrite", + I18N_NOOP("KWrite"), + kWriteVersion.latin1(), + I18N_NOOP( "KWrite - Text Editor" ), KAboutData::License_LGPL_V2, + I18N_NOOP( "(c) 2000-2005 The Kate Authors" ), 0, "http://kate.kde.org" ); + + aboutData.addAuthor ("Christoph Cullmann", I18N_NOOP("Maintainer"), "cullmann@kde.org", "http://www.babylon2k.de"); + aboutData.addAuthor ("Anders Lund", I18N_NOOP("Core Developer"), "anders@alweb.dk", "http://www.alweb.dk"); + aboutData.addAuthor ("Joseph Wenninger", I18N_NOOP("Core Developer"), "jowenn@kde.org","http://stud3.tuwien.ac.at/~e9925371"); + aboutData.addAuthor ("Hamish Rodda",I18N_NOOP("Core Developer"), "rodda@kde.org"); + aboutData.addAuthor ("Waldo Bastian", I18N_NOOP( "The cool buffersystem" ), "bastian@kde.org" ); + aboutData.addAuthor ("Charles Samuels", I18N_NOOP("The Editing Commands"), "charles@kde.org"); + aboutData.addAuthor ("Matt Newell", I18N_NOOP("Testing, ..."), "newellm@proaxis.com"); + aboutData.addAuthor ("Michael Bartl", I18N_NOOP("Former Core Developer"), "michael.bartl1@chello.at"); + aboutData.addAuthor ("Michael McCallum", I18N_NOOP("Core Developer"), "gholam@xtra.co.nz"); + aboutData.addAuthor ("Jochen Wilhemly", I18N_NOOP( "KWrite Author" ), "digisnap@cs.tu-berlin.de" ); + aboutData.addAuthor ("Michael Koch",I18N_NOOP("KWrite port to KParts"), "koch@kde.org"); + aboutData.addAuthor ("Christian Gebauer", 0, "gebauer@kde.org" ); + aboutData.addAuthor ("Simon Hausmann", 0, "hausmann@kde.org" ); + aboutData.addAuthor ("Glen Parker",I18N_NOOP("KWrite Undo History, Kspell integration"), "glenebob@nwlink.com"); + aboutData.addAuthor ("Scott Manson",I18N_NOOP("KWrite XML Syntax highlighting support"), "sdmanson@alltel.net"); + aboutData.addAuthor ("John Firebaugh",I18N_NOOP("Patches and more"), "jfirebaugh@kde.org"); + + aboutData.addCredit ("Matteo Merli",I18N_NOOP("Highlighting for RPM Spec-Files, Perl, Diff and more"), "merlim@libero.it"); + aboutData.addCredit ("Rocky Scaletta",I18N_NOOP("Highlighting for VHDL"), "rocky@purdue.edu"); + aboutData.addCredit ("Yury Lebedev",I18N_NOOP("Highlighting for SQL"),""); + aboutData.addCredit ("Chris Ross",I18N_NOOP("Highlighting for Ferite"),""); + aboutData.addCredit ("Nick Roux",I18N_NOOP("Highlighting for ILERPG"),""); + aboutData.addCredit ("Carsten Niehaus", I18N_NOOP("Highlighting for LaTeX"),""); + aboutData.addCredit ("Per Wigren", I18N_NOOP("Highlighting for Makefiles, Python"),""); + aboutData.addCredit ("Jan Fritz", I18N_NOOP("Highlighting for Python"),""); + aboutData.addCredit ("Daniel Naber","",""); + aboutData.addCredit ("Roland Pabel",I18N_NOOP("Highlighting for Scheme"),""); + aboutData.addCredit ("Cristi Dumitrescu",I18N_NOOP("PHP Keyword/Datatype list"),""); + aboutData.addCredit ("Carsten Pfeiffer", I18N_NOOP("Very nice help"), ""); + aboutData.addCredit (I18N_NOOP("All people who have contributed and I have forgotten to mention"),"",""); + + aboutData.setTranslator(I18N_NOOP("_: NAME OF TRANSLATORS\nYour names"), I18N_NOOP("_: EMAIL OF TRANSLATORS\nYour emails")); + + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); + + KApplication a; + + KGlobal::locale()->insertCatalogue("katepart"); + + DCOPClient *client = kapp->dcopClient(); + if (!client->isRegistered()) + { + client->attach(); + client->registerAs("kwrite"); + } + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if (kapp->isRestored()) + { + KWrite::restore(); + } + else + { + bool nav = false; + int line = 0, column = 0; + + QTextCodec *codec = args->isSet("encoding") ? QTextCodec::codecForName(args->getOption("encoding")) : 0; + + if (args->isSet ("line")) + { + line = args->getOption ("line").toInt(); + nav = true; + } + + if (args->isSet ("column")) + { + column = args->getOption ("column").toInt(); + nav = true; + } + + if ( args->count() == 0 ) + { + KWrite *t = new KWrite; + + if( args->isSet( "stdin" ) ) + { + QTextIStream input(stdin); + + // set chosen codec + if (codec) + input.setCodec (codec); + + QString line; + QString text; + + do + { + line = input.readLine(); + text.append( line + "\n" ); + } while( !line.isNull() ); + + + KTextEditor::EditInterface *doc = KTextEditor::editInterface (t->view()->document()); + if( doc ) + doc->setText( text ); + } + + if (nav && KTextEditor::viewCursorInterface(t->view())) + KTextEditor::viewCursorInterface(t->view())->setCursorPosition (line, column); + } + else + { + for ( int z = 0; z < args->count(); z++ ) + { + KWrite *t = new KWrite(); + + // this file is no local dir, open it, else warn + bool noDir = !args->url(z).isLocalFile() || !QDir (args->url(z).path()).exists(); + + if (noDir) + { + if (Kate::document (t->view()->document())) + Kate::Document::setOpenErrorDialogsActivated (false); + + if (codec && KTextEditor::encodingInterface(t->view()->document())) + KTextEditor::encodingInterface(t->view()->document())->setEncoding(codec->name()); + + t->loadURL( args->url( z ) ); + + if (Kate::document (t->view()->document())) + Kate::Document::setOpenErrorDialogsActivated (true); + + if (nav && KTextEditor::viewCursorInterface(t->view())) + KTextEditor::viewCursorInterface(t->view())->setCursorPosition (line, column); + } + else + KMessageBox::sorry( t, i18n("The file '%1' could not be opened: it is not a normal file, it is a folder.").arg(args->url(z).url()) ); + } + } + } + + // no window there, uh, ohh, for example borked session config !!! + // create at least one !! + if (KWrite::noWindows()) + new KWrite(); + + return a.exec (); +} + +KWriteEditorChooser::KWriteEditorChooser(QWidget *): + KDialogBase(KDialogBase::Plain,i18n("Choose Editor Component"),KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Cancel) +{ + (new QVBoxLayout(plainPage()))->setAutoAdd(true); + m_chooser=new KTextEditor::EditorChooser(plainPage(),"Editor Chooser"); + setMainWidget(m_chooser); + m_chooser->readAppSetting(); +} + +KWriteEditorChooser::~KWriteEditorChooser() { +; +} + +void KWriteEditorChooser::slotOk() { + m_chooser->writeAppSetting(); + KDialogBase::slotOk(); +} +// kate: space-indent on; indent-width 2; replace-tabs on; mixed-indent off; diff --git a/kate/app/kwritemain.h b/kate/app/kwritemain.h new file mode 100644 index 000000000..7af2c67ad --- /dev/null +++ b/kate/app/kwritemain.h @@ -0,0 +1,138 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __KWRITE_MAIN_H__ +#define __KWRITE_MAIN_H__ + +#include <ktexteditor/view.h> +#include <ktexteditor/document.h> + +#include <kparts/mainwindow.h> + +#include <kdialogbase.h> + +namespace KTextEditor { class EditorChooser; } + +class KAction; +class KToggleAction; +class KSelectAction; +class KRecentFilesAction; + +class KWrite : public KParts::MainWindow +{ + Q_OBJECT + + public: + KWrite(KTextEditor::Document * = 0L); + ~KWrite(); + + void loadURL(const KURL &url); + + KTextEditor::View *view() const { return m_view; } + + static bool noWindows () { return winList.isEmpty(); } + + private: + void setupActions(); + void setupStatusBar(); + + bool queryClose(); + + void dragEnterEvent( QDragEnterEvent * ); + void dropEvent( QDropEvent * ); + + public slots: + void slotNew(); + void slotFlush (); + void slotOpen(); + void slotOpen( const KURL& url); + void newView(); + void toggleStatusBar(); + void editKeys(); + void editToolbars(); + void changeEditor(); + + private slots: + void slotNewToolbarConfig(); + + public slots: + void printNow(); + void printDlg(); + + void newStatus(const QString &msg); + void newCaption(); + + void slotDropEvent(QDropEvent *); + + void slotEnableActions( bool enable ); + + /** + * adds a changed URL to the recent files + */ + void slotFileNameChanged(); + + //config file functions + public: + void readConfig (KConfig *); + void writeConfig (KConfig *); + + void readConfig (); + void writeConfig (); + + //session management + public: + void restore(KConfig *,int); + static void restore(); + + private: + void readProperties(KConfig *); + void saveProperties(KConfig *); + void saveGlobalProperties(KConfig *); + + private: + KTextEditor::View * m_view; + + KRecentFilesAction * m_recentFiles; + KToggleAction * m_paShowPath; + KToggleAction * m_paShowStatusBar; + + QString encoding; + + static QPtrList<KTextEditor::Document> docList; + static QPtrList<KWrite> winList; +}; + +class KWriteEditorChooser: public KDialogBase +{ + Q_OBJECT + + public: + KWriteEditorChooser(QWidget *parent); + virtual ~KWriteEditorChooser(); + + private: + KTextEditor::EditorChooser *m_chooser; + + protected slots: + void slotOk(); +}; + +#endif +// kate: space-indent on; indent-width 2; replace-tabs on; mixed-indent off; |