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 | 114a878c64ce6f8223cfd22d76a20eb16d177e5e (patch) | |
tree | acaf47eb0fa12142d3896416a69e74cbf5a72242 /src | |
download | tdevelop-114a878c64ce6f8223cfd22d76a20eb16d177e5e.tar.gz tdevelop-114a878c64ce6f8223cfd22d76a20eb16d177e5e.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/kdevelop@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src')
125 files changed, 15437 insertions, 0 deletions
diff --git a/src/Mainpage.dox b/src/Mainpage.dox new file mode 100644 index 00000000..77210259 --- /dev/null +++ b/src/Mainpage.dox @@ -0,0 +1,118 @@ +/** +@mainpage The KDevelop Generic Shell + +This library contains the Shell - a profile-based implementation of KDevelop plugin architecture. + +<b>Link with</b>: -lkdevshell + +<b>Include path</b>: -I\$(kde_includes)/kdevelop/shell + +\section creatingapp Creating an application using generic shell +KDevelop platform applications can use generic shell as a ready to use implementation +of KDevelop plugin architecture. + +This is done by creating application %main.cpp file and @ref ShellExtension subclass. +Example: +- %main.cpp for "myapp" application: + @code + #include <config.h> + + #include <kaboutdata.h> + #include <kapplication.h> + #include <kcmdlineargs.h> + #include <klocale.h> + #include <dcopclient.h> + + #include <splashscreen.h> + #include <toplevel.h> + #include <plugincontroller.h> + #include <partcontroller.h> + #include <core.h> + #include <projectmanager.h> + #include <newmainwindow.h> + + #include "myappextension.h" + + static KCmdLineOptions options[] = + { + { "profile <profile>", I18N_NOOP("Profile to load"), 0 }, + { 0,0,0 } + }; + + int main(int argc, char *argv[]) + { + static const char description[] = I18N_NOOP("My Application"); + KAboutData aboutData("myapp", I18N_NOOP("My Application"), + VERSION, description, KAboutData::License_GPL, + I18N_NOOP("(c) 1999-2004, MyApp developers"), + "", "http://www.myapp.org"); + aboutData.addAuthor("Me", I18N_NOOP("Creator"), "me@myapp.org"); + + KCmdLineArgs::init(argc, argv, &aboutData); + KCmdLineArgs::addCmdLineOptions( options ); + + KApplication app; + + MyAppExtension::init(); + + QPixmap pm; + pm.load(locate("data", "myapp/pics/myapp-splash.png")); + SplashScreen * splash = new SplashScreen( pm ); + splash->show(); + + app.processEvents(); + + QObject::connect(PluginController::getInstance(), SIGNAL(loadingPlugin(const QString &)), + splash, SLOT(showMessage(const QString &))); + + splash->message( i18n( "Loading Settings" ) ); + TopLevel::getInstance()->loadSettings(); + + PluginController::getInstance()->loadInitialPlugins(); + + splash->message( i18n( "Starting GUI" ) ); + NewMainWindow *mw = dynamic_cast<NewMainWindow*>(TopLevel::getInstance()->main()); + if (mw) + mw->enableShow(); + TopLevel::getInstance()->main()->show(); + + Core::getInstance()->doEmitCoreInitialized(); + + delete splash; + + kapp->dcopClient()->registerAs("myapp"); + + return app.exec(); + } + @endcode + +- Shell extension for "myapp" application: + @code + class MyAppExtension: public ShellExtension { + public: + static void init() + { + s_instance = new MyAppExtension(); + } + + virtual void createGlobalSettingsPage(KDialogBase */*dlg*/) {}; + virtual void acceptGlobalSettingsPage(KDialogBase */*dlg*/) {}; + + virtual QString xmlFile() + { + return "myappui.rc"; + } + + virtual QString defaultProfile() + { + return "MyApp"; + } + + protected: + KDevAssistantExtension(); + + }; + @endcode + +*/ + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 00000000..88e7326d --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,57 @@ +INCLUDES = -I$(top_srcdir)/lib -I$(top_srcdir)/lib/interfaces \ + -I$(top_srcdir)/lib/interfaces/extensions -I$(top_srcdir)/lib/interfaces/external \ + -I$(top_srcdir)/lib/interfaces/extras -I$(top_srcdir)/lib/util -I$(top_srcdir)/lib/widgets \ + -I$(top_srcdir)/src/newui -I$(top_srcdir)/src/profileengine/lib \ + $(all_includes) + +KDE_OPTIONS=nofinal + +lib_LTLIBRARIES = libkdevshell.la +libkdevshell_la_LDFLAGS = $(all_libraries) +libkdevshell_la_LIBADD = \ + $(top_builddir)/src/profileengine/lib/libprofileengine.la $(top_builddir)/lib/libkdevelop.la \ + $(top_builddir)/lib/widgets/libkdevwidgets.la $(top_builddir)/lib/interfaces/extras/libkdevextras.la \ + $(top_builddir)/src/newui/libd.la $(LIB_KHTML) -lktexteditor +libkdevshell_la_SOURCES = api.cpp core.cpp documentationpart.cpp \ + editorproxy.cpp generalinfowidget.cpp generalinfowidgetbase.ui languageselectwidget.cpp \ + mainwindowshare.cpp mimewarningdialog.ui multibuffer.cpp partcontroller.cpp \ + plugincontroller.cpp pluginselectdialog.cpp pluginselectdialog.h pluginselectdialogbase.ui \ + projectmanager.cpp projectsession.cpp shellextension.cpp simplemainwindow.cpp \ + splashscreen.cpp statusbar.cpp toplevel.cpp + +bin_PROGRAMS = kdevelop kdevassistant + +kdevelop_SOURCES = main.cpp kdevideextension.cpp settingswidget.ui + +kdevelop_METASOURCES = AUTO +kdevelop_LDFLAGS = $(all_libraries) $(KDE_RPATH) +kdevelop_LDADD = libkdevshell.la + +rcdir = $(kde_datadir)/kdevelop +rc_DATA = kdevelopui.rc eventsrc + +# default KDevelop configuration +kdevelopdatadir = $(kde_confdir) +kdevelopdata_DATA = kdeveloprc kdevassistantrc + +SUBDIRS = profiles profileengine newui kconf_update +kdevassistant_LDFLAGS = $(all_libraries) $(KDE_RPATH) +kdevassistant_SOURCES = main_assistant.cpp kdevassistantextension.cpp +kdevassistant_LDADD = libkdevshell.la + +rc_assistantdir = $(kde_datadir)/kdevassistant +rc_assistant_DATA = kdevassistantui.rc +shellincludedir = $(includedir)/kdevelop/shell +shellinclude_HEADERS = api.h core.h documentationpart.h editorproxy.h \ + generalinfowidget.h languageselectwidget.h mainwindowshare.h partcontroller.h \ + plugincontroller.h projectmanager.h projectsession.h shellextension.h splashscreen.h \ + statusbar.h toplevel.h generalinfowidgetbase.h mimewarningdialog.h settingswidget.h \ + simplemainwindow.h multibuffer.h + +DOXYGEN_REFERENCES = dcop interfaces kdecore kdefx kdeui khtml kmdi kio kjs kparts kutils kdevutil kdevinterfaces kdevextensions +DOXYGEN_PROJECTNAME = KDevelop Generic Shell +DOXYGEN_DOCDIRPREFIX = kdevshell +include ../Doxyfile.am +profilesdatadir = $(kde_datadir)/kdevelop/profiles +profilesdata_DATA = projectprofiles + diff --git a/src/api.cpp b/src/api.cpp new file mode 100644 index 00000000..8e56da3d --- /dev/null +++ b/src/api.cpp @@ -0,0 +1,60 @@ +#include "core.h" +#include "codemodel.h" +#include "partcontroller.h" +#include "plugincontroller.h" +#include "toplevel.h" +#include "api.h" + + +API *API::s_instance = 0; + + +KDevMainWindow *API::mainWindow() const +{ + return TopLevel::getInstance(); +} + +KDevPartController *API::partController() const +{ + return PartController::getInstance(); +} + + +KDevCore *API::core() const +{ + return Core::getInstance(); +} + + +CodeModel *API::codeModel() const +{ + return m_classStore; +} + + +API *API::getInstance() +{ + if (!s_instance) + s_instance = new API; + return s_instance; +} + + +API::API() + : KDevApi() +{ + m_classStore = new CodeModel(); +} + + +API::~API() +{ + delete( m_classStore ); + m_classStore = 0; +} + +KDevPluginController * API::pluginController() const +{ + return PluginController::getInstance(); +} + diff --git a/src/api.h b/src/api.h new file mode 100644 index 00000000..fb20447a --- /dev/null +++ b/src/api.h @@ -0,0 +1,41 @@ +#ifndef _API_H_ +#define _API_H_ + + +#include "kdevapi.h" + + +class CodeModel; + +/** +API implementation. +*/ +class API : public KDevApi +{ +public: + + virtual KDevMainWindow *mainWindow() const; + virtual KDevPartController *partController() const; + virtual KDevPluginController *pluginController() const; + virtual KDevCore *core() const; + virtual CodeModel *codeModel() const; + + static API *getInstance(); + + ~API(); + +protected: + + API(); + +private: + + static API *s_instance; + + CodeModel *m_classStore; + + +}; + + +#endif diff --git a/src/core.cpp b/src/core.cpp new file mode 100644 index 00000000..d7b6b285 --- /dev/null +++ b/src/core.cpp @@ -0,0 +1,118 @@ +#include <qtimer.h> + + +#include <kapplication.h> +#include <kdebug.h> +#include <kstatusbar.h> +#include <kmainwindow.h> +#include <kconfig.h> +#include <kdeversion.h> +#include <kstandarddirs.h> +#include <kglobal.h> +#include <kactioncollection.h> + +#include "toplevel.h" +#include "partcontroller.h" +#include "api.h" +#include "projectmanager.h" + +#include "core.h" + + +Core *Core::s_instance = 0; + + +Core *Core::getInstance() +{ + if (!s_instance) + s_instance = new Core; + return s_instance; +} + +void Core::setupShourtcutTips(KXMLGUIClient * client) +{ + QPtrList<KXMLGUIClient> clients; + if (client != 0) + clients.append(client); + else + clients = TopLevel::getInstance()->main()->guiFactory()->clients(); + + for( QPtrListIterator<KXMLGUIClient> it(clients); it.current(); ++it ) { + KActionCollection *actionCollection = (*it)->actionCollection(); + for (int i = 0; i < actionCollection->count(); i++) { + KAction *action = actionCollection->action(i); + + QString tooltip = action->toolTip(); + if (tooltip.isEmpty()) + tooltip = action->text().remove('&'); + else { + int i = tooltip.findRev('('); + if (i > 0) tooltip = tooltip.left(i).stripWhiteSpace(); + } + + QString shortcut = action->shortcutText(); + if (!shortcut.isEmpty()) + tooltip += " (" + shortcut + ")"; + action->setToolTip(tooltip); + } + } +} + +Core::Core() + : KDevCore() +{ +} + + +Core::~Core() +{ +} + +bool Core::queryClose() +{ + // save the the project to open it automaticly on startup if needed + KConfig* config = kapp->config(); + config->setGroup("General Options"); + config->writePathEntry("Last Project",ProjectManager::getInstance()->projectFile().url()); + + if ( !PartController::getInstance()->querySaveFiles() ) + return false; + + if ( !ProjectManager::getInstance()->closeProject( true ) ) + return false; + + if ( !PartController::getInstance()->readyToClose() ) + return false; + + return true; +} + + +void Core::running(KDevPlugin * which, bool runs) +{ + emit activeProcessChanged( which, runs ); +} + + +void Core::fillContextMenu(QPopupMenu *popup, const Context *context) +{ + emit contextMenu(popup, context); +} + + +void Core::openProject(const QString& projectFileName) +{ + ProjectManager::getInstance()->loadProject(KURL( projectFileName )); +} + +namespace MainWindowUtils{ +QString beautifyToolTip(const QString& text) +{ + QString temp = text; + temp.replace(QRegExp("&"), ""); + temp.replace(QRegExp("\\.\\.\\."), ""); + return temp; +} +} + +#include "core.moc" diff --git a/src/core.h b/src/core.h new file mode 100644 index 00000000..e48eecda --- /dev/null +++ b/src/core.h @@ -0,0 +1,71 @@ +#ifndef _CORE_H_ +#define _CORE_H_ + +#include <qregexp.h> +#include <kxmlguiclient.h> + +#include <kparts/partmanager.h> + + +#include "kdevcore.h" + +namespace MainWindowUtils{ + +QString beautifyToolTip(const QString& text); +} + +/** +Core implementation. +*/ +class Core : public KDevCore +{ + Q_OBJECT + +public: + + static Core *getInstance(); + + /** + * Setup shourtcut tips. For every KAction with a shortcut, + * appends the shortcut string, in parenthesis, to the + * actions's tooltip. If tooltip already has any text in + * parens, it's removed and shortcut is added instead. + * + * @param client + * Pointer to KXMLGUIClient object, which contain an collection + * of actions (KActionCollection). If the parameter is null, + * function is applied to the all available KXMLGUIClient objects. + */ + static void setupShourtcutTips(KXMLGUIClient * client = 0); + + ~Core(); + + virtual void running(KDevPlugin *which, bool runs); + virtual void fillContextMenu(QPopupMenu *popup, const Context *context); + virtual void openProject(const QString& projectFileName); + + void doEmitProjectOpened() { emit projectOpened(); } + void doEmitProjectClosed() { emit projectClosed(); } + void doEmitLanguageChanged() { emit languageChanged(); } + void doEmitCoreInitialized() { emit coreInitialized(); } + void doEmitProjectConfigWidget(KDialogBase *base) { emit projectConfigWidget(base); } + void doEmitConfigWidget(KDialogBase *base) { emit configWidget(base); } + void doEmitStopButtonPressed(KDevPlugin* which = 0) { emit stopButtonClicked( which ); } + + bool queryClose(); + +signals: + + void activeProcessChanged(KDevPlugin* which, bool runs); + +protected: + + Core(); + +private: + static Core *s_instance; + +}; + + +#endif diff --git a/src/documentationpart.cpp b/src/documentationpart.cpp new file mode 100644 index 00000000..b9ad78d0 --- /dev/null +++ b/src/documentationpart.cpp @@ -0,0 +1,21 @@ +#include "partcontroller.h" + +#include "documentationpart.h" + +HTMLDocumentationPart::HTMLDocumentationPart() + : KDevHTMLPart() +{ + setOptions(CanDuplicate | CanOpenInNewWindow); +} + +void HTMLDocumentationPart::slotDuplicate( ) +{ + PartController::getInstance()->showDocument(url(), true); +} + +void HTMLDocumentationPart::slotOpenInNewWindow( const KURL & url ) +{ + PartController::getInstance()->showDocument(url, true); +} + +#include "documentationpart.moc" diff --git a/src/documentationpart.h b/src/documentationpart.h new file mode 100644 index 00000000..b992bbf0 --- /dev/null +++ b/src/documentationpart.h @@ -0,0 +1,25 @@ +#ifndef __DOCUMENTATIONPART_H__ +#define __DOCUMENTATIONPART_H__ + +#include <kdevhtmlpart.h> + +/** +HTML documentation part. + +Implements shell-dependent "duplicate" and "open in new window" actions of KDevHTMLPart. +*/ +class HTMLDocumentationPart : public KDevHTMLPart +{ + Q_OBJECT + +public: + + HTMLDocumentationPart(); + +protected slots: + + virtual void slotDuplicate(); + virtual void slotOpenInNewWindow(const KURL &url); +}; + +#endif diff --git a/src/editorproxy.cpp b/src/editorproxy.cpp new file mode 100644 index 00000000..b256491d --- /dev/null +++ b/src/editorproxy.cpp @@ -0,0 +1,297 @@ +#include <qwidget.h> +#include <qpopupmenu.h> +#include <qtimer.h> + +#include <kdeversion.h> +#include <kdebug.h> +#include <kconfig.h> +#include <kapplication.h> + +#include <kparts/part.h> + +#include <ktexteditor/document.h> +#include <ktexteditor/view.h> +#include <ktexteditor/viewcursorinterface.h> +#include <ktexteditor/popupmenuinterface.h> +#include <ktexteditor/editinterface.h> +#include <ktexteditor/selectioninterface.h> +#include <ktexteditor/view.h> +#include <kxmlguiclient.h> +#include <kxmlguifactory.h> +#include <kmainwindow.h> +#include <kactioncollection.h> +#include <klocale.h> +#include <kstdaccel.h> + +#include "toplevel.h" +#include "partcontroller.h" +#include "core.h" +#include "multibuffer.h" +#include "kdeveditorutil.h" + +#include "editorproxy.h" + +using namespace KTextEditor; + +EditorProxy *EditorProxy::s_instance = 0; + + +EditorProxy::EditorProxy() + : QObject() +{ + m_delayedLineTimer = new QTimer( this ); + connect( m_delayedLineTimer, SIGNAL( timeout() ), this, SLOT(setLineNumberDelayed()) ); + KConfig *config = kapp->config(); + + m_delayedViewCreationCompatibleUI = true; + + KAction *ac = new KAction( i18n("Show Context Menu"), 0, this, + SLOT(showPopup()), TopLevel::getInstance()->main()->actionCollection(), "show_popup" ); + KShortcut cut ;/*= KStdAccel::shortcut(KStdAccel::PopupMenuContext);*/ + cut.append(KKey(CTRL+Key_Return)); + ac->setShortcut(cut); +} + + +EditorProxy *EditorProxy::getInstance() +{ + if (!s_instance) + s_instance = new EditorProxy; + + return s_instance; +} + +void EditorProxy::setLineNumberDelayed() +{ + if( !this ) return; ///This should fix a strange crash I use to encounter, where setLineNumberDelayed is called with this == NULL + setLineNumber(m_delayedPart, m_delayedLine, m_delayedCol); +} + + +void EditorProxy::setLineNumber(KParts::Part *part, int lineNum, int col) +{ + if (!part || !part->inherits("KTextEditor::Document")) + return; + + if ( lineNum < 0 ) + return; + + KURL url = dynamic_cast<KParts::ReadOnlyPart*>( part )->url(); + ViewCursorInterface *iface = dynamic_cast<ViewCursorInterface*>(part->widget()); + if (iface) + { +#if KDE_IS_VERSION(3,5,5) +#else + if (!part->widget()->hasFocus()) //workaround for QXIMInputContext crashes. Keep for KDE <=3.5.4! + { + m_delayedPart = part; + m_delayedLine = lineNum; + m_delayedCol = col; + m_delayedLineTimer->start( 1, true ); + } else +#endif + iface->setCursorPositionReal(lineNum, col == -1 ? 0 : col); + } + else { + // Save the position for a rainy day (or when the view gets activated and wants its position) + for (QValueList<MultiBuffer*>::ConstIterator it = m_editorParts.begin(); it != m_editorParts.end(); ++it) + if ((*it)->hasURL( url )) { + (*it)->registerDelayedActivation( part, lineNum, col ); + return; + } + + // Shouldn't hit this? + Q_ASSERT(false); + } +} + +void EditorProxy::installPopup( KParts::Part * part ) +{ + + if ( part->inherits("KTextEditor::Document") && part->widget()) + { + PopupMenuInterface *iface = dynamic_cast<PopupMenuInterface*>(part->widget()); + if (iface) + { + KTextEditor::View * view = static_cast<KTextEditor::View*>( part->widget() ); + + QPopupMenu * popup = static_cast<QPopupMenu*>( part->factory()->container("ktexteditor_popup", view ) ); + + if (!popup) + { + kdWarning() << k_funcinfo << "Popup not found!" << endl; + return; + } + + KAction * action = NULL; + //If there is a tab for this file, we don't need to plug the closing menu entries here + KConfig *config = KGlobal::config(); + config->setGroup("UI"); + bool m_tabBarShown = ! config->readNumEntry("TabWidgetVisibility", 0); + if (!m_tabBarShown) + { + action = TopLevel::getInstance()->main()->actionCollection()->action( "file_close" ); + if ( action && !action->isPlugged( popup ) ) + { + popup->insertSeparator( 0 ); + action->plug( popup, 0 ); + } + action = TopLevel::getInstance()->main()->actionCollection()->action( "file_closeother" ); + if ( action && !action->isPlugged( popup ) ) + action->plug( popup, 1 ); + } + + iface->installPopup( popup ); + + connect(popup, SIGNAL(aboutToShow()), this, SLOT(popupAboutToShow())); + + // ugly hack: mark the "original" items + m_popupIds.resize(popup->count()); + for (uint index=0; index < popup->count(); ++index) + m_popupIds[index] = popup->idAt(index); + } + } +} + +void EditorProxy::popupAboutToShow() +{ + QPopupMenu *popup = (QPopupMenu*)sender(); + if (!popup) + return; + + // ugly hack: remove all but the "original" items + for (int index=popup->count()-1; index >= 0; --index) + { + int id = popup->idAt(index); + if (m_popupIds.contains(id) == 0) + { + QMenuItem *item = popup->findItem(id); + if ( item && item->popup() ) + delete item->popup(); + else + popup->removeItemAt(index); + } + } + + KTextEditor::Document * doc = dynamic_cast<KTextEditor::Document*>( PartController::getInstance()->activePart() ); + if (!doc ) return; + + unsigned int line; + unsigned int col; + if ( !KDevEditorUtil::currentPositionReal( &line, &col, doc ) ) return; + + QString wordstr; + QString selection = KDevEditorUtil::currentSelection( doc ); + if ( !selection.isEmpty() && selection.contains('\n') != 0 ) + { + wordstr = selection; + } + else + { + wordstr = KDevEditorUtil::currentWord( doc ); + } + + QString linestr = KDevEditorUtil::currentLine( doc ); + + EditorContext context( doc->url(), line, col, linestr, wordstr ); + Core::getInstance()->fillContextMenu( popup, &context ); + + // Remove redundant separators (any that are first, last, or doubled) + bool lastWasSeparator = true; + for( uint i = 0; i < popup->count(); ) + { + int id = popup->idAt( i ); + if( lastWasSeparator && popup->findItem( id )->isSeparator() ) + { + popup->removeItem( id ); + // Since we removed an item, don't increment i + } else + { + lastWasSeparator = false; + i++; + } + } + if( lastWasSeparator && popup->count() > 0 ) + popup->removeItem( popup->idAt( popup->count() - 1 ) ); +} + +void EditorProxy::showPopup( ) +{ + kdDebug(9000) << k_funcinfo << endl; + + if ( KParts::Part * part = PartController::getInstance()->activePart() ) + { + ViewCursorInterface *iface = dynamic_cast<ViewCursorInterface*>( part->widget() ); + if ( iface ) + { + KTextEditor::View * view = static_cast<KTextEditor::View*>( part->widget() ); + QPopupMenu * popup = static_cast<QPopupMenu*>( view->factory()->container("ktexteditor_popup", view ) ); + + if ( popup ) + { + popup->exec( view->mapToGlobal( iface->cursorCoordinates() ) ); + } + } + } +} + +void EditorProxy::registerEditor(MultiBuffer* wrapper) +{ + m_editorParts.append(wrapper); +} + +void EditorProxy::deregisterEditor(MultiBuffer* wrapper) +{ + m_editorParts.remove(wrapper); +} + +QWidget * EditorProxy::widgetForPart( KParts::Part * part ) +{ + if ( !part ) return 0; + + if (part->widget()) + return part->widget(); + + KURL url = dynamic_cast<KParts::ReadOnlyPart*>( part )->url(); + + for (QValueList<MultiBuffer*>::ConstIterator it = m_editorParts.begin(); it != m_editorParts.end(); ++it) + if ((*it)->hasURL( url )) + return *it; + + return 0L; +} + +QWidget * EditorProxy::topWidgetForPart( KParts::Part * part ) +{ + if ( !part ) return 0; + + KURL url = dynamic_cast<KParts::ReadOnlyPart*>( part )->url(); + + for (QValueList<MultiBuffer*>::ConstIterator it = m_editorParts.begin(); it != m_editorParts.end(); ++it) + if ((*it)->hasURL( url )) + return *it; + + if (part->widget()) + return part->widget(); + + return 0L; +} + +bool EditorProxy::isDelayedViewCapable( ) +{ + return m_delayedViewCreationCompatibleUI; +} + +QWidget *EditorProxy::findPartWidget(KParts::Part *part) +{ + for (QValueList<MultiBuffer*>::ConstIterator it = m_editorParts.begin(); it != m_editorParts.end(); ++it) + if ((*it)->hasPart(part)) + return *it; + + if (part->widget()) + return part->widget(); + + return 0L; +} + +#include "editorproxy.moc" diff --git a/src/editorproxy.h b/src/editorproxy.h new file mode 100644 index 00000000..51564dd1 --- /dev/null +++ b/src/editorproxy.h @@ -0,0 +1,67 @@ +#ifndef __EDITORPROXY_H__ +#define __EDITORPROXY_H__ + + +#include <qobject.h> +#include <qmemarray.h> +#include <qguardedptr.h> + +class QPopupMenu; +class MultiBuffer; +class QTimer; + +#include <kparts/part.h> +#include <ktexteditor/markinterface.h> +#include <kdeversion.h> +# include <ktexteditor/markinterfaceextension.h> + +class EditorProxy : public QObject +{ + Q_OBJECT + +public: + + static EditorProxy *getInstance(); + + void setLineNumber(KParts::Part *part, int lineNum, int col); + + void installPopup(KParts::Part *part); + + void registerEditor(MultiBuffer* wrapper); + void deregisterEditor(MultiBuffer* wrapper); + + QWidget * widgetForPart( KParts::Part * part ); + QWidget * topWidgetForPart( KParts::Part * part ); + + bool isDelayedViewCapable(); + + QWidget * findPartWidget( KParts::Part * part ); + +public slots: + void setLineNumberDelayed(); + +private slots: + + void popupAboutToShow(); + void showPopup(); + +private: + + EditorProxy(); + + static EditorProxy *s_instance; + + QMemArray<int> m_popupIds; + + // This list is used to save line/col information for not yet activated editor views. + QValueList< MultiBuffer* > m_editorParts; + + QTimer* m_delayedLineTimer; + bool m_delayedViewCreationCompatibleUI; + KParts::Part *m_delayedPart; + int m_delayedLine; + int m_delayedCol; +}; + + +#endif diff --git a/src/eventsrc b/src/eventsrc new file mode 100644 index 00000000..37425f90 --- /dev/null +++ b/src/eventsrc @@ -0,0 +1,147 @@ +[!Global!] +IconName=kdevelop +Comment=KDevelop +Comment[hi]=के-डेवलप + +[ProcessSuccess] +Name=Process successful +Name[ca]=Procés correcte +Name[da]=Processen lykkedes +Name[de]=Prozess erfolgreich +Name[el]=Η διεργασία επιτυχής +Name[es]=Proceso correcto +Name[et]=Protsess oli edukas +Name[eu]=Prozesu zuzena +Name[fa]=موفقیت فرآیند +Name[fr]=Processus réussi +Name[ga]=D'éirigh leis an bpróiseas +Name[gl]=Proceso con éxito +Name[hi]=प्रक्रिया सफल +Name[hu]=Sikeres folyamat +Name[it]=Processo riuscito +Name[ja]=プロセス成功 +Name[lt]=Procesas pavyko +Name[ms]=Proses berjaya +Name[nds]=Perzess funkscheneer +Name[ne]=प्रक्रिया सफल +Name[nl]=Proces succesvol +Name[pl]=Proces zakończony pomyślnie +Name[pt]=Processo com sucesso +Name[pt_BR]=Processamento com sucesso +Name[ru]=Процесс завершён успешно +Name[sk]=Úspešný proces +Name[sl]=Proces uspešen +Name[sr]=Процес је успео +Name[sr@Latn]=Proces je uspeo +Name[sv]=Processen lyckades +Name[ta]=செயல்முறை வெற்றி +Name[tg]=Амал бо мувафақият ба анҷом расид +Name[tr]=İşlem Başarılı +Name[zh_CN]=处理成功 +Name[zh_TW]=行程成功 +Comment=Process finished successfully +Comment[ca]=Procés finalitzat amb èxit +Comment[da]=Processen afsluttede med succes +Comment[de]=Prozess erfolgreich beendet +Comment[el]=Η διεργασία τερμάτισε με επιτυχία +Comment[es]=Proceso finalizado con éxito +Comment[et]=Protsess edukalt lõpetatud +Comment[eu]=Prozesua ongi amaitu da +Comment[fa]=فرآیند با موفقیت پایان یافت +Comment[fr]=Le processus s'est terminé avec succès +Comment[gl]=O proceso finalizou exitosamente +Comment[hi]=प्रक्रिया सफलतापूर्वक सम्पन्न +Comment[hu]=A folyamat sikeresen befejeződött +Comment[it]=Processo terminato correttamente +Comment[ja]=プロセスは成功しました。 +Comment[ms]=Proses selesai dengan jaya +Comment[nds]=Perzess mit Spood beendt +Comment[ne]=प्रक्रिया सफलतापूर्वक समाप्त भयो +Comment[nl]=Het proces werd succesvol voltooid +Comment[pl]=Proces zakończony pomyślnie +Comment[pt]=O processo terminou com sucesso +Comment[pt_BR]=Processamento terminado com sucesso +Comment[ru]=Процесс завершён успешно +Comment[sk]=Proces skončil úspešne +Comment[sl]=Proces je uspešno končal +Comment[sr]=Процес је успешно завршен +Comment[sr@Latn]=Proces je uspešno završen +Comment[sv]=Processen avslutades med lyckat resultat +Comment[ta]=வெற்றிகரமாக முடிவடைந்த செயலாக்கம் +Comment[tg]=Амал бо мувафақият ба анҷом расид +Comment[tr]=İşlem başarıyla bitti. +Comment[zh_CN]=处理成功完成 +Comment[zh_TW]=行程成功完成 +default_presentation=0 + +[ProcessError] +Name=Process error +Name[ca]=Procés fallit +Name[da]=Procesfejl +Name[de]=Prozessfehler +Name[el]=Σφάλμα διεργασίας +Name[es]=Proceso fallido +Name[et]=Protsessi viga +Name[eu]=Prozesu errorea +Name[fa]=خطای پردازه +Name[fr]=Erreur du processus +Name[gl]=Error no proceso +Name[hi]=प्रक्रिया त्रुटि +Name[hu]=Hibás folyamat +Name[it]=Errore di processo +Name[ja]=プロセスエラー +Name[lt]=Proceso klaida +Name[ms]=Ralat proses +Name[nds]=Perzessfehler +Name[ne]=प्रक्रिया त्रुटि +Name[nl]=Procesfout +Name[pa]=ਕਾਰਜ ਗਲਤੀ +Name[pl]=Błąd w procesie +Name[pt]=Erro no processo +Name[pt_BR]=Processamento com erro +Name[ru]=Ошибка при выполнении процесса +Name[sk]=Chyba procesu +Name[sl]=Napaka procesa +Name[sr]=Грешка у процесу +Name[sr@Latn]=Greška u procesu +Name[sv]=Processfel +Name[ta]=செயல்முறை பிழை +Name[tg]=Ҳангоми иҷро намудани амал хатогие дида мешавад +Name[tr]=İşlem Hatası +Name[zh_CN]=处理失败 +Name[zh_TW]=行程錯誤 +Comment=Process finished with errors +Comment[ca]=Procés finalitzat amb errors +Comment[da]=Processen afsluttede med fejl +Comment[de]=Prozess mit Fehlerstatus beendet +Comment[el]=Η διεργασία τερμάτισε με σφάλματα +Comment[es]=Proceso finalizado con errores +Comment[et]=Protsess lõppes vigadega +Comment[eu]=Prozesua erroreekin amaitu da +Comment[fa]=پردازه با خطا پایان یافت +Comment[fr]=Le processus s'est terminé avec des erreurs +Comment[gl]=O proceso finalizou con erros +Comment[hi]=प्रक्रिया त्रुटियों के साथ सम्पन्न +Comment[hu]=A folyamat hibajelzéssel fejeződött be +Comment[it]=Processo terminato con errori +Comment[ja]=プロセスはエラーを起こし、終了しました。 +Comment[lt]=Procesas baigtas su klaidomis +Comment[ms]=Proses selesai dengan ralat +Comment[nds]=Perzess mit Fehlers beendt +Comment[ne]=प्रक्रिया त्रुटि आएर समाप्त भयो +Comment[nl]=Het proces eindigde met fouten +Comment[pl]=Proces zakończony z błędami +Comment[pt]=O processo terminou com erros +Comment[pt_BR]=Processamento terminado com erros +Comment[ru]=Ошибка при выполнении процесса +Comment[sk]=Proces skončil s chybami +Comment[sl]=Proces je končal brez napak +Comment[sr]=Процес је завршен са грешкама +Comment[sr@Latn]=Proces je završen sa greškama +Comment[sv]=Processen avslutades med fel +Comment[ta]=பிழையுடன் முடிவடைந்த செயலாக்கம் +Comment[tg]=Ҳангоми иҷро намудани амал хатогие дида мешавад +Comment[tr]=İşlem hatalarla bitti +Comment[zh_CN]=处理失败 +Comment[zh_TW]=行程完成但有錯誤 +default_presentation=0 diff --git a/src/generalinfowidget.cpp b/src/generalinfowidget.cpp new file mode 100644 index 00000000..e57dc41a --- /dev/null +++ b/src/generalinfowidget.cpp @@ -0,0 +1,292 @@ +/*************************************************************************** + * Copyright (C) 2002 by Yann Hodique * + * Yann.Hodique@lifl.fr * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include <klineedit.h> +#include <qtextedit.h> +#include <qcombobox.h> +#include <qlabel.h> +#include <qfileinfo.h> +#include <qdir.h> + +#include <kurl.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kcharsets.h> +#include <qregexp.h> +#include <kmessagebox.h> + +#include "generalinfowidget.h" +#include "generalinfowidget.moc" +#include "domutil.h" +#include "projectmanager.h" + +QString makeRelativePath(const QString& fromPath, const QString& toPath); + +GeneralInfoWidget::GeneralInfoWidget(QDomDocument &projectDom, QWidget *parent, const char *name) + : GeneralInfoWidgetBase(parent, name), m_projectDom(projectDom) { + + connect(project_directory_edit, SIGNAL(textChanged(const QString&)), + this, SLOT(slotProjectDirectoryChanged(const QString&))); + connect(project_directory_combo, SIGNAL(activated(int)), + this, SLOT(slotProjectDirectoryComboChanged())); + readConfig(); +} + + + +GeneralInfoWidget::~GeneralInfoWidget() {} + +void GeneralInfoWidget::readConfig() { + if(DomUtil::readBoolEntry(m_projectDom,"/general/absoluteprojectpath",false)) + this->project_directory_combo->setCurrentItem(0); + else + this->project_directory_combo->setCurrentItem(1); + this->project_directory_edit->setText(DomUtil::readEntry(m_projectDom,"/general/projectdirectory",".")); + this->author_edit->setText(DomUtil::readEntry(m_projectDom,"/general/author")); + this->email_edit->setText(DomUtil::readEntry(m_projectDom,"/general/email")); + this->version_edit->setText(DomUtil::readEntry(m_projectDom,"/general/version")); + this->description_edit->setText(DomUtil::readEntry(m_projectDom,"/general/description")); + + QStringList encodings; + encodings << i18n("Use global editor settings"); + encodings += KGlobal::charsets()->descriptiveEncodingNames(); + QStringList::const_iterator it = encodings.constBegin(); + while ( it != encodings.constEnd() ) + { + encoding_combo->insertItem( *it ); + ++it; + } + encoding_combo->setCurrentItem( 0 ); + +// const QString DefaultEncoding = KGlobal::charsets()->encodingForName( DomUtil::readEntry( m_projectDom, "/general/defaultencoding", QString::null ) ); + const QString DefaultEncoding = DomUtil::readEntry( m_projectDom, "/general/defaultencoding", QString::null ); + for ( int i = 0; i < encoding_combo->count(); i++ ) + { + if ( KGlobal::charsets()->encodingForName( encoding_combo->text( i ) ) == DefaultEncoding ) + { + encoding_combo->setCurrentItem( i ); + break; + } + } + +} +/** + * Update the configure.in, configure.in or configure.ac file with the version value from project options. + * Very basic updating - uses regex to update the field in + * AC_INIT, AM_INIT_AUTOMAKE, and AC_DEFINE macros. + * On next make, the build system re-runs configure to update config.h + * version info. + * + * @param configureinpath Full path to configure.in file + * @param newVersion The new version number or string +*/ +void GeneralInfoWidget::configureinUpdateVersion( QString configureinpath, QString newVersion ) +{ + QFile configurein(configureinpath); + + if ( !configurein.open( IO_ReadOnly ) ){ + KMessageBox::error(this, i18n("Could not open %1 for reading.").arg(configureinpath)); + return; + } + + QTextStream stream( &configurein); + QStringList list; + + // Options for version: + + // we ignore old AC_INIT that had no version.. + // only match the if there is a comma and at least two args.. + // AC_INIT (package, version, [bug-report], [tarname]) + QRegExp ac_init("^AC_INIT\\s*\\(\\s*([^,]+),([^,\\)]+)(.*)"); + + // AM_INIT_AUTOMAKE([OPTIONS]) + // example: AM_INIT_AUTOMAKE([gnits 1.5 no-define dist-bzip2]) + QRegExp am_autoSpace("^AM_INIT_AUTOMAKE\\s{0,}\\(\\s{0,}([\\[\\s]{0,}[^\\s]+)\\s+([^\\s\\)\\]]+)(.*)"); + + // AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) + QRegExp am_autoComma("^AM_INIT_AUTOMAKE\\s*\\(\\s*([^,]+),([^,\\)]+)(.*)"); + + // look for version in a define. + // AC_DEFINE(VERSION, "5.6") + QRegExp ac_define("^AC_DEFINE\\s*\\("); + QRegExp version("(\\bversion\\b)"); + version.setCaseSensitive(FALSE); + + while ( !stream.eof() ) { + QString line = stream.readLine(); + if ( ac_init.search(line) >= 0){ + line = "AC_INIT(" + ac_init.cap(1).stripWhiteSpace(); + line += ", "; + line += newVersion; + line += ac_init.cap(3).stripWhiteSpace(); + } + else if ( am_autoComma.search(line) >= 0 ){ + line="AM_INIT_AUTOMAKE("; + line += am_autoComma.cap(1).stripWhiteSpace(); + line += ", "; + line += newVersion; + line += am_autoComma.cap(3).stripWhiteSpace(); + } + else if ( am_autoSpace.search(line) >= 0 ){ + line = "AM_INIT_AUTOMAKE(" + am_autoSpace.cap(1).stripWhiteSpace(); + line += " "; + line += newVersion; + line += " "; + line += am_autoSpace.cap(3).stripWhiteSpace(); + } + else if ( ac_define.search(line) >=0 && version.search(line) >=0) { + // replace version in: AC_DEFINE(VERSION,"0.1") + line="AC_DEFINE(" + version.cap(1).stripWhiteSpace()+", \"" + newVersion +"\")"; + } + list.push_back(line); + } + configurein.close(); + + // write our changes.. + QFile configureout(configureinpath); + if ( !configureout.open( IO_WriteOnly ) ){ + KMessageBox::error(this, i18n("Could not open %1 for writing.").arg(configureinpath)); + return ; + } + QTextStream output( &configureout); + for(QStringList::iterator iter = list.begin();iter!=list.end();iter++){ + output << (*iter) <<"\n"; + } + configureout.close(); +} + +void GeneralInfoWidget::writeConfig() { + DomUtil::writeEntry(m_projectDom,"/general/projectdirectory",project_directory_edit->text()); + DomUtil::writeBoolEntry(m_projectDom,"/general/absoluteprojectpath",isProjectDirectoryAbsolute()); + DomUtil::writeEntry(m_projectDom,"/general/email",email_edit->text()); + DomUtil::writeEntry(m_projectDom,"/general/author",author_edit->text()); + DomUtil::writeEntry(m_projectDom,"/general/email",email_edit->text()); + if ( DomUtil::readEntry(m_projectDom,"/general/version") != version_edit->text() && !DomUtil::elementByPath( m_projectDom, "/kdevautoproject").isNull() ){ + // update the configure.in.in, configure.in or configure.ac file. + QFile inInFile(projectDirectory() + "/configure.in.in"); + QFile inFile(projectDirectory() + "/configure.in"); + QFile acFile(projectDirectory() + "/configure.ac"); + if ( inInFile.exists()){ + configureinUpdateVersion( inInFile.name(), version_edit->text() ); + } + if ( inFile.exists()){ + configureinUpdateVersion( inFile.name(), version_edit->text() ); + } + if (acFile.exists()){ + configureinUpdateVersion( acFile.name(), version_edit->text() ); + } + if (! inInFile.exists()&& !inFile.exists() && !acFile.exists()) { + KMessageBox::error(this, i18n("Could not find configure.in.in, configure.in or configure.ac to update the project version.")); + } + } + DomUtil::writeEntry(m_projectDom,"/general/version",version_edit->text()); + DomUtil::writeEntry(m_projectDom,"/general/description",description_edit->text()); + + QString DefaultEncoding = QString::null; + if ( encoding_combo->currentItem() > 0 ) + { + DefaultEncoding = KGlobal::charsets()->encodingForName( encoding_combo->currentText() ); + } + DomUtil::writeEntry( m_projectDom, "/general/defaultencoding", DefaultEncoding ); +} + +void GeneralInfoWidget::accept() { + writeConfig(); +} + +bool GeneralInfoWidget::isProjectDirectoryAbsolute() { + return project_directory_combo->currentItem() == 0; +} + +QString GeneralInfoWidget::projectDirectory() { + return ProjectManager::projectDirectory( project_directory_edit->text(), isProjectDirectoryAbsolute() ); +} + +void GeneralInfoWidget::slotProjectDirectoryChanged( const QString& text ) { + if(text.isEmpty()) + { + setProjectDirectoryError(i18n("Please enter a path.")); + } + else if(isProjectDirectoryAbsolute() && text[0] != '/') + { + setProjectDirectoryError( + i18n("'%1' is not an absolute path.").arg( + project_directory_edit->text())); + } + else if(!isProjectDirectoryAbsolute() && text[0] == '/') + { + setProjectDirectoryError( + i18n("'%1' is not a relative path.").arg( + project_directory_edit->text())); + } + else + { + QFileInfo info(projectDirectory()); + if(!info.exists()) + setProjectDirectoryError( + i18n("'%1' does not exist.").arg( + project_directory_edit->text())); + else if(!info.isDir()) + setProjectDirectoryError( + i18n("'%1' is not a directory.").arg( + project_directory_edit->text())); + else + setProjectDirectorySuccess(); + } +} + +void GeneralInfoWidget::slotProjectDirectoryComboChanged() { + QString text = project_directory_edit->text(); + if(isProjectDirectoryAbsolute() && text[0] != '/' ) + project_directory_edit->setText(ProjectManager::projectDirectory(text,false)); + else if(!isProjectDirectoryAbsolute() && text[0] == '/') + { + project_directory_edit->setText(KURL(ProjectManager::getInstance()->projectFile(), text).url()); + } +} + +void GeneralInfoWidget::setProjectDirectoryError( const QString& error ) { + project_directory_diagnostic_icon->setPixmap(SmallIcon("no")); + project_directory_diagnostic_label->setText( error ); +} + +void GeneralInfoWidget::setProjectDirectorySuccess() { + project_directory_diagnostic_icon->setPixmap(SmallIcon("ok")); + if(isProjectDirectoryAbsolute()) + project_directory_diagnostic_label->setText( + i18n("'%1' is a valid project directory.").arg(projectDirectory())); + else + project_directory_diagnostic_label->setText( + i18n("'%1' is a valid project directory.").arg(projectDirectory())); +} + +QString makeRelativePath(const QString& fromPath, const QString& toPath) +{ + if ( fromPath == toPath ) + return "."; + + QStringList fromDirs = QStringList::split( '/', fromPath ); + QStringList toDirs = QStringList::split( '/', toPath ); + QStringList::iterator fromIt = fromDirs.begin(); + QStringList::iterator toIt = toDirs.begin(); + + QString relative; + + for ( ; (*fromIt) == (*toIt); ++fromIt, ++toIt ) + ; + + for ( ; fromIt != fromDirs.end(); ++fromIt ) + relative += "../"; + + for ( ; toIt != toDirs.end(); ++toIt ) + relative += *toIt + "/"; + + return relative; +} diff --git a/src/generalinfowidget.h b/src/generalinfowidget.h new file mode 100644 index 00000000..b6e3a85f --- /dev/null +++ b/src/generalinfowidget.h @@ -0,0 +1,53 @@ +/*************************************************************************** + * Copyright (C) 2002 by Yann Hodique * + * Yann.Hodique@lifl.fr * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef _GENERALINFOWIDGET_H_ +#define _GENERALINFOWIDGET_H_ + +#include <qwidget.h> +#include <qdom.h> + +#include "generalinfowidgetbase.h" + +class QDomDocument; + +/** +General project information widget. +*/ +class GeneralInfoWidget : public GeneralInfoWidgetBase { + Q_OBJECT + +public: + + GeneralInfoWidget(QDomDocument &projectDom, QWidget *parent=0, const char *name=0); + ~GeneralInfoWidget(); + +public slots: + void accept(); + +private slots: + void slotProjectDirectoryChanged( const QString& text ); + void slotProjectDirectoryComboChanged(); + +private: + + QDomDocument m_projectDom; + + void readConfig(); + void writeConfig(); + + bool isProjectDirectoryAbsolute(); + QString projectDirectory(); + void setProjectDirectoryError( const QString& error ); + void setProjectDirectorySuccess(); + void configureinUpdateVersion( QString configureinpath, QString newVersion ); +}; + +#endif diff --git a/src/generalinfowidgetbase.ui b/src/generalinfowidgetbase.ui new file mode 100644 index 00000000..370c42e4 --- /dev/null +++ b/src/generalinfowidgetbase.ui @@ -0,0 +1,245 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>GeneralInfoWidgetBase</class> +<widget class="QWidget"> + <property name="name"> + <cstring>general_info_widget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>518</width> + <height>375</height> + </rect> + </property> + <property name="caption"> + <string>General Settings</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QComboBox" row="0" column="4"> + <item> + <property name="text"> + <string>Absolute Path</string> + </property> + </item> + <item> + <property name="text"> + <string>Relative to Project File</string> + </property> + </item> + <property name="name"> + <cstring>project_directory_combo</cstring> + </property> + </widget> + <spacer row="4" column="3" rowspan="1" colspan="2"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>408</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="5" column="0" rowspan="1" colspan="5"> + <property name="name"> + <cstring>description_label</cstring> + </property> + <property name="text"> + <string>Description:</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>project_directory_label</cstring> + </property> + <property name="text"> + <string>Project directory:</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>author_label</cstring> + </property> + <property name="text"> + <string>Author:</string> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>email_label</cstring> + </property> + <property name="text"> + <string>Email:</string> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>version_label</cstring> + </property> + <property name="text"> + <string>Version:</string> + </property> + </widget> + <widget class="KLineEdit" row="4" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>version_edit</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>32767</height> + </size> + </property> + <property name="toolTip" stdset="0"> + <string>Project Version +You may need to run automake & friends to update +the version in all files after changing this.</string> + </property> + </widget> + <widget class="KLineEdit" row="3" column="1" rowspan="1" colspan="4"> + <property name="name"> + <cstring>email_edit</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Used in templates as $EMAIL$ +Placed in the AUTHORS file</string> + </property> + </widget> + <widget class="KLineEdit" row="2" column="1" rowspan="1" colspan="4"> + <property name="name"> + <cstring>author_edit</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Used in templates as $AUTHOR$ +Placed in the AUTHORS file</string> + </property> + </widget> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>project_directory_diagnostic_icon</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>16</width> + <height>16</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>16</width> + <height>16</height> + </size> + </property> + <property name="font"> + <font> + <pointsize>10</pointsize> + </font> + </property> + <property name="text"> + <string></string> + </property> + <property name="pixmap"> + <pixmap>image0</pixmap> + </property> + </widget> + <widget class="KLineEdit" row="0" column="1" rowspan="1" colspan="3"> + <property name="name"> + <cstring>project_directory_edit</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Where the project starts.</string> + </property> + </widget> + <widget class="KSqueezedTextLabel" row="1" column="2" rowspan="1" colspan="3"> + <property name="name"> + <cstring>project_directory_diagnostic_label</cstring> + </property> + <property name="font"> + <font> + </font> + </property> + <property name="text"> + <string>Please select a project directory</string> + </property> + </widget> + <widget class="QLabel" row="7" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Default encoding:</string> + </property> + </widget> + <widget class="QComboBox" row="7" column="2" rowspan="1" colspan="2"> + <property name="name"> + <cstring>encoding_combo</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Default encoding used when opening text files</string> + </property> + </widget> + <widget class="QTextEdit" row="6" column="0" rowspan="1" colspan="5"> + <property name="name"> + <cstring>description_edit</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Text that stays in the project file.</string> + </property> + </widget> + </grid> +</widget> +<images> + <image name="image0"> + <data format="PNG" length="532">89504e470d0a1a0a0000000d49484452000000100000001008060000001ff3ff61000001db49444154388da593316853511486bf276f78810a195fc0218a83e91688c3bb9b42974c925570509cc4cd3116445dd4ba889b0a82e8225dac6b07b1b74ba18b1887428796e64183efa2c1dc21f03bdc247d4dede48103971ffefffce7dc73226b2dff13f13c907dfa2c1612889363f8c8392e3c7dccea171b95f168ea20cb32f1e419341a90542099088c3df811148ef50fef591914749faf442705dc4f31f4503870c591b731e05c1002bebb82fb7b39f796bb11c01980acd3117b39f47af0a307692d90060ef677a15a0d2dedf7591c7a6ee67d3ac66826c0b95aa8fa6d1beae7e1c675586ac34e0fe20adcbd03b76fc1c8c3619fc541410330c628181d14b0b50987057c5d0f7358ba0a833eb44c1079f112f23e3847e1f2a3295a6b519a4a17ebd242225d6a84f7db779224fdfa235deb48691a32461b31ba0202145af03ef43cf46106de4366e0f708ce56e07213f23ce4183cc99c8318294924905a4de9e020546e35a5070f8393d7afa41809b49624330731c0680c95c937e10ad8d985e52e6c6d874c6b302c8e2d962f3b48411f09ea8259a57fe5469ca833a90e086b2dd65aaaa0b55348a7924151f998dac6e8510cf5b93b986ee49bb167b504596ba368fe1adbc6a879928e0736e7c850ba857298c99a9e165332c05fc9532863e03dd50a0000000049454e44ae426082</data> + </image> +</images> +<tabstops> + <tabstop>project_directory_edit</tabstop> + <tabstop>project_directory_combo</tabstop> + <tabstop>author_edit</tabstop> + <tabstop>email_edit</tabstop> + <tabstop>version_edit</tabstop> + <tabstop>description_edit</tabstop> + <tabstop>encoding_combo</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in implementation">kdialog.h</include> + <include location="global" impldecl="in declaration">ksqueezedtextlabel.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +<includehints> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>ksqueezedtextlabel.h</includehint> +</includehints> +</UI> diff --git a/src/kconf_update/Makefile.am b/src/kconf_update/Makefile.am new file mode 100644 index 00000000..b31e578c --- /dev/null +++ b/src/kconf_update/Makefile.am @@ -0,0 +1,18 @@ +AM_CPPFLAGS = -DKDE_NO_COMPAT -DQT_NO_COMPAT $(all_includes) + +update_DATA = kdev-gen-settings.upd +updatedir = $(kde_datadir)/kconf_update + +# The Qt app cannot go into kde_datadir, that is not portable. +# install to kde_bindir/kconf_update_bin instead. +# KDE 3.2 will allow kconf_update scripts to run directly from there, +# but for us that's too late. Use the .sh script as a workaround. +kconf_PROGRAMS = kdev-gen-settings-kconf_update +kconfdir = $(libdir)/kconf_update_bin + +kdev_gen_settings_kconf_update_SOURCES = kdev-gen-settings-kconf_update.cpp +kdev_gen_settings_kconf_update_LDFLAGS = $(all_libraries) $(KDE_RPATH) +kdev_gen_settings_kconf_update_LDADD = $(LIB_QT) + +# vim: set noet: + diff --git a/src/kconf_update/kdev-gen-settings-kconf_update.cpp b/src/kconf_update/kdev-gen-settings-kconf_update.cpp new file mode 100644 index 00000000..1f3c9740 --- /dev/null +++ b/src/kconf_update/kdev-gen-settings-kconf_update.cpp @@ -0,0 +1,113 @@ +/* + kconf_update app for migrating kdevelop's ui settings to the new + code that will be in 3.3. + + Copyright (c) 2005 by Matt Rogers <mattr@kde.org> + Based on code Copyright (c) 2003 by Martijn Klingens <klingens@kde.org> + + ************************************************************************* + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + ************************************************************************* +*/ + +#include <qmap.h> +#include <qtextstream.h> +#include <qregexp.h> + +static QTextStream qcin ( stdin, IO_ReadOnly ); +static QTextStream qcout( stdout, IO_WriteOnly ); +static QTextStream qcerr( stderr, IO_WriteOnly ); + +// Group cache. Yes, I know global vars are ugly :) +bool needFlush = false; +QString newKeyValue; +int newDataValue; + +void parseKey( const QString &group, const QString &key, + const QString &value, const QString &rawLine ) +{ + + //qcerr << "*** group='" << group << "'" << endl; + if ( group == "General Options" && key == "Embed KDevDesigner") + { + newKeyValue = "Designer App"; + if ( value.lower() == "true" ) + newDataValue = 0; + else + newDataValue = 2; + qcout << newKeyValue << "=" << newDataValue << endl; + qcout << "# DELETE [" << key << "]" << endl; + + } + else if ( group == "General Options" && key == "Application Font" ) + { + newKeyValue = "OutputViewFont"; + qcout << newKeyValue << "=" << value << endl; + qcout << "# DELETE [" << key << "]" << endl; + } + else if ( group == "MakeOutputView" && key == "Messages Font" ) + { + qcout << "# DELETE [" << key << "]" << endl; + } + else if ( group == "TerminalEmulator" && key == "UseKDESetting" ) + { + newKeyValue = "UseKDESetting"; + if ( value.lower() == "true" ) + newDataValue = 0; + else + newDataValue = 1; + qcout << newKeyValue << "=" << newDataValue << endl; + } + else + { + // keys we don't convert. output the raw line instead. + qcout << rawLine << endl; + } +} + +int main() +{ + qcin.setEncoding( QTextStream::UnicodeUTF8 ); + qcout.setEncoding( QTextStream::UnicodeUTF8 ); + + QString curGroup; + + QRegExp groupRegExp( "^\\[(.*)\\]" ); + QRegExp keyRegExp( "^([a-zA-Z0-9:, _-]*)\\s*=\\s*(.*)\\s*" ); + QRegExp commentRegExp( "^(#.*)?$" ); + + while ( !qcin.atEnd() ) + { + QString line = qcin.readLine(); + + if ( commentRegExp.exactMatch( line ) ) + { + // We found a comment, leave unchanged + qcout << line << endl; + } + else if ( groupRegExp.exactMatch( line ) ) + { + curGroup = groupRegExp.capturedTexts()[ 1 ]; + qcout << line << endl; + } + else if ( keyRegExp.exactMatch( line ) ) + { + // We found the a key line + parseKey( curGroup, keyRegExp.capturedTexts()[ 1 ], keyRegExp.capturedTexts()[ 2 ], line ); + } + else + { + qcout << line << endl; + } + } + + return 0; +} + +// vim: set noet ts=4 sts=4 sw=4: + diff --git a/src/kconf_update/kdev-gen-settings.upd b/src/kconf_update/kdev-gen-settings.upd new file mode 100644 index 00000000..3592126f --- /dev/null +++ b/src/kconf_update/kdev-gen-settings.upd @@ -0,0 +1,8 @@ +#Update the KDevelop General Settings page to work with the +#new UI file created on 20050406 +Id=kdev-gen-settings-update/5 +File=kdeveloprc +Script=kdev-gen-settings-kconf_update +Options=overwrite +AllKeys + diff --git a/src/kdevassistantextension.cpp b/src/kdevassistantextension.cpp new file mode 100644 index 00000000..acb1e92b --- /dev/null +++ b/src/kdevassistantextension.cpp @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "kdevassistantextension.h" + +KDevAssistantExtension::KDevAssistantExtension() + : ShellExtension() +{ +} + +void KDevAssistantExtension::init() +{ + s_instance = new KDevAssistantExtension(); +} + +QString KDevAssistantExtension::xmlFile() +{ + return "kdevassistantui.rc"; +} + +QString KDevAssistantExtension::defaultProfile() +{ + return "KDevAssistant"; +} diff --git a/src/kdevassistantextension.h b/src/kdevassistantextension.h new file mode 100644 index 00000000..d00b02ca --- /dev/null +++ b/src/kdevassistantextension.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef KDEVASSISTANTEXTENSION_H +#define KDEVASSISTANTEXTENSION_H + +#include "shellextension.h" + +class KDevAssistantExtension : public ShellExtension { +public: + static void init(); + + virtual void createGlobalSettingsPage(KDialogBase */*dlg*/) {}; + virtual void acceptGlobalSettingsPage(KDialogBase */*dlg*/) {}; + + virtual QString xmlFile(); + + virtual QString defaultProfile(); + +protected: + KDevAssistantExtension(); + +}; + +#endif diff --git a/src/kdevassistantrc b/src/kdevassistantrc new file mode 100644 index 00000000..eaab6fc6 --- /dev/null +++ b/src/kdevassistantrc @@ -0,0 +1,14 @@ +[RightToolWindow] +LastWidget=Documentation +Width=254 + +[UI] +CloseOnHover=false +CloseOnHoverDelay=false +MDIMode=4 +MDIStyle=1 +OpenNewTabAfterCurrent=true +ShowCloseTabsButton=true +ShowTabIcons=true +TabWidgetVisibility=0 +UseSimpleMainWindow=true diff --git a/src/kdevassistantui.rc b/src/kdevassistantui.rc new file mode 100644 index 00000000..a5b202ce --- /dev/null +++ b/src/kdevassistantui.rc @@ -0,0 +1,168 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="9" name="kdevassistant" > +<MenuBar> + <Menu name="file" noMerge="1"><text>&File</text> + <DefineGroup name="new_merge"/> + <Separator/> + <Action name="file_open"/> +<!-- <Action name="file_open_recent"/> --> + <DefineGroup name="open_merge"/> + <Separator/> + <DefineGroup name="save_merge"/> +<!-- <Action name="file_save_all"/> --> + <Separator/> + <DefineGroup name="revert_merge"/> +<!-- <Action name="file_revert_all"/> --> + <Separator/> + <DefineGroup name="print_merge"/> + <Merge/> + <Separator/> + <Action name="file_close"/> + <DefineGroup name="close_merge"/> + <Action name="file_close_all"/> + <Action name="file_closeother"/> + <Separator/> + <Action name="file_quit"/> + </Menu> +<!-- <Menu name="edit"><text>&Edit</text> + <DefineGroup name="edit_undo_merge"/> + <Separator/> + <DefineGroup name="edit_paste_merge"/> + <Separator/> + <DefineGroup name="edit_select_merge"/> + <Separator/> + <DefineGroup name="edit_find_merge"/> + <DefineGroup name="kdev_edit_find_merge"/> + <Separator/> + <DefineGroup name="edit_astyle"/> + <Separator/> + <Merge/> + </Menu> --> + <Merge/> + <Menu name="view"> + <text>&View</text> + <DefineGroup name="history_operations"/> + <Action name="file_switchto"/> + <Action name="raise_editor"/> + <Separator/> + <DefineGroup name="error_operations"/> + <Separator/> + <Merge/> + <Separator/> + <DefineGroup name="view_operations"/> + </Menu> +<!-- <Menu name="project"> + <text>&Project</text> + <DefineGroup name="project_new"/> + <Action name="project_open"/> + <Action name="project_open_recent"/> + <Action name="project_active_language"/> + <DefineGroup name="project_import"/> + <Separator/> + <Merge/> + <Action name="project_options"/> + <Separator/> + <Action name="project_close"/> + </Menu> + <Menu name="build"> + <text>Bu&ild</text> + <Merge/> + <Separator/> + <Action name="stop_processes"/> + </Menu> --> +<!-- <Menu name="tools"> + <text>&Tools</text> + <DefineGroup name="tools_operations"/> + <Separator/> + <DefineGroup name="tools_file_operations"/> + <Separator/> + <DefineGroup name="tools_language_operations"/> + <Separator/> + <DefineGroup name="tools_project_operations"/> + <Separator/> + <Merge/> + </Menu> --> + <Menu name="settings" noMerge="1"> + <text>&Settings</text> + <Action name="settings_show_menubar" /> + <Merge name="StandardToolBarMenuHandler" /> + <Action name="settings_main_toolbar"/> +<!-- <Action name="settings_build_toolbar"/> --> + <Action name="settings_view_toolbar"/> + <Action name="settings_browser_toolbar"/> + <DefineGroup name="show_toolbar_merge" /> + <Action name="settings_viewbar"/> + <Action name="settings_statusbar"/> + <DefineGroup name="show_merge" /> + <Separator /> + <Action name="settings_configure_shortcuts" /> + <Action name="settings_configure_toolbars" /> + <Action name="settings_configure_notifications" /> + <Action name="settings_configure_editors" /> + <Action name="settings_configure" /> + <DefineGroup name="configure_merge" /> + </Menu> + <Menu append="settings_merge" name="window"> + <text>&Window</text> + <Action name="view_next_window"/> + <Action name="view_previous_window"/> + <Separator/> + <Action name="split_h"/> + <Action name="split_v"/> + <Separator/> + <Action name="switch_left_dock"/> + <Action name="switch_right_dock"/> + <Action name="switch_bottom_dock"/> + <Separator/> + <DefineGroup name="window_operations"/> + <Merge/> + </Menu> + <Menu name="help" append="about_merge"> + <text>&Help</text> + <Merge/> + </Menu> +</MenuBar> + +<ToolBar name="mainToolBar" position="Top" noMerge="1" fullWidth="true" newline="true" > + <text>Main Toolbar</text> +<!-- <Action name="project_open" /> --> + <DefineGroup name="project_operations"/> + <DefineGroup name="file_operations"/> + <DefineGroup name="print_merge"/> + <DefineGroup name="edit_operations"/> + <DefineGroup name="find_operations"/> +<!-- <Action name="tree_view"/> + <Action name="output_view"/> --> + <DefineGroup name="view_operations"/> + <DefineGroup name="zoom_operations"/> + <Merge/> + <Action name="help_whats_this"/> +</ToolBar> + +<!--<ToolBar name="buildToolBar" position="Top" noMerge="1"> + <text>Build Toolbar</text> + <DefineGroup name="build_operations"/> + <DefineGroup name="debug_operations"/> + <Action name="stop_processes"/> +</ToolBar>--> + +<ToolBar name="browserToolBar" position="Top" noMerge="1"> + <text>Browser Toolbar</text> + <DefineGroup name="class_operations" /> + <DefineGroup name="browser_operations" /> + <Action name="browser_back" /> + <Action name="browser_forward" /> + <Merge/> +</ToolBar> + +<ToolBar name="extraToolBar" position="Top" noMerge="1" hidden="true"> + <text>Extra Toolbar</text> +</ToolBar> + +<Menu name="rb_popup"> + <Separator/> + <Action name="file_close"/> + <Action name="file_closeother"/> +</Menu> + +</kpartgui> diff --git a/src/kdeveloprc b/src/kdeveloprc new file mode 100644 index 00000000..fe62909f --- /dev/null +++ b/src/kdeveloprc @@ -0,0 +1,70 @@ +[AStyle] +Brackets=Break +Fill=Spaces +FillSpaces=2 +IndentBrackets=false +IndentCases=false +IndentClasses=false +IndentLabels=true +IndentNamespaces=true +IndentSwitches=false +KeepBlocks=false +KeepStatements=false +MaxStatement=40 +MinConditional=-1 +PadOperators=false +PadParentheses=false +Style=UserDefined + +[Editor] +EmbeddedKTextEditor=Embedded KDE Advanced Text Editor Component + +[General Options] +Read Last Project On Startup=true + +[Mainwindow] +Height 768=548 +Width 1024=735 + +[Mainwindow Toolbar mainToolBar] +Hidden=false +IconSize=22 +IconText=IconOnly +Index=0 +NewLine=false +Offset=-1 +Position=Top + +[Mainwindow Toolbar QextMdiTaskBar] +Hidden=true +IconSize=22 +IconText=IconOnly +Index=1 +NewLine=false +Offset=-1 +Position=Bottom + +[Mainwindow Toolbar browserToolBar] +Hidden=false +IconSize=22 +IconText=IconOnly +Index=2 +NewLine=true +Offset=-1 +Position=Top + +[Plugins] +KDevScripting=false + +[UI] +MDIStyle=3 +MDIMode=4 +TabVisibility=0 +CloseOnHover=false +CloseOnHoverDelay=false +OpenNewTabAfterCurrent=true +ShowCloseTabsButton=true +ShowTabIcons=false + +[Kate View Defaults] +Icon Bar=true diff --git a/src/kdevelopui.rc b/src/kdevelopui.rc new file mode 100644 index 00000000..f1939592 --- /dev/null +++ b/src/kdevelopui.rc @@ -0,0 +1,191 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="33" name="kdevelop" > +<MenuBar> + <Menu name="file" noMerge="1"><text>&File</text> + <DefineGroup name="new_merge"/> + <Separator/> + <Action name="file_open"/> + <Action name="file_open_recent"/> + <DefineGroup name="open_merge"/> + <Separator/> + <DefineGroup name="save_merge"/> + <Action name="file_save_all"/> + <Separator/> + <DefineGroup name="revert_merge"/> + <Action name="file_revert_all"/> + <Separator/> + <DefineGroup name="print_merge"/> + <Merge/> + <Separator/> + <Action name="file_close"/> + <DefineGroup name="close_merge"/> + <Action name="file_close_all"/> + <Action name="file_closeother"/> + <Separator/> + <Action name="file_quit"/> + </Menu> + <Menu name="edit"><text>&Edit</text> + <DefineGroup name="edit_undo_merge"/> + <Separator/> + <DefineGroup name="edit_paste_merge"/> + <Separator/> + <DefineGroup name="edit_select_merge"/> + <Separator/> + <DefineGroup name="edit_find_merge"/> + <DefineGroup name="kdev_edit_find_merge"/> + <Separator/> + <DefineGroup name="edit_astyle"/> + <Separator/> + <Merge/> + </Menu> + <Menu name="view"> + <text>&View</text> + <DefineGroup name="history_operations"/> + <Action name="history_back"/> + <Action name="history_forward"/> + <Action name="goto_last_edit_pos"/> + <Separator/> + <Action name="file_switchto"/> + <Action name="raise_editor"/> + <Separator/> + <DefineGroup name="error_operations"/> + <Separator/> + <Merge/> + <Separator/> + <DefineGroup name="view_operations"/> + </Menu> + <Menu name="project"> + <text>&Project</text> + <DefineGroup name="project_new"/> + <Action name="project_open"/> + <Action name="project_open_recent"/> +<!-- <Action name="project_active_language"/> --> + <DefineGroup name="project_import"/> + <Separator/> + <DefineGroup name="project_classes"/> + <Merge/> + <DefineGroup name="designer_project"/> + <Action name="project_options"/> + <Separator/> + <Action name="project_close"/> + </Menu> + <Menu name="build"> + <text>Bu&ild</text> + <Merge/> + <Separator/> + <Action name="stop_processes"/> + </Menu> + <Menu name="debug"> + <text>&Debug</text> + <DefineGroup name="debug"/> + <DefineGroup name="profile"/> + </Menu> + <Merge/> + <Menu name="tools"> + <text>&Tools</text> + <DefineGroup name="tools_operations"/> + <Separator/> + <DefineGroup name="tools_file_operations"/> + <Separator/> + <DefineGroup name="tools_language_operations"/> + <Separator/> + <DefineGroup name="tools_project_operations"/> + <Separator/> + <Merge/> + </Menu> + <Menu name="settings" noMerge="1"> + <text>&Settings</text> + <Action name="settings_show_menubar" /> + <Merge name="StandardToolBarMenuHandler" /> + <Action name="settings_main_toolbar"/> + <Action name="settings_build_toolbar"/> + <Action name="settings_view_toolbar"/> + <Action name="settings_browser_toolbar"/> + <DefineGroup name="show_toolbar_merge" /> + <Action name="settings_viewbar"/> + <Action name="settings_statusbar"/> + <DefineGroup name="show_merge" /> + <Separator /> + <Action name="settings_configure_shortcuts" /> + <Action name="set_configure_toolbars" /> + <Action name="settings_configure_notifications" /> + <Action name="settings_configure_plugins" /> + <Action name="settings_configure_editors" /> + <Action name="settings_configure" /> + <DefineGroup name="configure_merge" /> + </Menu> + <Menu append="settings_merge" name="window"> + <text>&Window</text> + <Action name="view_next_window"/> + <Action name="view_previous_window"/> + <Separator/> + <Action name="split_h"/> + <Action name="split_v"/> + <Separator/> + <Action name="switch_left_dock"/> + <Action name="switch_right_dock"/> + <Action name="switch_bottom_dock"/> + <Separator/> + <DefineGroup name="window_operations"/> + <Merge/> + </Menu> + <Menu name="help" append="about_merge"> + <text>&Help</text> + <Merge/> + </Menu> +</MenuBar> + +<ToolBar name="mainToolBar" position="Top" noMerge="1" fullWidth="true" newline="true" > + <text>Main Toolbar</text> + <Action name="project_open" /> + <DefineGroup name="project_operations"/> + <Action name="goto_last_edit_pos"/> + <Action name="history_back"/> + <Action name="history_forward"/> + <DefineGroup name="file_operations"/> + <DefineGroup name="print_merge"/> + <DefineGroup name="edit_operations"/> + <DefineGroup name="find_operations"/> + <DefineGroup name="view_operations"/> + <DefineGroup name="screenmode_operations"/> + <DefineGroup name="zoom_operations"/> + <Merge/> + <Action name="help_whats_this"/> +</ToolBar> + +<ToolBar name="buildToolBar" position="Top" noMerge="1"> + <text>Build Toolbar</text> + <Merge/> +<!-- <DefineGroup name="build_operations"/> + <DefineGroup name="debug_operations"/>--> + <Action name="stop_processes"/> +</ToolBar> + +<ToolBar name="browserToolBar" position="Top" noMerge="1"> + <text>Browser Toolbar</text> +<!-- <DefineGroup name="class_operations" /> + <DefineGroup name="browser_operations" />--> + <Merge/> +</ToolBar> + +<ToolBar name="extraToolBar" position="Top" noMerge="1" hidden="true"> + <text>Extra Toolbar</text> +</ToolBar> + +<Menu name="rb_popup"> + <Separator/> + <Action name="file_close"/> + <Action name="file_closeother"/> +</Menu> + +<ToolBar name="debugToolBar"> + <text>Debugger Toolbar</text> + <Merge/> +</ToolBar> + +<ToolBar name="viewsession_toolbar" > + <text>View Sessions Toolbar</text> + <Merge/> +</ToolBar> + +</kpartgui> diff --git a/src/kdevideextension.cpp b/src/kdevideextension.cpp new file mode 100644 index 00000000..b6dc4e0d --- /dev/null +++ b/src/kdevideextension.cpp @@ -0,0 +1,129 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "kdevideextension.h" + +#include <qvbox.h> +#include <qcheckbox.h> +#include <qbuttongroup.h> +#include <qradiobutton.h> +#include <qcombobox.h> +#include <klineedit.h> + +#include <klocale.h> +#include <kconfig.h> +#include <kdialogbase.h> +#include <kiconloader.h> +#include <kurlrequester.h> +#include <kapplication.h> +#include <kfontrequester.h> + +#include <kdevplugin.h> +#include <kdevmakefrontend.h> +#include <kdevplugincontroller.h> + +#include "api.h" +#include "settingswidget.h" + +KDevIDEExtension::KDevIDEExtension() + : ShellExtension() +{ +} + +void KDevIDEExtension::init() +{ + s_instance = new KDevIDEExtension(); +} + +void KDevIDEExtension::createGlobalSettingsPage(KDialogBase *dlg) +{ + KConfig* config = kapp->config(); + QVBox *vbox = dlg->addVBoxPage(i18n("General"), i18n("General"), BarIcon("kdevelop", KIcon::SizeMedium) ); + gsw = new SettingsWidget(vbox, "general settings widget"); + + gsw->projectsURL->setMode((int)KFile::Directory); + + config->setGroup("General Options"); + gsw->lastProjectCheckbox->setChecked(config->readBoolEntry("Read Last Project On Startup",true)); + gsw->outputFont->setFont( config->readFontEntry( "OutputViewFont" ) ); + config->setGroup("MakeOutputView"); + gsw->lineWrappingCheckBox->setChecked(config->readBoolEntry("LineWrapping",true)); + gsw->dirNavigMsgCheckBox->setChecked(config->readBoolEntry("ShowDirNavigMsg",false)); + gsw->compileOutputCombo->setCurrentItem(config->readNumEntry("CompilerOutputLevel",2)); + gsw->forceCLocaleRadio->setChecked( config->readBoolEntry( "ForceCLocale", true ) ); + gsw->userLocaleRadio->setChecked( !config->readBoolEntry( "ForceCLocale", true ) ); + + config->setGroup("General Options"); + gsw->projectsURL->setURL(config->readPathEntry("DefaultProjectsDir", QDir::homeDirPath()+"/")); + gsw->designerButtonGroup->setButton( config->readNumEntry( "DesignerApp", 0 ) ); + + QString DesignerSetting = config->readEntry( "DesignerSetting", "ExternalDesigner" ); + gsw->qtDesignerRadioButton->setChecked( DesignerSetting == "ExternalDesigner" ); + gsw->seperateAppRadioButton->setChecked( DesignerSetting == "ExternalKDevDesigner" ); + gsw->embeddedDesignerRadioButton->setChecked( DesignerSetting == "EmbeddedKDevDesigner" ); + + config->setGroup("TerminalEmulator"); + gsw->terminalEdit->setText( config->readEntry( "TerminalApplication", QString::fromLatin1("konsole") ) ); + bool useKDESetting = config->readBoolEntry( "UseKDESetting", true ); + gsw->useKDETerminal->setChecked( useKDESetting ); + gsw->useOtherTerminal->setChecked( !useKDESetting ); +} + +void KDevIDEExtension::acceptGlobalSettingsPage(KDialogBase *dlg) +{ + KConfig* config = kapp->config(); + + config->setGroup("General Options"); + config->writeEntry("DesignerApp", gsw->designerButtonGroup->selectedId()); + config->writeEntry("Read Last Project On Startup",gsw->lastProjectCheckbox->isChecked()); + config->writePathEntry("DefaultProjectsDir", gsw->projectsURL->url()); + config->writeEntry("OutputViewFont", gsw->outputFont->font()); + + QString DesignerSetting; + if ( gsw->qtDesignerRadioButton->isChecked() ) DesignerSetting = "ExternalDesigner"; + if ( gsw->seperateAppRadioButton->isChecked() ) DesignerSetting = "ExternalKDevDesigner"; + if ( gsw->embeddedDesignerRadioButton->isChecked() ) DesignerSetting = "EmbeddedKDevDesigner"; + config->writeEntry( "DesignerSetting", DesignerSetting ); + + config->setGroup("MakeOutputView"); + config->writeEntry("LineWrapping",gsw->lineWrappingCheckBox->isChecked()); + config->writeEntry("ShowDirNavigMsg",gsw->dirNavigMsgCheckBox->isChecked()); + config->writeEntry( "ForceCLocale", gsw->forceCLocaleRadio->isChecked() ); + //current item id must be in sync with the enum! + config->writeEntry("CompilerOutputLevel",gsw->compileOutputCombo->currentItem()); + config->sync(); + if( KDevPlugin *makeExt = API::getInstance()->pluginController()->extension("KDevelop/MakeFrontend")) + { + static_cast<KDevMakeFrontend*>(makeExt)->updateSettingsFromConfig(); + } + + config->setGroup("TerminalEmulator"); + config->writeEntry("UseKDESetting", gsw->useKDETerminal->isChecked() ); + config->writeEntry("TerminalApplication", gsw->terminalEdit->text().stripWhiteSpace() ); +} + +QString KDevIDEExtension::xmlFile() +{ + return "kdevelopui.rc"; +} + +QString KDevIDEExtension::defaultProfile() +{ + return "IDE"; +} diff --git a/src/kdevideextension.h b/src/kdevideextension.h new file mode 100644 index 00000000..af93d8cb --- /dev/null +++ b/src/kdevideextension.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef KDEVIDEEXTENSION_H +#define KDEVIDEEXTENSION_H + +#include <shellextension.h> + +class SettingsWidget; + +class KDevIDEExtension : public ShellExtension { +public: + static void init(); + + virtual void createGlobalSettingsPage(KDialogBase *dlg); + virtual void acceptGlobalSettingsPage(KDialogBase *dlg); + + virtual QString xmlFile(); + + virtual QString defaultProfile(); + +protected: + KDevIDEExtension(); + +private: + SettingsWidget *gsw; +}; + +#endif diff --git a/src/kdevpluginprofilerc b/src/kdevpluginprofilerc new file mode 100644 index 00000000..1c2abb92 --- /dev/null +++ b/src/kdevpluginprofilerc @@ -0,0 +1,52 @@ +[Plugin Profiles] +profiles=Profile_BASE,Profile_COMPILED,Profile_CPP,Profile_SCRIPT,Profile_WEB +default=Profile_BASE + +[Category] +Ada= +C= +C/GNOME= +C/GBA= +C/PalmOS= +C++=Profile_CPP +C++/Embedded=Profile_CPP +C++/KDE=Profile_CPP +C++/wxWidgets= +C++/KDevelop +C++/Generic +C++/GTK+ +C++/QMake= +PHP= +Database= +Shell= +Java= +Java/KDE= +Java/Ant= +Perl= +Ruby= +Python= +Fortran= +Haskell= +Pascal/Free Pascal= + +[Profile_BASE] +plugins=KDevFileView,KDevClassView,KDevBookmarks,KDevQuickOpen + +[Profile_COMPILED] +inherits=Profile_BASE +plugins= + +[Profile_CPP] +inherits=Profile_COMPILED +plugins=KDevDebugger + +[Profile_SCRIPT] +inherits=Profile_BASE +plugins= + +[Profile_WEB] +inherits=Profile_SCRIPT +plugins=KDevcopyto + + + diff --git a/src/languageselectwidget.cpp b/src/languageselectwidget.cpp new file mode 100644 index 00000000..45922c2d --- /dev/null +++ b/src/languageselectwidget.cpp @@ -0,0 +1,165 @@ +/*************************************************************************** + * Copyright (C) 2003 by Harald Fernengel * + * harry@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <qstring.h> +#include <qvariant.h> +#include <qheader.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlistview.h> +#include <qgroupbox.h> +#include <qhbox.h> +#include <qregexp.h> + +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <kservice.h> +#include <ktrader.h> +#include <kapplication.h> +#include <kdevplugin.h> +#include "domutil.h" + +#include "languageselectwidget.h" +#include "plugincontroller.h" + +class LangPluginItem : public QCheckListItem +{ +public: + // name - "Name", label - "GenericName", info - "Comment" + LangPluginItem( QListView * parent, QString const & name, QString const & label, + QString const & info ) + : QCheckListItem( parent, label, QCheckListItem::CheckBox), + _name( name ), _info( info ) + {} + + QString info() { return _info; } + QString name() { return _name; } + +private: + QString _name; + QString _info; +}; + + +LanguageSelectWidget::LanguageSelectWidget(QDomDocument &projectDom, + QWidget *parent, const char *name) + : QWidget(parent, name), m_projectDom(projectDom) +{ + init(); +} + +void LanguageSelectWidget::init() +{ + QVBoxLayout *layout = new QVBoxLayout(this); + + QGroupBox * groupBox1 = new QGroupBox( i18n("Additional Language Support"), this ); + groupBox1->setColumnLayout(0, Qt::Vertical ); + groupBox1->layout()->setSpacing( 6 ); + groupBox1->layout()->setMargin( 11 ); + QVBoxLayout * groupBox1Layout = new QVBoxLayout( groupBox1->layout() ); + groupBox1Layout->setAlignment( Qt::AlignTop ); + + _currentLanguage = new QLabel( "", groupBox1 ); + + _pluginList = new QListView( groupBox1 ); + _pluginList->setResizeMode( QListView::LastColumn ); + _pluginList->addColumn(""); + _pluginList->header()->hide(); + + groupBox1Layout->addWidget(_currentLanguage); + groupBox1Layout->addWidget( _pluginList ); + layout->addWidget( groupBox1 ); + + QGroupBox * groupBox2 = new QGroupBox( i18n("Description"), this ); + groupBox2->setColumnLayout(0, Qt::Vertical ); + groupBox2->layout()->setSpacing( 6 ); + groupBox2->layout()->setMargin( 11 ); + QVBoxLayout * groupBox2Layout = new QVBoxLayout( groupBox2->layout() ); + groupBox2Layout->setAlignment( Qt::AlignTop ); + + _pluginDescription = new QLabel( groupBox2 ); + _pluginDescription->setAlignment( int( QLabel::WordBreak | QLabel::AlignVCenter ) ); + + groupBox2Layout->addWidget( _pluginDescription ); + + layout->addWidget( groupBox2 ); + + connect( _pluginList, SIGNAL( selectionChanged( QListViewItem * ) ), this, SLOT( itemSelected( QListViewItem * ) ) ); + + readProjectConfig(); +} + + +LanguageSelectWidget::~LanguageSelectWidget() +{} + +void LanguageSelectWidget::readProjectConfig() +{ + KTrader::OfferList languageSupportOffers = + KTrader::self()->query(QString::fromLatin1("KDevelop/LanguageSupport"), + QString::fromLatin1("[X-KDevelop-Version] == %1" + ).arg( KDEVELOP_PLUGIN_VERSION )); + + QStringList languages = DomUtil::readListEntry(m_projectDom, "/general/secondaryLanguages", "language"); + QString language = DomUtil::readEntry(m_projectDom, "/general/primarylanguage"); + _currentLanguage->setText(i18n("Primary language is '%1'. Please select additional languages the project might contain.").arg(language)); + + for (KTrader::OfferList::ConstIterator it = languageSupportOffers.begin(); it != languageSupportOffers.end(); ++it) + { + QString la = (*it)->property("X-KDevelop-Language").toString(); + if (la == language) + continue; + LangPluginItem *item = new LangPluginItem( _pluginList, (*it)->property("X-KDevelop-Language").toString(), (*it)->genericName(), (*it)->comment() ); + item->setOn(languages.contains(la)); + } + + QListViewItem * first = _pluginList->firstChild(); + if ( first ) { + _pluginList->setSelected( first, true ); + } +} + +void LanguageSelectWidget::itemSelected( QListViewItem * item ) +{ + if ( !item ) return; + + LangPluginItem * pitem = static_cast<LangPluginItem*>( item ); + _pluginDescription->setText( pitem->info() ); +} + +void LanguageSelectWidget::saveProjectConfig() +{ + QStringList languages; + + QListViewItemIterator it( _pluginList ); + while ( it.current() ) + { + LangPluginItem * item = static_cast<LangPluginItem*>( it.current() ); + if (item->isOn()) + { + languages.append( item->name() ); + } + ++it; + } + + DomUtil::writeListEntry(m_projectDom, "/general/secondaryLanguages", "language", languages); +} + + +void LanguageSelectWidget::accept() +{ + saveProjectConfig(); + emit accepted(); +} + +#include "languageselectwidget.moc" diff --git a/src/languageselectwidget.h b/src/languageselectwidget.h new file mode 100644 index 00000000..dcd063f0 --- /dev/null +++ b/src/languageselectwidget.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2003 by Harald Fernengel * + * harry@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _LANGUAGESELECTWIDGET_H_ +#define _LANGUAGESELECTWIDGET_H_ + +#include <qdialog.h> +#include <qdom.h> +#include <qstringlist.h> + +class QListView; + +class LanguageSelectWidget : public QWidget +{ + Q_OBJECT + +public: + /* for selection of project parts */ + LanguageSelectWidget( QDomDocument &projectDom, QWidget *parent=0, const char *name=0 ); + ~LanguageSelectWidget(); + +public slots: + void accept(); + +signals: + void accepted(); + +private slots: + void itemSelected( QListViewItem * ); + +private: + void init(); + void readProjectConfig(); + void saveProjectConfig(); + + QDomDocument m_projectDom; + QListView * _pluginList; + QLabel * _pluginDescription; + QLabel * _currentLanguage; + +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 00000000..54d64b4c --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,153 @@ +#include <config.h> + +#include <kaboutdata.h> +#include <kapplication.h> +#include <kcmdlineargs.h> +#include <klocale.h> +#include <kmainwindow.h> +#include <kstandarddirs.h> +#include <kdebug.h> +#include <dcopclient.h> + +#include <qfileinfo.h> + +#include "splashscreen.h" +#include "toplevel.h" +#include "plugincontroller.h" +#include "partcontroller.h" +#include "core.h" +#include "projectmanager.h" + +#include "kdevideextension.h" + +static KCmdLineOptions options[] = +{ + { "profile <profile>", I18N_NOOP("Profile to load"), 0 }, + { "+file(s)", I18N_NOOP("Files to load"), 0 }, + { 0,0,0 } +}; + +int main(int argc, char *argv[]) +{ + static const char description[] = I18N_NOOP("The KDevelop Integrated Development Environment"); + KAboutData aboutData("kdevelop", I18N_NOOP("KDevelop"), + VERSION, description, KAboutData::License_GPL, + I18N_NOOP("(c) 1999-2007, The KDevelop developers"), "", "http://www.kdevelop.org"); + aboutData.addAuthor("Alexander Dymo", I18N_NOOP("Release coordinator, Overall improvements, Pascal support, C++ support, New File and Documentation parts"), "adymo@kdevelop.org"); + aboutData.addAuthor("Amilcar do Carmo Lucas", I18N_NOOP("Release coordinator, API documentation, Doxygen and autoproject patches"), "amilcar@ida.ing.tu-bs.de"); + aboutData.addAuthor("David Nolden", I18N_NOOP("Advanced C++ code completion, C++ support, overall improvements"), "david.nolden.kdevelop@art-master.de"); + aboutData.addAuthor("Bernd Gehrmann", I18N_NOOP("Initial idea, basic architecture, much initial source code"), "bernd@kdevelop.org"); + aboutData.addAuthor("Caleb Tennis", I18N_NOOP("KTabBar, bugfixes"), "caleb@aei-tech.com"); + aboutData.addAuthor("Richard Dale", I18N_NOOP("Java & Objective C support"), "Richard_Dale@tipitina.demon.co.uk"); + aboutData.addAuthor("John Birch", I18N_NOOP("Debugger frontend"), "jbb@kdevelop.org"); + aboutData.addAuthor("Vladimir Prus", I18N_NOOP("Debugger frontend"), "ghost@cs.msu.su"); + aboutData.addAuthor("Sandy Meier", I18N_NOOP("PHP support, context menu stuff"), "smeier@kdevelop.org"); + aboutData.addAuthor("Kurt Granroth", I18N_NOOP("KDE application templates"), "kurth@granroth.org"); + aboutData.addAuthor("Ian Reinhart Geiser", I18N_NOOP("Dist part, bash support, application templates"), "geiseri@yahoo.com"); + aboutData.addAuthor("Matthias Hoelzer-Kluepfel", I18N_NOOP("Several components, htdig indexing"), "hoelzer@kde.org"); + aboutData.addAuthor("Victor Roeder", I18N_NOOP("Help with Automake manager and persistent class store"), "victor_roeder@gmx.de"); + aboutData.addAuthor("Megan Webb", I18N_NOOP("Automake manager patches, Astyle plugin update, plugin patches and improvements"),"kdeveloper.megan@gmail.com"); + aboutData.addAuthor("Harald Fernengel", I18N_NOOP("Ported to Qt 3, patches, valgrind, diff and perforce support"), "harry@kdevelop.org"); + aboutData.addAuthor("Roberto Raggi", I18N_NOOP("QEditor component, code completion, Abbrev component, C++ support, Java support"), "roberto@kdevelop.org"); + aboutData.addAuthor("Simon Hausmann", I18N_NOOP("Help with KParts infrastructure"), "hausmann@kde.org"); + aboutData.addAuthor("Oliver Kellogg", I18N_NOOP("Ada support"), "okellogg@users.sourceforge.net"); + aboutData.addAuthor("Andreas Pakulat", I18N_NOOP("QMake projectmanager, Qt4 Support"), "apaku@gmx.de"); + aboutData.addAuthor("Jakob Simon-Gaarde", I18N_NOOP("QMake projectmanager"), "jsgaarde@tdcspace.dk"); + aboutData.addAuthor("F@lk Brettschneider", I18N_NOOP("MDI modes, QEditor, bugfixes"), "falkbr@kdevelop.org"); + aboutData.addAuthor("Mario Scalas", I18N_NOOP("PartExplorer, redesign of CvsPart, patches, bugs(fixes)"), "mario.scalas@libero.it"); + aboutData.addAuthor("Jens Dagerbo", I18N_NOOP("Replace, Bookmarks, FileList and CTags2 plugins. Overall improvements and patches"), "jens.dagerbo@swipnet.se"); + aboutData.addAuthor("Julian Rockey", I18N_NOOP("Filecreate part and other bits and patches"), "linux@jrockey.com"); + aboutData.addCredit("Ajay Guleria", I18N_NOOP("ClearCase support"), "ajay_guleria@yahoo.com"); + aboutData.addCredit("Marek Janukowicz", I18N_NOOP("Ruby support"), "child@t17.ds.pwr.wroc.pl"); + + aboutData.addCredit("The KWrite authors", I18N_NOOP("Kate editor component"), "kwrite-devel@kde.org"); + aboutData.addCredit("The KHTML authors", I18N_NOOP("HTML documentation component"), "kwrite-devel@kde.org"); + aboutData.addCredit("Robert Moniot", I18N_NOOP("Fortran documentation"), "moniot@fordham.edu"); + aboutData.addCredit("Ka-Ping Yee", I18N_NOOP("Python documentation utility"), "ping@lfw.org"); + aboutData.addCredit("Dimitri van Heesch", I18N_NOOP("Doxygen wizard"), "dimitri@stack.nl"); + aboutData.addCredit("Hugo Varotto", I18N_NOOP("Fileselector component"), "hugo@varotto-usa.com"); + aboutData.addCredit("Matt Newell", I18N_NOOP("Fileselector component"), "newellm@proaxis.com"); + aboutData.addCredit("Trolltech AS", I18N_NOOP("Designer code"), "info@trolltech.com"); + aboutData.addCredit("Daniel Engelschalt", I18N_NOOP("C++ code completion, persistent class store"), "daniel.engelschalt@gmx.net"); + aboutData.addCredit("Stephane ANCELOT", I18N_NOOP("Patches"), "sancelot@free.fr"); + aboutData.addCredit("Jens Zurheide", I18N_NOOP("Patches"), "jens.zurheide@gmx.de"); + aboutData.addCredit("Luc Willems", I18N_NOOP("Help with Perl support"), "Willems.luc@pandora.be"); + aboutData.addCredit("Marcel Turino", I18N_NOOP("Documentation index view"), "M.Turino@gmx.de"); + aboutData.addCredit("Yann Hodique", I18N_NOOP("Patches"), "Yann.Hodique@lifl.fr"); + aboutData.addCredit("Tobias Gl\303\244\303\237er" , I18N_NOOP("Documentation Finder, qmake projectmanager patches, usability improvements, bugfixes ... "), "tobi.web@gmx.de"); + aboutData.addCredit("Andreas Koepfle" , I18N_NOOP("QMake project manager patches"), "koepfle@ti.uni-mannheim.de"); + aboutData.addCredit("Sascha Cunz" , I18N_NOOP("Cleanup and bugfixes for qEditor, AutoMake and much other stuff"), "sascha@kdevelop.org"); + aboutData.addCredit("Robert Gruber" , I18N_NOOP("SnippetPart, debugger and usability patches"), "rgruber@users.sourceforge.net"); + aboutData.addCredit("Zoran Karavla", I18N_NOOP("Artwork for the Ruby language"), "webmaster@the-error.net", "http://the-error.net"); + + KCmdLineArgs::init(argc, argv, &aboutData); + KCmdLineArgs::addCmdLineOptions( options ); + KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); + + KApplication app; + + KDevIDEExtension::init(); + + KDevSplashScreen *splash = 0; + QString splashFile = locate("appdata", "pics/kdevelop-splash.png"); + if (!splashFile.isEmpty()) + { + QPixmap pm; + pm.load(splashFile); + splash = new KDevSplashScreen( pm ); + } + + app.processEvents(); + + if (splash) splash->message( i18n( "Loading Settings" ) ); + TopLevel::getInstance()->loadSettings(); + + QObject::connect(PluginController::getInstance(), SIGNAL(loadingPlugin(const QString &)), + splash, SLOT(message(const QString &))); + if (splash) splash->show(); + + PluginController::getInstance()->loadInitialPlugins(); + + Core::getInstance()->doEmitCoreInitialized(); + + if (splash) splash->message( i18n( "Starting GUI" ) ); + TopLevel::getInstance()->main()->show(); + + if (splash) delete splash; + + for( int i=0; i<args->count(); ++i ){ + kdDebug(9000) << "------> arg " << args->arg(i) << endl; + } + + bool openProject = false; + if( args->count() == 0 ){ + ProjectManager::getInstance()->loadDefaultProject(); + openProject = true; + } else if( args->count() > 0 ){ + KURL url = args->url( 0 ); + QString ext = QFileInfo( url.fileName() ).extension(); + if( ext == "kdevelop" ){ + ProjectManager::getInstance()->loadProject( url ); + openProject = true; + } + } + + if( !openProject ){ + for( int a=0; a<args->count(); ++a ){ + PartController::getInstance()->editDocument( KURL(args->url(a)) ); + } + } + + kapp->dcopClient()->registerAs("kdevelop"); + + int ret = app.exec(); + + ProjectManager::getInstance()->closeProject( true ); // exiting + delete ProjectManager::getInstance(); + + delete PluginController::getInstance(); + if (TopLevel::mainWindowValid()) + delete TopLevel::getInstance(); + + return ret; +} diff --git a/src/main_assistant.cpp b/src/main_assistant.cpp new file mode 100644 index 00000000..0eb80192 --- /dev/null +++ b/src/main_assistant.cpp @@ -0,0 +1,115 @@ +#include <config.h> + +#include <kaboutdata.h> +#include <kapplication.h> +#include <kcmdlineargs.h> +#include <klocale.h> +#include <kmainwindow.h> +#include <kstandarddirs.h> +#include <kdebug.h> +#include <dcopclient.h> + +#include <qfileinfo.h> + +#include "splashscreen.h" +#include "toplevel.h" +#include "plugincontroller.h" +#include "partcontroller.h" +#include "core.h" +#include "projectmanager.h" + +#include "kdevassistantextension.h" + +static KCmdLineOptions options[] = +{ + { "profile <profile>", I18N_NOOP("Profile to load"), 0 }, +/* { "+file(s)", I18N_NOOP("Files to load"), 0 },*/ + { 0,0,0 } +}; + +int main(int argc, char *argv[]) +{ + static const char description[] = I18N_NOOP("The KDevelop Integrated Development Environment:\nassistant and documentation viewer"); + KAboutData aboutData("kdevassistant", I18N_NOOP("KDevelop Assistant"), + VERSION, description, KAboutData::License_GPL, + I18N_NOOP("(c) 1999-2007, The KDevelop developers"), "", "http://www.kdevelop.org"); + aboutData.addAuthor("Alexander Dymo", I18N_NOOP("Release coordinator, Overall improvements, Pascal support, C++ support, New File and Documentation parts"), "adymo@kdevelop.org"); + aboutData.addAuthor("Amilcar do Carmo Lucas", I18N_NOOP("Release coordinator, API documentation, Doxygen and autoproject patches"), "amilcar@ida.ing.tu-bs.de"); + aboutData.addAuthor("Bernd Gehrmann", I18N_NOOP("Initial idea, basic architecture, much initial source code"), "bernd@kdevelop.org"); + aboutData.addAuthor("Caleb Tennis", I18N_NOOP("KTabBar, bugfixes"), "caleb@aei-tech.com"); + aboutData.addAuthor("Richard Dale", I18N_NOOP("Java & Objective C support"), "Richard_Dale@tipitina.demon.co.uk"); + aboutData.addAuthor("John Birch", I18N_NOOP("Debugger frontend"), "jbb@kdevelop.org"); + aboutData.addAuthor("Sandy Meier", I18N_NOOP("PHP support, context menu stuff"), "smeier@kdevelop.org"); + aboutData.addAuthor("Kurt Granroth", I18N_NOOP("KDE application templates"), "kurth@granroth.org"); + aboutData.addAuthor("Ian Reinhart Geiser", I18N_NOOP("Dist part, bash support, application templates"), "geiseri@yahoo.com"); + aboutData.addAuthor("Matthias Hoelzer-Kluepfel", I18N_NOOP("Several components, htdig indexing"), "hoelzer@kde.org"); + aboutData.addAuthor("Victor Roeder", I18N_NOOP("Help with Automake manager and persistent class store"), "victor_roeder@gmx.de"); + aboutData.addAuthor("Harald Fernengel", I18N_NOOP("Ported to Qt 3, patches, valgrind, diff and perforce support"), "harry@kdevelop.org"); + aboutData.addAuthor("Roberto Raggi", I18N_NOOP("QEditor component, code completion, Abbrev component, C++ support, Java support"), "roberto@kdevelop.org"); + aboutData.addAuthor("Simon Hausmann", I18N_NOOP("Help with KParts infrastructure"), "hausmann@kde.org"); + aboutData.addAuthor("Oliver Kellogg", I18N_NOOP("Ada support"), "okellogg@users.sourceforge.net"); + aboutData.addAuthor("Jakob Simon-Gaarde", I18N_NOOP("QMake projectmanager"), "jsgaarde@tdcspace.dk"); + aboutData.addAuthor("F@lk Brettschneider", I18N_NOOP("MDI modes, QEditor, bugfixes"), "falkbr@kdevelop.org"); + aboutData.addAuthor("Mario Scalas", I18N_NOOP("PartExplorer, redesign of CvsPart, patches, bugs(fixes)"), "mario.scalas@libero.it"); + aboutData.addAuthor("Jens Dagerbo", I18N_NOOP("Replace, Bookmarks, FileList and CTags2 plugins. Overall improvements and patches"), "jens.dagerbo@swipnet.se"); + aboutData.addAuthor("Julian Rockey", I18N_NOOP("Filecreate part and other bits and patches"), "linux@jrockey.com"); + aboutData.addCredit("Ajay Guleria", I18N_NOOP("ClearCase support"), "ajay_guleria@yahoo.com"); + aboutData.addCredit("Marek Janukowicz", I18N_NOOP("Ruby support"), "child@t17.ds.pwr.wroc.pl"); + + aboutData.addCredit("The KWrite authors", I18N_NOOP("Kate editor component"), "kwrite-devel@kde.org"); + aboutData.addCredit("The KHTML authors", I18N_NOOP("HTML documentation component"), "kfm-devel@kde.org"); + aboutData.addCredit("Robert Moniot", I18N_NOOP("Fortran documentation"), "moniot@fordham.edu"); + aboutData.addCredit("Ka-Ping Yee", I18N_NOOP("Python documentation utility"), "ping@lfw.org"); + aboutData.addCredit("Dimitri van Heesch", I18N_NOOP("Doxygen wizard"), "dimitri@stack.nl"); + aboutData.addCredit("Hugo Varotto", I18N_NOOP("Fileselector component"), "hugo@varotto-usa.com"); + aboutData.addCredit("Matt Newell", I18N_NOOP("Fileselector component"), "newellm@proaxis.com"); + aboutData.addCredit("Trolltech AS", I18N_NOOP("Designer code"), "info@trolltech.com"); + aboutData.addCredit("Daniel Engelschalt", I18N_NOOP("C++ code completion, persistent class store"), "daniel.engelschalt@gmx.net"); + aboutData.addCredit("Stephane ANCELOT", I18N_NOOP("Patches"), "sancelot@free.fr"); + aboutData.addCredit("Jens Zurheide", I18N_NOOP("Patches"), "jens.zurheide@gmx.de"); + aboutData.addCredit("Luc Willems", I18N_NOOP("Help with Perl support"), "Willems.luc@pandora.be"); + aboutData.addCredit("Marcel Turino", I18N_NOOP("Documentation index view"), "M.Turino@gmx.de"); + aboutData.addCredit("Yann Hodique", I18N_NOOP("Patches"), "Yann.Hodique@lifl.fr"); + aboutData.addCredit("Tobias Gl\303\244\303\237er" , I18N_NOOP("Documentation Finder, qmake projectmanager patches, usability improvements, bugfixes ... "), "tobi.web@gmx.de"); + aboutData.addCredit("Andreas Koepfle" , I18N_NOOP("QMake project manager patches"), "koepfle@ti.uni-mannheim.de"); + aboutData.addCredit("Sascha Cunz" , I18N_NOOP("Cleanup and bugfixes for qEditor, AutoMake and much other stuff"), "mail@sacu.de"); + + KCmdLineArgs::init(argc, argv, &aboutData); + KCmdLineArgs::addCmdLineOptions( options ); +// KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); + + KApplication app; + + KDevAssistantExtension::init(); + + KDevSplashScreen *splash = 0; + QString splashFile = locate("data", "kdevelop/pics/kdevassistant-splash.png"); + if (!splashFile.isEmpty()) + { + QPixmap pm; + pm.load(splashFile); + splash = new KDevSplashScreen( pm ); + } + if (splash) splash->show(); + + app.processEvents(); + + QObject::connect(PluginController::getInstance(), SIGNAL(loadingPlugin(const QString &)), + splash, SLOT(showMessage(const QString &))); + + if (splash) splash->message( i18n( "Loading Settings" ) ); + TopLevel::getInstance()->loadSettings(); + + PluginController::getInstance()->loadInitialPlugins(); + + if (splash) splash->message( i18n( "Starting GUI" ) ); + TopLevel::getInstance()->main()->show(); + + Core::getInstance()->doEmitCoreInitialized(); + + if (splash) delete splash; + + kapp->dcopClient()->registerAs("kdevassistant"); + + return app.exec(); +} diff --git a/src/mainwindowshare.cpp b/src/mainwindowshare.cpp new file mode 100644 index 00000000..4dcb17c9 --- /dev/null +++ b/src/mainwindowshare.cpp @@ -0,0 +1,451 @@ +/*************************************************************************** + mainwindowshare.cpp - shared stuff of the main widgets + ------------------- + begin : 19 Dec 2002 + copyright : (C) 2002 by Falk Brettschneider + email : falk@kdevelop.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <qcheckbox.h> +#include <qvbox.h> +#include <qbuttongroup.h> +#include <qradiobutton.h> +#include <qdir.h> +#include <qregexp.h> + +#include <kxmlguiclient.h> +#include <kaction.h> +#include <kaboutdata.h> +#include <kstdaction.h> +#include <kapplication.h> +#include <klocale.h> +#include <kstatusbar.h> +#include <kparts/mainwindow.h> +#include <kdialogbase.h> +#include <kconfig.h> +#include <kkeydialog.h> +#include <kmenubar.h> +#include <kedittoolbar.h> +#include <kbugreport.h> +#include <kurlrequester.h> +#include <kpopupmenu.h> +#include <kiconloader.h> + +#include <ktexteditor/document.h> +#include <ktexteditor/view.h> +#include <ktexteditor/configinterface.h> +#include <kparts/partmanager.h> +#include <kdeversion.h> +#include <kdebug.h> +#include <knotifydialog.h> + + +#include <config.h> + +#include "partcontroller.h" +#include "projectmanager.h" +#include "core.h" +#include "api.h" +#include "kdevmakefrontend.h" +#include "toplevel.h" +#include "plugincontroller.h" + +#include "kdevplugininfo.h" + +#include "mainwindowshare.h" + +#include "shellextension.h" + +using namespace MainWindowUtils; + +MainWindowShare::MainWindowShare(QObject* pParent, const char* name) + :QObject(pParent, name) + ,m_toggleMainToolbar(0L) + ,m_toggleBuildToolbar(0L) + ,m_toggleViewToolbar(0L) + ,m_toggleBrowserToolbar(0L) + ,m_toggleStatusbar(0L) + ,m_stopProcesses(0L) +{ + m_pMainWnd = (KParts::MainWindow*)pParent; +} + +void MainWindowShare::init() +{ + connect(Core::getInstance(), SIGNAL(contextMenu(QPopupMenu *, const Context *)), + this, SLOT(contextMenu(QPopupMenu *, const Context *))); + + connect( m_pMainWnd->actionCollection(), SIGNAL( actionStatusText( const QString & ) ), + this, SLOT( slotActionStatusText( const QString & ) ) ); +} + +void MainWindowShare::slotActionStatusText( const QString &text ) +{ +// kdDebug(9000) << "MainWindowShare::slotActionStatusText() - " << text << endl; + + if ( ! m_pMainWnd ) return; + + KStatusBar * statusBar = m_pMainWnd->statusBar(); + + if ( ! statusBar ) return; + + statusBar->message( text ); +} + +void MainWindowShare::createActions() +{ + ProjectManager::getInstance()->createActions( m_pMainWnd->actionCollection() ); + + KStdAction::quit(this->parent(), SLOT(close()), m_pMainWnd->actionCollection()); + + KAction* action; + + m_stopProcesses = new KToolBarPopupAction( i18n( "&Stop" ), "stop", + Key_Escape, this, SLOT(slotStopButtonPressed()), + m_pMainWnd->actionCollection(), "stop_processes" ); + m_stopProcesses->setToolTip(i18n("Stop")); + m_stopProcesses->setWhatsThis(i18n("<b>Stop</b><p>Stops all running processes (like building process, grep command, etc.). When placed onto a toolbar provides a popup menu to choose a process to stop.")); + m_stopProcesses->setEnabled( false ); + connect(m_stopProcesses->popupMenu(), SIGNAL(aboutToShow()), + this, SLOT(slotStopMenuAboutToShow())); + connect(m_stopProcesses->popupMenu(), SIGNAL(activated(int)), + this, SLOT(slotStopPopupActivated(int))); + + connect( Core::getInstance(), SIGNAL(activeProcessChanged(KDevPlugin*, bool)), + this, SLOT(slotActiveProcessChanged(KDevPlugin*, bool)) ); + + action = KStdAction::showMenubar( + this, SLOT(slotShowMenuBar()), + m_pMainWnd->actionCollection(), "settings_show_menubar" ); + action->setToolTip(beautifyToolTip(action->text())); + action->setWhatsThis(QString("<b>%1</b><p>%2").arg(beautifyToolTip(action->text())).arg(i18n("Lets you switch the menubar on/off."))); + + action = KStdAction::keyBindings( + this, SLOT(slotKeyBindings()), + m_pMainWnd->actionCollection(), "settings_configure_shortcuts" ); + action->setToolTip(beautifyToolTip(action->text())); + action->setWhatsThis(QString("<b>%1</b><p>%2").arg(beautifyToolTip(action->text())).arg(i18n("Lets you configure shortcut keys."))); + + action = KStdAction::configureToolbars( + this, SLOT(slotConfigureToolbars()), + m_pMainWnd->actionCollection(), "settings_configure_toolbars" ); + action->setToolTip(beautifyToolTip(action->text())); + action->setWhatsThis(QString("<b>%1</b><p>%2").arg(beautifyToolTip(action->text())).arg(i18n("Lets you configure toolbars."))); + + action = KStdAction::configureNotifications( + this, SLOT(slotConfigureNotifications()), + m_pMainWnd->actionCollection(), "settings_configure_notifications" ); + action->setToolTip(beautifyToolTip(action->text())); + action->setWhatsThis(QString("<b>%1</b><p>%2").arg(beautifyToolTip(action->text())).arg(i18n("Lets you configure system notifications."))); + + action = KStdAction::preferences(this, SLOT(slotSettings()), + m_pMainWnd->actionCollection(), "settings_configure" ); + action->setToolTip( i18n( "Configure KDevelop" ) ); + action->setWhatsThis(QString("<b>%1</b><p>%2").arg(i18n( "Configure KDevelop" )).arg(i18n("Lets you customize KDevelop."))); + + m_toggleStatusbar = KStdAction::showToolbar(this, SLOT(slotToggleStatusbar()),m_pMainWnd->actionCollection(), "settings_statusbar"); + m_toggleStatusbar->setText(i18n("Show &Statusbar")); + m_toggleStatusbar->setToolTip( i18n("Show statusbar") ); + m_toggleStatusbar->setWhatsThis(i18n("<b>Show statusbar</b><p>Hides or shows the statusbar.")); + + action = new KAction( i18n("&Next Window"), ALT+Key_Right, this, SIGNAL(gotoNextWindow()),m_pMainWnd->actionCollection(), "view_next_window"); + action->setToolTip( i18n("Next window") ); + action->setWhatsThis(i18n("<b>Next window</b><p>Switches to the next window.")); + + action = new KAction( i18n("&Previous Window"), ALT+Key_Left, this, SIGNAL(gotoPreviousWindow()),m_pMainWnd->actionCollection(), "view_previous_window"); + action->setToolTip( i18n("Previous window") ); + action->setWhatsThis(i18n("<b>Previous window</b><p>Switches to the previous window.")); + + action = new KAction( i18n("&Last Accessed Window"), ALT+Key_Up, this, SIGNAL(gotoLastWindow()), m_pMainWnd->actionCollection(), "view_last_window"); + action->setToolTip( i18n("Last accessed window") ); + action->setWhatsThis(i18n("<b>Last accessed window</b><p>Switches to the last viewed window (Hold the Alt key pressed and walk on by repeating the Up key).")); + + action = new KAction( i18n("&First Accessed Window"), ALT+Key_Down, this, SIGNAL(gotoFirstWindow()), m_pMainWnd->actionCollection(), "view_first_window"); + action->setToolTip( i18n("First accessed window") ); + action->setWhatsThis(i18n("<b>First accessed window</b><p>Switches to the first accessed window (Hold the Alt key pressed and walk on by repeating the Down key).")); + + action = new KAction( i18n("Configure Plugins..."), SmallIconSet("configure"), 0, PluginController::getInstance(), SLOT(selectPlugins()), m_pMainWnd->actionCollection(), "settings_configure_plugins" ); + + m_configureEditorAction = new KAction( i18n("Configure &Editor..."), SmallIconSet("configure"), 0, this, SLOT( slotConfigureEditors() ), m_pMainWnd->actionCollection(), "settings_configure_editors"); + m_configureEditorAction->setToolTip( i18n("Configure editor settings") ); + m_configureEditorAction->setWhatsThis(i18n("<b>Configure editor</b><p>Opens editor configuration dialog.")); + m_configureEditorAction->setEnabled( false ); + + KDevPartController * partController = API::getInstance()->partController(); + connect( partController, SIGNAL(activePartChanged(KParts::Part*)), this, SLOT(slotActivePartChanged(KParts::Part* )) ); +} + +void MainWindowShare::slotReportBug() +{ + KBugReport a(m_pMainWnd, true, KGlobal::instance()->aboutData() ); + a.exec(); +} + +void MainWindowShare::slotToggleMainToolbar() +{ + if (m_toggleMainToolbar->isChecked()) + m_pMainWnd->toolBar("mainToolBar")->show(); + else + m_pMainWnd->toolBar("mainToolBar")->hide(); +} + +void MainWindowShare::slotToggleBuildToolbar() +{ + if (m_toggleBuildToolbar->isChecked()) + m_pMainWnd->toolBar("buildToolBar")->show(); + else + m_pMainWnd->toolBar("buildToolBar")->hide(); +} + +void MainWindowShare::slotToggleViewToolbar() +{ + if (m_toggleViewToolbar->isChecked()) + m_pMainWnd->toolBar("viewToolBar")->show(); + else + m_pMainWnd->toolBar("viewToolBar")->hide(); +} + +void MainWindowShare::slotToggleBrowserToolbar() +{ + if (m_toggleBrowserToolbar->isChecked()) + m_pMainWnd->toolBar("browserToolBar")->show(); + else + m_pMainWnd->toolBar("browserToolBar")->hide(); +} + +void MainWindowShare::slotToggleStatusbar() +{ + KStatusBar* sb = (KStatusBar*) m_pMainWnd->statusBar(); + if (m_toggleStatusbar->isChecked()) + sb->show(); + else + sb->hide(); +} + +void MainWindowShare::slotStopButtonPressed() +{ + Core::getInstance()->doEmitStopButtonPressed(); +} + +void MainWindowShare::slotActiveProcessChanged( KDevPlugin* plugin, bool active ) +{ + if ( !plugin ) + return; + + if ( active ) { + activeProcesses.append( plugin ); + } else { + activeProcesses.removeRef( plugin ); + } + m_stopProcesses->setEnabled( !activeProcesses.isEmpty() ); +} + +void MainWindowShare::slotStopPopupActivated( int id ) +{ + KDevPlugin* plugin = activeProcesses.at( id ); + if ( plugin && plugin->info()->genericName() == m_stopProcesses->popupMenu()->text( id ) ) { + Core::getInstance()->doEmitStopButtonPressed( plugin ); + return; + } else { + // oops... list has changed in the meantime + QString str = m_stopProcesses->popupMenu()->text( id ); + for ( plugin = activeProcesses.first(); plugin; plugin = activeProcesses.next() ) { + if ( plugin->info()->genericName() == str ) { + Core::getInstance()->doEmitStopButtonPressed( plugin ); + return; + } + } + } +} + +void MainWindowShare::slotStopMenuAboutToShow() +{ + QPopupMenu* popup = m_stopProcesses->popupMenu(); + popup->clear(); + + int i = 0; + for ( KDevPlugin* plugin = activeProcesses.first(); plugin; plugin = activeProcesses.next() ) { + popup->insertItem( plugin->info()->genericName(), i++ ); + } +} + +void MainWindowShare::slotShowMenuBar() +{ + if (m_pMainWnd->menuBar()->isVisible()) { + m_pMainWnd->menuBar()->hide(); + } else { + m_pMainWnd->menuBar()->show(); + } + m_pMainWnd->saveMainWindowSettings( KGlobal::config(), "Mainwindow" ); +} + +void MainWindowShare::slotConfigureNotifications() +{ + KNotifyDialog::configure(m_pMainWnd, "Notification Configuration Dialog"); +} + +void MainWindowShare::slotSettings() +{ + KDialogBase dlg(KDialogBase::IconList, i18n("Configure KDevelop"), + KDialogBase::Help|KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, m_pMainWnd, + "customization dialog"); + dlg.setHelp("setup"); + + ShellExtension::getInstance()->createGlobalSettingsPage(&dlg); + + KConfig* config = kapp->config(); + + config->setGroup("Global Settings Dialog"); + int height = config->readNumEntry( "Height", 600 ); + int width = config->readNumEntry( "Width", 800 ); + + dlg.resize( width, height ); + + Core::getInstance()->doEmitConfigWidget(&dlg); + dlg.exec(); + + config->setGroup("Global Settings Dialog"); + config->writeEntry( "Height", dlg.size().height() ); + config->writeEntry( "Width", dlg.size().width() ); + + if ( dlg.result() != QDialog::Rejected ) + ShellExtension::getInstance()->acceptGlobalSettingsPage(&dlg); +} + +void MainWindowShare::slotConfigureEditors() +{ + kdDebug(9000) << " *** MainWindowShare::slotConfigureEditors()" << endl; + + KDevPartController * partController = API::getInstance()->partController(); + KParts::Part * part = partController->activePart(); + + KTextEditor::ConfigInterface * conf = dynamic_cast<KTextEditor::ConfigInterface*>( part ); + if ( ! conf ) + { + kdDebug(9000) << "*** No KTextEditor::ConfigInterface for part!" << endl; + return; + } + + // show the modal config dialog for this part if it has a ConfigInterface + conf->configDialog(); + conf->writeConfig(); + +} + +void MainWindowShare::slotGUICreated( KParts::Part * part ) +{ +// kdDebug(9000) << "MainWindowShare::slotGUICreated()" << endl; + + if ( ! part ) return; + + // disable configuration entry if created part is not an editor + if ( ! dynamic_cast<KTextEditor::ConfigInterface *>( part ) ) + { + m_configureEditorAction->setEnabled( false ); + return; + } + + m_configureEditorAction->setEnabled( true ); + + // remove the part's merged menu entry + KAction * action = part->action("set_confdlg"); // name from katepartui.rc + if ( action ) + { + kdDebug(9000) << " *** found \"set_confdlg\" action - unplugging" << endl; + action->unplugAll(); + } + + if ( KAction * action = part->action("file_save") ) + { + kdDebug(9000) << " *** found \"file_save\" action - disconnecting" << endl; + disconnect( action, SIGNAL(activated()), 0, 0 ); + connect( action, SIGNAL(activated()), PartController::getInstance(), SLOT(slotSave()) ); + } + + if ( KAction * action = part->action("file_reload") ) + { + kdDebug(9000) << " *** found \"file_reload\" action - disconnecting" << endl; + disconnect( action, SIGNAL(activated()), 0, 0 ); + connect( action, SIGNAL(activated()), PartController::getInstance(), SLOT(slotReload()) ); + } +} + +// called when OK ar Apply is clicked in the EditToolbar Dialog +void MainWindowShare::slotNewToolbarConfig() +{ + // replug actionlists here... + + m_pMainWnd->applyMainWindowSettings( KGlobal::config(), "Mainwindow" ); + +// PartController::getInstance()->reinstallPopups(); +} + +void MainWindowShare::slotKeyBindings() +{ + KKeyDialog dlg( false, m_pMainWnd ); + QPtrList<KXMLGUIClient> clients = m_pMainWnd->guiFactory()->clients(); + for( QPtrListIterator<KXMLGUIClient> it( clients ); + it.current(); ++it ) { + dlg.insert( (*it)->actionCollection() ); + } + if ( dlg.configure() == KKeyDialog::Accepted ) + { + // this is needed for when we have multiple embedded kateparts and change one of them. + // it also needs to be done to their views, as they too have actioncollections to update + if( const QPtrList<KParts::Part> * partlist = PartController::getInstance()->parts() ) + { + QPtrListIterator<KParts::Part> it( *partlist ); + while ( KParts::Part* part = it.current() ) + { + if ( KTextEditor::Document * doc = dynamic_cast<KTextEditor::Document*>( part ) ) + { + doc->reloadXML(); + + QPtrList<KTextEditor::View> const & list = doc->views(); + QPtrListIterator<KTextEditor::View> itt( list ); + while( KTextEditor::View * view = itt.current() ) + { + view->reloadXML(); + ++itt; + } + } + ++it; + } + } + Core::setupShourtcutTips(); + } +} + +void MainWindowShare::slotConfigureToolbars() +{ + m_pMainWnd->saveMainWindowSettings( KGlobal::config(), "Mainwindow" ); + KEditToolbar dlg( m_pMainWnd->factory() ); + connect(&dlg, SIGNAL(newToolbarConfig()), this, SLOT(slotNewToolbarConfig())); + dlg.exec(); +} + +void MainWindowShare::contextMenu(QPopupMenu* popup, const Context *) +{ + if ( m_pMainWnd->menuBar()->isVisible() ) + return; + + int id = popup->insertItem( i18n("Show &Menubar"), m_pMainWnd->menuBar(), SLOT(show()) ); + popup->setWhatsThis(id, i18n("<b>Show menubar</b><p>Lets you switch the menubar on/off.")); +} + +void MainWindowShare::slotActivePartChanged( KParts::Part * part ) +{ + m_configureEditorAction->setEnabled( part && dynamic_cast<KTextEditor::Document*>(part) ); +} + +#include "mainwindowshare.moc" +//kate: space-indent on; indent-width 4; diff --git a/src/mainwindowshare.h b/src/mainwindowshare.h new file mode 100644 index 00000000..6fba07a3 --- /dev/null +++ b/src/mainwindowshare.h @@ -0,0 +1,88 @@ +/*************************************************************************** + mainwindowshare.h - shared stuff of the main widgets + ------------------- + begin : 19 Dec 2002 + copyright : (C) 2002 by Falk Brettschneider + email : falk@kdevelop.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#ifndef __MAINWINDOWSHARE_H__ +#define __MAINWINDOWSHARE_H__ + +#include <qobject.h> + +class KAction; +class KToggleAction; +namespace KParts { + class MainWindow; +} +/** +Shared main window functionality. +*/ +class MainWindowShare : public QObject +{ + Q_OBJECT +public: + MainWindowShare(QObject* pParent = 0L, const char* name = 0L); + ~MainWindowShare() {} + + void createActions(); + void init(); + +public slots: + void slotGUICreated( KParts::Part * ); + +signals: + void gotoNextWindow(); + void gotoPreviousWindow(); + void gotoFirstWindow(); + void gotoLastWindow(); + +private slots: + void slotReportBug(); + void slotKeyBindings(); + void slotConfigureToolbars(); + void slotConfigureNotifications(); + void slotConfigureEditors(); + void slotSettings(); + void slotActiveProcessChanged( KDevPlugin*, bool ); + void slotActivePartChanged( KParts::Part* part ); + void slotStopPopupActivated(int); + void slotStopMenuAboutToShow(); + void slotStopButtonPressed(); + void slotNewToolbarConfig(); + void slotShowMenuBar(); + void slotActionStatusText( const QString &text ); + + void slotToggleMainToolbar(); + void slotToggleBuildToolbar(); + void slotToggleViewToolbar(); + void slotToggleBrowserToolbar(); + void slotToggleStatusbar(); + + void contextMenu(QPopupMenu *, const Context *); + +private: + KToggleAction* m_toggleMainToolbar; + KToggleAction* m_toggleBuildToolbar; + KToggleAction* m_toggleViewToolbar; + KToggleAction* m_toggleBrowserToolbar; + KToggleAction* m_toggleStatusbar; + + KAction * m_configureEditorAction; + + KToolBarPopupAction* m_stopProcesses; //!< Stops all running processes + + KParts::MainWindow* m_pMainWnd; + QPtrList<KDevPlugin> activeProcesses; +}; + +#endif // __MAINWINDOWSHARE_H__ diff --git a/src/mimewarningdialog.ui b/src/mimewarningdialog.ui new file mode 100644 index 00000000..21fdbee4 --- /dev/null +++ b/src/mimewarningdialog.ui @@ -0,0 +1,254 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>MimeWarningDialog</class> +<widget class="QDialog"> + <property name="name"> + <cstring>MimeWarningDialog</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>404</width> + <height>248</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="caption"> + <string>Could Not Open File</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>text1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>KDevelop could not open</string> + </property> + </widget> + <widget class="KSqueezedTextLabel"> + <property name="name"> + <cstring>text2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Some URL</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>text3</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string><qt>No suitable viewer was found for the <b>%1</b> mimetype.</qt></string> + </property> + </widget> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>buttonGroup1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>GroupBoxPanel</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <property name="title"> + <string>What Do You Want to Do?</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>open_with_kde</cstring> + </property> + <property name="text"> + <string>Let KDE find a suitable program</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>open_as_text</cstring> + </property> + <property name="text"> + <string>Open it in KDevelop as plain text</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>24</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QCheckBox"> + <property name="name"> + <cstring>always_open_as_text</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Always open this mimetype as text</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>41</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>101</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>pushButton1</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>pushButton2</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>open_with_kde</sender> + <signal>toggled(bool)</signal> + <receiver>always_open_as_text</receiver> + <slot>setDisabled(bool)</slot> + </connection> + <connection> + <sender>open_as_text</sender> + <signal>toggled(bool)</signal> + <receiver>always_open_as_text</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>pushButton2</sender> + <signal>clicked()</signal> + <receiver>MimeWarningDialog</receiver> + <slot>reject()</slot> + </connection> + <connection> + <sender>pushButton1</sender> + <signal>clicked()</signal> + <receiver>MimeWarningDialog</receiver> + <slot>accept()</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/src/multibuffer.cpp b/src/multibuffer.cpp new file mode 100644 index 00000000..cdbffe85 --- /dev/null +++ b/src/multibuffer.cpp @@ -0,0 +1,303 @@ +/* + * KDevelop Multiple Buffer Support + * + * Copyright (c) 2005 Adam Treat <treat@kde.org> + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +// Ewww... need this to access KParts::Part::setWidget(), so that kdevelop +// doesn't need to be rearchitected for multiple views before the lazy view +// creation can go in +#define protected public +#include <kparts/part.h> +#undef protected + +#include "multibuffer.h" + +#include "api.h" +#include "toplevel.h" +#include "editorproxy.h" +#include "partcontroller.h" +#include "kdevlanguagesupport.h" + +#include <kdebug.h> +#include <kmimetype.h> +#include <kmainwindow.h> +#include <kapplication.h> + +#include <kparts/factory.h> + +#include <ktexteditor/view.h> +#include <ktexteditor/document.h> +#include <ktexteditor/viewcursorinterface.h> + +MultiBuffer::MultiBuffer( QWidget *parent ) + : QSplitter( parent, "MultiBuffer" ), + m_editorFactory( 0 ), + m_delayActivate( false ), + m_activated( false ), + m_activeBuffer( 0 ) +{ + EditorProxy::getInstance() ->registerEditor( this ); + if ( KDevLanguageSupport *lang = + API::getInstance() ->languageSupport() ) + { + setOrientation( lang->splitOrientation() ); + connect( lang, SIGNAL( splitOrientationChanged( Qt::Orientation ) ), + this, SLOT( setOrientation( Qt::Orientation ) ) ); + } + else + { + setOrientation( Qt::Vertical ); + } +} + +MultiBuffer::~MultiBuffer() +{ + EditorProxy::getInstance() ->deregisterEditor( this ); +} + +KParts::Part *MultiBuffer::activeBuffer( ) const +{ + if ( m_activeBuffer ) + return m_activeBuffer; + // The active buffer might just been deleted... + else if ( m_buffers.begin().data() ) + return ( m_buffers.begin().data() ); + else + return 0; +} + +bool MultiBuffer::hasURL( const KURL &url ) const +{ + return m_buffers.contains( url ); +} + +int MultiBuffer::numberOfBuffers() const +{ + return m_buffers.count(); +} + +bool MultiBuffer::isActivated() const +{ + if ( m_delayActivate ) + return m_activated; + else + return true; +} + +void MultiBuffer::setDelayedActivation( bool delayed ) +{ + m_delayActivate = delayed; + if ( delayed ) + m_activated = false; +} + +KParts::Part* MultiBuffer::openURL( const KURL &url ) +{ + KParts::ReadOnlyPart * part = + dynamic_cast<KParts::ReadOnlyPart*>( createPart( url ) ); + + if ( !part ) + return 0; + + if ( !part->openURL( url ) ) + return 0; + + m_buffers.insert( url, part ); + return part; +} + +bool MultiBuffer::closeURL( const KURL &url ) +{ + if ( !m_buffers.contains( url ) ) + return false; + + bool result = false; + KParts::ReadOnlyPart * part = + dynamic_cast<KParts::ReadOnlyPart *>( m_buffers[ url ] ); + if ( part ) + if (part->closeURL()) + { + m_buffers.remove( url ); + return true; + } + return false; +} + +void MultiBuffer::registerURL( const KURL &url, KParts::Part *part ) +{ + m_buffers.insert( url, part ); +} + +void MultiBuffer::registerDelayedActivation( KParts::Part *part, + int line, int col ) +{ + m_delayedActivation[ part ] = qMakePair( line, col ); +} + +KParts::Part* MultiBuffer::createPart( const QString &mimeType, + const QString &partType, + const QString &className, + const QString &preferredName ) +{ + m_editorFactory = PartController::getInstance() ->findPartFactory( + mimeType, partType, preferredName ); + + if ( !className.isEmpty() && m_editorFactory ) + { + return m_editorFactory->createPart( + this, 0, 0, 0, className.latin1() ); + } + + return 0; +} + +KParts::Part* MultiBuffer::createPart( const KURL &url ) +{ + if ( !url.isValid() ) + return 0; + + KMimeType::Ptr mimeType = KMimeType::findByURL( url ); + + QString className; + QString services[] = { "KParts/ReadWritePart", "KParts/ReadOnlyPart" }; + QString classnames[] = { "KParts::ReadWritePart", "KParts::ReadOnlyPart" }; + for ( uint i = 0; i < 2; ++i ) + { + m_editorFactory = PartController::getInstance() ->findPartFactory( + mimeType->name(), services[ i ] ); + if ( m_editorFactory ) + { + className = classnames[ i ]; + break; + } + } + + if ( !className.isEmpty() && m_editorFactory ) + { + return m_editorFactory->createPart( + this, 0, 0, 0, className.latin1() ); + } + + return 0; +} + +void MultiBuffer::show() +{ + if ( !m_delayedActivation.count() || m_activated ) + { + QSplitter::show(); + return ; + } + + ActivationMap::Iterator it = m_delayedActivation.begin(); + for ( ; it != m_delayedActivation.end(); ++it ) + { + KTextEditor::Document *document = + dynamic_cast<KTextEditor::Document*>( it.key() ); + + if ( !document ) + continue; + + int line = it.data().first; + int column = it.data().second; + KTextEditor::View *view = document->createView( this ); + document->setWidget( view ); + + // We're managing the view deletion by being its parent, + // don't let the part self-destruct + disconnect( view, SIGNAL( destroyed() ), + document, SLOT( slotWidgetDestroyed() ) ); + + document->insertChildClient( view ); + PartController::getInstance() ->integrateTextEditorPart( document ); + + KTextEditor::ViewCursorInterface *iface = + dynamic_cast<KTextEditor::ViewCursorInterface*>( + static_cast<KTextEditor::View*>( view ) ); + if ( iface ) + { + iface->setCursorPositionReal( line, + column == -1 ? 0 : column ); + } + else + { + // Shouldn't get here + Q_ASSERT( false ); + } + view->show(); + kdDebug( 9000 ) << "Delayed activation of " + << document->url().fileName() << " is now complete." << endl; + } + + m_activated = true; + QSplitter::show(); +} + +void MultiBuffer::setOrientation( Qt::Orientation orientation ) +{ + QSplitter::setOrientation( orientation ); +} + +void MultiBuffer::activePartChanged( const KURL &url ) +{ + if ( !m_buffers.contains( url ) ) + return ; + + m_activeBuffer = m_buffers[ url ]; + TopLevel::getInstance() ->setCurrentDocumentCaption( url.fileName() ); +} + +void MultiBuffer::focusInEvent( QFocusEvent *ev ) +{ + KParts::Part *active = activeBuffer(); + if (active && active->widget()) + active->widget()->setFocus(); + QSplitter::focusInEvent(ev); +} + +bool MultiBuffer::hasPart( KParts::Part *part ) +{ + for (BufferMap::iterator it = m_buffers.begin(); it != m_buffers.end(); ++it) + { + if (it.data() == part) + return true; + } + return false; +} + +void MultiBuffer::updateUrlForPart(KParts::Part *part, KURL url) +{ + if (!url.isValid()) + return; + KURL formerURL; + for (BufferMap::iterator it = m_buffers.begin(); it != m_buffers.end(); ++it) + { + if (it.data() == part) + { + formerURL = it.key(); + break; + } + } + m_buffers.remove(formerURL); + m_buffers.insert(url, part); +} + +#include "multibuffer.moc" + +// kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on diff --git a/src/multibuffer.h b/src/multibuffer.h new file mode 100644 index 00000000..3d04f256 --- /dev/null +++ b/src/multibuffer.h @@ -0,0 +1,89 @@ +/* + * KDevelop Multiple Buffer Support + * + * Copyright (c) 2005 Adam Treat <treat@kde.org> + * + * This program 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef MULTIBUFFER_H +#define MULTIBUFFER_H + +#include <qpair.h> +#include <qsplitter.h> +#include <qguardedptr.h> + +namespace KParts +{ +class Part; +class Factory; +class ReadOnlyPart; +} + +class KURL; + +typedef QMap< KURL, KParts::Part* > BufferMap; +typedef QMap< KParts::Part*, QPair<int, int> > ActivationMap; + +class MultiBuffer : public QSplitter +{ + Q_OBJECT +public: + MultiBuffer( QWidget * parent = 0 ); + virtual ~MultiBuffer(); + + KParts::Part *activeBuffer() const; + bool hasURL( const KURL &url ) const; + bool hasPart( KParts::Part *part ); + int numberOfBuffers() const; + bool isActivated() const; + void setDelayedActivation( bool delayed ); + + KParts::Part* createPart( const QString &mimeType, + const QString &partType, + const QString &className, + const QString &preferredName = QString::null ); + + KParts::Part* openURL( const KURL &url ); + bool closeURL( const KURL &url ); + + void registerURL( const KURL &url, KParts::Part *part ); + void registerDelayedActivation( KParts::Part *part, int line, int col ); + + void updateUrlForPart( KParts::Part *part, KURL url ); + +public slots: + virtual void show(); + virtual void setOrientation( Qt::Orientation ); + void activePartChanged( const KURL &url ); + +protected: + virtual void focusInEvent( QFocusEvent *ev ); + +private: + KParts::Part* createPart( const KURL &url ); + +private: + BufferMap m_buffers; + QGuardedPtr<KParts::Factory> m_editorFactory; + ActivationMap m_delayedActivation; + bool m_delayActivate; + bool m_activated; + QGuardedPtr<KParts::Part> m_activeBuffer; +}; + +#endif + +// kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on diff --git a/src/newui/Makefile.am b/src/newui/Makefile.am new file mode 100644 index 00000000..b99b17e4 --- /dev/null +++ b/src/newui/Makefile.am @@ -0,0 +1,14 @@ +INCLUDES = -I$(top_srcdir)/lib -I$(top_srcdir)/lib/interfaces \ + -I$(top_srcdir)/lib/interfaces/extensions -I$(top_srcdir)/lib/interfaces/external \ + -I$(top_srcdir)/lib/interfaces/extras -I$(top_srcdir)/lib/util -I$(top_srcdir)/lib/widgets \ + -I$(top_srcdir)/src/profileengine/lib $(all_includes) +METASOURCES = AUTO + + +lib_LTLIBRARIES = libd.la +libd_la_LDFLAGS = $(all_libraries) + +noinst_HEADERS = dmainwindow.h ddockwindow.h buttonbar.h button.h comdefs.h docksplitter.h dtabwidget.h +libd_la_SOURCES = dmainwindow.cpp buttonbar.cpp \ + button.cpp ddockwindow.cpp docksplitter.cpp dtabwidget.cpp +libd_la_LIBADD = $(LIB_KPARTS) $(LIB_QT) $(LIB_KDECORE) $(LIB_KDEUI) diff --git a/src/newui/button.cpp b/src/newui/button.cpp new file mode 100644 index 00000000..d2403422 --- /dev/null +++ b/src/newui/button.cpp @@ -0,0 +1,350 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "button.h" + +#include <qpainter.h> +#include <qtooltip.h> +#include <qstyle.h> +#include <qapplication.h> +#include <qregexp.h> + +#include <kdebug.h> +#include <kiconloader.h> +#include <kxmlguiclient.h> +#include <kaction.h> +#include <kpopupmenu.h> +#include <kinputdialog.h> +#include <klocale.h> +#include <kapplication.h> +#include <kconfig.h> + +#include "buttonbar.h" + +namespace Ideal { + +Button::Button(ButtonBar *parent, const QString text, const QIconSet &icon, + const QString &description) + :QPushButton(icon, text, parent), m_buttonBar(parent), m_description(description), + m_place(parent->place()), m_realText(text), m_realIconSet(icon) +{ + hide(); + setFlat(true); + setToggleButton(true); + setFocusPolicy(NoFocus); + setDescription(m_description); + setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + resize(sizeHint()); + fixDimensions(Ideal::Bottom); + + QToolTip::add(this, m_realText); + + m_assignAccelAction = new KAction(i18n("Assign Accelerator..."), 0, + this, SLOT(assignAccel()), this); + m_clearAccelAction = new KAction(i18n("Clear Accelerator"), 0, + this, SLOT(clearAccel()), this); + + KConfig *config = kapp->config(); + config->setGroup("UI"); + QString accel = config->readEntry(QString("button_%1").arg(text), ""); + if (!accel.isEmpty()) + setRealText(QString("&%1 %2").arg(accel).arg(m_realText)); +} + +Button::~Button() +{ +// m_buttonBar->removeButton(this); + KConfig *config = kapp->config(); + config->setGroup("UI"); + + QRegExp r("^&([0-9])\\s.*"); + QRegExp r2("^&[0-9]\\s"); + if (r.search(m_realText) > -1) + { + QString text = m_realText; + if (text.contains(r2)) + text.remove(r2); + config->writeEntry(QString("button_%1").arg(text), r.cap(1)); + } + else + { + config->writeEntry(QString("button_%1").arg(m_realText), ""); + } +} + +void Button::setDescription(const QString &description) +{ + m_description = description; + QToolTip::remove(this); + QToolTip::add(this, m_description); +} + +QString Button::description() const +{ + return m_description; +} + +void Button::drawButton(QPainter *p) +{ + QRect r = rect(); + QSize sh = r.size(); + switch (m_place) + { + case Ideal::Left: + case Ideal::Right: + sh.setHeight(r.width()); + sh.setWidth(r.height()); + break; + } + + QStyle::SFlags flags = QStyle::Style_Default; + if (isEnabled()) + flags |= QStyle::Style_Enabled; + if (hasFocus()) + flags |= QStyle::Style_HasFocus; + if (isDown()) + flags |= QStyle::Style_Down; + if (isOn()) + flags |= QStyle::Style_On; + if (! isFlat() && ! isDown()) + flags |= QStyle::Style_Raised; + if (isDefault()) + flags |= QStyle::Style_ButtonDefault; + + QPixmap pm(sh.width(), sh.height()); + pm.fill(eraseColor()); + QPainter p2(&pm); + + style().drawControl(QStyle::CE_PushButton,&p2,this, QRect(0,0,pm.width(),pm.height()), colorGroup(),flags); + + style().drawControl(QStyle::CE_PushButtonLabel, &p2, this, + QRect(0,0,pm.width(),pm.height()), + colorGroup(), flags, QStyleOption()); + + switch (m_place) + { + case Ideal::Left: + p->rotate(-90); + p->drawPixmap(1-pm.width(), 0, pm); + break; + case Ideal::Right: + p->rotate(90); + p->drawPixmap(0, 1-pm.height(), pm); + break; + default: + p->drawPixmap(0, 0, pm); + break; + } +} + +void Button::drawButtonLabel(QPainter */*p*/) +{ +} + +ButtonMode Button::mode() +{ + return m_buttonBar->mode(); +} + +void Button::setPlace(Ideal::Place place) +{ + Place oldPlace = m_place; + m_place = place; + fixDimensions(oldPlace); +} + +void Button::fixDimensions(Place oldPlace) +{ + switch (m_place) + { + case Ideal::Left: + case Ideal::Right: + if ((oldPlace == Ideal::Bottom) || (oldPlace == Ideal::Top)) + { + setFixedWidth(height()); + setMinimumHeight(sizeHint().width()); + setMaximumHeight(32767); + } + break; + case Ideal::Top: + case Ideal::Bottom: + if ((oldPlace == Ideal::Left) || (oldPlace == Ideal::Right)) + { + setFixedHeight(width()); + setMinimumWidth(sizeHint().height()); + setMaximumWidth(32767); + } + break; + } +} + +QSize Button::sizeHint() const +{ + return sizeHint(text()); +} + +QSize Button::sizeHint(const QString &text) const +{ + constPolish(); + int w = 0, h = 0; + + if ( iconSet() && !iconSet()->isNull() && (m_buttonBar->mode() != Text) ) { + int iw = iconSet()->pixmap( QIconSet::Small, QIconSet::Normal ).width() + 4; + int ih = iconSet()->pixmap( QIconSet::Small, QIconSet::Normal ).height(); + w += iw; + h = QMAX( h, ih ); + } + if ( isMenuButton() ) + w += style().pixelMetric(QStyle::PM_MenuButtonIndicator, this); + if ( pixmap() ) { + QPixmap *pm = (QPixmap *)pixmap(); + w += pm->width(); + h += pm->height(); + } else if (m_buttonBar->mode() != Icons) { + QString s( text ); + bool empty = s.isEmpty(); + if ( empty ) + s = QString::fromLatin1("XXXX"); + QFontMetrics fm = fontMetrics(); + QSize sz = fm.size( ShowPrefix, s ); + if(!empty || !w) + w += sz.width(); + if(!empty || !h) + h = QMAX(h, sz.height()); + } + + return (style().sizeFromContents(QStyle::CT_ToolButton, this, QSize(w, h)). + expandedTo(QApplication::globalStrut())); +} + +void Button::updateSize() +{ + switch (m_place) + { + case Ideal::Left: + case Ideal::Right: + setMinimumHeight(sizeHint().width()); + resize(sizeHint().height(), sizeHint().width()); + break; + case Ideal::Top: + case Ideal::Bottom: + resize(sizeHint().width(), sizeHint().height()); + break; + } +} + +QString Button::realText() const +{ + return m_realText; +} + +void Button::setMode(Ideal::ButtonMode mode) +{ + switch (mode) + { + case Text: + disableIconSet(); + enableText(); + break; + case IconsAndText: + enableIconSet(); + enableText(); + break; + case Icons: + disableText(); + enableIconSet(); + break; + } +} + +void Button::enableIconSet() +{ + if (!iconSet()) + { + if (m_realIconSet.isNull()) + m_realIconSet = SmallIcon("file_new"); + setIconSet(m_realIconSet); + } +} + +void Button::disableIconSet() +{ + setIconSet(QIconSet()); +} + +void Button::disableText() +{ + if (text().length() > 0) + setText(""); +} + +void Button::enableText() +{ + setText(m_realText); +} + +void Button::contextMenuEvent(QContextMenuEvent *e) +{ + QPopupMenu menu; + + m_assignAccelAction->plug(&menu); + if (m_realText.contains(QRegExp("^&[0-9]\\s"))) + m_clearAccelAction->plug(&menu); + + emit contextMenu( &menu ); + + menu.exec(e->globalPos()); +} + +void Button::assignAccel() +{ + bool ok; + int num = KInputDialog::getInteger(i18n("Change Button Number"), i18n("New accelerator number:"), 1, 0, 10, 1, &ok, this); + if (ok) + { + QString text = realTextWithoutAccel(); + text = QString("&%1 %2").arg(num).arg(text); + setRealText(text); + } +} + +void Button::setRealText(const QString &text) +{ + m_realText = text; + setText(text); + updateSize(); +} + +void Button::clearAccel() +{ + setRealText(realTextWithoutAccel()); +} + +QString Button::realTextWithoutAccel() const +{ + QString text = m_realText; + QRegExp r("^&[0-9]\\s"); + if (text.contains(r)) + text.remove(r); + return text; +} + +} + +#include "button.moc" diff --git a/src/newui/button.h b/src/newui/button.h new file mode 100644 index 00000000..a7afbcfe --- /dev/null +++ b/src/newui/button.h @@ -0,0 +1,108 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef IDEALBUTTON_H +#define IDEALBUTTON_H + +#include <qpushbutton.h> +#include <qiconset.h> + +#include "comdefs.h" + +class KAction; + +namespace Ideal { + +class ButtonBar; + +/** +@short A button to place onto the ButtonBar + +A QPushButton derivative with a size of a QToolBar. Button can be rotated +(placed onto different places in ideal mode). +*/ +class Button : public QPushButton { + Q_OBJECT +public: + Button(ButtonBar *parent, const QString text, const QIconSet &icon = QIconSet(), + const QString &description = QString::null); + + /**Sets the description used as a tooltip.*/ + void setDescription(const QString &description); + /**Returns the description.*/ + QString description() const; + + /**Sets the place of a button.*/ + void setPlace(Ideal::Place place); + /**Sets the mode of a button.*/ + void setMode(Ideal::ButtonMode mode); + + QSize sizeHint() const; + QSize sizeHint(const QString &text) const; + + /**Updates size of a widget. Used after squeezing button's text.*/ + void updateSize(); + + /**Returns the real (i.e. not squeezed) text of a button.*/ + QString realText() const; + QString realTextWithoutAccel() const; + void setRealText(const QString &text); + +protected: + ButtonMode mode(); + + virtual void drawButton(QPainter *p); + virtual void drawButtonLabel(QPainter *p); + + virtual void contextMenuEvent(QContextMenuEvent *e); + +protected slots: + void assignAccel(); + void clearAccel(); + +signals: + void contextMenu(QPopupMenu*); + +private: + virtual ~Button(); + + void fixDimensions(Place oldPlace); + + void enableIconSet(); + void disableIconSet(); + void enableText(); + void disableText(); + + ButtonBar *m_buttonBar; + + QString m_description; + Place m_place; + + QString m_realText; + QIconSet m_realIconSet; + + KAction *m_assignAccelAction; + KAction *m_clearAccelAction; + +friend class ButtonBar; +}; + +} + +#endif diff --git a/src/newui/buttonbar.cpp b/src/newui/buttonbar.cpp new file mode 100644 index 00000000..8f60dabf --- /dev/null +++ b/src/newui/buttonbar.cpp @@ -0,0 +1,346 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "buttonbar.h" + +#include <qlayout.h> + +#include <kdebug.h> +#include <kconfig.h> +#include <kstringhandler.h> +#include <klocale.h> + +#include "button.h" + +namespace Ideal { + +//ButtonLayout class + +ButtonLayout::ButtonLayout(ButtonBar *parent, Direction d, int margin, int spacing, const char *name) + :QBoxLayout(parent, d, margin, spacing, name), m_buttonBar(parent) +{ +} + +QSize ButtonLayout::minimumSize() const +{ + QSize size = QBoxLayout::minimumSize(); + + if (!m_buttonBar->autoResize()) + return size; + + switch (m_buttonBar->place()) + { + case Ideal::Left: + case Ideal::Right: + return QSize(size.width(),0); + break; + case Ideal::Top: + case Ideal::Bottom: + return QSize(0,size.height()); + } + return QBoxLayout::minimumSize(); +} + + + +//ButtonBar class + + +ButtonBar::ButtonBar(Place place, ButtonMode mode, QWidget *parent, const char *name) + :QWidget(parent, name), m_place(place), l(0), m_shrinked(false), m_autoResize(true) +{ + switch (m_place) + { + case Ideal::Left: + case Ideal::Right: + l = new ButtonLayout(this, QBoxLayout::TopToBottom, 0, 0); + break; + case Ideal::Top: + case Ideal::Bottom: + l = new ButtonLayout(this, QBoxLayout::LeftToRight, 0, 0); + break; + } + + l->setResizeMode(QLayout::Minimum); + setMode(mode); + + l->insertStretch(-1); +} + +ButtonBar::~ButtonBar() +{ +} + +void ButtonBar::addButton(Button *button) +{ + int buttonCount = m_buttons.count(); + + button->setMode(m_mode); + m_buttons.append(button); + l->insertWidget(buttonCount, button); + button->show(); + fixDimensions(); +} + +void ButtonBar::removeButton(Button *button) +{ + m_buttons.remove(button); + l->remove(button); + delete button; +} + +void ButtonBar::setMode(ButtonMode mode) +{ + m_mode = mode; + for (ButtonList::iterator it = m_buttons.begin(); it != m_buttons.end(); ++it) + (*it)->setMode(mode); +} + +ButtonMode ButtonBar::mode() const +{ + return m_mode; +} + +Place ButtonBar::place() const +{ + return m_place; +} + +void ButtonBar::fixDimensions() +{ + switch (m_place) + { + case Ideal::Left: + case Ideal::Right: + setFixedWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(32767); + break; + case Ideal::Top: + case Ideal::Bottom: + setFixedHeight(sizeHint().height()); + setMinimumWidth(sizeHint().width()); + setMaximumWidth(32767); + break; + } +} + +void ButtonBar::setButtonsPlace(Ideal::Place place) +{ + for (ButtonList::iterator it = m_buttons.begin(); it != m_buttons.end(); ++it) + (*it)->setPlace(place); +} + +void ButtonBar::resizeEvent(QResizeEvent *ev) +{ + int preferredDimension = 0; + int actualDimension = 0; + int oldDimension = 0; + switch (m_place) + { + case Ideal::Left: + case Ideal::Right: + preferredDimension = l->QBoxLayout::minimumSize().height(); + actualDimension = size().height(); + oldDimension = ev->oldSize().height(); + break; + case Ideal::Top: + case Ideal::Bottom: + preferredDimension = l->QBoxLayout::minimumSize().width(); + actualDimension = size().width(); + oldDimension = ev->oldSize().width(); + break; + } + + if (preferredDimension > actualDimension) + shrink(preferredDimension, actualDimension); + else if (m_shrinked && (originalDimension() < actualDimension)) + unshrink(); + else if (m_shrinked && actualDimension > oldDimension) + deshrink(preferredDimension, actualDimension); + + QWidget::resizeEvent(ev); +} + +void ButtonBar::shrink(int preferredDimension, int actualDimension) +{ + if (!preferredDimension) + return; + + m_shrinked = true; + + uint textLength = 0; + QValueList<uint> texts; + uint maxLength = 0; + for (ButtonList::const_iterator it = m_buttons.constBegin(); it != m_buttons.constEnd(); ++it) + { + uint length = (*it)->text().length(); + maxLength = length > maxLength ? length : maxLength ; + texts.append(length); + textLength += length; + } + + uint newPreferredLength = actualDimension * textLength / preferredDimension; + + uint newMaxLength = maxLength; + uint newTextLength; + do { + newMaxLength -= 1; + newTextLength = 0; + for (QValueList<uint>::iterator it = texts.begin(); it != texts.end(); ++it) + { + if (*it > newMaxLength) + *it = newMaxLength; + newTextLength += *it; + } + } while (newTextLength > newPreferredLength); + + int i = 0; + for (ButtonList::iterator it = m_buttons.begin(); it != m_buttons.end(); ++it) + { + (*it)->setText(KStringHandler::rsqueeze((*it)->realText(), texts[i++])); + (*it)->updateSize(); + } +} + +void ButtonBar::deshrink(int preferredDimension, int actualDimension) +{ + if (!preferredDimension) + return; + + m_shrinked = true; + + uint textLength = 0; + QValueList<uint> texts; + uint maxLength = 0; + for (ButtonList::const_iterator it = m_buttons.constBegin(); it != m_buttons.constEnd(); ++it) + { + uint length = (*it)->text().length(); + maxLength = length > maxLength ? length : maxLength ; + texts.append(length); + textLength += length; + } + + uint newPreferredLength = actualDimension * textLength / preferredDimension; + + if (newPreferredLength <= textLength) + return; + + uint newTextLength; + uint prevTextLength = 0; + do { + newTextLength = 0; + int i = 0; + for (QValueList<uint>::iterator it = texts.begin(); it != texts.end(); ++it, i++) + { + if (m_buttons[i]->text().contains("...")) + (*it)++; + newTextLength += *it; + } + if (newTextLength == prevTextLength) + break; + prevTextLength = newTextLength; + } while (newTextLength < newPreferredLength); + + int i = 0; + for (ButtonList::iterator it = m_buttons.begin(); it != m_buttons.end(); ++it) + { + if (texts[i] >= (*it)->realText().length()) + (*it)->setText((*it)->realText()); + else + (*it)->setText(KStringHandler::rsqueeze((*it)->realText(), texts[i])); + (*it)->updateSize(); + ++i; + } +} + +void ButtonBar::unshrink() +{ + for (ButtonList::iterator it = m_buttons.begin(); it != m_buttons.end(); ++it) + { + (*it)->setText((*it)->realText()); + (*it)->updateSize(); + } + m_shrinked = false; +} + +int ButtonBar::originalDimension() +{ + int size = 0; + for (ButtonList::const_iterator it = m_buttons.constBegin(); it != m_buttons.constEnd(); ++it) + { + size += (*it)->sizeHint((*it)->realText()).width(); + } + return size; +} + +bool ButtonBar::autoResize() const +{ + return m_autoResize; +} + +void ButtonBar::setAutoResize(bool b) +{ + m_autoResize = b; +} + +Button *ButtonBar::firstButton() +{ + if (!m_buttons.isEmpty()) + return m_buttons.first(); + return 0; +} + +Button *ButtonBar::nextTo(Button *button) +{ + ButtonList::iterator it = m_buttons.find(button); + Button *next = 0; + if ((*it) == m_buttons.last()) + next = m_buttons.first(); + else + { + it++; + next = *it; + } + if (next->isVisible()) + return next; + else + return nextTo(next); +} + +Button *ButtonBar::prevTo(Button *button) +{ + ButtonList::iterator it = m_buttons.find(button); + Button *prev = 0; + if (it == m_buttons.begin()) + prev = m_buttons.last(); + else + { + it--; + prev = *it; + } + if (prev->isVisible()) + return prev; + else + return prevTo(prev); +} + +} + +#include "buttonbar.moc" diff --git a/src/newui/buttonbar.h b/src/newui/buttonbar.h new file mode 100644 index 00000000..5f5a7e36 --- /dev/null +++ b/src/newui/buttonbar.h @@ -0,0 +1,112 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef IDEALBUTTONBAR_H +#define IDEALBUTTONBAR_H + +#include <qwidget.h> +#include <qvaluelist.h> + +#include "comdefs.h" + +#include <qlayout.h> + +namespace Ideal { + +class Button; +class ButtonBar; + +/**@short A layout for a ButtonBar class. + +Overrides minimumSize method to allow shrinking button bar buttons.*/ +class ButtonLayout: public QBoxLayout{ +public: + ButtonLayout(ButtonBar *parent, Direction d, int margin = 0, int spacing = -1, const char * name = 0); + + virtual QSize minimumSize() const; + +private: + ButtonBar *m_buttonBar; +}; + +/** +@short A bar with tool buttons. + +Looks like a toolbar but has another behaviour. It is suitable for +placing on the left(right, bottom, top) corners of a window as a bar with slider. +*/ +class ButtonBar : public QWidget { + Q_OBJECT +public: + ButtonBar(Place place, ButtonMode mode = IconsAndText, + QWidget *parent = 0, const char *name = 0); + virtual ~ButtonBar(); + + /**Adds a button to the bar.*/ + virtual void addButton(Button *button); + /**Removes a button from the bar and deletes the button.*/ + virtual void removeButton(Button *button); + + /**Sets the mode.*/ + void setMode(ButtonMode mode); + /**@returns the mode.*/ + ButtonMode mode() const; + + /**@returns the place.*/ + Place place() const; + + bool autoResize() const; + void setAutoResize(bool b); + + /**Shrinks the button bar so all buttons are visible. Shrinking is done by + reducing the amount of text shown on buttons. Button icon size is a minimum size + of a button. If a button does not have an icon, it displays "...".*/ + virtual void shrink(int preferredDimension, int actualDimension); + virtual void deshrink(int preferredDimension, int actualDimension); + /**Restores the size of button bar buttons.*/ + virtual void unshrink(); + + Button *firstButton(); + Button *nextTo(Button *button); + Button *prevTo(Button *button); + +protected: + virtual void resizeEvent ( QResizeEvent *ev ); + + int originalDimension(); + +private: + void fixDimensions(); + void setButtonsPlace(Ideal::Place place); + + typedef QValueList<Button*> ButtonList; + ButtonList m_buttons; + + ButtonMode m_mode; + Place m_place; + + ButtonLayout *l; + + bool m_shrinked; + bool m_autoResize; +}; + +} + +#endif diff --git a/src/newui/comdefs.h b/src/newui/comdefs.h new file mode 100644 index 00000000..8233f12c --- /dev/null +++ b/src/newui/comdefs.h @@ -0,0 +1,30 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef COMDEFS_H +#define COMDEFS_H + +namespace Ideal { + + enum Place { Left=1, Right=2, Top=4, Bottom=8 }; + enum ButtonMode { Text, IconsAndText, Icons }; + +} + +#endif diff --git a/src/newui/ddockwindow.cpp b/src/newui/ddockwindow.cpp new file mode 100644 index 00000000..bb249abc --- /dev/null +++ b/src/newui/ddockwindow.cpp @@ -0,0 +1,413 @@ +/*************************************************************************** + * Copyright (C) 2005 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "ddockwindow.h" + +#include <qtoolbutton.h> +#include <qlayout.h> +#include <qstyle.h> +#include <qwidgetstack.h> +#include <qimage.h> +#include <qapplication.h> +#include <qpopupmenu.h> + +#include <kdebug.h> +#include <kglobal.h> +#include <kconfig.h> +#include <kcombobox.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kapplication.h> + +#include "buttonbar.h" +#include "button.h" +#include "dmainwindow.h" + +DDockWindow::DDockWindow(DMainWindow *parent, Position position) + :QDockWindow(QDockWindow::InDock, parent), m_position(position), m_visible(false), + m_mainWindow(parent), m_doNotCloseActiveWidget(false), m_toggledButton(0), m_lastContextMenuButton(0) +{ + setMovingEnabled(false); + setResizeEnabled(true); + + Ideal::Place place = Ideal::Left; + switch (position) { + case DDockWindow::Bottom: + m_name = "BottomToolWindow"; + place = Ideal::Bottom; + m_internalLayout = new QVBoxLayout(boxLayout(), 0); + m_internalLayout->setDirection(QBoxLayout::BottomToTop); + break; + case DDockWindow::Left: + m_name = "LeftToolWindow"; + place = Ideal::Left; + m_internalLayout = new QHBoxLayout(boxLayout(), 0); + m_internalLayout->setDirection(QBoxLayout::LeftToRight); + break; + case DDockWindow::Right: + m_name = "RightToolWindow"; + place = Ideal::Right; + m_internalLayout = new QHBoxLayout(boxLayout(), 0); + m_internalLayout->setDirection(QBoxLayout::RightToLeft); + break; + } + + KConfig *config = kapp->config(); + config->setGroup("UI"); + int mode = config->readNumEntry("MDIStyle", 3); + Ideal::ButtonMode buttonMode = Ideal::Text; + if (mode == 0) + buttonMode = Ideal::Icons; + else if (mode == 1) + buttonMode = Ideal::Text; + else if (mode == 3) + buttonMode = Ideal::IconsAndText; + + m_bar = new Ideal::ButtonBar(place, buttonMode, this); + m_internalLayout->addWidget(m_bar); + + m_widgetStack = new QWidgetStack(this); + m_internalLayout->addWidget(m_widgetStack); + + m_moveToDockLeft = new KAction( i18n("Move to left dock"), 0, this, SLOT(moveToDockLeft()), this ); + m_moveToDockRight = new KAction( i18n("Move to right dock"), 0, this, SLOT(moveToDockRight()), this ); + m_moveToDockBottom = new KAction( i18n("Move to bottom dock"), 0, this, SLOT(moveToDockBottom()), this ); + + setVisible(m_visible); + + loadSettings(); +} + +DDockWindow::~DDockWindow() +{ +//done in DMainWindow now +// saveSettings(); +} + +void DDockWindow::setVisible(bool v) +{ + //write dock width to the config file + KConfig *config = kapp->config(); + QString group = QString("%1").arg(m_name); + config->setGroup(group); + + if (m_visible) + config->writeEntry("ViewWidth", m_position == DDockWindow::Bottom ? height() : width() ); + setResizeEnabled(v); + setVerticallyStretchable(true); + setHorizontallyStretchable(true); + v ? m_widgetStack->show() : m_widgetStack->hide(); + m_visible = v; + + m_internalLayout->invalidate(); + if (!m_visible) + { + if (m_position == DDockWindow::Bottom) + setFixedExtentHeight(m_internalLayout->sizeHint().height()); + else + setFixedExtentWidth(m_internalLayout->sizeHint().width()); + emit hidden(); + } + else + { + //restore widget size from the config + int size = 0; + if (m_position == DDockWindow::Bottom) + { + size = config->readNumEntry("ViewWidth", m_internalLayout->sizeHint().height()); + setFixedExtentHeight(size); + } + else + { + size = config->readNumEntry("ViewWidth", m_internalLayout->sizeHint().width()); + setFixedExtentWidth(size); + } + } +} + +void DDockWindow::loadSettings() +{ +} + +void DDockWindow::saveSettings() +{ + KConfig *config = kapp->config(); + QString group = QString("%1").arg(m_name); + int invisibleWidth = 0; + config->setGroup(group); + if (config->hasKey("ViewWidth")) + invisibleWidth = config->readNumEntry("ViewWidth"); + config->deleteEntry("ViewWidth"); + config->deleteEntry("ViewLastWidget"); + if (m_toggledButton && m_visible) + { + config->writeEntry("ViewWidth", m_position == DDockWindow::Bottom ? height() : width()); + config->writeEntry("ViewLastWidget", m_toggledButton->realTextWithoutAccel()); + } + else if (invisibleWidth != 0) + config->writeEntry("ViewWidth", invisibleWidth); +} + +QWidget *DDockWindow::currentWidget() const +{ + return m_widgetStack->visibleWidget(); +} + +void DDockWindow::addWidget(const QString &title, QWidget *widget, bool skipActivation) +{ + kdDebug(9000) << k_funcinfo << endl; + QPixmap *pm = const_cast<QPixmap*>(widget->icon()); + Ideal::Button *button; + if (pm != 0) + { + //force 16pt for now + if (pm->height() > 16) + { + QImage img = pm->convertToImage(); + img = img.smoothScale(16, 16); + pm->convertFromImage(img); + } + button = new Ideal::Button(m_bar, title, *pm); + } + else + button = new Ideal::Button(m_bar, title); + m_widgets[button] = widget; + m_buttons[widget] = button; + m_bar->addButton(button); + + m_widgetStack->addWidget(widget); + connect(button, SIGNAL(clicked()), this, SLOT(selectWidget())); + connect(button, SIGNAL(contextMenu(QPopupMenu*)), this, SLOT(contextMenu(QPopupMenu*)) ); + + if (!skipActivation) + { + //if the widget was selected last time the dock is deleted + //we need to show it + KConfig *config = kapp->config(); + QString group = QString("%1").arg(m_name); + config->setGroup(group); + if (config->readEntry("ViewLastWidget") == title) + { + kdDebug(9000) << k_funcinfo << " : activating last widget " << title << endl; + button->setOn(true); + selectWidget(button); + } + } +} + +void DDockWindow::raiseWidget(QWidget *widget) +{ + kdDebug(9000) << k_funcinfo << endl; + + if ( !widget ) return; + + Ideal::Button *button = m_buttons[widget]; + if ((button != 0) && (!button->isOn())) + { + button->setOn(true); + selectWidget(button); + } +} + +void DDockWindow::lowerWidget(QWidget * widget) +{ + kdDebug(9000) << k_funcinfo << endl; + + if ( !widget ) return; + + Ideal::Button *button = m_buttons[widget]; + if ((button != 0) && (button->isOn())) + { + button->setOn(false); + selectWidget(button); + } +} + +void DDockWindow::removeWidget(QWidget *widget) +{ + kdDebug(9000) << k_funcinfo << endl; + if (m_widgetStack->id(widget) == -1) + return; //not in dock + + bool changeVisibility = false; + if (m_widgetStack->visibleWidget() == widget) + changeVisibility = true; + + Ideal::Button *button = m_buttons[widget]; + if (button) + m_bar->removeButton(button); + m_widgets.remove(button); + m_buttons.remove(widget); + m_widgetStack->removeWidget(widget); + + if (changeVisibility) + { + m_toggledButton = 0; + setVisible(false); + } +} + +void DDockWindow::selectWidget(Ideal::Button *button) +{ + bool special = m_doNotCloseActiveWidget; + m_doNotCloseActiveWidget = false; + kdDebug(9000) << k_funcinfo << endl; + if (m_toggledButton == button) + { + if (special && m_visible && (!isActive())) + { + //special processing for keyboard navigation events + m_toggledButton->setOn(true); + m_widgets[button]->setFocus(); + } + else + { + m_widgets[button]->setFocus(); + setVisible(!m_visible); + } + return; + } + + if (m_toggledButton) + m_toggledButton->setOn(false); + m_toggledButton = button; + setVisible(true); + m_widgetStack->raiseWidget(m_widgets[button]); + m_widgets[button]->setFocus(); +} + +void DDockWindow::selectWidget() +{ + selectWidget((Ideal::Button*)sender()); +} + +void DDockWindow::hideWidget(QWidget *widget) +{ + Ideal::Button *button = m_buttons[widget]; + if (button != 0) + { + button->setOn(false); + button->hide(); + } + widget->hide(); + if (button == m_toggledButton) + setVisible(false); +} + +void DDockWindow::showWidget(QWidget *widget) +{ + Ideal::Button *button = m_buttons[widget]; + if (button != 0) + button->show(); +// widget->show(); +} + +void DDockWindow::setMovingEnabled(bool) +{ + //some operations on KMainWindow cause moving to be enabled + //but we always don't want DDockWindow instances to be movable + QDockWindow::setMovingEnabled(false); +} + +void DDockWindow::selectLastWidget() +{ + m_doNotCloseActiveWidget = true; + if (m_toggledButton) + m_toggledButton->animateClick(); + else if (Ideal::Button *button = m_bar->firstButton()) + button->animateClick(); +} + +bool DDockWindow::isActive() +{ + if (m_toggledButton) + { + QWidget *w = qApp->focusWidget(); + if (!w) + return false; + QWidget *toolWidget = m_widgets[m_toggledButton]; + if (toolWidget == w) + return true; + else + { + do { + w = (QWidget*)w->parent(); + if (w && (w == toolWidget)) return true; + } while (w); + } + } + return false; +} + +void DDockWindow::selectNextWidget() +{ + if (!m_toggledButton) + return; + Ideal::Button *b = m_bar->nextTo(m_toggledButton); + if (b) + b->animateClick(); +} + +void DDockWindow::selectPrevWidget() +{ + if (!m_toggledButton) + return; + Ideal::Button *b = m_bar->prevTo(m_toggledButton); + if (b) + b->animateClick(); +} + +void DDockWindow::contextMenu(QPopupMenu * menu) +{ + m_lastContextMenuButton = static_cast<Ideal::Button*>( const_cast<QObject*>( sender() ) ); + + menu->insertSeparator(); + + if ( position() != DDockWindow::Left ) + m_moveToDockLeft->plug( menu ); + if ( position()!= DDockWindow::Right ) + m_moveToDockRight->plug( menu ); + if ( position() != DDockWindow::Bottom ) + m_moveToDockBottom->plug( menu ); +} + +void DDockWindow::moveToDockLeft() +{ + moveToDock( DDockWindow::Left ); +} + +void DDockWindow::moveToDockRight() +{ + moveToDock( DDockWindow::Right ); +} + +void DDockWindow::moveToDockBottom() +{ + moveToDock( DDockWindow::Bottom ); +} + +void DDockWindow::moveToDock(DDockWindow::Position position ) +{ + if ( m_widgets.contains( m_lastContextMenuButton ) ) + { + mainWindow()->moveWidget( position, m_widgets[ m_lastContextMenuButton ], m_lastContextMenuButton->realTextWithoutAccel() ); + } +} + +#include "ddockwindow.moc" diff --git a/src/newui/ddockwindow.h b/src/newui/ddockwindow.h new file mode 100644 index 00000000..ece0db8c --- /dev/null +++ b/src/newui/ddockwindow.h @@ -0,0 +1,114 @@ +/*************************************************************************** + * Copyright (C) 2005 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef DDOCKWINDOW_H +#define DDOCKWINDOW_H + +#include <qdockwindow.h> +#include <qvaluelist.h> + +class QBoxLayout; +class QToolButton; +class QWidgetStack; +class QPopupMenu; + +class KComboBox; +class KAction; + +class DMainWindow; + +namespace Ideal { + class Button; + class ButtonBar; +} + +class DDockWindow : public QDockWindow { + Q_OBJECT +public: + enum Position { Bottom, Left, Right }; + + DDockWindow(DMainWindow *parent, Position position); + virtual ~DDockWindow(); + + virtual void setVisible(bool v); + bool visible() const { return m_visible; } + Position position() const { return m_position; } + + virtual void addWidget(const QString &title, QWidget *widget, bool skipActivation = false); + virtual void raiseWidget(QWidget *widget); + virtual void lowerWidget(QWidget *widget); + /**Removes the widget from dock. Does not delete it.*/ + virtual void removeWidget(QWidget *widget); + + virtual void hideWidget(QWidget *widget); + virtual void showWidget(QWidget *widget); + + virtual QWidget *currentWidget() const; + + virtual void setMovingEnabled(bool b); + + virtual void saveSettings(); + + DMainWindow *mainWindow() const { return m_mainWindow; } + + virtual void selectLastWidget(); + virtual void selectNextWidget(); + virtual void selectPrevWidget(); + + bool isActive(); + +signals: + void hidden(); + +private slots: + void selectWidget(); + void selectWidget(Ideal::Button *button); + void contextMenu(QPopupMenu*); + void moveToDockLeft(); + void moveToDockRight(); + void moveToDockBottom(); + void moveToDock(DDockWindow::Position); + +protected: + virtual void loadSettings(); + + Ideal::ButtonBar *m_bar; + QWidgetStack *m_widgetStack; + + QMap<Ideal::Button*, QWidget*> m_widgets; + QMap<QWidget*, Ideal::Button*> m_buttons; + +private: + Position m_position; + bool m_visible; + QString m_name; + DMainWindow *m_mainWindow; + bool m_doNotCloseActiveWidget; + + Ideal::Button *m_toggledButton; + Ideal::Button *m_lastContextMenuButton; + QBoxLayout *m_internalLayout; + + + KAction * m_moveToDockLeft; + KAction * m_moveToDockRight; + KAction * m_moveToDockBottom; +}; + +#endif diff --git a/src/newui/dmainwindow.cpp b/src/newui/dmainwindow.cpp new file mode 100644 index 00000000..27ffcf73 --- /dev/null +++ b/src/newui/dmainwindow.cpp @@ -0,0 +1,309 @@ +/*************************************************************************** + * Copyright (C) 2005 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "dmainwindow.h" + +#include <kdebug.h> +#include <kapplication.h> +#include <kconfig.h> +#include <kiconloader.h> + +#include <qtoolbutton.h> + +#include "dtabwidget.h" +#include "docksplitter.h" + +DMainWindow::DMainWindow(QWidget *parent, const char *name) + :KParts::MainWindow(parent, name), m_firstRemoved(false), m_currentWidget(0) +{ + loadSettings(); + createToolWindows(); + m_central = new Ideal::DockSplitter(Qt::Horizontal, this); + m_activeTabWidget = createTab(); + m_central->addDock(0, 0, m_activeTabWidget); + setCentralWidget(m_central); +} + +void DMainWindow::loadSettings() +{ + KConfig *config = kapp->config(); + config->setGroup("UI"); + m_openTabAfterCurrent = config->readBoolEntry("OpenNewTabAfterCurrent", true); + m_showIconsOnTabs = config->readBoolEntry("ShowTabIcons", false); +} + +void DMainWindow::saveSettings() +{ + m_leftDock->saveSettings(); + m_rightDock->saveSettings(); + m_bottomDock->saveSettings(); +} + +DMainWindow::~DMainWindow() +{ +/* for (QValueList<QWidget*>::iterator it = m_widgets.begin(); it != m_widgets.end(); ++it) + removeWidget(*it);*/ +} + +DDockWindow *DMainWindow::toolWindow(DDockWindow::Position position) const +{ + switch (position) { + case DDockWindow::Bottom: return m_bottomDock; + case DDockWindow::Left: return m_leftDock; + case DDockWindow::Right: return m_rightDock; + } + return 0; +} + +void DMainWindow::createToolWindows() +{ + m_bottomDock = new DDockWindow(this, DDockWindow::Bottom); + moveDockWindow(m_bottomDock, Qt::DockBottom); + m_leftDock = new DDockWindow(this, DDockWindow::Left); + moveDockWindow(m_leftDock, Qt::DockLeft); + m_rightDock = new DDockWindow(this, DDockWindow::Right); + moveDockWindow(m_rightDock, Qt::DockRight); +} + +void DMainWindow::addWidget(QWidget *widget, const QString &title) +{ +// invalidateActiveTabWidget(); + if (m_firstRemoved && m_activeTabWidget == m_tabs.first()) + { + m_central->addDock(0, 0, m_activeTabWidget); + m_firstRemoved = false; + } + + addWidget(m_activeTabWidget, widget, title); +} + +void DMainWindow::addWidget(DTabWidget *tab, QWidget *widget, const QString &title) +{ + static QPixmap emptyPixmap; + + int idx = -1; + if (m_openTabAfterCurrent && (tab->count() > 0)) + idx = tab->currentPageIndex() + 1; + if (m_showIconsOnTabs) + { + const QPixmap *pixmap = widget->icon(); + const QIconSet &icons = (pixmap && (pixmap->size().height() <= 16)) ? *(pixmap) : SmallIcon("kdevelop"); + tab->insertTab(widget, icons, title, idx); + } + else + tab->insertTab(widget, emptyPixmap, title, idx); + m_widgets.append(widget); + m_widgetTabs[widget] = tab; + widget->installEventFilter(this); + tab->showPage(widget); +} + +void DMainWindow::removeWidget(QWidget *widget) +{ + if (!m_widgets.contains(widget)) + return; //not a widget in main window + + if (m_widgetTabs.contains(widget)) + { + DTabWidget *tab = m_widgetTabs[widget]; + if (tab->indexOf(widget) >= 0) + { + tab->removePage(widget); + widget->reparent(0,QPoint(0,0),false); + if (tab->count() == 0) + { + if (tab->closeButton()) + tab->closeButton()->hide(); + //remove and delete tabwidget if it is not the first one + if (tab != m_tabs.first()) + { + QPair<uint, uint> idx = m_central->indexOf(tab); + m_tabs.remove(tab); + m_activeTabWidget = m_tabs.first(); + m_central->removeDock(idx.first, idx.second, true); + } + //only temporarily remove the first tabwidget + else + { + m_central->removeDock(0, 0, false); + m_firstRemoved = true; + } + //focus smth in m_activeTabWidget + if (m_activeTabWidget) + { + if (m_activeTabWidget->currentPage()) + { + m_activeTabWidget->currentPage()->setFocus(); + } + } + } + } + } + + m_widgets.remove(widget); + m_widgetTabs.remove(widget); + if (m_activeTabWidget && m_activeTabWidget->currentPage()) + { + //a hack to please multibuffer and actually switch the active part + QFocusEvent ev(QEvent::FocusIn); + QApplication::sendEvent(m_activeTabWidget->currentPage(), &ev); + } +} + +DTabWidget *DMainWindow::splitHorizontal() +{ + m_activeTabWidget = createTab(); + m_central->addDock(m_central->numRows(), 0, m_activeTabWidget); + return m_activeTabWidget; +} + +DTabWidget *DMainWindow::splitVertical() +{ +// invalidateActiveTabWidget(); + int row = m_central->indexOf(m_activeTabWidget).first; + m_activeTabWidget = createTab(); + m_central->addDock(row, m_central->numCols(row), m_activeTabWidget); + return m_activeTabWidget; +} + +void DMainWindow::invalidateActiveTabWidget() +{ +/* QWidget *focused = m_central->focusWidget(); + kdDebug(9000) << "invalidate: " << focused << endl; + if (focused == 0) + return; + if (!m_widgets.contains(focused)) + { + kdDebug(9000) << " focused is not in m_widgets" << endl; + return; + } + if (m_widgetTabs.contains(focused)) + { + kdDebug(9000) << " focused is in m_widgets and m_widgetTabs" << endl; + DTabWidget *tab = m_widgetTabs[focused]; + if (tab->indexOf(focused) >= 0) + m_activeTabWidget = tab; + kdDebug(9000) << " tab: " << tab << endl; + }*/ +} + +DTabWidget *DMainWindow::createTab() +{ + DTabWidget *tab = new DTabWidget(m_central); + m_tabs.append(tab); + if (tab->closeButton()) + connect(tab->closeButton(), SIGNAL(clicked()), this, SLOT(closeTab())); + connect(tab, SIGNAL(closeRequest(QWidget*)), this, SLOT(closeTab(QWidget*))); + connect(tab, SIGNAL(contextMenu(QWidget*,const QPoint &)), + this, SLOT(tabContext(QWidget*,const QPoint &))); + return tab; +} + +bool DMainWindow::eventFilter(QObject *obj, QEvent *ev) +{ + QWidget *w = (QWidget*)obj; + if (!m_widgets.contains(w)) + return KParts::MainWindow::eventFilter(obj, ev); + + if ((m_currentWidget != w) && (ev->type() == QEvent::FocusIn)) + { + m_currentWidget = w; + emit widgetChanged(w); + } + else if (ev->type() == QEvent::IconChange) + { + if (m_widgetTabs.contains(w)) + { + DTabWidget *tab = m_widgetTabs[w]; + tab->setTabIconSet(w, w->icon() ? (*(w->icon())) : QPixmap()); + } + } + else if (ev->type() == QEvent::CaptionChange) + { + kdDebug(9000) << "caption change" << endl; + DTabWidget *tab = m_widgetTabs[w]; + tab->changeTab(w, w->caption()); + } + + return KParts::MainWindow::eventFilter(obj, ev); +} + +void DMainWindow::closeTab() +{ + //nothing to do here, should be reimplemented +} + +void DMainWindow::tabContext(QWidget *, const QPoint &) +{ + //nothing to do here, should be reimplemented +} + +void DMainWindow::closeTab(QWidget *) +{ + //nothing to do here, should be reimplemented +} + +void DMainWindow::moveWidget(DDockWindow::Position position, QWidget * view, const QString & title) +{ + if (m_docks.contains(view)) + { + toolWindow(m_docks[view])->removeWidget(view); + + toolWindow(position)->addWidget( title, view, true ); + m_docks[view] = position; + } +} + +void DMainWindow::addDockWidget(DDockWindow::Position position, QWidget *view, const QString &title) +{ + toolWindow(position)->addWidget(title, view); + m_docks[view] = position; + connect(view, SIGNAL(destroyed()), this, SLOT(widgetDestroyed())); +} + +void DMainWindow::removeDockWidget(QWidget *view) +{ + toolWindow(m_docks[view])->removeWidget(view); + m_docks.remove(view); +} + +bool DMainWindow::hasDockWidget(QWidget *view) +{ + return m_docks.contains(view); +} + +DDockWindow::Position DMainWindow::dockWidgetPosition(QWidget *view) +{ + return m_docks[view]; +} + +void DMainWindow::widgetDestroyed() +{ + QWidget *w = static_cast<QWidget*>(const_cast<QObject*>(sender())); + + if (m_docks.contains(w)) + { + kdError() << "Widget destroyed before being removed from UI!" << endl; + m_docks.remove(w); + } +} + +#include "dmainwindow.moc" + +// kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on diff --git a/src/newui/dmainwindow.h b/src/newui/dmainwindow.h new file mode 100644 index 00000000..326d0c02 --- /dev/null +++ b/src/newui/dmainwindow.h @@ -0,0 +1,113 @@ +/*************************************************************************** + * Copyright (C) 2005 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef DMAINWINDOW_H +#define DMAINWINDOW_H + +#include <kxmlguiclient.h> +#include <kparts/mainwindow.h> + +#include "ddockwindow.h" + +class DTabWidget; +namespace Ideal { + class DockSplitter; +} + +/**Main window which provides simplified IDEA mode.*/ +class DMainWindow: public KParts::MainWindow { + Q_OBJECT +public: + DMainWindow(QWidget *parent = 0, const char *name = 0); + virtual ~DMainWindow(); + + /**@return The tool window in given @p position.*/ + DDockWindow *toolWindow(DDockWindow::Position position) const; + + /**Adds a tabbed widget into the active (focused) tab widget. + If @p widget is null then only tab is created.*/ + virtual void addWidget(QWidget *widget, const QString &title); + virtual void addWidget(DTabWidget *tab, QWidget *widget, const QString &title); + /**Removes widget. Does not delete it.*/ + virtual void removeWidget(QWidget *widget); + /**Moves a widget from an existing dockposition to a new position**/ + virtual void moveWidget(DDockWindow::Position newPosition, QWidget *widget, const QString & title); + + /**Adds a dock widget into given position.*/ + virtual void addDockWidget(DDockWindow::Position position, QWidget *view, const QString &title); + /**Removes a dock widget.*/ + virtual void removeDockWidget(QWidget *view); + + virtual void saveSettings(); + + bool hasDockWidget(QWidget *view); + DDockWindow::Position dockWidgetPosition(QWidget *view); + +public slots: + DTabWidget *splitHorizontal(); + DTabWidget *splitVertical(); + +protected slots: + /**This does nothing. Reimplement in subclass to close the tab + when corner close button is pressed.*/ + virtual void closeTab(); + /**This does nothing. Reimplement in subclass to close the tab + when hover close button is pressed.*/ + virtual void closeTab(QWidget*); + /**This does nothing. Reimplement in subclass to show tab context menu.*/ + virtual void tabContext(QWidget*,const QPoint &); + + void widgetDestroyed(); + +signals: + void widgetChanged(QWidget *); + +protected: + bool eventFilter(QObject *obj, QEvent *ev); + + virtual void loadSettings(); + + virtual void createToolWindows(); + virtual DTabWidget *createTab(); + + DDockWindow *m_leftDock; + DDockWindow *m_rightDock; + DDockWindow *m_bottomDock; + + QMap<QWidget*, DDockWindow::Position> m_docks; + + Ideal::DockSplitter *m_central; + DTabWidget *m_activeTabWidget; + + QValueList<DTabWidget*> m_tabs; + + bool m_openTabAfterCurrent; + bool m_showIconsOnTabs; + bool m_firstRemoved; + + QValueList<QWidget*> m_widgets; + QMap<QWidget*, DTabWidget*> m_widgetTabs; + QWidget *m_currentWidget; + +private slots: + void invalidateActiveTabWidget(); + +}; + +#endif diff --git a/src/newui/docksplitter.cpp b/src/newui/docksplitter.cpp new file mode 100644 index 00000000..46212f6c --- /dev/null +++ b/src/newui/docksplitter.cpp @@ -0,0 +1,175 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "docksplitter.h" + +#include <kdebug.h> + +namespace Ideal { + +DockSplitter::DockSplitter(Orientation orientation, QWidget *parent, const char *name) + :QSplitter(parent, name), m_orientation(orientation) +{ + switch (m_orientation) + { + case Horizontal: + setOrientation(Vertical); + break; + case Vertical: + setOrientation(Horizontal); + break; + } + setOpaqueResize(true); + appendSplitter(); +} + +DockSplitter::~DockSplitter() +{ +} + +void DockSplitter::addDock(uint row, uint col, QWidget *dock) +{ + if (m_docks.count() <= row) + for (uint i = m_docks.count(); i <= row ; ++i) + m_docks.append(QValueList<QWidget*>()); + + if (m_docks[row].count() <= col) + { + for (uint i = m_docks[row].count(); i <= col ; ++i) + m_docks[row].append(0); + m_docks[row][col] = dock; + } + else if (m_docks[row][col] == 0) + m_docks[row][col] = dock; + else + m_docks[row].insert(m_docks[row].at(col), dock); + + if (m_splitters.count() <= row) + createSplitters(row); + QSplitter *splitter = m_splitters[row]; + + dock->reparent(splitter, QPoint(0,0), true); + if (col < m_docks[row].count()-1) + shiftWidgets(splitter, row, col+1); +} + +void DockSplitter::appendSplitter() +{ + switch (m_orientation) + { + case Horizontal: + m_splitters.append(new QSplitter(Horizontal, this)); + break; + case Vertical: + m_splitters.append(new QSplitter(Vertical, this)); + break; + } + m_splitters[m_splitters.size()-1]->setOpaqueResize(true); + m_splitters[m_splitters.size()-1]->show(); +} + +void DockSplitter::createSplitters(uint index) +{ + kdDebug(9000) << "DockSplitter::createSplitters index = " << index << " count = " << m_splitters.count() << endl; + for (uint i = m_splitters.count(); i <= index; ++i) + { + kdDebug(9000) << " appendSplitter..." << endl; + appendSplitter(); + } +} + +void DockSplitter::removeDock(uint row, uint col, bool alsoDelete) +{ + if ((row >= m_docks.count()) || (col >= m_docks[row].count())) + return; + + QWidget *w = m_docks[row][col]; + m_docks[row].remove(m_docks[row].at(col)); + + if (alsoDelete) + { + delete w; + w = 0; + } + else + { + w->reparent(0, QPoint(0,0), false); + w->hide(); + } + + m_splitters[row]->setMinimumSize(m_splitters[row]->minimumSizeHint()); + + if (isRowEmpty(row)) + { + m_docks.remove(m_docks.at(row)); + delete m_splitters[row]; + m_splitters[row] = 0; + m_splitters.remove(m_splitters.at(row)); + } +} + +bool DockSplitter::isRowEmpty(int row) +{ + if (m_docks[row].count() == 0) + return true; + for (uint i = 0; i < m_docks[row].count(); ++i) + if (m_docks[row][i] != 0) + return false; + return true; +} + +void DockSplitter::shiftWidgets(QSplitter *splitter, uint row, uint fromCol) +{ + kdDebug(9000) << "shiftWidgets: row=" << row << " from col=" << fromCol << endl; + kdDebug(9000) << "row size is: " << m_docks[row].count() << endl; + + for (uint i = fromCol; i < m_docks[row].count(); ++i) + { + kdDebug(9000) << "move from " << i << " to last" << endl; + if (m_docks[row][i]) + splitter->moveToLast(m_docks[row][i]); + else + kdDebug(9000) << "m_docks[" << row << "][" << i << "] is 0" << endl; + } +} + +int DockSplitter::numRows() const +{ + return m_docks.count(); +} + +int DockSplitter::numCols(int row) const +{ + if (row < numRows()) + return m_docks[row].count(); + return 0; +} + +QPair<uint, uint> DockSplitter::indexOf(QWidget *dock) +{ + for (uint i = 0; i < m_docks.count(); ++i) + for (uint j = 0; j < m_docks[i].count(); ++j) + if (dock == m_docks[i][j]) + return qMakePair(i, j); + return qMakePair(0u, 0u); +} + +} + +#include "docksplitter.moc" diff --git a/src/newui/docksplitter.h b/src/newui/docksplitter.h new file mode 100644 index 00000000..214ad529 --- /dev/null +++ b/src/newui/docksplitter.h @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef IDEALDOCKSPLITTER_H +#define IDEALDOCKSPLITTER_H + +#include <qsplitter.h> +#include <qvaluelist.h> + +namespace Ideal { + +class DockWidget; + +/** +@short Splitter for docks +*/ +class DockSplitter: public QSplitter { + Q_OBJECT +public: + DockSplitter(Orientation orientation, QWidget *parent = 0, const char *name = 0); + ~DockSplitter(); + + void addDock(uint row, uint col, QWidget *dock); + void removeDock(uint row, uint col, bool alsoDelete = false); + + QPair<uint, uint> indexOf(QWidget *dock); + + int numRows() const; + int numCols(int row) const; + +protected: + void appendSplitter(); + void createSplitters(uint index); + void shiftWidgets(QSplitter *splitter, uint row, uint fromCol); + + bool isRowEmpty(int row); + +private: + Orientation m_orientation; + QValueList<QSplitter*> m_splitters; + QValueList<QValueList<QWidget*> > m_docks; +}; + +} + +#endif diff --git a/src/newui/dtabwidget.cpp b/src/newui/dtabwidget.cpp new file mode 100644 index 00000000..34ac9a5a --- /dev/null +++ b/src/newui/dtabwidget.cpp @@ -0,0 +1,106 @@ +/*************************************************************************** + * Copyright (C) 2005 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "dtabwidget.h" + +#include <qtoolbutton.h> +#include <qtabbar.h> + +#include <kconfig.h> +#include <kiconloader.h> +#include <kapplication.h> + +DTabWidget::DTabWidget(QWidget *parent, const char *name) + :KTabWidget(parent, name), m_closeButton(0) +{ + setFocusPolicy(NoFocus); + setMargin(0); + + loadSettings(); + + if (!m_tabBarShown) + tabBar()->hide(); + else { + m_closeButton = new QToolButton(this); + m_closeButton->setIconSet(SmallIcon("tab_remove")); + m_closeButton->adjustSize(); + m_closeButton->hide(); + setCornerWidget(m_closeButton, TopRight); + + if (m_closeOnHover) + setHoverCloseButton(true); + + setTabReorderingEnabled(true); + } + + connect(this, SIGNAL(currentChanged(QWidget*)), this, SLOT(setFocus(QWidget*))); +// connect(this, SIGNAL(currentChanged(QWidget*)), this, SLOT(updateHistory(QWidget*))); +} + +void DTabWidget::loadSettings() +{ + KConfig *config = kapp->config(); + config->setGroup("UI"); +// m_tabBarShown = config->readBoolEntry("TabBarShown", true); + m_tabBarShown = ! config->readNumEntry("TabWidgetVisibility", 0); + m_closeOnHover = config->readBoolEntry("CloseOnHover", false); + m_closeButtonShown = config->readBoolEntry("ShowCloseTabsButton", true); + //we do not delay hover close buttons - that looks and feels ugly + setHoverCloseButtonDelayed(false); +} + +void DTabWidget::saveSettings() +{ +} + +QToolButton *DTabWidget::closeButton() const +{ + return m_closeButton; +} + +void DTabWidget::setFocus(QWidget *w) +{ + if (w) + w->setFocus(); +} + +void DTabWidget::insertTab(QWidget *child, const QString &label, int index) +{ + if (m_closeButton && m_closeButtonShown) + m_closeButton->show(); + KTabWidget::insertTab(child, label, index); + if (index != -1) tabBar()->repaint(); +} + +void DTabWidget::insertTab(QWidget *child, const QIconSet &iconset, + const QString &label, int index) +{ + if (m_closeButton && m_closeButtonShown) + m_closeButton->show(); + KTabWidget::insertTab(child, iconset, label, index); + if (index != -1) tabBar()->repaint(); +} + +/*void DTabWidget::updateHistory(QWidget *w) +{ + if (m_history.top() != w) + m_history.push(w); +}*/ + +#include "dtabwidget.moc" diff --git a/src/newui/dtabwidget.h b/src/newui/dtabwidget.h new file mode 100644 index 00000000..4f51e47b --- /dev/null +++ b/src/newui/dtabwidget.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (C) 2005 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef DTABWIDGET_H +#define DTABWIDGET_H + +#include <ktabwidget.h> + +class QToolButton; + +class DTabWidget: public KTabWidget { + Q_OBJECT +public: + DTabWidget(QWidget *parent=0, const char *name=0); + + /**@return The close button at the top right corner. + May be 0 if the configuration do not allow close buttons or the tabbar.*/ + QToolButton *closeButton() const; + + 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); + +protected: + virtual void loadSettings(); + virtual void saveSettings(); + +private slots: + void setFocus(QWidget *w); +// void updateHistory(QWidget *w); + +private: + bool m_tabBarShown; + bool m_closeOnHover; + bool m_closeButtonShown; + + QToolButton *m_closeButton; +// QValueStack<QWidget*> *m_history; + +}; + +#endif diff --git a/src/partcontroller.cpp b/src/partcontroller.cpp new file mode 100644 index 00000000..1fb15445 --- /dev/null +++ b/src/partcontroller.cpp @@ -0,0 +1,1867 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <qpopupmenu.h> +#include <qfile.h> +#include <qlayout.h> +#include <qmap.h> +#include <qlabel.h> +#include <qradiobutton.h> +#include <qcheckbox.h> +#include <qdom.h> + +#include <kmimetype.h> +#include <kservice.h> +#include <ktrader.h> +#include <kapplication.h> +#include <krun.h> +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kparts/part.h> +#include <kparts/factory.h> +#include <kparts/partmanager.h> +#include <kparts/browserextension.h> +#include <kfiledialog.h> +#include <kmainwindow.h> +#include <kaction.h> +#include <kmessagebox.h> +#include <kstatusbar.h> +#include <khtml_part.h> +#include <kpopupmenu.h> +#include <kio/netaccess.h> +#include <kdialogbase.h> +#include <klineedit.h> +#include <kshortcut.h> +#include <kcompletion.h> +#include <kdirwatch.h> +#include <kdeversion.h> +#include <kiconloader.h> +#include <kuserprofile.h> +#include <kencodingfiledialog.h> +#include <ksqueezedtextlabel.h> + +#include <ktexteditor/view.h> +#include <ktexteditor/document.h> +#include <ktexteditor/viewcursorinterface.h> +#include <ktexteditor/encodinginterface.h> + +#include "toplevel.h" +#include "api.h" +#include "core.h" +#include "editorproxy.h" +#include "documentationpart.h" +#include "ksavealldialog.h" + +#include "kdevproject.h" +#include "urlutil.h" +#include "mimewarningdialog.h" +#include "domutil.h" +#include "kdevjobtimer.h" + +#include "designer.h" +#include "kdevlanguagesupport.h" + +#include "multibuffer.h" +#include "partcontroller.h" + + +class QDomDocument; + +PartController *PartController::s_instance = 0; + +using namespace MainWindowUtils; + +struct HistoryEntry +{ + KURL url; + QString context; + + HistoryEntry( const KURL& u, const QString& c ): url( u ), context( c ) {} +}; + +struct ModificationData +{ + KTextEditor::Document * doc; + bool isModified; + unsigned char reason; +}; + + +PartController::PartController(QWidget *parent) + : KDevPartController(parent), _editorFactory(0L), m_currentActivePart(0), m_removingActivePart(false) +{ + connect(this, SIGNAL(partRemoved(KParts::Part*)), this, SLOT(slotPartRemoved(KParts::Part* )) ); + connect(this, SIGNAL(partAdded(KParts::Part*)), this, SLOT(slotPartAdded(KParts::Part* )) ); + connect(this, SIGNAL(activePartChanged(KParts::Part*)), this, SLOT(slotActivePartChanged(KParts::Part*))); + + setupActions(); + + m_isJumping = false; + + m_openNextAsText = false; +} + + +PartController::~PartController() +{ +} + + +void PartController::createInstance(QWidget *parent) +{ + if (!s_instance) + s_instance = new PartController(parent); +} + + +PartController *PartController::getInstance() +{ + return s_instance; +} + + +void PartController::setupActions() +{ + KActionCollection *ac = TopLevel::getInstance()->main()->actionCollection(); + + KAction* newAction = KStdAction::open(this, SLOT(slotOpenFile()), ac, "file_open"); + newAction->setToolTip( i18n("Open file") ); + newAction->setWhatsThis( i18n("<b>Open file</b><p>Opens an existing file without adding it to the project.</p>") ); + + m_openRecentAction = KStdAction::openRecent( this, SLOT(slotOpenRecent(const KURL&) ), ac, "file_open_recent" ); + m_openRecentAction->setWhatsThis(QString("<b>%1</b><p>%2").arg(beautifyToolTip(m_openRecentAction->text())).arg(i18n("Opens recently opened file."))); + m_openRecentAction->loadEntries( kapp->config(), "RecentFiles" ); + + m_saveAllFilesAction = new KAction(i18n("Save Al&l"), 0, this, SLOT(slotSaveAllFiles()), ac, "file_save_all"); + m_saveAllFilesAction->setToolTip( i18n("Save all modified files") ); + m_saveAllFilesAction->setWhatsThis(i18n("<b>Save all</b><p>Saves all modified files.")); + m_saveAllFilesAction->setEnabled(false); + + m_revertAllFilesAction = new KAction(i18n("Rever&t All"), 0, this, SLOT(slotRevertAllFiles()), ac, "file_revert_all"); + m_revertAllFilesAction->setToolTip(i18n("Revert all changes")); + m_revertAllFilesAction->setWhatsThis(i18n("<b>Revert all</b><p>Reverts all changes in opened files. Prompts to save changes so the reversion can be canceled for each modified file.")); + m_revertAllFilesAction->setEnabled(false); + + m_closeWindowAction = KStdAction::close(this, SLOT(slotCloseWindow()), ac, "file_close"); + m_closeWindowAction->setToolTip( i18n("Close current file") ); + m_closeWindowAction->setWhatsThis(QString("<b>%1</b><p>%2").arg(beautifyToolTip(m_closeWindowAction->text())).arg(i18n("Closes current file."))); + m_closeWindowAction->setEnabled(false); + + m_closeAllWindowsAction = new KAction(i18n("Close All"), 0, this, SLOT(slotCloseAllWindows()), ac, "file_close_all"); + m_closeAllWindowsAction->setToolTip( i18n("Close all files") ); + m_closeAllWindowsAction->setWhatsThis(i18n("<b>Close all</b><p>Close all opened files.")); + m_closeAllWindowsAction->setEnabled(false); + + m_closeOtherWindowsAction = new KAction(i18n("Close All Others"), 0, this, SLOT(slotCloseOtherWindows()), ac, "file_closeother"); + m_closeOtherWindowsAction->setToolTip( i18n("Close other files") ); + m_closeOtherWindowsAction->setWhatsThis(i18n("<b>Close all others</b><p>Close all opened files except current.")); + m_closeOtherWindowsAction->setEnabled(false); + + new KActionSeparator(ac, "dummy_separator"); + + m_backAction = new KToolBarPopupAction(i18n("Back"), "back", 0, this, SLOT(slotBack()), ac, "history_back"); + m_backAction->setEnabled( false ); + m_backAction->setToolTip(i18n("Back")); + m_backAction->setWhatsThis(i18n("<b>Back</b><p>Moves backwards one step in the navigation history.")); + connect(m_backAction->popupMenu(), SIGNAL(aboutToShow()), this, SLOT(slotBackAboutToShow())); + connect(m_backAction->popupMenu(), SIGNAL(activated(int)), this, SLOT(slotBackPopupActivated(int))); + + m_forwardAction = new KToolBarPopupAction(i18n("Forward"), "forward", 0, this, SLOT(slotForward()), ac, "history_forward"); + m_forwardAction->setEnabled( false ); + m_forwardAction->setToolTip(i18n("Forward")); + m_forwardAction->setWhatsThis(i18n("<b>Forward</b><p>Moves forward one step in the navigation history.")); + connect(m_forwardAction->popupMenu(), SIGNAL(aboutToShow()), this, SLOT(slotForwardAboutToShow())); + connect(m_forwardAction->popupMenu(), SIGNAL(activated(int)), this, SLOT(slotForwardPopupActivated(int))); + + m_gotoLastEditPosAction = new KAction( i18n("Goto Last Edit Position"), "bottom", 0, this, SLOT(gotoLastEditPos()), ac, "goto_last_edit_pos" ); + m_gotoLastEditPosAction->setEnabled( false ); + m_gotoLastEditPosAction->setToolTip( i18n("Goto Last Edit Position") ); + m_gotoLastEditPosAction->setWhatsThis( i18n("<b>Goto Last Edit Position</b><p>Open the last edited file and position cursor at the point of edit") ); +} + +void PartController::setEncoding(const QString &encoding) +{ + m_presetEncoding = encoding; +} + +KParts::Part* PartController::findOpenDocument(const KURL& url) +{ + // if we find it this way, all is well + KParts::Part * part = partForURL( url ); + if ( part ) + { + return part; + } + + // ok, let's see if we can try harder + if ( API::getInstance()->project() ) + { + KURL partURL = findURLInProject( url ); + partURL.cleanPath(); + return partForURL( partURL ); + } + + return 0L; +} + +KURL PartController::findURLInProject(const KURL& url) +{ + QStringList fileList = API::getInstance()->project()->allFiles(); + + bool filenameOnly = (url.url().find('/') == -1); + QString filename = filenameOnly ? "/" : ""; + filename += url.url(); + + for (QStringList::Iterator it = fileList.begin(); it != fileList.end(); ++it) { + if ((*it).endsWith(filename)) { + // Match! The first one is as good as any one, I guess... + return KURL( API::getInstance()->project()->projectDirectory() + "/" + *it ); + } + } + + return url; +} + +void PartController::editDocument(const KURL &inputUrl, int lineNum, int col) +{ + editDocumentInternal(inputUrl, lineNum, col); +} + +void PartController::splitCurrentDocument(const KURL &inputUrl, + int lineNum, int col) +{ + editDocumentInternal(inputUrl, lineNum, col, true, true); +} + +void PartController::scrollToLineColumn(const KURL &inputUrl, + int lineNum, int col, bool storeHistory ) +{ + if ( KParts::ReadOnlyPart *existingPart = partForURL( inputUrl ) ) + { + if( storeHistory ) addHistoryEntry( existingPart ); + EditorProxy::getInstance()->setLineNumber( existingPart, lineNum, col ); + return; + } +} + +void PartController::editDocumentInternal( const KURL & inputUrl, int lineNum, + int col, bool activate, + bool addToCurrentBuffer ) +{ + kdDebug(9000) << k_funcinfo << "\n " << inputUrl.prettyURL() + << " linenum " << lineNum << " activate? " << activate + << " addToCurrentBuffer? " << addToCurrentBuffer << endl; + + KURL url = inputUrl; + + // is it already open? + // (Try this once before verifying the URL, we could be dealing with a file that no longer exists on disc) + if ( KParts::Part *existingPart = partForURL( url ) ) + { + // if we've been asked to OpenAs an open file with a specific encoding, assume the user wants to change encoding + if ( !m_presetEncoding.isNull() ) + { + if ( KTextEditor::EncodingInterface * ei = dynamic_cast<KTextEditor::EncodingInterface*>( existingPart ) ) + { + ei->setEncoding( m_presetEncoding ); + } + m_presetEncoding = QString::null; + } + + addHistoryEntry(); + activatePart( existingPart ); + EditorProxy::getInstance()->setLineNumber( existingPart, lineNum, col ); + return; + } + + // Make sure the URL exists + if ( !url.isValid() || !KIO::NetAccess::exists(url, false, 0) ) + { + bool done = false; + + // Try to find this file in the current project's list instead + if ( API::getInstance()->project() ) + { + if (url.isRelativeURL(url.url())) { + KURL relURL(API::getInstance()->project()->projectDirectory()); + relURL.addPath( url.url() ); + + kdDebug() << k_funcinfo << "Looking for file in project dir: " << API::getInstance()->project()->projectDirectory() << " url " << url.url() << " transformed to " << relURL.url() << ": " << done << endl; + if (relURL.isValid() && KIO::NetAccess::exists(relURL, false, 0)) { + url = relURL; + done = true; + } + else { + KURL relURL(API::getInstance()->project()->buildDirectory()); + relURL.addPath( url.url() ); + kdDebug() << k_funcinfo << "Looking for file in build dir: " << API::getInstance()->project()->buildDirectory() << " url " << url.url() << " transformed to " << relURL.url() << ": " << done << endl; + if (relURL.isValid() && KIO::NetAccess::exists(relURL, false, 0)) { + url = relURL; + done = true; + } + } + } + + if (!done) { + url = findURLInProject(url); + + if ( !url.isValid() || !KIO::NetAccess::exists(url, false, 0) ) + // See if this url is relative to the current project's directory + url = API::getInstance()->project()->projectDirectory() + "/" + url.path(); + + else + done = true; + } + } + + if ( !done && ( !url.isValid() || !KIO::NetAccess::exists(url, false, 0) )) + { + // Not found - prompt the user to find it? + kdDebug(9000) << "cannot find URL: " << url.url() << endl; + return; + } + } + + // We now have a url that exists ;) + + // clean it and resolve possible symlink + url.cleanPath(true); + if (url.isLocalFile()) + { + QString path = url.path(); + path = URLUtil::canonicalPath(path); + if ( !path.isEmpty() ) + url.setPath(path); + } + + // is it already open? + KParts::Part *existingPart = partForURL(url); + if (existingPart) + { + addHistoryEntry(); + activatePart(existingPart); + EditorProxy::getInstance()->setLineNumber(existingPart, lineNum, col); + return; + } + + if ( !addToCurrentBuffer ) + { + if ( KDevLanguageSupport *lang = + API::getInstance()->languageSupport() ) + { + // Let the language part override the addToCurrentBuffer flag + // if it decides to... + addToCurrentBuffer = lang->shouldSplitDocument( inputUrl ); + + if ( addToCurrentBuffer ) + { + kdDebug(9000) << + "languagePart() insists addToCurrentBuffer = true" << endl; + // Set activate = true, otherwise we have hard to fix + // multi-buffer delayed activation. + // I'll re-look at this later... + activate = true; + } + } + } + + KMimeType::Ptr MimeType = KMimeType::findByURL( url ); + + kdDebug(9000) << "mimeType = " << MimeType->name() << endl; + + // is the URL pointing to a directory? + if ( MimeType->is( "inode/directory" ) ) + { + return; + } + + if ( !m_presetEncoding.isNull() ) + { + m_openNextAsText = true; + } + + KConfig *config = kapp->config(); + config->setGroup("General Options"); + + // we don't trust KDE with designer files, let's handle it ourselves + if ( !m_openNextAsText && MimeType->is( "application/x-designer" ) ) + { + QString DesignerSetting = config->readEntry( "DesignerSetting", "ExternalDesigner" ); + QString designerExec = "designer"; + QStringList designerPluginPaths; + QDomDocument* dom = API::getInstance()->projectDom(); + if ( dom != 0 ) + { + // The global option specifies a fallback if the project + // has no setting or no project is open. However for Qt4 + // projects we want to use ExternalDesigner in any case. + if ( DomUtil::readIntEntry( *dom, "/kdevcppsupport/qt/version", 3 ) == 4 ) + { + designerPluginPaths = DomUtil::readListEntry(*dom, "/kdevcppsupport/qt/designerpluginpaths", "path" ); + DesignerSetting = "ExternalDesigner"; + } + + DesignerSetting = DomUtil::readEntry(*dom, "/kdevcppsupport/qt/designerintegration", DesignerSetting ); + designerExec = DomUtil::readEntry(*dom, "/kdevcppsupport/qt/designer", designerExec ); + } + if ( DesignerSetting == "ExternalKDevDesigner" ) + { + designerExec = "kdevdesigner"; + } + else if ( DesignerSetting == "EmbeddedKDevDesigner" ) + { + if ( KParts::ReadOnlyPart *designerPart = qtDesignerPart() ) + { + addHistoryEntry(); + activatePart(designerPart); + designerPart->openURL(url); + return; + } + else if ( KParts::Factory * KDevDesignerFactory = static_cast<KParts::Factory*>( KLibLoader::self()->factory( QFile::encodeName( "libkdevdesignerpart" ) ) ) ) + { + KParts::ReadWritePart * kdevpart = static_cast<KParts::ReadWritePart*>( KDevDesignerFactory->createPart( TopLevel::getInstance()->main(), 0, 0, 0, "KParts::ReadWritePart" ) ); + kdevpart->openURL( url ); + addHistoryEntry(); + integratePart( kdevpart, url ); + m_openRecentAction->addURL( url ); + m_openRecentAction->saveEntries( kapp->config(), "RecentFiles" ); + return; + } + } + + if( designerPluginPaths.isEmpty() ) + KRun::runCommand( designerExec+" "+url.pathOrURL() ); + else + KRun::runCommand( "QT_PLUGIN_PATH=\""+designerPluginPaths.join(":")+"\" "+designerExec+" "+url.pathOrURL() ); + + return; + } + + config->setGroup("General"); + + QStringList texttypeslist = config->readListEntry( "TextTypes" ); + if ( texttypeslist.contains( MimeType->name() ) ) + { + m_openNextAsText = true; + } + + bool isText = false; + QVariant v = MimeType->property("X-KDE-text"); + if (v.isValid()) + isText = v.toBool(); + // is this regular text - open in editor + if ( m_openNextAsText || isText || MimeType->is( "application/x-zerosize" ) ) + { + KTextEditor::Editor *editorpart = + createEditorPart( activate, addToCurrentBuffer, url ); + if ( editorpart ) + { + if ( m_presetEncoding.isNull() && API::getInstance()->projectDom() ) + { + QDomDocument * projectDom = API::getInstance()->projectDom(); + m_presetEncoding = DomUtil::readEntry( *projectDom, "/general/defaultencoding", QString::null ); + } + + if ( !m_presetEncoding.isNull() ) + { + if ( KTextEditor::EncodingInterface * ei = dynamic_cast<KTextEditor::EncodingInterface*>( editorpart ) ) + { + ei->setEncoding( m_presetEncoding ); + } + m_presetEncoding = QString::null; + } + + addHistoryEntry(); + + QWidget * widget = EditorProxy::getInstance()->topWidgetForPart( editorpart ); + + integratePart(editorpart, url, widget, true, activate, addToCurrentBuffer); + EditorProxy::getInstance()->setLineNumber(editorpart, lineNum, col); + + m_openNextAsText = false; + + m_openRecentAction->addURL( url ); + m_openRecentAction->saveEntries( kapp->config(), "RecentFiles" ); + + return; + } + } + + // OK, it's not text and it's not a designer file.. let's see what else we can come up with.. + + KParts::Factory *factory = 0; + QString className; + + QString services[] = { "KParts/ReadWritePart", "KParts/ReadOnlyPart" }; + QString classnames[] = { "KParts::ReadWritePart", "KParts::ReadOnlyPart" }; + for (uint i=0; i<2; ++i) + { + factory = findPartFactory( MimeType->name(), services[i] ); + if (factory) + { + className = classnames[i]; + break; + } + } + + kdDebug(9000) << "factory = " << factory << endl; + + if (factory) + { + // create the object of the desired class + KParts::ReadOnlyPart *part = static_cast<KParts::ReadOnlyPart*>( factory->createPart( TopLevel::getInstance()->main(), 0, 0, 0, className.latin1() ) ); + if ( part ) + { + part->openURL( url ); + addHistoryEntry(); + + if ( dynamic_cast<KTextEditor::Editor*>( part ) ) // we can have ended up with a texteditor, in which case need to treat it as such + { + integratePart(part, url, part->widget(), true, activate); + EditorProxy::getInstance()->setLineNumber(part, lineNum, col); + } + else + { + integratePart( part, url ); + } + + m_openRecentAction->addURL( url ); + m_openRecentAction->saveEntries( kapp->config(), "RecentFiles" ); + } + } + else + { + MimeWarningDialog dlg; + dlg.text2->setText( QString( "<qt><b>%1</b></qt>" ).arg(url.path())); + dlg.text3->setText( dlg.text3->text().arg(MimeType->name()) ); + + if ( dlg.exec() == QDialog::Accepted ) + { + if ( dlg.open_with_kde->isChecked() ) + { + KRun::runURL(url, MimeType->name() ); + } + else + { + if ( dlg.always_open_as_text->isChecked() ) + { + KConfig *config = kapp->config(); + config->setGroup("General"); + QStringList texttypeslist = config->readListEntry( "TextTypes" ); + texttypeslist << MimeType->name(); + config->writeEntry( "TextTypes", texttypeslist ); + } + m_openNextAsText = true; + editDocument( url, lineNum, col ); + } + } + } +} + + +void PartController::showDocument(const KURL &url, bool newWin) +{ + QString fixedPath = HTMLDocumentationPart::resolveEnvVarsInURL(url.url()); // possibly could env vars + KURL docUrl(fixedPath); + kdDebug(9000) << "SHOW: " << docUrl.url() << endl; + + if ( docUrl.isLocalFile() && KMimeType::findByURL(docUrl)->name() != "text/html" ) { + // a link in a html-file pointed to a local text file - display + // it in the editor instead of a html-view to avoid uglyness + editDocument( docUrl ); + return; + } + + addHistoryEntry(); + + HTMLDocumentationPart *part = dynamic_cast<HTMLDocumentationPart*>(activePart()); + if (!part || newWin) + { + part = new HTMLDocumentationPart; + integratePart(part,docUrl); + connect(part, SIGNAL(fileNameChanged(KParts::ReadOnlyPart* )), + this, SIGNAL(partURLChanged(KParts::ReadOnlyPart* ))); + } + else + { + activatePart(part); + } + part->openURL(docUrl); +} + +KParts::Factory *PartController::findPartFactory(const QString &mimeType, const QString &partType, const QString &preferredName) +{ + KTrader::OfferList offers = KTrader::self()->query(mimeType, QString("'%1' in ServiceTypes").arg(partType)); + + if (offers.count() > 0) + { + KService::Ptr ptr = 0; + // if there is a preferred plugin we'll take it + if ( !preferredName.isEmpty() ) { + KTrader::OfferList::Iterator it; + for (it = offers.begin(); it != offers.end(); ++it) { + if ((*it)->desktopEntryName() == preferredName) { + ptr = (*it); + } + } + } + // else we just take the first in the list + if ( !ptr ) { + ptr = offers.first(); + } + return static_cast<KParts::Factory*>(KLibLoader::self()->factory(QFile::encodeName(ptr->library()))); + } + + return 0; +} + +KTextEditor::Editor * PartController::createEditorPart( bool activate, + bool addToCurrentBuffer, + const KURL &url ) +{ + MultiBuffer *multiBuffer = 0; + if ( addToCurrentBuffer ) + { + multiBuffer = + dynamic_cast<MultiBuffer*>( + EditorProxy::getInstance()->topWidgetForPart( activePart() ) + ); + } + if ( !multiBuffer ) + { + kdDebug(9000) << "Creating a new MultiBuffer for " + << url.fileName() << endl; + multiBuffer = new MultiBuffer( TopLevel::getInstance()->main() ); + } + + static bool alwaysActivate = true; + + kapp->config()->setGroup("Editor"); + QString preferred = kapp->config()->readPathEntry("EmbeddedKTextEditor"); + // If we are not using kyzis... + // Don't create non-wrapped views for now, + // avoid two paths (== two chances for bad bugs) + if ( preferred != "kyzispart" ) + alwaysActivate = false; + + KTextEditor::Editor *editorpart = + dynamic_cast<KTextEditor::Editor*>(multiBuffer->createPart( "text/plain", + "KTextEditor/Document", + alwaysActivate | activate ? + "KTextEditor::Editor" : "KTextEditor::Document", + preferred + )); + + if ( url.isValid() ) + editorpart->openURL( url ); + + multiBuffer->registerURL( url, editorpart ); + multiBuffer->setDelayedActivation( !activate ); + return editorpart; +} + +void PartController::integratePart(KParts::Part *part, const KURL &url, + QWidget* widget, bool isTextEditor, + bool activate, bool addToCurrentBuffer ) +{ + if (!widget) widget = part->widget(); + + if (!widget) { + /// @todo error handling + kdDebug(9000) << "no widget for this part!!" << endl; + return; // to avoid later crash + } + + if ( !addToCurrentBuffer ) + TopLevel::getInstance()->embedPartView(widget, url.fileName(), url.url()); + + addPart(part, activate); + + // tell the parts we loaded a document + KParts::ReadOnlyPart *ro_part = dynamic_cast<KParts::ReadOnlyPart*>(part); + if ( !ro_part ) return; + + emit loadedFile( ro_part->url() ); + + connect( part, SIGNAL(modifiedOnDisc(Kate::Document*, bool, unsigned char)), this, SLOT(slotDocumentDirty(Kate::Document*, bool, unsigned char)) ); + + // let's get notified when a document has been changed + connect(part, SIGNAL(completed()), this, SLOT(slotUploadFinished())); + + // yes, we're cheating again. this signal exists for katepart's + // Document object and our HTMLDocumentationPart +// connect(part, SIGNAL(fileNameChanged()), this, SLOT(slotFileNameChanged())); + + // Connect to the document's views newStatus() signal in order to keep track of the + // modified-status of the document. + + if (isTextEditor) + integrateTextEditorPart(static_cast<KTextEditor::Document*>(part)); + + KInterfaceDesigner::Designer *designerPart = dynamic_cast<KInterfaceDesigner::Designer *>(part); + if (designerPart && API::getInstance()->languageSupport()) + { + kdDebug() << "integrating designer part with language support" << endl; + connect(designerPart, SIGNAL(addedFunction(DesignerType, const QString&, Function )), + API::getInstance()->languageSupport(), + SLOT(addFunction(DesignerType, const QString&, Function ))); + connect(designerPart, SIGNAL(editedFunction(DesignerType, const QString&, Function, Function )), API::getInstance()->languageSupport(), + SLOT(editFunction(DesignerType, const QString&, Function, Function ))); + connect(designerPart, SIGNAL(removedFunction(DesignerType, const QString&, Function )), + API::getInstance()->languageSupport(), + SLOT(removeFunction(DesignerType, const QString&, Function ))); + connect(designerPart, SIGNAL(editFunction(DesignerType, const QString&, const QString& )), + API::getInstance()->languageSupport(), + SLOT(openFunction(DesignerType, const QString&, const QString& ))); + connect(designerPart, SIGNAL(editSource(DesignerType, const QString& )), + API::getInstance()->languageSupport(), + SLOT(openSource(DesignerType, const QString& ))); + connect(designerPart, SIGNAL(newStatus(const QString &, int)), + this, SLOT(slotNewDesignerStatus(const QString &, int))); + } +} + +void PartController::integrateTextEditorPart(KTextEditor::Document* doc) +{ + // There's shortcut conflict between Kate and the debugger, resolve + // it here. Ideally, the should be some standard mechanism, configurable + // by config files. + // However, it does not exists and situation here some rare commands + // like "Dynamic word wrap" or "Show line numbers" from Kate take + // all possible shortcuts, leaving us with IDE that has no shortcuts for + // debugger, is very bad. + // + // We could try to handle this in debugger, but that would require + // the debugger to intercept all new KTextEditor::View creations, which is + // not possible. + + + if ( !doc ) return; + + connect( doc, SIGNAL(textChanged()), this, SLOT(textChanged()) ); + connect( doc, SIGNAL(fileNameChanged()), + this, SLOT(slotDocumentUrlChanged())); + + if( doc->widget() ) + { + connect( doc->widget(), SIGNAL(dropEventPass(QDropEvent *)), + TopLevel::getInstance()->main(), SLOT(slotDropEvent(QDropEvent *)) ); + } + + if ( KTextEditor::View * view = dynamic_cast<KTextEditor::View*>( doc->widget() ) ) + { + KActionCollection* c = view->actionCollection(); + // Be extra carefull, in case the part either don't provide those + // action, or uses different shortcuts. + + if (KAction* a = c->action("view_folding_markers")) + { + if (a->shortcut() == KShortcut(Key_F9)) + a->setShortcut(KShortcut()); + } + + if (KAction* a = c->action("view_dynamic_word_wrap")) + { + if (a->shortcut() == KShortcut(Key_F10)) + a->setShortcut(KShortcut()); + } + + if (KAction* a = c->action("view_line_numbers")) + { + if (a->shortcut() == KShortcut(Key_F11)) + a->setShortcut(KShortcut()); + } + } + + //EditorProxy::getInstance()->installPopup(doc, contextPopupMenu()); + + // What's potentially problematic is that this signal isn't officially part of the + // KTextEditor::View interface. It is nevertheless there, and used in kate and kwrite. + // There doesn't seem to be any othere way of making this work with katepart, and since + // signals are dynamic, if we try to connect to an editorpart that lacks this signal, + // all we get is a runtime warning. At this point in time we are only really supported + // by katepart anyway so IMHO this hack is justified. //teatime + QPtrList<KTextEditor::View> list = doc->views(); + QPtrListIterator<KTextEditor::View> it( list ); + while ( it.current() ) + { + connect( it, SIGNAL( newStatus() ), this, SLOT( slotNewStatus() ) ); + ++it; + } +} + +void PartController::slotPartAdded( KParts::Part * part ) +{ + kdDebug(9000) << k_funcinfo << endl; + + if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart*>( part ) ) + { + updatePartURL( ro_part ); + } + + updateMenuItems(); +} + +void PartController::slotPartRemoved( KParts::Part * part ) +{ + kdDebug(9000) << k_funcinfo << endl; + + _partURLMap.remove( static_cast<KParts::ReadOnlyPart*>(part) ); + + if ( part == m_currentActivePart ) + { + m_removingActivePart = true; + } + + updateMenuItems(); +} + +void PartController::updatePartURL( KParts::ReadOnlyPart * ro_part ) +{ + if ( ro_part->url().isEmpty() ) + { + kdDebug(9000) << "updatePartURL() called with empty URL for part: " << ro_part << endl; + return; + } + _partURLMap[ ro_part ] = ro_part->url(); +} + +bool PartController::partURLHasChanged( KParts::ReadOnlyPart * ro_part ) +{ + if ( _partURLMap.contains( ro_part ) && !ro_part->url().isEmpty() ) + { + if ( _partURLMap[ ro_part ] != ro_part->url() ) + { + return true; + } + } + return false; +} + +KURL PartController::storedURLForPart( KParts::ReadOnlyPart * ro_part ) +{ + if ( _partURLMap.contains( ro_part ) ) + { + return _partURLMap[ ro_part ]; + } + return KURL(); +} + + +void PartController::slotUploadFinished() +{ + KParts::ReadOnlyPart *ro_part = const_cast<KParts::ReadOnlyPart*>( dynamic_cast<const KParts::ReadOnlyPart*>(sender()) ); + if ( !ro_part ) return; + + if ( partURLHasChanged( ro_part ) ) + { + emit partURLChanged( ro_part ); + updatePartURL( ro_part ); + } +} + +KParts::ReadOnlyPart *PartController::partForURL(const KURL &url) +{ + QPtrListIterator<KParts::Part> it(*parts()); + for ( ; it.current(); ++it) + { + KParts::ReadOnlyPart *ro_part = dynamic_cast<KParts::ReadOnlyPart*>(it.current()); + if (ro_part && url.path() == ro_part->url().path()) + return ro_part; + } + return 0; +} + +KParts::Part * PartController::partForWidget( const QWidget * widget ) +{ + QPtrListIterator<KParts::Part> it(*parts()); + for ( ; it.current(); ++it) + { + if ( it.current()->widget() == widget ) + { + return *it; + } + } + return 0; +} + + +void PartController::activatePart(KParts::Part *part) +{ + if ( !part ) return; + + QWidget * widget = EditorProxy::getInstance()->widgetForPart( part ); + if (widget) + { + TopLevel::getInstance()->raiseView( widget ); + widget->show(); + widget->setFocus(); + } + + setActivePart(part); + + QWidget* w2 = EditorProxy::getInstance()->widgetForPart( part ); + if (w2 != widget) + w2->setFocus(); +} + +bool PartController::closePart(KParts::Part *part) +{ + KParts::ReadOnlyPart * ro_part = + dynamic_cast<KParts::ReadOnlyPart*>( part ); + + if ( !ro_part ) return true; + + KURL url = ro_part->url(); + + if (QWidget* w = EditorProxy::getInstance()->topWidgetForPart( part ) ) + { + if ( MultiBuffer *multiBuffer = dynamic_cast<MultiBuffer*>( w ) ) + { + kdDebug(9000) << "About to delete MultiBuffered document..." + << " numberOfBuffers: " << multiBuffer->numberOfBuffers() + << " isActivated: " << multiBuffer->isActivated() + << endl; + if ( !multiBuffer->closeURL( url ) ) + return false; + + if ( multiBuffer->numberOfBuffers() == 0 + || !multiBuffer->isActivated() ) + { + TopLevel::getInstance()->removeView( w ); + _dirtyDocuments.remove( static_cast<KParts::ReadWritePart*>( ro_part ) ); + emit closedFile( url ); +/* kdDebug(9000) << "Deleting MultiBuffer Part" << endl;*/ + TopLevel::getInstance()->main()->guiFactory()->removeClient( part ); + delete part; +/* kdDebug(9000) << "DeleteLater Actual MultiBuffer" << endl;*/ + multiBuffer->deleteLater(); + return true; + } + else + { +/* kdDebug(9000) << "Deleting MultiBuffer Part" << endl;*/ + _dirtyDocuments.remove( static_cast<KParts::ReadWritePart*>( ro_part ) ); + TopLevel::getInstance()->main()->guiFactory()->removeClient( part ); + emit closedFile( url ); + delete part; + // Switch to a remaining buffer + setActivePart( multiBuffer->activeBuffer() ); + return true; + } + } + else if ( !ro_part->closeURL() ) + return false; + TopLevel::getInstance()->removeView( w ); + } + else if ( !ro_part->closeURL() ) + return false; + TopLevel::getInstance()->main()->guiFactory()->removeClient( part ); + + _dirtyDocuments.remove( static_cast<KParts::ReadWritePart*>( ro_part ) ); + emit closedFile( url ); + +/* kdDebug(9000) << "Deleting Regular Part" << endl;*/ + delete part; + return true; +} + + +void PartController::updateMenuItems() +{ + bool hasWriteParts = false; + bool hasReadOnlyParts = false; + + QPtrListIterator<KParts::Part> it(*parts()); + for ( ; it.current(); ++it) + { + if (it.current()->inherits("KParts::ReadWritePart")) + hasWriteParts = true; + if (it.current()->inherits("KParts::ReadOnlyPart")) + hasReadOnlyParts = true; + } + + m_saveAllFilesAction->setEnabled(hasWriteParts); + m_revertAllFilesAction->setEnabled(hasWriteParts); + m_closeWindowAction->setEnabled(hasReadOnlyParts); + m_closeAllWindowsAction->setEnabled(hasReadOnlyParts); + m_closeOtherWindowsAction->setEnabled(hasReadOnlyParts); + + m_backAction->setEnabled( !m_backHistory.isEmpty() ); +} + +void PartController::slotRevertAllFiles() +{ + revertAllFiles(); +} + +void PartController::reloadFile( const KURL & url ) +{ + KParts::ReadWritePart * part = dynamic_cast<KParts::ReadWritePart*>( partForURL( url ) ); + if ( part ) + { + if ( part->isModified() ) + { + if ( KMessageBox::warningYesNo( TopLevel::getInstance()->main(), + i18n( "The file \"%1\" is modified in memory. Are you sure you want to reload it? (Local changes will be lost.)" ).arg( url.path() ), + i18n( "File is Modified" ), i18n("Reload"), i18n("Do Not Reload") ) == KMessageBox::Yes ) + { + part->setModified( false ); + } + else + { + return; + } + } + + unsigned int line = 0; unsigned int col = 0; + KTextEditor::ViewCursorInterface * iface = dynamic_cast<KTextEditor::ViewCursorInterface*>( part->widget() ); + if (iface) + { + iface->cursorPositionReal( &line, &col ); + } + + part->openURL( url ); + + _dirtyDocuments.remove( part ); + emit documentChangedState( url, Clean ); + + if ( iface ) + { + iface->setCursorPositionReal( line, col ); + } + } +} + +void PartController::revertFiles( const KURL::List & list ) +{ + KURL::List::ConstIterator it = list.begin(); + while ( it != list.end() ) + { + reloadFile( *it ); + ++it; + } +} + +void PartController::revertAllFiles() +{ + revertFiles( openURLs() ); +} + +void PartController::slotCloseWindow() +{ + closePart( activePart() ); +} + +KURL::List PartController::modifiedDocuments() +{ + KURL::List modFiles; + + QPtrListIterator<KParts::Part> it( *parts() ); + while( it.current() ) + { + KParts::ReadWritePart *rw_part = dynamic_cast<KParts::ReadWritePart*>(it.current()); + if ( rw_part && rw_part->isModified() ) + { + modFiles << rw_part->url(); + } + ++it; + } + return modFiles; +} + +void PartController::slotSave() +{ + kdDebug(9000) << k_funcinfo << endl; + + if ( KParts::ReadWritePart * part = dynamic_cast<KParts::ReadWritePart*>( activePart() ) ) + { + saveFile( part->url() ); + } +} + +void PartController::slotReload() +{ + kdDebug(9000) << k_funcinfo << endl; + + if ( KParts::ReadWritePart * part = dynamic_cast<KParts::ReadWritePart*>( activePart() ) ) + { + reloadFile( part->url() ); + } +} + +void PartController::slotSaveAllFiles() +{ + saveAllFiles(); +} + +bool PartController::saveFile( const KURL & url, bool force ) +{ + KParts::ReadWritePart * part = dynamic_cast<KParts::ReadWritePart*>( partForURL( url ) ); + if ( !part ) return true; + + switch( documentState( url ) ) + { + case Clean: + if ( !force ) + { + return true; + } + kdDebug(9000) << "Forced save" << endl; + break; + + case Modified: + kdDebug(9000) << "Normal save" << endl; + break; + + case Dirty: + case DirtyAndModified: + { + int code = KMessageBox::warningYesNoCancel( TopLevel::getInstance()->main(), + i18n("The file \"%1\" is modified on disk.\n\nAre you sure you want to overwrite it? (External changes will be lost.)").arg( url.path() ), + i18n("File Externally Modified"), i18n("Overwrite"), i18n("Do Not Overwrite") ); + if ( code == KMessageBox::Yes ) + { + kdDebug(9000) << "Dirty save!!" << endl; + } + else if ( code == KMessageBox::No ) + { + return true; + } + else + { + return false; // a 'false' return means to interrupt the process that caused the save + } + } + break; + + default: + ; + } + + if ( part->save() ) + { + _dirtyDocuments.remove( part ); + emit documentChangedState( url, Clean ); + emit savedFile( url ); + } + + return true; +} + +bool PartController::saveAllFiles() +{ + return saveFiles( openURLs() ); +} + +bool PartController::saveFiles( KURL::List const & filelist ) +{ + KURL::List::ConstIterator it = filelist.begin(); + while ( it != filelist.end() ) + { + if (saveFile( *it )==false) + return false; //user cancelled + ++it; + } + return true; +} + +bool PartController::querySaveFiles() +{ + return saveFilesDialog( KURL::List() ); +} + +void PartController::clearModified( KURL::List const & filelist ) +{ + KURL::List::ConstIterator it = filelist.begin(); + while ( it != filelist.end() ) + { + KParts::ReadWritePart * rw_part = dynamic_cast<KParts::ReadWritePart*>( partForURL( *it ) ); + if ( rw_part ) + { + rw_part->setModified( false ); + } + ++it; + } +} + +bool PartController::saveFilesDialog( KURL::List const & ignoreList ) +{ + KURL::List modList = modifiedDocuments(); + + if ( modList.count() > 0 && modList != ignoreList ) + { + KSaveSelectDialog dlg( modList, ignoreList, TopLevel::getInstance()->main() ); + if ( dlg.exec() == QDialog::Accepted ) + { + saveFiles( dlg.filesToSave() ); + clearModified( dlg.filesNotToSave() ); + } + else + { + return false; + } + } + return true; +} + +bool PartController::closeFilesDialog( KURL::List const & ignoreList ) +{ + if ( !saveFilesDialog( ignoreList ) ) return false; + + QPtrList<KParts::Part> partList( *parts() ); + QPtrListIterator<KParts::Part> it( partList ); + while ( KParts::Part* part = it.current() ) + { + KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart*>( part ); + if ( ro_part && !ignoreList.contains( ro_part->url() ) || !ro_part ) + { + closePart( part ); + } + ++it; + } + return true; +} + +bool PartController::closeFiles( const KURL::List & list ) +{ + KURL::List::ConstIterator it = list.begin(); + while ( it != list.end() ) + { + if ( !closePart( partForURL( *it ) ) ) + { + return false; + } + ++it; + } + return true; +} + +bool PartController::closeFile( const KURL & url ) +{ + return closePart( partForURL( url ) ); +} + +bool PartController::closeAllFiles() +{ + return closeFilesDialog( KURL::List() ); +} + +void PartController::slotCloseAllWindows() +{ + closeAllFiles(); +} + +bool PartController::closeAllOthers( const KURL & url ) +{ + KURL::List ignoreList; + ignoreList.append( url ); + + return closeFilesDialog( ignoreList ); +} + + +void PartController::slotCloseOtherWindows() +{ + if ( KParts::ReadOnlyPart * active = dynamic_cast<KParts::ReadOnlyPart*>( activePart() ) ) + { + closeAllOthers( active->url() ); + } +} + +void PartController::slotOpenFile() +{ + QString DefaultEncoding; + if ( QDomDocument * projectDom = API::getInstance()->projectDom() ) + { + DefaultEncoding = DomUtil::readEntry( *projectDom, "/general/defaultencoding", QString::null ); + } + + if ( DefaultEncoding.isEmpty() ) + { + // have a peek at katepart's settings: + KConfig * config = kapp->config(); + config->setGroup("Kate Document Defaults"); + DefaultEncoding = config->readEntry("Encoding", QString::null ); + } + + KEncodingFileDialog::Result result = KEncodingFileDialog::getOpenURLsAndEncoding( DefaultEncoding, QString::null, + QString::null, TopLevel::getInstance()->main(), QString::null ); + + for ( KURL::List::Iterator it = result.URLs.begin(); it != result.URLs.end(); ++it ) + { + m_presetEncoding = result.encoding; + editDocument( *it ); + } +} + +void PartController::slotOpenRecent( const KURL& url ) +{ + editDocument( url ); + // stupid bugfix - don't allow an active item in the list + m_openRecentAction->setCurrentItem( -1 ); +} + +bool PartController::readyToClose() +{ + blockSignals( true ); + + closeAllFiles(); // this should never return false, as the files are already saved + + return true; +} + +void PartController::slotActivePartChanged( KParts::Part *part ) +{ + kdDebug(9000) << k_funcinfo << part << endl; + + if ( !m_isJumping && !m_removingActivePart ) + { + if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart*>(m_currentActivePart) ) + { + addHistoryEntry( ro_part ); + } + } + + m_currentActivePart = part; + m_removingActivePart = false; + + if (part) { + KXMLGUIClient* client = dynamic_cast<KXMLGUIClient*>(part->widget()); + if (client) Core::setupShourtcutTips(client); + } + + updateMenuItems(); + QTimer::singleShot( 100, this, SLOT(slotWaitForFactoryHack()) ); +} + +void PartController::showPart( KParts::Part* part, const QString& name, const QString& shortDescription ) +{ + if (!part->widget()) { + /// @todo error handling + return; // to avoid later crash + } + + QPtrListIterator<KParts::Part> it(*parts()); + for ( ; it.current(); ++it) + { + if( it.current() == part ){ + // part already embedded + activatePart( it.current() ); + return; + } + } + + // embed the part + TopLevel::getInstance()->embedPartView( part->widget(), name, shortDescription ); + addPart( part ); +} + +void PartController::slotDocumentDirty( Kate::Document * d, bool isModified, unsigned char reason ) +{ + kdDebug(9000) << k_funcinfo << endl; + + // KTextEditor::Document * doc = reinterpret_cast<KTextEditor::Document*>( d ); // theoretically unsafe in MI scenario + KTextEditor::Document * doc = 0; + + QPtrListIterator<KParts::Part> it( *parts() ); + while( it.current() ) + { + if ( (void*)it.current() == (void*)d ) + { + doc = dynamic_cast<KTextEditor::Document*>( it.current() ); + break; + } + ++it; + } + + // this is a bit strange, but in order to avoid weird crashes + // down in KDirWatcher, we want to step off the call chain before + // opening any messageboxes + if ( doc ) + { + ModificationData * p = new ModificationData; + p->doc = doc; + p->isModified = isModified; + p->reason = reason; + KDevJobTimer::singleShot( 0, this, SLOT(slotDocumentDirtyStepTwo(void*)), p ); + } +} + +void PartController::slotDocumentDirtyStepTwo( void * payload ) +{ + if ( !payload ) return; + + ModificationData * p = reinterpret_cast<ModificationData*>( payload ); + KTextEditor::Document * doc = p->doc; + + // let's make sure the document is still loaded + bool haveDocument = false; + if( const QPtrList<KParts::Part> * partlist = parts() ) + { + QPtrListIterator<KParts::Part> it( *partlist ); + while ( KParts::Part * part = it.current() ) + { + if ( p->doc == dynamic_cast<KTextEditor::Document*>( part ) ) + { + haveDocument = true; + break; + } + ++it; + } + } + if ( !haveDocument ) return; + + bool isModified = p->isModified; + unsigned char reason = p->reason; + delete p; + + KURL url = storedURLForPart( doc ); + if ( url.isEmpty() ) + { + kdDebug(9000) << "Warning!! the stored url is empty. Bailing out!" << endl; + } + + if ( reason > 0 ) + { + if ( !_dirtyDocuments.contains( doc ) ) + { + _dirtyDocuments.append( doc ); + } + + if ( reactToDirty( url, reason ) ) + { + // file has been reloaded + emit documentChangedState( url, Clean ); + _dirtyDocuments.remove( doc ); + } + else + { + doEmitState( url ); + } + } + else + { + _dirtyDocuments.remove( doc ); + emit documentChangedState( url, Clean ); + } + + kdDebug(9000) << doc->url().url() << endl; + kdDebug(9000) << isModified << endl; + kdDebug(9000) << reason << endl; +} + +bool PartController::isDirty( KURL const & url ) +{ + return _dirtyDocuments.contains( static_cast<KTextEditor::Document*>( partForURL( url ) ) ); +} + +bool PartController::reactToDirty( KURL const & url, unsigned char reason ) +{ + KConfig *config = kapp->config(); + config->setGroup("Editor"); + QString dirtyAction = config->readEntry( "DirtyAction" ); + + if ( dirtyAction == "nothing" ) return false; + + bool isModified = true; + if( KParts::ReadWritePart * part = dynamic_cast<KParts::ReadWritePart*>( partForURL( url ) ) ) + { + isModified = part->isModified(); + } + else + { + kdDebug(9000) << k_funcinfo << " Warning. Not a ReadWritePart." << endl; + return false; + } + + if ( isModified ) + { + KMessageBox::sorry( TopLevel::getInstance()->main(), + i18n("Conflict: The file \"%1\" has changed on disk while being modified in memory.\n\n" + "You should investigate before saving to make sure you are not losing data.").arg( url.path() ), + i18n("Conflict") ); + return false; + } + + if ( reason == 3 ) // means the file was deleted + { + KMessageBox::sorry( TopLevel::getInstance()->main(), + i18n("Warning: The file \"%1\" has been deleted on disk.\n\n" + "If this was not your intention, make sure to save this file now.").arg( url.path() ), + i18n("File Deleted") ); + return false; + } + + if ( dirtyAction == "alert" ) + { + if ( KMessageBox::warningYesNo( TopLevel::getInstance()->main(), + i18n("The file \"%1\" has changed on disk.\n\nDo you want to reload it?").arg( url.path() ), + i18n("File Changed"), i18n("Reload"), i18n("Do Not Reload") ) == KMessageBox::No ) + { + return false; + } + } + + // here we either answered yes above or are in autoreload mode + reloadFile( url ); + + return true; +} + +void PartController::slotNewDesignerStatus(const QString &formName, int status) +{ + kdDebug(9000) << k_funcinfo << endl; + kdDebug(9000) << " formName: " << formName << ", status: " << status << endl; + emit documentChangedState( KURL::fromPathOrURL(formName), DocumentState(status) ); +} + +void PartController::slotNewStatus( ) +{ + kdDebug(9000) << k_funcinfo << endl; + + QObject * senderobj = const_cast<QObject*>( sender() ); + KTextEditor::View * view = dynamic_cast<KTextEditor::View*>( senderobj ); + if ( view ) + { + doEmitState( view->document()->url() ); + } +} + +DocumentState PartController::documentState( KURL const & url ) +{ + KParts::ReadWritePart * rw_part = dynamic_cast<KParts::ReadWritePart*>( partForURL( url ) ); + if ( !rw_part ) return Clean; + + DocumentState state = Clean; + if ( rw_part->isModified() ) + { + state = Modified; + } + + if ( isDirty( url ) ) + { + if ( state == Modified ) + { + state = DirtyAndModified; + } + else + { + state = Dirty; + } + } + + return state; +} + +void PartController::doEmitState( KURL const & url ) +{ + emit documentChangedState( url, documentState( url ) ); +} + +KURL::List PartController::openURLs( ) +{ + KURL::List list; + QPtrListIterator<KParts::Part> it(*parts()); + for ( ; it.current(); ++it) + { + if ( KParts::ReadOnlyPart *ro_part = dynamic_cast<KParts::ReadOnlyPart*>(it.current()) ) + { + list << ro_part->url(); + } + } + return list; +} + +///////////////////////////////////////////////////////////////////////////// + +//BEGIN History methods + +PartController::HistoryEntry::HistoryEntry( const KURL & u, int l, int c) + : url(u), line(l), col(c) +{ + id = abs( QTime::currentTime().msecsTo( QTime() ) ); // should provide a reasonably unique number +} + +void PartController::slotBack() +{ + HistoryEntry thatEntry = m_backHistory.front(); + m_backHistory.pop_front(); + m_backAction->setEnabled( !m_backHistory.isEmpty() ); + + HistoryEntry thisEntry = createHistoryEntry(); + if ( !thisEntry.url.isEmpty() ) + { + m_forwardHistory.push_front( thisEntry ); + m_forwardAction->setEnabled( true ); + } + + jumpTo( thatEntry ); +} + +void PartController::slotForward() +{ + HistoryEntry thatEntry = m_forwardHistory.front(); + m_forwardHistory.pop_front(); + m_forwardAction->setEnabled( !m_forwardHistory.isEmpty() ); + + HistoryEntry thisEntry = createHistoryEntry(); + if ( !thisEntry.url.isEmpty() ) + { + m_backHistory.push_front( thisEntry ); + m_backAction->setEnabled( true ); + } + + jumpTo( thatEntry ); +} + +void PartController::slotBackAboutToShow() +{ + KPopupMenu *popup = m_backAction->popupMenu(); + popup->clear(); + + if ( m_backHistory.isEmpty()) return; + + int i = 0; + QValueList<HistoryEntry>::ConstIterator it = m_backHistory.begin(); + while( i < 10 && it != m_backHistory.end() ) + { + popup->insertItem( (*it).url.fileName() + QString(" (%1)").arg( (*it).line +1), (*it).id ); + ++i; + ++it; + } +} + +void PartController::slotForwardAboutToShow( ) +{ + KPopupMenu * popup = m_forwardAction->popupMenu(); + popup->clear(); + + if ( m_forwardHistory.isEmpty() ) return; + + int i = 0; + QValueList<HistoryEntry>::ConstIterator it = m_forwardHistory.begin(); + while( i < 10 && it != m_forwardHistory.end() ) + { + popup->insertItem( (*it).url.fileName() + QString(" (%1)").arg( (*it).line +1), (*it).id ); + ++i; + ++it; + } +} + +void PartController::slotBackPopupActivated( int id ) +{ + QValueList<HistoryEntry>::Iterator it = m_backHistory.begin(); + while( it != m_backHistory.end() ) + { + if ( (*it).id == id ) + { + HistoryEntry entry = *it; + m_backHistory.erase( m_backHistory.begin(), ++it ); + m_backAction->setEnabled( !m_backHistory.isEmpty() ); + + HistoryEntry thisEntry = createHistoryEntry(); + if ( !thisEntry.url.isEmpty() ) + { + m_forwardHistory.push_front( thisEntry ); + m_forwardAction->setEnabled( true ); + } + + jumpTo( entry ); + return; + } + ++it; + } +} + +void PartController::slotForwardPopupActivated( int id ) +{ + QValueList<HistoryEntry>::Iterator it = m_forwardHistory.begin(); + while( it != m_forwardHistory.end() ) + { + if ( (*it).id == id ) + { + HistoryEntry entry = *it; + m_forwardHistory.erase( m_forwardHistory.begin(), ++it ); + m_forwardAction->setEnabled( !m_forwardHistory.isEmpty() ); + + HistoryEntry thisEntry = createHistoryEntry(); + if ( !thisEntry.url.isEmpty() ) + { + m_backHistory.push_front( thisEntry ); + m_backAction->setEnabled( true ); + } + + jumpTo( entry ); + return; + } + ++it; + } +} + +void PartController::jumpTo( const HistoryEntry & entry ) +{ + m_isJumping = true; + editDocument( entry.url, entry.line, entry.col ); + m_isJumping = false; +} + + +PartController::HistoryEntry PartController::createHistoryEntry( KParts::ReadOnlyPart * ro_part ) { + if( ro_part == 0 ) + ro_part = dynamic_cast<KParts::ReadOnlyPart*>( activePart() ); + + if ( !ro_part ) return HistoryEntry(); + KTextEditor::ViewCursorInterface * cursorIface = dynamic_cast<KTextEditor::ViewCursorInterface*>( ro_part->widget() ); + if ( !cursorIface ) return HistoryEntry(); + + uint line = 0; + uint col = 0; + cursorIface->cursorPositionReal( &line, &col ); + + return HistoryEntry( ro_part->url(), line, col ); +} + + +// this should be called _before_ a jump is made +void PartController::addHistoryEntry( KParts::ReadOnlyPart * part ) +{ + if ( m_isJumping ) return; + + HistoryEntry thisEntry = createHistoryEntry( part ); + if ( !thisEntry.url.isEmpty() ) + { + HistoryEntry lastEntry = m_backHistory.front(); + if ( (lastEntry.url.path() != thisEntry.url.path()) || (lastEntry.line != thisEntry.line) ) + { + m_backHistory.push_front( thisEntry ); + m_backAction->setEnabled( true ); + + m_forwardHistory.clear(); + m_forwardAction->setEnabled( false ); + } + else + { + kdDebug(9000) << "** avoiding to create duplicate history entry **" << endl; + } + } +} + +//END History methods + +void PartController::slotWaitForFactoryHack( ) +{ + //kdDebug(9000) << k_funcinfo << endl; + + if ( !activePart() ) return; + + if ( dynamic_cast<KTextEditor::View*>( activePart()->widget() ) ) + { + if ( !activePart()->factory() ) + { + QTimer::singleShot( 100, this, SLOT(slotWaitForFactoryHack()) ); + return; + } + else + { + EditorProxy::getInstance()->installPopup( activePart() ); + } + } + + if ( MultiBuffer *multiBuffer = + dynamic_cast<MultiBuffer*>( + EditorProxy::getInstance()->topWidgetForPart( activePart() ) ) + ) + { + KURL url = dynamic_cast<KParts::ReadOnlyPart*>( activePart() )->url(); + multiBuffer->activePartChanged( url ); + // Really unfortunate, but the mainWindow relies upon this + // to set the tab's icon + emit documentChangedState( url, documentState( url ) ); + } +} + +KParts::ReadOnlyPart *PartController::qtDesignerPart() +{ + QPtrListIterator<KParts::Part> it(*parts()); + for ( ; it.current(); ++it) + { + KInterfaceDesigner::Designer *des = dynamic_cast<KInterfaceDesigner::Designer*>(it.current()); + if (des && des->designerType() == KInterfaceDesigner::QtDesigner) + return des; + } + return 0; +} + +KTextEditor::Editor *PartController::openTextDocument( bool activate ) +{ + KTextEditor::Editor *editorpart = + createEditorPart( activate, false, KURL( i18n("unnamed") ) ); + + if ( editorpart ) + { + if ( !m_presetEncoding.isNull() ) + { + KParts::BrowserExtension * extension = + KParts::BrowserExtension::childObject( editorpart ); + if ( extension ) + { + KParts::URLArgs args; + args.serviceType = QString( "text/plain;" ) + m_presetEncoding; + extension->setURLArgs(args); + } + m_presetEncoding = QString::null; + } + + QWidget * widget = + EditorProxy::getInstance()->topWidgetForPart( editorpart ); + + addHistoryEntry(); + integratePart(editorpart, KURL(i18n("unnamed")), widget, true, true); + + EditorProxy::getInstance()->setLineNumber(editorpart, 0, 0); + } + + return editorpart; +} + +void PartController::textChanged() +{ + if ( KTextEditor::Document * doc = dynamic_cast<KTextEditor::Document*>( activePart() ) ) + { + if ( KTextEditor::ViewCursorInterface * vci = dynamic_cast<KTextEditor::ViewCursorInterface*>( doc->widget() ) ) + { + m_gotoLastEditPosAction->setEnabled( true ); + + m_lastEditPos.url = doc->url(); + vci->cursorPosition( &m_lastEditPos.pos.first, &m_lastEditPos.pos.second ); + } + } +} + +void PartController::gotoLastEditPos() +{ + editDocument( m_lastEditPos.url, m_lastEditPos.pos.first, m_lastEditPos.pos.second ); +} + +void PartController::slotDocumentUrlChanged() +{ + QObject *obj = const_cast<QObject*>(sender()); + KTextEditor::Document *doc = dynamic_cast<KTextEditor::Document*>( obj ); + if (!doc) + return; + + MultiBuffer *multiBuffer = dynamic_cast<MultiBuffer*>( + EditorProxy::getInstance()->findPartWidget( doc )); + if (!multiBuffer) + return; + + multiBuffer->updateUrlForPart(doc, doc->url()); + updatePartURL(doc); + emit partURLChanged(doc); +} + +#include "partcontroller.moc" + diff --git a/src/partcontroller.h b/src/partcontroller.h new file mode 100644 index 00000000..9aa4e226 --- /dev/null +++ b/src/partcontroller.h @@ -0,0 +1,232 @@ +#ifndef __PARTCONTROLLER_H__ +#define __PARTCONTROLLER_H__ + +#include "kdevpartcontroller.h" + +#include <qwidget.h> +#include <qdatetime.h> +#include <qptrlist.h> +#include <kurl.h> +#include <qmap.h> +#include <qguardedptr.h> +#include <qpair.h> + +namespace KParts +{ + class Part; + class Factory; + class PartManager; + class ReadOnlyPart; + class ReadWritePart; +} + +namespace KTextEditor +{ + class Document; + class Editor; +} + +namespace Kate { class Document; } + +class QTabWidget; +class QPopupMenu; +class KAction; +class KToolBarPopupAction; +class KRecentFilesAction; +class HTMLDocumentationPart; +class HistoryEntry; +class KDirWatch; + +/** +Part controler implementation. +*/ +class PartController : public KDevPartController +{ + Q_OBJECT + +public: + + PartController(QWidget *toplevel); + static void createInstance(QWidget *parent); + static PartController *getInstance(); + + ///// KDevPartController interface + + void setEncoding(const QString &encoding); + void editDocument(const KURL &inputUrl, int lineNum=-1, int col=-1); + void splitCurrentDocument(const KURL &inputUrl, int lineNum=-1, int col=-1); + void scrollToLineColumn(const KURL &url, int lineNum=-1, int col=-1, bool storeHistory = false ); + void editDocumentInternal(const KURL &inputUrl, int lineNum=-1, int col=-1, + bool activate = true, bool addToCurrentBuffer = false ); + void integrateTextEditorPart(KTextEditor::Document* doc); + + void showDocument(const KURL &url, bool newWin = false); + void showPart( KParts::Part* part, const QString& name, const QString& shortDescription ); + + KParts::ReadOnlyPart *partForURL(const KURL &url); + KParts::ReadOnlyPart *qtDesignerPart(); + KParts::Part * partForWidget( const QWidget * widget ); + + void activatePart( KParts::Part * part ); + bool closePart( KParts::Part * part ); + + KURL::List openURLs(); + + bool querySaveFiles(); + + bool saveAllFiles(); + bool saveFiles( const KURL::List & list); + bool saveFile( const KURL & url, bool force = false ); + + void revertAllFiles(); + void revertFiles( const KURL::List & list ); + + bool closeAllFiles(); + bool closeFiles( const KURL::List & list ); + + DocumentState documentState( KURL const & ); + + //////////////////////////////////////// + + bool readyToClose(); + + bool closeFile( const KURL & ); + bool closeAllOthers( const KURL & ); + void reloadFile( const KURL & url ); + + KTextEditor::Editor *openTextDocument( bool activate = true ); + KParts::Factory *findPartFactory(const QString &mimeType, + const QString &partType, + const QString &preferredName = QString::null ); + +public slots: + + void slotActivePartChanged( KParts::Part* part ); + void slotCloseWindow(); + void slotCloseOtherWindows(); + void slotCloseAllWindows(); + + void slotSave(); + void slotReload(); + +protected: + + ~PartController(); + +private slots: + + void slotWaitForFactoryHack(); + + void slotDocumentUrlChanged(); + void slotSaveAllFiles(); + void slotRevertAllFiles(); + + void slotOpenFile(); + void slotOpenRecent(const KURL&); + + void slotBack(); + void slotForward(); + void slotBackAboutToShow(); + void slotForwardAboutToShow(); + void slotBackPopupActivated( int id ); + void slotForwardPopupActivated( int id ); + + void slotPartAdded( KParts::Part* ); + void slotPartRemoved( KParts::Part* ); + + void slotUploadFinished(); + + void updateMenuItems(); + + void slotDocumentDirty( Kate::Document * doc, bool isModified, unsigned char reason ); + void slotDocumentDirtyStepTwo( void * ); + void slotNewStatus(); + void slotNewDesignerStatus(const QString &formName, int status); + void textChanged(); + void gotoLastEditPos(); + +private: + KURL findURLInProject(const KURL& url); + KParts::Part* findOpenDocument(const KURL& url); + + void setupActions(); + + bool closeFilesDialog( KURL::List const & ignoreList ); + bool saveFilesDialog( KURL::List const & ignoreList ); + + void doEmitState( KURL const & ); + + KTextEditor::Editor * createEditorPart( bool activate, + bool addToCurrentBuffer = false, + const KURL &url = KURL() ); + + void integratePart(KParts::Part *part, const KURL &url, QWidget* widget = 0, + bool isTextEditor=false, bool activate=true, + bool addToCurrentBuffer = false ); + + // returns a list of modified documents + KURL::List modifiedDocuments(); + void clearModified( KURL::List const & filelist ); + + bool isDirty( KURL const & url ); + bool reactToDirty( KURL const & url, unsigned char reason ); + + KURL storedURLForPart( KParts::ReadOnlyPart * ); + void updatePartURL( KParts::ReadOnlyPart * ); + bool partURLHasChanged( KParts::ReadOnlyPart * ); + + static PartController *s_instance; + + KAction *m_closeWindowAction, *m_saveAllFilesAction, *m_revertAllFilesAction; + KAction *m_closeAllWindowsAction, *m_closeOtherWindowsAction; + KRecentFilesAction *m_openRecentAction; + QString m_presetEncoding; + + KToolBarPopupAction* m_backAction; + KToolBarPopupAction* m_forwardAction; + KAction * m_gotoLastEditPosAction; + + bool m_openNextAsText; + + QValueList<KParts::ReadWritePart*> _dirtyDocuments; + + QMap< KParts::ReadOnlyPart*, KURL > _partURLMap; // used to note when a URL changes (a file changes name) + + QGuardedPtr<KParts::Factory> _editorFactory; + + struct HistoryEntry + { + HistoryEntry() {} + HistoryEntry( const KURL & url, int line, int col ); + + KURL url; + int line; + int col; + int id; + }; + + void addHistoryEntry( KParts::ReadOnlyPart * part = 0 ); + HistoryEntry createHistoryEntry( KParts::ReadOnlyPart * part = 0 ); + void jumpTo( const HistoryEntry & ); + + QValueList<HistoryEntry> m_backHistory; + QValueList<HistoryEntry> m_forwardHistory; + bool m_isJumping; + + struct LastEditPos + { + KURL url; + QPair<unsigned int,unsigned int> pos; + + LastEditPos() : pos( -1, -1) {} + }; + + LastEditPos m_lastEditPos; + + KParts::Part * m_currentActivePart; + bool m_removingActivePart; +}; + + + +#endif diff --git a/src/plugincontroller.cpp b/src/plugincontroller.cpp new file mode 100644 index 00000000..2dc01654 --- /dev/null +++ b/src/plugincontroller.cpp @@ -0,0 +1,391 @@ +#include <qfile.h> +#include <qvbox.h> + +#include <kcmdlineargs.h> +#include <kapplication.h> +#include <klibloader.h> +#include <kservice.h> +#include <ktrader.h> +#include <kmessagebox.h> +#include <kconfig.h> +#include <klocale.h> +#include <kmainwindow.h> +#include <kparts/componentfactory.h> +#include <assert.h> +#include <kdebug.h> +#include <kdialogbase.h> +#include <kcmdlineargs.h> +#include <kstandarddirs.h> +#include <kstatusbar.h> +#include <kiconloader.h> + +#include <kdevapi.h> +#include <kdevplugin.h> +#include <kdevmakefrontend.h> +#include <kdevappfrontend.h> +#include <kdevdifffrontend.h> +#include <kdevsourceformatter.h> +#include <kdevcreatefile.h> +#include <kdevplugininfo.h> +#include <kaction.h> + +#include <profileengine.h> + +#include "core.h" +#include "api.h" +#include "toplevel.h" +#include "projectmanager.h" +//#include "partselectwidget.h" +#include "domutil.h" +#include "plugincontroller.h" +#include "pluginselectdialog.h" + +#include "shellextension.h" + +// a separate method in this anonymous namespace to avoid having it all +// inline in plugincontroller.h +namespace +{ + template <class ComponentType> + ComponentType *loadDefaultPart( const QString &serviceType ) + { + KTrader::OfferList offers = KTrader::self()->query(serviceType, QString("[X-KDevelop-Version] == %1").arg(KDEVELOP_PLUGIN_VERSION)); + KTrader::OfferList::ConstIterator serviceIt = offers.begin(); + for ( ; serviceIt != offers.end(); ++serviceIt ) { + KService::Ptr service = *serviceIt; + + ComponentType *part = KParts::ComponentFactory + ::createInstanceFromService< ComponentType >( service, API::getInstance(), 0, + PluginController::argumentsFromService( service ) ); + + if ( part ) + return part; + } + return 0; + } +} + +PluginController *PluginController::s_instance = 0; + + +PluginController *PluginController::getInstance() +{ + if (!s_instance) + s_instance = new PluginController(); + return s_instance; +} + + +PluginController::PluginController() + : KDevPluginController() +{ +/* m_defaultProfile = QString::fromLatin1( "FullIDE" ); + m_defaultProfilePath = kapp->dirs()->localkdedir() + "/" + + KStandardDirs::kde_default( "data" ) + + QString::fromLatin1("/kdevelop/profiles/FullIDE");*/ + + KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); + if( args->isSet("profile") ){ + m_profile = QString::fromLocal8Bit( args->getOption("profile") ); + } else { + m_profile = ShellExtension::getInstance()->defaultProfile(); + } + +} + + +void PluginController::loadInitialPlugins() +{ + loadCorePlugins(); + + QStringList disableList; + Profile * profile = engine().findProfile( currentProfile() ); + if( profile ) + { + Profile::EntryList disableEntryList = profile->list( Profile::ExplicitDisable ); + for ( Profile::EntryList::const_iterator it = disableEntryList.constBegin(); it != disableEntryList.constEnd(); ++it ) + { + disableList << (*it).name; + } + } + loadGlobalPlugins( disableList ); +} + + +PluginController::~PluginController() +{ + unloadPlugins(); +} + +void PluginController::loadCorePlugins() +{ + KTrader::OfferList coreOffers = m_engine.offers(m_profile, ProfileEngine::Core); + loadPlugins( coreOffers ); +} + +void PluginController::loadGlobalPlugins( const QStringList & ignorePlugins ) +{ + KTrader::OfferList globalOffers = m_engine.offers(m_profile, ProfileEngine::Global); + loadPlugins( globalOffers, ignorePlugins ); +} + +void PluginController::loadProjectPlugins( const QStringList & ignorePlugins ) +{ + KTrader::OfferList projectOffers = m_engine.offers(m_profile, ProfileEngine::Project); + loadPlugins( projectOffers, ignorePlugins ); +} + +void PluginController::loadPlugins( KTrader::OfferList offers, const QStringList & ignorePlugins ) +{ + + TopLevel::getInstance()->main()->setFocus(); + for (KTrader::OfferList::ConstIterator it = offers.begin(); it != offers.end(); ++it) + { + QString name = (*it)->desktopEntryName(); + + // Check if it is already loaded or shouldn't be + if( m_parts[ name ] != 0 || ignorePlugins.contains( name ) ) + continue; + + emit loadingPlugin(i18n("Loading: %1").arg((*it)->genericName())); + + KDevPlugin *plugin = loadPlugin( *it ); + if ( plugin ) + { + m_parts.insert( name, plugin ); + integratePart( plugin ); + } + } +} + +void PluginController::unloadPlugins() +{ + for( QDictIterator<KDevPlugin> it( m_parts ); !it.isEmpty(); ) + { + KDevPlugin* part = it.current(); + removePart( part ); + m_parts.remove( it.currentKey() ); + delete part; + } +} + +void PluginController::unloadProjectPlugins( ) +{ + // this is nasty, but we need to unload the version control plugin too, and the + // right moment to do this is here + KTrader::OfferList offers = KTrader::self()->query("KDevelop/VersionControl", ""); + + offers += m_engine.offers(m_profile, ProfileEngine::Project); + for (KTrader::OfferList::ConstIterator it = offers.begin(); it != offers.end(); ++it) + { + QString name = (*it)->desktopEntryName(); + + if ( KDevPlugin * plugin = m_parts[ name ] ) + { + kdDebug(9000) << " *** Removing: " << name << endl; + removeAndForgetPart( name, plugin ); + delete plugin; + } + } +} + +void PluginController::unloadPlugins( QStringList const & unloadParts ) +{ + QStringList::ConstIterator it = unloadParts.begin(); + while ( it != unloadParts.end() ) + { + KDevPlugin* part = m_parts[ *it ]; + if( part ) + { + kdDebug(9000) << " *** Removing: " << *it << endl; + removePart( part ); + m_parts.remove( *it ); + delete part; + } + ++it; + } +} + +KDevPlugin *PluginController::loadPlugin( const KService::Ptr &service ) +{ + int err = 0; + KDevPlugin * pl = KParts::ComponentFactory + ::createInstanceFromService<KDevPlugin>( service, API::getInstance(), 0, + argumentsFromService( service ), &err ); + if (!pl) + { + KMessageBox::error( + 0, + i18n("<b>Could not load plugin</b><br>" + "Plugin %1 could not be loaded<br>" + "Library loader error: %2").arg(service->name()). + arg(KLibLoader::self()->lastErrorMessage()), + i18n("Could not load plugin")); + } +// kdDebug() << "ERR: " << err << endl; + return pl; +} + +QStringList PluginController::argumentsFromService( const KService::Ptr &service ) +{ + QStringList args; + if ( !service ) + // service is a reference to a pointer, so a check whether it is 0 is still required + return args; + QVariant prop = service->property( "X-KDevelop-Args" ); + if ( prop.isValid() ) + args = QStringList::split( " ", prop.toString() ); + return args; +} + +void PluginController::integratePart(KXMLGUIClient *part) +{ + if ( ! part ) return; + Core::setupShourtcutTips(part); + + TopLevel::getInstance()->main()->guiFactory()->addClient(part); + connect( part->actionCollection(), SIGNAL( actionStatusText( const QString & ) ), + TopLevel::getInstance()->main()->actionCollection(), SIGNAL( actionStatusText( const QString & ) ) ); +} + +void PluginController::integrateAndRememberPart(const QString &name, KDevPlugin *part) +{ + m_parts.insert(name, part); + integratePart(part); +} + +void PluginController::removePart(KXMLGUIClient *part) +{ + if (TopLevel::mainWindowValid()) // is 0 when window was already closed + TopLevel::getInstance()->main()->guiFactory()->removeClient(part); +} + +void PluginController::removeAndForgetPart(const QString &name, KDevPlugin *part) +{ + kdDebug() << "removing: " << name << endl; + m_parts.remove(name); + removePart(part); +} + +const QValueList<KDevPlugin*> PluginController::loadedPlugins() +{ + QValueList<KDevPlugin*> plugins; + QDictIterator<KDevPlugin> itt(m_parts); + while( itt.current() ) + { + plugins.append( itt.current() ); + ++itt; + } + return plugins; +} + +KDevPlugin * PluginController::extension( const QString & serviceType, const QString & constraint ) +{ + KTrader::OfferList offers = KDevPluginController::query(serviceType, constraint); + for (KTrader::OfferList::const_iterator it = offers.constBegin(); it != offers.end(); ++it) + { + KDevPlugin *ext = m_parts[(*it)->desktopEntryName()]; + if (ext) return ext; + } + return 0; +} + +KDevPlugin * PluginController::loadPlugin( const QString & serviceType, const QString & constraint ) +{ + KTrader::OfferList offers = KDevPluginController::query( serviceType, constraint ); + if ( !offers.size() == 1 ) return 0; + + KTrader::OfferList::const_iterator it = offers.constBegin(); + QString name = (*it)->desktopEntryName(); + + KDevPlugin * plugin = 0; + if ( plugin = m_parts[ name ] ) + { + return plugin; + } + + if ( plugin = loadPlugin( *it ) ) + { + m_parts.insert( name, plugin ); + integratePart( plugin ); + } + + return plugin; +} + +void PluginController::unloadPlugin( const QString & plugin ) +{ + QStringList pluginList; + pluginList << plugin; + unloadPlugins( pluginList ); +} + +KURL::List PluginController::profileResources(const QString &nameFilter) +{ + return m_engine.resources(currentProfile(), nameFilter); +} + +KURL::List PluginController::profileResourcesRecursive(const QString &nameFilter) +{ + return m_engine.resourcesRecursive(currentProfile(), nameFilter); +} + +QString PluginController::changeProfile(const QString &newProfile) +{ + kdDebug() << "CHANGING PROFILE: from " << currentProfile() << " to " << newProfile << endl; + QStringList unload; + KTrader::OfferList coreLoad; + KTrader::OfferList globalLoad; + m_engine.diffProfiles(ProfileEngine::Core, currentProfile(), newProfile, unload, coreLoad); + m_engine.diffProfiles(ProfileEngine::Global, currentProfile(), newProfile, unload, globalLoad); + + QString oldProfile = m_profile; + m_profile = newProfile; + + unloadPlugins(unload); + loadPlugins( coreLoad ); + loadPlugins( globalLoad ); + + return oldProfile; +} + +void PluginController::selectPlugins( ) +{ + kdDebug(9000) << k_funcinfo << endl; + + PluginSelectDialog dlg; + if ( dlg.exec() == QDialog::Accepted ) + { + QStringList unselectedPlugins = dlg.unselectedPluginNames(); + + kdDebug(9000) << unselectedPlugins << endl; + + unloadPlugins( unselectedPlugins ); + loadGlobalPlugins( unselectedPlugins ); + + if ( ProjectManager::getInstance()->projectLoaded() ) + { + loadProjectPlugins( unselectedPlugins ); + DomUtil::writeListEntry( *API::getInstance()->projectDom(), "/general/ignoreparts", "part", unselectedPlugins ); + } + } +} + +/* +KDevPlugin * PluginController::getPlugin( const KService::Ptr & service ) +{ + KDevPlugin * plugin = m_parts[ (*it)->name() ]; + if ( !plugin ) + { + KDevPlugin * plugin = loadPlugin( *it ); + if ( plugin ) + { + integratePart( plugin ); + m_parts.insert( (*it)->name(), plugin ); + } + } + return plugin; +} +*/ +#include "plugincontroller.moc" + diff --git a/src/plugincontroller.h b/src/plugincontroller.h new file mode 100644 index 00000000..9b526e3e --- /dev/null +++ b/src/plugincontroller.h @@ -0,0 +1,96 @@ +#ifndef __PLUGINCONTROLLER_H__ +#define __PLUGINCONTROLLER_H__ + +#include <qdict.h> +#include <qvaluelist.h> + +#include <kservice.h> + +#include <kdevplugincontroller.h> + +#include <profileengine.h> + +class KXMLGUIClient; +class KService; +class KDevPlugin; +class KDialogBase; +class ProjectInfo; + +/** +Plugin controller implementation. +Loads and unloads plugins. +*/ +class PluginController : public KDevPluginController +{ + Q_OBJECT + +public: + + ~PluginController(); + + static PluginController *getInstance(); + static QStringList argumentsFromService( const KService::Ptr &service ); + + + virtual KDevPlugin * loadPlugin( const QString & serviceType, const QString & constraint ); + virtual void unloadPlugin( const QString & plugin ); + + QString currentProfile() const { return m_profile; } + + void loadInitialPlugins(); + + void loadProjectPlugins( const QStringList & ignorePlugins ); + void unloadProjectPlugins(); + + void loadGlobalPlugins( const QStringList & ignorePlugins = QStringList() ); + + // KDevPlugin * getPlugin( const KService::Ptr &service ); + + virtual KDevPlugin *extension(const QString &serviceType, const QString &constraint = ""); + + void unloadPlugins( QStringList const & ); + + void integratePart(KXMLGUIClient *part); + void integrateAndRememberPart(const QString &name, KDevPlugin *part); + void removePart(KXMLGUIClient* part); + void removeAndForgetPart(const QString &name, KDevPlugin* part); + + const QValueList<KDevPlugin*> loadedPlugins(); + + ProfileEngine &engine() { return m_engine; } + + virtual KURL::List profileResources(const QString &nameFilter); + virtual KURL::List profileResourcesRecursive(const QString &nameFilter); + + //returns the name of an old profile that was unloaded + QString changeProfile(const QString &newProfile); + +public slots: + void selectPlugins(); + +signals: + void loadingPlugin(const QString &plugin); + +protected: + PluginController(); + +private slots: +// void slotConfigWidget( KDialogBase* ); + void loadCorePlugins(); + void loadPlugins( KTrader::OfferList offers, const QStringList & ignorePlugins = QStringList() ); + void unloadPlugins(); + +private: + static KDevPlugin *loadPlugin( const KService::Ptr &service ); + + + QDict<KDevPlugin> m_parts; + QString m_profile; + + static PluginController *s_instance; + + ProfileEngine m_engine; + +}; + +#endif diff --git a/src/pluginselectdialog.cpp b/src/pluginselectdialog.cpp new file mode 100644 index 00000000..de4a9e1e --- /dev/null +++ b/src/pluginselectdialog.cpp @@ -0,0 +1,181 @@ +/*************************************************************************** + * Copyright (C) 2006 by Jens Dagerbo * + * jens.dagerbo@swipnet.se * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <qlistview.h> +#include <qheader.h> +#include <qlabel.h> +#include <qregexp.h> + +#include <kdebug.h> +#include <kapplication.h> +#include <kurllabel.h> + +#include "kdevplugin.h" +#include "projectmanager.h" +#include "plugincontroller.h" +#include "pluginselectdialog.h" + +class PluginItem : public QCheckListItem +{ +public: + // name - "Name", label - "GenericName", info - "Comment" + PluginItem( QListView * parent, QString const & name, QString const & label, + QString const & info, QString const url = QString::null ) + : QCheckListItem( parent, label, QCheckListItem::CheckBox), + _name( name ), _info( info ), _url( url ) + {} + + QString info() { return _info; } + QString name() { return _name; } + QString url() { return _url; } + +private: + QString _name; + QString _info; + QString _url; +}; + + +PluginSelectDialog::PluginSelectDialog(QWidget* parent, const char* name, bool modal, WFlags fl ) + : PluginSelectDialogBase( parent,name, modal,fl ) +{ + plugin_list->setResizeMode( QListView::LastColumn ); + plugin_list->addColumn(""); + plugin_list->header()->hide(); + + connect( plugin_list, SIGNAL( selectionChanged( QListViewItem * ) ), this, SLOT( itemSelected( QListViewItem * ) ) ); + connect( urllabel, SIGNAL( leftClickedURL( const QString & ) ), this, SLOT( openURL( const QString & ) ) ); + + init(); +} + +PluginSelectDialog::~PluginSelectDialog() +{ +} + +void PluginSelectDialog::saveAsDefault() +{ + kdDebug(9000) << k_funcinfo << endl; + + ProfileEngine & engine = PluginController::getInstance()->engine(); + Profile * profile = engine.findProfile( PluginController::getInstance()->currentProfile() ); + + profile->clearList( Profile::ExplicitDisable ); + + QListViewItemIterator it( plugin_list ); + while ( it.current() ) + { + PluginItem * item = static_cast<PluginItem*>( it.current() ); + if ( !item->isOn() ) + { + profile->addEntry( Profile::ExplicitDisable, item->name() ); + } + ++it; + } + + profile->save(); +} + +void PluginSelectDialog::openURL( const QString & url ) +{ + kapp->invokeBrowser( url ); +} + +void PluginSelectDialog::itemSelected( QListViewItem * item ) +{ + if ( ! item ) return; + + PluginItem * pitem = static_cast<PluginItem*>( item ); + plugin_description_label->setText( pitem->info() ); + + if ( pitem->url().isEmpty() ) + { + urllabel->clear(); + } + else + { + urllabel->setURL( pitem->url() ); + urllabel->setText( pitem->url() ); + } +} + +void PluginSelectDialog::init( ) +{ + const QValueList<KDevPlugin*> loadedPlugins = PluginController::getInstance()->loadedPlugins(); + QStringList loadedPluginDesktopNames; + QValueList<KDevPlugin*>::ConstIterator it = loadedPlugins.begin(); + while( it != loadedPlugins.end() ) + { + loadedPluginDesktopNames << (*it)->instance()->instanceName(); + ++it; + } + + kdDebug(9000) << " *** loadedPluginDesktopNames: " << loadedPluginDesktopNames << endl; + + KTrader::OfferList localOffers; + if ( ProjectManager::getInstance()->projectLoaded() ) + { + localOffers = PluginController::getInstance()->engine().offers( + PluginController::getInstance()->currentProfile(), ProfileEngine::Project ); + } + + KTrader::OfferList globalOffers = PluginController::getInstance()->engine().offers( + PluginController::getInstance()->currentProfile(), ProfileEngine::Global); + + KTrader::OfferList offers = localOffers + globalOffers; + for (KTrader::OfferList::ConstIterator it = offers.begin(); it != offers.end(); ++it) + { + // parse out any existing url to make it clickable + QString Comment = (*it)->comment(); + QRegExp re("\\bhttp://[\\S]*"); + re.search( Comment ); + Comment.replace( re, "" ); + + QString url; + if ( re.pos() > -1 ) + { + url = re.cap(); + } + + PluginItem *item = new PluginItem( plugin_list, (*it)->desktopEntryName(), (*it)->genericName(), Comment, url ); + item->setOn( loadedPluginDesktopNames.contains( (*it)->desktopEntryName() ) ); + + kdDebug(9000) << (*it)->desktopEntryName() << " : " << (loadedPluginDesktopNames.contains( (*it)->desktopEntryName() ) ? "YES" : "NO" ) << endl; + } + + QListViewItem * first = plugin_list->firstChild(); + if ( first ) + { + plugin_list->setSelected( first, true ); + } +} + +QStringList PluginSelectDialog::unselectedPluginNames( ) +{ + QStringList unselectedPlugins; + QListViewItem * item = plugin_list->firstChild(); + while ( item ) + { + PluginItem * pluginItem = static_cast<PluginItem*>( item ); + if ( !pluginItem->isOn() ) + { + unselectedPlugins << pluginItem->name(); + } + item = item->nextSibling(); + } + return unselectedPlugins; +} + + + +#include "pluginselectdialog.moc" + +// kate: space-indent off; indent-width 4; tab-width 4; show-tabs off; diff --git a/src/pluginselectdialog.h b/src/pluginselectdialog.h new file mode 100644 index 00000000..5925ad7a --- /dev/null +++ b/src/pluginselectdialog.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2006 by Jens Dagerbo * + * jens.dagerbo@swipnet.se * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +#ifndef PLUGINSELECTDIALOG_H +#define PLUGINSELECTDIALOG_H + +#include "pluginselectdialogbase.h" + +class PluginController; + +class PluginSelectDialog : public PluginSelectDialogBase +{ + Q_OBJECT + +public: + PluginSelectDialog( QWidget* parent = 0, const char* name = 0, bool modal = FALSE, WFlags fl = 0 ); + ~PluginSelectDialog(); + + QStringList unselectedPluginNames(); + +private: + void init(); + +protected slots: + virtual void saveAsDefault(); + void itemSelected( QListViewItem * ); + void openURL( const QString & ); + +}; + +#endif + +// kate: space-indent off; indent-width 4; tab-width 4; show-tabs off; diff --git a/src/pluginselectdialogbase.ui b/src/pluginselectdialogbase.ui new file mode 100644 index 00000000..e976899a --- /dev/null +++ b/src/pluginselectdialogbase.ui @@ -0,0 +1,179 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>PluginSelectDialogBase</class> +<widget class="QDialog"> + <property name="name"> + <cstring>PluginSelectDialogBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>587</width> + <height>644</height> + </rect> + </property> + <property name="caption"> + <string>Plugin Selection</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string>Plugins:</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QListView"> + <property name="name"> + <cstring>plugin_list</cstring> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Make this the default for this profile:</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>saveAsDefault_button</cstring> + </property> + <property name="text"> + <string>Save &as Default</string> + </property> + <property name="toolTip" stdset="0"> + <string></string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox2</cstring> + </property> + <property name="title"> + <string>Description:</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>plugin_description_label</cstring> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>40</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter</set> + </property> + </widget> + <widget class="KURLLabel"> + <property name="name"> + <cstring>urllabel</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>191</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>ok_button</cstring> + </property> + <property name="text"> + <string>O&K</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>cancel_button</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>cancel_button</sender> + <signal>clicked()</signal> + <receiver>PluginSelectDialogBase</receiver> + <slot>reject()</slot> + </connection> + <connection> + <sender>ok_button</sender> + <signal>clicked()</signal> + <receiver>PluginSelectDialogBase</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>saveAsDefault_button</sender> + <signal>clicked()</signal> + <receiver>PluginSelectDialogBase</receiver> + <slot>saveAsDefault()</slot> + </connection> +</connections> +<slots> + <slot access="protected">saveAsDefault()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kurllabel.h</includehint> +</includehints> +</UI> diff --git a/src/profileengine/Makefile.am b/src/profileengine/Makefile.am new file mode 100644 index 00000000..3803a6dd --- /dev/null +++ b/src/profileengine/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = lib editor +DOXYGEN_EMPTY = YES +include ../../Doxyfile.am diff --git a/src/profileengine/editor/Makefile.am b/src/profileengine/editor/Makefile.am new file mode 100644 index 00000000..c83169cd --- /dev/null +++ b/src/profileengine/editor/Makefile.am @@ -0,0 +1,22 @@ +INCLUDES = -I$(top_srcdir)/lib -I$(top_srcdir)/lib/external_interfaces \ + -I$(top_srcdir)/lib/interfaces -I$(top_srcdir)/lib/util -I$(top_srcdir)/lib/widgets \ + -I$(top_srcdir)/src/profileengine/lib -I$(top_srcdir)/lib/structure $(all_includes) +METASOURCES = AUTO + +libprofileeditor_la_LDFLAGS = $(all_libraries) +libprofileeditor_la_LIBADD = $(top_builddir)/src/profileengine/lib/libprofileengine.la +noinst_LTLIBRARIES = libprofileeditor.la +libprofileeditor_COMPILE_FIRST = profileeditorbase.h +libprofileeditor_la_SOURCES = profileeditorbase.ui profileeditor.cpp \ + addprofilewidget.ui +noinst_HEADERS = profileeditor.h + + +bin_PROGRAMS = kdevprofileeditor +kdevprofileeditor_LDFLAGS = $(all_libraries) +kdevprofileeditor_LDADD = \ + $(top_builddir)/src/profileengine/lib/libprofileengine.la libprofileeditor.la \ + $(LIB_KDEUI) $(LIB_KIO) +kdevprofileeditor_SOURCES = main.cpp + + diff --git a/src/profileengine/editor/addprofilewidget.ui b/src/profileengine/editor/addprofilewidget.ui new file mode 100644 index 00000000..56a46f1d --- /dev/null +++ b/src/profileengine/editor/addprofilewidget.ui @@ -0,0 +1,121 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>AddProfileWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>AddProfileWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>312</width> + <height>192</height> + </rect> + </property> + <property name="caption"> + <string>Add Profile</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>&Name:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>nameEdit</cstring> + </property> + </widget> + <widget class="KLineEdit"> + <property name="name"> + <cstring>nameEdit</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>&Generic name:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>genericNameEdit</cstring> + </property> + </widget> + <widget class="KLineEdit"> + <property name="name"> + <cstring>genericNameEdit</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>&Description:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>descriptionEdit</cstring> + </property> + </widget> + <widget class="QTextEdit"> + <property name="name"> + <cstring>descriptionEdit</cstring> + </property> + </widget> + </vbox> + </widget> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/src/profileengine/editor/main.cpp b/src/profileengine/editor/main.cpp new file mode 100644 index 00000000..52e8d0f1 --- /dev/null +++ b/src/profileengine/editor/main.cpp @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <kapplication.h> +#include <kaboutdata.h> +#include <kcmdlineargs.h> + +#include "profileeditor.h" + +static KCmdLineOptions options[] = +{ + KCmdLineLastOption +}; + +int main(int argc, char **argv) +{ + KAboutData about("kdevprofileeditor", I18N_NOOP("KDevelop Profile Editor"), "1", "", + KAboutData::License_GPL, I18N_NOOP("(c) 2004, The KDevelop Developers"), 0, 0, ""); + about.addAuthor("Alexander Dymo", 0, "adymo@kdevelop.org"); + KCmdLineArgs::init(argc, argv, &about); + KCmdLineArgs::addCmdLineOptions(options); + + KApplication app(argc, argv); + ProfileEditor editor; + editor.show(); + app.setMainWidget(&editor); + + return app.exec(); +} diff --git a/src/profileengine/editor/profileeditor.cpp b/src/profileengine/editor/profileeditor.cpp new file mode 100644 index 00000000..0303793f --- /dev/null +++ b/src/profileengine/editor/profileeditor.cpp @@ -0,0 +1,400 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo <adymo@kdevelop.org> * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "profileeditor.h" + +#include <qlayout.h> +#include <klineedit.h> +#include <qtextedit.h> +#include <qpalette.h> + +#include <kdebug.h> +#include <kpushbutton.h> +#include <klistbox.h> +#include <klistview.h> +#include <kcombobox.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kdialogbase.h> +#include <kglobalsettings.h> +#include <kdeversion.h> + +#include <profile.h> + +#include "addprofilewidget.h" + +class ProfileItem: public KListViewItem { +public: + ProfileItem(KListView *parent, Profile *profile) + :KListViewItem(parent), m_profile(profile) + { + setText(0, profile->genericName()); + setText(1, profile->description()); + } + + ProfileItem(KListViewItem *parent, Profile *profile) + : KListViewItem(parent), m_profile(profile) + { + setText(0, profile->genericName()); + setText(1, profile->description()); + } + + Profile *profile() const { return m_profile; } + +private: + Profile *m_profile; +}; + +class EDListItem: public KListViewItem{ +public: + EDListItem(KListView *parent, const QString &text, bool derived) + : KListViewItem(parent, text), m_derived(derived) + { + } + + bool isDerived() const { return m_derived; } + + virtual void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment) + { + QColorGroup cgNew = cg; + if (m_derived) + cgNew.setColor(QColorGroup::Text, KGlobalSettings::inactiveTextColor()); + KListViewItem::paintCell(p, cgNew, column, width, alignment); + } + +private: + bool m_derived; +}; + + +class ProfileListBuilding { +public: + ProfileItem * operator() (ProfileItem *parent, Profile *profile) + { + parent->setOpen(true); + return new ProfileItem(parent, profile); + } +}; + + +ProfileEditor::ProfileEditor(QWidget *parent, const char *name) + :ProfileEditorBase(parent, name) +{ + refresh(); +} + +void ProfileEditor::refresh() +{ + profilesList->clear(); + + ProfileItem *item = new ProfileItem(profilesList, engine.rootProfile()); + ProfileListBuilding op; + engine.walkProfiles<ProfileListBuilding, ProfileItem>(op, item, engine.rootProfile()); + + profilesList->setSelected(item, true); + profilesList->setCurrentItem(item); + + refreshAvailableList(); + refreshPropertyCombo(); +} + +void ProfileEditor::refreshPropertyCombo() +{ + KTrader::OfferList list = KTrader::self()->query(QString::fromLatin1("KDevelop/Plugin")); + QStringList props; + for (KTrader::OfferList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it) + { + QStringList currProps = (*it)->property("X-KDevelop-Properties").toStringList(); + for (QStringList::const_iterator p = currProps.constBegin(); + p != currProps.constEnd(); ++p) + if (!props.contains(*p)) + props.append(*p); + } + props.sort(); + propertyCombo->insertStringList(props); + propertyCombo->setCurrentText(""); +} + +void ProfileEditor::refreshAvailableList() +{ + //filling a list of available plugins + allList->clear(); + allCore = new KListViewItem(allList, i18n("Core")); + allCore->setOpen(true); + allGlobal = new KListViewItem(allList, i18n("Global")); + allGlobal->setOpen(true); + allProject = new KListViewItem(allList, i18n("Project")); + allProject->setOpen(true); + + KTrader::OfferList olist = engine.allOffers(ProfileEngine::Core); + for (KTrader::OfferList::iterator it = olist.begin(); it != olist.end(); ++it) + new KListViewItem(allCore, (*it)->desktopEntryName(), (*it)->genericName()); + olist = engine.allOffers(ProfileEngine::Global); + for (KTrader::OfferList::iterator it = olist.begin(); it != olist.end(); ++it) + new KListViewItem(allGlobal, (*it)->desktopEntryName(), (*it)->genericName()); + olist = engine.allOffers(ProfileEngine::Project); + for (KTrader::OfferList::iterator it = olist.begin(); it != olist.end(); ++it) + new KListViewItem(allProject, (*it)->desktopEntryName(), (*it)->genericName()); +} + +void ProfileEditor::profileExecuted(QListViewItem *item) +{ + if (!item || item->text(0) == "KDevelop") + removeProfileButton->setEnabled(false); + else + removeProfileButton->setEnabled(true); + + fillPropertyList(currentProfile()); + fillEDLists(currentProfile()); + fillPluginsList(currentProfile()); +} + +void ProfileEditor::fillPropertyList(Profile *profile) +{ + derivedPropertiesBox->clear(); + ownPropertiesBox->clear(); + + Profile::EntryList list = profile->list(Profile::Properties); + for (Profile::EntryList::const_iterator it = list.begin(); it != list.end(); ++it) + { + if ((*it).derived) + derivedPropertiesBox->insertItem((*it).name); + else + ownPropertiesBox->insertItem((*it).name); + } +} + +void ProfileEditor::fillEDLists(Profile *profile) +{ + //filling a list of enabled plugins + enabledList->clear(); + Profile::EntryList list = profile->list(Profile::ExplicitEnable); + for (Profile::EntryList::const_iterator it = list.begin(); it != list.end(); ++it) + new EDListItem(enabledList, (*it).name, (*it).derived); + + //filling a list of disabled plugins + disabledList->clear(); + list = profile->list(Profile::ExplicitDisable); + for (Profile::EntryList::const_iterator it = list.begin(); it != list.end(); ++it) + new EDListItem(disabledList, (*it).name, (*it).derived); +} + +void ProfileEditor::fillPluginsList(Profile *profile) +{ + pluginsView->clear(); + + KListViewItem *core = new KListViewItem(pluginsView, i18n("Core Plugins")); + core->setOpen(true); + KListViewItem *global = new KListViewItem(pluginsView, i18n("Global Plugins")); + global->setOpen(true); + KListViewItem *project = new KListViewItem(pluginsView, i18n("Project Plugins")); + project->setOpen(true); + + KTrader::OfferList coreOffers = engine.offers(profile->name(), ProfileEngine::Core); + for (KTrader::OfferList::const_iterator it = coreOffers.constBegin(); + it != coreOffers.constEnd(); ++it) + new KListViewItem(core, (*it)->desktopEntryName(), (*it)->genericName(), + (*it)->property("X-KDevelop-Properties").toStringList().join(", ")); + + KTrader::OfferList globalOffers = engine.offers(profile->name(), ProfileEngine::Global); + for (KTrader::OfferList::const_iterator it = globalOffers.constBegin(); + it != globalOffers.constEnd(); ++it) + new KListViewItem(global, (*it)->desktopEntryName(), (*it)->genericName(), + (*it)->property("X-KDevelop-Properties").toStringList().join(", ")); + + KTrader::OfferList projectOffers = engine.offers(profile->name(), ProfileEngine::Project); + for (KTrader::OfferList::const_iterator it = projectOffers.constBegin(); + it != projectOffers.constEnd(); ++it) + new KListViewItem(project, (*it)->desktopEntryName(), (*it)->genericName(), + (*it)->property("X-KDevelop-Properties").toStringList().join(", ")); +} + +void ProfileEditor::propertyExecuted(QListBoxItem *item) +{ + removePropertyButton->setEnabled(item != 0); +} + +void ProfileEditor::addProfile() +{ + if (!profilesList->currentItem()) + return; + + KDialogBase dlg(KDialogBase::Plain, i18n("Add Profile"), KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok); + dlg.plainPage()->setMargin(0); + (new QVBoxLayout(dlg.plainPage(), 0, 0))->setAutoAdd(true); + AddProfileWidget *prof = new AddProfileWidget(dlg.plainPage()); + prof->nameEdit->setFocus(); + if (dlg.exec() == QDialog::Accepted) + { + Profile *profile = new Profile(currentProfile(), prof->nameEdit->text(), + prof->genericNameEdit->text(), + prof->descriptionEdit->text()); + profilesList->currentItem()->setOpen(true); + new ProfileItem(static_cast<KListViewItem*>(profilesList->currentItem()), profile); + } +} + +void ProfileEditor::removeProfile() +{ + if (KMessageBox::warningContinueCancel(this, i18n("Remove selected profile and all its subprofiles?"), + i18n("Remove Profile"),KStdGuiItem::del()) == KMessageBox::Continue) + { + Profile *profile = currentProfile(); + if (profile->remove()) + { + QListViewItem *item = profilesList->currentItem(); + profilesList->setCurrentItem(item->parent()); + profile->detachFromParent(); + delete profile; + delete item; + } + else + KMessageBox::error(this, i18n("Cannot remove this profile because it is not a local (user-created) profile."), i18n("Remove Profile")); + } +} + +void ProfileEditor::addProperty() +{ + if ( (!propertyCombo->currentText().isEmpty()) && + (ownPropertiesBox->findItem(propertyCombo->currentText()) == 0) && + (derivedPropertiesBox->findItem(propertyCombo->currentText()) == 0) ) + { + ownPropertiesBox->insertItem(propertyCombo->currentText()); + + currentProfile()->addEntry(Profile::Properties, propertyCombo->currentText()); + currentProfile()->save(); + } + + fillPluginsList(currentProfile()); +} + +void ProfileEditor::removeProperty() +{ + currentProfile()->removeEntry(Profile::Properties, ownPropertiesBox->currentText()); + currentProfile()->save(); + + ownPropertiesBox->removeItem(ownPropertiesBox->currentItem()); + + fillPluginsList(currentProfile()); +} + +Profile *ProfileEditor::currentProfile() +{ + ProfileItem *item = dynamic_cast<ProfileItem*>(profilesList->currentItem()); + if (!item) + return 0; + return item->profile(); +} + +void ProfileEditor::accept() +{ +} + +void ProfileEditor::addEnabled() +{ + if (!allList->currentItem() && allEdit->text().isEmpty()) + return; + QString text; + if (!allEdit->text().isEmpty()) + { + text = allEdit->text(); + allEdit->clear(); + } + else + { + if ((allList->currentItem() == allGlobal) || (allList->currentItem() == allProject)) + return; + text = allList->currentItem()->text(0); + } + + if (enabledList->findItem(text, 0) != 0) + return; + if (disabledList->findItem(text, 0) != 0) + { + KMessageBox::error(this, i18n("This plugin is already contained in the list of disabled plugins."), + i18n("Enable Plugin")); + return; + } + currentProfile()->addEntry(Profile::ExplicitEnable, text); + currentProfile()->save(); + fillPluginsList(currentProfile()); + new EDListItem(enabledList, text, false); +} + +void ProfileEditor::delEnabled() +{ + if (!enabledList->currentItem()) + return; + + EDListItem *item = dynamic_cast<EDListItem*>(enabledList->currentItem()); + if (item && !item->isDerived()) + { + currentProfile()->removeEntry(Profile::ExplicitEnable, enabledList->currentItem()->text(0)); + currentProfile()->save(); + fillPluginsList(currentProfile()); + delete enabledList->currentItem(); + } +} + +void ProfileEditor::addDisabled() +{ + if (!allList->currentItem() && allEdit->text().isEmpty()) + return; + QString text; + if (!allEdit->text().isEmpty()) + { + text = allEdit->text(); + allEdit->clear(); + } + else + { + if ((allList->currentItem() == allGlobal) || (allList->currentItem() == allProject)) + return; + text = allList->currentItem()->text(0); + } + + if (disabledList->findItem(text, 0) != 0) + return; + if (enabledList->findItem(text, 0) != 0) + { + KMessageBox::error(this, i18n("This plugin is already contained in the list of enabled plugins."), + i18n("Disable Plugin")); + return; + } + currentProfile()->addEntry(Profile::ExplicitDisable, text); + currentProfile()->save(); + fillPluginsList(currentProfile()); + new EDListItem(disabledList, text, false); +} + +void ProfileEditor::delDisabled() +{ + if (!disabledList->currentItem()) + return; + + EDListItem *item = dynamic_cast<EDListItem*>(disabledList->currentItem()); + if (item && !item->isDerived()) + { + currentProfile()->removeEntry(Profile::ExplicitDisable, disabledList->currentItem()->text(0)); + delete disabledList->currentItem(); + currentProfile()->save(); + fillPluginsList(currentProfile()); + } +} + +#include "profileeditor.moc" diff --git a/src/profileengine/editor/profileeditor.h b/src/profileengine/editor/profileeditor.h new file mode 100644 index 00000000..1ec6e91a --- /dev/null +++ b/src/profileengine/editor/profileeditor.h @@ -0,0 +1,69 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo <adymo@kdevelop.org> * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef PROFILEEDITOR_H +#define PROFILEEDITOR_H + +#include <profileengine.h> + +#include "profileeditorbase.h" + +class QListBoxItem; +class QListViewItem; +class KListViewItem; + +class ProfileEditor : public ProfileEditorBase { + Q_OBJECT +public: + ProfileEditor(QWidget *parent = 0, const char *name = 0); + +public slots: + virtual void removeProperty(); + virtual void addProperty(); + virtual void removeProfile(); + virtual void addProfile(); + virtual void propertyExecuted(QListBoxItem *item); + virtual void profileExecuted(QListViewItem *item); + + virtual void delDisabled(); + virtual void addDisabled(); + virtual void delEnabled(); + virtual void addEnabled(); + + virtual void accept(); + +protected: + void refresh(); + void refreshPropertyCombo(); + void refreshAvailableList(); + + void fillPropertyList(Profile *profile); + void fillEDLists(Profile *profile); + void fillPluginsList(Profile *profile); + + Profile *currentProfile(); + +private: + ProfileEngine engine; + + KListViewItem *allCore; + KListViewItem *allGlobal; + KListViewItem *allProject; +}; + +#endif diff --git a/src/profileengine/editor/profileeditorbase.ui b/src/profileengine/editor/profileeditorbase.ui new file mode 100644 index 00000000..e91fd13d --- /dev/null +++ b/src/profileengine/editor/profileeditorbase.ui @@ -0,0 +1,680 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>ProfileEditorBase</class> +<widget class="QWidget"> + <property name="name"> + <cstring>ProfileEditorBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>637</width> + <height>476</height> + </rect> + </property> + <property name="caption"> + <string>Profile Editor for The KDevelop Platform</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QSplitter" row="0" column="0"> + <property name="name"> + <cstring>splitter2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <widget class="QWidgetStack"> + <property name="name"> + <cstring>widgetStack1</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>WStackPage</cstring> + </property> + <attribute name="id"> + <number>0</number> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout11</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KPushButton" row="0" column="1"> + <property name="name"> + <cstring>addProfileButton</cstring> + </property> + <property name="text"> + <string>Add Profile</string> + </property> + </widget> + <spacer row="2" column="1"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>142</height> + </size> + </property> + </spacer> + <widget class="KListView" row="0" column="0" rowspan="3" colspan="1"> + <column> + <property name="text"> + <string>Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Description</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>profilesList</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="resizeMode"> + <enum>NoColumn</enum> + </property> + </widget> + <widget class="KPushButton" row="1" column="1"> + <property name="name"> + <cstring>removeProfileButton</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Remove Profile</string> + </property> + </widget> + </grid> + </widget> + </vbox> + </widget> + </widget> + <widget class="QTabWidget"> + <property name="name"> + <cstring>tabWidget2</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Properties</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KPushButton" row="1" column="2"> + <property name="name"> + <cstring>addPropertyButton</cstring> + </property> + <property name="text"> + <string>Add</string> + </property> + </widget> + <widget class="KComboBox" row="1" column="1"> + <property name="name"> + <cstring>propertyCombo</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="editable"> + <bool>true</bool> + </property> + <property name="autoCompletion"> + <bool>true</bool> + </property> + </widget> + <widget class="KPushButton" row="1" column="3"> + <property name="name"> + <cstring>removePropertyButton</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Remove</string> + </property> + </widget> + <widget class="QLayoutWidget" row="0" column="0" rowspan="2" colspan="1"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Derived properties:</string> + </property> + </widget> + <widget class="KListBox"> + <property name="name"> + <cstring>derivedPropertiesBox</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget" row="0" column="1" rowspan="1" colspan="3"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>Own properties:</string> + </property> + </widget> + <widget class="KListBox"> + <property name="name"> + <cstring>ownPropertiesBox</cstring> + </property> + </widget> + </vbox> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Lists of Explicitly Enabled && Disabled Plugins</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="0" column="2" rowspan="4" colspan="1"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Enabled:</string> + </property> + </widget> + <widget class="KListView"> + <column> + <property name="text"> + <string>Plugin Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>enabledList</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget" row="4" column="2" rowspan="4" colspan="1"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2_2</cstring> + </property> + <property name="text"> + <string>Disabled:</string> + </property> + </widget> + <widget class="KListView"> + <column> + <property name="text"> + <string>Plugin Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>disabledList</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="KPushButton" row="2" column="1"> + <property name="name"> + <cstring>delEnabledButton</cstring> + </property> + <property name="text"> + <string><-</string> + </property> + </widget> + <spacer row="3" column="1"> + <property name="name"> + <cstring>spacer2_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <spacer row="4" column="1"> + <property name="name"> + <cstring>spacer2_3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="KPushButton" row="6" column="1"> + <property name="name"> + <cstring>delDisabledButton</cstring> + </property> + <property name="text"> + <string><-</string> + </property> + </widget> + <spacer row="7" column="1"> + <property name="name"> + <cstring>spacer2_4</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget" row="0" column="0" rowspan="8" colspan="1"> + <property name="name"> + <cstring>layout10</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2_3</cstring> + </property> + <property name="text"> + <string>Available plugins:</string> + </property> + </widget> + <widget class="KListView"> + <column> + <property name="text"> + <string>Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Generic Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>allList</cstring> + </property> + </widget> + <widget class="KLineEdit"> + <property name="name"> + <cstring>allEdit</cstring> + </property> + </widget> + </vbox> + </widget> + <spacer row="0" column="1"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="KPushButton" row="1" column="1"> + <property name="name"> + <cstring>addEnabledButton</cstring> + </property> + <property name="text"> + <string>-></string> + </property> + </widget> + <widget class="KPushButton" row="5" column="1"> + <property name="name"> + <cstring>addDisabledButton</cstring> + </property> + <property name="text"> + <string>-></string> + </property> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>TabPage</cstring> + </property> + <attribute name="title"> + <string>List of Plugins to Be Loaded</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KListView" row="0" column="0"> + <column> + <property name="text"> + <string>Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Generic Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Properties</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>pluginsView</cstring> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + </widget> + </grid> + </widget> + </widget> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>profilesList</sender> + <signal>currentChanged(QListViewItem*)</signal> + <receiver>ProfileEditorBase</receiver> + <slot>profileExecuted(QListViewItem*)</slot> + </connection> + <connection> + <sender>ownPropertiesBox</sender> + <signal>currentChanged(QListBoxItem*)</signal> + <receiver>ProfileEditorBase</receiver> + <slot>propertyExecuted(QListBoxItem*)</slot> + </connection> + <connection> + <sender>addProfileButton</sender> + <signal>clicked()</signal> + <receiver>ProfileEditorBase</receiver> + <slot>addProfile()</slot> + </connection> + <connection> + <sender>removeProfileButton</sender> + <signal>clicked()</signal> + <receiver>ProfileEditorBase</receiver> + <slot>removeProfile()</slot> + </connection> + <connection> + <sender>addPropertyButton</sender> + <signal>clicked()</signal> + <receiver>ProfileEditorBase</receiver> + <slot>addProperty()</slot> + </connection> + <connection> + <sender>removePropertyButton</sender> + <signal>clicked()</signal> + <receiver>ProfileEditorBase</receiver> + <slot>removeProperty()</slot> + </connection> + <connection> + <sender>profilesList</sender> + <signal>executed(QListViewItem*)</signal> + <receiver>ProfileEditorBase</receiver> + <slot>profileExecuted(QListViewItem*)</slot> + </connection> + <connection> + <sender>profilesList</sender> + <signal>selectionChanged(QListViewItem*)</signal> + <receiver>ProfileEditorBase</receiver> + <slot>profileExecuted(QListViewItem*)</slot> + </connection> + <connection> + <sender>addEnabledButton</sender> + <signal>clicked()</signal> + <receiver>ProfileEditorBase</receiver> + <slot>addEnabled()</slot> + </connection> + <connection> + <sender>delEnabledButton</sender> + <signal>clicked()</signal> + <receiver>ProfileEditorBase</receiver> + <slot>delEnabled()</slot> + </connection> + <connection> + <sender>addDisabledButton</sender> + <signal>clicked()</signal> + <receiver>ProfileEditorBase</receiver> + <slot>addDisabled()</slot> + </connection> + <connection> + <sender>delDisabledButton</sender> + <signal>clicked()</signal> + <receiver>ProfileEditorBase</receiver> + <slot>delDisabled()</slot> + </connection> +</connections> +<tabstops> + <tabstop>profilesList</tabstop> + <tabstop>addProfileButton</tabstop> + <tabstop>removeProfileButton</tabstop> + <tabstop>tabWidget2</tabstop> + <tabstop>derivedPropertiesBox</tabstop> + <tabstop>ownPropertiesBox</tabstop> + <tabstop>propertyCombo</tabstop> + <tabstop>addPropertyButton</tabstop> + <tabstop>removePropertyButton</tabstop> + <tabstop>enabledList</tabstop> + <tabstop>disabledList</tabstop> + <tabstop>pluginsView</tabstop> +</tabstops> +<slots> + <slot>profileExecuted(QListViewItem *item)</slot> + <slot>propertyExecuted(QListBoxItem *item)</slot> + <slot>addProfile()</slot> + <slot>removeProfile()</slot> + <slot>addProperty()</slot> + <slot>removeProperty()</slot> + <slot>addEnabled()</slot> + <slot>delEnabled()</slot> + <slot>addDisabled()</slot> + <slot>delDisabled()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kpushbutton.h</includehint> + <includehint>klistview.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>klistbox.h</includehint> + <includehint>klistbox.h</includehint> + <includehint>klistview.h</includehint> + <includehint>klistview.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>klistview.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>klistview.h</includehint> +</includehints> +</UI> diff --git a/src/profileengine/lib/Mainpage.dox b/src/profileengine/lib/Mainpage.dox new file mode 100644 index 00000000..72d14aa5 --- /dev/null +++ b/src/profileengine/lib/Mainpage.dox @@ -0,0 +1,10 @@ +/** +@mainpage The KDevelop Shell Profiles Library + +This library contains plugin profiles engine for KDevelop shell. + +<b>Link with</b>: -lprofileengine + +<b>Include path</b>: -I\$(kde_includes)/kdevelop/shell/profileengine +*/ + diff --git a/src/profileengine/lib/Makefile.am b/src/profileengine/lib/Makefile.am new file mode 100644 index 00000000..50d17ed5 --- /dev/null +++ b/src/profileengine/lib/Makefile.am @@ -0,0 +1,16 @@ +INCLUDES = -I$(top_srcdir)/lib -I$(top_srcdir)/lib/external_interfaces \ + -I$(top_srcdir)/lib/interfaces -I$(top_srcdir)/lib/util -I$(top_srcdir)/lib/widgets \ + -I$(top_srcdir)/lib/structure $(all_includes) +METASOURCES = AUTO +lib_LTLIBRARIES = libprofileengine.la +libprofileengine_la_LDFLAGS = $(all_libraries) +libprofileengine_la_LIBADD = $(LIB_QT) $(LIB_KDECORE) $(LIB_KIO) +libprofileengine_la_SOURCES = profileengine.cpp profile.cpp + +profileincludedir = $(includedir)/kdevelop/shell/profileengine +profileinclude_HEADERS = profileengine.h profile.h + +DOXYGEN_REFERENCES = dcop interfaces kdecore kdefx kdeui khtml kmdi kio kjs kparts kutils kdevutil kdevinterfaces +DOXYGEN_PROJECTNAME = KDevelop Shell Profiles Library +DOXYGEN_DOCDIRPREFIX = kdevprofiles +include ../../../Doxyfile.am diff --git a/src/profileengine/lib/profile.cpp b/src/profileengine/lib/profile.cpp new file mode 100644 index 00000000..e13b623e --- /dev/null +++ b/src/profileengine/lib/profile.cpp @@ -0,0 +1,205 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo <adymo@kdevelop.org> * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "profile.h" + +#include <qdir.h> +#include <qfileinfo.h> + +#include <kdebug.h> +#include <kstandarddirs.h> +#include <kconfig.h> +#include <kio/netaccess.h> + +Profile::Profile(Profile *parent, const QString &name) + :m_parent(parent), m_name(name) +{ + if (m_parent) + m_parent->addChildProfile(this); + + QString profileConfig = locate("data", "kdevelop/profiles" + dirName() + "/profile.config"); + KConfig config(profileConfig); + + config.setGroup("Information"); + m_genericName = config.readEntry("GenericName"); + m_description = config.readEntry("Description"); + + config.setGroup("Properties"); + m_properties = config.readListEntry("List"); + + config.setGroup("Enable"); + m_explicitEnable = config.readListEntry("List"); + + config.setGroup("Disable"); + m_explicitDisable = config.readListEntry("List"); +} + +Profile::Profile(Profile *parent, const QString &name, const QString &genericName, const QString &description) + :m_parent(parent), m_name(name), m_genericName(genericName), m_description(description) +{ + if (m_parent) + m_parent->addChildProfile(this); + save(); +} + +Profile::~Profile() +{ + for (QValueList<Profile*>::iterator it = m_children.begin(); it != m_children.end(); ++it) + delete *it; +} + +void Profile::addChildProfile(Profile *profile) +{ + m_children.append(profile); +} + +void Profile::removeChildProfile(Profile *profile) +{ + m_children.remove(profile); +} + +QString Profile::dirName() const +{ + if (m_parent) + return m_parent->dirName() + "/" + m_name; + else + return "/"/* + m_name*/; +} + +void Profile::save() +{ + QString profileConfig = locateLocal("data", "kdevelop/profiles" + dirName() + "/profile.config"); + KConfig config(profileConfig); + + config.setGroup("Information"); + config.writeEntry("GenericName", m_genericName); + config.writeEntry("Description", m_description); + + config.setGroup("Properties"); + config.writeEntry("List", m_properties); + + config.setGroup("Enable"); + config.writeEntry("List", m_explicitEnable); + + config.setGroup("Disable"); + config.writeEntry("List", m_explicitDisable); + + config.sync(); +} + +Profile::EntryList Profile::list(List type) +{ + EntryList parentList; + if (m_parent) + parentList = m_parent->list(type); + EntryList list = parentList; + for (EntryList::iterator it = list.begin(); it != list.end(); ++it) + (*it).derived = true; + QStringList &personalList = listByType(type); + for (QStringList::const_iterator it = personalList.begin(); it != personalList.end(); ++it) + list.append(Entry(*it, false)); + return list; +} + +void Profile::addEntry(List type, const QString &value) +{ + QStringList &list = listByType(type); + if (!list.contains(value)) + list.append(value); +} + +void Profile::removeEntry(List type, const QString &value) +{ + QStringList &list = listByType(type); + list.remove(value); +} + +void Profile::clearList( List type ) +{ + switch (type) + { + case Properties: + m_properties.clear(); + case ExplicitEnable: + m_explicitEnable.clear(); + case ExplicitDisable: + m_explicitDisable.clear(); + } +} + +QStringList &Profile::listByType(List type) +{ + switch (type) { + case Properties: + return m_properties; + case ExplicitEnable: + return m_explicitEnable; + case ExplicitDisable: + default: + return m_explicitDisable; + } +} + +bool Profile::hasInEntryList(EntryList &list, QString value) +{ + for (EntryList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it) + if ((*it).name == value) + return true; + return false; +} + +bool Profile::remove() +{ + QStringList dirs = KGlobal::dirs()->findDirs("data", "kdevelop/profiles" + dirName()); + if ((dirs.count() == 1) && dirs[0].startsWith(QDir::homeDirPath())) + return KIO::NetAccess::del(KURL::fromPathOrURL(dirs[0]), 0); + return false; +} + +void Profile::detachFromParent() +{ + if (m_parent) + m_parent->removeChildProfile(this); +} + +KURL::List Profile::resources(const QString &nameFilter) +{ + QStringList resources; + QStringList resourceDirs = KGlobal::dirs()->resourceDirs("data"); + for (QStringList::const_iterator it = resourceDirs.begin(); it != resourceDirs.end(); ++it) + { + QString dir = *it; + dir = dir + "kdevelop/profiles" + dirName(); + + QDir d(dir); + const QFileInfoList *infoList = d.entryInfoList(nameFilter, QDir::Files); + if (!infoList) + continue; + for (QFileInfoList::const_iterator infoIt = infoList->constBegin(); + infoIt != infoList->constEnd(); ++ infoIt) + resources.append((*infoIt)->absFilePath()); + } + + return KURL::List(resources); +} + +void Profile::addResource(const KURL &url) +{ + QString saveLocation = KGlobal::dirs()->saveLocation("data", "kdevelop/profiles"+dirName(), true); + KIO::NetAccess::file_copy(url, KURL::fromPathOrURL(saveLocation), -1, true); +} diff --git a/src/profileengine/lib/profile.h b/src/profileengine/lib/profile.h new file mode 100644 index 00000000..3f6d495a --- /dev/null +++ b/src/profileengine/lib/profile.h @@ -0,0 +1,96 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo <adymo@kdevelop.org> * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef PROFILE_H +#define PROFILE_H + +#include <kurl.h> +#include <qstringlist.h> + +/** +@short KDevelop profile + +A class which represents a profile for KDevelop platform stored on disk. +*/ +class Profile { +public: + /**An entry in the lists that store profile information*/ + struct Entry { + Entry() {} + Entry(const QString &_name, bool _derived): name(_name), derived(_derived) {} + QString name; + bool derived; + }; + typedef QValueList<Entry> EntryList; + + /**Lists which are held by a profile.*/ + enum List { + Properties /**<X-KDevelop-Properties defined for this profile.*/, + ExplicitEnable /**<A list of explicitly enabled plugins (names).*/, + ExplicitDisable /**<A list of explicitly disabled plugins (names).*/ + }; + + Profile(Profile *parent, const QString &name); + Profile(Profile *parent, const QString &name, const QString &genericName, const QString &description); + ~Profile(); + + QValueList<Profile*> children() const { return m_children; } + Profile *parent() const { return m_parent; } + + void save(); + bool remove(); + + QString name() const { return m_name; } + QString genericName() const { return m_genericName; } + QString description() const { return m_description; } + + EntryList list(List type); + + void addEntry(List type, const QString &value); + void removeEntry(List type, const QString &value); + void clearList(List type); + + bool hasInEntryList(EntryList &list, QString value); + + KURL::List resources(const QString &nameFilter); + void addResource(const KURL &url); + + void detachFromParent(); + +protected: + void addChildProfile(Profile *profile); + void removeChildProfile(Profile *profile); + QString dirName() const; + + QStringList &listByType(List type); + +private: + Profile *m_parent; + QValueList<Profile*> m_children; + + QString m_name; + + QString m_genericName; + QString m_description; + + QStringList m_properties; + QStringList m_explicitEnable; + QStringList m_explicitDisable; +}; + +#endif diff --git a/src/profileengine/lib/profileengine.cpp b/src/profileengine/lib/profileengine.cpp new file mode 100644 index 00000000..a46fa766 --- /dev/null +++ b/src/profileengine/lib/profileengine.cpp @@ -0,0 +1,264 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo <adymo@kdevelop.org> * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "profileengine.h" + +#include <qdir.h> + +#include <kurl.h> +#include <kdebug.h> +#include <kglobal.h> +#include <kstandarddirs.h> + +#include <kdevplugin.h> + +ProfileEngine::ProfileEngine() +{ + QStringList dirs = KGlobal::dirs()->findDirs("data", "kdevelop/profiles"); + + m_rootProfile = new Profile(0, "KDevelop"); + + QString currPath = "/"; + QMap<QString, Profile*> passedPaths; + + for (QStringList::const_iterator it = dirs.constBegin(); it != dirs.constEnd(); ++it) + processDir(*it, currPath, passedPaths, m_rootProfile); +} + +ProfileEngine::~ProfileEngine() +{ + delete m_rootProfile; +} + +void ProfileEngine::processDir(const QString &dir, const QString &currPath, QMap<QString, Profile*> &passedPaths, Profile *root) +{ +// kdDebug() << "processDir: " << dir << " " << currPath << endl; + + QDir qDir(dir); + QStringList entryList = qDir.entryList(QDir::Dirs); + for (QStringList::const_iterator eit = entryList.constBegin(); eit != entryList.constEnd(); ++eit) + { + if ((*eit != "..") && (*eit != ".")) + { + QString dirName = *eit; + Profile *profile = 0; + if (passedPaths.contains(currPath + dirName)) + profile = passedPaths[currPath + dirName]; + else + { + profile = new Profile(root, dirName); + passedPaths[currPath + dirName] = profile; + } + processDir(dir + *eit + "/", currPath + dirName, passedPaths, profile); + } + } +} + +KTrader::OfferList ProfileEngine::offers(const QString &profileName, OfferType offerType) +{ + ProfileListing listing; + Profile *profile = 0; + getProfileWithListing(listing, &profile, profileName); + + if (!profile) + return KTrader::OfferList(); + + QString constraint = QString::fromLatin1("[X-KDevelop-Version] == %1").arg(KDEVELOP_PLUGIN_VERSION); + switch (offerType) { + case Global: + constraint += QString::fromLatin1(" and [X-KDevelop-Scope] == 'Global'"); + break; + case Project: + constraint += QString::fromLatin1(" and [X-KDevelop-Scope] == 'Project'"); + break; + case Core: + constraint += QString::fromLatin1(" and [X-KDevelop-Scope] == 'Core'"); + break; + } + QString constraint_add = ""; + Profile::EntryList properties = profile->list(Profile::Properties); + int i = 0; + for (Profile::EntryList::const_iterator it = properties.begin(); it != properties.end(); ++it) + constraint_add += QString::fromLatin1(" %1 '%2' in [X-KDevelop-Properties]"). + arg((i++)==0?"":"or").arg((*it).name); + if (!constraint_add.isEmpty()) + constraint += " and ( " + constraint_add + " ) "; + +//BEGIN debug +/* kdDebug(9000) << "=============" << endl + << " =============" << endl + << " ============= Query for Profile:" << endl + << " " << constraint << endl << endl << endl;*/ +//END debug + + KTrader::OfferList list = KTrader::self()->query(QString::fromLatin1("KDevelop/Plugin"), constraint); + QStringList names; + +/* Wrong, this is not what we want to do. + Profile::EntryList disableList = profile->list(Profile::ExplicitDisable); + KTrader::OfferList::iterator it = list.begin(); + while (it != list.end()) + { + QString name = (*it)->desktopEntryName(); + names.append(name); + if (profile->hasInEntryList(disableList, name)) + { + it = list.remove(it); + continue; + } + ++it; + } +*/ + Profile::EntryList enableList = profile->list(Profile::ExplicitEnable); + for (Profile::EntryList::const_iterator it = enableList.begin(); it != enableList.end(); ++it) + { + if (names.contains((*it).name)) + continue; + QString constraint = QString::fromLatin1("[X-KDevelop-Version] == %1").arg(KDEVELOP_PLUGIN_VERSION); + constraint += QString::fromLatin1("and [Name] == '%1'").arg((*it).name); + KTrader::OfferList enable = KTrader::self()->query(QString::fromLatin1("KDevelop/Plugin"), constraint); + list += enable; + } + +/*//BEGIN debug + kdDebug() << "=============" << endl + << " =============" << endl + << " ============= Plugins for Profile:" << endl; + for (KTrader::OfferList::const_iterator it = list.begin(); it != list.end(); ++it) + kdDebug() << " " << (*it)->name() << endl; + kdDebug() << endl << endl; +//END debug*/ + + return list; +} + +KTrader::OfferList ProfileEngine::allOffers(OfferType offerType) +{ + QString constraint = QString::fromLatin1("[X-KDevelop-Version] == %1").arg(KDEVELOP_PLUGIN_VERSION); + switch (offerType) { + case Global: + constraint += QString::fromLatin1(" and [X-KDevelop-Scope] == 'Global'"); + break; + case Project: + constraint += QString::fromLatin1(" and [X-KDevelop-Scope] == 'Project'"); + break; + case Core: + constraint += QString::fromLatin1(" and [X-KDevelop-Scope] == 'Core'"); + break; + } + return KTrader::self()->query(QString::fromLatin1("KDevelop/Plugin"), constraint); +} + +void ProfileEngine::getProfileWithListing(ProfileListing &listing, Profile **profile, + const QString &profileName) +{ + if (profileName == "KDevelop") + *profile = m_rootProfile; + else + { + walkProfiles<ProfileListing>(listing, m_rootProfile); + *profile = listing.profiles[profileName]; + } +} + +KURL::List ProfileEngine::resources(const QString &profileName, const QString &nameFilter) +{ + ProfileListing listing; + Profile *profile = 0; + getProfileWithListing(listing, &profile, profileName); + + if (!profile) + return KURL::List(); + + return resources(profile, nameFilter); +} + +KURL::List ProfileEngine::resources(Profile *profile, const QString &nameFilter) +{ + return profile->resources(nameFilter); +} + +KURL::List ProfileEngine::resourcesRecursive(const QString &profileName, const QString &nameFilter) +{ + ProfileListing listing; + Profile *profile = 0; + getProfileWithListing(listing, &profile, profileName); + KURL::List resources = profile->resources(nameFilter); + + ProfileListingEx listingEx(nameFilter); + walkProfiles<ProfileListingEx>(listingEx, profile); + + resources += listingEx.resourceList; + return resources; +} + +void ProfileEngine::diffProfiles(OfferType offerType, const QString &profile1, + const QString &profile2, QStringList &unload, KTrader::OfferList &load) +{ + KTrader::OfferList offers1 = offers(profile1, offerType); + KTrader::OfferList offers2 = offers(profile2, offerType); + + QStringList offers1List; + for (KTrader::OfferList::const_iterator it = offers1.constBegin(); + it != offers1.constEnd(); ++it) + offers1List.append((*it)->desktopEntryName()); + QMap<QString, KService::Ptr> offers2List; + for (KTrader::OfferList::const_iterator it = offers2.constBegin(); + it != offers2.constEnd(); ++it) + offers2List[(*it)->desktopEntryName()] = *it; + +// kdDebug() << "OLD PROFILE: " << offers1List << endl; +// kdDebug() << "NEW PROFILE: " << offers2List << endl; + + for (QStringList::const_iterator it = offers1List.constBegin(); + it != offers1List.constEnd(); ++it) + { +// kdDebug() << "checking: " << *it << endl; + if (offers2List.contains(*it)) + { +// kdDebug() << " keep" << endl; + offers2.remove(offers2List[*it]); + } + else + { +// kdDebug() << " unload" << endl; + unload.append(*it); + } + } + load = offers2; +} + +Profile *ProfileEngine::findProfile(const QString & profileName) +{ + Profile *profile; + ProfileListing listing; + getProfileWithListing(listing, &profile, profileName); + return profile; +} + +void ProfileEngine::addResource(const QString &profileName, const KURL &url) +{ + ProfileListing listing; + Profile *profile = 0; + getProfileWithListing(listing, &profile, profileName); + + if (!profile) + return; + + profile->addResource(url); +} diff --git a/src/profileengine/lib/profileengine.h b/src/profileengine/lib/profileengine.h new file mode 100644 index 00000000..7a9a9abf --- /dev/null +++ b/src/profileengine/lib/profileengine.h @@ -0,0 +1,272 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo <adymo@kdevelop.org> * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef PROFILEENGINE_H +#define PROFILEENGINE_H + +#include <qmap.h> + +#include <ktrader.h> + +#include "profile.h" + +/** +Profile listing operation. +Used to get a plain list of profiles +and store it in the QMap<QString, Profile*>. +*/ +class ProfileListing{ +public: + void operator() (Profile *profile) + { + profiles[profile->name()] = profile; + } + + QMap<QString, Profile*> profiles; +}; + +/**Profile resource listing operation. +Used to get a list of urls to the profile resources. + +Resource urls can be filtered by an @p filter parameter +passed to the constructor. Filter can have values +as described in @ref QDir::setNameFilter function documentation.*/ +class ProfileListingEx { +public: + ProfileListingEx(const QString &filter): m_filter(filter) {} + void operator() (Profile *profile) + { + resourceList += profile->resources(m_filter); + } + + KURL::List resourceList; + QString m_filter; +}; + +/** +Profile engine. + +- Uses KDevelop profiles to form lists of plugin offers; +- Provides means of managing profiles; +- Provides means to access the resources provided by a profile. + +KDevelop profiles form a tree with a root profile named "KDevelop". +For example, such profiles tree can look as: +@code +KDevelop +- IDE + - CompiledLanguageIDE + - AdaIDE + - CandCppIDE + - CIDE + - CppIDE + - KDECppIDE + - FortranIDE + ... + - DatabaseIDE + - ScriptingLanguageIDE + .. +- KDevAssistant +@endcode +To manage a tree of profiles, use @ref ProfileEngine::walkProfiles methods. +*/ +class ProfileEngine { +public: + ProfileEngine(); + ~ProfileEngine(); + + /**Type of the plugin offer. Engine will usually find profiles and return offers + of selected type. + @sa KDevPlugin class documentation for more information of plugin types.*/ + enum OfferType { + Global /**<Global plugins.*/, + Project /**<Project plugins.*/, + Core /**<Core plugins.*/ + }; + + /**@return The list of plugin offers for given profile and type.*/ + KTrader::OfferList offers(const QString &profileName, OfferType offerType); + /**@return The list of all plugin offers for given type.*/ + KTrader::OfferList allOffers(OfferType offerType); + + /**@return The list of URLs to the resources (files) with given @p extension. + @param profileName A name of a profile to find resources in. + @param nameFilter Name filter for files. @see QDir::setNameFilter documentation + for name filters syntax.*/ + KURL::List resources(const QString &profileName, const QString &nameFilter); + + /**@return The list of URLs to the resources (files) with given @p extension. + This list is obtained by a recursive search that process given profile + and all it's subprofiles. + @param profileName A name of a profile to find resources in. + @param nameFilter Name filter for files. @see QDir::setNameFilter documentation + for name filters syntax.*/ + KURL::List resourcesRecursive(const QString &profileName, const QString &nameFilter); + + /**Adds a resource for the profile. Resource will be copied to the user profile directory + (like $HOME/.kde/share/apps/kdevelop/profiles/...). + @param profileName A name of the profile. + @param url The url to a file to copy as a profile resource.*/ + void addResource(const QString &profileName, const KURL &url); + + /**Gets the difference between @p profile1 and @p profile2. + Difference is calculated as two lists of plugins to be unloaded and loaded + in order to switch from @p profile1 to @p profile2. + @param offerType A type of plugin offers to list. + @param profile1 A name of the first profile. + @param profile2 A name of the second profile. + @param unload Will be filled with a list of plugins to unload. + @param load Will be filled with a list of plugins to load. + @note Resulting lists are not cleared. Pass only clean lists in the + common case.*/ + void diffProfiles(OfferType offerType, const QString &profile1, const QString &profile2, + QStringList &unload, KTrader::OfferList &load); + + /**@return The root profile. Root profile is always named "KDevelop" and it + defines an empty list of plugins. Applications built on KDevelop platform + will define nested profiles.*/ + Profile *rootProfile() const { return m_rootProfile; } + /**Finds a profile with given name. + @return The profile found or 0 if it does not exist.*/ + Profile *findProfile(const QString &profileName); + + /**Walks profiles tree and applies operation @p op to each profile found + in the tree below @p root (@p root profile itself is not processed). + + Operation is a class that have operator(Profile *). + Example of operation class which is used to build a plain list of profiles: + @code + class ProfileListing{ + public: + void operator() (Profile *profile) + { + profiles[profile->name()] = profile; + } + + QMap<QString, Profile*> profiles; + }; + @endcode + Use case for such operation - building a list of all profiles: + @code + ProfileEngine engine; + ProfileListing listing; + engine.walkProfiles<ProfileListing>(listing, engine.rootProfile()); + @endcode + + @note @ref ProfileListing and @ref ProfileListingEx operations are already defined in + profileengine.h header file. + + @param op An operation to apply. + @param root A profile to start walking from. Complete subtree of the @p root is traversed. + */ + template<class Operation> + void walkProfiles(Operation &op, Profile *root) + { + QValueList<Profile*> children = root->children(); + for (QValueList<Profile*>::iterator it = children.begin(); it != children.end(); ++it) + { + op(*it); + walkProfiles<Operation>(op, *it); + } + } + /**Walks profiles tree and applies operation @p op to each profile + found in the tree below @p root (@p root profile itself is not processed) + but the operation in this case returns a result of type defined by + "Result" template parameter. + + When iterating the tree, the result of operation applied to the parent profile + is passed as @p result parameter to the recursive call for child profiles. + + For example, this function can be used to build another hierarcy of profiles + or other objects connected to profiles. + Example of operation class which is used to build a listview with items + where each item represents a profile: + @code + class ProfileListBuilding { + public: + ProfileItem * operator() (ProfileItem *parent, Profile *profile) + { + parent->setOpen(true); + return new ProfileItem(parent, profile); + } + }; + + class ProfileItem: public KListViewItem { + public: + ProfileItem(KListView *parent, Profile *profile) + :KListViewItem(parent), m_profile(profile) + { + setText(0, profile->genericName()); + setText(1, profile->description()); + } + + ProfileItem(KListViewItem *parent, Profile *profile) + : KListViewItem(parent), m_profile(profile) + { + setText(0, profile->genericName()); + setText(1, profile->description()); + } + + Profile *profile() const { return m_profile; } + + private: + Profile *m_profile; + }; + + @endcode + Use case for such operation - building a listview: + @code + ProfileEngine engine; + ProfileItem *item = new ProfileItem(profilesList, engine.rootProfile()); + ProfileListBuilding op; + engine.walkProfiles<ProfileListBuilding, ProfileItem>(op, item, engine.rootProfile()); + @endcode + + @param op An operation to apply. + @param result A result of the operation as it would have been applied to the @p root. + @param root A profile to start walking from. Complete subtree of the @p root is traversed. + */ + template<class Operation, class Result> + void walkProfiles(Operation &op, Result *result, Profile *root) + { + QValueList<Profile*> children = root->children(); + for (QValueList<Profile*>::iterator it = children.begin(); it != children.end(); ++it) + { + Result *newResult = op(result, *it); + walkProfiles<Operation>(op, newResult, *it); + } + } + +protected: + void processDir(const QString &dir, const QString &currPath, QMap<QString, Profile*> &passedPaths, Profile *root); + + KURL::List resources(Profile *profile, const QString &nameFilter); + + /**Gets a complete listing of available profiles and looks for a profile. + @param listing Profiles listing will be saved here. + @param profile Will be a pointer to a profile with the name @p profileName or 0 + if no profile with that name is found. + @param profileName The name of a profile to find.*/ + void getProfileWithListing(ProfileListing &listing, Profile **profile, + const QString &profileName); + +private: + Profile *m_rootProfile; +}; + +#endif diff --git a/src/profiles/IDE/CompiledLanguageIDE/AdaIDE/Makefile.am b/src/profiles/IDE/CompiledLanguageIDE/AdaIDE/Makefile.am new file mode 100644 index 00000000..43f3c4a3 --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/AdaIDE/Makefile.am @@ -0,0 +1,3 @@ +profilesdir = $(kde_datadir)/kdevelop/profiles/IDE/CompiledLanguageIDE/AdaIDE +profiles_DATA = profile.config + diff --git a/src/profiles/IDE/CompiledLanguageIDE/AdaIDE/profile.config b/src/profiles/IDE/CompiledLanguageIDE/AdaIDE/profile.config new file mode 100644 index 00000000..27e52f63 --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/AdaIDE/profile.config @@ -0,0 +1,12 @@ +[Disable] +List= + +[Enable] +List= + +[Information] +Description=Ada IDE profile +GenericName=Ada IDE + +[Properties] +List= diff --git a/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CIDE/Makefile.am b/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CIDE/Makefile.am new file mode 100644 index 00000000..2c4bd865 --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CIDE/Makefile.am @@ -0,0 +1,3 @@ +profilesdir = $(kde_datadir)/kdevelop/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CIDE +profiles_DATA = profile.config + diff --git a/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CIDE/profile.config b/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CIDE/profile.config new file mode 100644 index 00000000..9b0ea064 --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CIDE/profile.config @@ -0,0 +1,12 @@ +[Disable] +List= + +[Enable] +List= + +[Information] +Description=C IDE profile +GenericName=C IDE + +[Properties] +List=CDevelopment,CProjectDocumentation diff --git a/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CppIDE/KDECppIDE/Makefile.am b/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CppIDE/KDECppIDE/Makefile.am new file mode 100644 index 00000000..661d148f --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CppIDE/KDECppIDE/Makefile.am @@ -0,0 +1,3 @@ +profilesdir = $(kde_datadir)/kdevelop/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CppIDE/KDECppIDE +profiles_DATA = profile.config + diff --git a/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CppIDE/KDECppIDE/profile.config b/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CppIDE/KDECppIDE/profile.config new file mode 100644 index 00000000..b5b45c4c --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CppIDE/KDECppIDE/profile.config @@ -0,0 +1,12 @@ +[Disable] +List= + +[Enable] +List= + +[Information] +Description=C++ IDE for KDE profile +GenericName=C++ IDE for KDE + +[Properties] +List=KDEDevelopment diff --git a/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CppIDE/Makefile.am b/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CppIDE/Makefile.am new file mode 100644 index 00000000..b094d414 --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CppIDE/Makefile.am @@ -0,0 +1,3 @@ +profilesdir = $(kde_datadir)/kdevelop/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CppIDE +profiles_DATA = profile.config +SUBDIRS = KDECppIDE diff --git a/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CppIDE/profile.config b/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CppIDE/profile.config new file mode 100644 index 00000000..8167928c --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/CppIDE/profile.config @@ -0,0 +1,12 @@ +[Disable] +List= + +[Enable] +List= + +[Information] +Description=C++ IDE profile +GenericName=C++ IDE + +[Properties] +List=CPPDevelopment,CPPProjectDocumentation diff --git a/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/Makefile.am b/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/Makefile.am new file mode 100644 index 00000000..7ce0bb6b --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = CIDE CppIDE + +profilesdir = $(kde_datadir)/kdevelop/profiles/IDE/CompiledLanguageIDE/CandCppIDE +profiles_DATA = profile.config diff --git a/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/profile.config b/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/profile.config new file mode 100644 index 00000000..a25f28e7 --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/CandCppIDE/profile.config @@ -0,0 +1,12 @@ +[Disable] +List= + +[Enable] +List= + +[Information] +Description=C and C++ IDE profile +GenericName=C and C++ IDE + +[Properties] +List= diff --git a/src/profiles/IDE/CompiledLanguageIDE/FortranIDE/Makefile.am b/src/profiles/IDE/CompiledLanguageIDE/FortranIDE/Makefile.am new file mode 100644 index 00000000..a179dc49 --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/FortranIDE/Makefile.am @@ -0,0 +1,3 @@ +profilesdir = $(kde_datadir)/kdevelop/profiles/IDE/CompiledLanguageIDE/FortranIDE +profiles_DATA = profile.config + diff --git a/src/profiles/IDE/CompiledLanguageIDE/FortranIDE/profile.config b/src/profiles/IDE/CompiledLanguageIDE/FortranIDE/profile.config new file mode 100644 index 00000000..73fdd80c --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/FortranIDE/profile.config @@ -0,0 +1,12 @@ +[Disable] +List= + +[Enable] +List= + +[Information] +Description=Fortran IDE profile +GenericName=Fortran IDE + +[Properties] +List= diff --git a/src/profiles/IDE/CompiledLanguageIDE/HaskellIDE/Makefile.am b/src/profiles/IDE/CompiledLanguageIDE/HaskellIDE/Makefile.am new file mode 100644 index 00000000..d131025e --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/HaskellIDE/Makefile.am @@ -0,0 +1,3 @@ +profilesdir = $(kde_datadir)/kdevelop/profiles/IDE/CompiledLanguageIDE/HaskellIDE +profiles_DATA = profile.config + diff --git a/src/profiles/IDE/CompiledLanguageIDE/HaskellIDE/profile.config b/src/profiles/IDE/CompiledLanguageIDE/HaskellIDE/profile.config new file mode 100644 index 00000000..b015764f --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/HaskellIDE/profile.config @@ -0,0 +1,12 @@ +[Disable] +List= + +[Enable] +List= + +[Information] +Description=Haskell IDE profile +GenericName=Haskell IDE + +[Properties] +List= diff --git a/src/profiles/IDE/CompiledLanguageIDE/JavaIDE/Makefile.am b/src/profiles/IDE/CompiledLanguageIDE/JavaIDE/Makefile.am new file mode 100644 index 00000000..2bb472df --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/JavaIDE/Makefile.am @@ -0,0 +1,3 @@ +profilesdir = $(kde_datadir)/kdevelop/profiles/IDE/CompiledLanguageIDE/JavaIDE +profiles_DATA = profile.config + diff --git a/src/profiles/IDE/CompiledLanguageIDE/JavaIDE/profile.config b/src/profiles/IDE/CompiledLanguageIDE/JavaIDE/profile.config new file mode 100644 index 00000000..f91cb5c7 --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/JavaIDE/profile.config @@ -0,0 +1,12 @@ +[Disable] +List=kdevdebugger + +[Enable] +List= + +[Information] +Description=Java IDE profile +GenericName=Java IDE + +[Properties] +List=JavaDevelopment,JavaProjectDocumentation diff --git a/src/profiles/IDE/CompiledLanguageIDE/Makefile.am b/src/profiles/IDE/CompiledLanguageIDE/Makefile.am new file mode 100644 index 00000000..17e848a0 --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/Makefile.am @@ -0,0 +1,4 @@ +profilesdir = $(kde_datadir)/kdevelop/profiles/IDE/CompiledLanguageIDE +profiles_DATA = profile.config + +SUBDIRS = CandCppIDE JavaIDE AdaIDE FortranIDE HaskellIDE PascalIDE diff --git a/src/profiles/IDE/CompiledLanguageIDE/PascalIDE/Makefile.am b/src/profiles/IDE/CompiledLanguageIDE/PascalIDE/Makefile.am new file mode 100644 index 00000000..1a3a3132 --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/PascalIDE/Makefile.am @@ -0,0 +1,3 @@ +profilesdir = $(kde_datadir)/kdevelop/profiles/IDE/CompiledLanguageIDE/PascalIDE +profiles_DATA = profile.config + diff --git a/src/profiles/IDE/CompiledLanguageIDE/PascalIDE/profile.config b/src/profiles/IDE/CompiledLanguageIDE/PascalIDE/profile.config new file mode 100644 index 00000000..3098037f --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/PascalIDE/profile.config @@ -0,0 +1,12 @@ +[Disable] +List= + +[Enable] +List= + +[Information] +Description=Pascal IDE profile +GenericName=Pascal IDE + +[Properties] +List= diff --git a/src/profiles/IDE/CompiledLanguageIDE/profile.config b/src/profiles/IDE/CompiledLanguageIDE/profile.config new file mode 100644 index 00000000..5f553b49 --- /dev/null +++ b/src/profiles/IDE/CompiledLanguageIDE/profile.config @@ -0,0 +1,12 @@ +[Disable] +List= + +[Enable] +List= + +[Information] +Description=Compiled Language IDE profile +GenericName=Compiled Language IDE + +[Properties] +List=CompiledDevelopment diff --git a/src/profiles/IDE/DatabaseIDE/Makefile.am b/src/profiles/IDE/DatabaseIDE/Makefile.am new file mode 100644 index 00000000..e6cc84a8 --- /dev/null +++ b/src/profiles/IDE/DatabaseIDE/Makefile.am @@ -0,0 +1,3 @@ +profilesdir = $(kde_datadir)/kdevelop/profiles/IDE/DatabaseIDE +profiles_DATA = profile.config + diff --git a/src/profiles/IDE/DatabaseIDE/profile.config b/src/profiles/IDE/DatabaseIDE/profile.config new file mode 100644 index 00000000..fabcc679 --- /dev/null +++ b/src/profiles/IDE/DatabaseIDE/profile.config @@ -0,0 +1,12 @@ +[Disable] +List= + +[Enable] +List= + +[Information] +Description=SQL IDE profile +GenericName=SQL IDE + +[Properties] +List= diff --git a/src/profiles/IDE/Makefile.am b/src/profiles/IDE/Makefile.am new file mode 100644 index 00000000..aebf65da --- /dev/null +++ b/src/profiles/IDE/Makefile.am @@ -0,0 +1,3 @@ +profilesdir = $(kde_datadir)/kdevelop/profiles/IDE +profiles_DATA = profile.config +SUBDIRS = CompiledLanguageIDE ScriptingLanguageIDE DatabaseIDE diff --git a/src/profiles/IDE/ScriptingLanguageIDE/Makefile.am b/src/profiles/IDE/ScriptingLanguageIDE/Makefile.am new file mode 100644 index 00000000..28f2afbc --- /dev/null +++ b/src/profiles/IDE/ScriptingLanguageIDE/Makefile.am @@ -0,0 +1,4 @@ +profilesdir = $(kde_datadir)/kdevelop/profiles/IDE/ScriptingLanguageIDE +profiles_DATA = profile.config + +SUBDIRS = RubyIDE PerlIDE PHPIDE PythonIDE ShellIDE diff --git a/src/profiles/IDE/ScriptingLanguageIDE/PHPIDE/Makefile.am b/src/profiles/IDE/ScriptingLanguageIDE/PHPIDE/Makefile.am new file mode 100644 index 00000000..0dfc6f41 --- /dev/null +++ b/src/profiles/IDE/ScriptingLanguageIDE/PHPIDE/Makefile.am @@ -0,0 +1,3 @@ +profilesdir = $(kde_datadir)/kdevelop/profiles/IDE/ScriptingLanguageIDE/PHPIDE +profiles_DATA = profile.config + diff --git a/src/profiles/IDE/ScriptingLanguageIDE/PHPIDE/profile.config b/src/profiles/IDE/ScriptingLanguageIDE/PHPIDE/profile.config new file mode 100644 index 00000000..f43dba40 --- /dev/null +++ b/src/profiles/IDE/ScriptingLanguageIDE/PHPIDE/profile.config @@ -0,0 +1,12 @@ +[Disable] +List= + +[Enable] +List= + +[Information] +Description=PHP IDE profile +GenericName=PHP IDE + +[Properties] +List=PHPProjectDocumentation diff --git a/src/profiles/IDE/ScriptingLanguageIDE/PerlIDE/Makefile.am b/src/profiles/IDE/ScriptingLanguageIDE/PerlIDE/Makefile.am new file mode 100644 index 00000000..06f94ac1 --- /dev/null +++ b/src/profiles/IDE/ScriptingLanguageIDE/PerlIDE/Makefile.am @@ -0,0 +1,3 @@ +profilesdir = $(kde_datadir)/kdevelop/profiles/IDE/ScriptingLanguageIDE/PerlIDE +profiles_DATA = profile.config + diff --git a/src/profiles/IDE/ScriptingLanguageIDE/PerlIDE/profile.config b/src/profiles/IDE/ScriptingLanguageIDE/PerlIDE/profile.config new file mode 100644 index 00000000..fd33b65c --- /dev/null +++ b/src/profiles/IDE/ScriptingLanguageIDE/PerlIDE/profile.config @@ -0,0 +1,12 @@ +[Disable] +List= + +[Enable] +List= + +[Information] +Description=Perl IDE profile +GenericName=Perl IDE + +[Properties] +List= diff --git a/src/profiles/IDE/ScriptingLanguageIDE/PythonIDE/Makefile.am b/src/profiles/IDE/ScriptingLanguageIDE/PythonIDE/Makefile.am new file mode 100644 index 00000000..04a98540 --- /dev/null +++ b/src/profiles/IDE/ScriptingLanguageIDE/PythonIDE/Makefile.am @@ -0,0 +1,3 @@ +profilesdir = $(kde_datadir)/kdevelop/profiles/IDE/ScriptingLanguageIDE/PythonIDE +profiles_DATA = profile.config + diff --git a/src/profiles/IDE/ScriptingLanguageIDE/PythonIDE/profile.config b/src/profiles/IDE/ScriptingLanguageIDE/PythonIDE/profile.config new file mode 100644 index 00000000..db605e85 --- /dev/null +++ b/src/profiles/IDE/ScriptingLanguageIDE/PythonIDE/profile.config @@ -0,0 +1,12 @@ +[Disable] +List= + +[Enable] +List= + +[Information] +Description=Python IDE profile +GenericName=Python IDE + +[Properties] +List= diff --git a/src/profiles/IDE/ScriptingLanguageIDE/RubyIDE/Makefile.am b/src/profiles/IDE/ScriptingLanguageIDE/RubyIDE/Makefile.am new file mode 100644 index 00000000..8728ed31 --- /dev/null +++ b/src/profiles/IDE/ScriptingLanguageIDE/RubyIDE/Makefile.am @@ -0,0 +1,3 @@ +profilesdir = $(kde_datadir)/kdevelop/profiles/IDE/ScriptingLanguageIDE/RubyIDE +profiles_DATA = profile.config + diff --git a/src/profiles/IDE/ScriptingLanguageIDE/RubyIDE/profile.config b/src/profiles/IDE/ScriptingLanguageIDE/RubyIDE/profile.config new file mode 100644 index 00000000..5e58c161 --- /dev/null +++ b/src/profiles/IDE/ScriptingLanguageIDE/RubyIDE/profile.config @@ -0,0 +1,12 @@ +[Disable] +List=kdevfilelist,kdevsnippet,kdevvalgrind,kdevastyle,kdevctags2,kdevsecurity,kdevregexptest + +[Enable] +List= + +[Information] +Description=Ruby IDE profile +GenericName=Ruby IDE + +[Properties] +List=RubyDebugger diff --git a/src/profiles/IDE/ScriptingLanguageIDE/ShellIDE/Makefile.am b/src/profiles/IDE/ScriptingLanguageIDE/ShellIDE/Makefile.am new file mode 100644 index 00000000..a62bce23 --- /dev/null +++ b/src/profiles/IDE/ScriptingLanguageIDE/ShellIDE/Makefile.am @@ -0,0 +1,3 @@ +profilesdir = $(kde_datadir)/kdevelop/profiles/IDE/ScriptingLanguageIDE/ShellIDE +profiles_DATA = profile.config + diff --git a/src/profiles/IDE/ScriptingLanguageIDE/ShellIDE/profile.config b/src/profiles/IDE/ScriptingLanguageIDE/ShellIDE/profile.config new file mode 100644 index 00000000..910f9eb5 --- /dev/null +++ b/src/profiles/IDE/ScriptingLanguageIDE/ShellIDE/profile.config @@ -0,0 +1,12 @@ +[Disable] +List= + +[Enable] +List= + +[Information] +Description=Shell scripting IDE profile +GenericName=Shell scripting IDE + +[Properties] +List= diff --git a/src/profiles/IDE/ScriptingLanguageIDE/profile.config b/src/profiles/IDE/ScriptingLanguageIDE/profile.config new file mode 100644 index 00000000..6b39de13 --- /dev/null +++ b/src/profiles/IDE/ScriptingLanguageIDE/profile.config @@ -0,0 +1,12 @@ +[Disable] +List= + +[Enable] +List= + +[Information] +Description=Scripting Language IDE profile +GenericName=Scripting Language IDE + +[Properties] +List=ScriptDevelopment diff --git a/src/profiles/IDE/profile.config b/src/profiles/IDE/profile.config new file mode 100644 index 00000000..0bb6b317 --- /dev/null +++ b/src/profiles/IDE/profile.config @@ -0,0 +1,12 @@ +[Disable] +List= + +[Enable] +List= + +[Information] +Description=Generic KDevelop IDE profile +GenericName=KDevelop IDE + +[Properties] +List=AdditionalTools,CodeEditing,CodeNavigation,Console,Documentation,EditorChooser,FileCreation,FileReplace,FileSearch,GlobalFileManagement,OpenFileNavigation,OptionalCodeEditing,OutputTool,ProjectCreation,ProjectFileGroupsManagement,ProjectFileManagement,UISwitching,ViewManagement,CVSService,ClearcaseVCS,PerforceVCS,SubversionVCS,ProjectPackaging,VCS diff --git a/src/profiles/KDevAssistant/Makefile.am b/src/profiles/KDevAssistant/Makefile.am new file mode 100644 index 00000000..f8a5f334 --- /dev/null +++ b/src/profiles/KDevAssistant/Makefile.am @@ -0,0 +1,3 @@ +profilesdir = $(kde_datadir)/kdevelop/profiles/KDevAssistant +profiles_DATA = profile.config + diff --git a/src/profiles/KDevAssistant/profile.config b/src/profiles/KDevAssistant/profile.config new file mode 100644 index 00000000..dc1435a9 --- /dev/null +++ b/src/profiles/KDevAssistant/profile.config @@ -0,0 +1,12 @@ +[Disable] +List= + +[Enable] +List= + +[Information] +Description=KDevelop Assistant profile +GenericName=KDevelop Assistant + +[Properties] +List=GlobalFileManagement,Documentation,UISwitching,ViewManagement diff --git a/src/profiles/Makefile.am b/src/profiles/Makefile.am new file mode 100644 index 00000000..7d10138d --- /dev/null +++ b/src/profiles/Makefile.am @@ -0,0 +1,3 @@ +profilesdir = $(kde_datadir)/kdevelop/profiles +profiles_DATA = profile.config +SUBDIRS = IDE KDevAssistant diff --git a/src/profiles/profile.config b/src/profiles/profile.config new file mode 100644 index 00000000..9d884533 --- /dev/null +++ b/src/profiles/profile.config @@ -0,0 +1,3 @@ +[Information] +GenericName=KDevelop +Description=Default KDevelop profile diff --git a/src/projectmanager.cpp b/src/projectmanager.cpp new file mode 100644 index 00000000..3b06340f --- /dev/null +++ b/src/projectmanager.cpp @@ -0,0 +1,668 @@ +#include <qfile.h> +#include <qfileinfo.h> +#include <qdir.h> +#include <qdom.h> +#include <qstringlist.h> +#include <qptrlist.h> +#include <qvbox.h> +#include <qsize.h> +#include <qtimer.h> + +class QDomDocument; + +#include <kmessagebox.h> +#include <kdebug.h> +#include <klocale.h> +#include <kservice.h> +#include <ktrader.h> +#include <kfiledialog.h> +#include <kmainwindow.h> +#include <kparts/componentfactory.h> +#include <kaction.h> +#include <kapplication.h> +#include <kcmdlineargs.h> +#include <kprocess.h> +#include <kglobal.h> +#include <kstandarddirs.h> +#include <kio/netaccess.h> +#include <ktempfile.h> +#include <kmenubar.h> +#include <kstatusbar.h> +#include <kiconloader.h> + +#include "kdevproject.h" +#include "kdevlanguagesupport.h" +#include "kdevplugin.h" +#include "kdevcreatefile.h" +#include "kdevversioncontrol.h" + + +#include "toplevel.h" +#include "core.h" +#include "api.h" +#include "plugincontroller.h" +#include "partcontroller.h" +#include "codemodel.h" +// #include "partselectwidget.h" +#include "languageselectwidget.h" +#include "generalinfowidget.h" +#include "projectsession.h" +#include "domutil.h" +#include "settings.h" + +#include "projectmanager.h" + +QString ProjectInfo::sessionFile() const +{ + QString sf = m_projectURL.path(-1); + sf.truncate(sf.length() - 8); // without ".kdevelop" + sf += "kdevses"; // suffix for a KDevelop session file + return sf; +} + +QString ProjectManager::projectDirectory( const QString& path, bool absolute ) { + if(absolute) + return path; + KURL url(ProjectManager::getInstance()->projectFile(), path); + url.cleanPath(); + return url.path(-1); +} + +ProjectManager *ProjectManager::s_instance = 0; + +ProjectManager::ProjectManager() +: m_info(0L) + ,m_pProjectSession(new ProjectSession) +{ +} + +ProjectManager::~ProjectManager() +{ + delete m_pProjectSession; + delete m_info; +} + +ProjectManager *ProjectManager::getInstance() +{ + if (!s_instance) + s_instance = new ProjectManager; + return s_instance; +} + +void ProjectManager::createActions( KActionCollection* ac ) +{ + KAction *action; + + action = new KAction(i18n("&Open Project..."), "project_open", 0, + this, SLOT(slotOpenProject()), + ac, "project_open"); + action->setToolTip( i18n("Open project")); + action->setWhatsThis(i18n("<b>Open project</b><p>Opens a KDevelop3 or KDevelop2 project.")); + + m_openRecentProjectAction = + new KRecentFilesAction(i18n("Open &Recent Project"), 0, + this, SLOT(loadProject(const KURL &)), + ac, "project_open_recent"); + m_openRecentProjectAction->setToolTip(i18n("Open recent project")); + m_openRecentProjectAction->setWhatsThis(i18n("<b>Open recent project</b><p>Opens recently opened project.")); + m_openRecentProjectAction->loadEntries(kapp->config(), "RecentProjects"); + + m_closeProjectAction = + new KAction(i18n("C&lose Project"), "fileclose",0, + this, SLOT(closeProject()), + ac, "project_close"); + m_closeProjectAction->setEnabled(false); + m_closeProjectAction->setToolTip(i18n("Close project")); + m_closeProjectAction->setWhatsThis(i18n("<b>Close project</b><p>Closes the current project.")); + + m_projectOptionsAction = new KAction(i18n("Project &Options"), "configure", 0, + this, SLOT(slotProjectOptions()), + ac, "project_options" ); + m_projectOptionsAction->setToolTip(i18n("Project options")); + m_projectOptionsAction->setWhatsThis(i18n("<b>Project options</b><p>Lets you customize project options.")); + m_projectOptionsAction->setEnabled(false); +} + +void ProjectManager::slotOpenProject() +{ + KConfig *config = kapp->config(); + config->setGroup("General Options"); + QString defaultProjectsDir = config->readPathEntry("DefaultProjectsDir", QDir::homeDirPath()+"/"); + + KURL url = KFileDialog::getOpenURL(defaultProjectsDir, + i18n("*.kdevelop|KDevelop 3 Project Files\n" + "*.kdevprj|KDevelop 2 Project Files"), + TopLevel::getInstance()->main(), i18n("Open Project") ); + + if( url.isEmpty() ) + return; + + if (url.path().endsWith("kdevprj")) + loadKDevelop2Project( url ); + else + loadProject( url ); +} + +void ProjectManager::slotProjectOptions() +{ + KDialogBase dlg(KDialogBase::IconList, i18n("Project Options"), + KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, TopLevel::getInstance()->main(), + "project options dialog"); + + QVBox *box = dlg.addVBoxPage( i18n("General"), i18n("General"), BarIcon( "kdevelop", KIcon::SizeMedium ) ); + GeneralInfoWidget *g = new GeneralInfoWidget(*API::getInstance()->projectDom(), box, "general informations widget"); + connect (&dlg, SIGNAL(okClicked()), g, SLOT(accept())); + + KConfig *config = kapp->config(); + config->setGroup("Project Settings Dialog"); + int height = config->readNumEntry( "Height", 600 ); + int width = config->readNumEntry( "Width", 800 ); + + dlg.resize( width, height ); + + Core::getInstance()->doEmitProjectConfigWidget(&dlg); + dlg.exec(); + + saveProjectFile(); + + config->setGroup("Project Settings Dialog"); + config->writeEntry( "Height", dlg.size().height() ); + config->writeEntry( "Width", dlg.size().width() ); +} + +void ProjectManager::loadSettings() +{ +} + +void ProjectManager::saveSettings() +{ + KConfig *config = kapp->config(); + + if (projectLoaded()) + { + config->setGroup("General Options"); + config->writePathEntry("Last Project", ProjectManager::getInstance()->projectFile().url()); + } + + m_openRecentProjectAction->saveEntries(config, "RecentProjects"); +} + +void ProjectManager::loadDefaultProject() +{ + KConfig *config = kapp->config(); + config->setGroup("General Options"); + QString project = config->readPathEntry("Last Project"); + bool readProject = config->readBoolEntry("Read Last Project On Startup", true); + if (!project.isEmpty() && readProject) + { + loadProject(KURL(project)); + } +} + +bool ProjectManager::loadProject(const KURL &projectURL) +{ + KURL url = projectURL; + + if (!url.isValid()) + return false; + + if (url.isLocalFile()) + { + QDir dir(url.path()); + QString can_path = dir.canonicalPath(); + //if the directory doesn't exist, the returned string is null which confuses the user later on. so better short-cut here + if(can_path.isNull()) + return false; + else + url.setPath(can_path); + } + + // reopen the already opened project? + if( projectLoaded() && url.path() == projectFile().path() ) + { + if (KMessageBox::questionYesNo(TopLevel::getInstance()->main(), + i18n("Are you sure you want to reopen the current project?"), QString::null, i18n("Reopen"), i18n("Do Not Reopen")) == KMessageBox::No) + return false; + } + + TopLevel::getInstance()->main()->menuBar()->setEnabled( false ); + kapp->setOverrideCursor( waitCursor ); + + if( projectLoaded() && !closeProject() ) + { + m_openRecentProjectAction->setCurrentItem( -1 ); + TopLevel::getInstance()->main()->menuBar()->setEnabled( true ); + kapp->restoreOverrideCursor(); + return false; + } + + m_info = new ProjectInfo; + m_info->m_projectURL = url; + + QTimer::singleShot( 0, this, SLOT(slotLoadProject()) ); + + // no one cares about this value + return true; +} + +void ProjectManager::slotLoadProject( ) +{ + if( !loadProjectFile() ) + { + m_openRecentProjectAction->removeURL(m_info->m_projectURL); + delete m_info; m_info = 0; + saveSettings(); + TopLevel::getInstance()->main()->menuBar()->setEnabled( true ); + kapp->restoreOverrideCursor(); + return; + } + + getGeneralInfo(); + + if( !loadLanguageSupport(m_info->m_language) ) { + delete m_info; m_info = 0; + TopLevel::getInstance()->main()->menuBar()->setEnabled( true ); + kapp->restoreOverrideCursor(); + return; + } + + if( !loadProjectPart() ) { + unloadLanguageSupport(); + delete m_info; m_info = 0; + API::getInstance()->setProjectDom( 0 ); + TopLevel::getInstance()->main()->menuBar()->setEnabled( true ); + kapp->restoreOverrideCursor(); + return; + } + + TopLevel::getInstance()->statusBar()->message( i18n("Changing plugin profile...") ); + m_oldProfileName = PluginController::getInstance()->changeProfile(m_info->m_profileName); + + TopLevel::getInstance()->statusBar()->message( i18n("Loading project plugins...") ); + loadLocalParts(); + + // shall we try to load a session file from network?? Probably not. + if (m_info->m_projectURL.isLocalFile()) + { + // first restore the project session stored in a .kdevses file + if (!m_pProjectSession->restoreFromFile(m_info->sessionFile(), PluginController::getInstance()->loadedPlugins() )) + { + kdWarning() << i18n("error during restoring of the KDevelop session !") << endl; + } + } +#if KDE_IS_VERSION(3,5,0) + m_openRecentProjectAction->addURL(projectFile(), projectName()); // KDE >= 3.5.x +#else + m_openRecentProjectAction->addURL(projectFile()); // KDE 3.4.x +#endif + m_closeProjectAction->setEnabled(true); + m_projectOptionsAction->setEnabled(true); + + Core::getInstance()->doEmitProjectOpened(); + + TopLevel::getInstance()->main()->menuBar()->setEnabled( true ); + kapp->restoreOverrideCursor(); + + TopLevel::getInstance()->statusBar()->message( i18n("Project loaded."), 3000 ); + + return; +} + + +bool ProjectManager::closeProject( bool exiting ) +{ + if( !projectLoaded() ) + return true; + + // save the session if it is a local file + if (m_info->m_projectURL.isLocalFile()) + { + m_pProjectSession->saveToFile(m_info->sessionFile(), PluginController::getInstance()->loadedPlugins() ); + } + + if ( !PartController::getInstance()->querySaveFiles() ) + return false; + + Core::getInstance()->doEmitProjectClosed(); + + PluginController::getInstance()->unloadProjectPlugins(); + PluginController::getInstance()->changeProfile(m_oldProfileName); + unloadLanguageSupport(); + unloadProjectPart(); + + /// @todo if this fails, user is screwed + saveProjectFile(); + + API::getInstance()->setProjectDom(0); + API::getInstance()->codeModel()->wipeout(); + + delete m_info; + m_info = 0; + + m_closeProjectAction->setEnabled(false); + m_projectOptionsAction->setEnabled(false); + + if ( !exiting ) + { + PartController::getInstance()->slotCloseAllWindows(); + } + + return true; +} + +bool ProjectManager::loadProjectFile() +{ + QString path; + if (!KIO::NetAccess::download(m_info->m_projectURL, path, 0)) { + KMessageBox::sorry(TopLevel::getInstance()->main(), + i18n("Could not read project file: %1").arg(m_info->m_projectURL.prettyURL())); + return false; + } + + QFile fin(path); + if (!fin.open(IO_ReadOnly)) + { + KMessageBox::sorry(TopLevel::getInstance()->main(), + i18n("Could not read project file: %1").arg(m_info->m_projectURL.prettyURL())); + return false; + } + + int errorLine, errorCol; + QString errorMsg; + if (!m_info->m_document.setContent(&fin, &errorMsg, &errorLine, &errorCol)) + { + KMessageBox::sorry(TopLevel::getInstance()->main(), + i18n("This is not a valid project file.\n" + "XML error in line %1, column %2:\n%3") + .arg(errorLine).arg(errorCol).arg(errorMsg)); + fin.close(); + KIO::NetAccess::removeTempFile(path); + return false; + } + if (m_info->m_document.documentElement().nodeName() != "kdevelop") + { + KMessageBox::sorry(TopLevel::getInstance()->main(), + i18n("This is not a valid project file.")); + fin.close(); + KIO::NetAccess::removeTempFile(path); + return false; + } + + fin.close(); + KIO::NetAccess::removeTempFile(path); + + API::getInstance()->setProjectDom(&m_info->m_document); + + return true; +} + +bool ProjectManager::saveProjectFile() +{ + Q_ASSERT( API::getInstance()->projectDom() ); + + if (m_info->m_projectURL.isLocalFile()) { + QFile fout(m_info->m_projectURL.path()); + if( !fout.open(IO_WriteOnly) ) { + KMessageBox::sorry(TopLevel::getInstance()->main(), i18n("Could not write the project file.")); + return false; + } + + QTextStream stream(&fout); + API::getInstance()->projectDom()->save(stream, 2); + fout.close(); + } else { + KTempFile fout(QString::fromLatin1("kdevelop3")); + fout.setAutoDelete(true); + if (fout.status() != 0) { + KMessageBox::sorry(TopLevel::getInstance()->main(), i18n("Could not write the project file.")); + return false; + } + API::getInstance()->projectDom()->save(*(fout.textStream()), 2); + fout.close(); + KIO::NetAccess::upload(fout.name(), m_info->m_projectURL, 0); + } + + return true; +} + +static QString getAttribute(QDomElement elem, QString attr) +{ + QDomElement el = elem.namedItem(attr).toElement(); + return el.firstChild().toText().data(); +} + +static void getAttributeList(QDomElement elem, QString attr, QString tag, QStringList &list) +{ + list.clear(); + + QDomElement el = elem.namedItem(attr).toElement(); + QDomElement item = el.firstChild().toElement(); + while (!item.isNull()) + { + if (item.tagName() == tag) + list << item.firstChild().toText().data(); + item = item.nextSibling().toElement(); + } +} + +void ProjectManager::getGeneralInfo() +{ + QDomElement docEl = m_info->m_document.documentElement(); + QDomElement generalEl = docEl.namedItem("general").toElement(); + + m_info->m_projectPlugin = getAttribute(generalEl, "projectmanagement"); + m_info->m_vcsPlugin = getAttribute(generalEl, "versioncontrol"); + m_info->m_language = getAttribute(generalEl, "primarylanguage"); + m_info->m_projectName = getAttribute(generalEl, "projectname"); + if( m_info->m_projectName.isEmpty() ) + { + m_info->m_projectName = m_info->m_projectURL.filename(); + m_info->m_projectName = m_info->m_projectName.left(m_info->m_projectName.length()-QString(".kdevelop").length()); + QDomElement prjname = m_info->m_document.createElement("projectname"); + prjname.appendChild( m_info->m_document.createTextNode( m_info->m_projectName) ); + generalEl.appendChild( prjname ); + } + + getAttributeList(generalEl, "ignoreparts", "part", m_info->m_ignoreParts); + getAttributeList(generalEl, "keywords", "keyword", m_info->m_keywords); + + //FIXME: adymo: workaround for those project templates without "profile" element +// m_info->m_profileName = getAttribute(generalEl, "profile"); + QDomElement el = generalEl.namedItem("profile").toElement(); + if (el.isNull()) +// m_info->m_profileName = profileByAttributes(m_info->m_language, m_info->m_keywords); + m_info->m_profileName = Settings::profileByAttributes(m_info->m_language, m_info->m_keywords); + else + m_info->m_profileName = el.firstChild().toText().data(); +} + +bool ProjectManager::loadProjectPart() +{ + KService::Ptr projectService = KService::serviceByDesktopName(m_info->m_projectPlugin); + if (!projectService) { + // this is for backwards compatibility with pre-alpha6 projects + projectService = KService::serviceByDesktopName(m_info->m_projectPlugin.lower()); + } + if (!projectService) { + KMessageBox::sorry(TopLevel::getInstance()->main(), + i18n("No project management plugin %1 found.") + .arg(m_info->m_projectPlugin)); + return false; + } + + KDevProject *projectPart = KParts::ComponentFactory + ::createInstanceFromService< KDevProject >( projectService, API::getInstance(), 0, + PluginController::argumentsFromService( projectService ) ); + if ( !projectPart ) { + KMessageBox::sorry(TopLevel::getInstance()->main(), + i18n("Could not create project management plugin %1.") + .arg(m_info->m_projectPlugin)); + return false; + } + + API::getInstance()->setProject( projectPart ); + + QDomDocument& dom = *API::getInstance()->projectDom(); + QString path = DomUtil::readEntry(dom,"/general/projectdirectory", "."); + bool absolute = DomUtil::readBoolEntry(dom,"/general/absoluteprojectpath",false); + QString projectDir = projectDirectory( path, absolute ); + kdDebug(9000) << "projectDir: " << projectDir << " projectName: " << m_info->m_projectName << endl; + + projectPart->openProject(projectDir, m_info->m_projectName); + + PluginController::getInstance()->integratePart( projectPart ); + + return true; +} + +void ProjectManager::unloadProjectPart() +{ + KDevProject *projectPart = API::getInstance()->project(); + if( !projectPart ) return; + PluginController::getInstance()->removePart( projectPart ); + projectPart->closeProject(); + delete projectPart; + API::getInstance()->setProject(0); +} + +bool ProjectManager::loadLanguageSupport(const QString& lang) +{ + kdDebug(9000) << "Looking for language support for " << lang << endl; + + if (lang == m_info->m_activeLanguage) + { + kdDebug(9000) << "Language support already loaded" << endl; + return true; + } + + KTrader::OfferList languageSupportOffers = + KTrader::self()->query(QString::fromLatin1("KDevelop/LanguageSupport"), + QString::fromLatin1("[X-KDevelop-Language] == '%1' and [X-KDevelop-Version] == %2").arg(lang).arg(KDEVELOP_PLUGIN_VERSION)); + + if (languageSupportOffers.isEmpty()) { + KMessageBox::sorry(TopLevel::getInstance()->main(), + i18n("No language plugin for %1 found.") + .arg(lang)); + return false; + } + + KService::Ptr languageSupportService = *languageSupportOffers.begin(); + KDevLanguageSupport *langSupport = KParts::ComponentFactory + ::createInstanceFromService<KDevLanguageSupport>( languageSupportService, + API::getInstance(), + 0, + PluginController::argumentsFromService( languageSupportService ) ); + + if ( !langSupport ) { + KMessageBox::sorry(TopLevel::getInstance()->main(), + i18n("Could not create language plugin for %1.") + .arg(lang)); + return false; + } + + API::getInstance()->setLanguageSupport( langSupport ); + PluginController::getInstance()->integratePart( langSupport ); + m_info->m_activeLanguage = lang; + kdDebug(9000) << "Language support for " << lang << " successfully loaded." << endl; + return true; +} + +void ProjectManager::unloadLanguageSupport() +{ + KDevLanguageSupport *langSupport = API::getInstance()->languageSupport(); + if( !langSupport ) return; + kdDebug(9000) << "Language support for " << langSupport->name() << " unloading..." << endl; + PluginController::getInstance()->removePart( langSupport ); + delete langSupport; + API::getInstance()->setLanguageSupport(0); +} + +void ProjectManager::loadLocalParts() +{ + // Make sure to refresh load/ignore lists + getGeneralInfo(); + + PluginController::getInstance()->unloadPlugins( m_info->m_ignoreParts ); + PluginController::getInstance()->loadProjectPlugins( m_info->m_ignoreParts ); + PluginController::getInstance()->loadGlobalPlugins( m_info->m_ignoreParts ); +} + +KURL ProjectManager::projectFile() const +{ + if (!m_info) + return KURL(); + return m_info->m_projectURL; +} + +QString ProjectManager::projectName() const +{ + if (!m_info) return QString(); + + return m_info->m_projectName; +} + +bool ProjectManager::projectLoaded() const +{ + return m_info != 0; +} + +ProjectSession* ProjectManager::projectSession() const +{ + return m_pProjectSession; +} + +bool ProjectManager::loadKDevelop2Project( const KURL & url ) +{ + if( !url.isValid() || !url.isLocalFile() ){ + KMessageBox::sorry(0, i18n("Invalid URL.")); + return false; + } + + QString cmd = KGlobal::dirs()->findExe( "kdevprj2kdevelop" ); + if (cmd.isEmpty()) { + KMessageBox::sorry(0, i18n("You do not have 'kdevprj2kdevelop' installed.")); + return false; + } + + QFileInfo fileInfo( url.path() ); + + KShellProcess proc( "/bin/sh" ); + proc.setWorkingDirectory( fileInfo.dirPath(true) ); + proc << "perl" << cmd << KShellProcess::quote( url.path() ); + proc.start( KProcess::Block ); + + QString projectFile = fileInfo.dirPath( true ) + "/" + fileInfo.baseName() + ".kdevelop"; + return loadProject( KURL(projectFile) ); +} + +// QString ProjectManager::profileByAttributes(const QString &language, const QStringList &keywords) +// { +// KConfig config(locate("data", "kdevelop/profiles/projectprofiles")); +// config.setGroup(language); +// +// QStringList profileKeywords = QStringList::split("/", "Empty"); +// if (config.hasKey("Keywords")) +// profileKeywords = config.readListEntry("Keywords"); +// +// int idx = 0; +// for (QStringList::const_iterator it = profileKeywords.constBegin(); +// it != profileKeywords.constEnd(); ++it) +// { +// if (keywords.contains(*it)) +// { +// idx = profileKeywords.findIndex(*it); +// break; +// } +// } +// +// QStringList profiles; +// if (config.hasKey("Profiles")) +// { +// profiles = config.readListEntry("Profiles"); +// kdDebug() << "IDX: " << idx << " PROFILE: " << profiles[idx] << endl; +// return profiles[idx]; +// } +// return "KDevelop"; +// } + +#include "projectmanager.moc" diff --git a/src/projectmanager.h b/src/projectmanager.h new file mode 100644 index 00000000..1cfb07d6 --- /dev/null +++ b/src/projectmanager.h @@ -0,0 +1,111 @@ +#ifndef __PROJECTMANAGER_H__ +#define __PROJECTMANAGER_H__ + + +#include <qstring.h> +#include <qobject.h> +#include <qdict.h> + + +#include <kxmlguiclient.h> +#include <kservice.h> +#include <kurl.h> + +class KAction; +class KSelectAction; +class KService; +class ProjectInfo; +class ProjectSession; +class KRecentFilesAction; +class KDevPlugin; + + +class ProjectInfo +{ +public: + KURL m_projectURL; + QDomDocument m_document; + QString m_profileName; + QString m_projectName; + QString m_projectPlugin, m_language, m_activeLanguage, m_vcsPlugin; + QStringList m_ignoreParts, m_keywords; + + QString sessionFile() const; +}; + +/** +Project manager. +Loads and unloads projects. +*/ +class ProjectManager : public QObject, public KXMLGUIClient +{ + Q_OBJECT + +public: + + ~ProjectManager(); + + static QString projectDirectory( const QString& path, bool absolute ); + + static ProjectManager *getInstance(); + + void loadSettings(); + void saveSettings(); + void loadDefaultProject(); + + bool projectLoaded() const; + + KURL projectFile() const; + QString projectName() const; + + void createActions( KActionCollection* ac ); + + ProjectSession* projectSession() const; + +public slots: + bool loadProject( const KURL& url); + bool loadKDevelop2Project( const KURL& url); + bool closeProject( bool exiting = false ); + +private slots: + void slotOpenProject(); + void slotProjectOptions(); + + void slotLoadProject(); + + void loadLocalParts(); + +private: + ProjectManager(); + + void setupActions(); + void getGeneralInfo(); + + bool loadProjectFile(); + bool saveProjectFile(); + + bool loadProjectPart(); + void unloadProjectPart(); + + bool loadLanguageSupport(const QString& lang); + void unloadLanguageSupport(); + +// QString profileByAttributes(const QString &language, const QStringList &keywords); + + ProjectInfo *m_info; + + KAction *m_closeProjectAction, *m_projectOptionsAction; + KRecentFilesAction *m_openRecentProjectAction; + + static ProjectManager *s_instance; + + ProjectSession* m_pProjectSession; + + KDevPlugin *m_vcsPlugin; + QString m_vcsName; + + QString m_oldProfileName; +}; + + +#endif diff --git a/src/projectprofiles b/src/projectprofiles new file mode 100644 index 00000000..d2224272 --- /dev/null +++ b/src/projectprofiles @@ -0,0 +1,39 @@ +[Ada] +Profiles=AdaIDE + +[Bash] +Profiles=ShellIDE + +[C] +Profiles=CIDE + +[C++] +Keywords=Empty,KDE +Profiles=CppIDE,KDECppIDE + +[Fortran77] +Profiles=FortranIDE + +[Haskell] +Profiles=HaskellIDE + +[Java] +Profiles=JavaIDE + +[Pascal] +Profiles=PascalIDE + +[Perl] +Profiles=PerlIDE + +[PHP] +Profiles=PHPIDE + +[Python] +Profiles=PythonIDE + +[Ruby] +Profiles=RubyIDE + +[SQL] +Profiles=DatabaseIDE diff --git a/src/projectsession.cpp b/src/projectsession.cpp new file mode 100644 index 00000000..be3ec4a1 --- /dev/null +++ b/src/projectsession.cpp @@ -0,0 +1,450 @@ +/*************************************************************************** + projectsession.cpp - description + ------------------- + begin : 30 Nov 2002 + copyright : (C) 2002 by Falk Brettschneider + email : falk@kdevelop.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <qdom.h> +#include <qptrlist.h> +#include <qfile.h> +#include <qtimer.h> + +#include <kparts/part.h> +#include <kurl.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kinstance.h> +#include <ktexteditor/viewcursorinterface.h> +#include <ktexteditor/document.h> +#include <ktexteditor/encodinginterface.h> + +#include "api.h" +#include "partcontroller.h" +#include "domutil.h" +#include "documentationpart.h" +#include "toplevel.h" +#include "kdevplugin.h" + +#include "projectsession.h" +#include "projectsession.moc" +//--------------------------------------------------------------------------- +ProjectSession::ProjectSession() +{ + initXMLTree(); +} + +//--------------------------------------------------------------------------- +ProjectSession::~ProjectSession() +{ +} + +//--------------------------------------------------------------------------- +void ProjectSession::initXMLTree() +{ + // initializes the XML tree on startup of kdevelop and when a project + // has been closed to ensure that the XML tree exists already including + // doctype when a project gets opened that doesn't have a kdevses file + // or a new project gets generated (which doesn't have a kdevses file + // either as the project has never been closed before opening it). + domdoc.clear(); + QDomDocument doc("KDevPrjSession"); + domdoc=doc; + domdoc.appendChild( domdoc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) ); + // KDevPrjSession is the root element of the XML file + QDomElement session = domdoc.documentElement(); + session = domdoc.createElement("KDevPrjSession"); + domdoc.appendChild( session); +} + +//--------------------------------------------------------------------------- +bool ProjectSession::restoreFromFile( const QString & sessionFileName, const QValueList< KDevPlugin * > plugins ) +{ + bool bFileOpenOK = true; + + QFile f(sessionFileName); + if ( f.open(IO_ReadOnly) ) { // file opened successfully + bool ok = domdoc.setContent( &f); + f.close(); + if (!ok) { + KMessageBox::sorry(0L, + i18n("The file %1 does not contain valid XML.\n" + "The loading of the session failed.").arg(sessionFileName)); + initXMLTree(); // because it was now broken after failed setContent() + return false; + } + } + else { + bFileOpenOK = false; + } + + // Check for proper document type. + if (domdoc.doctype().name() != "KDevPrjSession") { + KMessageBox::sorry(0L, + i18n("The file %1 does not contain a valid KDevelop project session ('KDevPrjSession').\n").arg(sessionFileName) + + i18n("The document type seems to be: '%1'.").arg(domdoc.doctype().name())); + return false; + } + + QDomElement session = domdoc.documentElement(); + + // read the information about the mainframe widget + if (bFileOpenOK) { + recreateDocs(session); + } + + // now also let the plugins load their session stuff + QDomElement pluginListEl = session.namedItem("pluginList").toElement(); + QValueList<KDevPlugin*>::ConstIterator it = plugins.begin(); + while( it != plugins.end() ) + { + KDevPlugin* pPlugin = (*it); + QString pluginName = pPlugin->instance()->instanceName(); + QDomElement pluginEl = pluginListEl.namedItem(pluginName).toElement(); + if (!pluginEl.isNull()) { + // now plugin, load what you find! + pPlugin->restorePartialProjectSession(&pluginEl); + } + ++it; + } + + QTimer::singleShot( 0, this, SLOT(loadDocument()) ); + + return true; +} + +//--------------------------------------------------------------------------- +void ProjectSession::recreateDocs(QDomElement& el) +{ +//// QDomElement mainframeEl = el.namedItem("Mainframe").toElement(); +//// bool bMaxMode =initXMLTree() (bool) mainframeEl.attribute("MaximizeMode", "0").toInt(); +//// QextMdiMainFrm* pMainWidget = (QextMdiMainFrm*) qApp->mainWidget(); +//// pMainWidget->setEnableMaximizedChildFrmMode(bMaxMode); +//// bool bTaskBarWasOn = pMainWidget->isViewTaskBarOn(); +//// pMainWidget->hideViewTaskBar(); + + // read the information about the documents + QDomElement docsAndViewsEl = el.namedItem("DocsAndViews").toElement(); + int nNrOfDocs = docsAndViewsEl.attribute("NumberOfDocuments", "0").toInt(); + // loop over all docs + int nDoc = 0; + QDomElement docEl; + for (docEl = docsAndViewsEl.firstChild().toElement(), nDoc = 0; + nDoc < nNrOfDocs; + nDoc++, docEl = docEl.nextSibling().toElement()) + { + // read the document name and type + QString docName = docEl.attribute( "URL", ""); + if (!docName.isEmpty() /* && URL::exists(docName)*/) { + KURL url(docName); + // create the views of this document, the first view creation will also create the document + kdDebug() << k_funcinfo << "Doc to be activated? " << (nDoc == nNrOfDocs - 1) << endl; + recreateViews(url, docEl, (nDoc == nNrOfDocs - 1)); + } + } + + //FIXME: God, I hate KMDI. What the hell is this? +/* if (nNrOfDocs > 0) { + API::getInstance()->mainWindow()->callCommand("qextmdi-UI: do hack on session loading finished"); + }*/ +//// if (bTaskBarWasOn) { +//// pMainWidget->showViewTaskBar(); +//// } +} + +//--------------------------------------------------------------------------- +void ProjectSession::recreateViews(KURL& url, QDomElement docEl, bool activate) +{ + // read information about the views + int nNrOfViews = docEl.attribute( "NumberOfViews", "0").toInt(); + + // we should restore every view, but right now we only support a single view per document + // so use this simple method for now + + if ( nNrOfViews > 0 ) + { + QDomElement viewEl = docEl.firstChild().toElement(); + DocumentData dd; + dd.type = viewEl.attribute("Type"); + dd.line = viewEl.attribute("line", "0").toInt(); + dd.url = url; + dd.activate = activate; + dd.encoding = viewEl.attribute( "Encoding" ); + + _docDataList << dd; + } + +/* + // loop over all views of this document + int nView = 0; + + QDomElement viewEl; + QString viewType; + QString context; + if (docEl.hasAttribute("context")) { + context = docEl.attribute("context"); + } + + for (viewEl = docEl.firstChild().toElement(), nView = 0; nView < nNrOfViews; nView++, viewEl = viewEl.nextSibling().toElement()) { + +//// // is it the focused view? (XXX well, this only refers to the module instance) +//// if (viewEl.attribute( "Focus", "0").toInt()) { +//// // yes, memorize for later use +//// pFocusedView = pView; +//// } + + if (context.isEmpty()) { + int line = 0; + if (viewEl.hasAttribute("line")) { + line = viewEl.attribute("line", "0").toInt(); + } + PartController::getInstance()->editDocument(url, line); + } + else { + PartController::getInstance()->showDocument(url); + } + QDomElement viewPropertiesEl = viewEl.namedItem("AdditionalSettings").toElement(); + if (!viewPropertiesEl.isNull()) { + emit sig_restoreAdditionalViewProperties(url.url(), &viewPropertiesEl); + } + + } +//// // restore focus +//// if (pFocusedView != 0L) { +//// if (pFocusedView->parentWidget()->inherits("QextMdiChildView")) { +//// ((QextMdiChildView*)pFocusedView->parentWidget())->activate(); +//// } +//// pFocusedView->setFocus(); +//// } +*/ +} + +//--------------------------------------------------------------------------- +bool ProjectSession::saveToFile( const QString & sessionFileName, const QValueList< KDevPlugin * > plugins ) +{ + QString section, keyword; + QDomElement session = domdoc.documentElement(); + + int nDocs = 0; + QString docIdStr; + +//// // read the information about the mainframe widget +//// QDomElement mainframeEl = session.namedItem("Mainframe").toElement(); +//// if(mainframeEl.isNull()){ +//// mainframeEl=domdoc.createElement("Mainframe"); +//// session.appendChild( mainframeEl); +//// } +//// bool bMaxMode = ((QextMdiMainFrm*)m_pDocViewMan->parent())->isInMaximizedChildFrmMode(); +//// mainframeEl.setAttribute("MaximizeMode", bMaxMode); + + + // read the information about the documents + QDomElement docsAndViewsEl = session.namedItem("DocsAndViews").toElement(); + if (docsAndViewsEl.isNull()) { + docsAndViewsEl = domdoc.createElement("DocsAndViews"); + session.appendChild( docsAndViewsEl); + } + else { + // we need to remove the old ones before memorizing the current ones (to avoid merging) + QDomNode n = docsAndViewsEl.firstChild(); + while ( !n.isNull() ) { + QDomNode toBeRemoved = n; + n = n.nextSibling(); + docsAndViewsEl.removeChild(toBeRemoved); + } + } + + QPtrListIterator<KParts::Part> it( *PartController::getInstance()->parts() ); + for ( ; it.current(); ++it ) + { + + KParts::ReadOnlyPart* pReadOnlyPart = dynamic_cast<KParts::ReadOnlyPart*>(it.current()); + if (!pReadOnlyPart) + continue; + + QString url = pReadOnlyPart->url().url(); + + docIdStr.setNum(nDocs); + QDomElement docEl = domdoc.createElement("Doc" + docIdStr); + docEl.setAttribute( "URL", url); + docsAndViewsEl.appendChild( docEl); + nDocs++; + docEl.setAttribute( "NumberOfViews", 1); + + QDomElement viewEl = domdoc.createElement( "View0"); + docEl.appendChild( viewEl); + + if ( dynamic_cast<HTMLDocumentationPart*>(pReadOnlyPart) ) + { + viewEl.setAttribute("Type", "Documentation"); + } + else if ( pReadOnlyPart->inherits("KTextEditor::Document") ) + { + viewEl.setAttribute("Type", "Source"); + KTextEditor::ViewCursorInterface *iface = dynamic_cast<KTextEditor::ViewCursorInterface*>(pReadOnlyPart->widget()); + if (iface) { + unsigned int line, col; + iface->cursorPosition(&line, &col); + viewEl.setAttribute( "line", line ); + } + if ( KTextEditor::EncodingInterface * ei = dynamic_cast<KTextEditor::EncodingInterface*>( pReadOnlyPart ) ) + { + QString encoding = ei->encoding(); + if ( !encoding.isNull() ) + { + viewEl.setAttribute( "Encoding", encoding ); + } + } + } + else + { + viewEl.setAttribute("Type", "Other"); + } + } + +/* + QPtrListIterator<KParts::Part> it( *PartController::getInstance()->parts() ); + for ( ; it.current(); ++it ) { +//// QString partName = it.current()->name(); +//// QMessageBox::information(0L,"",partName); + + KParts::ReadOnlyPart* pReadOnlyPart = dynamic_cast<KParts::ReadOnlyPart*>(it.current()); + if (!pReadOnlyPart) + continue; // note: read-write parts are also a read-only part, they inherit from it + + HTMLDocumentationPart* pDocuPart = dynamic_cast<HTMLDocumentationPart*>(pReadOnlyPart); + + /// @todo Save relative path for project sharing? + QString url = pReadOnlyPart->url().url(); + + docIdStr.setNum(nDocs); + QDomElement docEl = domdoc.createElement("Doc" + docIdStr); + docEl.setAttribute( "URL", url); + docsAndViewsEl.appendChild( docEl); + nDocs++; +//// docEl.setAttribute( "Type", "???"); +//// // get the view list +//// QPtrList<KWpEditorPartriteView> viewList = pDoc->viewList(); +//// // write the number of views +//// docEl.setAttribute( "NumberOfViews", viewList.count()); + docEl.setAttribute( "NumberOfViews", 1); + // loop over all views of this document + int nView = 0; +//// KWriteView* pView = 0L; + QString viewIdStr; +//// for (viewList.first(), nView = 0; viewList.current() != 0; viewList.next(), nView++) { +//// pView = viewList.current(); +//// if (pView != 0L) { + viewIdStr.setNum( nView); + QDomElement viewEl = domdoc.createElement( "View"+viewIdStr); + docEl.appendChild( viewEl); + // focus? +//// viewEl.setAttribute("Focus", (((CEditWidget*)pView->parentWidget()) == m_pDocViewMan->currentEditView())); + viewEl.setAttribute("Type", "???"); + + QDomElement viewPropertiesEl = domdoc.createElement("AdditionalSettings"); + viewEl.appendChild(viewPropertiesEl); + emit sig_saveAdditionalViewProperties(url, &viewPropertiesEl); + + if (pReadOnlyPart->inherits("KTextEditor::Document")) { + KTextEditor::ViewCursorInterface *iface = dynamic_cast<KTextEditor::ViewCursorInterface*>(pReadOnlyPart->widget()); + if (iface) { + unsigned int line, col; + iface->cursorPosition(&line, &col); + viewEl.setAttribute( "line", line ); + } + } + + if (pDocuPart) { + docEl.setAttribute( "context", pDocuPart->context() ); + } + } +*/ + docsAndViewsEl.setAttribute("NumberOfDocuments", nDocs); + + + // now also let the project-related plugins save their session stuff + // read the information about the documents + QDomElement pluginListEl = session.namedItem("pluginList").toElement(); + if (pluginListEl.isNull()) { + pluginListEl = domdoc.createElement("pluginList"); + session.appendChild( pluginListEl); + } + else { + // we need to remove the old ones before memorizing the current ones (to avoid merging) + QDomNode n = pluginListEl.firstChild(); + while ( !n.isNull() ) { + QDomNode toBeRemoved = n; + n = n.nextSibling(); + pluginListEl.removeChild(toBeRemoved); + } + } + + QValueList<KDevPlugin*>::ConstIterator itt = plugins.begin(); + while( itt != plugins.end() ) + { + KDevPlugin* pPlugin = (*itt); + QString pluginName = pPlugin->instance()->instanceName(); + QDomElement pluginEl = domdoc.createElement(pluginName); + + // now plugin, save what you have! + pPlugin->savePartialProjectSession(&pluginEl); + + // if the plugin wrote anything, accept itt for the session, otherwise forget itt + if (pluginEl.hasChildNodes() || pluginEl.hasAttributes()) + { + pluginListEl.appendChild(pluginEl); + } + ++itt; + } + + // Write it out to the session file on disc + QFile f(sessionFileName); + if ( f.open(IO_WriteOnly) ) { // file opened successfully + QTextStream t( &f ); // use a text stream + t << domdoc.toCString(); + f.close(); + } + initXMLTree(); // clear and initialize the tree again + + return true; +} + + +void ProjectSession::loadDocument( ) +{ + while ( !_docDataList.isEmpty() ) + { + DocumentData & dd = _docDataList.first(); + if ( dd.type == "Source" ) + { + PartController::getInstance()->setEncoding( dd.encoding ); + PartController::getInstance()->editDocumentInternal( dd.url, dd.line, -1, dd.activate ); + } + else if ( dd.type == "Documentation" ) + { + // FIXME needs to be deferred if !activate ? + PartController::getInstance()->showDocument( dd.url, true ); + } + else + { + // FIXME needs to be deferred if !activate ? + PartController::getInstance()->editDocument( dd.url ); + } + _docDataList.pop_front(); + + loadDocument(); + //QTimer::singleShot( 0, this, SLOT(loadDocument()) ); + } +} + diff --git a/src/projectsession.h b/src/projectsession.h new file mode 100644 index 00000000..60c0b732 --- /dev/null +++ b/src/projectsession.h @@ -0,0 +1,89 @@ +/*************************************************************************** + projectsession.h - description + ------------------- + begin : 30 Nov 2002 + copyright : (C) 2002 by Falk Brettschneider + email : falk@kdevelop.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#ifndef _PROJECTSESSION_H_ +#define _PROJECTSESSION_H_ + +#include <qobject.h> +#include <qdom.h> +#include <qdict.h> +#include <qvaluelist.h> + +class QWidget; +class KURL; +class KDevPlugin; + +/** + * This class stores and restores the last situation before the certain project + * was closed. + * Session stuff that is not related to a certain project doesn't belong to here; + * it must be saved in a program session which likely is "kdeveloprc". + **/ +class ProjectSession : public QObject +{ + Q_OBJECT +// methods +public: + ProjectSession(); + virtual ~ProjectSession(); + + /** Opens the .kdevses file and saves the project session in XML format to it. */ + bool saveToFile(const QString& fileName, const QValueList<KDevPlugin*> plugins ); + + /** Opens the .kdevses file and loads the project session from it. */ + bool restoreFromFile(const QString& fileName, const QValueList<KDevPlugin*> plugins ); + +signals: + void sig_restoreMainWindowProperties(const QDomElement* el); + void sig_saveMainWindowProperties(QDomElement* el); + + void sig_restoreAdditionalViewProperties(const QString& viewName, const QDomElement* el); + void sig_saveAdditionalViewProperties(const QString& viewName, QDomElement* el); + +private slots: + /** + * This slot loads one document from _docDataList and sets a timer to load the next + */ + void loadDocument(); + +private: + /** Restores the part of the project session that concerns to the documents (files). */ + void recreateDocs(QDomElement& el); + /** recreates views and their properties of a certain document. */ + void recreateViews(KURL& url, QDomElement docEl, bool activate); + /** setup a valid XML file. */ + void initXMLTree(); + +// attributes +private: + /** the XML document object controlling the XML tree. */ + QDomDocument domdoc; + + struct DocumentData + { + DocumentData() : line(0) {} + KURL url; + int line; + QString type; + bool activate; + QString encoding; + }; + + QValueList<DocumentData> _docDataList; + +}; + +#endif // _PROJECTSESSION_H_ diff --git a/src/settingswidget.ui b/src/settingswidget.ui new file mode 100644 index 00000000..eedcd231 --- /dev/null +++ b/src/settingswidget.ui @@ -0,0 +1,528 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>SettingsWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>Form2</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>456</width> + <height>593</height> + </rect> + </property> + <property name="caption"> + <string>Form2</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QCheckBox" row="1" column="2" rowspan="1" colspan="2"> + <property name="name"> + <cstring>lastProjectCheckbox</cstring> + </property> + <property name="text"> + <string>Lo&ad last project on startup</string> + </property> + <property name="toolTip" stdset="0"> + <string>Check this if you want KDevelop to load the last opened project on startup</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Mark this checkbox if you want to continue to work with the last project you worked on. This will cause KDevelop to automatically load this project on start-up. It will usually be shown in the state you left work so you can readily proceed.</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string><qt><h3>Project Settings</h3></qt></string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter</set> + </property> + </widget> + <widget class="QCheckBox" row="6" column="2" rowspan="1" colspan="2"> + <property name="name"> + <cstring>lineWrappingCheckBox</cstring> + </property> + <property name="text"> + <string>Line wrappin&g</string> + </property> + <property name="toolTip" stdset="0"> + <string>By default, KDevelop will wrap long lines around in the Messages Output View window</string> + </property> + <property name="whatsThis" stdset="0"> + <string>By default, KDevelop will wrap long lines around in the Messages Output View window so that valuable information will not be easily overlooked. In some cases this will clutter long message lists. Remove the checkbox mark if you do not want the lines wrap around.</string> + </property> + </widget> + <widget class="QLayoutWidget" row="5" column="2" rowspan="1" colspan="2"> + <property name="name"> + <cstring>layout10</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>compilerLabel</cstring> + </property> + <property name="text"> + <string>&Compiler output:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>compileOutputCombo</cstring> + </property> + </widget> + <widget class="QComboBox"> + <item> + <property name="text"> + <string>Very Short</string> + </property> + </item> + <item> + <property name="text"> + <string>Short</string> + </property> + </item> + <item> + <property name="text"> + <string>Long</string> + </property> + </item> + <property name="name"> + <cstring>compileOutputCombo</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" stdset="0"> + <string>Choose what sort of output you want from the build process</string> + </property> + <property name="whatsThis" stdset="0"> + <string>KDevelop preprocesses the messages the Messages Output View window receives during the build processes in order to filter superfluous information. You can control the level of detail KDevelop will display using the dropdown box in this field. +<b>Very Short</b> Displays only warnings, errors, and the filenames which are compiled. +<b>Short</b> Suppresses all compiler flags and formats the output to be more readable. +<b>Full</b> Displays all output messages unmodified.</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel" row="3" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>textLabel2_2</cstring> + </property> + <property name="text"> + <string><qt><h3>Output View Settings</h3></qt></string> + </property> + <property name="textFormat"> + <enum>AutoText</enum> + </property> + <property name="alignment"> + <set>WordBreak|AlignBottom|AlignLeft</set> + </property> + </widget> + <widget class="QLayoutWidget" row="2" column="2" rowspan="1" colspan="2"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Default pro&jects directory:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>projectsURL</cstring> + </property> + </widget> + <widget class="KURLRequester"> + <property name="name"> + <cstring>projectsURL</cstring> + </property> + <property name="focusPolicy"> + <enum>WheelFocus</enum> + </property> + <property name="toolTip" stdset="0"> + <string>Set the directory where you want your projects in.</string> + </property> + <property name="whatsThis" stdset="0"> + <string>By default, KDevelop uses a common parent directory for all new projects. Enter the absolute path of this common directory in the box or select it from your directory structure. KDevelop will place the any new project here as a subdirectory.</string> + </property> + </widget> + </hbox> + </widget> + <spacer row="1" column="0" rowspan="2" colspan="1"> + <property name="name"> + <cstring>spacer13</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget" row="4" column="2" rowspan="1" colspan="2"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>buttonLabel</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Window &font:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>outputFont</cstring> + </property> + <property name="toolTip" stdset="0"> + <string></string> + </property> + </widget> + <widget class="KFontRequester"> + <property name="name"> + <cstring>outputFont</cstring> + </property> + </widget> + </hbox> + </widget> + <spacer row="10" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>spacer13_2_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>16</width> + <height>60</height> + </size> + </property> + </spacer> + <widget class="QButtonGroup" row="12" column="3"> + <property name="name"> + <cstring>terminalButtonGroup</cstring> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="title"> + <string></string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton" row="0" column="0"> + <property name="name"> + <cstring>useKDETerminal</cstring> + </property> + <property name="text"> + <string>Use &KDE setting</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Use the terminal as set in KControl</string> + </property> + <property name="whatsThis" stdset="0"> + <string>If checked, KDevelop will use the default terminal as set in KControl in KDE components, Component Chooser.</string> + </property> + </widget> + <widget class="QLayoutWidget" row="1" column="0"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>useOtherTerminal</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Other:</string> + </property> + <property name="toolTip" stdset="0"> + <string>Set a different terminal than the KDE default one</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Choose some other terminal different from the default one.</string> + </property> + </widget> + <widget class="KLineEdit"> + <property name="name"> + <cstring>terminalEdit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + </hbox> + </widget> + </grid> + </widget> + <widget class="QLabel" row="11" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>textLabel5_2</cstring> + </property> + <property name="text"> + <string><qt><h3>Terminal Emulation</h3></qt></string> + </property> + <property name="alignment"> + <set>AlignTop</set> + </property> + </widget> + <spacer row="12" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>spacer13_2_2_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>50</height> + </size> + </property> + </spacer> + <spacer row="13" column="3"> + <property name="name"> + <cstring>spacer23</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>MinimumExpanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="9" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>textLabel5</cstring> + </property> + <property name="text"> + <string><qt><h3>UI Designer Integration</h3>This will only be used when no project is opened. For the project specific setting see Project Options/C++ Specific and open the Qt tab.</qt></string> + </property> + <property name="alignment"> + <set>WordBreak|AlignTop</set> + </property> + </widget> + <widget class="QButtonGroup" row="10" column="3"> + <property name="name"> + <cstring>designerButtonGroup</cstring> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="title"> + <string></string> + </property> + <property name="flat"> + <bool>false</bool> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QRadioButton" row="0" column="0"> + <property name="name"> + <cstring>embeddedDesignerRadioButton</cstring> + </property> + <property name="text"> + <string>&Use KDevelop's embedded designer</string> + </property> + <property name="toolTip" stdset="0"> + <string>Start KDevelop own designer embedded within KDevelop</string> + </property> + <property name="whatsThis" stdset="0"> + <string>KDevelop comes with its own UI designer that can either be embedded or be run as a separate program. Check this button if you wish to integrate the UI designer into KDevelop.</string> + </property> + </widget> + <widget class="QRadioButton" row="1" column="0"> + <property name="name"> + <cstring>seperateAppRadioButton</cstring> + </property> + <property name="text"> + <string>Run KDevelop's &designer as a separate application</string> + </property> + <property name="toolTip" stdset="0"> + <string>Start KDevelop own designer externally</string> + </property> + <property name="whatsThis" stdset="0"> + <string>KDevelop comes with its own UI designer that can either be embedded or be run as a separate program. Check this button if you wish to run KDevelop's UI designer as a separate program.</string> + </property> + </widget> + <widget class="QRadioButton" row="2" column="0"> + <property name="name"> + <cstring>qtDesignerRadioButton</cstring> + </property> + <property name="text"> + <string>Run &Qt Designer</string> + </property> + <property name="toolTip" stdset="0"> + <string>Use Qt Designer externally</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Check this button if you wish to use Qt Designer rather than KDevelop's integrated designer.</string> + </property> + </widget> + </grid> + </widget> + <widget class="QCheckBox" row="7" column="2" rowspan="1" colspan="2"> + <property name="name"> + <cstring>dirNavigMsgCheckBox</cstring> + </property> + <property name="text"> + <string>Directory &navigation messages</string> + </property> + <property name="accel"> + <string>Alt+N</string> + </property> + <property name="toolTip" stdset="0"> + <string>Check this if you want to know what directory make is in</string> + </property> + <property name="whatsThis" stdset="0"> + <string>The make tool usually will display messages like “Entering directory”, or “Leaving directory” when it switches the directories it currently works in. As this clutters the messages list in the Messages Output View window, KDevelop suppresses those messages by default. Mark the checkbox if you want to protocol which directories make worked in.</string> + </property> + </widget> + <spacer row="4" column="0" rowspan="5" colspan="1"> + <property name="name"> + <cstring>spacer13_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>16</width> + <height>150</height> + </size> + </property> + </spacer> + <widget class="QButtonGroup" row="8" column="1" rowspan="1" colspan="3"> + <property name="name"> + <cstring>buttonGroup3</cstring> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="title"> + <string></string> + </property> + <property name="alignment"> + <set>AlignAuto</set> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>6</number> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>forceCLocaleRadio</cstring> + </property> + <property name="text"> + <string>Force English compiler output</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>userLocaleRadio</cstring> + </property> + <property name="text"> + <string>Use kde language and disable "jump-to-source" functionality</string> + </property> + </widget> + </vbox> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>useOtherTerminal</sender> + <signal>toggled(bool)</signal> + <receiver>terminalEdit</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kfontrequester.h</includehint> + <includehint>klineedit.h</includehint> +</includehints> +</UI> diff --git a/src/shellextension.cpp b/src/shellextension.cpp new file mode 100644 index 00000000..8b9c4dbb --- /dev/null +++ b/src/shellextension.cpp @@ -0,0 +1,26 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "shellextension.h" + +ShellExtension *ShellExtension::s_instance = 0; + +ShellExtension::ShellExtension() +{ +} diff --git a/src/shellextension.h b/src/shellextension.h new file mode 100644 index 00000000..b0d91069 --- /dev/null +++ b/src/shellextension.h @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef SHELLEXTENSION_H +#define SHELLEXTENSION_H + +#include <qstring.h> + +class KDialogBase; + +/** +Shell extension. +Provides application-dependent and shell-independent functionality. +Shell uses extensions to perform application dependent actions. +*/ +class ShellExtension { +public: + /**Returns an instance of a shell. Subclasses must create an instance of a shell + by themselves. For example they could provide static init() method like: + @code + static void init() + { + s_instance = new MyExtension(); + } + @endcode*/ + static ShellExtension *getInstance() { return s_instance; } + + /**Reimplement to create global settings page in the dialog @p dlg.*/ + virtual void createGlobalSettingsPage(KDialogBase *dlg) = 0; + /**Reimplement to perform actions when the global settings page in the + dialog @p dlg is accepted (user clicked "Ok").*/ + virtual void acceptGlobalSettingsPage(KDialogBase *dlg) = 0; + + /**Reimplement to return the name of KXMLGUI resource file for an application.*/ + virtual QString xmlFile() = 0; + + /**Reimplement to set a default profile for the shell. Default profile + will be used by a shell if no --profile argument is specified.*/ + virtual QString defaultProfile() = 0; + +protected: + ShellExtension(); + static ShellExtension *s_instance; +}; + +#endif diff --git a/src/simplemainwindow.cpp b/src/simplemainwindow.cpp new file mode 100644 index 00000000..5b5e0345 --- /dev/null +++ b/src/simplemainwindow.cpp @@ -0,0 +1,1011 @@ +/*************************************************************************** + * Copyright (C) 2005 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "simplemainwindow.h" + +#include <qtextedit.h> + +#include <kaction.h> +#include <kstdaction.h> +#include <kparts/part.h> +#include <kpopupmenu.h> +#include <kmenubar.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kedittoolbar.h> +#include <ktexteditor/view.h> +#include <ktexteditor/document.h> +#include <kapplication.h> +#include <kurldrag.h> +#include <kconfig.h> + +#include <ddockwindow.h> +#include <dtabwidget.h> +#include <profile.h> +#include <profileengine.h> +#include <designer.h> +#include <kdevproject.h> +#include <urlutil.h> + +#include "api.h" +#include "core.h" +#include "plugincontroller.h" +#include "mainwindowshare.h" +#include "shellextension.h" +#include "partcontroller.h" +#include "statusbar.h" +#include "documentationpart.h" +#include "toplevel.h" +#include "projectmanager.h" +#include "editorproxy.h" +#include "multibuffer.h" + +SimpleMainWindow::SimpleMainWindow(QWidget* parent, const char *name) + :DMainWindow(parent, name) +{ + resize(800, 600); // starts kdevelop at 800x600 the first time + m_mainWindowShare = new MainWindowShare(this); + + connect(m_bottomDock, SIGNAL(hidden()), this, SLOT(raiseEditor())); + connect(m_leftDock, SIGNAL(hidden()), this, SLOT(raiseEditor())); + connect(m_rightDock, SIGNAL(hidden()), this, SLOT(raiseEditor())); +} + +SimpleMainWindow::~ SimpleMainWindow( ) +{ + TopLevel::invalidateInstance( this ); +} + +void SimpleMainWindow::init() +{ + actionCollection()->setHighlightingEnabled( true ); + setStandardToolBarMenuEnabled( true ); + setXMLFile(ShellExtension::getInstance()->xmlFile()); + + createFramework(); + createActions(); + new KDevStatusBar(this); + + setAcceptDrops(true); + + createGUI(0); + + m_mainWindowShare->init(); + setupWindowMenu(); + menuBar()->setEnabled( false ); + + //FIXME: this checks only for global offers which is not quite correct because + //a profile can offer core plugins and no global plugins. + if ( PluginController::getInstance()->engine().allOffers(ProfileEngine::Global).isEmpty() ) + { + KMessageBox::sorry( this, i18n("Unable to find plugins, KDevelop will not work" + " properly.\nPlease make sure " + "that KDevelop is installed in your KDE directory; otherwise, you have " + "to add KDevelop's installation " + "path to the environment variable KDEDIRS and run kbuildsycoca. Restart " + "KDevelop afterwards.\n" + "Example for BASH users:\nexport KDEDIRS=/path/to/kdevelop:$KDEDIRS && kbuildsycoca"), + i18n("Could Not Find Plugins") ); + } + + connect(Core::getInstance(), SIGNAL(coreInitialized()), this, SLOT(slotCoreInitialized())); + connect(Core::getInstance(), SIGNAL(projectOpened()), this, SLOT(projectOpened())); + connect(Core::getInstance(), SIGNAL(projectClosed()), this, SLOT(projectClosed())); + connect(Core::getInstance(), SIGNAL(contextMenu(QPopupMenu *, const Context *)), + this, SLOT(contextMenu(QPopupMenu *, const Context *))); + connect(PartController::getInstance(), SIGNAL(partURLChanged(KParts::ReadOnlyPart *)), + this, SLOT(slotPartURLChanged(KParts::ReadOnlyPart * ))); + connect(PartController::getInstance(), SIGNAL(activePartChanged(KParts::Part*)), + this, SLOT(activePartChanged(KParts::Part*))); + + connect(PartController::getInstance(), + SIGNAL(documentChangedState(const KURL &, DocumentState)), + this, SLOT(documentChangedState(const KURL&, DocumentState))); + + loadSettings(); +} + +void SimpleMainWindow::dragEnterEvent( QDragEnterEvent *event ) +{ + event->accept(KURLDrag::canDecode(event)); +} + +void SimpleMainWindow::dropEvent( QDropEvent *event ) +{ + slotDropEvent(event); +} + +void SimpleMainWindow::slotDropEvent( QDropEvent *event ) +{ + KURL::List list; + if ( !KURLDrag::decode( event, list ) ) return; + + KURL::List::Iterator it = list.begin(); + while( it != list.end() ) + { + kdDebug(9000) << "drop url:" << *it << endl; + PartController::getInstance()->editDocument( *it ); + ++it; + } +} + +void SimpleMainWindow::contextMenu(QPopupMenu *popupMenu, const Context *context) +{ + int cont = context->type(); + m_splitURLs.clear(); + if (cont == Context::EditorContext) + { + KURL url = static_cast<const EditorContext*>(context)->url(); + QWidget *w = widgetForURL(url); + if (w && m_widgetTabs[w] && m_widgetTabs[w]->count() > 1) + { + m_splitURLs.append(url); + m_splitHor1->plug(popupMenu); + m_splitVer1->plug(popupMenu); + popupMenu->insertSeparator(); + } + } + else if (cont == Context::FileContext) + { + if (PartController::getInstance()->openURLs().count() > 0) + { + KURL::List urls = static_cast<const FileContext*>(context)->urls(); + KURL::List::ConstIterator it = urls.begin(); + while ( it != urls.end() ) + { + if ( !URLUtil::isDirectory( *it ) ) + { + m_splitURLs.append( *it ); + } + ++it; + } + + if ( m_splitURLs.isEmpty() ) return; + + bool isOpen = true; + for (KURL::List::const_iterator it = m_splitURLs.begin(); it != m_splitURLs.end(); ++it) + { + if (!PartController::getInstance()->openURLs().contains(*it) && (*it).isValid()) + { + isOpen = false; + break; + } + } + + if ( (isOpen && PartController::getInstance()->openURLs().count() == 1) || + (m_splitURLs.count() == 1 && !(*m_splitURLs.begin()).isValid() ) ) + { + return; + } + + popupMenu->insertSeparator(); + if (isOpen) + { + m_splitHor1->plug(popupMenu); + m_splitVer1->plug(popupMenu); + } + else + { + m_splitHor2->plug(popupMenu); + m_splitVer2->plug(popupMenu); + } + } + } +} + +void SimpleMainWindow::embedPartView(QWidget *view, const QString &title, const QString &/*toolTip*/) +{ + kdDebug() << "SimpleMainWindow::embedPartView: " << view << endl; + if (!view ) + return; + + QString shortName = title; + shortName = shortName.right( shortName.length() - (shortName.findRev('/') +1)); + + addWidget(view, title); + view->show(); +} + +void SimpleMainWindow::embedSelectView(QWidget *view, const QString &title, const QString &/*toolTip*/) +{ + embedView( DDockWindow::Left, view, title ); +} + +void SimpleMainWindow::embedOutputView(QWidget *view, const QString &title, const QString &/*toolTip*/) +{ + embedView( DDockWindow::Bottom, view, title ); +} + +void SimpleMainWindow::embedSelectViewRight(QWidget *view, const QString &title, const QString &/*toolTip*/) +{ + embedView( DDockWindow::Right, view, title ); +} + +void SimpleMainWindow::embedView( DDockWindow::Position pos, QWidget * view, const QString & title ) +{ + if ( !hasDockWidget( view ) ) + { + DDockWindow::Position position = recallToolViewPosition( view->name(), pos ); + addDockWidget(position, view, title); + } +} + +DDockWindow::Position SimpleMainWindow::recallToolViewPosition( const QString & name, DDockWindow::Position defaultPos ) +{ + KConfig * config = kapp->config(); + config->setGroup( "DToolDockPosition" ); + + QString position = config->readEntry( name ); + + if ( name == "unknown" ) + { + kdDebug() << name << endl; + } + + if ( position == "DockLeft" ) return DDockWindow::Left; + if ( position == "DockRight" ) return DDockWindow::Right; + if ( position == "DockBottom" ) return DDockWindow::Bottom; + + return defaultPos; +} + +void SimpleMainWindow::rememberToolViewPosition( const QString & name, DDockWindow::Position pos ) +{ + KConfig * config = kapp->config(); + config->setGroup( "DToolDockPosition" ); + + QString position = "unknown"; + + switch( pos ) + { + case DDockWindow::Left: + position = "DockLeft"; + break; + case DDockWindow::Right: + position = "DockRight"; + break; + case DDockWindow::Bottom: + position = "DockBottom"; + break; + default: ; + } + + config->writeEntry( name, position ); +} + + +void SimpleMainWindow::removeView(QWidget *view) +{ + if (!view) + return; + + //try to remove it from all parts of main window + //@fixme This method needs to be divided in two - one for docks and one for part views + if (hasDockWidget(view)) + { + rememberToolViewPosition( view->name(), dockWidgetPosition(view) ); + removeDockWidget(view); + } + else + removeWidget(view); +} + +void SimpleMainWindow::setViewAvailable(QWidget *pView, bool bEnabled) +{ + DDockWindow *dock; + if (hasDockWidget(pView)) + dock = toolWindow(dockWidgetPosition(pView)); + else + return; + + bEnabled ? dock->showWidget(pView) : dock->hideWidget(pView); +} + +void SimpleMainWindow::raiseView(QWidget *view) +{ + //adymo: a workaround to make editor wrappers work: + //editor view is passed to this function but the ui library knows only + //of its parent which is an editor wrapper, simply replacing the view + //by its wrapper helps here + if (view->parent()) + kdDebug() << view->parent()->className() << endl; + if (view->parent() && (view->parent()->isA("EditorWrapper") || view->parent()->isA("MultiBuffer"))) + { +// kdDebug() << "parent is editor wrapper: " << +// static_cast<EditorWrapper*>(view->parent()) << endl; + view = (QWidget*)view->parent(); + } + + if (hasDockWidget(view)) + { + DDockWindow *dock = toolWindow(dockWidgetPosition(view)); + dock->raiseWidget(view); + } + else if (m_widgets.contains(view) && m_widgetTabs.contains(view)) + m_widgetTabs[view]->showPage(view); +} + +void SimpleMainWindow::lowerView(QWidget * view) +{ + if (!hasDockWidget(view)) + return; + + DDockWindow *dock = toolWindow(dockWidgetPosition(view)); + dock->lowerWidget(view); +} + +void SimpleMainWindow::loadSettings() +{ + KConfig *config = kapp->config(); + + ProjectManager::getInstance()->loadSettings(); + applyMainWindowSettings(config, "SimpleMainWindow"); + + Core::setupShourtcutTips(); +} + +void SimpleMainWindow::saveSettings( ) +{ + KConfig *config = kapp->config(); + + ProjectManager::getInstance()->saveSettings(); + saveMainWindowSettings(config, "SimpleMainWindow"); + + QMap<QWidget*, DDockWindow::Position>::iterator it = m_docks.begin(); + while ( it != m_docks.end() ) + { + if ( !strcmp(it.key()->name(), "unnamed") ) + { + kdError() << "Toolviews must have a name : " << it.key() << endl; + } + + rememberToolViewPosition( it.key()->name(), it.data() ); + ++it; + } + + DMainWindow::saveSettings(); +} + +void SimpleMainWindow::setCurrentDocumentCaption( const QString &caption ) +{ + if( !PartController::getInstance()->activePart() ) return; + + if (QWidget *widget = EditorProxy::getInstance()->topWidgetForPart(PartController::getInstance()->activePart())) + { + widget->setCaption(caption); + } +} + +KMainWindow *SimpleMainWindow::main() +{ + return this; +} + +void SimpleMainWindow::createFramework() +{ + PartController::createInstance( this ); + + connect(PartController::getInstance(), SIGNAL(activePartChanged(KParts::Part*)), + this, SLOT(createGUI(KParts::Part*))); +} + +void SimpleMainWindow::createActions() +{ + m_raiseEditor = new KAction(i18n("Raise &Editor"), ALT+Key_C, + this, SLOT(raiseEditor()), actionCollection(), "raise_editor"); + m_raiseEditor->setToolTip(i18n("Raise editor")); + m_raiseEditor->setWhatsThis(i18n("<b>Raise editor</b><p>Focuses the editor.")); + + m_lowerAllDocks = new KAction(i18n("Lower All Docks"), CTRL+SHIFT+Key_C, + this, SLOT(lowerAllDocks()), actionCollection(), "lower_all_docks"); + + new KAction(i18n("Switch to next TabWidget"), 0, this, + SLOT(switchToNextTabWidget()), actionCollection(), "switch_to_next_tabwidget" ); + + m_splitHor = new KAction(i18n("Split &Horizontal"), CTRL+SHIFT+Key_T, + this, SLOT(slotSplitHorizontalBase()), actionCollection(), "split_h"); + m_splitHor->setIcon("view_top_bottom"); + + m_splitVer = new KAction(i18n("Split &Vertical"), CTRL+SHIFT+Key_L, + this, SLOT(slotSplitVerticalBase()), actionCollection(), "split_v"); + m_splitVer->setIcon("view_left_right"); + + m_splitHor1 = new KAction(i18n("Split &Horizontal"), 0, + this, SLOT(slotSplitHorizontal()), actionCollection(), "split_h1"); + m_splitHor1->setIcon("view_top_bottom"); + + m_splitVer1 = new KAction(i18n("Split &Vertical"), 0, + this, SLOT(slotSplitVertical()), actionCollection(), "split_v1"); + m_splitVer1->setIcon("view_left_right"); + + m_splitHor2 = new KAction(i18n("Split &Horizontal and Open"), 0, + this, SLOT(slotSplitHorizontal()), actionCollection(), "split_h2"); + m_splitHor2->setIcon("view_top_bottom"); + + m_splitVer2 = new KAction(i18n("Split &Vertical and Open"), 0, + this, SLOT(slotSplitVertical()), actionCollection(), "split_v2"); + m_splitVer2->setIcon("view_left_right"); + + m_raiseLeftDock = new KAction(i18n("Switch Left Dock"), CTRL+SHIFT+ALT+Key_L, + this, SLOT(raiseLeftDock()), actionCollection(), "switch_left_dock"); + + m_raiseRightDock = new KAction(i18n("Switch Right Dock"), CTRL+SHIFT+ALT+Key_R, + this, SLOT(raiseRightDock()), actionCollection(), "switch_right_dock"); + + m_raiseBottomDock = new KAction(i18n("Switch Bottom Dock"), CTRL+SHIFT+ALT+Key_B, + this, SLOT(raiseBottomDock()), actionCollection(), "switch_bottom_dock"); + + KStdAction::configureToolbars(this, SLOT(configureToolbars()), + actionCollection(), "set_configure_toolbars"); + + m_mainWindowShare->createActions(); + + connect(m_mainWindowShare, SIGNAL(gotoNextWindow()), this, SLOT(gotoNextWindow())); + connect(m_mainWindowShare, SIGNAL(gotoPreviousWindow()), this, SLOT(gotoPreviousWindow())); + connect(m_mainWindowShare, SIGNAL(gotoFirstWindow()), this, SLOT(gotoFirstWindow())); + connect(m_mainWindowShare, SIGNAL(gotoLastWindow()), this, SLOT(gotoLastWindow())); +} + +void SimpleMainWindow::raiseEditor() +{ + kdDebug() << "SimpleMainWindow::raiseEditor" << endl; + KDevPartController *partcontroller = API::getInstance()->partController(); + if (partcontroller->activePart() && partcontroller->activePart()->widget()) + partcontroller->activePart()->widget()->setFocus(); +} + +void SimpleMainWindow::gotoNextWindow() +{ + if (m_bottomDock->isActive()) + m_bottomDock->selectNextWidget(); + else if (m_rightDock->isActive()) + m_rightDock->selectNextWidget(); + else if (m_leftDock->isActive()) + m_leftDock->selectNextWidget(); + else + { + if ((m_activeTabWidget->currentPageIndex() + 1) < m_activeTabWidget->count()) + m_activeTabWidget->setCurrentPage(m_activeTabWidget->currentPageIndex() + 1); + else + m_activeTabWidget->setCurrentPage(0); + } +} + +void SimpleMainWindow::gotoPreviousWindow() +{ + if (m_bottomDock->isActive()) + m_bottomDock->selectPrevWidget(); + else if (m_rightDock->isActive()) + m_rightDock->selectPrevWidget(); + else if (m_leftDock->isActive()) + m_leftDock->selectPrevWidget(); + else + { + if ((m_activeTabWidget->currentPageIndex() - 1) >= 0) + m_activeTabWidget->setCurrentPage(m_activeTabWidget->currentPageIndex() - 1); + else + m_activeTabWidget->setCurrentPage(m_activeTabWidget->count() - 1); + } +} + +void SimpleMainWindow::gotoFirstWindow() +{ + //@TODO: Implement me +} + +void SimpleMainWindow::gotoLastWindow() +{ + //@TODO: implement me +} + +void SimpleMainWindow::slotCoreInitialized() +{ + menuBar()->setEnabled(true); +} + +void SimpleMainWindow::projectOpened() +{ + setCaption(QString::null); +} + +void SimpleMainWindow::slotPartURLChanged(KParts::ReadOnlyPart *part) +{ + if (QWidget *widget = EditorProxy::getInstance()->topWidgetForPart(part)) + { + kdDebug() << "new caption for widget: " << part->url().fileName() << endl; + widget->setCaption(part->url().fileName()); + } + //do smth with caption: ro_part->url().fileName() +} + +void SimpleMainWindow::documentChangedState(const KURL &url, DocumentState state) +{ + QWidget * widget = EditorProxy::getInstance()->topWidgetForPart( + PartController::getInstance()->partForURL(url)); + kdDebug() << "SimpleMainWindow::documentChangedState: " << widget << endl; + if (widget) + { + //calculate the icon size if showTabIcons is false + //this is necessary to avoid tab resizing by setIcon() call + int isize = 16; + if (m_activeTabWidget && !m_showIconsOnTabs) + { + isize = m_activeTabWidget->fontMetrics().height() - 1; + isize = isize > 16 ? 16 : isize; + } + switch (state) + { + // we should probably restore the original icon instead of just using "kdevelop", + // but I have never seen any other icon in use so this should do for now + case Clean: + if (m_showIconsOnTabs) + widget->setIcon(SmallIcon("kdevelop", isize)); + else + widget->setIcon(QPixmap()); + break; + case Modified: + widget->setIcon(SmallIcon("filesave", isize)); + break; + case Dirty: + widget->setIcon(SmallIcon("revert", isize)); + break; + case DirtyAndModified: + widget->setIcon(SmallIcon("stop", isize)); + break; + } + } + setCaption(url.url()); +} + +void SimpleMainWindow::closeTab() +{ +// actionCollection()->action("file_close")->activate(); + if (sender()->isA("QToolButton") && sender()->parent()->isA("DTabWidget")) + { + DTabWidget *tab = (DTabWidget*)sender()->parent(); + if (tab && tab->currentPage()) + closeTab(tab->currentPage()); + } +} + +void SimpleMainWindow::tabContext(QWidget *w, const QPoint &p) +{ + DTabWidget *tabWidget = static_cast<DTabWidget*>(const_cast<QObject*>(sender())); + if (!tabWidget) + return; + + KPopupMenu tabMenu; + tabMenu.insertTitle(tabWidget->tabLabel(w)); + + //Find the document on whose tab the user clicked + m_currentTabURL = QString::null; + QPtrListIterator<KParts::Part> it(*PartController::getInstance()->parts()); + while (KParts::Part* part = it.current()) + { + QWidget *top_widget = EditorProxy::getInstance()->topWidgetForPart(part); + if (top_widget == w) + { + if (KParts::ReadOnlyPart *ro_part = dynamic_cast<KParts::ReadOnlyPart*>(part)) + { + m_currentTabURL = ro_part->url(); + tabMenu.insertItem(i18n("Close"), 0); + + if (PartController::getInstance()->parts()->count() > 1) + tabMenu.insertItem(i18n("Close All Others"), 4); + + if( KParts::ReadWritePart * rw_part = dynamic_cast<KParts::ReadWritePart*>( ro_part ) ) + { + if( rw_part->isModified() ) tabMenu.insertItem( i18n("Save"),1); + tabMenu.insertItem( i18n("Reload"),2); + } + + if (dynamic_cast<HTMLDocumentationPart*>(ro_part)) + { + tabMenu.insertItem(i18n("Duplicate"), 3); + break; + } + + //Create the file context + KURL::List list; + list << m_currentTabURL; + FileContext context( list ); + Core::getInstance()->fillContextMenu(&tabMenu, &context); + } + break; + } + ++it; + } + + connect(&tabMenu, SIGNAL(activated(int)), this, SLOT(tabContextActivated(int))); + tabMenu.exec(p); +} + +void SimpleMainWindow::tabContextActivated(int id) +{ + if(m_currentTabURL.isEmpty()) + return; + + switch(id) + { + case 0: + PartController::getInstance()->closeFile(m_currentTabURL); + break; + case 1: + PartController::getInstance()->saveFile(m_currentTabURL); + break; + case 2: + PartController::getInstance()->reloadFile(m_currentTabURL); + break; + case 3: + PartController::getInstance()->showDocument(m_currentTabURL, true); + break; + case 4: + PartController::getInstance()->closeAllOthers(m_currentTabURL); + break; + default: + break; + } +} + +void SimpleMainWindow::configureToolbars() +{ + saveMainWindowSettings(KGlobal::config(), "SimpleMainWindow"); + KEditToolbar dlg(factory()); + connect(&dlg, SIGNAL(newToolbarConfig()), this, SLOT(slotNewToolbarConfig())); + dlg.exec(); +} + +void SimpleMainWindow::slotNewToolbarConfig() +{ +// setupWindowMenu(); + m_mainWindowShare->slotGUICreated(PartController::getInstance()->activePart()); + applyMainWindowSettings(KGlobal::config(), "SimpleMainWindow"); +} + +bool SimpleMainWindow::queryClose() +{ + saveSettings(); + return Core::getInstance()->queryClose(); +} + +bool SimpleMainWindow::queryExit() +{ + return true; +} + +void SimpleMainWindow::setupWindowMenu() +{ + // get the xmlgui created one instead + m_windowMenu = static_cast<QPopupMenu*>(main()->child("window", "KPopupMenu")); + + if (!m_windowMenu) + { + kdDebug(9000) << "Couldn't find the XMLGUI window menu. Creating new." << endl; + + m_windowMenu = new QPopupMenu(main(), "window"); + menuBar()->insertItem(i18n("&Window"), m_windowMenu); + } + + actionCollection()->action("file_close")->plug(m_windowMenu); + actionCollection()->action("file_close_all")->plug(m_windowMenu); + actionCollection()->action("file_closeother")->plug(m_windowMenu); + + QObject::connect(m_windowMenu, SIGNAL(activated(int)), this, SLOT(openURL(int))); + QObject::connect(m_windowMenu, SIGNAL(aboutToShow()), this, SLOT(fillWindowMenu())); +} + +void SimpleMainWindow::openURL(int w) +{ + QValueList<QPair<int, KURL> >::ConstIterator it = m_windowList.begin(); + while (it != m_windowList.end()) + { + if ((*it).first == w) + { + KURL url((*it).second); + if (!url.isEmpty()) + { + PartController::getInstance()->editDocument(url); + return; + } + } + ++it; + } +} + +void SimpleMainWindow::fillWindowMenu() +{ + // clear menu + QValueList< QPair< int, KURL > >::ConstIterator it = m_windowList.begin(); + while (it != m_windowList.end()) + { + m_windowMenu->removeItem( (*it).first ); + ++it; + } + + int temp = 0; + + QMap<QString, KURL> map; + QStringList string_list; + KURL::List list = PartController::getInstance()->openURLs(); + KURL::List::Iterator itt = list.begin(); + while (itt != list.end()) + { + map[(*itt).fileName()] = *itt; + string_list.append((*itt).fileName()); + ++itt; + } + string_list.sort(); + + list.clear(); + for(uint i = 0; i != string_list.size(); ++i) + list.append(map[string_list[i]]); + + itt = list.begin(); + int i = 0; + + if (list.count() > 0) + m_windowList << qMakePair(m_windowMenu->insertSeparator(), KURL()); + + while (itt != list.end()) + { + temp = m_windowMenu->insertItem( i < 10 ? QString("&%1 %2").arg(i).arg((*itt).fileName()) : (*itt).fileName() ); + m_windowList << qMakePair(temp, *itt); + ++i; + ++itt; + } +} + +void SimpleMainWindow::slotSplitVertical() +{ + DTabWidget *tab = splitVertical(); + openDocumentsAfterSplit(tab); +} + +void SimpleMainWindow::slotSplitHorizontal() +{ + DTabWidget *tab = splitHorizontal(); + openDocumentsAfterSplit(tab); +} + +void SimpleMainWindow::slotSplitVerticalBase() +{ + if (KParts::ReadOnlyPart *ro_part = activePartForSplitting()) + { + m_splitURLs << ro_part->url(); + slotSplitVertical(); + } +} + +KParts::ReadOnlyPart *SimpleMainWindow::activePartForSplitting() +{ + if (PartController::getInstance()->openURLs().count() < 2) + return 0; + m_splitURLs.clear(); + KParts::ReadOnlyPart *ro_part = + dynamic_cast<KParts::ReadOnlyPart*>(PartController::getInstance()->activePart()); + return ro_part; +} + +void SimpleMainWindow::slotSplitHorizontalBase() +{ + if (KParts::ReadOnlyPart *ro_part = activePartForSplitting()) + { + m_splitURLs << ro_part->url(); + slotSplitHorizontal(); + } +} + +void SimpleMainWindow::openDocumentsAfterSplit(DTabWidget *tab) +{ + if (m_splitURLs.count() > 0) + { + for (KURL::List::const_iterator it = m_splitURLs.begin(); it != m_splitURLs.end(); ++it) + { + KParts::ReadOnlyPart *part = PartController::getInstance()->partForURL(*it); + if (!part) + PartController::getInstance()->editDocument(*it); + else + { + PartController::getInstance()->activatePart( part ); + QWidget *inTab = widgetForURL(*it); + if (inTab) + { + DTabWidget *oldTab = m_widgetTabs[inTab]; + QString title = oldTab->tabLabel(inTab); + removeWidget(inTab); + addWidget(tab, inTab, title); + } + } + } + m_splitURLs.clear(); + } +} + +QWidget *SimpleMainWindow::widgetForURL(KURL url) +{ + KParts::ReadOnlyPart *part = PartController::getInstance()->partForURL(url); + return widgetInTab( part ? part->widget() : 0 ); +} + +QWidget *SimpleMainWindow::widgetInTab(QWidget *w) +{ + QWidget *inTab = 0; + if (w && w->parent() && w->parent()->isA("EditorProxy")) + inTab = (QWidget*)w->parent(); + else if (w && w->parent() && w->parent()->isA("MultiBuffer") + && w->parent()->parent() && w->parent()->parent()->isA("EditorProxy")) + inTab = (QWidget*)w->parent()->parent(); + else if (w && w->parent() && w->parent()->isA("MultiBuffer")) + inTab = (QWidget*)w->parent(); + else + inTab = w; + return inTab; +} + +void SimpleMainWindow::closeTab(QWidget *w) +{ + const QPtrList<KParts::Part> *partlist = PartController::getInstance()->parts(); + QPtrListIterator<KParts::Part> it(*partlist); + while (KParts::Part* part = it.current()) + { + QWidget *widget = EditorProxy::getInstance()->topWidgetForPart(part); + if (widget && widget == w) + { + // weirdness beyond weirdness.. sometimes the active view is an embedded splitter with two files + // so we check if the widget is a multibuffer, in which case we let it decide what part to close + if (MultiBuffer * mb = dynamic_cast<MultiBuffer*>( widget ) ) + { + PartController::getInstance()->closePart( mb->activeBuffer() ); + } + else + { + PartController::getInstance()->closePart(part); + } + return; + } + ++it; + } +} + +void SimpleMainWindow::activePartChanged(KParts::Part *part) +{ + if (!part) + return; + QWidget *w = part->widget(); + kdDebug() << "active part widget is : " << w << endl; + QWidget *inTab = widgetInTab(w); + if (m_widgetTabs[inTab] != 0) + { + kdDebug() << " setting m_activeTabWidget " << endl; + m_activeTabWidget = m_widgetTabs[inTab]; + } +} + +void SimpleMainWindow::createGUI(KParts::Part *part) { + if ( !part ) + setCaption( QString::null ); + DMainWindow::createGUI(part); + + m_mainWindowShare->slotGUICreated( part ); +} + +void SimpleMainWindow::raiseBottomDock() +{ + raiseDock(m_bottomDock); +} + +void SimpleMainWindow::raiseLeftDock() +{ + raiseDock(m_leftDock); +} + +void SimpleMainWindow::raiseRightDock() +{ + raiseDock(m_rightDock); +} + +void SimpleMainWindow::raiseDock(DDockWindow *dock) +{ + dock->selectLastWidget(); +} + +void SimpleMainWindow::lowerAllDocks() +{ + m_bottomDock->lowerWidget( m_bottomDock->currentWidget() ); + m_leftDock->lowerWidget( m_leftDock->currentWidget() ); + m_rightDock->lowerWidget( m_rightDock->currentWidget() ); +} + +void SimpleMainWindow::switchToNextTabWidget() +{ + QValueList<DTabWidget*> tabWidgets = m_widgetTabs.values(); + + if ( tabWidgets.count() < 2 ) return; + + QValueList<DTabWidget*> reduced; + QValueList<DTabWidget*>::iterator it = tabWidgets.begin(); + while ( it != tabWidgets.end() ) + { + if ( !reduced.contains( *it ) ) + { + reduced << *it; + } + ++it; + } + + it = reduced.begin(); + while ( it != reduced.end() ) + { + if ( *it == m_activeTabWidget ) + { + if ( ++it != reduced.end() ) + { + if ( (*it)->currentPage() ) + (*it)->currentPage()->setFocus(); + } + else + { + if ( (*reduced.begin())->currentPage() ) + (*reduced.begin())->currentPage()->setFocus(); + } + return; + } + ++it; + } +} + +void SimpleMainWindow::setCaption(const QString &caption) +{ + kdDebug(9000) << k_funcinfo << endl; + + bool modified = false; + if ( !caption.isEmpty() ) + { + KURL url( caption ); + DocumentState const state = PartController::getInstance()->documentState( url ); + modified = ( state == Modified || state == DirtyAndModified ); + } + + KDevProject *project = API::getInstance()->project(); + if (project) + { + QString projectname = project->projectName(); + + QString suffix(".kdevelop"); + if (projectname.endsWith(suffix)) + projectname.truncate(projectname.length() - suffix.length()); + + if (!caption.isEmpty()) + DMainWindow::setCaption(projectname + " - " + caption, modified); + else + DMainWindow::setCaption(projectname, modified); + } + else + DMainWindow::setCaption(caption, modified); +} + +void SimpleMainWindow::projectClosed() +{ + DMainWindow::setCaption(QString::null); +} + +#include "simplemainwindow.moc" + +// kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on diff --git a/src/simplemainwindow.h b/src/simplemainwindow.h new file mode 100644 index 00000000..f7df3e1a --- /dev/null +++ b/src/simplemainwindow.h @@ -0,0 +1,140 @@ +/*************************************************************************** + * Copyright (C) 2005 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program 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 program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef SIMPLEMAINWINDOW_H +#define SIMPLEMAINWINDOW_H + +#include <dmainwindow.h> +#include <kdevplugin.h> +#include <kdevmainwindow.h> +#include <kdevpartcontroller.h> + +class KAction; +class QPopupMenu; +class MainWindowShare; +class Context; + +namespace KParts { + class ReadOnlyPart; +} + +class SimpleMainWindow: public DMainWindow, public KDevMainWindow { + Q_OBJECT +public: + SimpleMainWindow(QWidget* parent = 0, const char *name = 0); + virtual ~SimpleMainWindow(); + + virtual void embedPartView(QWidget *view, const QString &title, const QString& toolTip = QString::null); + virtual void embedSelectView(QWidget *view, const QString &title, const QString &toolTip); + virtual void embedOutputView(QWidget *view, const QString &title, const QString &toolTip); + virtual void embedSelectViewRight(QWidget* view, const QString& title, const QString &toolTip); + + virtual void removeView(QWidget *view); + virtual void setViewAvailable(QWidget *pView, bool bEnabled); + virtual void raiseView(QWidget *view); + virtual void lowerView(QWidget *view); + + virtual void loadSettings(); + virtual void saveSettings(); + virtual void setCurrentDocumentCaption( const QString &caption ); + + virtual KMainWindow *main(); + + void init(); + +public slots: + void slotDropEvent( QDropEvent *event ); + void setCaption(const QString &); + +protected: + virtual bool queryClose(); + virtual bool queryExit(); + +protected slots: + virtual void closeTab(); + virtual void closeTab(QWidget *w); + virtual void tabContext(QWidget *w, const QPoint &p); + void contextMenu(QPopupMenu *popupMenu, const Context *context); + +private slots: + void gotoNextWindow(); + void gotoPreviousWindow(); + void gotoFirstWindow(); + void gotoLastWindow(); + void switchToNextTabWidget(); + void slotCoreInitialized(); + void projectOpened(); + void projectClosed(); + void slotPartURLChanged(KParts::ReadOnlyPart *part); + void activePartChanged(KParts::Part *part); + void documentChangedState(const KURL &url, DocumentState state); + void tabContextActivated(int); + void configureToolbars(); + void slotNewToolbarConfig(); + void raiseEditor(); + void openURL(int w); + void fillWindowMenu(); + void slotSplitVertical(); + void slotSplitHorizontal(); + void slotSplitVerticalBase(); + void slotSplitHorizontalBase(); + void createGUI(KParts::Part *part); + void raiseBottomDock(); + void raiseLeftDock(); + void raiseRightDock(); + void raiseDock(DDockWindow *dock); + void lowerAllDocks(); + +private: + void createFramework(); + void createActions(); + void setupWindowMenu(); + void dragEnterEvent( QDragEnterEvent *event ); + void dropEvent( QDropEvent *event ); + void openDocumentsAfterSplit(DTabWidget *tab); + QWidget *widgetForURL(KURL url); + QWidget *widgetInTab(QWidget *w); + KParts::ReadOnlyPart *activePartForSplitting(); + void embedView( DDockWindow::Position position, QWidget *view, const QString & title ); + DDockWindow::Position recallToolViewPosition( const QString & name, DDockWindow::Position defaultPos ); + void rememberToolViewPosition( const QString & name, DDockWindow::Position pos ); + + MainWindowShare *m_mainWindowShare; + + KURL m_currentTabURL; + KAction *m_raiseEditor; + KAction *m_lowerAllDocks; + KAction *m_splitHor; + KAction *m_splitVer; + KAction *m_splitHor1; + KAction *m_splitVer1; + KAction *m_splitHor2; + KAction *m_splitVer2; + KAction *m_raiseBottomDock; + KAction *m_raiseLeftDock; + KAction *m_raiseRightDock; + QPopupMenu *m_windowMenu; + QValueList<QPair<int, KURL> > m_windowList; + + KURL::List m_splitURLs; +}; + +// kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on + +#endif diff --git a/src/splashscreen.cpp b/src/splashscreen.cpp new file mode 100644 index 00000000..0c7ac7f2 --- /dev/null +++ b/src/splashscreen.cpp @@ -0,0 +1,85 @@ + +#include "splashscreen.h" +#include "splashscreen.moc" + +#include <config.h> + +#include <qtimer.h> +#include <qfont.h> + +#include <klocale.h> +#include <kglobalsettings.h> + +KDevSplashScreen::KDevSplashScreen(const QPixmap& pixmap, WFlags f) : QSplashScreen(pixmap, f) +{ + QTimer *timer = new QTimer( this ); + QObject::connect(timer, SIGNAL(timeout()), this, SLOT(animate())); + timer->start(150); + + state = 0; + progress_bar_size = 3; +} + + +KDevSplashScreen::~KDevSplashScreen() +{ +} + + +void KDevSplashScreen::animate() +{ + state = ((state + 1) % (2*progress_bar_size-1)); + repaint(); +} + + +void KDevSplashScreen::message( const QString &str, int flags, const QColor &color) +{ + QSplashScreen::message(str,flags,color); + animate(); + m_string = str; +} + + +void KDevSplashScreen::drawContents (QPainter* painter) +{ + int position; + QColor base_color (201,229,165); // Base green color + + // Draw background circles + painter->setPen(NoPen); + painter->setBrush(QColor(215,234,181)); + painter->drawEllipse(51,7,9,9); + painter->drawEllipse(62,7,9,9); + painter->drawEllipse(73,7,9,9); + + // Draw animated circles, increments are chosen + // to get close to background's color + // (didn't work well with QColor::light function) + for (int i=0; i < progress_bar_size; i++) + { + position = (state+i)%(2*progress_bar_size-1); + painter->setBrush(QColor(base_color.red()-18*i, + base_color.green()-10*i, + base_color.blue()-28*i)); + + if (position < 3) painter->drawEllipse(51+position*11,7,9,9); + } + + painter->setPen(QColor(74,112,18)); + QFont fnt(KGlobalSettings::generalFont()); + fnt.setPointSize(8); + painter->setFont(fnt); + + // Draw version number + QRect r = rect(); + r.setRect(r.x() + 5, r.y() + 5, r.width() - 10, r.height() - 10); + painter->drawText(r, Qt::AlignRight, i18n("Version %1").arg( VERSION )); + + // Draw message at given position, limited to 43 chars + // If message is too long, string is truncated + if (m_string.length() > 40) {m_string.truncate(39); m_string += "...";} + painter->drawText (90, 16, m_string, 42); + +} + diff --git a/src/splashscreen.h b/src/splashscreen.h new file mode 100644 index 00000000..15114f3f --- /dev/null +++ b/src/splashscreen.h @@ -0,0 +1,38 @@ + +#ifndef _SPLASHSCREEN_H_ +#define _SPLASHSCREEN_H_ + +#include <qsplashscreen.h> +#include <qpainter.h> +#include <qlabel.h> + +class QPixmap; + +/** +Splash screen. +*/ +class KDevSplashScreen : public QSplashScreen +{ +Q_OBJECT + +public: + KDevSplashScreen(const QPixmap& pixmap, WFlags f = 0); + virtual ~KDevSplashScreen(); + +protected: + void drawContents (QPainter * painter); + +public slots: + void animate(); + void message( const QString &str, int flags = AlignLeft, + const QColor &color = black ); + +private: + int state; + int progress_bar_size; + QString m_string; + +}; + +#endif + diff --git a/src/statusbar.cpp b/src/statusbar.cpp new file mode 100644 index 00000000..cff28b3e --- /dev/null +++ b/src/statusbar.cpp @@ -0,0 +1,112 @@ +/*************************************************************************** + * Copyright (C) 2001 by Bernd Gehrmann * + * bernd@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <qlayout.h> +#include <qlineedit.h> +#include <qpainter.h> +#include <qtimer.h> +#include <qfontmetrics.h> + +#include <kdebug.h> +#include <kglobalsettings.h> +#include <klocale.h> +#include <kparts/part.h> +#include <ktexteditor/viewcursorinterface.h> +#include <kdeversion.h> + +#include <ktexteditor/viewstatusmsginterface.h> + +#include "statusbar.h" +#include "partcontroller.h" + +KDevStatusBar::KDevStatusBar(QWidget *parent, const char *name) + : KStatusBar(parent, name), _cursorIface(0), _activePart(0) +{ + QWidget * w = new QWidget( this ); + addWidget( w, 1, true ); + w->hide(); + + _status = new QLabel( this ); + _status->setMinimumWidth(_status->fontMetrics().width("Line: XXXXX Col: XXX OVR NORM * ")); + _status->setAlignment(QWidget::AlignCenter); + addWidget(_status, 0, true); + + connect(PartController::getInstance(), SIGNAL(activePartChanged(KParts::Part*)), + this, SLOT(activePartChanged(KParts::Part*))); +} + + +KDevStatusBar::~KDevStatusBar() +{} + +void KDevStatusBar::activePartChanged(KParts::Part *part) +{ + if ( _activePart && _activePart->widget() ) + disconnect( _activePart->widget(), 0, this, 0 ); + + _activePart = part; + _cursorIface = 0; + _viewmsgIface = 0; + + if (part && part->widget()) + { + if ((_viewmsgIface = dynamic_cast<KTextEditor::ViewStatusMsgInterface*>(part->widget()))) + { + connect( part->widget(), SIGNAL( viewStatusMsg( const QString & ) ), + this, SLOT( setStatus( const QString & ) ) ); + + _status->show(); + } + else if ((_cursorIface = dynamic_cast<KTextEditor::ViewCursorInterface*>(part->widget()))) + { + connect(part->widget(), SIGNAL(cursorPositionChanged()), this, SLOT(cursorPositionChanged())); + + _status->show(); + cursorPositionChanged(); + } + else + { + // we can't produce any status data, hide the status box + _status->hide(); + } + } +} + +void KDevStatusBar::cursorPositionChanged() +{ + if (_cursorIface) + { + uint line, col; + _cursorIface->cursorPosition(&line, &col); + setCursorPosition(line, col); + } +} + +void KDevStatusBar::setStatus(const QString &str) +{ + _status->setText(str); +} + + +void KDevStatusBar::setCursorPosition(int line, int col) +{ + _status->setText(i18n(" Line: %1 Col: %2 ").arg(line+1).arg(col)); +} + +void KDevStatusBar::addWidget ( QWidget *widget, int stretch, bool permanent) +{ + KStatusBar::addWidget(widget,stretch,permanent); + + if(widget->sizeHint().height() + 4 > height()) + setFixedHeight(widget->sizeHint().height() + 4); +} + +#include "statusbar.moc" diff --git a/src/statusbar.h b/src/statusbar.h new file mode 100644 index 00000000..30b80724 --- /dev/null +++ b/src/statusbar.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2001 by Bernd Gehrmann * + * bernd@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _STATUSBAR_H_ +#define _STATUSBAR_H_ + +#include <kstatusbar.h> +#include <qmap.h> + +class QLabel; + +namespace KTextEditor { class ViewStatusMsgInterface; } +namespace KTextEditor { class ViewCursorInterface; } +namespace KParts { class Part; } + +/** +Status bar. +*/ +class KDevStatusBar : public KStatusBar +{ + Q_OBJECT + +public: + KDevStatusBar( QWidget *parent=0, const char *name=0 ); + ~KDevStatusBar(); + void addWidget ( QWidget *widget, int stretch = 0, bool permanent = FALSE ); + +private slots: + void cursorPositionChanged(); + void activePartChanged(KParts::Part *part); + void setStatus(const QString &str); + void setCursorPosition(int line, int col); + +private: + QLabel *_status; + + KTextEditor::ViewCursorInterface * _cursorIface; + KTextEditor::ViewStatusMsgInterface * _viewmsgIface; + KParts::Part *_activePart; + +}; + +#endif diff --git a/src/toplevel.cpp b/src/toplevel.cpp new file mode 100644 index 00000000..048b325c --- /dev/null +++ b/src/toplevel.cpp @@ -0,0 +1,35 @@ +#include <kxmlguiclient.h> +#include <kapplication.h> +#include <kconfig.h> + + +#include "toplevel.h" +#include "core.h" + +#include "simplemainwindow.h" + +KDevMainWindow *TopLevel::s_instance = 0; + +bool TopLevel::mainWindowValid() +{ + return s_instance != 0; +} + +KDevMainWindow *TopLevel::getInstance() +{ + if (!s_instance) + { + SimpleMainWindow *mainWindow = new SimpleMainWindow(0, "SimpleMainWindow"); + s_instance = mainWindow; + mainWindow->init(); + kapp->setMainWidget(mainWindow); + } + + return s_instance; +} + +void TopLevel::invalidateInstance(KDevMainWindow *instance) +{ + if ( s_instance == instance ) + s_instance = 0; +} diff --git a/src/toplevel.h b/src/toplevel.h new file mode 100644 index 00000000..8eb0243a --- /dev/null +++ b/src/toplevel.h @@ -0,0 +1,27 @@ +#ifndef __TOPLEVEL_H__ +#define __TOPLEVEL_H__ + + +#include "kdevmainwindow.h" + + +/**\brief This class handles the single object of type KDevMainWindow. + +It is completely static (all methods and attributes). +*/ + +class TopLevel +{ +public: + + static KDevMainWindow *getInstance(); //!< Get a pointer to the single KDevTopLevel object + static bool mainWindowValid(); + static void invalidateInstance(KDevMainWindow *instance); //!< Signal that the object has been (or is about to be) destroyed + +private: + + static KDevMainWindow *s_instance; //!< Pointer to the single KDevTopLevel object or 0L + +}; + +#endif |