summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSlávek Banko <slavek.banko@axis.cz>2013-10-07 23:28:24 +0200
committerSlávek Banko <slavek.banko@axis.cz>2013-10-08 05:14:51 +0200
commit3af5832abe7c802a384cd58d34f7cc4433595ced (patch)
treecc300d6fae4cb5798f0cf5db3ece63026f34379a /src
downloadkscope-3af5832abe7c802a384cd58d34f7cc4433595ced.tar.gz
kscope-3af5832abe7c802a384cd58d34f7cc4433595ced.zip
Initial import of kscope 1.6.2
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am68
-rw-r--r--src/autocompletionlayout.ui217
-rw-r--r--src/bookmark.pngbin0 -> 690 bytes
-rw-r--r--src/bookmarksdlg.cpp60
-rw-r--r--src/bookmarksdlg.h53
-rw-r--r--src/bookmarkslayout.ui116
-rw-r--r--src/call_graph.pngbin0 -> 741 bytes
-rw-r--r--src/called_tree.pngbin0 -> 463 bytes
-rw-r--r--src/calling_tree.pngbin0 -> 445 bytes
-rw-r--r--src/calltreedlg.cpp336
-rw-r--r--src/calltreedlg.h111
-rw-r--r--src/calltreelayout.ui430
-rw-r--r--src/calltreemanager.cpp136
-rw-r--r--src/calltreemanager.h71
-rw-r--r--src/configfrontend.cpp172
-rw-r--r--src/configfrontend.h77
-rw-r--r--src/cscopefrontend.cpp524
-rw-r--r--src/cscopefrontend.h186
-rw-r--r--src/cscopemsgdlg.cpp66
-rw-r--r--src/cscopemsgdlg.h49
-rw-r--r--src/cscopemsglayout.ui79
-rw-r--r--src/ctagsfrontend.cpp179
-rw-r--r--src/ctagsfrontend.h77
-rw-r--r--src/ctagslist.cpp446
-rw-r--r--src/ctagslist.h108
-rw-r--r--src/dirscanner.cpp164
-rw-r--r--src/dirscanner.h144
-rw-r--r--src/dotfrontend.cpp297
-rw-r--r--src/dotfrontend.h76
-rw-r--r--src/dotparse.ypp234
-rw-r--r--src/dotscan.lpp36
-rw-r--r--src/editormanager.cpp89
-rw-r--r--src/editormanager.h56
-rw-r--r--src/editorpage.cpp720
-rw-r--r--src/editorpage.h215
-rw-r--r--src/editortabs.cpp640
-rw-r--r--src/editortabs.h129
-rw-r--r--src/encoder.cpp114
-rw-r--r--src/encoder.h53
-rw-r--r--src/file_ro.pngbin0 -> 892 bytes
-rw-r--r--src/file_rw.pngbin0 -> 647 bytes
-rw-r--r--src/file_save.pngbin0 -> 838 bytes
-rw-r--r--src/filelist.cpp197
-rw-r--r--src/filelist.h75
-rw-r--r--src/fileview.cpp131
-rw-r--r--src/fileview.h80
-rw-r--r--src/fileviewlayout.ui136
-rw-r--r--src/frontend.cpp365
-rw-r--r--src/frontend.h212
-rw-r--r--src/graphedge.cpp306
-rw-r--r--src/graphedge.h143
-rw-r--r--src/graphnode.cpp192
-rw-r--r--src/graphnode.h123
-rw-r--r--src/graphprefdlg.cpp82
-rw-r--r--src/graphprefdlg.h54
-rw-r--r--src/graphpreflayout.ui262
-rw-r--r--src/graphwidget.cpp1162
-rw-r--r--src/graphwidget.h213
-rw-r--r--src/hi16-app-kscope.pngbin0 -> 815 bytes
-rw-r--r--src/hi32-app-kscope.pngbin0 -> 1828 bytes
-rw-r--r--src/historypage.cpp124
-rw-r--r--src/historypage.h72
-rw-r--r--src/historyview.cpp124
-rw-r--r--src/historyview.h91
-rw-r--r--src/kscope.cpp1754
-rw-r--r--src/kscope.desktop12
-rw-r--r--src/kscope.h235
-rw-r--r--src/kscope.lsm16
-rw-r--r--src/kscope_config165
-rw-r--r--src/kscopeactions.cpp533
-rw-r--r--src/kscopeactions.h98
-rw-r--r--src/kscopeconfig.cpp768
-rw-r--r--src/kscopeconfig.h218
-rw-r--r--src/kscopepixmaps.cpp376
-rw-r--r--src/kscopepixmaps.h77
-rw-r--r--src/kscopeui.rc141
-rw-r--r--src/lo16-app-kscope.pngbin0 -> 326 bytes
-rw-r--r--src/lo32-app-kscope.pngbin0 -> 308 bytes
-rw-r--r--src/main.cpp97
-rw-r--r--src/makedlg.cpp267
-rw-r--r--src/makedlg.h78
-rw-r--r--src/makefrontend.cpp134
-rw-r--r--src/makefrontend.h61
-rw-r--r--src/makelayout.ui245
-rw-r--r--src/newprojectdlg.cpp354
-rw-r--r--src/newprojectdlg.h112
-rw-r--r--src/newprojectlayout.ui778
-rw-r--r--src/openprojectdlg.cpp131
-rw-r--r--src/openprojectdlg.h61
-rw-r--r--src/openprojectlayout.ui202
-rw-r--r--src/prefcolor.cpp172
-rw-r--r--src/prefcolor.h59
-rw-r--r--src/prefcolorlayout.ui69
-rw-r--r--src/preferencesdlg.cpp206
-rw-r--r--src/preferencesdlg.h93
-rw-r--r--src/preffont.cpp174
-rw-r--r--src/preffont.h60
-rw-r--r--src/preffontlayout.ui69
-rw-r--r--src/preffrontend.cpp238
-rw-r--r--src/preffrontend.h65
-rw-r--r--src/preffrontendlayout.ui193
-rw-r--r--src/prefopt.cpp145
-rw-r--r--src/prefopt.h58
-rw-r--r--src/prefoptlayout.ui217
-rw-r--r--src/progressdlg.cpp116
-rw-r--r--src/progressdlg.h66
-rw-r--r--src/project.cpp442
-rw-r--r--src/project.h92
-rw-r--r--src/projectbase.cpp190
-rw-r--r--src/projectbase.h281
-rw-r--r--src/projectfilesdlg.cpp439
-rw-r--r--src/projectfilesdlg.h104
-rw-r--r--src/projectfileslayout.ui201
-rw-r--r--src/projectmanager.cpp180
-rw-r--r--src/projectmanager.h56
-rw-r--r--src/query_locked.pngbin0 -> 774 bytes
-rw-r--r--src/query_unlocked.pngbin0 -> 923 bytes
-rw-r--r--src/querypage.cpp211
-rw-r--r--src/querypage.h86
-rw-r--r--src/querypagebase.cpp194
-rw-r--r--src/querypagebase.h148
-rw-r--r--src/queryresultsmenu.cpp170
-rw-r--r--src/queryresultsmenu.h110
-rw-r--r--src/queryview.cpp444
-rw-r--r--src/queryview.h217
-rw-r--r--src/queryviewdlg.cpp111
-rw-r--r--src/queryviewdlg.h88
-rw-r--r--src/queryviewdriver.cpp180
-rw-r--r--src/queryviewdriver.h84
-rw-r--r--src/queryviewlayout.ui167
-rw-r--r--src/querywidget.cpp601
-rw-r--r--src/querywidget.h152
-rw-r--r--src/querywidgetlayout.ui62
-rw-r--r--src/scanprogressdlg.cpp82
-rw-r--r--src/scanprogressdlg.h69
-rw-r--r--src/scanprogresslayout.ui115
-rw-r--r--src/searchlist.cpp270
-rw-r--r--src/searchlist.h144
-rw-r--r--src/searchresultsdlg.cpp160
-rw-r--r--src/searchresultsdlg.h74
-rw-r--r--src/searchresultslayout.ui214
-rw-r--r--src/symbolcompletion.cpp344
-rw-r--r--src/symbolcompletion.h195
-rw-r--r--src/symboldlg.cpp334
-rw-r--r--src/symboldlg.h91
-rw-r--r--src/symbollayout.ui297
-rw-r--r--src/tab_list.pngbin0 -> 279 bytes
-rw-r--r--src/tabwidget.cpp84
-rw-r--r--src/tabwidget.h59
-rw-r--r--src/treewidget.cpp260
-rw-r--r--src/treewidget.h82
-rw-r--r--src/welcomedlg.ui126
152 files changed, 27595 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..e82522d
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,68 @@
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = bookmarksdlg.h calltreedlg.h calltreemanager.h \
+ configfrontend.h cscopefrontend.h cscopemsgdlg.h ctagsfrontend.h ctagslist.h \
+ dirscanner.h dotfrontend.h editormanager.h editorpage.h editortabs.h encoder.h \
+ filelist.h fileview.h frontend.h graphedge.h graphnode.h graphprefdlg.h \
+ graphwidget.h historypage.h historyview.h kscope.h kscopeactions.h kscopeconfig.h \
+ kscopepixmaps.h makedlg.h makefrontend.h newprojectdlg.h openprojectdlg.h prefcolor.h \
+ preferencesdlg.h preffont.h preffrontend.h prefopt.h progressdlg.h project.h \
+ projectbase.h projectfilesdlg.h projectmanager.h querypage.h querypagebase.h \
+ queryresultsmenu.h queryview.h queryviewdlg.h queryviewdriver.h querywidget.h \
+ scanprogressdlg.h searchlist.h searchresultsdlg.h symbolcompletion.h symboldlg.h \
+ tabwidget.h treewidget.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/kscope.pot
+
+KDE_ICON = kscope
+
+#########################################################################
+# APPLICATION SECTION
+#########################################################################
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+bin_PROGRAMS = kscope
+
+# the application source, library search path, and link libraries
+kscope_SOURCES = autocompletionlayout.ui bookmarksdlg.cpp bookmarkslayout.ui \
+ calltreedlg.cpp calltreelayout.ui calltreemanager.cpp configfrontend.cpp \
+ cscopefrontend.cpp cscopemsgdlg.cpp cscopemsglayout.ui ctagsfrontend.cpp ctagslist.cpp \
+ dirscanner.cpp dotfrontend.cpp dotparse.ypp dotscan.lpp editormanager.cpp \
+ editorpage.cpp editortabs.cpp encoder.cpp filelist.cpp fileview.cpp fileviewlayout.ui \
+ frontend.cpp graphedge.cpp graphnode.cpp graphprefdlg.cpp graphpreflayout.ui \
+ graphwidget.cpp historypage.cpp historyview.cpp kscope.cpp kscopeactions.cpp \
+ kscopeconfig.cpp kscopepixmaps.cpp main.cpp makedlg.cpp makefrontend.cpp makelayout.ui \
+ newprojectdlg.cpp newprojectlayout.ui openprojectdlg.cpp openprojectlayout.ui \
+ prefcolor.cpp prefcolorlayout.ui preferencesdlg.cpp preffont.cpp preffontlayout.ui \
+ preffrontend.cpp preffrontendlayout.ui prefopt.cpp prefoptlayout.ui progressdlg.cpp \
+ project.cpp projectbase.cpp projectfilesdlg.cpp projectfileslayout.ui \
+ projectmanager.cpp querypage.cpp querypagebase.cpp queryresultsmenu.cpp queryview.cpp \
+ queryviewdlg.cpp queryviewdriver.cpp queryviewlayout.ui querywidget.cpp \
+ querywidgetlayout.ui scanprogressdlg.cpp scanprogresslayout.ui searchlist.cpp \
+ searchresultsdlg.cpp searchresultslayout.ui symbolcompletion.cpp symboldlg.cpp \
+ symbollayout.ui tabwidget.cpp treewidget.cpp welcomedlg.ui
+
+kscope_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+kscope_LDADD = -lkateinterfaces -lktexteditor $(LIB_KDEUI)
+
+# this is where the desktop file will go
+shelldesktopdir = $(kde_appsdir)/Development
+shelldesktop_DATA = kscope.desktop
+
+# this is where the shell's XML-GUI resource file goes
+shellrcdir = $(kde_datadir)/kscope
+shellrc_DATA = kscopeui.rc kscope_config
+
+picsdir = $(kde_datadir)/kscope/pics
+pics_DATA = file_ro.png file_rw.png file_save.png query_locked.png \
+ query_unlocked.png tab_list.png call_graph.png called_tree.png calling_tree.png \
+ bookmark.png
+
+BUILT_SOURCES = dotparse.h
+AM_YFLAGS = -d
diff --git a/src/autocompletionlayout.ui b/src/autocompletionlayout.ui
new file mode 100644
index 0000000..2c8c274
--- /dev/null
+++ b/src/autocompletionlayout.ui
@@ -0,0 +1,217 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>AutoCompletionLayout</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>AutoCompletionLayout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>287</width>
+ <height>183</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Auto-Completion Properties</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout20</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Minimum Characters</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer15</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>71</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>m_pMinCharsSpin</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout21</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Delay (ms)</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer16</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>101</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>m_pDelaySpin</cstring>
+ </property>
+ <property name="maxValue">
+ <number>10000</number>
+ </property>
+ <property name="lineStep">
+ <number>100</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout22</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Maximum Entries</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer17</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>81</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>m_pMaxEntriesSpin</cstring>
+ </property>
+ <property name="maxValue">
+ <number>1000</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer19</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout23</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer18</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>111</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pOKButton</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pCancelButton</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/src/bookmark.png b/src/bookmark.png
new file mode 100644
index 0000000..5e76158
--- /dev/null
+++ b/src/bookmark.png
Binary files differ
diff --git a/src/bookmarksdlg.cpp b/src/bookmarksdlg.cpp
new file mode 100644
index 0000000..577476a
--- /dev/null
+++ b/src/bookmarksdlg.cpp
@@ -0,0 +1,60 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2007 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include "bookmarksdlg.h"
+#include "queryview.h"
+
+BookmarksDlg::BookmarksDlg(QWidget* pParent, const char* szName) :
+ BookmarksLayout (pParent, szName, true)
+{
+ // Do not show the "Function" column
+ m_pView->setColumnWidth(0, 0);
+
+ // Handle requests for source locations
+ connect(m_pView, SIGNAL(lineRequested(const QString&, uint)), this,
+ SLOT(slotLineRequested(const QString&, uint)));
+}
+
+BookmarksDlg::~BookmarksDlg()
+{
+}
+
+void BookmarksDlg::getBookmark(QString& sPath, uint& nLine)
+{
+ sPath = m_sPath;
+ nLine = m_nLine;
+}
+
+void BookmarksDlg::slotLineRequested(const QString& sPath, uint nLine)
+{
+ m_sPath = sPath;
+ m_nLine = nLine;
+ accept();
+}
+
+#include "bookmarksdlg.moc"
+
diff --git a/src/bookmarksdlg.h b/src/bookmarksdlg.h
new file mode 100644
index 0000000..ab74f9d
--- /dev/null
+++ b/src/bookmarksdlg.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2007 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef BOOKMARKSDLG_H
+#define BOOKMARKSDLG_H
+
+#include "bookmarkslayout.h"
+
+class BookmarksDlg : public BookmarksLayout
+{
+Q_OBJECT
+
+public:
+ BookmarksDlg(QWidget* pParent = 0, const char* szName = 0);
+ ~BookmarksDlg();
+
+ QueryView* getView() { return m_pView; }
+ void getBookmark(QString&, uint&);
+
+private:
+ QString m_sPath;
+ uint m_nLine;
+
+private slots:
+ void slotLineRequested(const QString&, uint);
+};
+
+#endif
+
diff --git a/src/bookmarkslayout.ui b/src/bookmarkslayout.ui
new file mode 100644
index 0000000..f1f8135
--- /dev/null
+++ b/src/bookmarkslayout.ui
@@ -0,0 +1,116 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>BookmarksLayout</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>BookmarksLayout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>480</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Global Bookmarks</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QueryView">
+ <property name="name">
+ <cstring>m_pView</cstring>
+ </property>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </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>291</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pCloseButton</cstring>
+ </property>
+ <property name="text">
+ <string>Close</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>QueryView</class>
+ <header location="local">queryview.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="XBM.GZ" length="79">789c534e494dcbcc4b554829cdcdad8c2fcf4c29c95030e0524611cd48cd4ccf28010a1797249664262b2467241641a592324b8aa363156c15aab914146aadb90067111b1f</data>
+ </image>
+</images>
+<connections>
+ <connection>
+ <sender>m_pCloseButton</sender>
+ <signal>clicked()</signal>
+ <receiver>BookmarksLayout</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>queryview.h</includehint>
+</includehints>
+</UI>
diff --git a/src/call_graph.png b/src/call_graph.png
new file mode 100644
index 0000000..0b87ddd
--- /dev/null
+++ b/src/call_graph.png
Binary files differ
diff --git a/src/called_tree.png b/src/called_tree.png
new file mode 100644
index 0000000..db58776
--- /dev/null
+++ b/src/called_tree.png
Binary files differ
diff --git a/src/calling_tree.png b/src/calling_tree.png
new file mode 100644
index 0000000..89e40d2
--- /dev/null
+++ b/src/calling_tree.png
Binary files differ
diff --git a/src/calltreedlg.cpp b/src/calltreedlg.cpp
new file mode 100644
index 0000000..65ee4f8
--- /dev/null
+++ b/src/calltreedlg.cpp
@@ -0,0 +1,336 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qfile.h>
+#include <qtoolbutton.h>
+#include <qbuttongroup.h>
+#include <qwidgetstack.h>
+#include <klocale.h>
+#include <kfiledialog.h>
+#include "calltreedlg.h"
+#include "graphwidget.h"
+#include "treewidget.h"
+#include "kscopepixmaps.h"
+#include "kscopeconfig.h"
+#include "graphprefdlg.h"
+
+/** The currently supported version of saved call-tree files. */
+#define FILE_VERSION 5
+
+/** Window flags for call-tree widgets. */
+#define CALL_TREE_W_FLAGS \
+ WStyle_Customize | \
+ WStyle_NormalBorder | \
+ WStyle_Title | \
+ WDestructiveClose
+
+/** File Name index for the file name generation */
+int CallTreeDlg::s_nFileNameIndex = 0;
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+CallTreeDlg::CallTreeDlg(QWidget* pParent, const char* szName) :
+ CallTreeLayout(pParent, szName, CALL_TREE_W_FLAGS)
+{
+ // Set button pixmaps
+ m_pCalledButton->setPixmap(GET_PIXMAP(CalledTree));
+ m_pCallingButton->setPixmap(GET_PIXMAP(CallingTree));
+ m_pGraphButton->setPixmap(GET_PIXMAP(CallGraph));
+ m_pSaveButton->setPixmap(GET_PIXMAP(ButtonSaveAs));
+ m_pZoomInButton->setPixmap(GET_PIXMAP(ButtonZoomIn));
+ m_pZoomOutButton->setPixmap(GET_PIXMAP(ButtonZoomOut));
+ m_pRotateButton->setPixmap(GET_PIXMAP(ButtonRotate));
+ m_pPrefButton->setPixmap(GET_PIXMAP(ButtonPref));
+
+ // Open the location of a call
+ connect(m_pGraphWidget, SIGNAL(lineRequested(const QString&, uint)),
+ this, SIGNAL(lineRequested(const QString&, uint)));
+ connect(m_pCalledWidget, SIGNAL(lineRequested(const QString&, uint)),
+ this, SIGNAL(lineRequested(const QString&, uint)));
+ connect(m_pCallingWidget, SIGNAL(lineRequested(const QString&, uint)),
+ this, SIGNAL(lineRequested(const QString&, uint)));
+
+ m_pCallingWidget->setMode(TreeWidget::Calling);
+
+ // Get the default view from KScope's configuration
+ m_nDefView = Config().getDefGraphView();
+}
+
+/**
+ * Class destructor.
+ */
+CallTreeDlg::~CallTreeDlg()
+{
+}
+
+/**
+ * @param sFunc The function to use as the root of the call tree
+ */
+void CallTreeDlg::setRoot(const QString& sFunc)
+{
+ m_sRoot = sFunc;
+
+ // Generate unique file name to save call tree later
+ m_sFileName = sFunc;
+ m_sFileName.replace(' ', '_');
+ m_sFileName += QString::number(++s_nFileNameIndex);
+
+ // Set the root item in all views
+ m_pGraphWidget->setRoot(sFunc);
+ m_pCalledWidget->setRoot(sFunc);
+ m_pCallingWidget->setRoot(sFunc);
+}
+
+/**
+ * Displays the dialogue.
+ */
+void CallTreeDlg::show()
+{
+ // Set the default view.
+ m_pViewGroup->setButton(m_nDefView);
+ m_pStack->raiseWidget(m_nDefView);
+ slotViewChanged(m_nDefView);
+
+ CallTreeLayout::show();
+}
+
+/**
+ * Informs the call tree manager that this object should be removed from the
+ * list of call tree dialogues.
+ * The close event is received when the dialogue is explicitly closed by the
+ * user. This dialogue will not appear when the project is reopened, and it
+ * is therefore safe to delete the graph file at this point.
+ * @param pEvent Information on the closing event
+ */
+void CallTreeDlg::closeEvent(QCloseEvent* pEvent)
+{
+ if (!m_sFilePath.isEmpty())
+ QFile::remove(m_sFilePath);
+
+ emit closed(this);
+ QWidget::closeEvent(pEvent);
+}
+
+extern void yyinit(CallTreeDlg*, FILE*, Encoder*);
+extern int yyparse();
+
+/**
+ * Restores a call tree from the given call tree file.
+ * NOTE: The call tree file is deleted when loading is complete.
+ * @param sProjPath The full path of the project directory
+ * @param sFileName The name of the call tree file to load
+ * @return true if successful, false otherwise
+ */
+bool CallTreeDlg::load(const QString& sProjPath, const QString& sFileName)
+{
+ QString sPath;
+ FILE* pFile;
+ int nVersion, nView, nResult;
+ Encoder enc;
+
+ // Create the full path name
+ sPath = sProjPath + "/" + sFileName;
+
+ // Open the file for reading
+ pFile = fopen(sPath.latin1(), "r");
+ if (pFile == NULL)
+ return false;
+
+ // Check file version
+ if ((fscanf(pFile, "VERSION=%d\n", &nVersion) != 1) ||
+ (nVersion != FILE_VERSION)) {
+ fclose(pFile);
+ return false;
+ }
+
+ // Get default view
+ if ((fscanf(pFile, "View=%d\n", &nView) == 1) &&
+ (nView >= 0) &&
+ (nView <= 2)) {
+ m_nDefView = nView;
+ }
+
+ // Read the call trees and the graph stored on this file
+ yyinit(this, pFile, &enc);
+ nResult = yyparse();
+
+ // Close the file
+ fclose(pFile);
+
+ // Check the result returned by the parser
+ if (nResult != 0)
+ return false;
+
+ // Store the file name
+ m_sFileName = sFileName;
+ m_sFilePath = sPath;
+
+ // Draw the graph
+ m_pGraphWidget->draw();
+ return true;
+}
+
+/**
+ * Writes the contents of the call tree dialog to a call tree file.
+ * This method is called for call trees before the owner project is
+ * closed.
+ * @param sProjPath The full path of the project directory
+ */
+void CallTreeDlg::store(const QString& sProjPath)
+{
+ QString sPath;
+ FILE* pFile;
+
+ // Create the full file path
+ sPath = sProjPath + "/" + m_sFileName;
+ m_sFilePath = sPath;
+
+ // Open a file for writing (create if necessary)
+ pFile = fopen(sPath.latin1(), "w+");
+ if (pFile == NULL)
+ return;
+
+ // Write header
+ fprintf(pFile, "VERSION=%d\n", FILE_VERSION);
+ fprintf(pFile, "View=%d\n", m_pViewGroup->selectedId());
+
+ // Save the contents of all widgets
+ m_pCalledWidget->save(pFile);
+ m_pCallingWidget->save(pFile);
+ m_pGraphWidget->save(pFile);
+
+ // Close the file
+ fclose(pFile);
+}
+
+/**
+ * Saves the graph to a dot file.
+ * The user is prompted for a name to use for the file, and then graph
+ * widget writes its information to this file (using the dot language).
+ * This slot is connected to the clicked() signal of the "Save As..." button.
+ */
+void CallTreeDlg::slotSaveClicked()
+{
+ QString sFile;
+
+ // Prompt the user for a file name
+ sFile = KFileDialog::getSaveFileName(":kscope");
+
+ // Save the graph to a file (unless the user did not give a file name)
+ if (!sFile.isEmpty())
+ m_pGraphWidget->save(sFile);
+}
+
+/**
+ * Increases the zoom factor of the graph.
+ * This slot is connected to the clicked() signal of the "Zoom In" button.
+ */
+void CallTreeDlg::slotZoomInClicked()
+{
+ m_pGraphWidget->zoom(true);
+ m_pGraphWidget->draw();
+}
+
+/**
+ * Decreases the zoom factor of the graph.
+ * This slot is connected to the clicked() signal of the "Zoom Out" button.
+ */
+void CallTreeDlg::slotZoomOutClicked()
+{
+ m_pGraphWidget->zoom(false);
+ m_pGraphWidget->draw();
+}
+
+/**
+ * Changes the graph's layout direction.
+ * This slot is connected to the clicked() signal of the "Rotate" button.
+ */
+void CallTreeDlg::slotRotateClicked()
+{
+ m_pGraphWidget->rotate();
+ m_pGraphWidget->draw();
+}
+
+/**
+ * Opens the call graph preferences dialogue.
+ * This slot is connected to the clicked() signal of the "Preferences" button.
+ */
+void CallTreeDlg::slotPrefClicked()
+{
+ GraphPrefDlg dlg(this);
+ int nMaxNodeDegree;
+
+ if (dlg.exec() == QDialog::Accepted) {
+ nMaxNodeDegree = dlg.getMaxNodeDegree();
+ Config().setGraphMaxNodeDegree(nMaxNodeDegree);
+ m_pGraphWidget->setMaxNodeDegree(nMaxNodeDegree);
+ }
+}
+
+/**
+ * Prepares the selected view.
+ * This slot is called when the user chooses a different view through the
+ * toggle buttons in the dialogue's toolbar.
+ * @param nView Identifies the selected view
+ */
+void CallTreeDlg::slotViewChanged(int nView)
+{
+ switch (nView) {
+ case 0:
+ // Call graph
+ setCaption(i18n("Call Graph"));
+ m_pGraphGroup->setEnabled(true);
+ m_pHelpLabel->setText(i18n("Right-click a function node or an arrow "
+ "head for more options."));
+ break;
+
+ case 1:
+ // Called functions tree
+ setCaption(i18n("Called Functions Tree"));
+ m_pGraphGroup->setEnabled(false);
+ m_pHelpLabel->setText(i18n("Right-click a tree item for more "
+ "options."));
+ m_pCalledWidget->queryRoot();
+ break;
+
+ case 2:
+ // Calling functions tree
+ setCaption(i18n("Calling Functions Tree"));
+ m_pGraphGroup->setEnabled(false);
+ m_pHelpLabel->setText(i18n("Right-click a tree item for more "
+ "options."));
+ m_pCallingWidget->queryRoot();
+ break;
+ }
+
+ Config().setDefGraphView(nView);
+}
+
+#include "calltreedlg.moc"
diff --git a/src/calltreedlg.h b/src/calltreedlg.h
new file mode 100644
index 0000000..d5f567b
--- /dev/null
+++ b/src/calltreedlg.h
@@ -0,0 +1,111 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef CALLTREEDLG_H
+#define CALLTREEDLG_H
+
+#include <qwidget.h>
+#include <qlistview.h>
+#include <calltreelayout.h>
+
+/**
+ * A multiple-view window showing function call information.
+ * The available views are:
+ * - Call graph, showing both calling and call functions
+ * - Called functions tree
+ * - Calling functions tree
+ * NOTE: This is class is now derived from QWidget instead of QDialog. This
+ * means that call-trees are independent windows, which can be maximised or
+ * minimised.
+ * @author Elad Lahav
+ */
+class CallTreeDlg : public CallTreeLayout
+{
+ Q_OBJECT
+
+public:
+ CallTreeDlg(QWidget* pParent = 0, const char* szName = 0);
+ ~CallTreeDlg();
+
+ void setRoot(const QString&);
+ bool load(const QString&, const QString&);
+ void store(const QString&);
+
+ /** Returns Call Tree filename */
+ QString getFileName() { return m_sFileName; }
+
+public slots:
+ virtual void show();
+
+signals:
+ /**
+ * Emitted when the user makes a request to view the contents of a
+ * location in the source code.
+ * This can be the location of a call, the definition of a function,
+ * etc.
+ * @param sPath The full path of the file to show
+ * @param nLine The line number in this file
+ */
+ void lineRequested(const QString& sPath, uint nLine);
+
+ /**
+ * Emitted when the user closes the tree view.
+ */
+ void closed(const CallTreeDlg*);
+
+protected:
+ virtual void closeEvent(QCloseEvent*);
+
+protected slots:
+ virtual void slotSaveClicked();
+ virtual void slotZoomInClicked();
+ virtual void slotZoomOutClicked();
+ virtual void slotRotateClicked();
+ virtual void slotPrefClicked();
+ virtual void slotViewChanged(int);
+
+private:
+ /** The root function. */
+ QString m_sRoot;
+
+ /** A unique file name used for storing the call tree on a file.
+ The name is a combination of the root function and an incremented
+ index. */
+ QString m_sFileName;
+
+ /** The full path of the file on which the call tree was saved
+ (empty if this graph was never stored). */
+ QString m_sFilePath;
+
+ /** The view to show when the dialogue is first displayed. */
+ int m_nDefView;
+
+ /** An index for the generating unique file names. */
+ static int s_nFileNameIndex;
+};
+
+#endif
diff --git a/src/calltreelayout.ui b/src/calltreelayout.ui
new file mode 100644
index 0000000..2562977
--- /dev/null
+++ b/src/calltreelayout.ui
@@ -0,0 +1,430 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>CallTreeLayout</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>CallTreeLayout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>695</width>
+ <height>578</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Call Graph</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>m_pViewGroup</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <property name="exclusive">
+ <bool>true</bool>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QToolButton">
+ <property name="name">
+ <cstring>m_pGraphButton</cstring>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="toggleButton">
+ <bool>true</bool>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Call Graph</string>
+ </property>
+ </widget>
+ <widget class="QToolButton">
+ <property name="name">
+ <cstring>m_pCalledButton</cstring>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="toggleButton">
+ <bool>true</bool>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Called Functions Tree</string>
+ </property>
+ </widget>
+ <widget class="QToolButton">
+ <property name="name">
+ <cstring>m_pCallingButton</cstring>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="toggleButton">
+ <bool>true</bool>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Calling Functions Tree</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>VLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>m_pGraphGroup</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QToolButton">
+ <property name="name">
+ <cstring>m_pSaveButton</cstring>
+ </property>
+ <property name="text">
+ <string>a</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Save As...</string>
+ </property>
+ </widget>
+ <widget class="QToolButton">
+ <property name="name">
+ <cstring>m_pZoomInButton</cstring>
+ </property>
+ <property name="text">
+ <string>a</string>
+ </property>
+ <property name="toggleButton">
+ <bool>false</bool>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Zoom In</string>
+ </property>
+ </widget>
+ <widget class="QToolButton">
+ <property name="name">
+ <cstring>m_pZoomOutButton</cstring>
+ </property>
+ <property name="text">
+ <string>a</string>
+ </property>
+ <property name="toggleButton">
+ <bool>false</bool>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Zoom Out</string>
+ </property>
+ </widget>
+ <widget class="QToolButton">
+ <property name="name">
+ <cstring>m_pRotateButton</cstring>
+ </property>
+ <property name="text">
+ <string>a</string>
+ </property>
+ <property name="toggleButton">
+ <bool>false</bool>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Rotate</string>
+ </property>
+ </widget>
+ <widget class="QToolButton">
+ <property name="name">
+ <cstring>m_pPrefButton</cstring>
+ </property>
+ <property name="text">
+ <string>a</string>
+ </property>
+ <property name="toggleButton">
+ <bool>false</bool>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Preferences</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>110</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QWidgetStack">
+ <property name="name">
+ <cstring>m_pStack</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </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>
+ <widget class="GraphWidget">
+ <property name="name">
+ <cstring>m_pGraphWidget</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>WStackPage</cstring>
+ </property>
+ <attribute name="id">
+ <number>1</number>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="TreeWidget">
+ <property name="name">
+ <cstring>m_pCalledWidget</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>WStackPage</cstring>
+ </property>
+ <attribute name="id">
+ <number>2</number>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="TreeWidget">
+ <property name="name">
+ <cstring>m_pCallingWidget</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_pHelpLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Help Message</string>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>GraphWidget</class>
+ <header location="local">graphwidget.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>7</hordata>
+ <verdata>7</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+ <customwidget>
+ <class>TreeWidget</class>
+ <header location="local">treewidget.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>7</hordata>
+ <verdata>7</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="1003">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b249444154388db5944d4c5c5518869f73ce9db9cc40f929cc30300e18129a50685268a28291982e1a2175212eaab1c49d3f8971e7aec6aedb54a32b435dd8685cb8c0c4b8b0feb421b7bd8186a069d23209144b18cb0c02f3732ff3c3ccbdd705a571941213f1dd9d93739ef37e6fbeef08d334d9d5d0d090c701c8344d2176c1a6697a5d5d5dd8b64d2a95c2b2ac7f05b12c8b783c8e6118d8b6fd685fdb753a39394928e2a7c55724d693a7e214104220242805520a84d8b9e4790f0b1302c7751958f1e30534be9fa41a0c60db362dbe227f64af91b6e7719c2dfc0117a71c603da591de2882a7d3d4ec27122b10acad50aeb88044d542b84de3af7ab44aa55274f4e449dbf354bc347aa096fbf37e7efa2ecbad1b36907d78b289de8120232f37726250c3f52cf0a026a0f6065b9645d929e038167aa096d91b307171059034b5f8e9e9eb44fa052b4b25eeccd9dc99cb71f6ad082fbea2e351c075bdbdc13b9109fc01b83fef63e2e232e03076b68393231a0dcd024daf502c1e66e67a89cb971ef0e5a74bb4b61e6378248094b92ab0ac024b70ca017ef8360394187b2dc6d8b89ffa500e4d4f93d9083275d5e6f9913ade3dd70ee87c7d25c95646a25415aadab152b09ed4f8c5cc130a853839eac3951b684a61e70ef3f9c739668c24eba912afbfddc6d4d506e6a6d7b8b7d082aa8eb8dab19482cdcd220e36dd3dc19df23545de0a71f952861923493456cfd3cf36123c54a0b7bf0e8064621b21f7712c040857071ca4eea0f40a99f510573ec971cb48030e811a1faded3e94be85f2fb00703d1ff26f96ab9f011a5b04d0c4f26fdb948a754c1b25668c2491483d5d5d611617d6b8f0fe32cb779b492ce65168b4c774a4701eefd8f3a02d56e6e8f13aeefe9a63fa5a89d1970e91d908f3d46003e1480d173e28b37827c9b977348ab92ce16890237d1ec907ee3e8e3d8f60d0e1f4583d009f7d9860662acff89bad1c1faad0717493f7ce7713ed8cb0995c255f2a317a26427b67198f6a70f51c0a41b902279ed1187f23cc17130b7c74de65eac77a7a8f05517e41e2deefa4930576db60fa7a8ee1535134df3e93e7b82e0817476439fd6a9070a49f6fbe4a3077739db99b15c001146dd13a46cf1cc1f83943c62e51de76b0738fc9381e8f3390f0236b252e124999e11724fd833196164bacadb87848224fe874f779b43fe9f2dca928956d505a96dbb3f9bdc18661e00534c26d1a7a40e13912a11c9454280da41048a9915c75585df500074d53d816dc9edd229528ef0db66dbbea3ffdaffa471f1f28d8344df1bf800f1a6e9aa6f813c39885bc050f269c0000000049454e44ae426082</data>
+ </image>
+</images>
+<connections>
+ <connection>
+ <sender>m_pPrefButton</sender>
+ <signal>clicked()</signal>
+ <receiver>CallTreeLayout</receiver>
+ <slot>slotPrefClicked()</slot>
+ </connection>
+ <connection>
+ <sender>m_pRotateButton</sender>
+ <signal>clicked()</signal>
+ <receiver>CallTreeLayout</receiver>
+ <slot>slotRotateClicked()</slot>
+ </connection>
+ <connection>
+ <sender>m_pZoomOutButton</sender>
+ <signal>clicked()</signal>
+ <receiver>CallTreeLayout</receiver>
+ <slot>slotZoomOutClicked()</slot>
+ </connection>
+ <connection>
+ <sender>m_pZoomInButton</sender>
+ <signal>clicked()</signal>
+ <receiver>CallTreeLayout</receiver>
+ <slot>slotZoomInClicked()</slot>
+ </connection>
+ <connection>
+ <sender>m_pSaveButton</sender>
+ <signal>clicked()</signal>
+ <receiver>CallTreeLayout</receiver>
+ <slot>slotSaveClicked()</slot>
+ </connection>
+ <connection>
+ <sender>m_pViewGroup</sender>
+ <signal>clicked(int)</signal>
+ <receiver>CallTreeLayout</receiver>
+ <slot>slotViewChanged(int)</slot>
+ </connection>
+ <connection>
+ <sender>m_pViewGroup</sender>
+ <signal>clicked(int)</signal>
+ <receiver>m_pStack</receiver>
+ <slot>raiseWidget(int)</slot>
+ </connection>
+</connections>
+<slots>
+ <slot access="protected">slotSaveClicked()</slot>
+ <slot access="protected">slotZoomInClicked()</slot>
+ <slot access="protected">slotZoomOutClicked()</slot>
+ <slot access="protected">slotRotateClicked()</slot>
+ <slot access="protected">slotViewChanged(int)</slot>
+ <slot access="protected">slotViewChanged(QWidget*)</slot>
+ <slot access="protected">slotPrefClicked()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>graphwidget.h</includehint>
+ <includehint>treewidget.h</includehint>
+ <includehint>treewidget.h</includehint>
+</includehints>
+</UI>
diff --git a/src/calltreemanager.cpp b/src/calltreemanager.cpp
new file mode 100644
index 0000000..5dc8e9f
--- /dev/null
+++ b/src/calltreemanager.cpp
@@ -0,0 +1,136 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include "calltreemanager.h"
+#include "calltreedlg.h"
+#include "projectmanager.h"
+
+/**
+ * Class constructor.
+ * @param pParent The widget to use as the parent of all Call Tree
+ * dialogues
+ */
+CallTreeManager::CallTreeManager(QWidget* pParent) : QObject(pParent)
+{
+ // Delete dialogue objects when they are removed from the list
+ m_lstDialogs.setAutoDelete(true);
+}
+
+/**
+ * Class destructor.
+ */
+CallTreeManager::~CallTreeManager()
+{
+}
+
+/**
+ * Saves all call trees into the project directory.
+ * @param sProjPath The project's directory
+ * @param slFiles Holds a list of saved file names, upon return
+ */
+void CallTreeManager::saveOpenDialogs(const QString& sProjPath,
+ QStringList& slFiles)
+{
+ CallTreeDlg *pDlg;
+
+ // Iterate over the open dialogues
+ for (pDlg = m_lstDialogs.first(); pDlg != NULL;
+ pDlg = m_lstDialogs.next()) {
+ pDlg->store(sProjPath);
+ slFiles += pDlg->getFileName();
+ }
+}
+
+/**
+ * Loads all call trees according to the list of files
+ * @param sProjPath The project's directory
+ * @param slFiles A list of file names to open
+ */
+void CallTreeManager::loadOpenDialogs(const QString& sProjPath,
+ const QStringList& slFiles)
+{
+ QStringList::ConstIterator itr;
+ CallTreeDlg *pDlg;
+
+ for (itr = slFiles.begin(); itr != slFiles.end(); ++itr) {
+ // Create a new dialogue for this file
+ pDlg = addDialog();
+
+ // Try to load the graph from the file
+ if (!pDlg->load(sProjPath, *itr)) {
+ m_lstDialogs.remove(pDlg);
+ continue;
+ }
+
+ // Show the call tree
+ pDlg->show();
+ }
+}
+
+/**
+ * Creates a new Call Tree dialogue.
+ * @return The newly allocated dialogue object
+ */
+CallTreeDlg* CallTreeManager::addDialog()
+{
+ CallTreeDlg* pDlg;
+
+ // Create a modeless call tree dialogue
+ pDlg = new CallTreeDlg();
+ m_lstDialogs.append(pDlg);
+
+ // Open an editor whenever a function name is double-clicked
+ connect(pDlg, SIGNAL(lineRequested(const QString&, uint)),
+ this, SIGNAL(lineRequested(const QString&, uint)));
+
+ // Track the closing of the call tree dialog
+ connect(pDlg, SIGNAL(closed(const CallTreeDlg*)), this,
+ SLOT(slotRemoveDialog(const CallTreeDlg*)));
+
+ return pDlg;
+}
+
+/**
+ * Closes all Call Tree dialogues.
+ */
+void CallTreeManager::closeAll()
+{
+ m_lstDialogs.clear();
+}
+
+/**
+ * Removes a Call Tree dialogue from the list of open Call Trees.
+ * This slot is connected to the closed() signal emitted by the dialogue.
+ * @param pDlg The dialogue to remove from the list
+ */
+void CallTreeManager::slotRemoveDialog(const CallTreeDlg* pDlg)
+{
+ m_lstDialogs.remove(pDlg);
+}
+
+#include "calltreemanager.moc"
+
diff --git a/src/calltreemanager.h b/src/calltreemanager.h
new file mode 100644
index 0000000..adb91e6
--- /dev/null
+++ b/src/calltreemanager.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef CALLTREEMANAGER_H
+#define CALLTREEMANAGER_H
+
+#include <qwidget.h>
+#include <qptrlist.h>
+
+class CallTreeDlg;
+
+/**
+ * Manages all call tree dialogs within the project.
+ * Responsible for saving/loading of the call tree dialogs.
+ * @author Albert Yosher
+ */
+class CallTreeManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ CallTreeManager(QWidget*);
+ ~CallTreeManager();
+
+ void saveOpenDialogs(const QString&, QStringList&);
+ void loadOpenDialogs(const QString&, const QStringList&);
+ CallTreeDlg* addDialog();
+ void closeAll();
+
+signals:
+ /**
+ * Emitted when any call tree dialogue sends a request to view a location
+ * in the source code.
+ * @param sPath The full path of the file to show
+ * @param nLine The line number in this file
+ */
+ void lineRequested(const QString& sPath, uint nLine);
+
+private:
+ /** The list of open call tree dialogues. */
+ QPtrList<CallTreeDlg> m_lstDialogs;
+
+private slots:
+ void slotRemoveDialog(const CallTreeDlg*);
+};
+
+#endif
diff --git a/src/configfrontend.cpp b/src/configfrontend.cpp
new file mode 100644
index 0000000..27e4e32
--- /dev/null
+++ b/src/configfrontend.cpp
@@ -0,0 +1,172 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <kstandarddirs.h>
+#include "configfrontend.h"
+
+/**
+ * Class constructor.
+ * @param bAutoDelete True to destroy the object when the process ends,
+ * false otherwise
+ */
+ConfigFrontend::ConfigFrontend(bool bAutoDelete) :
+ Frontend(1, bAutoDelete)
+{
+}
+
+/**
+ * Class destructor.
+ */
+ConfigFrontend::~ConfigFrontend()
+{
+}
+
+/**
+ * Executes the script using the "sh" shell.
+ * @param sCscopePath If given, overrides the automatic check for Cscope's
+ * path
+ * @param sCtagsPath If given, overrides the automatic check for Ctags'
+ * path
+ * @param sDotPath If given, overrides the automatic check for Dot's
+ * path
+ * @param bCscopeOptsOnly Only verify cscope's path and options
+ * @return true if successful, false otherwise
+ */
+bool ConfigFrontend::run(const QString& sCscopePath,
+ const QString& sCtagsPath, const QString& sDotPath,
+ bool bCscopeOptsOnly)
+{
+ QStringList slArgs;
+ KStandardDirs sd;
+ QString sScript;
+
+ // Execute using the user's shell
+ setUseShell(true);
+
+ // Find the configuration script
+ sScript = sd.findResource("data", "kscope/kscope_config");
+ if (sScript.isEmpty())
+ return false;
+
+ // Set command line arguments
+ slArgs.append("sh");
+ slArgs.append(sScript);
+
+ if (bCscopeOptsOnly)
+ slArgs.append("-co");
+
+ // Initialise environment
+ setEnvironment("CSCOPE_PATH", sCscopePath);
+ setEnvironment("CTAGS_PATH", sCtagsPath);
+ setEnvironment("DOT_PATH", sDotPath);
+
+ // Parser initialisation
+ m_delim = Newline;
+ m_nNextResult = CscopePath;
+
+ if (!Frontend::run("sh", slArgs))
+ return false;
+
+ emit test(CscopePath);
+ return true;
+}
+
+/**
+ * Handles tokens generated by the script.
+ * Each token represents a line in the script's output, and is the result of
+ * a different test.
+ * @param sToken The generated token
+ */
+Frontend::ParseResult ConfigFrontend::parseStdout(QString& sToken,
+ ParserDelim)
+{
+ uint nResult;
+
+ // Store the type of test for which the given token in the result
+ nResult = m_nNextResult;
+
+ // Determine the next test
+ switch (m_nNextResult) {
+ case CscopePath:
+ if (sToken == "ERROR")
+ m_nNextResult = CtagsPath;
+ else
+ m_nNextResult = CscopeVersion;
+ break;
+
+ case CscopeVersion:
+ if (sToken == "ERROR")
+ m_nNextResult = CtagsPath;
+ else
+ m_nNextResult = CscopeVerbose;
+ break;
+
+ case CscopeVerbose:
+ m_nNextResult = CscopeSlowPath;
+ break;
+
+ case CscopeSlowPath:
+ m_nNextResult = CtagsPath;
+ break;
+
+ case CtagsPath:
+ if (sToken == "ERROR")
+ m_nNextResult = END;
+ else
+ m_nNextResult = CtagsExub;
+ break;
+
+ case CtagsExub:
+ if (sToken == "ERROR")
+ m_nNextResult = END;
+ else
+ m_nNextResult = DotPath;
+ break;
+
+ case DotPath:
+ if (sToken == "ERROR")
+ m_nNextResult = END;
+ else
+ m_nNextResult = DotPlain;
+ break;
+
+ case DotPlain:
+ m_nNextResult = END;
+ break;
+
+ case END:
+ return DiscardToken;
+ }
+
+ // Publish the result and the type of the next test
+ emit result(nResult, sToken);
+ emit test(m_nNextResult);
+
+ return DiscardToken;
+}
+
+#include "configfrontend.moc"
diff --git a/src/configfrontend.h b/src/configfrontend.h
new file mode 100644
index 0000000..df5e303
--- /dev/null
+++ b/src/configfrontend.h
@@ -0,0 +1,77 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef CONFIGFRONTEND_H
+#define CONFIGFRONTEND_H
+
+#include <frontend.h>
+
+/**
+ * Frontend to the kscope_config shell script.
+ * The script executes a set of tests and outputs their results.
+ * @author Elad Lahav
+ */
+class ConfigFrontend : public Frontend
+{
+ Q_OBJECT
+
+public:
+ ConfigFrontend(bool bAutoDelete = false);
+ ~ConfigFrontend();
+
+ bool run(const QString&, const QString&, const QString&,
+ bool bCscopeOptsOnly = false);
+
+ /**
+ * The types of tests executed by the script.
+ */
+ enum { CscopePath, CscopeVersion, CscopeVerbose, CscopeSlowPath,
+ CtagsPath, CtagsExub, DotPath, DotPlain, END };
+
+signals:
+ /**
+ * Indicates that the script is now running a given test.
+ * @param nType The type of test being executed
+ */
+ void test(uint nType);
+
+ /**
+ * Called after a test has produced a result.
+ * @param nType The type of test executed
+ * @param sResult The obtained result
+ */
+ void result(uint nType, const QString& sResult);
+
+protected:
+ virtual ParseResult parseStdout(QString&, ParserDelim);
+
+private:
+ /** The type of test whose result is expected next. */
+ uint m_nNextResult;
+};
+
+#endif
diff --git a/src/cscopefrontend.cpp b/src/cscopefrontend.cpp
new file mode 100644
index 0000000..7c8f288
--- /dev/null
+++ b/src/cscopefrontend.cpp
@@ -0,0 +1,524 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qfileinfo.h>
+#include <qtimer.h>
+#include <kconfig.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kglobalsettings.h>
+#include "cscopefrontend.h"
+#include "kscopeconfig.h"
+#include "configfrontend.h"
+
+#define BUILD_STR "Building symbol database %d of %d"
+#define SEARCH_STR "Search %d of %d"
+#define INV_STR "Possible references retrieved %d of %d"
+#define REGEXP_STR "Symbols matched %d of %d"
+#define SEARCHEND_STR "%d lines"
+
+QString CscopeFrontend::s_sProjPath;
+uint CscopeFrontend::s_nProjArgs;
+uint CscopeFrontend::s_nSupArgs;
+
+/**
+ * Class constructor.
+ * @param bAutoDelete true to delete the object once the process has
+ * terminated, false otherwise
+ */
+CscopeFrontend::CscopeFrontend(bool bAutoDelete) :
+ Frontend(CSCOPE_RECORD_SIZE, bAutoDelete),
+ m_state(Unknown),
+ m_sErrMsg(""),
+ m_bRebuildOnExit(false)
+{
+}
+
+/**
+ * Class destructor.
+ */
+CscopeFrontend::~CscopeFrontend()
+{
+}
+
+/**
+ * Executes a Cscope process using the given command line arguments.
+ * The full path to the Cscope executable should be set in the "Path" key
+ * under the "Cscope" group.
+ * @param slArgs Command line arguments for Cscope
+ * @return true if successful, false otherwise
+ */
+bool CscopeFrontend::run(const QStringList& slArgs)
+{
+ QStringList slCmdLine;
+
+ // Set the command line arguments
+ slCmdLine.append(Config().getCscopePath());
+ slCmdLine += slArgs;
+
+ // Use verbose mode, if supported
+ if (s_nSupArgs & VerboseOut)
+ slCmdLine << "-v";
+
+ // Project-specific options
+ if (s_nProjArgs & Kernel)
+ slCmdLine << "-k";
+ if (s_nProjArgs & InvIndex)
+ slCmdLine << "-q";
+ if (s_nProjArgs & NoCompression)
+ slCmdLine << "-c";
+ if (s_nProjArgs & s_nSupArgs & SlowPathDef)
+ slCmdLine << "-D";
+
+ // Run a new process
+ if (!Frontend::run("cscope", slCmdLine, s_sProjPath)) {
+ emit aborted();
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Executes a Cscope query.
+ * A query is composed of a numeric type and a query text, which are written
+ * to the stndard input of the currently running Cscope process.
+ * @param nType The type of query to run
+ * @param sText The query's text
+ * @param bCase true for case-sensitive queries, false otherwise
+ * @param nMaxRecords The maximal number of records to return (abort if this
+ * number is exceeded)
+ */
+void CscopeFrontend::query(uint nType, const QString& sText, bool bCase,
+ uint nMaxRecords)
+{
+ QString sQuery;
+ QStringList slArgs;
+
+ m_nMaxRecords = nMaxRecords;
+
+ // Create the Cscope command line
+ slArgs.append(QString("-L") + QString::number(nType));
+ slArgs.append(sText);
+ slArgs.append("-d");
+ if (!bCase)
+ slArgs.append("-C");
+
+ run(slArgs);
+
+ // Initialise stdout parsing
+ m_state = SearchSymbol;
+ m_delim = WSpace;
+
+ emit progress(0, 1);
+}
+
+/**
+ * Rebuilds the symbol database of the current project.
+ */
+void CscopeFrontend::rebuild()
+{
+ QStringList slArgs;
+
+ // If a process is already running, kill it start a new one
+ if (isRunning()) {
+ m_bRebuildOnExit = true;
+ kill();
+ return;
+ }
+
+ // Run the database building process
+ slArgs.append("-b");
+ run(slArgs);
+
+ // Initialise output parsing
+ m_state = BuildStart;
+ m_delim = Newline;
+
+ emit progress(0, 1);
+}
+
+/**
+ * Sets default parameters for all CscopeFrontend projects based on the
+ * current project.
+ * @param sProjPath The full path of the project's directory
+ * @param nArgs Project-specific command-line arguments
+ */
+void CscopeFrontend::init(const QString& sProjPath, uint nArgs)
+{
+ s_sProjPath = sProjPath;
+ s_nProjArgs = nArgs;
+}
+
+/**
+ * Stops a Cscope action.
+ */
+void CscopeFrontend::slotCancel()
+{
+ kill();
+}
+
+/**
+ * Parses the output of a Cscope process.
+ * Implements a state machine, where states correspond to the output of the
+ * controlled Cscope process.
+ * @param sToken The current token read (the token delimiter is determined
+ * by the current state)
+ * @return A value indicating the way this token should be treated: dropped,
+ * added to the token queue, or finishes a new record
+ */
+Frontend::ParseResult CscopeFrontend::parseStdout(QString& sToken,
+ ParserDelim /* ignored */)
+{
+ int nFiles, nTotal, nRecords;
+ ParseResult result = DiscardToken;
+ ParserState stPrev;
+
+ // Remember previous state
+ stPrev = m_state;
+
+ // Handle the token according to the current state
+ switch (m_state) {
+ case BuildStart:
+ if (sToken == "Building cross-reference...") {
+ m_state = BuildSymbol;
+ m_delim = WSpace;
+ }
+ else if (sToken == "Building inverted index...") {
+ emit buildInvIndex();
+ }
+
+ result = DiscardToken;
+ break;
+
+ case BuildSymbol:
+ // A single angle bracket is the prefix of a progress indication,
+ // while double brackets is Cscope's prompt for a new query
+ if (sToken == ">") {
+ m_state = Building;
+ m_delim = Newline;
+ }
+
+ result = DiscardToken;
+ break;
+
+ case Building:
+ // Try to get building progress
+ if (sscanf(sToken.latin1(), BUILD_STR, &nFiles, &nTotal) == 2) {
+ emit progress(nFiles, nTotal);
+
+ // Check for last progress message
+ if (nFiles == nTotal) {
+ m_state = BuildStart;
+ m_delim = Newline;
+
+ result = DiscardToken;
+ break;
+ }
+ }
+
+ // Wait for another progress line or the "ready" symbol
+ m_state = BuildSymbol;
+ m_delim = WSpace;
+
+ result = DiscardToken;
+ break;
+
+ case SearchSymbol:
+ // Check for more search progress, or the end of the search,
+ // designated by a line in the format of "cscope: X lines"
+ if (sToken == ">") {
+ m_state = Searching;
+ m_delim = Newline;
+ result = DiscardToken;
+ break;
+ }
+ else if (sToken == "cscope:") {
+ m_state = SearchEnd;
+ m_delim = Newline;
+ result = DiscardToken;
+ break;
+ }
+
+ case File:
+ // Is this the first entry? If so, signal that the query is complete
+ if (stPrev != LineText)
+ emit progress(1, 1);
+
+ // Treat the token as the name of the file in this record
+ m_state = Func;
+ result = AcceptToken;
+ break;
+
+ case Searching:
+ // Try to get the search progress value (ignore other messages)
+ if ((sscanf(sToken.latin1(), SEARCH_STR, &nFiles, &nTotal) == 2) ||
+ (sscanf(sToken.latin1(), INV_STR, &nFiles, &nTotal) == 2) ||
+ (sscanf(sToken.latin1(), REGEXP_STR, &nFiles, &nTotal) == 2)) {
+ emit progress(nFiles, nTotal);
+ }
+
+ m_state = SearchSymbol;
+ m_delim = WSpace;
+ result = DiscardToken;
+ break;
+
+ case SearchEnd:
+ // Get the number of results found in this search
+ if ((sscanf(sToken.latin1(), SEARCHEND_STR, &nRecords) == 1) &&
+ (m_nMaxRecords > 0) &&
+ (nRecords > m_nMaxRecords)) {
+ result = Abort;
+ }
+ else {
+ m_state = File;
+ m_delim = WSpace;
+ result = DiscardToken;
+ }
+
+ break;
+
+ case Func:
+ // Treat the token as the name of the function in this record
+ if (sToken.toInt()) {
+ // In case of a global definition, there is no function name, and
+ // instead the line number is given immediately
+ m_state = LineText;
+ m_delim = Newline;
+ }
+ else {
+ // Not a number, it is the name of the function
+ m_state = Line;
+ }
+
+ result = AcceptToken;
+ break;
+
+ case Line:
+ // Treat the token as the line number in this record
+ m_state = LineText;
+ m_delim = Newline;
+ result = AcceptToken;
+ break;
+
+ case LineText:
+ // Treat the token as the text of this record, and report a new
+ // record
+ m_state = File;
+ m_delim = WSpace;
+ result = RecordReady;
+ break;
+
+ default:
+ // Do nothing (prevents a compilation warning for unused enum values)
+ break;
+ }
+
+ return result;
+}
+
+/**
+ * Handles Cscope messages sent to the standard error stream.
+ * @param sText The error message text
+ */
+void CscopeFrontend::parseStderr(const QString& sText)
+{
+ // Wait for a complete line to arrive
+ m_sErrMsg += sText;
+ if (!sText.endsWith("\n"))
+ return;
+
+ // Display the error message
+ emit error(m_sErrMsg);
+
+ // Line displayed, reset the text accumulator
+ m_sErrMsg = "";
+}
+
+/**
+ * Called when the underlying process exits.
+ * Checks if the rebuild flag was raised, and if so restarts the building
+ * process.
+ */
+void CscopeFrontend::finalize()
+{
+ // Reset the parser state machine
+ m_state = Unknown;
+
+ // Restart the building process, if required
+ if (m_bRebuildOnExit) {
+ m_bRebuildOnExit = false;
+ rebuild();
+ }
+}
+
+/**
+ * Class constructor.
+ * @param pMainWidget The parent widget to use for the progress bar and
+ * label
+ */
+CscopeProgress::CscopeProgress(QWidget* pMainWidget) : QObject(),
+ m_pMainWidget(pMainWidget),
+ m_pProgressBar(NULL),
+ m_pLabel(NULL)
+{
+}
+
+/**
+ * Class destructor.
+ */
+CscopeProgress::~CscopeProgress()
+{
+}
+
+/**
+ * Displays query progress information.
+ * If the progress value is below the expected final value, a progress bar is
+ * used to show the advance of the query process. Otherwise, a label is
+ * displayed asking the user to wait ahile the query output is processed.
+ * @param nProgress The current progress value
+ * @param nTotal The expected final value
+ */
+void CscopeProgress::setProgress(int nProgress, int nTotal)
+{
+ // Was the final value is reached?
+ if (nProgress == nTotal) {
+ // Destroy the progress bar
+ if (m_pProgressBar != NULL) {
+ delete m_pProgressBar;
+ m_pProgressBar = NULL;
+ }
+
+ // Show the "Please wait..." label
+ if (m_pLabel == NULL) {
+ m_pLabel = new QLabel(i18n("Processing query results, "
+ "please wait..."), m_pMainWidget);
+ m_pLabel->setFrameStyle(QFrame::Box | QFrame::Plain);
+ m_pLabel->setLineWidth(1);
+ m_pLabel->adjustSize();
+
+ m_pLabel->setPaletteBackgroundColor(
+ KGlobalSettings::highlightColor());
+ m_pLabel->setPaletteForegroundColor(
+ KGlobalSettings::highlightedTextColor());
+
+ QTimer::singleShot(1000, this, SLOT(slotShowLabel()));
+ }
+
+ return;
+ }
+
+ // Create the progress bar, if it does not exist.
+ // Note that the progress bar will only be displayed one second after the
+ // first progress signal is received. Thus the bar will not be displayed
+ // on very short queries.
+ if (m_pProgressBar == NULL) {
+ m_pProgressBar = new QProgressBar(m_pMainWidget);
+ QTimer::singleShot(1000, this, SLOT(slotShowProgressBar()));
+ }
+
+ // Set the current progress value
+ m_pProgressBar->setProgress(nProgress, nTotal);
+}
+
+/**
+ * detsroys any progress widgets when the process is terminated.
+ */
+void CscopeProgress::finished()
+{
+ // Destroy the progress bar
+ if (m_pProgressBar != NULL) {
+ delete m_pProgressBar;
+ m_pProgressBar = NULL;
+ }
+
+ // Destroy the label
+ if (m_pLabel != NULL) {
+ delete m_pLabel;
+ m_pLabel = NULL;
+ }
+}
+
+/**
+ * Shows the progress bar.
+ * This slot is connected to a timer activated when the first progress signal
+ * is received.
+ */
+void CscopeProgress::slotShowProgressBar()
+{
+ if (m_pProgressBar != NULL)
+ m_pProgressBar->show();
+}
+
+/**
+ * Shows the "Please wait...".
+ * This slot is connected to a timer activated when the progress bar
+ * reaches its final value.
+ */
+void CscopeProgress::slotShowLabel()
+{
+ if (m_pLabel != NULL)
+ m_pLabel->show();
+}
+
+void CscopeVerifier::verify()
+{
+ ConfigFrontend* pConf;
+
+ pConf = new ConfigFrontend(true);
+ connect(pConf, SIGNAL(result(uint, const QString&)), this,
+ SLOT(slotConfigResult(uint, const QString&)));
+ connect(pConf, SIGNAL(finished(uint)), this, SLOT(slotFinished()));
+
+ pConf->run(Config().getCscopePath(), "", "", true);
+}
+
+void CscopeVerifier::slotConfigResult(uint nType, const QString& sResult)
+{
+ switch (nType) {
+ case ConfigFrontend::CscopeVerbose:
+ if (sResult == "Yes")
+ m_nArgs |= CscopeFrontend::VerboseOut;
+ break;
+
+ case ConfigFrontend::CscopeSlowPath:
+ if (sResult == "Yes")
+ m_nArgs |= CscopeFrontend::SlowPathDef;
+
+ // If we got this far, then Cscope is configured properly
+ m_bResult = true;
+ break;
+ }
+}
+
+void CscopeVerifier::slotFinished()
+{
+ emit done(m_bResult, m_nArgs);
+ delete this;
+}
+
+#include "cscopefrontend.moc"
diff --git a/src/cscopefrontend.h b/src/cscopefrontend.h
new file mode 100644
index 0000000..2b2c569
--- /dev/null
+++ b/src/cscopefrontend.h
@@ -0,0 +1,186 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef CSCOPEFRONTEND_H
+#define CSCOPEFRONTEND_H
+
+#include <qstringlist.h>
+#include <qprogressbar.h>
+#include <qlabel.h>
+#include "frontend.h"
+
+#define CSCOPE_RECORD_SIZE 4
+
+/**
+ * Controls a Cscope process for the current project.
+ * This class creates a Cscope process, using the project's files for
+ * configuration. Once the process is running, KScope uses the query() method
+ * to initiate Cscope queries on the project's files. The queries' output is
+ * parsed into a set of records, each consisting of the following fields:
+ * - File name
+ * - Function name
+ * - Line number
+ * - The line's text
+ * These records are used to display the output in different windows, such as
+ * QueryWidget and CallTreeDlg.
+ * @author Elad Lahav
+ */
+
+class CscopeFrontend : public Frontend
+{
+ Q_OBJECT
+
+public:
+ CscopeFrontend(bool bAutoDelete = false);
+ ~CscopeFrontend();
+
+ /**
+ * The available Cscope query types.
+ */
+ enum QueryType { Reference = 0, Definition = 1, Called = 2, Calling = 3,
+ Text = 4, Pattern = 6, FileName = 7, Including = 8, None = 9 };
+
+ /**
+ * Options for running Cscope, used to construct the command line.
+ * Some of these options are global, while some are project specific.
+ */
+ enum Options { VerboseOut = 0x01, SlowPathDef = 0x02,
+ Kernel = 0x04, InvIndex = 0x08, NoCompression = 0x10 };
+
+ void query(uint, const QString&, bool bCase = true, uint nMaxRecords = 0);
+ void rebuild();
+
+ static void init(const QString&, uint);
+
+ /**
+ * @param nArgs The command-line arguments supported by the version of
+ * Cscope currently in use
+ */
+ static void setSupArgs(uint nArgs) { s_nSupArgs = nArgs; }
+
+public slots:
+ void slotCancel();
+
+signals:
+ /**
+ * Emitted when Cscope starts building the inverted index.
+ */
+ void buildInvIndex();
+
+protected:
+ virtual ParseResult parseStdout(QString&, ParserDelim);
+ virtual void parseStderr(const QString&);
+ virtual void finalize();
+
+private:
+ /**
+ * The possible states of the parser state machine.
+ */
+ enum ParserState { Unknown = 0, BuildStart, BuildSymbol, Building,
+ SearchSymbol, Searching, SearchEnd, File, Func, Line, LineText };
+
+ /** The current state of the parser state machine. */
+ ParserState m_state;
+
+ /** Accumulates text sent by Cscope to the standard error stream. */
+ QString m_sErrMsg;
+
+ /** If true, the rebuild process will be restarted when the process
+ exits. */
+ bool m_bRebuildOnExit;
+
+ /** The maximal number of records requested for the current query.
+ The process aborts if this number if reached. */
+ int m_nMaxRecords;
+
+ /** The full path of the directory holding the project files. */
+ static QString s_sProjPath;
+
+ /** Project-specific options for the command-line arguments. */
+ static uint s_nProjArgs;
+
+ /** The command line arguments supported by this version of Cscope. */
+ static uint s_nSupArgs;
+
+ bool run(const QStringList&);
+};
+
+/**
+ * Provides progress information on a Cscope query.
+ * Classes used to display query results can use this class to show a
+ * progress bar while a query is running, and a "Please Wait..." label while
+ * output is being processed.
+ * @author Elad Lahav
+ */
+class CscopeProgress : public QObject
+{
+ Q_OBJECT
+
+public:
+ CscopeProgress(QWidget*);
+ ~CscopeProgress();
+
+ void setProgress(int, int);
+ void finished();
+
+private:
+ /** The parent widget for the progress bar and label. */
+ QWidget* m_pMainWidget;
+
+ /** A bar used to display query progress information. */
+ QProgressBar* m_pProgressBar;
+
+ /** A label used to display a "Please wait..." message. */
+ QLabel* m_pLabel;
+
+private slots:
+ void slotShowProgressBar();
+ void slotShowLabel();
+};
+
+class CscopeVerifier : public QObject
+{
+ Q_OBJECT
+
+public:
+ CscopeVerifier() : m_bResult(false), m_nArgs(0) {}
+
+ void verify();
+
+signals:
+ void done(bool, uint);
+
+private:
+ bool m_bResult;
+ uint m_nArgs;
+
+private slots:
+ void slotConfigResult(uint, const QString&);
+ void slotFinished();
+};
+
+#endif
diff --git a/src/cscopemsgdlg.cpp b/src/cscopemsgdlg.cpp
new file mode 100644
index 0000000..1bf6656
--- /dev/null
+++ b/src/cscopemsgdlg.cpp
@@ -0,0 +1,66 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qtextedit.h>
+#include <qpushbutton.h>
+#include "cscopemsgdlg.h"
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+CscopeMsgDlg::CscopeMsgDlg(QWidget* pParent, const char* szName)
+ : CscopeMsgLayout(pParent, szName, false, 0)
+{
+ // Hide the dialog when the "Hide" button is clicked
+ connect(m_pHideButton, SIGNAL(clicked()), this, SLOT(hide()));
+
+ // Clear all messages when the "Clear" button is clicked
+ connect(m_pClearButton, SIGNAL(clicked()), m_pMsgText, SLOT(clear()));
+}
+
+/**
+ * Class destructor.
+ */
+CscopeMsgDlg::~CscopeMsgDlg()
+{
+}
+
+/**
+ * Appends a given message to the text box.
+ * After a new messsage is added, the dialog becomes visible.
+ * @param sText The text of the message to add
+ */
+void CscopeMsgDlg::addText(const QString& sText)
+{
+ m_pMsgText->append(sText);
+ show();
+}
+
+#include "cscopemsgdlg.moc"
+
diff --git a/src/cscopemsgdlg.h b/src/cscopemsgdlg.h
new file mode 100644
index 0000000..0cd45cd
--- /dev/null
+++ b/src/cscopemsgdlg.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef CSCOPEMSGDLG_H
+#define CSCOPEMSGDLG_H
+
+#include "cscopemsglayout.h"
+
+/**
+ * Displays messages sent by Cscope to its standard error stream.
+ * @author Elad Lahav
+ */
+class CscopeMsgDlg : public CscopeMsgLayout
+{
+ Q_OBJECT
+
+public:
+ CscopeMsgDlg(QWidget* pParent = 0, const char* szName = 0);
+ ~CscopeMsgDlg();
+
+ void addText(const QString&);
+};
+
+#endif
+
diff --git a/src/cscopemsglayout.ui b/src/cscopemsglayout.ui
new file mode 100644
index 0000000..1a6458d
--- /dev/null
+++ b/src/cscopemsglayout.ui
@@ -0,0 +1,79 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>CscopeMsgLayout</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>CscopeMsgLayout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>451</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Cscope Error Messages</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTextEdit">
+ <property name="name">
+ <cstring>m_pMsgText</cstring>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </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>321</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pClearButton</cstring>
+ </property>
+ <property name="text">
+ <string>Clear</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pHideButton</cstring>
+ </property>
+ <property name="text">
+ <string>Hide</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/src/ctagsfrontend.cpp b/src/ctagsfrontend.cpp
new file mode 100644
index 0000000..73f7519
--- /dev/null
+++ b/src/ctagsfrontend.cpp
@@ -0,0 +1,179 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qfileinfo.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kshell.h>
+#include "ctagsfrontend.h"
+#include "kscopeconfig.h"
+
+QStringList CtagsFrontend::s_slExtraArgs;
+
+/**
+ * Class constructor.
+ */
+CtagsFrontend::CtagsFrontend() : Frontend(CTAGS_RECORD_SIZE)
+{
+}
+
+/**
+ * Class destructor.
+ */
+CtagsFrontend::~CtagsFrontend()
+{
+}
+
+/**
+ * Executes a Ctags process on a source file.
+ * @param sFileName The full path to the source file
+ * @return true if successful, false otherwise
+ */
+bool CtagsFrontend::run(const QString& sFileName)
+{
+ QString sPath;
+ QStringList slArgs;
+
+ // Make sure the executable exists
+ sPath = Config().getCtagsPath();
+
+ // Set the command line arguments
+ slArgs.append(sPath);
+ slArgs.append("--excmd=n");
+ slArgs.append("-u"); // don't sort
+ slArgs.append("-f");
+ slArgs.append("-");
+
+ // Per-project command-line arguments
+ slArgs += s_slExtraArgs;
+
+ slArgs.append(sFileName);
+
+ // Run a new process
+ if (!Frontend::run("ctags", slArgs))
+ return false;
+
+ // Initialize stdout parsing
+ m_state = Name;
+ m_delim = Tab;
+
+ return true;
+}
+
+/**
+ * Tests that the given file path leads to an executable.
+ * @param sPath The path to check
+ * @return true if the file in the given path exists and has executable
+ * permissions, false otherwise
+ */
+bool CtagsFrontend::verify(const QString& sPath)
+{
+ QFileInfo fi(sPath);
+
+ if (!fi.exists() || !fi.isFile() || !fi.isExecutable() ||
+ fi.fileName().find("ctags", 0, false) == -1) {
+ KMessageBox::error(0, i18n("Ctags cannot be found in the given "
+ "path"));
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Turns the per-project string of additional arguments into a list of
+ * command-line arguments.
+ * @param sArgs The per-project command string
+ */
+void CtagsFrontend::setExtraArgs(const QString& sArgs)
+{
+ s_slExtraArgs = KShell::splitArgs(sArgs);
+}
+
+/**
+ * Parses the output of a Ctags process.
+ * @param sToken The current token read (the token delimiter is determined
+ * by the current state)
+ * @param delim The delimiter that ends this token
+ * @return A value indicating the way this token should be treated: dropped,
+ * added to the token queue, or finishes a new record
+ */
+Frontend::ParseResult CtagsFrontend::parseStdout(QString& sToken,
+ ParserDelim delim)
+{
+ ParseResult result = DiscardToken;
+
+ // Handle the token according to the current state
+ switch (m_state) {
+ case Name:
+ if (sToken.left(6) == "ctags:") {
+ m_state = Other;
+ m_delim = Newline;
+ break;
+ }
+
+ m_state = File;
+ result = AcceptToken;
+ break;
+
+ case File:
+ m_state = Line;
+ result = DiscardToken;
+ break;
+
+ case Line:
+ sToken = sToken.left(sToken.length() - 2);
+ m_state = Type;
+ m_delim = All;
+ result = AcceptToken;
+ break;
+
+ case Type:
+ if (delim == Newline) {
+ m_state = Name;
+ m_delim = Tab;
+ }
+ else {
+ m_state = Other;
+ m_delim = Newline;
+ }
+
+ result = RecordReady;
+ break;
+
+ case Other:
+ m_state = Name;
+ m_delim = Tab;
+ result = DiscardToken;
+ break;
+
+ }
+
+ return result;
+}
+
+#include "ctagsfrontend.moc"
diff --git a/src/ctagsfrontend.h b/src/ctagsfrontend.h
new file mode 100644
index 0000000..3c0c452
--- /dev/null
+++ b/src/ctagsfrontend.h
@@ -0,0 +1,77 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef CTAGSFRONTEND_H
+#define CTAGSFRONTEND_H
+
+#include <frontend.h>
+
+#define CTAGS_RECORD_SIZE 3
+
+/**
+ * Controls a Ctags process for an file in an EditorPage window.
+ * A new Ctags process is run each time the file in the editor window is
+ * loaded (including the initial load, and any subsequent ones which follow a
+ * 'save' operation.)
+ * The output of the process is parsed into a set of records, each composed of
+ * the following fields:
+ * - Tag type
+ * - Tag name
+ * - Line number
+ * The records are then displayed in the CtagsList widget that is attached to
+ * each EditorPage window.
+ * @author Elad Lahav
+ */
+
+class CtagsFrontend : public Frontend
+{
+ Q_OBJECT
+
+public:
+ CtagsFrontend();
+ ~CtagsFrontend();
+
+ bool run(const QString&);
+
+ static bool verify(const QString&);
+ static void setExtraArgs(const QString&);
+
+protected:
+ virtual ParseResult parseStdout(QString&, ParserDelim);
+
+private:
+ /** State values for the parser state machine. */
+ enum ParserState { Name = 0, File, Line, Type, Other };
+
+ /** The current state of the parser state machine. */
+ ParserState m_state;
+
+ /** Additional ommand-line arguments (per-project). */
+ static QStringList s_slExtraArgs;
+};
+
+#endif
diff --git a/src/ctagslist.cpp b/src/ctagslist.cpp
new file mode 100644
index 0000000..687e9fb
--- /dev/null
+++ b/src/ctagslist.cpp
@@ -0,0 +1,446 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qheader.h>
+#include <klocale.h>
+#include "ctagslist.h"
+#include "kscopeconfig.h"
+#include "kscopepixmaps.h"
+
+/**
+ * Defines a special list item for the tag list.
+ * This special definition allows the tag list to be sorted according to
+ * symbol line numbers. By default, all items are treated as text, hence the
+ * comparison of line numbers such as "123" and "24" sets "24" to be the
+ * larger item. By overriding the comparison function, this class allows for
+ * correct sorting.
+ * @author Elad Lahav
+ */
+class CtagsListItem : public QListViewItem
+{
+public:
+ /**
+ * Class constructor.
+ * @param pParent The owning list view widget
+ * @param sName The name of the tag
+ * @param sLine The line in which the tag is defined
+ * @param sType The type of the tag
+ */
+ CtagsListItem(QListView* pParent, QString sName, QString sLine,
+ QString sType) : QListViewItem(pParent, sName, sLine, sType),
+ m_nPendLine (sLine.toUInt()) {}
+
+ /**
+ * Compares two tag list items, and determines their order.
+ * If comparison is based on a text-column, the default behaviour is
+ * used. Otherwise, the text is converted to unsigned integers, and then
+ * compared as numbers.
+ * @param pItem The item to compare against the local object
+ * @param nCol The column index by which to compare
+ * @param bAscend true if sorting in ascending order, false otherwise
+ * @return 0 if the items are equal, 1 if the local item is greater, -1
+ * if the local item is lesser
+ */
+ virtual int compare(QListViewItem* pItem, int nCol, bool bAscend) const {
+ if (nCol == 1) {
+ uint nLineCur, nLineOther;
+ int nResult;
+
+ // Get the line numbers of each item
+ nLineCur = text(1).toUInt();
+ nLineOther = pItem->text(1).toUInt();
+
+ // Compare the line numbers
+ nResult = nLineCur - nLineOther;
+ if (nResult == 0)
+ return 0; // Items are equal
+ else if (nResult > 0)
+ return 1; // The first item is greater
+ else
+ return -1; // The second item is greater
+ }
+
+ // Use default comparison for text columns
+ return QListViewItem::compare(pItem, nCol, bAscend);
+ }
+
+ /**
+ * @return The line number associated with this item
+ */
+ inline uint getLine() { return m_nPendLine; }
+
+private:
+ /** The numeric value of the line number column of this item. */
+ uint m_nPendLine;
+};
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+CtagsList::CtagsList(QWidget* pParent, const char* szName) :
+ SearchList(0, pParent, szName),
+ m_arrLines(16),
+ m_nItems(0),
+ m_nCurItem(0),
+ m_bReady(false),
+ m_nCurLine(0),
+ m_nPendLine(0)
+{
+ m_pList->setShowSortIndicator(true);
+ connect(m_pList->header(), SIGNAL(clicked(int)), this,
+ SLOT(slotSortChanged(int)));
+
+ // Determine the default sorting order
+ switch (Config().getCtagSortOrder()) {
+ case KScopeConfig::NameAsc:
+ m_pList->setSorting(0, true);
+ break;
+
+ case KScopeConfig::NameDes:
+ m_pList->setSorting(0, false);
+ break;
+
+ case KScopeConfig::LineAsc:
+ m_pList->setSorting(1, true);
+ break;
+
+ case KScopeConfig::LineDes:
+ m_pList->setSorting(1, false);
+ break;
+
+ case KScopeConfig::TypeAsc:
+ m_pList->setSorting(2, true);
+ break;
+
+ case KScopeConfig::TypeDes:
+ m_pList->setSorting(2, false);
+ break;
+ }
+
+ // Add the list columns
+ m_pList->addColumn(i18n("Name"));
+ m_pList->addColumn(i18n("Line"));
+ m_pList->addColumn(i18n("Type"));
+ m_pList->setColumnAlignment(1, Qt::AlignRight);
+
+ // Set colours and font
+ applyPrefs();
+}
+
+/**
+ * Class destructor.
+ */
+CtagsList::~CtagsList()
+{
+}
+
+/**
+ * Adds a Ctags output entry to the list.
+ * This slot is connected to the dataReady() signal of a CtagsFrontend object.
+ * @param pToken The first token in the entry
+ */
+void CtagsList::slotDataReady(FrontendToken* pToken)
+{
+ QString sName, sType, sLine;
+ CtagsListItem* pItem;
+ KScopePixmaps::PixName pix;
+
+ // Get the name of the symbol
+ sName = pToken->getData();
+ pToken = pToken->getNext();
+
+ // Get the line number
+ sLine = pToken->getData();
+ pToken = pToken->getNext();
+
+ // Get the type of the symbol
+ sType = pToken->getData();
+ pToken = pToken->getNext();
+
+ // Set the appropriate pixmap
+ switch (sType[0].latin1()) {
+ case 'f':
+ sType = i18n("Function");
+ pix = KScopePixmaps::SymFunc;
+ break;
+
+ case 'v':
+ sType = i18n("Variable");
+ pix = KScopePixmaps::SymVar;
+ break;
+
+ case 's':
+ sType = i18n("Struct");
+ pix = KScopePixmaps::SymStruct;
+ break;
+
+ case 'd':
+ sType = i18n("Macro");
+ pix = KScopePixmaps::SymMacro;
+ break;
+
+ case 'm':
+ sType = i18n("Member");
+ pix = KScopePixmaps::SymMember;
+ break;
+
+ case 'g':
+ sType = i18n("Enum");
+ pix = KScopePixmaps::SymEnum;
+ break;
+
+ case 'e':
+ sType = i18n("Enumerator");
+ pix = KScopePixmaps::SymEnumerator;
+ break;
+
+ case 't':
+ sType = i18n("Typedef");
+ pix = KScopePixmaps::SymTypedef;
+ break;
+
+ case 'l':
+ sType = i18n("Label");
+ pix = KScopePixmaps::SymLabel;
+ break;
+
+ case 'i':
+ sType = i18n("Include");
+ pix = KScopePixmaps::SymInclude;
+ break;
+
+ default:
+ sType = "Unknown";
+ pix = KScopePixmaps::SymUnknown;
+ }
+
+ // Add a new item to the list
+ pItem = new CtagsListItem(m_pList, sName, sLine, sType);
+ pItem->setPixmap(0, Pixmaps().getPixmap(pix));
+ m_nItems++;
+
+ // Resize the line array, if required
+ if (m_arrLines.size() < m_nItems)
+ m_arrLines.resize(m_nItems, QGArray::SpeedOptim);
+
+ // Add the new item to the line array
+ m_arrLines[m_nItems - 1] = pItem;
+}
+
+/**
+ * Handles the "resize" event, which occurs when the size of the widget
+ * changes.
+ * @param pEvent The event data
+ */
+void CtagsList::resizeEvent(QResizeEvent* pEvent)
+{
+ SearchList::resizeEvent(pEvent);
+ emit resized();
+}
+
+/**
+ * Emits the lineRequested() signal when a list item is selected.
+ * This function is called if either an item is double-clicked, or an item is
+ * highlighted and the ENTER key is pressed.
+ * @param pItem The selected list item
+ */
+void CtagsList::processItemSelected(QListViewItem* pItem)
+{
+ QString sLine;
+
+ sLine = pItem->text(1);
+ emit lineRequested(sLine.toUInt());
+}
+
+/**
+ * Constructs a tool-tip for the given item.
+ * @param pItem The item for which a tip is required
+ * @param sTip The constructed tip string (on return)
+ * @return Always true
+ */
+bool CtagsList::getTip(QListViewItem* pItem, QString& sTip)
+{
+ sTip = QString("Type: <b>%1</b><br>Name: <b>%2</b><br>Line: <b>%3</b>").
+ arg(pItem->text(2)).arg(pItem->text(0)).arg(pItem->text(1));
+ return true;
+}
+
+/**
+ * Sets the list's colours and font, according the user's preferences.
+ */
+void CtagsList::applyPrefs()
+{
+ // Apply colour settings
+ m_pList->setPaletteBackgroundColor(Config().getColor(
+ KScopeConfig::TagListBack));
+ m_pList->setPaletteForegroundColor(Config().getColor(
+ KScopeConfig::TagListFore));
+ m_pList->setFont(Config().getFont(KScopeConfig::TagList));
+}
+
+/**
+ * Selects the symbol that dominates the given line in the source file.
+ * @param nLine The requested line
+ */
+void CtagsList::gotoLine(uint nLine)
+{
+ CtagsListItem* pItem;
+ int nFrom, nTo, nItem, nDiff;
+
+ // Wait until Ctags finishes
+ if (!m_bReady) {
+ m_nPendLine = nLine;
+ return;
+ }
+
+ // Do nothing if no tags are available
+ if (m_nItems == 0)
+ return;
+
+ // Calculate the difference from the current line
+ nDiff = (int)(nLine - m_nCurLine);
+ m_nCurLine = nLine;
+
+ // In most cases, all the user does is move to the next or prevuious lines
+ // Handle these simple cases first
+ if (nDiff == 1) {
+ if ((m_nCurItem < m_nItems - 1) &&
+ (m_arrLines[m_nCurItem + 1]->getLine() == nLine)) {
+ m_nCurItem++;
+ }
+ else {
+ return; // New line corresponds to the same tag
+ }
+ }
+ else if (nDiff == -1) {
+ if ((m_nCurItem > 0) &&
+ (m_arrLines[m_nCurItem]->getLine() > nLine)) {
+ m_nCurItem--;
+ }
+ else {
+ return; // New line corresponds to the same tag
+ }
+ }
+ else {
+ // Initialise binary search
+ nFrom = 0;
+ nTo = m_nItems - 1;
+ m_nCurItem = 0; // use the first item if nothing else works
+
+ // Perform a binary search
+ // This algorithm finds the greatest line that is smaller or equal to
+ // the requested line
+ do {
+ nItem = (nFrom + nTo) / 2;
+ pItem = m_arrLines[nItem];
+
+ if (pItem->getLine() == nLine) {
+ m_nCurItem = nItem;
+ break;
+ }
+ else if (nLine > pItem->getLine()) {
+ m_nCurItem = nItem;
+ nFrom = nItem + 1;
+ }
+ else {
+ nTo = nItem - 1;
+ }
+ } while (nFrom <= nTo);
+ }
+
+ // Mark the selected item
+ pItem = m_arrLines[m_nCurItem];
+ m_pList->setSelected(pItem, true);
+ m_pList->ensureItemVisible(pItem);
+
+ m_nPendLine = 0;
+}
+
+/**
+ * Deletes all items in the list.
+ */
+void CtagsList::clear()
+{
+ m_pList->clear();
+ m_nItems = 0;
+ m_nCurItem = 0;
+ m_nCurLine = 0;
+ m_nPendLine = 0;
+ m_bReady = false;
+}
+
+/**
+ * Indicates Ctags has finished processing the current file.
+ * If a goto operation has been scheduled, it is processed.
+ * @param nRecords The number of records generated by Ctags
+ */
+void CtagsList::slotCtagsFinished(uint nRecords)
+{
+ if (nRecords) {
+ m_bReady = true;
+ if (m_nPendLine)
+ gotoLine(m_nPendLine);
+ }
+}
+
+/**
+ * Determines the new sort order in the tags list.
+ * This slot is connected to the clicked() signal of the tag list's header.
+ * @param nSection Identifies the column whose header button was clicked.
+ */
+void CtagsList::slotSortChanged(int nSection)
+{
+ Qt::SortOrder order;
+
+ // Determine whether the new order is ascending or descending
+ order = m_pList->sortOrder();
+
+ // Translate the section number into the order constant
+ switch (nSection) {
+ case 0:
+ // Sort by name
+ Config().setCtagSortOrder(order == Qt::Ascending ?
+ KScopeConfig::NameAsc : KScopeConfig::NameDes);
+ break;
+
+ case 1:
+ // Sort by line
+ Config().setCtagSortOrder(order == Qt::Ascending ?
+ KScopeConfig::LineAsc : KScopeConfig::LineDes);
+ break;
+
+ case 2:
+ // Sort by type
+ Config().setCtagSortOrder(order == Qt::Ascending ?
+ KScopeConfig::TypeAsc : KScopeConfig::TypeDes);
+ break;
+ }
+}
+
+#include "ctagslist.moc"
diff --git a/src/ctagslist.h b/src/ctagslist.h
new file mode 100644
index 0000000..4d318cc
--- /dev/null
+++ b/src/ctagslist.h
@@ -0,0 +1,108 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef CTAGSLIST_H
+#define CTAGSLIST_H
+
+#include <qwidget.h>
+#include <qpixmap.h>
+#include <qmemarray.h>
+#include "searchlist.h"
+#include "frontend.h"
+
+class CtagsListItem;
+class CtagsToolTip;
+
+/**
+ * Displays a list of tags for a source file.
+ * The list is embedded inside an editor page. Whenever a new document is
+ * opened in that editor, or the current document is changed and saved, the
+ * source file is re-scanned for tags, and the results are displayed in this
+ * list.
+ * @author Elad Lahav
+ */
+
+class CtagsList : public SearchList
+{
+ Q_OBJECT
+
+public:
+ CtagsList(QWidget* pParent = 0, const char* szName = 0);
+ ~CtagsList();
+
+ void applyPrefs();
+ void gotoLine(uint);
+ void clear();
+
+ virtual bool getTip(QListViewItem*, QString&);
+
+public slots:
+ void slotDataReady(FrontendToken*);
+ void slotCtagsFinished(uint);
+
+signals:
+ /**
+ * Emitted when the size of the list is changed (usually as the result
+ * of moving the separator between the list and the editor.)
+ */
+ void resized();
+
+ /**
+ * Emitted when the user selects a tag item from the list.
+ * @param nLine The line number associated with the selected tag
+ */
+ void lineRequested(uint nLine);
+
+protected:
+ virtual void resizeEvent(QResizeEvent*);
+ virtual void processItemSelected(QListViewItem*);
+
+private:
+ /** An array of pointers to the tag list items, sorted by the line
+ number. */
+ QMemArray<CtagsListItem*> m_arrLines;
+
+ /** The number of items in the tag list. */
+ uint m_nItems;
+
+ /** The last item selected by gotoLine(). */
+ uint m_nCurItem;
+
+ /** This value is set to 'false' while the Ctags process is running. */
+ bool m_bReady;
+
+ /** The current line number. */
+ uint m_nCurLine;
+
+ /** Stores the requested line number during Ctags operation. */
+ uint m_nPendLine;
+
+private slots:
+ void slotSortChanged(int);
+};
+
+#endif
diff --git a/src/dirscanner.cpp b/src/dirscanner.cpp
new file mode 100644
index 0000000..517237e
--- /dev/null
+++ b/src/dirscanner.cpp
@@ -0,0 +1,164 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qapplication.h>
+#include "dirscanner.h"
+
+/**
+ * Class constructor.
+ * @param nFiles The number of files scanned since the previous event
+ * @param bFinished true if all files were scanned, false otherwise
+ */
+DirScanEvent::DirScanEvent(int nFiles, bool bFinished)
+ : QCustomEvent(EventId),
+ m_nFiles(nFiles),
+ m_bFinished(bFinished)
+{
+}
+
+/**
+ * Class constructor.
+ * @param pEventReceiver Pointer to an object to receive DirScanEvent
+ * updates
+ * @param pDicFiles Pointer to a map of current project files (to
+ avoid duplication)
+ */
+DirScanner::DirScanner(QObject* pEventReceiver,
+ QDict<QListViewItem>* pDicFiles) : QThread(),
+ m_pEventReceiver(pEventReceiver),
+ m_pDicFiles(pDicFiles)
+{
+}
+
+/**
+ * Class destructor.
+ */
+DirScanner::~DirScanner()
+{
+}
+
+/**
+ * Begins a new search for source files.
+ * Invokes the search thread on a given directory. The search may be either
+ * recursive (i.e., the search will descend to each sub-directory) or flat
+ * (will search the given directory only.)
+ * @param sDir The name of the directory to search
+ * @param sNameFilter Defines the search pattern
+ * @param bRecursive true to descend into sub-dorectories, false otherwise
+ */
+void DirScanner::start(const QString& sDir, const QString& sNameFilter,
+ bool bRecursive)
+{
+ // Initialise the search parameters
+ m_dir = QDir(sDir);
+ m_sNameFilter = sNameFilter;
+ m_bCancel = false;
+ m_bRecursive = bRecursive;
+ m_slFiles.clear();
+
+ // Invoke the thread
+ QThread::start();
+}
+
+/**
+ * Begins a scan of files on the directory associated with this object.
+ * Note that this function is synchronous: it returns when the scan ends.
+ */
+void DirScanner::run()
+{
+ int nFiles;
+
+ nFiles = scanDir(m_dir);
+ QApplication::postEvent(m_pEventReceiver,
+ new DirScanEvent(nFiles, true));
+
+ m_setScanned.clear();
+}
+
+/**
+ * Recursively scans a directory for a files matching the current filter.
+ * @param dir A directory object set to the folder from which files are
+ * added
+ * @return The total number of files added
+ */
+int DirScanner::scanDir(QDir& dir)
+{
+ QString sCanon;
+ QStringList slDirFiles, slDirs;
+ QStringList::const_iterator itr;
+ QString sFile;
+ int nFiles = 0;
+
+ if (m_bCancel)
+ return -1;
+
+ // Make sure this directory has not been previously visited (e.g., through a
+ // symbolic link)
+ sCanon = dir.canonicalPath();
+ if (m_setScanned.exists(sCanon))
+ return 0;
+
+ m_setScanned.insert(sCanon);
+
+ // Add all files in this directory
+ slDirFiles = dir.entryList(m_sNameFilter, QDir::Files);
+ for (itr = slDirFiles.begin(); itr != slDirFiles.end(); ++itr) {
+ sFile = dir.absPath() + "/" + *itr;
+
+ // Make sure an entry for this file does not exist
+ if (m_pDicFiles->find(sFile) == NULL) {
+ m_slFiles.append(sFile);
+ nFiles++;
+ }
+ }
+
+ QApplication::postEvent(m_pEventReceiver,
+ new DirScanEvent(nFiles, false));
+
+ // Recurse into sub-directories, if requested
+ if (!m_bRecursive)
+ return nFiles;
+
+ slDirs = dir.entryList(QDir::Dirs);
+
+ // Iterate the list of sub-directories
+ for (itr = slDirs.begin(); itr != slDirs.end(); ++itr) {
+ if (m_bCancel)
+ return -1;
+
+ // Skip the "." and ".." directories
+ if (*itr == "." || *itr == "..")
+ continue;
+
+ // Add the files in each sub-directory
+ QDir dirSub(dir);
+ if (dirSub.cd(*itr))
+ nFiles += scanDir(dirSub);
+ }
+
+ return nFiles;
+}
diff --git a/src/dirscanner.h b/src/dirscanner.h
new file mode 100644
index 0000000..b25fc2d
--- /dev/null
+++ b/src/dirscanner.h
@@ -0,0 +1,144 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef DIRSCANNER_H
+#define DIRSCANNER_H
+
+#include <qobject.h>
+#include <qevent.h>
+#include <qthread.h>
+#include <qdir.h>
+#include <qstringlist.h>
+#include <qdict.h>
+#include <qlistview.h>
+
+class DirScanner;
+
+/**
+ * Defines a new event that can be used to pass progress information from the
+ * dir scanning thread to the main application thread.
+ * @author Elad Lahav
+ */
+class DirScanEvent : public QCustomEvent
+{
+public:
+ /** The event's unique ID. */
+ enum { EventId = 6924 };
+
+ DirScanEvent(int, bool);
+
+ /** The number of files already scanned. */
+ int m_nFiles;
+
+ /** True if the dir scanning thread has finished, false otherwise. */
+ bool m_bFinished;
+};
+
+/**
+ * A set of unique strings.
+ * Qt3 does not have a set class, so this is a simple implementation based on
+ * a QDict of dummy int pointers.
+ * @author Elad Lahav
+ */
+class StringSet : public QDict<int>
+{
+public:
+ StringSet() : QDict<int>() {}
+
+ void insert(const QString& sItem) {
+ static int nDummy = 0;
+ QDict<int>::insert(sItem, &nDummy);
+ }
+
+ bool exists(const QString& sItem) {
+ return find(sItem) != NULL;
+ }
+};
+
+/**
+ * Scans a directory for files matching a given pattern, using a separate thread.
+ * @author Elad Lahav
+ */
+class DirScanner : public QThread
+{
+public:
+ DirScanner(QObject*, QDict<QListViewItem>*);
+ ~DirScanner();
+
+ void start(const QString&, const QString&, bool);
+
+ /**
+ * @return The list of files scanned by this thread.
+ */
+ const QStringList& getFiles() { return m_slFiles; }
+
+ /**
+ * Stops a scanning process, by setting the object's cancel flag.
+ */
+ void cancel() { m_bCancel = true; }
+
+ /**
+ * @return true if the user has cancelled the process, false otherwise
+ */
+ bool wasCancelled() { return m_bCancel; }
+
+protected:
+ virtual void run();
+
+private:
+ /** Pointer to an object that receives the scanner update events. */
+ QObject* m_pEventReceiver;
+
+ /** Currently scanned directory. */
+ QDir m_dir;
+
+ /**
+ * A set of already-scanned directories (prevents infinite loops in case
+ * of cyclic symbolic links in the scanned file system).
+ */
+ StringSet m_setScanned;
+
+ /** Pointer to a list of files indexed by the file path (used to identify
+ files that should not appear in the scan results.) */
+ QDict<QListViewItem>* m_pDicFiles;
+
+ /** Regular expression for scanning source files. */
+ QString m_sNameFilter;
+
+ /** The list of scanned file paths. */
+ QStringList m_slFiles;
+
+ /** A cancellation flag. Stops the scanning process when raised. */
+ bool m_bCancel;
+
+ /** true to descend to child directories, false otherwise. */
+ bool m_bRecursive;
+
+ int scanDir(QDir&);
+};
+
+#endif
diff --git a/src/dotfrontend.cpp b/src/dotfrontend.cpp
new file mode 100644
index 0000000..e0cfbed
--- /dev/null
+++ b/src/dotfrontend.cpp
@@ -0,0 +1,297 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2006 Elad Lahav (elad_lahav@users.sf.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qfileinfo.h>
+#include <qpaintdevicemetrics.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include "dotfrontend.h"
+#include "graphwidget.h"
+#include "kscopeconfig.h"
+
+/**
+ * Class constructor.
+ * @param pGraph The graph widget on which to draw the output
+ */
+DotFrontend::DotFrontend(GraphWidget* pGraph) : Frontend(1),
+ m_pGraph(pGraph)
+{
+}
+
+/**
+ * Class destructor.
+ */
+DotFrontend::~DotFrontend()
+{
+}
+
+/**
+ * Executes dot on the goven input file.
+ * @param sFile The path to a temporary file holding the graph's
+ * description
+ * @return true if successful, false otherwise
+ */
+bool DotFrontend::run(const QString& sFile)
+{
+ QString sPath;
+ QStringList slArgs;
+ QPaintDeviceMetrics pdm(m_pGraph);
+
+ // Set the horizontal and vertical DPI values
+ m_dDpiX = (double)pdm.logicalDpiX();
+ m_dDpiY = (double)pdm.logicalDpiY();
+
+ // Make sure the executable exists
+ sPath = Config().getDotPath();
+
+ // Set the command line arguments
+ slArgs.append(sPath);
+ slArgs.append("-Tplain");
+ slArgs.append(sFile);
+
+ // Run a new process
+ if (!Frontend::run("dot", slArgs))
+ return false;
+
+ // Initialize stdout parsing
+ m_state = Graph;
+ m_delim = All;
+
+ return true;
+}
+
+/**
+ * Tests that the given file path leads to an executable.
+ * @param sPath The path to check
+ * @return true if the file in the given path exists and has executable
+ * permissions, false otherwise
+ */
+bool DotFrontend::verify(const QString& sPath)
+{
+ QFileInfo fi(sPath);
+
+ if (!fi.exists() || !fi.isFile() || !fi.isExecutable() ||
+ fi.fileName() != "dot") {
+ KMessageBox::error(0, i18n("Dot cannot be found in the given "
+ "path"));
+ return false;
+ }
+
+ return true;
+}
+
+#define PAD 5
+
+/**
+ * Parses the output of a Dot process.
+ * @param sToken The current token read (the token delimiter is determined
+ * by the current state)
+ * @param delim The delimiter that ends this token
+ * @return A value indicating the way this token should be treated: dropped,
+ * added to the token queue, or finishes a new record
+ */
+Frontend::ParseResult DotFrontend::parseStdout(QString& sToken,
+ ParserDelim delim)
+{
+ static int nWidth, nHeight, nXpos, nYpos, nCurveSize, nCurveCount;
+ static QPointArray arrCurve;
+ static QString sNode, sEdgeHead, sEdgeTail;
+ ParseResult result = DiscardToken;
+ double dVal;
+ bool bOK;
+
+ // Handle the token according to the current state
+ switch (m_state) {
+ case Graph:
+ if (sToken == "graph")
+ m_state = GraphScale;
+ break;
+
+ case GraphScale:
+ sToken.toDouble(&bOK);
+ if (bOK)
+ m_state = GraphWidth;
+ break;
+
+ case GraphWidth:
+ // Read and transform the graph's width
+ dVal = sToken.toDouble(&bOK);
+ if (bOK) {
+ nWidth = (int)(dVal * m_dDpiX) + (PAD * 2);
+ m_state = GraphHeight;
+ }
+ break;
+
+ case GraphHeight:
+ // Read and transform the graph's height
+ dVal = sToken.toDouble(&bOK);
+ if (bOK) {
+ nHeight = (int)(dVal * m_dDpiY) + (PAD * 2);
+
+ // Set the graph's size
+ m_pGraph->resize(nWidth, nHeight);
+
+ m_state = NodeEdgeStop;
+ }
+ break;
+
+ case NodeEdgeStop:
+ // "node" starts a new node
+ // "edge" starts a new edge
+ // "stop" ends this graph
+ if (sToken == "node") {
+ m_state = NodeName;
+ }
+ else if (sToken == "edge") {
+ m_state = EdgeHead;
+ }
+ else if (sToken == "stop") {
+ m_state = Graph;
+ }
+ break;
+
+ case NodeName:
+ // Get a node's name
+ sNode = sToken;
+ m_state = NodeCentreX;
+ break;
+
+ case NodeCentreX:
+ // Read and transform the node's centre location (X coordinate)
+ dVal = sToken.toDouble(&bOK);
+ if (bOK) {
+ nXpos = (int)(dVal * m_dDpiX) + PAD;
+ m_state = NodeCentreY;
+ }
+ break;
+
+ case NodeCentreY:
+ // Read and transform the node's centre location (Y coordinate)
+ dVal = sToken.toDouble(&bOK);
+ if (bOK) {
+ nYpos = (int)(dVal * m_dDpiY) + PAD;
+ m_state = NodeWidth;
+ }
+ break;
+
+ case NodeWidth:
+ // Read and transform the node's width
+ dVal = sToken.toDouble(&bOK);
+ if (bOK) {
+ nWidth = (int)(dVal * m_dDpiX);
+ m_state = NodeHeight;
+ }
+ break;
+
+ case NodeHeight:
+ // Read and transform the node's height
+ dVal = sToken.toDouble(&bOK);
+ if (bOK) {
+ nHeight = (int)(dVal * m_dDpiY);
+
+ // Create the bounding rectangle of the node
+ QRect rect;
+ rect.setX(nXpos - (nWidth / 2));
+ rect.setY(nYpos - (nHeight / 2));
+ rect.setWidth(nWidth);
+ rect.setHeight(nHeight);
+
+ // Draw the node
+ m_pGraph->drawNode(sNode, rect);
+
+ m_state = EndNodeEdge;
+ }
+ break;
+
+ case EdgeHead:
+ // Get the edge's head node
+ sEdgeHead = sToken;
+ m_state = EdgeTail;
+ break;
+
+ case EdgeTail:
+ // Get the edge's tail node
+ sEdgeTail = sToken;
+ m_state = EdgeCurveSize;
+ break;
+
+ case EdgeCurveSize:
+ // Get the number of control points in the edge's spline
+ nCurveSize = sToken.toInt(&bOK);
+ if (bOK) {
+ arrCurve.resize(nCurveSize);
+ nCurveCount = 0;
+ m_state = EdgeCurveX;
+ }
+ break;
+
+ case EdgeCurveX:
+ // Read and a control point (X coordinate)
+ dVal = sToken.toDouble(&bOK);
+ if (bOK) {
+ nXpos = (int)(dVal * m_dDpiX) + PAD;
+ m_state = EdgeCurveY;
+ }
+ break;
+
+ case EdgeCurveY:
+ // Read and a control point (Y coordinate)
+ dVal = sToken.toDouble(&bOK);
+ if (bOK) {
+ nYpos = (int)(dVal * m_dDpiY) + PAD;
+
+ // Add the control point to the spline array
+ arrCurve.setPoint(nCurveCount++, nXpos, nYpos);
+
+ // Check if this is the last control point
+ if (nCurveCount == nCurveSize) {
+ // Draw the edge
+ m_pGraph->drawEdge(sEdgeHead, sEdgeTail, arrCurve);
+
+ // Must detach from contents since a QPointArray shares data
+ arrCurve.detach();
+
+ m_state = EndNodeEdge;
+ }
+ else {
+ // Another control point available
+ m_state = EdgeCurveX;
+ }
+ }
+ break;
+
+ case EndNodeEdge:
+ // Discard everything else on a node or edge line
+ if (delim == Newline)
+ m_state = NodeEdgeStop;
+ break;
+ }
+
+ return result;
+}
+
+#include "dotfrontend.moc"
diff --git a/src/dotfrontend.h b/src/dotfrontend.h
new file mode 100644
index 0000000..24f14f0
--- /dev/null
+++ b/src/dotfrontend.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2006 Elad Lahav (elad_lahav@users.sf.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+#ifndef DOTFRONTEND_H
+#define DOTFRONTEND_H
+
+#include <frontend.h>
+#include <qpointarray.h>
+
+class GraphWidget;
+
+/**
+ * Front-end for executing graphviz's command-line tool.
+ * This tool accepts the description of a graph in the 'dot' language, and
+ * outputs a set of drawing instructions for the graph.
+ * @author Elad Lahav
+ */
+class DotFrontend : public Frontend
+{
+ Q_OBJECT
+
+public:
+ DotFrontend(GraphWidget*);
+ ~DotFrontend();
+
+ bool run(const QString&);
+
+ static bool verify(const QString&);
+
+protected:
+ virtual ParseResult parseStdout(QString&, ParserDelim);
+
+private:
+ /** The owner graph widget on which to draw. */
+ GraphWidget* m_pGraph;
+
+ /** State values for the parser state machine. */
+ enum ParserState { Graph, GraphScale, GraphWidth, GraphHeight,
+ NodeEdgeStop, NodeName, NodeCentreX, NodeCentreY, NodeWidth, NodeHeight,
+ EdgeHead, EdgeTail, EdgeCurveSize, EdgeCurveX, EdgeCurveY,
+ EndNodeEdge };
+
+ /** The current state of the parser state machine. */
+ ParserState m_state;
+
+ /** The horizontal DPI value of the graph widget. */
+ double m_dDpiX;
+
+ /** The vertical DPI value of the graph widget. */
+ double m_dDpiY;
+};
+
+#endif
diff --git a/src/dotparse.ypp b/src/dotparse.ypp
new file mode 100644
index 0000000..f21b9e3
--- /dev/null
+++ b/src/dotparse.ypp
@@ -0,0 +1,234 @@
+/* dot.y */
+
+%{
+#include <qdict.h>
+#include <qptrstack.h>
+#include <qlistview.h>
+#include "calltreedlg.h"
+#include "graphwidget.h"
+#include "treewidget.h"
+#include "encoder.h"
+
+extern FILE* yyin;
+int yylex();
+void yyinit(CallTreeDlg*, FILE*, Encoder*);
+void yyerror(const char*);
+
+static QMap<QString, QString> s_pMapAttr;
+static QStack<QListViewItem> s_pParentStack;
+static QListView* s_pTree;
+
+static GraphWidget* s_pGraph;
+static TreeWidget* s_pCallTree;
+static TreeWidget* s_pCallingTree;
+static Encoder* s_pEncoder;
+
+// Avoid compiler warnings
+#define YYENABLE_NLS 0
+#ifndef YYLTYPE_IS_TRIVIAL
+#define YYLTYPE_IS_TRIVIAL 0
+#endif
+%}
+
+%union {
+ QString* pText;
+}
+
+%token GRAPH DIGRAPH NODE NAME STRING NUMBER DIR_EDGE UNDIR_EDGE
+%token CALL_TREE CALLING_TREE
+%type <pText> NAME STRING NUMBER attr_val
+
+%start file
+
+%%
+
+file
+ : call_tree calling_tree graph
+
+graph
+ : graph_type NAME '{' graph_desc_list '}' { delete $2; }
+ ;
+
+graph_type
+ : GRAPH
+ | DIGRAPH
+ ;
+
+graph_desc_list
+ :
+ | graph_desc_entry graph_desc_list
+ ;
+
+graph_desc_entry
+ : def_node_attr
+ | graph_attr
+ | node_record
+ | edge_record
+ ;
+
+def_node_attr
+ : NODE attributes ';'
+ ;
+
+graph_attr
+ : GRAPH attributes ';'
+ {
+ if (s_pMapAttr.find("kscope_zoom") != s_pMapAttr.end())
+ s_pGraph->setZoom(s_pMapAttr["kscope_zoom"].toDouble());
+ }
+ ;
+
+node_record
+ : NAME attributes ';'
+ {
+ s_pGraph->addNode(*$1);
+ delete $1;
+ s_pMapAttr.clear();
+ }
+ ;
+
+edge_record
+ : NAME edge_type NAME attributes ';'
+ {
+ GraphWidget::CallData cd;
+
+ cd.m_sCaller = *$1;
+ cd.m_sCallee = *$3;
+ cd.m_sFile = s_pMapAttr["kscope_file"];
+ cd.m_sLine = s_pMapAttr["kscope_line"];
+ cd.m_sText = s_pEncoder->decode(s_pMapAttr["kscope_text"]);
+ s_pGraph->addCall(cd);
+
+ delete $1;
+ delete $3;
+ s_pMapAttr.clear();
+ }
+ ;
+
+edge_type
+ : DIR_EDGE
+ | UNDIR_EDGE
+ ;
+
+attributes
+ :
+ | '[' attr_list ']'
+ ;
+
+attr_list
+ :
+ | non_empty_attr_list
+ ;
+
+non_empty_attr_list
+ : attr
+ | attr ',' attr_list
+ ;
+
+attr
+ : NAME '=' attr_val
+ {
+ s_pMapAttr.insert(*$1, *$3);
+ delete $1;
+ delete $3;
+ }
+ ;
+
+attr_val
+ : NAME
+ | STRING
+ | NUMBER
+ ;
+
+call_tree
+ : call_tree_prepare '{' root_node '}'
+ ;
+
+call_tree_prepare
+ : CALL_TREE { s_pTree = s_pCallTree; }
+ ;
+
+calling_tree
+ : calling_tree_prepare '{' root_node '}'
+ ;
+
+calling_tree_prepare
+ : CALLING_TREE { s_pTree = s_pCallingTree; }
+ ;
+
+root_node
+ : root_tree_node '{' child_list '}'
+ {
+ QListViewItem* pItem;
+
+ pItem = s_pParentStack.pop();
+ if (pItem->firstChild() != NULL)
+ pItem->setOpen(true);
+ }
+ ;
+
+root_tree_node
+ : NAME
+ {
+ QListViewItem* pItem;
+
+ pItem = new QListViewItem(s_pTree, *$1);
+ s_pParentStack.push(pItem);
+ delete $1;
+ }
+ ;
+
+child_list
+ :
+ | child_node child_list
+ ;
+
+child_node
+ : tree_node tree_attributes '{' child_list '}'
+ {
+ QListViewItem* pItem;
+
+ pItem = s_pParentStack.pop();
+ if (pItem->firstChild() != NULL)
+ pItem->setOpen(true);
+ }
+ ;
+
+tree_node
+ : NAME
+ {
+ QListViewItem* pItem;
+
+ pItem = new QListViewItem(s_pParentStack.top(), *$1);
+ s_pParentStack.push(pItem);
+ delete $1;
+ }
+ ;
+
+tree_attributes
+ : attributes
+ {
+ QListViewItem* pItem;
+
+ pItem = s_pParentStack.top();
+ pItem->setText(1, s_pMapAttr["kscope_file"]);
+ pItem->setText(2, s_pMapAttr["kscope_line"]);
+ pItem->setText(3, s_pEncoder->decode(s_pMapAttr["kscope_text"]));
+ }
+ ;
+
+%%
+
+void yyinit(CallTreeDlg* pDlg, FILE* pFile, Encoder* pEnc)
+{
+ yyin = pFile;
+ s_pCallTree = pDlg->m_pCalledWidget;
+ s_pCallingTree = pDlg->m_pCallingWidget;
+ s_pGraph = pDlg->m_pGraphWidget;
+ s_pEncoder = pEnc;
+}
+
+void yyerror(const char* szError)
+{
+ fprintf(stderr, "%s\n", szError);
+}
diff --git a/src/dotscan.lpp b/src/dotscan.lpp
new file mode 100644
index 0000000..0667d33
--- /dev/null
+++ b/src/dotscan.lpp
@@ -0,0 +1,36 @@
+/* dot.l */
+
+%{
+#include <qstring.h>
+#include "dotparse.h"
+%}
+
+%option noyywrap
+
+name [a-zA-Z_][a-zA-Z0-9_]*
+string \"(\\.|[^\"])*\"
+space [ \t\n]+
+number [1-9][0-9]*
+float [0-9]*\.[0-9]+
+
+%%
+
+"graph" return GRAPH;
+"digraph" return DIGRAPH;
+"calltree" return CALL_TREE;
+"callingtree" return CALLING_TREE;
+"node" return NODE;
+"->" return DIR_EDGE;
+"--" return UNDIR_EDGE;
+{name} { yylval.pText = new QString(yytext); return NAME; }
+{string} {
+ QString str = &yytext[1];
+ yylval.pText = new QString(str.left(yyleng - 2));
+ return STRING;
+ }
+{number} { yylval.pText = new QString(yytext); return NUMBER; }
+{float} { yylval.pText = new QString(yytext); return NUMBER; }
+{space} ;
+. return yytext[0];
+
+%%
diff --git a/src/editormanager.cpp b/src/editormanager.cpp
new file mode 100644
index 0000000..253bf6c
--- /dev/null
+++ b/src/editormanager.cpp
@@ -0,0 +1,89 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <ktexteditor/editorchooser.h>
+#include <kate/document.h>
+#include "editormanager.h"
+#include "kscopeconfig.h"
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+EditorManager::EditorManager(QWidget* pParent, const char* szName) :
+ KParts::PartManager(pParent, szName)
+{
+ applyPrefs();
+}
+
+/**
+ * Class destructor.
+ */
+EditorManager::~EditorManager()
+{
+}
+
+/**
+ * Creates a new document part.
+ * @return A pointer to the new document
+ */
+KTextEditor::Document* EditorManager::add()
+{
+ KTextEditor::Document* pDoc;
+
+ // Create the document
+ pDoc = KTextEditor::EditorChooser::createDocument(this);
+ addPart(pDoc);
+
+ return pDoc;
+}
+
+/**
+ * Deletes a document part.
+ * @param pDoc The document to remove
+ */
+void EditorManager::remove(KTextEditor::Document* pDoc)
+{
+ removePart(pDoc);
+ delete pDoc;
+}
+
+/**
+ * Applies the user preferences.
+ * Determines if Kate warnings are displayed in case the currently edited
+ * file is modified outside KScope.
+ * NOTE: This behaviour is determined by a static function, which is why this
+ * code appears here, rather then for every EditorPage object.
+ */
+void EditorManager::applyPrefs()
+{
+ Kate::Document::setFileChangedDialogsActivated(
+ Config().getWarnModifiedOnDisk());
+}
+
+#include "editormanager.moc"
diff --git a/src/editormanager.h b/src/editormanager.h
new file mode 100644
index 0000000..413ffed
--- /dev/null
+++ b/src/editormanager.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef EDITORMANAGER_H
+#define EDITORMANAGER_H
+
+#include <qwidget.h>
+#include <kparts/partmanager.h>
+#include <klibloader.h>
+#include <ktexteditor/document.h>
+
+/**
+ * Creates text editor parts, used to open source files.
+ * The EditorManager is responsible for creating parts, and managing their
+ * GUI integration.
+ * @author Elad Lahav
+ */
+
+class EditorManager : public KParts::PartManager
+{
+ Q_OBJECT
+
+public:
+ EditorManager(QWidget* pParent = 0, const char* szName = 0);
+ ~EditorManager();
+
+ KTextEditor::Document* add();
+ void remove(KTextEditor::Document*);
+ void applyPrefs();
+};
+
+#endif
diff --git a/src/editorpage.cpp b/src/editorpage.cpp
new file mode 100644
index 0000000..5c183b9
--- /dev/null
+++ b/src/editorpage.cpp
@@ -0,0 +1,720 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qfileinfo.h>
+#include <kdeversion.h>
+#include <ktexteditor/selectioninterface.h>
+#include <ktexteditor/viewcursorinterface.h>
+#include <ktexteditor/popupmenuinterface.h>
+#include <ktexteditor/editinterface.h>
+#include <kate/document.h>
+#include <kate/view.h>
+#include "editorpage.h"
+#include "kscopeconfig.h"
+
+/**
+ * Class constructor.
+ * @param pDoc The document object associated with this page
+ * @param pMenu A Cscope queries popup menu to use with the editor
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+EditorPage::EditorPage(KTextEditor::Document* pDoc, QPopupMenu* pMenu,
+ QTabWidget* pParent, const char* szName) : QHBox(pParent, szName),
+ m_pParentTab(pParent),
+ m_pDoc(pDoc),
+ m_bOpen(false),
+ m_bNewFile(false),
+ m_sName(""),
+ m_bWritable(true), /* new documents are writable by default */
+ m_bModified(false),
+ m_nLine(0),
+ m_bSaveNewSizes(false)
+{
+ KTextEditor::PopupMenuInterface* pMenuIf;
+ KTextEditor::ViewCursorInterface* pCursorIf;
+
+ // Create code-completion objects (will be deleted by QObject destructor)
+ m_pCompletion = new SymbolCompletion(this, this);
+
+ // Set read-only mode, if required
+ if (Config().getReadOnlyMode())
+ m_pDoc->setReadWrite(false);
+
+ // Create the child widgets
+ m_pSplit = new QSplitter(this);
+ m_pCtagsList = new CtagsList(m_pSplit);
+ m_pView = m_pDoc->createView(m_pSplit);
+ m_pSplit->setResizeMode(m_pCtagsList, QSplitter::KeepSize);
+
+ // Perform tasks only when the document has been loaded completely
+ connect(m_pDoc, SIGNAL(completed()), this, SLOT(slotFileOpened()));
+
+ // Be notified when the text in the editor changes
+ connect(m_pDoc, SIGNAL(textChanged()), this, SLOT(slotSetModified()));
+ connect(m_pDoc, SIGNAL(undoChanged()), this, SLOT(slotUndoChanged()));
+
+ // Store the sizes of the child windows when the tag list is resized
+ // (since it may imply a move of the splitter divider)
+ connect(m_pCtagsList, SIGNAL(resized()), this, SLOT(slotChildResized()));
+
+ // Go to a symbol's line if it is selected in the tag list
+ connect(m_pCtagsList, SIGNAL(lineRequested(uint)), this,
+ SLOT(slotGotoLine(uint)));
+
+ // Add Ctag records to the tag list
+ connect(&m_ctags, SIGNAL(dataReady(FrontendToken*)), m_pCtagsList,
+ SLOT(slotDataReady(FrontendToken*)));
+
+ // Monitor Ctags' operation
+ connect(&m_ctags, SIGNAL(finished(uint)), m_pCtagsList,
+ SLOT(slotCtagsFinished(uint)));
+
+ // Set the context menu
+ pMenuIf = dynamic_cast<KTextEditor::PopupMenuInterface*>(m_pView);
+ if (pMenuIf)
+ pMenuIf->installPopup(pMenu);
+
+ // Emit a signal whenever the cursor's position changes
+ pCursorIf = dynamic_cast<KTextEditor::ViewCursorInterface*>(m_pView);
+ if (pCursorIf) {
+ connect(m_pView, SIGNAL(cursorPositionChanged()), this,
+ SLOT(slotCursorPosChange()));
+ }
+}
+
+/**
+ * Class destructor.
+ */
+EditorPage::~EditorPage()
+{
+}
+
+/**
+ * Returns a pointer to the editor document object embedded in this page.
+ * @returns the document pointer
+ */
+KTextEditor::Document* EditorPage::getDocument()
+{
+ return m_pDoc;
+}
+
+/**
+ * Returns a pointer to the editor view object embedded in this page.
+ * @returns the view pointer
+ */
+KTextEditor::View* EditorPage::getView()
+{
+ return m_pView;
+}
+
+/**
+ * Returns the full path of the file being edited.
+ * @return The path of the file associated with the Document object, empty
+ * string if no file is currently open
+ */
+QString EditorPage::getFilePath()
+{
+ return m_pDoc->url().path();
+}
+
+/**
+ * Returns the name of the file being edited.
+ * @return The name of the file associated with the Document object, empty
+ * string if no file is currently open
+ */
+QString EditorPage::getFileName()
+{
+ return m_sName;
+}
+
+/**
+ * Determines whether this file can be modified, according to the file-system
+ * permissions, and KScope's global settings.
+ * @return true if this document can be changed, false otherwise
+ */
+bool EditorPage::isWritable()
+{
+ // Check global settings first
+ if (Config().getReadOnlyMode())
+ return false;
+
+ // Return FS write permissions
+ return m_bWritable;
+}
+
+/**
+ * Determines if the file edited in this page was modified, and the changes
+ * were not yet saved.
+ * @return true if the file was modified, false otherwise
+ */
+bool EditorPage::isModified()
+{
+ return m_pDoc->isModified();
+}
+
+/**
+ * Opens a file for editing.
+ * @param sFileName The full path name of the file to edit.
+ */
+void EditorPage::open(const QString& sFileName)
+{
+ // Open the given file
+ m_bOpen = false;
+ m_pDoc->openURL(sFileName);
+}
+
+/**
+ * Marks the page as containing a new unnamed file.
+ */
+void EditorPage::setNewFile()
+{
+ m_bNewFile = true;
+ emit newFile(this);
+}
+
+/**
+ * Saves the edited file.
+ */
+void EditorPage::save()
+{
+ if (m_pDoc->isModified())
+ m_pDoc->save();
+}
+
+/**
+ * Closes an edited file.
+ * @param bForce true to close the file regardless of any modifications,
+ * false to prompt the user in case of unsaved chnages
+ * @return true if the file has been closed, false if the user has aborted
+ */
+bool EditorPage::close(bool bForce)
+{
+ QString sPath;
+
+ // To override the prompt-on-close behaviour, we need to mark the file
+ // as unmodified
+ if (bForce)
+ m_pDoc->setModified(false);
+
+ // Close the file, unless the user aborts the action
+ sPath = m_pDoc->url().path();
+ if (!m_pDoc->closeURL())
+ return false;
+
+ emit fileClosed(sPath);
+ return true;
+}
+
+/**
+ * Applies any changes to the user preferences concerning an editor window.
+ */
+void EditorPage::applyPrefs()
+{
+ // Determine whether the editor should work in a read-only mode
+ if (m_bWritable)
+ m_pDoc->setReadWrite(!Config().getReadOnlyMode());
+
+ // Apply preferences to the tag list of this window
+ m_pCtagsList->applyPrefs();
+}
+
+/**
+ * Sets the keyboard focus to the editor part of the page.
+ * This method is called whenever the page is activated. It is more reasonable
+ * to set the focus to the editor than to the tag list.
+ */
+void EditorPage::setEditorFocus()
+{
+ m_pView->setFocus();
+ slotCursorPosChange();
+}
+
+/**
+ * Sets the keyboard focus to the tag list.
+ * This method is called when the "Go To Tag" menu command is invoked.
+ */
+void EditorPage::setTagListFocus()
+{
+ m_pCtagsList->slotSetFocus();
+}
+
+/**
+ * Sets a bookmark at the given line.
+ * @param nLine The line to mark
+ */
+void EditorPage::addBookmark(uint nLine)
+{
+ KTextEditor::MarkInterface* pMarkIf;
+
+ pMarkIf = dynamic_cast<KTextEditor::MarkInterface*>(m_pDoc);
+ if (pMarkIf)
+ pMarkIf->setMark(nLine, KTextEditor::MarkInterface::markType01);
+}
+
+/**
+ * Retrieves a list of all bookmarks in this page.
+ */
+void EditorPage::getBookmarks(FileLocationList& fll)
+{
+ KTextEditor::MarkInterface* pMarkIf;
+ QPtrList<KTextEditor::Mark> plMarks;
+ KTextEditor::Mark* pMark;
+
+ // Get the marks interface
+ pMarkIf = dynamic_cast<KTextEditor::MarkInterface*>(m_pDoc);
+ if (!pMarkIf)
+ return;
+
+ // Find all bookmarks
+ plMarks = pMarkIf->marks();
+ for (pMark = plMarks.first(); pMark; pMark = plMarks.next()) {
+ if (pMark->type == KTextEditor::MarkInterface::markType01)
+ fll.append(new FileLocation(getFilePath(), pMark->line, 0));
+ }
+}
+
+/**
+ * Returns the currently selected text in an open file.
+ * @return The selected text, or a null string if no text is currently
+ * selected
+ */
+QString EditorPage::getSelection()
+{
+ KTextEditor::SelectionInterface* pSelect;
+
+ // Get the selected text
+ pSelect = dynamic_cast<KTextEditor::SelectionInterface*>(m_pDoc);
+ if (!pSelect || !pSelect->hasSelection())
+ return QString::null;
+
+ // Return the selected text
+ return pSelect->selection();
+}
+/**
+ * Returns a the complete word defined by the current cursor position.
+ * Attempts to extract a valid C symbol from the location of the cursor, by
+ * starting at the current line and column, and looking forward and backward
+ * for non-symbol characters.
+ * @return A C symbol under the cursor, if any, or QString::null otherwise
+ */
+QString EditorPage::getWordUnderCursor(uint* pPosInWord)
+{
+ KTextEditor::ViewCursorInterface* pCursor;
+ KTextEditor::EditInterface* pEditIf;
+ QString sLine;
+ uint nLine, nCol, nFrom, nTo, nLast, nLength;
+ QChar ch;
+
+ // Get a cursor object
+ pCursor = dynamic_cast<KTextEditor::ViewCursorInterface*>(m_pView);
+ if (pCursor == NULL)
+ return QString::null;
+
+ // Get a pointer to the edit interface
+ pEditIf = dynamic_cast<KTextEditor::EditInterface*>(m_pDoc);
+ if (!pEditIf)
+ return QString::null;
+
+ // Get the line on which the cursor is positioned
+ pCursor->cursorPositionReal(&nLine, &nCol);
+ sLine = pEditIf->textLine(nLine);
+
+ // Find the beginning of the current word
+ for (nFrom = nCol; nFrom > 0;) {
+ ch = sLine.at(nFrom - 1);
+ if (!ch.isLetter() && !ch.isDigit() && ch != '_')
+ break;
+
+ nFrom--;
+ }
+
+ // Find the end of the current word
+ nLast = sLine.length();
+ for (nTo = nCol; nTo < nLast;) {
+ ch = sLine.at(nTo);
+ if (!ch.isLetter() && !ch.isDigit() && ch != '_')
+ break;
+
+ nTo++;
+ }
+
+ // Mark empty words
+ nLength = nTo - nFrom;
+ if (nLength == 0)
+ return QString::null;
+
+ // Return the in-word position, if required
+ if (pPosInWord != NULL)
+ *pPosInWord = nCol - nFrom;
+
+ // Extract the word under the cursor from the entire line
+ return sLine.mid(nFrom, nLength);
+}
+
+/**
+ * Combines getSelection() and getWordUnderCursor() to return a suggested
+ * text for queries.
+ * The function first looks if any text is selected. If so, the selected text
+ * is returned. Otherwise, the word under the cursor location is returned, if
+ * one exists.
+ * @return Either the currently selected text, or the word under the cursor,
+ * or QString::null if both options fail
+ */
+QString EditorPage::getSuggestedText()
+{
+ QString sText;
+
+ sText = getSelection();
+ if (sText == QString::null)
+ sText = getWordUnderCursor();
+
+ return sText;
+}
+
+/**
+ * Returns the contents of the requested line.
+ * Truncates the leading and trailing white spaces.
+ * @param nLine The line number
+ * @return The text of the requested line, if successful, QString::null
+ * otherwise
+ */
+QString EditorPage::getLineContents(uint nLine)
+{
+ KTextEditor::EditInterface* pEditIf;
+ QString sLine;
+
+ // Cannot accept line 0
+ if (nLine == 0)
+ return QString::null;
+
+ // Get a pointer to the edit interface
+ pEditIf = dynamic_cast<KTextEditor::EditInterface*>(m_pDoc);
+ if (!pEditIf)
+ return QString::null;
+
+ // Get the line on which the cursor is positioned
+ sLine = pEditIf->textLine(nLine - 1);
+ return sLine.stripWhiteSpace();
+}
+
+/**
+ * Moves the editing caret to the beginning of a given line.
+ * @param nLine The line number to move to
+ */
+void EditorPage::slotGotoLine(uint nLine)
+{
+ // Ensure there is an open document
+ if (!m_bOpen)
+ return;
+
+ // Set the cursor to the requested line
+ if (!setCursorPos(nLine))
+ return;
+
+ // Update Ctags view
+ m_pCtagsList->gotoLine(nLine);
+
+ // Set the focus to the selected line
+ m_pView->setFocus();
+}
+
+/**
+ * Sets this editor as the current page, when the edited file's name is
+ * selected in the "Window" menu.
+ */
+void EditorPage::slotMenuSelect()
+{
+ m_pParentTab->setCurrentPage(m_pParentTab->indexOf(this));
+}
+
+/**
+ * Displays a list of possible completions for the symbol currently under the
+ * cursor.
+ */
+void EditorPage::slotCompleteSymbol()
+{
+ m_pCompletion->slotComplete();
+}
+
+/**
+ * Stores the sizes of the child widgets whenever they are changed.
+ * This slot is connected to the resized() signal of the CtagsList child
+ * widget.
+ */
+void EditorPage::slotChildResized()
+{
+ SPLIT_SIZES si;
+
+ // Only store sizes when allowed to
+ if (!m_bSaveNewSizes) {
+ m_bSaveNewSizes = true;
+ return;
+ }
+
+ // Get the current widths of the child widgets
+ si = m_pSplit->sizes();
+ if (si.count() == 2)
+ Config().setEditorSizes(si);
+}
+
+/**
+ * Sets the visibility status and sizes of the child widgets.
+ * @param bShowTagList true to show the tag list, false otherwise
+ * @param si The new sizes to use
+ */
+void EditorPage::setLayout(bool bShowTagList, const SPLIT_SIZES& si)
+{
+ // Make sure sizes are not stored during this process
+ m_bSaveNewSizes = false;
+
+ // Adjust the layout
+ m_pCtagsList->setShown(bShowTagList);
+ if (bShowTagList)
+ m_pSplit->setSizes(si);
+}
+
+/**
+ * Returns the current position of the cursor.
+ * @param nLine Holds the line on which the cursor is currently located
+ * @param nCol Holds the column on which the cursor is currently located
+ * @return true if successful, false otherwise (cursor interface was not
+ * obtained)
+ */
+bool EditorPage::getCursorPos(uint& nLine, uint& nCol)
+{
+ KTextEditor::ViewCursorInterface* pCursorIf;
+
+ // Acquire the view cursor
+ pCursorIf = dynamic_cast<KTextEditor::ViewCursorInterface*>(m_pView);
+ if (pCursorIf == NULL)
+ return false;
+
+ // Get the cursor position (adjusted to 1-based counting)
+ pCursorIf->cursorPosition(&nLine, &nCol);
+ nLine++;
+ nCol++;
+
+ return true;
+}
+
+/**
+ * Moves the cursor to a given position.
+ * @param nLine The cursor's new line number
+ * @param nCol The cursor's new column number
+ * @return true if successful, false otherwise (cursor interface was not
+ * obtained)
+ */
+bool EditorPage::setCursorPos(uint nLine, uint nCol)
+{
+ Kate::View* pKateView;
+ KTextEditor::ViewCursorInterface* pCursorIf;
+
+ // Cannot accept line 0
+ if (nLine == 0)
+ return false;
+
+ // Adjust to 0-based counting
+ nLine--;
+ nCol--;
+
+ // Acquire the view cursor
+ pCursorIf = dynamic_cast<KTextEditor::ViewCursorInterface*>(m_pView);
+ if (pCursorIf == NULL)
+ return false;
+
+ // NOTE: The following code is a fix to a bug in Kate, which wrongly
+ // calculates the column number in setCursorPosition.
+ pKateView = dynamic_cast<Kate::View*>(m_pView);
+ if (pKateView != NULL) {
+ KTextEditor::EditInterface* pEditIf;
+ const char* szLine;
+ uint nRealCol;
+ uint nTabAdjust;
+
+ // Get a pointer to the edit interface
+ pEditIf = dynamic_cast<KTextEditor::EditInterface*>(m_pDoc);
+ if (!pEditIf)
+ return false;
+
+ nRealCol = 0;
+
+ // Check for out of bound line numbers
+ if (nLine < pEditIf->numLines()) {
+ // Get the contents of the requested line
+ szLine = pEditIf->textLine(nLine).latin1();
+
+ // Check for empty line
+ if (szLine != NULL) {
+ // The number of columns which a tab character adds
+ nTabAdjust = pKateView->tabWidth() - 1;
+
+ // Calculate the real column, based on the tab width
+ for (; nRealCol < nCol && szLine[nRealCol] != 0; nRealCol++) {
+ if (szLine[nRealCol] == '\t')
+ nCol -= nTabAdjust;
+ }
+ }
+ }
+ else {
+ // Marker set beyond end of file, move to the last line
+ nLine = pEditIf->numLines() - 1;
+ }
+ // Set the cursor position
+ pCursorIf->setCursorPositionReal(nLine, nRealCol);
+ }
+ else {
+ // Non-Kate editors: set the cursor position normally
+ pCursorIf->setCursorPosition(nLine, nCol);
+ }
+
+ return true;
+}
+
+void EditorPage::setTabWidth(uint nTabWidth)
+{
+ Kate::Document* pKateDoc;
+ Kate::Command* pKateCmd;
+ QString sCmd, sResult;
+
+ pKateDoc = dynamic_cast<Kate::Document*>(m_pDoc);
+ if ((pKateDoc) &&
+ (pKateCmd = pKateDoc->queryCommand("set-tab-width"))) {
+ sCmd.sprintf("set-tab-width %u", nTabWidth);
+ pKateCmd->exec((Kate::View*)m_pView, sCmd, sResult);
+ }
+}
+
+/**
+ * Called when a document has completed loading.
+ * Determines the file's properties and refreshes the tag list of the editor
+ * window.
+ * This slot is connected to the completed() signal of the document object.
+ * The signal is emitted when a new file is opened, or when a modified file is
+ * saved.
+ */
+void EditorPage::slotFileOpened()
+{
+ QFileInfo fi(m_pDoc->url().path());
+
+ // Get file information
+ m_sName = fi.fileName();
+ m_bWritable = fi.isWritable();
+
+ // Set read/write or read-only mode
+ m_pDoc->setReadWrite(!Config().getReadOnlyMode() && m_bWritable);
+
+ // Refresh the tag list
+ m_pCtagsList->clear();
+ m_ctags.run(m_pDoc->url().path());
+
+ // Check if this is a modified file that has just been saved
+ if (m_bModified)
+ emit fileSaved(m_pDoc->url().path(), m_bNewFile);
+
+ // Notify that the document has loaded
+ m_bOpen = true;
+ m_bModified = false;
+ emit fileOpened(this, m_pDoc->url().path());
+
+ // Set initial position of the cursor
+ m_nLine = 0;
+ slotCursorPosChange();
+
+ // This is no longer a new file
+ m_bNewFile = false;
+}
+
+/**
+ * Marks a file as modified when the contents of the editor change.
+ * This slot is conncted to the textChanged() signal of the Document object.
+ * In addition to marking the file, this method also emits the modified()
+ * signal.
+ */
+void EditorPage::slotSetModified()
+{
+ // Only perform tasks if the file is not already marked
+ if (!m_bModified && m_pDoc->isModified()) {
+ m_bModified = true;
+ emit modified(this, m_bModified);
+
+#if KDE_IS_VERSION(3,3,0)
+ Kate::DocumentExt* pKateDoc;
+
+ // If the editor is a Kate part, check whether it was modified on
+ // disk as well, and issue a warning if so
+ pKateDoc = dynamic_cast<Kate::DocumentExt*>(m_pDoc);
+ if (pKateDoc)
+ pKateDoc->slotModifiedOnDisk(dynamic_cast<Kate::View*>(m_pView));
+#endif
+ }
+
+ // Start/restart the auto-completion timer
+ m_pCompletion->slotAutoComplete();
+}
+
+/**
+ * Marks a file as not modified if all undo levels have been applied.
+ * This slot is conncted to the undoChanged() signal of the Document object.
+ * In addition to marking the file, this method also emits the modified()
+ * signal.
+ */
+void EditorPage::slotUndoChanged()
+{
+ // Check if the file contents have been fully restored
+ if (m_bModified && !m_pDoc->isModified()) {
+ m_bModified = false;
+ emit modified(this, m_bModified);
+ }
+}
+
+/**
+ * Handles changes in the cursor position.
+ * Emits a signal with the new line and column numbers.
+ */
+void EditorPage::slotCursorPosChange()
+{
+ uint nLine, nCol;
+
+ // Find the new line and column number, and emit the signal
+ if (!getCursorPos(nLine, nCol))
+ return;
+
+ emit cursorPosChanged(nLine, nCol);
+
+ // Select the relevant symbol in the tag list
+ if (Config().getAutoTagHl() && (m_nLine != nLine)) {
+ m_pCtagsList->gotoLine(nLine);
+ m_nLine = nLine;
+ }
+
+ // Abort code completion on cursor changes during the completion
+ // process
+ m_pCompletion->abort();
+}
+
+#include "editorpage.moc"
diff --git a/src/editorpage.h b/src/editorpage.h
new file mode 100644
index 0000000..0af3aaf
--- /dev/null
+++ b/src/editorpage.h
@@ -0,0 +1,215 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef EDITORPAGE_H
+#define EDITORPAGE_H
+
+#include <qwidget.h>
+#include <qhbox.h>
+#include <qsplitter.h>
+#include <qtabwidget.h>
+#include <qpopupmenu.h>
+#include <ktexteditor/document.h>
+#include <ktexteditor/view.h>
+#include <ktexteditor/markinterfaceextension.h>
+#include "ctagsfrontend.h"
+#include "ctagslist.h"
+#include "kscopeconfig.h"
+#include "symbolcompletion.h"
+#include "projectbase.h"
+
+/**
+ * An editor window based on the system's current editing application.
+ * The page is divided into two panes. One holds an embedded editor, and the
+ * other holds a list of tags (generated by Ctags) of the file currently being
+ * edited.
+ * The widget creates an instance of the editor application, and uses its
+ * document and view objects that allow KScope to control it. A page also
+ * Each page is inserted in a separate tab in the EditorTabs widget.
+ * @author Elad Lahav
+ */
+
+class EditorPage : public QHBox, SymbolCompletion::Interface
+{
+ Q_OBJECT
+
+public:
+ EditorPage(KTextEditor::Document*, QPopupMenu*, QTabWidget* pParent = 0,
+ const char* szName = 0);
+ ~EditorPage();
+
+ void open(const QString&);
+ void setNewFile();
+ void save();
+ bool close(bool bForce = false);
+ void applyPrefs();
+ void setEditorFocus();
+ void setTagListFocus();
+ void addBookmark(uint);
+ void getBookmarks(FileLocationList&);
+
+ KTextEditor::Document* getDocument();
+ KTextEditor::View* getView();
+ QString getFilePath();
+ QString getFileName();
+ bool isWritable();
+ bool isModified();
+ QString getSelection();
+ QString getSuggestedText();
+ QString getLineContents(uint);
+ void setLayout(bool bShowTagList, const SPLIT_SIZES&);
+ bool getCursorPos(uint&, uint&);
+ bool setCursorPos(uint, uint nCol = 1);
+ void setTabWidth(uint);
+
+ virtual QString getWordUnderCursor(uint* pPosInWord = NULL);
+
+ /**
+ * Implements the SymbolCompletion interface method for returning an
+ * object that supports KTextEditor::CodeCompletionInterface.
+ * @return A pointer to the View object of the editor
+ */
+ virtual QObject* getCCObject() { return m_pView; }
+
+ /**
+ * @return true if a previously unsaved file is currently being edited,
+ * false otherwise
+ */
+ bool isNewFile() { return m_bNewFile; }
+
+ /** The identifier of the Window menu item which activates this page. */
+ int m_nMenuId;
+
+public slots:
+ void slotGotoLine(uint);
+ void slotMenuSelect();
+ void slotCompleteSymbol();
+
+signals:
+ /**
+ * Emitted when a file has been fully loaded into the editor.
+ * @param pPage The emitting object
+ * @param sPath The full path of the loaded file
+ */
+ void fileOpened(EditorPage* pPage, const QString& sPath);
+
+ /**
+ * Emitted when an editor is opened for editing a new file.
+ * @param pPage The emitting object
+ */
+ void newFile(EditorPage* pPage);
+
+ /**
+ * Emitted when the 'modified' status of the editor changes.
+ * This happens when the contents of the editor change, or when the file
+ * being edited is saved.
+ * @param pPage The emitting object
+ * @param bModified true if the new state is 'modified', false if the
+ * new state is 'unmodified'
+ */
+ void modified(EditorPage* pPage, bool bModified);
+
+ /**
+ * Emitted when the position of the cursor changes.
+ * @param nLine The new line number
+ * @param nCol The new column number
+ */
+ void cursorPosChanged(uint nLine, uint nCol);
+
+ /**
+ * Emitted when a file is saved after it was modified.
+ * Indicates the project's cross-reference database needs to be updated.
+ * @param sPath The full path of the saved file
+ * @param bIsNew true if this is a new file, false otherwise
+ */
+ void fileSaved(const QString& sPath, bool bIsNew);
+
+ /**
+ * Emitted when a file is closed.
+ * @param sPath The full path of the closed file
+ */
+ void fileClosed(const QString& sPath);
+
+private:
+ /** The tab widget holding this page. */
+ QTabWidget* m_pParentTab;
+
+ /** A Ctags process to use on the edited source file. */
+ CtagsFrontend m_ctags;
+
+ /** An adjustable splitter for separating the tag list from the editor
+ part. */
+ QSplitter* m_pSplit;
+
+ /** A list view for displaying Ctags results. */
+ CtagsList* m_pCtagsList;
+
+ /** The document part of the editor. */
+ KTextEditor::Document* m_pDoc;
+
+ /** The view part of the editor. */
+ KTextEditor::View* m_pView;
+
+ /** Whether a source file is currently loaded. */
+ bool m_bOpen;
+
+ /** Whether the file being edited is a new one (i.e., never saved
+ before.) */
+ bool m_bNewFile;
+
+ /** The name of the file being edited. */
+ QString m_sName;
+
+ /** true if the file system allows this file to be modified, false
+ otherwise. */
+ bool m_bWritable;
+
+ /** This variable is required in addition to m_pDoc->isModified() so
+ that the modified() signal is emitted only once. */
+ bool m_bModified;
+
+ /** The current line position of the cursor. */
+ uint m_nLine;
+
+ /** Provides symbol completion. */
+ SymbolCompletion* m_pCompletion;
+
+ /** Determines whether size changes in the child widgets should be
+ stored in the global configuration file.
+ Needs to be explicitly set to false before _each_ operation that
+ does not wish to change the defaults. */
+ bool m_bSaveNewSizes;
+
+private slots:
+ void slotChildResized();
+ void slotFileOpened();
+ void slotSetModified();
+ void slotUndoChanged();
+ void slotCursorPosChange();
+};
+
+#endif
diff --git a/src/editortabs.cpp b/src/editortabs.cpp
new file mode 100644
index 0000000..5af9be1
--- /dev/null
+++ b/src/editortabs.cpp
@@ -0,0 +1,640 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qfileinfo.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kurldrag.h>
+#include <kate/document.h>
+#include "editortabs.h"
+#include "kscopepixmaps.h"
+#include "queryview.h"
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+EditorTabs::EditorTabs(QWidget* pParent, const char* szName) :
+ TabWidget(pParent, szName),
+ m_pCurPage(NULL),
+ m_pWindowMenu(NULL),
+ m_nWindowMenuItems(0),
+ m_nNewFiles(0)
+{
+ // Display close buttons
+ setHoverCloseButton(true);
+
+ // Accept file drops
+ setAcceptDrops(true);
+
+ // Close an editor page when its close button is clicked
+ connect(this, SIGNAL(closeRequest(QWidget*)), this,
+ SLOT(slotRemovePage(QWidget*)));
+
+ // Set an editor page as the active part, when its tab is selected
+ connect(this, SIGNAL(currentChanged(QWidget*)), this,
+ SLOT(slotCurrentChanged(QWidget*)));
+
+ // Start dragging a file from a tab
+ connect(this, SIGNAL(initiateDrag(QWidget*)), this,
+ SLOT(slotInitiateDrag(QWidget*)));
+}
+
+/**
+ * Class destructor.
+ */
+EditorTabs::~EditorTabs()
+{
+}
+
+/**
+ * @param pWindowMenu Pointer to the main window's "Window" menu (used to
+ * add an activation menu item for each editor page)
+ */
+void EditorTabs::setWindowMenu(QPopupMenu* pWindowMenu)
+{
+ m_pWindowMenu = pWindowMenu;
+ connect(pWindowMenu, SIGNAL(aboutToShow()), this,
+ SLOT(slotFillWindowMenu()));
+ connect(pWindowMenu, SIGNAL(activated(int)), this,
+ SLOT(slotSetCurrentPage(int)));
+}
+
+/**
+ * Adds a new editor page to the tab widget.
+ * @param pNewPage The page to add
+ */
+void EditorTabs::addEditorPage(EditorPage* pNewPage)
+{
+ // Create a new tab and set is as the current one
+ insertTab(pNewPage, "");
+ showPage(pNewPage);
+
+ // Add the file edited by this page to the map, and display its name,
+ // once the file is opened
+ connect(pNewPage, SIGNAL(fileOpened(EditorPage*, const QString&)), this,
+ SLOT(slotAttachFile(EditorPage*, const QString&)));
+
+ // Handle new unnamed files
+ connect(pNewPage, SIGNAL(newFile(EditorPage*)), this,
+ SLOT(slotNewFile(EditorPage*)));
+
+ // Change tab icon when a file is modified
+ connect(pNewPage, SIGNAL(modified(EditorPage*, bool)), this,
+ SLOT(slotFileModified(EditorPage*, bool)));
+
+ // If this is the first page, the current page will not be set by the
+ // signal handler, so we need to do it manually
+ if (count() == 1)
+ slotCurrentChanged(pNewPage);
+}
+
+/**
+ * Finds and displays a page editing the given file.
+ * NOTE: The bForceChange parameters is used as a fix for the GUI merge
+ * problem arising when the found page is the current one.
+ * @param sFileName The name of the file to search
+ * @param bForceChange If set to true, the method will emit the signal
+ * editorChanged() even if the found page is the
+ * current one
+ * @return The editor page object, if found, NULL otherwise
+ */
+EditorPage* EditorTabs::findEditorPage(const QString& sFileName,
+ bool bForceChange)
+{
+ EditorMap::iterator itr;
+ EditorPage* pPage;
+ bool bEmit;
+
+ // Find the page according to the associated file name
+ itr = m_mapEdit.find(sFileName);
+ if (itr == m_mapEdit.end())
+ return NULL;
+
+ // Set the page as the current one
+ pPage = *itr;
+ bEmit = (bForceChange && (pPage == m_pCurPage));
+ showPage(pPage);
+
+ // Emit the editorChanged() signal, if required
+ if (bEmit)
+ emit editorChanged(NULL, m_pCurPage);
+
+ return *itr;
+}
+
+/**
+ * Returns the page associated with the selected tab.
+ * @return The current editor page
+ */
+EditorPage* EditorTabs::getCurrentPage()
+{
+ return (EditorPage*)currentPage();
+}
+
+/**
+ * Deletes the currently active page.
+ * Finds the current page, closes its editor window and deletes the page.
+ * If other editors are open, another page becomes active.
+ */
+void EditorTabs::removeCurrentPage()
+{
+ QWidget* pPage;
+
+ // Get the active page, if any
+ pPage = currentPage();
+ if (pPage == NULL)
+ return;
+
+ // Close the editor window
+ removePage(pPage, false);
+}
+
+/**
+ * Removes all editor pages.
+ * @return true if successful, false if the user aborts the operation
+ */
+bool EditorTabs::removeAllPages()
+{
+ QWidget* pPage;
+
+ // Check if there are any modified files
+ if (getModifiedFilesCount()) {
+ // Prompt the user to save these files
+ switch (KMessageBox::questionYesNoCancel(NULL,
+ i18n("Some files contain unsaved changes.\nWould you like to "
+ "save these files?"))) {
+ case KMessageBox::Yes:
+ // Save files
+ slotSaveAll();
+ break;
+
+ case KMessageBox::No:
+ // Close files, ignoring changes
+ break;
+
+ case KMessageBox::Cancel:
+ // Abort
+ return false;
+ }
+ }
+
+ // Avoid warning about modification on disk
+ Kate::Document::setFileChangedDialogsActivated(false);
+
+ // Iterate pages until none is left
+ while ((pPage = currentPage()) != NULL)
+ removePage(pPage, true);
+
+ // Restore kate warning if enabled
+ Kate::Document::setFileChangedDialogsActivated(
+ Config().getWarnModifiedOnDisk());
+
+ // All pages were successfully removed
+ return true;
+}
+
+/**
+ * Keeps track of the currently active editor page, and notifies on a change
+ * in the active page.
+ * This slot is connected to the currentChanged() signal of the QTabWidget
+ * object.
+ * @param pWidget The new active page
+ */
+void EditorTabs::slotCurrentChanged(QWidget* pWidget)
+{
+ EditorPage* pOldPage;
+
+ // TODO:
+ // For some reason, this slot is being called twice for every external
+ // tab activation (e.g., through the Window menu).
+ // We avoid it, but this really needs to be fixed properly.
+ if (pWidget == m_pCurPage)
+ return;
+
+ // Set the new active page
+ pOldPage = m_pCurPage;
+ m_pCurPage = (EditorPage*)pWidget;
+
+ if (m_pCurPage) {
+ // Set the keyboard focus to the editor part of the page
+ m_pCurPage->setEditorFocus();
+
+ // Adjust the splitter sizes
+ m_pCurPage->setLayout(Config().getShowTagList(),
+ Config().getEditorSizes());
+ }
+
+ /* Notify the main window */
+ emit editorChanged(pOldPage, m_pCurPage);
+}
+
+/**
+ * Updates the tab of an editor page to reflect the newly opened file.
+ * This slot is attached to the fileOpened() signal of an EditorPage object.
+ * @param pEditPage Pointer to the calling object
+ * @param sFilePath The full path of the file edited in this page
+ */
+void EditorTabs::slotAttachFile(EditorPage* pEditPage,
+ const QString& sFilePath)
+{
+ // Set the appropriate tab icon, according to the file permissions
+ if (pEditPage->isWritable())
+ setTabIconSet(pEditPage, Pixmaps().getPixmap(KScopePixmaps::TabRW));
+ else
+ setTabIconSet(pEditPage, Pixmaps().getPixmap(KScopePixmaps::TabRO));
+
+ // Do nothing if the file name has not changed
+ if (m_mapEdit[sFilePath] == pEditPage)
+ return;
+
+ // Set the tab caption to the file name, and a tool-tip to the full path
+ changeTab(pEditPage, pEditPage->getFileName());
+ setTabToolTip(pEditPage, sFilePath);
+
+ // Associate the EditorPage object with its file name
+ m_mapEdit[sFilePath] = pEditPage;
+}
+
+/**
+ * Marks a page as containing a new unnamed file.
+ * This slot is attached to the newFile() signal of an EditorPage object.
+ * @param pEditPage Pointer to the calling object
+ */
+void EditorTabs::slotNewFile(EditorPage* pEditPage)
+{
+ QString sCaption;
+
+ // Set the tab caption to mark a new file
+ m_nNewFiles++;
+ sCaption = i18n("Untitled ") + QString::number(m_nNewFiles);
+ changeTab(pEditPage,
+ Pixmaps().getPixmap(KScopePixmaps::TabRW),
+ sCaption);
+ setTabToolTip(pEditPage, i18n("New unsaved file"));
+}
+
+/**
+ * Applies the user's colour and font preferences to all pages.
+ */
+void EditorTabs::applyPrefs()
+{
+ EditorPage* pPage;
+ int i;
+
+ // Iterate editor pages
+ for (i = 0; i < count(); i++) {
+ pPage = (EditorPage*)page(i);
+ pPage->applyPrefs();
+ setTabIconSet(pPage, Pixmaps().getPixmap(pPage->isWritable() ?
+ KScopePixmaps::TabRW : KScopePixmaps::TabRO));
+ }
+}
+
+/**
+ * Fills a list with the paths and cursor positions of all files currently
+ * open.
+ * @param list The list to fill
+ */
+void EditorTabs::getOpenFiles(FileLocationList& list)
+{
+ int i;
+ EditorPage* pPage;
+ uint nLine, nCol;
+
+ // Iterate over all editor pages
+ for (i = 0; i < count(); i++) {
+ // Obtain file and cursor position information
+ pPage = (EditorPage*)page(i);
+ if (!pPage->getCursorPos(nLine, nCol)) {
+ nLine = 1;
+ nCol = 1;
+ }
+
+ // Create a new list item
+ list.append(new FileLocation(pPage->getFilePath(), nLine, nCol));
+ }
+}
+
+/**
+ * Constructs a list bookmarks set to open files.
+ * Used to store all currently set bookmarks when a session is closed.
+ * @param fll The list to fill
+ */
+void EditorTabs::getBookmarks(FileLocationList& fll)
+{
+ int i;
+ EditorPage* pPage;
+
+ // Iterate over all editor pages
+ for (i = 0; i < count(); i++) {
+ pPage = (EditorPage*)page(i);
+ pPage->getBookmarks(fll);
+ }
+}
+
+/**
+ * Assigns bookmarks to open files.
+ * Called when a session is opened, to restore any bookmarks set to existing
+ * editor pages.
+ * @param fll A list of bookmark positions
+ */
+void EditorTabs::setBookmarks(FileLocationList& fll)
+{
+ FileLocation* pLoc;
+ EditorMap::iterator itr;
+ EditorPage* pPage;
+
+ // Iterate over the list of bookmarks
+ for (pLoc = fll.first(); pLoc; pLoc = fll.next()) {
+ itr = m_mapEdit.find(pLoc->m_sPath);
+ // Get the relevant page, if any
+ if (itr != m_mapEdit.end()) {
+ pPage = *itr;
+ pPage->addBookmark(pLoc->m_nLine);
+ }
+ }
+}
+
+/**
+ * Fills a QueryView object with the list of currently active bookmarks.
+ * @param pView The widget to use for displaying bookmarks
+ */
+void EditorTabs::showBookmarks(QueryView* pView)
+{
+ int i;
+ EditorPage* pPage;
+ FileLocationList fll;
+ FileLocation* pLoc;
+
+ fll.setAutoDelete(true);
+
+ // Iterate over all editor pages
+ for (i = 0; i < count(); i++) {
+ // Obtain file and cursor position information
+ pPage = (EditorPage*)page(i);
+ pPage->getBookmarks(fll);
+
+ // Populate the view
+ for (pLoc = fll.first(); pLoc; pLoc = fll.next()) {
+ pView->addRecord("", pLoc->m_sPath,
+ QString::number(pLoc->m_nLine + 1),
+ pPage->getLineContents(pLoc->m_nLine + 1));
+ }
+
+ fll.clear();
+ }
+}
+
+/**
+ * Removes an editor page.
+ * If there are unsaved changes, the user is prompted, and the file is closed
+ * according to the user's choice.
+ * This slot is connected to the clicked() signal of the tab's close button.
+ * @param pPage The EditorPage object to remove
+ */
+void EditorTabs::slotRemovePage(QWidget* pPage)
+{
+ removePage(pPage, false);
+}
+
+/**
+ * Handles the "View->Show/Hide Tag List" menu item.
+ * Shows/hides the tag list for the current page, and sets the default values
+ * for all pages.
+ */
+void EditorTabs::slotToggleTagList()
+{
+ EditorPage* pPage;
+
+ // Change the default value
+ Config().setShowTagList(!Config().getShowTagList());
+
+ // Apply for the current page, if any
+ if ((pPage = (EditorPage*)currentPage()) != NULL) {
+ pPage->setLayout(Config().getShowTagList(),
+ Config().getEditorSizes());
+ }
+}
+
+/**
+ * Handles drag events over an empty tab widget, or over the tab bar.
+ * The event is accepted if the dragged object is a list of file paths.
+ * @param pEvent The drag move event object
+ */
+void EditorTabs::dragMoveEvent(QDragMoveEvent* pEvent)
+{
+ KURL::List list;
+ bool bAccept;
+
+ bAccept = KURLDrag::decode(pEvent, list);
+ pEvent->accept(bAccept);
+}
+
+/**
+ * Handles file drops over an empty tab widget, or over the tab bar.
+ * @param pEvent The drop event object
+ */
+void EditorTabs::dropEvent(QDropEvent* pEvent)
+{
+ emit filesDropped(pEvent);
+}
+
+/**
+ * Called when an editor tab is dragged from the tab widget.
+ * Initialises the drag operation with a URL that corresponds to the path of
+ * the file being edited in the corresponding page.
+ * This slot is connected to the initiateDrag() signal emitted by the tab
+ * widget.
+ * @param pWidget The page whose tab is being dragged
+ */
+void EditorTabs::slotInitiateDrag(QWidget* pWidget)
+{
+ KURL url;
+ KURLDrag* pDrag;
+
+ // Create a URL list containing the appropriate file path
+ url.setPath(((EditorPage*)pWidget)->getFilePath());
+ pDrag = new KURLDrag(KURL::List(url), this);
+
+ // Start the drag
+ pDrag->dragCopy();
+}
+
+/**
+ * Changes the tab icon of a modified file.
+ * @param pEditPage The editor page whose file was modified
+ * @param bModified true if the file has changed its status to modified,
+ * false otherwise (i.e., when undo operations restore it
+ * to its original contents.)
+ */
+void EditorTabs::slotFileModified(EditorPage* pEditPage, bool bModified)
+{
+ if (bModified)
+ setTabIconSet(pEditPage, Pixmaps().getPixmap(KScopePixmaps::TabSave));
+ else
+ setTabIconSet(pEditPage, Pixmaps().getPixmap(KScopePixmaps::TabRW));
+}
+
+/**
+ * Counts the number of pages containing modified files.
+ * @return The number of modified files
+ */
+int EditorTabs::getModifiedFilesCount()
+{
+ int i, nResult;
+
+ // Iterate through pages
+ for (i = 0, nResult = 0; i < count(); i++) {
+ if (((EditorPage*)page(i))->isModified())
+ nResult++;
+ }
+
+ return nResult;
+}
+
+/**
+ * Saves all files open for editing.
+ */
+void EditorTabs::slotSaveAll()
+{
+ int i;
+
+ // Iterate through pages
+ for (i = 0; i < count(); i++)
+ ((EditorPage*)page(i))->save();
+}
+
+/**
+ * Selects the page to the left of the current one.
+ */
+void EditorTabs::slotGoLeft()
+{
+ int nIndex;
+
+ nIndex = currentPageIndex();
+ if (nIndex > 0) {
+ nIndex--;
+ setCurrentPage(nIndex);
+ }
+}
+
+/**
+ * Selects the page to the right of the current one.
+ */
+void EditorTabs::slotGoRight()
+{
+ int nIndex;
+
+ nIndex = currentPageIndex();
+ if (nIndex < count() - 1) {
+ nIndex++;
+ setCurrentPage(nIndex);
+ }
+}
+
+/**
+ * Fills the main window's "Window" menu with the current list of file tabs.
+ * This slot is attached to the aboutToShow() signal, emitted by the Window
+ * popup menu.
+ */
+void EditorTabs::slotFillWindowMenu()
+{
+ QString sLabel;
+ int i;
+
+ // Delete old menu items
+ // NOTE: We can't use aboutToHide() to do that, since it is emitted
+ // _before_ the activated() signal
+ for (i = 0; i < m_nWindowMenuItems; i++)
+ m_pWindowMenu->removeItem(i);
+
+ // Add new items
+ for (i = 0; i < count(); i++) {
+ sLabel = (i < 10) ? QString("&%1 %2").arg(i).arg(label(i)) : label(i);
+ m_pWindowMenu->insertItem(sLabel, i);
+ }
+
+ // Store the number of items added
+ m_nWindowMenuItems = i;
+}
+
+/**
+ * Sets the current page to the given one.
+ * This slot is attached to the activated() signal, emitted by the "Window"
+ * popup menu. The tab number to switch to is given by the menu item ID.
+ * Note that we do not trust setCurrentPage() to filter out the IDs of other
+ * menu items (which are supposed to be negative numbers).
+ */
+void EditorTabs::slotSetCurrentPage(int nId)
+{
+ if (nId >= 0 && nId < count())
+ setCurrentPage(nId);
+}
+
+/**
+ * Closes an edited file, and removes its page.
+ * Once a file has been closed, its page is removed from the tab widget stack,
+ * its menu item in the "Windows" menu is deleted and all other references to
+ * it are removed.
+ * Note that the operation may fail if the user chooses not to close the file
+ * when prompted for unsaved changes.
+ * @param pPage The EditorPage object to remove
+ * @param bForce true to close the page even if there are unsaved changes,
+ * false otherwise
+ * @return true if the page was removed, false otherwise
+ */
+bool EditorTabs::removePage(QWidget* pPage, bool bForce)
+{
+ EditorPage* pEditPage;
+ QString sFilePath;
+
+ // Store the file path for later
+ pEditPage = (EditorPage*)pPage;
+ sFilePath = pEditPage->getFilePath();
+
+ // Close the edited file (may fail if the user aborts the action)
+ if (!pEditPage->close(bForce))
+ return false;
+
+ // Remove the page and all references to it
+ m_mapEdit.remove(sFilePath);
+ TabWidget::removePage(pPage);
+
+ // Update the new state if no other page exists (if another page has
+ // become active, it will update the new state, so there is no need for
+ // special handling)
+ if (currentPage() == NULL)
+ slotCurrentChanged(NULL);
+
+ // Notify the page has been removed
+ emit editorRemoved(pEditPage);
+ return true;
+}
+
+#include "editortabs.moc"
diff --git a/src/editortabs.h b/src/editortabs.h
new file mode 100644
index 0000000..67d0c17
--- /dev/null
+++ b/src/editortabs.h
@@ -0,0 +1,129 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef EDITORTABS_H
+#define EDITORTABS_H
+
+#include <qwidget.h>
+#include <qpopupmenu.h>
+#include "tabwidget.h"
+#include "editorpage.h"
+#include "projectmanager.h"
+
+typedef QMap<QString, EditorPage*> EditorMap;
+class QueryView;
+
+/**
+ * A tab widget that holds several editor windows.
+ * This class provides the main widget in the KScope window. All editors are
+ * opened as pages of the tab widgets.
+ * @author Elad Lahav
+ */
+
+class EditorTabs : public TabWidget
+{
+ Q_OBJECT
+
+public:
+ EditorTabs(QWidget* pParent = 0, const char* szName = 0);
+ ~EditorTabs();
+
+ void setWindowMenu(QPopupMenu*);
+ void addEditorPage(EditorPage*);
+ EditorPage* findEditorPage(const QString&, bool bForceChange = false);
+ EditorPage* getCurrentPage();
+ void removeCurrentPage();
+ bool removeAllPages();
+ void applyPrefs();
+ void getOpenFiles(FileLocationList&);
+ void getBookmarks(FileLocationList&);
+ void setBookmarks(FileLocationList&);
+ void showBookmarks(QueryView*);
+
+public slots:
+ void slotRemovePage(QWidget*);
+ void slotToggleTagList();
+ void slotSaveAll();
+ void slotGoLeft();
+ void slotGoRight();
+
+signals:
+ /**
+ * Emitted when the current editor page changes.
+ * @param pOld The previous current page
+ * @param pNew The new current page
+ */
+ void editorChanged(EditorPage* pOld, EditorPage* pNew);
+
+ /**
+ * Emitted when an editor page is closed.
+ * @param pPage The removed page
+ */
+ void editorRemoved(EditorPage* pPage);
+
+ /**
+ * Indicates that files were dragged and dropped over the tab widget.
+ * @param pEvent The drop event information
+ */
+ void filesDropped(QDropEvent* pEvent);
+
+protected:
+ virtual void dragMoveEvent(QDragMoveEvent*);
+ virtual void dropEvent(QDropEvent*);
+
+private:
+ /** Links a file name with an editor page that has this file open. */
+ EditorMap m_mapEdit;
+
+ /** We need to keep track of the current page in order to implement the
+ editorChanged() signal. */
+ EditorPage* m_pCurPage;
+
+ /** A popup menu with Cscope operations for the editor windows. */
+ QPopupMenu* m_pWindowMenu;
+
+ /** The number of items added to the window menu (used for removing old
+ items). */
+ int m_nWindowMenuItems;
+
+ /** A counter for creating unique tab captions for new files. */
+ int m_nNewFiles;
+
+ int getModifiedFilesCount();
+ bool removePage(QWidget*, bool);
+
+private slots:
+ void slotCurrentChanged(QWidget*);
+ void slotAttachFile(EditorPage*, const QString&);
+ void slotNewFile(EditorPage*);
+ void slotFileModified(EditorPage*, bool);
+ void slotInitiateDrag(QWidget*);
+ void slotFillWindowMenu();
+ void slotSetCurrentPage(int);
+};
+
+#endif
diff --git a/src/encoder.cpp b/src/encoder.cpp
new file mode 100644
index 0000000..5d04744
--- /dev/null
+++ b/src/encoder.cpp
@@ -0,0 +1,114 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2006 Elad Lahav (elad_lahav@users.sf.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include "qstring.h"
+#include "encoder.h"
+
+#define CHAR_TO_HEX(c) ((c) < 0xA ? '0' + (c) : ('A' - 0xA) + (c))
+#define HEX_TO_CHAR(h) ((h) > 'A' ? (h) - ('A' - 0xA) : (h) - '0')
+
+/**
+ * Class constructor.
+ */
+Encoder::Encoder() : m_pBuf(NULL), m_nBufLen(0)
+{
+}
+
+/**
+ * Class destructor.
+ */
+Encoder::~Encoder() {
+ if (m_pBuf)
+ delete[] m_pBuf;
+}
+
+/**
+ * Encodes a string.
+ * @param str The string to encode
+ * @return The hex-encoded ASCII string
+ */
+const char* Encoder::encode(const QString& str)
+{
+ const char* szStr;
+ int nLen, i, j;
+
+ szStr = str.latin1();
+ nLen = str.length();
+
+ // Ensure the buffer is big enough to contain the result
+ resize((nLen * 2) + 1);
+
+ // Encode the string
+ for (i = 0, j = 0; i < nLen; i++, j += 2) {
+ m_pBuf[j] = CHAR_TO_HEX(szStr[i] >> 4);
+ m_pBuf[j + 1] = CHAR_TO_HEX(szStr[i] & 0x0f);
+ }
+
+ m_pBuf[j] = 0;
+ return m_pBuf;
+}
+
+/**
+ * Decodes a string.
+ * @param str The string to decode
+ * @return The decoded string.
+ */
+const char* Encoder::decode(const QString& str)
+{
+ const char* szStr;
+ int nLen, i, j;
+
+ szStr = str.latin1();
+ nLen = str.length();
+
+ // Ensure the buffer is big enough to contain the result
+ nLen /= 2;
+ resize(nLen + 1);
+
+ // Decode the string
+ for (i = 0, j = 0; i < nLen; i++, j += 2) {
+ m_pBuf[i] = HEX_TO_CHAR(szStr[j]) << 4;
+ m_pBuf[i] |= HEX_TO_CHAR(szStr[j + 1]);
+ }
+
+ m_pBuf[i] = 0;
+ return m_pBuf;
+}
+
+/**
+ * Sets a new size to the buffer.
+ * @param nNewLen The new size of the buffer
+ */
+void Encoder::resize(int nNewLen)
+{
+ if (m_nBufLen < nNewLen) {
+ if (m_pBuf)
+ delete[] m_pBuf;
+
+ m_pBuf = new char[nNewLen];
+ }
+}
diff --git a/src/encoder.h b/src/encoder.h
new file mode 100644
index 0000000..2e35cde
--- /dev/null
+++ b/src/encoder.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2006 Elad Lahav (elad_lahav@users.sf.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef __ENCODER_H
+#define __ENCODER_H
+
+/**
+ * Translates strings to hex-encoded ASCII, and vice-versa.
+ * @author Elad Lahav
+ */
+class Encoder
+{
+public:
+ Encoder();
+ ~Encoder();
+ const char* encode(const QString&);
+ const char* decode(const QString&);
+
+private:
+ /** A buffer to contain the result of encoding/decoding. */
+ char* m_pBuf;
+
+ /** The buffer's length. */
+ int m_nBufLen;
+
+ void resize(int);
+};
+
+#endif
diff --git a/src/file_ro.png b/src/file_ro.png
new file mode 100644
index 0000000..6d0d29d
--- /dev/null
+++ b/src/file_ro.png
Binary files differ
diff --git a/src/file_rw.png b/src/file_rw.png
new file mode 100644
index 0000000..8312c6b
--- /dev/null
+++ b/src/file_rw.png
Binary files differ
diff --git a/src/file_save.png b/src/file_save.png
new file mode 100644
index 0000000..41b3f43
--- /dev/null
+++ b/src/file_save.png
Binary files differ
diff --git a/src/filelist.cpp b/src/filelist.cpp
new file mode 100644
index 0000000..59492ce
--- /dev/null
+++ b/src/filelist.cpp
@@ -0,0 +1,197 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qlineedit.h>
+#include <qfileinfo.h>
+#include <klocale.h>
+#include "filelist.h"
+#include "kscope.h"
+#include "kscopeconfig.h"
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+FileList::FileList(QWidget* pParent, const char* szName) :
+ SearchList(1, pParent, szName),
+ m_sRoot("/")
+{
+ // Set the list's columns
+ m_pList->addColumn("");
+ m_pList->addColumn(i18n("File"));
+ m_pList->addColumn(i18n("Path"));
+
+ // Sort only when asked to by the user
+ if (Config().getAutoSortFiles())
+ m_pList->setSortColumn(1);
+ else
+ m_pList->setSortColumn(m_pList->columns() + 1);
+
+ m_pList->setAllColumnsShowFocus(true);
+
+ // Set colours and font
+ applyPrefs();
+}
+
+/**
+ * Class destructor.
+ */
+FileList::~FileList()
+{
+}
+
+/**
+ * Adds a single entry to the file list.
+ * Implements the addItem() virtual method of the FileListTarget base
+ * class. When a FileList object is given as a parameter to
+ * ProjectManager::fillList(), this method is called for each file included
+ * in the project. A new list item is created, containing the file's name and
+ * path, and is added to the list.
+ * @param sFilePath The full path of a source file
+ */
+void FileList::addItem(const QString& sFilePath)
+{
+ QString sFileType, sFileName, sPath;
+ int nTypePos;
+
+ // Extract the file name
+ sFileName = sFilePath.mid(sFilePath.findRev('/') + 1);
+
+ // Get the file's extension (empty string for file names without an
+ // extension)
+ nTypePos = sFileName.findRev('.');
+ if (nTypePos > -1)
+ sFileType = sFileName.mid(nTypePos + 1);
+
+ // If a root path has been set, use a $ sign instead of that part of the
+ // path
+ sPath = sFilePath;
+ if (m_sRoot != "/")
+ sPath.replace(m_sRoot, "$");
+
+ // Create the list item
+ new QListViewItem(m_pList, sFileType, sFileName, sPath);
+}
+
+/**
+ * Searches the list for the given file path.
+ * @param sPath The full path of the file to find
+ * @return true if the file was found in the list, false otherwise
+ */
+bool FileList::findFile(const QString& sPath)
+{
+ QString sFindPath(sPath);
+
+ if (m_sRoot != "/")
+ sFindPath.replace(m_sRoot, "$");
+
+ return (m_pList->findItem(sFindPath, 2) != NULL);
+}
+
+/**
+ * Removes all items from the file list.
+ */
+void FileList::clear()
+{
+ m_pList->clear();
+ m_pEdit->setText("");
+}
+
+/**
+ * Opens a file for editing when its entry is clicked in the file list.
+ * @param pItem The clicked list item
+ */
+void FileList::processItemSelected(QListViewItem* pItem)
+{
+ QString sPath;
+
+ // Get the file path (replace the root symbol, if required)
+ sPath = pItem->text(2);
+ if (sPath.startsWith("$"))
+ sPath.replace("$", m_sRoot);
+
+ // Submit a request to open the file for editing
+ emit fileRequested(sPath, 0);
+}
+
+/**
+ * Sets the list's colours and font, according the user's preferences.
+ */
+void FileList::applyPrefs()
+{
+ // Apply colour settings
+ m_pList->setPaletteBackgroundColor(Config().getColor(
+ KScopeConfig::FileListBack));
+ m_pList->setPaletteForegroundColor(Config().getColor(
+ KScopeConfig::FileListFore));
+ m_pList->setFont(Config().getFont(KScopeConfig::FileList));
+}
+
+/**
+ * Associates a root directory with this list.
+ * For each file in the list, the part of the path corresponding to the root
+ * is replaced with a $ sign.
+ * @param sRoot The new root path
+ */
+void FileList::setRoot(const QString& sRoot)
+{
+ QListViewItem* pItem;
+ QString sPath;
+
+ // Update all items in the list
+ for (pItem = m_pList->firstChild(); pItem != NULL;
+ pItem = pItem->nextSibling()) {
+ sPath = pItem->text(2);
+
+ // Restore the full path
+ sPath.replace("$", m_sRoot);
+
+ // Replace the root with a $ sign
+ if (sRoot != "/")
+ sPath.replace(sRoot, "$");
+
+ pItem->setText(2, sPath);
+ }
+
+ // Store the new root
+ m_sRoot = sRoot;
+}
+
+/**
+ * Constructs a tool-tip for the given item.
+ * @param pItem The item for which a tip is required
+ * @param sTip The constructed tip string (on return)
+ * @return Always true
+ */
+bool FileList::getTip(QListViewItem* pItem, QString& sTip)
+{
+ sTip = pItem->text(2);
+ return true;
+}
+
+#include "filelist.moc"
diff --git a/src/filelist.h b/src/filelist.h
new file mode 100644
index 0000000..8585dc6
--- /dev/null
+++ b/src/filelist.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef FILELIST_H
+#define FILELIST_H
+
+#include <qwidget.h>
+#include "searchlist.h"
+#include "projectmanager.h"
+
+/**
+ * Implements a searchable list of files.
+ * The file list is composed of a list view, and a search box, into which the
+ * user can enter a file name. The name is matched against the contents of
+ * the list, and matching items are selected.
+ * @author Elad Lahav
+ */
+
+class FileList : public SearchList, public FileListTarget
+{
+ Q_OBJECT
+
+public:
+ FileList(QWidget* pParent = 0, const char* szName = 0);
+ ~FileList();
+
+ virtual void addItem(const QString&);
+ bool findFile(const QString&);
+ void clear();
+ void applyPrefs();
+ void setRoot(const QString&);
+ virtual bool getTip(QListViewItem*, QString&);
+
+signals:
+ /**
+ * Emitted when a file is selected, by either double-clicking a list
+ * item, or by highlighting an item and pressing the ENTER key.
+ * @param sPath The full path of the selected file
+ * @param nLine Line number, always set to 0
+ */
+ void fileRequested(const QString& sPath, uint nLine);
+
+protected:
+ virtual void processItemSelected(QListViewItem*);
+
+private:
+ /** A common root path for all items in the list. */
+ QString m_sRoot;
+};
+
+#endif
diff --git a/src/fileview.cpp b/src/fileview.cpp
new file mode 100644
index 0000000..029c20a
--- /dev/null
+++ b/src/fileview.cpp
@@ -0,0 +1,131 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qpushbutton.h>
+#include <qfileinfo.h>
+#include <qtabwidget.h>
+#include <kfiledialog.h>
+#include "fileview.h"
+#include "filelist.h"
+#include "kscopepixmaps.h"
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ * @param fl Widget creation flags
+ */
+FileView::FileView(QWidget* pParent, const char* szName, WFlags fl) :
+ FileViewLayout(pParent, szName, fl),
+ m_pCurBranch(0),
+ m_sRoot("")
+{
+ QWidget* pPage;
+
+ // Set the tab widget icons
+ pPage = m_pTabWidget->page(0);
+ m_pTabWidget->setTabIconSet(pPage, GET_PIXMAP(TabFileList));
+ pPage = m_pTabWidget->page(1);
+ m_pTabWidget->setTabIconSet(pPage, GET_PIXMAP(TabFileTree));
+
+ // Create a single column for the file tree
+ m_pFileTree->addColumn("");
+
+ // Send the fileRequested() signal whenever a file is selected in either
+ // the list or the tree
+ connect(m_pFileList, SIGNAL(fileRequested(const QString&, uint)), this,
+ SIGNAL(fileRequested(const QString&, uint)));
+ connect(m_pFileTree, SIGNAL(doubleClicked(QListViewItem*)),
+ this, SLOT(slotTreeItemSelected(QListViewItem*)));
+ connect(m_pFileTree, SIGNAL(returnPressed(QListViewItem*)), this,
+ SLOT(slotTreeItemSelected(QListViewItem*)));
+}
+
+/**
+ * Class destructor.
+ */
+FileView::~FileView()
+{
+}
+
+/**
+ * Sets a new common root path to both the file list and the tree.
+ * @param sRoot The full path of the new root
+ */
+void FileView::setRoot(const QString& sRoot)
+{
+ // Nothing to do if the given root is the same as the old one
+ if (sRoot == m_sRoot)
+ return;
+
+ m_sRoot = sRoot;
+
+ // Remove the current branch
+ if (m_pCurBranch)
+ m_pFileTree->removeBranch(m_pCurBranch);
+
+ // Update the file list
+ m_pFileList->setRoot(sRoot);
+
+ // Nothing more to do for an empty root directory
+ if (sRoot.isEmpty())
+ return;
+
+ // Create and open a new branch, with the newly specified root
+ QFileInfo fi(sRoot);
+ m_pCurBranch = m_pFileTree->addBranch(KURL(sRoot), fi.fileName());
+ m_pCurBranch->setChildRecurse(false);
+ m_pFileTree->setOpen(m_pCurBranch->root(), true);
+}
+
+/**
+ * Clears the contents of the file view and file tree.
+ */
+void FileView::clear()
+{
+ m_pFileList->clear();
+ setRoot("");
+}
+
+/**
+ * Emits the fileRequested() signal when a file name is selected in the file
+ * tree. An item is selected by either double-clicking it or by hittin
+ * "ENTER" when it is highlighted.
+ * This slot is connected to the doubleClicked() and returnPressed() signals
+ * of the KFileTreeView object.
+ * @param pItem The selected tree item
+ */
+void FileView::slotTreeItemSelected(QListViewItem* pItem)
+{
+ KFileTreeViewItem* pTreeItem;
+
+ pTreeItem = (KFileTreeViewItem*)pItem;
+ if (pTreeItem && !pTreeItem->isDir())
+ emit fileRequested(pTreeItem->path(), 0);
+}
+
+#include "fileview.moc"
diff --git a/src/fileview.h b/src/fileview.h
new file mode 100644
index 0000000..5fc1fe3
--- /dev/null
+++ b/src/fileview.h
@@ -0,0 +1,80 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef FILEVIEW_H
+#define FILEVIEW_H
+
+#include <kfiletreeview.h>
+#include "fileviewlayout.h"
+
+/**
+ * A tabbed widget that contains a file list and a file tree.
+ * The list is an object of type FileList, which displays all files included
+ * in the current project. The tree is a standard KFileTreeView, which can
+ * browse through the entire file system. Optionally, the root of the tree
+ * can be set per project.
+ * @author Elad Lahav
+ */
+
+class FileView : public FileViewLayout
+{
+ Q_OBJECT
+
+public:
+ FileView(QWidget* pParent = 0, const char* szName = 0, WFlags fl = 0);
+ ~FileView();
+
+ /**
+ * @return The file list widget which is a child of this widget.
+ */
+ FileList* getFileList() { return m_pFileList; }
+
+ void setRoot(const QString&);
+ void clear();
+
+signals:
+ /**
+ * Emitted when a file is selected, by either double-clicking a list
+ * item, or by highlighting an item and pressing the ENTER key.
+ * @param sPath The full path of the selected file
+ * @param nLine Line number, always set to 0
+ */
+ void fileRequested(const QString& sPath, uint nLine);
+
+private:
+ /** The current branch in the file tree. */
+ KFileTreeBranch* m_pCurBranch;
+
+ /** The current root of the file tree. */
+ QString m_sRoot;
+
+private slots:
+ void slotTreeItemSelected(QListViewItem*);
+};
+
+#endif
+
diff --git a/src/fileviewlayout.ui b/src/fileviewlayout.ui
new file mode 100644
index 0000000..24bb1f5
--- /dev/null
+++ b/src/fileviewlayout.ui
@@ -0,0 +1,136 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>FileViewLayout</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>FileViewLayout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>364</width>
+ <height>639</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Form1</string>
+ </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="QTabWidget">
+ <property name="name">
+ <cstring>m_pTabWidget</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string></string>
+ </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="FileList">
+ <property name="name">
+ <cstring>m_pFileList</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Project File List</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string></string>
+ </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="KFileTreeView">
+ <property name="name">
+ <cstring>m_pFileTree</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>File Tree</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>FileList</class>
+ <header location="local">filelist.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>7</hordata>
+ <verdata>7</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+ <customwidget>
+ <class>KFileTreeView</class>
+ <header location="global">kfiletreeview.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>7</hordata>
+ <verdata>7</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="XBM.GZ" length="79">789c534e494dcbcc4b554829cdcdad8c2fcf4c29c95030e0524611cd48cd4ccf28010a1797249664262b2467241641a592324b8aa363156c15aab914146aadb90067111b1f</data>
+ </image>
+</images>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>filelist.h</includehint>
+ <includehint>kfiletreeview.h</includehint>
+</includehints>
+</UI>
diff --git a/src/frontend.cpp b/src/frontend.cpp
new file mode 100644
index 0000000..fee1c1b
--- /dev/null
+++ b/src/frontend.cpp
@@ -0,0 +1,365 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qfileinfo.h>
+#include <qdir.h>
+#include <klocale.h>
+#include "frontend.h"
+
+/**
+ * Class constructor.
+ * @param nRecordSize The number of fields in each record
+ * @param bAutoDelete (Optional) true to delete the object when the process
+ * terminates, false (default) otherwise
+ */
+Frontend::Frontend(uint nRecordSize, bool bAutoDelete) : KProcess(),
+ m_nRecords(0),
+ m_pHeadToken(NULL),
+ m_pTailToken(NULL),
+ m_pCurToken(NULL),
+ m_bAutoDelete(bAutoDelete),
+ m_bInToken(false),
+ m_nRecordSize(nRecordSize)
+{
+ // Parse data on the standard output
+ connect(this, SIGNAL(receivedStdout(KProcess*, char*, int)), this,
+ SLOT(slotReadStdout(KProcess*, char*, int)));
+
+ // Parse data on the standard error
+ connect(this, SIGNAL(receivedStderr(KProcess*, char*, int)), this,
+ SLOT(slotReadStderr(KProcess*, char*, int)));
+
+ // Delete the process object when the process exits
+ connect(this, SIGNAL(processExited(KProcess*)), this,
+ SLOT(slotProcessExit(KProcess*)));
+}
+
+/**
+ * Class destructor.
+ */
+Frontend::~Frontend()
+{
+ // Delete all pending tokens
+ while (m_pHeadToken)
+ removeToken();
+}
+
+/**
+ * Executes the back-end process.
+ * @param sName The name of the process (for error messages)
+ * @param slArgs A list containing the command-line arguments
+ * @param sWorkDir (Optional) working directory
+ * @param bBlock (Optional) true to block, false otherwise
+ * @return true if the process was executed successfully, false otherwise
+ */
+bool Frontend::run(const QString& sName, const QStringList& slArgs,
+ const QString& sWorkDir, bool bBlock)
+{
+ // Cannot start if another controlled process is currently running
+ if (isRunning()) {
+ m_sError = i18n("Cannot restart while another process is still "
+ "running");
+ return false;
+ }
+
+ // Reset variables
+ m_nRecords = 0;
+ m_bKilled = false;
+
+ // Setup the command-line arguments
+ clearArguments();
+ *this << slArgs;
+
+ // Set the working directory, if requested
+ if (!sWorkDir.isEmpty())
+ setWorkingDirectory(sWorkDir);
+
+ // Execute the child process
+ if (!start(bBlock ? KProcess::Block : KProcess::NotifyOnExit,
+ KProcess::All)) {
+ m_sError = sName + i18n(": Failed to start process");
+ return false;
+ }
+
+ m_sError = i18n("No error");
+ return true;
+}
+
+/**
+ * Kills the process, and emits the aborted() signal.
+ * This function should not be called unless the process needs to be
+ * interrupted.
+ */
+void Frontend::kill()
+{
+ m_bKilled = true;
+ KProcess::kill();
+
+ emit aborted();
+}
+
+/**
+ * Appends a token to the end of the token list.
+ * @param pToken The token to add
+ */
+void Frontend::addToken(FrontendToken* pToken)
+{
+ // Check if this is the firt token
+ if (m_pHeadToken == NULL) {
+ m_pHeadToken = pToken;
+ m_pTailToken = pToken;
+ }
+ else {
+ // Not the first token, append and reset the tail token
+ m_pTailToken->m_pNext = pToken;
+ m_pTailToken = pToken;
+ }
+}
+
+/**
+ * Removes and deletes the token at the head of the token list.
+ */
+void Frontend::removeToken()
+{
+ FrontendToken* pToken;
+
+ if (m_pHeadToken == NULL)
+ return;
+
+ pToken = m_pHeadToken;
+ m_pHeadToken = m_pHeadToken->m_pNext;
+ delete pToken;
+
+ if (m_pHeadToken == NULL)
+ m_pTailToken = NULL;
+}
+
+/**
+ * Removes tokens from the head of the list, according to the size of a
+ * record.
+ */
+void Frontend::removeRecord()
+{
+ uint i;
+
+ for (i = 0; (i < m_nRecordSize) && (m_pHeadToken != NULL); i++)
+ removeToken();
+}
+
+/**
+ * Extracts tokens of text out of a given buffer.
+ * @param ppBuf Points to the buffer to parse, and is set to the
+ * beginning of the next token, upon return
+ * @param pBufSize Points to the size of the buffer, and is set to the
+ * remaining size, upon return
+ * @param sResult Holds the token's text, upon successful return
+ * @param delim Holds the delimiter by which the token's end was
+ * determined
+ * @return true if a token was extracted up to the given delimter(s), false
+ * if the buffer ended before a delimiter could be identified
+ */
+bool Frontend::tokenize(char** ppBuf, int* pBufSize, QString& sResult,
+ ParserDelim& delim)
+{
+ int nSize;
+ char* pBuf;
+ bool bDelim, bWhiteSpace, bFoundToken = false;
+
+ // Iterate buffer
+ for (nSize = *pBufSize, pBuf = *ppBuf; (nSize > 0) && !bFoundToken;
+ nSize--, pBuf++) {
+ // Test if this is a delimiter character
+ switch (*pBuf) {
+ case '\n':
+ bDelim = ((m_delim & Newline) != 0);
+ bWhiteSpace = true;
+ delim = Newline;
+ break;
+
+ case ' ':
+ bDelim = ((m_delim & Space) != 0);
+ bWhiteSpace = true;
+ delim = Space;
+ break;
+
+ case '\t':
+ bDelim = ((m_delim & Tab) != 0);
+ bWhiteSpace = true;
+ delim = Tab;
+ break;
+
+ default:
+ bDelim = false;
+ bWhiteSpace = false;
+ }
+
+ if (m_bInToken && bDelim) {
+ m_bInToken = false;
+ *pBuf = 0;
+ bFoundToken = true;
+ }
+ else if (!m_bInToken && !bWhiteSpace) {
+ m_bInToken = true;
+ *ppBuf = pBuf;
+ }
+ }
+
+ // Either a token was found, or the search through the buffer was
+ // finished without a delimiter character
+ if (bFoundToken) {
+ sResult = *ppBuf;
+ *ppBuf = pBuf;
+ *pBufSize = nSize;
+ }
+ else if (m_bInToken) {
+ sResult = QString::fromLatin1(*ppBuf, *pBufSize);
+ }
+ else {
+ sResult = QString::null;
+ }
+
+ return bFoundToken;
+}
+
+/**
+ * Handles text sent by the back-end process to the standard error stream.
+ * By default, this method emits the error() signal with the given text.
+ * @param sText The text sent to the standard error stream
+ */
+void Frontend::parseStderr(const QString& sText)
+{
+ emit error(sText);
+}
+
+/**
+ * Deletes the process object upon the process' exit.
+ */
+void Frontend::slotProcessExit(KProcess*)
+{
+ // Allow specialised clean-up by inheriting classes
+ finalize();
+
+ // Signal the process has terminated
+ emit finished(m_nRecords);
+
+ // Delete the object, if required
+ if (m_bAutoDelete)
+ delete this;
+}
+
+/**
+ * Reads data written on the standard output by the controlled process.
+ * This is a private slot called attached to the readyReadStdout() signal of
+ * the controlled process, which means that it is called whenever data is
+ * ready to be read from the process' stream.
+ * The method reads whatever data is queued, and sends it to be interpreted
+ * by parseStdout().
+ */
+void Frontend::slotReadStdout(KProcess*, char* pBuffer, int nSize)
+{
+ char* pLocalBuf;
+ QString sToken;
+ bool bTokenEnded;
+ ParserDelim delim;
+
+ // Do nothing if waiting for process to die
+ if (m_bKilled)
+ return;
+
+ pLocalBuf = pBuffer;
+
+ // Iterate over the given buffer
+ while (nSize > 0) {
+ // Create a new token, if the last iteration has completed one
+ if (m_pCurToken == NULL)
+ m_pCurToken = new FrontendToken();
+
+ // Extract text until the requested delimiter
+ bTokenEnded = tokenize(&pLocalBuf, &nSize, sToken, delim);
+
+ // Add the extracted text to the current token
+ m_pCurToken->m_sData += sToken;
+
+ // If the buffer has ended before the requested delimiter, we need
+ // to wait for more output from the process
+ if (!bTokenEnded)
+ return;
+
+ // Call the process-specific parser function
+ switch (parseStdout(m_pCurToken->m_sData, delim)) {
+ case DiscardToken:
+ // Token should not be saved
+ delete m_pCurToken;
+ break;
+
+ case AcceptToken:
+ // Store token in linked list
+ addToken(m_pCurToken);
+ break;
+
+ case RecordReady:
+ // Store token, and notify the target object that an entry can
+ // be read
+ m_nRecords++;
+ addToken(m_pCurToken);
+ emit dataReady(m_pHeadToken);
+
+ // Delete all tokens in the entry
+ removeRecord();
+ break;
+
+ case Abort:
+ kill();
+ nSize = 0;
+ break;
+ }
+
+ m_pCurToken = NULL;
+ }
+}
+
+/**
+ * Reads data written on the standard error by the controlled process.
+ * This is a private slot called attached to the readyReadStderr() signal of
+ * the controlled process, which means that it is called whenever data is
+ * ready to be read from the process' stream.
+ * The method reads whatever data is queued, and sends it to be interpreted
+ * by parseStderr().
+ */
+void Frontend::slotReadStderr(KProcess*, char* pBuffer, int nSize)
+{
+ QString sBuf;
+
+ // Do nothing if waiting for process to die
+ if (m_bKilled)
+ return;
+
+ sBuf.setLatin1(pBuffer, nSize);
+ parseStderr(sBuf);
+}
+
+#include "frontend.moc"
diff --git a/src/frontend.h b/src/frontend.h
new file mode 100644
index 0000000..246128a
--- /dev/null
+++ b/src/frontend.h
@@ -0,0 +1,212 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef FRONTEND_H
+#define FRONTEND_H
+
+#include <qobject.h>
+#include <kprocess.h>
+
+
+/**
+ * Represents a single token in the parsed output stream.
+ * @author Elad Lahav
+ */
+
+class FrontendToken
+{
+public:
+ /**
+ * Class constructor.
+ */
+ FrontendToken() : m_pNext(NULL) {}
+
+ /**
+ * @return The text associated with this token
+ */
+ const QString& getData() const { return m_sData; }
+
+ /**
+ * @return A pointer to the next token in the strem.
+ */
+ FrontendToken* getNext() const { return m_pNext; }
+
+protected:
+ /** Free text associated with the token. */
+ QString m_sData;
+
+ /** A pointer to the next token in the stream. */
+ FrontendToken* m_pNext;
+
+ friend class Frontend;
+};
+
+/**
+ * Abstract base class that provides a front-end to console-based programmes.
+ * Provides a parsing infrastructure which is based on a list of records, all
+ * of the same structure. Each record is composed of a number of delimited
+ * fields (tokens.)
+ * @author Elad Lahav
+ */
+
+class Frontend : public KProcess
+{
+ Q_OBJECT
+
+public:
+ Frontend(uint, bool bAutoDelete = false);
+ ~Frontend();
+
+ virtual bool run(const QString&, const QStringList&,
+ const QString& sWorkDir = "", bool bBlock = false);
+ void kill();
+
+ /**
+ * @return An string describing the error which made run() fail
+ */
+ const QString& getRunError() { return m_sError; }
+
+signals:
+ /**
+ * Indicates tokens can be read.
+ * The Frontend object parses the back-end output and creates a list of
+ * tokens. This signal is emitted when a batch of characters has been
+ * converted into a token list.
+ * @param pToken The head of the token list
+ */
+ void dataReady(FrontendToken* pToken);
+
+ /**
+ * Emitted when the back-end process terminates.
+ * @param nRecords The number of complete records parsed
+ */
+ void finished(uint nRecords);
+
+ /**
+ * Indicates that the Cscope process was terminated.
+ */
+ void aborted();
+
+ /**
+ * This signal is used to report the progress of the back-end process.
+ * @param nProgress The current progress value
+ * @param nTotal The progress value that indicates the process
+ * is finished
+ */
+ void progress(int nProgress, int nTotal);
+
+ /**
+ * Emitted when an error message is produced by the back-end process.
+ */
+ void error(const QString& sMsg);
+
+protected:
+ /** A set of possible delimiters for parsing process output. */
+ enum ParserDelim { Newline = 0x01, Space = 0x02, Tab = 0x04,
+ WSpace = Space | Tab, All = WSpace | Newline };
+
+ /** Defines the set of return values for parseStdout(). Determines what
+ needs to be done with a new token passed to this method. */
+ enum ParseResult {
+ DiscardToken /** Delete this token */,
+ AcceptToken /** Add this token to the list */,
+ RecordReady /** This token completes a record */,
+ Abort /** Kill the process */
+ };
+
+ /** Number of complete records read so far. */
+ uint m_nRecords;
+
+ /** The head of the list of parsed output tokens. */
+ FrontendToken* m_pHeadToken;
+
+ /** The tail of the list of parsed output tokens. */
+ FrontendToken* m_pTailToken;
+
+ /** An iterator on the list of parsed output tokens. */
+ FrontendToken* m_pCurToken;
+
+ /** The current delimiters used for parsing the output. */
+ ParserDelim m_delim;
+
+ /** An error string produced if run() fails. */
+ QString m_sError;
+
+ /**
+ * Handles a text token received on the Standard Output stream of the
+ * controlled process.
+ * This is called by slotReadStdout whenever a new token is recognised.
+ * Inheriting classes should implement this method to parse the resutling
+ * stream of tokens.
+ * @param sToken A part of the text received on the Standard Output,
+ * disected according to current delimiter settings
+ * @param delim The delimiter that ended this token
+ * @result A ParseResult value, indicating what should be done with the
+ * new token
+ */
+ virtual ParseResult parseStdout(QString& sToken, ParserDelim delim) = 0;
+
+ virtual void parseStderr(const QString&);
+
+ /**
+ * Called when the process exits.
+ * Allows inheriting classes to implement process termination handlers.
+ */
+ virtual void finalize() {}
+
+protected slots:
+ virtual void slotProcessExit(KProcess*);
+
+private:
+ /** Determines whether the object should be deleted once the process has
+ exited */
+ bool m_bAutoDelete;
+
+ /** Determines whether the parser is in the middle of a token, or between
+ two tokens */
+ bool m_bInToken;
+
+ /** The number of fields in each parsed record. Should be defined for
+ every sub-class. */
+ uint m_nRecordSize;
+
+ /** This flag is raised when kill() is called. It signifies that even
+ though the process may not be dead yet, it should be considered as
+ such. */
+ bool m_bKilled;
+
+ void addToken(FrontendToken*);
+ void removeToken();
+ void removeRecord();
+ bool tokenize(char**, int*, QString&, ParserDelim&);
+
+private slots:
+ void slotReadStdout(KProcess*, char*, int);
+ void slotReadStderr(KProcess*, char*, int);
+};
+
+#endif
diff --git a/src/graphedge.cpp b/src/graphedge.cpp
new file mode 100644
index 0000000..283a5fe
--- /dev/null
+++ b/src/graphedge.cpp
@@ -0,0 +1,306 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <math.h>
+#include <stdlib.h>
+#include <qpainter.h>
+#include "graphedge.h"
+#include "graphnode.h"
+
+int GraphEdge::RTTI = 1002;
+
+// Some definitions required by the ConvexHull class
+typedef int (*CompFunc)(const void*, const void*);
+#define ISLEFT(P0, P1, P2) \
+ (P1.x() - P0.x()) * (P2.y() - P0.y()) - \
+ (P2.x() - P0.x()) * (P1.y() - P0.y())
+#define FARTHEST(P0, P1, P2) \
+ ((P1.x() - P0.x()) * (P1.x() - P0.x()) - \
+ (P1.y() - P0.y()) * (P1.y() - P0.y())) - \
+ ((P2.x() - P0.x()) * (P2.x() - P0.x()) - \
+ (P2.y() - P0.y()) * (P2.y() - P0.y()))
+
+
+/**
+ * An array of QPoint objects that can compute the convex hull surrounding all
+ * points in the array.
+ * @author Elad Lahav
+ */
+class ConvexHull : public QPointArray
+{
+public:
+ /**
+ * Class constructor.
+ */
+ ConvexHull() : QPointArray() {}
+
+ /**
+ * Computes the convex hull of the points stored in the array, using
+ * Graham's scan.
+ * @param arrHull Holds the coordinates of the convex hull, upon return
+ */
+ void compute(QPointArray& arrHull) {
+ uint i, nPivot, nTop;
+
+ // Find the pivot point
+ nPivot = 0;
+ for (i = 1; i < size(); i++) {
+ if ((*this)[i].y() < (*this)[nPivot].y()) {
+ nPivot = i;
+ }
+ else if ((*this)[i].y() == (*this)[nPivot].y() &&
+ (*this)[i].x() < (*this)[nPivot].x()) {
+ nPivot = i;
+ }
+ }
+
+ // Sort points in radial order, relative to the pivot
+ s_ptPivot = (*this)[nPivot];
+ (*this)[nPivot] = (*this)[0];
+ (*this)[0] = s_ptPivot;
+ qsort(&(*this).data()[1], (*this).size() - 1, sizeof(QPoint),
+ (CompFunc)compRadial);
+
+ // Initialise Graham's scan algorithm
+ arrHull.resize(size() + 1);
+ arrHull[0] = (*this)[0];
+ arrHull[1] = (*this)[1];
+ nTop = 1;
+
+ // Compute the convex hull
+ for (i = 2; i < size();) {
+ // TODO: According to the algorithm, the condition should be >0
+ // for pushing the point into the stack. For some reason, it works
+ // only with <0. Why?
+ if (ISLEFT(arrHull[nTop - 1], arrHull[nTop], (*this)[i]) < 0) {
+ arrHull[++nTop] = (*this)[i];
+ i++;
+ }
+ else {
+ nTop--;
+ }
+ }
+
+ // Close the hull
+ arrHull[++nTop] = (*this)[0];
+ arrHull.truncate(nTop + 1);
+ }
+
+private:
+ /** The current pivot point, required by compRadial. */
+ static QPoint s_ptPivot;
+
+ /**
+ * Compares two points based on their angle relative to the current
+ * pivot point.
+ * This function is passed as the comparison function of qsort().
+ * @param pPt1 A pointer to the first point
+ * @param pPt2 A pointer to the second point
+ * @return >0 if the first point is to the left of the second, <0 otherwise
+ */
+ static int compRadial(const QPoint* pPt1, const QPoint* pPt2) {
+ int nResult;
+
+ // Determine which point is to the left of the other. If the angle is
+ // the same, the greater point is the one farther from the pivot
+ nResult = ISLEFT(s_ptPivot, (*pPt1), (*pPt2));
+ if (nResult == 0)
+ return FARTHEST(s_ptPivot, (*pPt1), (*pPt2));
+
+ return nResult;
+ }
+};
+
+QPoint ConvexHull::s_ptPivot;
+
+/**
+ * Class constructor.
+ * @param pCanvas The canvas on which to draw the edge
+ * @param pHead The edge's starting point
+ * @param pTail The edge's end point
+ */
+GraphEdge::GraphEdge(QCanvas* pCanvas, GraphNode* pHead, GraphNode* pTail) :
+ QCanvasPolygonalItem(pCanvas),
+ m_pHead(pHead),
+ m_pTail(pTail),
+ m_arrPoly(4)
+{
+}
+
+/**
+ * Class destructor.
+ */
+GraphEdge::~GraphEdge()
+{
+ // Classes derived from QCanvasPolygonalItem must call hide() in their
+ // detructor (according to the Qt documentation)
+ hide();
+}
+
+/**
+ * Calculates the area surrounding the edge, and the bounding rectangle of
+ * the edge's polygonal head.
+ * The calculated area is used to find items on the canvas and to display
+ * tips. The bounding rectangle defines the tip's region (@see QToolTip).
+ * TODO: The function assumes that the we can simply append the polygon's
+ * array to that of the splines. Is this always the case, or should we sort
+ * the points of the polygon in radial order?
+ * @param arrCurve The control points of the edge's spline
+ * @param ai Used to calculate the arrow head polygon
+ */
+void GraphEdge::setPoints(const QPointArray& arrCurve, const ArrowInfo& ai)
+{
+ ConvexHull ch;
+ uint i;
+ int nXpos, nYpos;
+
+ // Redraw an existing edge
+ if (m_arrArea.size() > 0)
+ invalidate();
+
+ // Store the point array for drawing
+ m_arrCurve = arrCurve;
+
+ // Calculate the arrowhead's polygon
+ makeArrowhead(ai);
+
+ // Compute the convex hull of the edge
+ ch.resize(m_arrCurve.size() + m_arrPoly.size() - 2);
+ ch.putPoints(0, m_arrCurve.size() - 1, m_arrCurve);
+ ch.putPoints(m_arrCurve.size() - 1, m_arrPoly.size() - 1, m_arrPoly);
+ ch.compute(m_arrArea);
+
+ // Calculate the head's bounding rectangle
+ m_rcTip = QRect(m_arrPoly[0], m_arrPoly[0]);
+ for (i = 1; i < m_arrPoly.size(); i++) {
+ nXpos = m_arrPoly[i].x();
+ if (nXpos < m_rcTip.left())
+ m_rcTip.setLeft(nXpos);
+ else if (nXpos > m_rcTip.right())
+ m_rcTip.setRight(nXpos);
+
+ nYpos = m_arrPoly[i].y();
+ if (nYpos < m_rcTip.top())
+ m_rcTip.setTop(nYpos);
+ else if (nYpos > m_rcTip.bottom())
+ m_rcTip.setBottom(nYpos);
+ }
+}
+
+/**
+ * Sets the call information associated with this edge.
+ * @param sFile The call's file path
+ * @param sLine The call's line number
+ * @param sText The call's text
+ */
+void GraphEdge::setCallInfo(const QString& sFile, const QString& sLine,
+ const QString& sText)
+{
+ m_sFile = sFile;
+ m_sLine = sLine;
+ m_sText = sText;
+}
+
+/**
+ * Constructs a tool-tip string for this edge.
+ * @return The tool-tip text
+ */
+QString GraphEdge::getTip() const
+{
+ QString sTip;
+
+ sTip = m_sText + "<br><i>" + m_sFile + "</i>:" + m_sLine;
+ return sTip;
+}
+
+/**
+ * Draws the spline as a sequence of cubic Bezier curves.
+ * @param painter Used for drawing the item on the canvas view
+ */
+void GraphEdge::drawShape(QPainter& painter)
+{
+ uint i;
+
+ // Draw the polygon
+ painter.drawConvexPolygon(m_arrPoly);
+
+ // Draw the Bezier curves
+ for (i = 0; i < m_arrCurve.size() - 1; i += 3)
+ painter.drawCubicBezier(m_arrCurve, i);
+
+#if 0
+ // Draws the convex hull of the edge
+ QPen pen = painter.pen();
+ QBrush br = painter.brush();
+ painter.setPen(QPen(QColor(255, 0, 0)));
+ painter.setBrush(QBrush());
+ painter.drawPolygon(m_arrArea);
+ painter.setPen(pen);
+ painter.setBrush(br);
+#endif
+}
+
+/**
+ * Computes the coordinates of the edge's arrow head, based on its curve.
+ * @param ai Pre-computed values used for all edges
+ */
+void GraphEdge::makeArrowhead(const ArrowInfo& ai)
+{
+ QPoint ptLast, ptPrev;
+ double dX1, dY1, dX0, dY0, dX, dY, dDeltaX, dDeltaY, dNormLen;
+
+ // The arrowhead follows the line from the second last to the last points
+ // in the curve
+ ptLast = m_arrCurve[m_arrCurve.size() - 1];
+ ptPrev = m_arrCurve[m_arrCurve.size() - 2];
+
+ // The first and last points of the polygon are the end of the curve
+ m_arrPoly.setPoint(0, ptLast.x(), ptLast.y());
+ m_arrPoly.setPoint(3, ptLast.x(), ptLast.y());
+
+ // Convert integer points to double precision values
+ dX1 = (double)ptLast.x();
+ dY1 = (double)ptLast.y();
+ dX0 = (double)ptPrev.x();
+ dY0 = (double)ptPrev.y();
+
+ // The values (x1-x0), (y1-y0) and sqrt(1 + tan(theta)^2) are useful
+ dDeltaX = dX1 - dX0;
+ dDeltaY = dY1 - dY0;
+
+ // The normalised length of the arrow's sides
+ dNormLen = ai.m_dLength / sqrt(dDeltaX * dDeltaX + dDeltaY * dDeltaY);
+
+ // Compute the other two points
+ dX = dX1 - ((dDeltaX - ai.m_dTan * dDeltaY) / ai.m_dSqrt) * dNormLen;
+ dY = dY1 - ((dDeltaY + ai.m_dTan * dDeltaX) / ai.m_dSqrt) * dNormLen;
+ m_arrPoly.setPoint(1, (int)dX, (int)dY);
+
+ dX = dX1 - ((dDeltaX + ai.m_dTan * dDeltaY) / ai.m_dSqrt) * dNormLen;
+ dY = dY1 - ((dDeltaY - ai.m_dTan * dDeltaX) / ai.m_dSqrt) * dNormLen;
+ m_arrPoly.setPoint(2, (int)dX, (int)dY);
+}
diff --git a/src/graphedge.h b/src/graphedge.h
new file mode 100644
index 0000000..ce399b3
--- /dev/null
+++ b/src/graphedge.h
@@ -0,0 +1,143 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef GRAPHEDGE_H
+#define GRAPHEDGE_H
+
+#include <qcanvas.h>
+
+class GraphNode;
+
+/**
+ * Information used to draw arrow heads at the end of graph edges.
+ */
+struct ArrowInfo
+{
+ /** The length of the arrow. */
+ double m_dLength;
+
+ /** The tangent of the arrow's angle from the main line. */
+ double m_dTan;
+
+ /** Holds the value sqrt(1 + dTan^2). */
+ double m_dSqrt;
+};
+
+/**
+ * Draws a directed edge on a canvas.
+ * The edge is composed of a spline, which is its body, and a polygon, which
+ * is its head.
+ * @author Elad Lahav
+ */
+class GraphEdge : public QCanvasPolygonalItem
+{
+public:
+ GraphEdge(QCanvas*, GraphNode*, GraphNode*);
+ ~GraphEdge();
+
+ void setCallInfo(const QString&, const QString&, const QString&);
+ void setPoints(const QPointArray&, const ArrowInfo&);
+ QString getTip() const;
+
+ /**
+ * @return The coordinates of the convex hull surrounding the edge
+ */
+ virtual QPointArray areaPoints() const { return m_arrArea; }
+
+ /**
+ * @return The head node of the edge
+ */
+ GraphNode* getHead() { return m_pHead; }
+
+ /**
+ * @return The tail node of the edge
+ */
+ GraphNode* getTail() { return m_pTail; }
+
+ /**
+ * @return The bounding rectangle of the edge's head
+ */
+ QRect tipRect() const { return m_rcTip; }
+
+ /**
+ * @return The file path for this call
+ */
+ const QString& getFile() const { return m_sFile; }
+
+ /**
+ * @return The line number for this call
+ */
+ uint getLine() const { return m_sLine.toUInt(); }
+
+ /**
+ * @return The call's text
+ */
+ const QString& getText() const { return m_sText; }
+
+ /** Identifies this class among other QCanvasItem classes. */
+ static int RTTI;
+
+ /**
+ * @return The class identifier
+ */
+ virtual int rtti() const { return RTTI; }
+
+protected:
+ virtual void drawShape(QPainter&);
+
+private:
+ /** The edge's starting point. */
+ GraphNode* m_pHead;
+
+ /** The edge's end point. */
+ GraphNode* m_pTail;
+
+ /** The points of the polygon part of the edge. */
+ QPointArray m_arrPoly;
+
+ /** Control points for the spline part of the edge. */
+ QPointArray m_arrCurve;
+
+ QPointArray m_arrArea;
+
+ /** The bounding rectangle of the edge's head, used for displaying the
+ edge's tool-tip. */
+ QRect m_rcTip;
+
+ /** The call's source file. */
+ QString m_sFile;
+
+ /** The call's line number. */
+ QString m_sLine;
+
+ /** The call's text. */
+ QString m_sText;
+
+ void makeArrowhead(const ArrowInfo&);
+};
+
+#endif
diff --git a/src/graphnode.cpp b/src/graphnode.cpp
new file mode 100644
index 0000000..28a219d
--- /dev/null
+++ b/src/graphnode.cpp
@@ -0,0 +1,192 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qpainter.h>
+#include <qfontmetrics.h>
+#include "graphnode.h"
+
+int GraphNode::RTTI = 1001;
+
+/**
+ * Class constructor.
+ * @param pCanvas The owner canvas
+ * @param sFunc The node's function
+ * @param bMultiCall Whether this node represents multiple calls
+ */
+GraphNode::GraphNode(QCanvas* pCanvas, const QString& sFunc, bool bMultiCall) :
+ QCanvasPolygon(pCanvas),
+ m_sFunc(sFunc),
+ m_bMultiCall(bMultiCall),
+ m_bDfsFlag(false)
+{
+ // Every node deletes its out-edges only
+ m_dictOutEdges.setAutoDelete(true);
+}
+
+/**
+ * Class destructor.
+ */
+GraphNode::~GraphNode()
+{
+}
+
+/**
+ * Finds an edge leaving this node and reaching the given node.
+ * If such an edge does not exist, a new one is created.
+ * @param pTail The destination node
+ * @return The edge that ends at the given node
+ */
+GraphEdge* GraphNode::addOutEdge(GraphNode* pTail)
+{
+ GraphEdge* pEdge;
+
+ // Look for the edge
+ if ((pEdge = m_dictOutEdges.find(pTail->getFunc())) == NULL) {
+ // Create a new edge
+ pEdge = new GraphEdge(canvas(), this, pTail);
+ m_dictOutEdges.insert(pTail->getFunc(), pEdge);
+ pTail->m_dictInEdges.replace(m_sFunc, pEdge);
+ }
+
+ // Return the new/constructed edge
+ return pEdge;
+}
+
+/**
+ * Performs a weak depth-first-search on the graph.
+ * The search continues along all edges, both incoming and outgoing.
+ */
+void GraphNode::dfs()
+{
+ // Stop if this node is already marked
+ if (m_bDfsFlag)
+ return;
+
+ // Mark the node as visited
+ m_bDfsFlag = true;
+
+ // Continue along outgoing edges
+ QDictIterator<GraphEdge> itrOut(m_dictOutEdges);
+ for (; itrOut.current(); ++itrOut)
+ (*itrOut)->getTail()->dfs();
+
+ // Continue along incoming edges
+ QDictIterator<GraphEdge> itrIn(m_dictInEdges);
+ for (; itrIn.current(); ++itrIn)
+ (*itrIn)->getHead()->dfs();
+}
+
+/**
+ * Deletes all outgoing edges.
+ * Uses the auto-delete property of the dictionary.
+ */
+void GraphNode::removeOutEdges()
+{
+ m_dictOutEdges.clear();
+}
+
+/**
+ * Deletes all incoming edges.
+ * To avoid double deletions, the function lets the head node of the edge remove
+ * it.
+ */
+void GraphNode::removeInEdges()
+{
+ QDictIterator<GraphEdge> itr(m_dictInEdges);
+
+ // Delete edges through their head nodes
+ for (; itr.current(); ++itr)
+ (*itr)->getHead()->m_dictOutEdges.remove(m_sFunc);
+
+ // remove edges from the local dictionary (will not delete them)
+ m_dictInEdges.clear();
+}
+
+/**
+ * Returns the first found node connected to this one.
+ * This function is used with multi-call nodes for retrieving the parent node.
+ * @param pNode
+ * @param bCalled
+ */
+void GraphNode::getFirstNeighbour(GraphNode*& pNode, bool& bCalled)
+{
+ QDictIterator<GraphEdge> itrIn(m_dictInEdges);
+ QDictIterator<GraphEdge> itrOut(m_dictOutEdges);
+
+ if (itrIn.current()) {
+ pNode = itrIn.current()->getHead();
+ bCalled = false;
+ }
+ else if (itrOut.current()) {
+ pNode = itrOut.current()->getTail();
+ bCalled = true;
+ }
+ else {
+ pNode = NULL;
+ }
+}
+
+/**
+ * Modifies the bounding rectangle of the node.
+ * @param rect The new coordinates to set
+ */
+void GraphNode::setRect(const QRect& rect)
+{
+ QPointArray arr(4);
+
+ m_rect = rect;
+
+ arr.setPoint(0, m_rect.topLeft());
+ arr.setPoint(1, m_rect.topRight());
+ arr.setPoint(2, m_rect.bottomRight());
+ arr.setPoint(3, m_rect.bottomLeft());
+ setPoints(arr);
+}
+
+/**
+ * Draws the node.
+ * @param painter Used for drawing the item on the canvas view
+ */
+void GraphNode::drawShape(QPainter& painter)
+{
+ const QPen& pen = painter.pen();
+ const QFont& font = painter.font();
+
+ // Draw the rectangle
+ painter.setPen(QPen(Qt::black));
+ painter.drawRect(m_rect);
+
+ // Draw the text
+ painter.setPen(pen);
+ painter.setFont(m_font);
+ if (m_bMultiCall)
+ painter.drawText(m_rect, Qt::AlignCenter, "...");
+ else
+ painter.drawText(m_rect, Qt::AlignCenter, m_sFunc);
+
+ painter.setFont(font);
+}
diff --git a/src/graphnode.h b/src/graphnode.h
new file mode 100644
index 0000000..9f48639
--- /dev/null
+++ b/src/graphnode.h
@@ -0,0 +1,123 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef GRAPHNODE_H
+#define GRAPHNODE_H
+
+#include <qcanvas.h>
+#include <qdict.h>
+#include "graphedge.h"
+
+/**
+ * A canvas item that draws the name of a function insider a filled rectangle.
+ * This item represents a function in the call graph.
+ * @author Elad Lahav
+ */
+class GraphNode : public QCanvasPolygon
+{
+public:
+ GraphNode(QCanvas* pCanvas, const QString&, bool bMultiCall = false);
+ ~GraphNode();
+
+ GraphEdge* addOutEdge(GraphNode*);
+ void dfs();
+ void removeOutEdges();
+ void removeInEdges();
+ void getFirstNeighbour(GraphNode*&, bool&);
+
+ /**
+ * @param rect The bounding rectangle of the node
+ */
+ void setRect(const QRect& rect);
+
+ /**
+ * @param font The font to use for drawing the text
+ */
+ void setFont(const QFont& font) { m_font = font; }
+
+ /**
+ * @return The name of the function
+ */
+ const QString& getFunc() const { return m_sFunc; }
+
+ /**
+ * @return true for a multiple-call node, false otherwise
+ */
+ bool isMultiCall() { return m_bMultiCall; }
+
+ /**
+ * @return The set of outgoing edges
+ */
+ QDict<GraphEdge>& getOutEdges() { return m_dictOutEdges; }
+
+ /**
+ * @return true if this node was already visited during the current DFS,
+ * false otherwise
+ */
+ bool dfsVisited() { return m_bDfsFlag; }
+
+ /**
+ * Clears the 'DFS-visited' flag, in preparation for the next DFS.
+ */
+ void dfsReset() { m_bDfsFlag = false; }
+
+ /** Identifies this class among other QCanvasItem classes. */
+ static int RTTI;
+
+ /**
+ * @return The class identifier
+ */
+ virtual int rtti() const { return RTTI; }
+
+protected:
+ virtual void drawShape(QPainter&);
+
+private:
+ /** Function name. */
+ QString m_sFunc;
+
+ /** A list of outgoing edges indexed by destination. */
+ QDict<GraphEdge> m_dictOutEdges;
+
+ /** A list of incoming edges indexed by destination. */
+ QDict<GraphEdge> m_dictInEdges;
+
+ /** The bounding rectangle for the node. */
+ QRect m_rect;
+
+ /** The font to use for drawing the text. */
+ QFont m_font;
+
+ /** true for a multiple-call node, false otherwise. */
+ bool m_bMultiCall;
+
+ /** Determines whether this node was visited during a depth-first
+ search. */
+ bool m_bDfsFlag;
+};
+
+#endif
diff --git a/src/graphprefdlg.cpp b/src/graphprefdlg.cpp
new file mode 100644
index 0000000..c8d381c
--- /dev/null
+++ b/src/graphprefdlg.cpp
@@ -0,0 +1,82 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qspinbox.h>
+#include "graphprefdlg.h"
+#include "preferencesdlg.h"
+#include "kscopeconfig.h"
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+GraphPrefDlg::GraphPrefDlg(QWidget* pParent, const char* szName) :
+ GraphPrefLayout(pParent, szName, true, 0)
+{
+ m_pMaxDegSpin->setValue(Config().getGraphMaxNodeDegree());
+}
+
+/**
+ * Class destructor.
+ */
+GraphPrefDlg::~GraphPrefDlg()
+{
+}
+
+/**
+ * @return The maximal degree value set in the spin box
+ */
+int GraphPrefDlg::getMaxNodeDegree()
+{
+ return m_pMaxDegSpin->value();
+}
+
+/**
+ * Displays the general preferences dialogue, showing the "Colours" page.
+ * This slot is connected to the clicked() signal of the colours button.
+ */
+void GraphPrefDlg::slotFontClicked()
+{
+ PreferencesDlg dlg(PreferencesDlg::Fonts);
+
+ dlg.exec();
+}
+
+/**
+ * Displays the general preferences dialogue, showing the "Fonts" page.
+ * This slot is connected to the clicked() signal of the fonts button.
+ */
+void GraphPrefDlg::slotColorClicked()
+{
+ PreferencesDlg dlg(PreferencesDlg::Colors);
+
+ dlg.exec();
+}
+
+#include "graphprefdlg.moc"
+
diff --git a/src/graphprefdlg.h b/src/graphprefdlg.h
new file mode 100644
index 0000000..7a4a3c0
--- /dev/null
+++ b/src/graphprefdlg.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef GRAPHPREFDLG_H
+#define GRAPHPREFDLG_H
+
+#include "graphpreflayout.h"
+
+/**
+ * A dialogue that allows the user to configure the appearance and behaviour
+ * of the call graph.
+ * @author Elad Lahav
+ */
+class GraphPrefDlg : public GraphPrefLayout
+{
+ Q_OBJECT
+
+public:
+ GraphPrefDlg(QWidget* pParent = 0, const char* szName = 0);
+ ~GraphPrefDlg();
+
+ int getMaxNodeDegree();
+
+protected slots:
+ virtual void slotFontClicked();
+ virtual void slotColorClicked();
+};
+
+#endif
+
diff --git a/src/graphpreflayout.ui b/src/graphpreflayout.ui
new file mode 100644
index 0000000..a94a206
--- /dev/null
+++ b/src/graphpreflayout.ui
@@ -0,0 +1,262 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>GraphPrefLayout</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>GraphPrefLayout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>328</width>
+ <height>164</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Call Graph Preferences</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Maximal In/Out Node Degree</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>81</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>m_pMaxDegSpin</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Colours</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>131</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pColorButton</cstring>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </hbox>
+ </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>Fonts</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>121</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pFontButton</cstring>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>GraphPrefLayout</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>GraphPrefLayout</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>m_pColorButton</sender>
+ <signal>clicked()</signal>
+ <receiver>GraphPrefLayout</receiver>
+ <slot>slotColorClicked()</slot>
+ </connection>
+ <connection>
+ <sender>m_pFontButton</sender>
+ <signal>clicked()</signal>
+ <receiver>GraphPrefLayout</receiver>
+ <slot>slotFontClicked()</slot>
+ </connection>
+</connections>
+<slots>
+ <slot access="protected">slotColorClicked()</slot>
+ <slot access="protected">slotFontClicked()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/src/graphwidget.cpp b/src/graphwidget.cpp
new file mode 100644
index 0000000..00ca733
--- /dev/null
+++ b/src/graphwidget.cpp
@@ -0,0 +1,1162 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <math.h>
+#include <stdlib.h>
+#include <qfile.h>
+#include <qpainter.h>
+#include <qtooltip.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include "graphwidget.h"
+#include "graphnode.h"
+#include "graphedge.h"
+#include "kscopeconfig.h"
+#include "queryviewdlg.h"
+#include "encoder.h"
+#include "progressdlg.h"
+
+const char* GRAPH_DIRS[] = { "TB", "LR", "BT", "RL" };
+
+const char TMP_TMPL[] = "/tmp/kscope_dot.XXXXXX";
+#define TMP_TMPL_SIZE (sizeof(TMP_TMPL) + 1)
+
+/**
+ * Displays a tool tip on the graph.
+ * Note that we cannot use the standard tool tip class here, since graph
+ * items are neither rectangular nor is their position known in advance.
+ * @author Elad Lahav
+ */
+class GraphTip : public QToolTip
+{
+public:
+ /**
+ * Class constructor.
+ * @param pWidget Owner graph widget
+ */
+ GraphTip(GraphWidget* pWidget) : QToolTip(pWidget->viewport()),
+ m_pGraphWidget(pWidget) {}
+
+ /**
+ * Class destructor.
+ */
+ virtual ~GraphTip() {}
+
+protected:
+ /**
+ * Called when the pre-conditions for a tool tip are met.
+ * Asks the owner for a tip to display and, if one is returned, shows
+ * the tool tip.
+ * @param ptPos Current mouse position
+ */
+ virtual void maybeTip(const QPoint& ptPos) {
+ QString sText;
+ QRect rc;
+
+ // Display a tip, if required by the owner
+ sText = m_pGraphWidget->getTip(ptPos, rc);
+ if (sText != QString::null)
+ tip(rc, sText);
+ }
+
+private:
+ /** The parent graph widget. */
+ GraphWidget* m_pGraphWidget;
+};
+
+/**
+ * Provides a menu separator with text.
+ * The separator is added with QMenuData::insertItem(QWidget*).
+ * @author Elad Lahav
+ */
+class MenuLabel : public QLabel
+{
+public:
+ /**
+ * Class constructor.
+ * @param sText The text to display
+ * @param pParent The parent widget
+ */
+ MenuLabel(const QString& sText, QWidget* pParent) :
+ QLabel(sText, pParent) {
+ // Set the appropriate visual properties
+ setFrameShape(MenuBarPanel);
+ setAlignment(AlignHCenter | AlignVCenter);
+ setIndent(0);
+ }
+};
+
+ArrowInfo GraphWidget::s_ai;
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+GraphWidget::GraphWidget(QWidget* pParent, const char* szName) :
+ QCanvasView(pParent, szName),
+ m_progress(this),
+ m_dot(this),
+ m_dZoom(1.0),
+ m_nMaxNodeDegree(10), // will be overriden by CallTreeDlg
+ m_nMultiCallNum(0),
+ m_pProgressDlg(NULL)
+{
+ // Automatically delete nodes when they are removed
+ m_dictNodes.setAutoDelete(true);
+
+ // Create a canvas
+ setCanvas(new QCanvas(this));
+ canvas()->setBackgroundColor(Config().getColor(KScopeConfig::GraphBack));
+
+ // Create a persistent Cscope process
+ m_pCscope = new CscopeFrontend();
+
+ // Add records output by the Cscope process
+ connect(m_pCscope, SIGNAL(dataReady(FrontendToken*)), this,
+ SLOT(slotDataReady(FrontendToken*)));
+
+ // Display query progress information
+ connect(m_pCscope, SIGNAL(progress(int, int)), this,
+ SLOT(slotProgress(int, int)));
+
+ // Draw the graph when the process has finished
+ connect(m_pCscope, SIGNAL(finished(uint)), this,
+ SLOT(slotFinished(uint)));
+
+ // Show a multi-call node when a query results in too many records
+ connect(m_pCscope, SIGNAL(aborted()), this,
+ SLOT(slotAborted()));
+
+ // Redraw the graph when Dot exits
+ connect(&m_dot, SIGNAL(finished(uint)), this, SLOT(slotDotFinished()));
+
+ // Create the node popup menu
+ m_pNodePopup = new QPopupMenu(this);
+
+ m_pNodePopup->insertItem(new MenuLabel(i18n("<b>Called Functions</b>"),
+ m_pNodePopup));
+ m_pNodePopup->insertItem(i18n("Show"), this,
+ SLOT(slotShowCalled()));
+ m_pNodePopup->insertItem(i18n("List/Filter..."), this,
+ SLOT(slotListCalled()));
+ m_pNodePopup->insertItem(i18n("Hide"), this,
+ SLOT(slotHideCalled()));
+
+ m_pNodePopup->insertItem(new MenuLabel(i18n("<b>Calling Functions</b>"),
+ m_pNodePopup));
+ m_pNodePopup->insertItem(i18n("Show"), this,
+ SLOT(slotShowCalling()));
+ m_pNodePopup->insertItem(i18n("List/Filter..."), this,
+ SLOT(slotListCalling()));
+ m_pNodePopup->insertItem(i18n("Hide"), this,
+ SLOT(slotHideCalling()));
+
+ m_pNodePopup->insertItem(new MenuLabel(i18n("<b>This Function</b>"),
+ m_pNodePopup));
+ m_pNodePopup->insertItem(i18n("Find Definition"), this,
+ SLOT(slotFindDef()));
+ m_pNodePopup->insertItem(i18n("Remove"), this, SLOT(slotRemoveNode()));
+
+ // Create the multi-call node popup menu
+ m_pMultiCallPopup = new QPopupMenu(this);
+ m_pMultiCallPopup->insertItem(i18n("List..."), this,
+ SLOT(slotMultiCallDetails()));
+ m_pMultiCallPopup->insertSeparator();
+ m_pMultiCallPopup->insertItem(i18n("Remove"), this,
+ SLOT(slotRemoveNode()));
+
+ // Create the edge menu
+ m_pEdgePopup = new QPopupMenu(this);
+ m_pEdgePopup->insertItem(i18n("Open Call"), this, SLOT(slotOpenCall()));
+
+ (void)new GraphTip(this);
+}
+
+/**
+ * Class destructor.
+ */
+GraphWidget::~GraphWidget()
+{
+}
+
+/**
+ * Creates a root node for the graph.
+ * The root node defines the connected component which is always displayed
+ * (all other connected components are removed when they are no longer
+ * strongly connected to the root).
+ * @param sFunc The function name for the root node
+ */
+void GraphWidget::setRoot(const QString& sFunc)
+{
+ // Insert a new node to the graph
+ addNode(sFunc);
+ draw();
+}
+
+/**
+ * Locates a node by its name and, if one does not exist, creates a new node.
+ * @param sFunc The name of a function
+ * @return The node corresponding to the given name
+ */
+GraphNode* GraphWidget::addNode(const QString& sFunc, bool bMultiCall)
+{
+ GraphNode* pNode;
+
+ // Look for a node with the given name
+ if ((pNode = m_dictNodes.find(sFunc)) == NULL) {
+ // Node not found, create it
+ pNode = new GraphNode(canvas(), sFunc, bMultiCall);
+ m_dictNodes.insert(sFunc, pNode);
+ }
+
+ // Return the found/created node
+ return pNode;
+}
+
+/**
+ * Adds a call to the graph.
+ * A call is made between two functions, the caller and the callee.
+ * @param data Contains information on the call
+ */
+void GraphWidget::addCall(const CallData& data)
+{
+ GraphNode* pCaller, * pCallee;
+ GraphEdge* pEdge;
+
+ // Find the relevant nodes (create new nodes if necessary)
+ pCaller = addNode(data.m_sCaller);
+ pCallee = addNode(data.m_sCallee);
+
+ // Create a new edge
+ pEdge = pCaller->addOutEdge(pCallee);
+ pEdge->setCallInfo(data.m_sFile, data.m_sLine, data.m_sText);
+}
+
+/**
+ * Creates a special node representing multiple calls to/from a function.
+ * Such a node is creates when the number of calls to/from a function exceeds
+ * a certain number. Thus the graph does not become too cluttered.
+ * A multiple call node can be replaced by some/all of the actual calls by
+ * using the "Details..." action in the node's popup menu.
+ * @param sFunc The parent function
+ * @param bCalled true if the multiple calls are called from that function,
+ * false if they are calling the function
+ */
+void GraphWidget::addMultiCall(const QString& sFunc, bool bCalled)
+{
+ QString sMulti;
+ GraphNode* pCaller, * pCallee;
+ GraphEdge* pEdge;
+
+ // Create a unique name for the new node.
+ // The name is of the form 0XXX, where XXX is a hexadecimal number.
+ // We assume that no function starts with a digit, and that there are no
+ // more than 0xfff multi-call nodes in the graph.
+ sMulti.sprintf("0%.3x", m_nMultiCallNum);
+ m_nMultiCallNum = (m_nMultiCallNum + 1) & 0xfff;
+
+ // Find the relevant nodes (create new nodes if necessary)
+ if (bCalled) {
+ pCaller = addNode(sFunc);
+ pCallee = addNode(sMulti, true);
+ }
+ else {
+ pCaller = addNode(sMulti, true);
+ pCallee = addNode(sFunc);
+ }
+
+ // Create a new edge
+ pEdge = pCaller->addOutEdge(pCallee);
+}
+
+/**
+ * Draws the graph on the canvas using the graphviz engine.
+ * A new canvas is created, so all items need to be regenerated.
+ * TODO: Can we use the same canvas and only reposition existing items?
+ */
+void GraphWidget::draw()
+{
+ QWMatrix mtx;
+ char szTempFile[TMP_TMPL_SIZE];
+ int nFd;
+ FILE* pFile;
+
+ // Do nothing if drawing process has already started
+ if (m_dot.isRunning())
+ return;
+
+ // Apply the zoom factor
+ mtx.scale(m_dZoom, m_dZoom);
+ setWorldMatrix(mtx);
+
+ // Do not draw until the Dot process finishes
+ setUpdatesEnabled(false);
+
+ // Open a temporary file
+ strcpy(szTempFile, TMP_TMPL);
+ nFd = mkstemp(szTempFile);
+ if ((pFile = fdopen(nFd, "w")) == NULL)
+ return;
+
+ // Remember the file name (so it can be deleted later)
+ m_sDrawFilePath = szTempFile;
+
+ // Write the graph contents to the temporary file
+ {
+ QTextStream str(pFile, IO_WriteOnly);
+ write(str, "graph", "--", false);
+ }
+
+ // Close the file
+ fclose(pFile);
+
+ // Draw the graph
+ if (m_dot.run(szTempFile)) {
+ // Create the progress dialogue
+ m_pProgressDlg = new ProgressDlg(i18n("KScope"),
+ i18n("Generating graph, please wait"), this);
+ m_pProgressDlg->setMinimumDuration(1000);
+ m_pProgressDlg->setValue(0);
+
+ // TODO:
+ // Implement cancel (what do we do when the drawing process is
+ // terminated, even though the nodes and edges were already added by
+ // Cscope?)
+ // m_pProgressDlg->setAllowCancel(true);
+ }
+}
+
+/**
+ * Stores a graph on a file.
+ * The file uses the dot language to describe the graph.
+ * @param pFile An open file to write to
+ */
+void GraphWidget::save(FILE* pFile)
+{
+ // Write the graph using the dot language
+ QTextStream str(pFile, IO_WriteOnly);
+ write(str, "digraph", "->", true);
+}
+
+/**
+ * Exports a graph to a dot file.
+ * @param sFile The full path of the file to export to
+ */
+void GraphWidget::save(const QString& sFile)
+{
+ QFile file(sFile);
+
+ // Open/create the file
+ if (!file.open(IO_WriteOnly))
+ return;
+
+ QTextStream str(&file);
+ write(str, "digraph", "->", false);
+}
+
+/**
+ * Changes the zoom factor.
+ * @param bIn true to zoom in, false to zoom out
+ */
+void GraphWidget::zoom(bool bIn)
+{
+ QWMatrix mtx;
+
+ // Set the new zoom factor
+ if (bIn)
+ m_dZoom *= 2.0;
+ else
+ m_dZoom /= 2.0;
+
+ // Apply the transformation matrix
+ mtx.scale(m_dZoom, m_dZoom);
+ setWorldMatrix(mtx);
+}
+
+/**
+ * Determines the initial zoom factor.
+ * This method is called from the file parser and therefore does not redraw
+ * the widget.
+ * @param dZoom The zoom factor to use
+ */
+void GraphWidget::setZoom(double dZoom)
+{
+ m_dZoom = dZoom;
+}
+
+/**
+ * Changes the graph's direction 90 degrees counter-clockwise.
+ */
+void GraphWidget::rotate()
+{
+ QString sDir;
+ int i;
+
+ // Get the current direction
+ sDir = Config().getGraphOrientation();
+
+ // Find the next direction
+ for (i = 0; i < 4 && sDir != GRAPH_DIRS[i]; i++);
+ if (i == 4)
+ i = 0;
+ else
+ i = (i + 1) % 4;
+
+ // Set the new direction
+ sDir = GRAPH_DIRS[i];
+ Config().setGraphOrientation(sDir);
+}
+
+/**
+ * Checks if a tool tip is required for the given position.
+ * NOTE: We currently return a tool tip for edges only
+ * @param ptPos The position to query
+ * @param rc Holds the tip's rectangle, upon return
+ * @return The tip's text, or QString::null if no tip is required
+ */
+QString GraphWidget::getTip(const QPoint& ptPos, QRect& rc)
+{
+ QPoint ptRealPos, ptTopLeft, ptBottomRight;
+ QCanvasItemList il;
+ QCanvasItemList::Iterator itr;
+ GraphEdge* pEdge;
+ QString sText, sFile, sLine;
+
+ ptRealPos = viewportToContents(ptPos);
+ ptRealPos /= m_dZoom;
+ pEdge = NULL;
+
+ // Check if there is an edge at this position
+ il = canvas()->collisions(ptRealPos);
+ for (itr = il.begin(); itr != il.end(); ++itr) {
+ pEdge = dynamic_cast<GraphEdge*>(*itr);
+ if (pEdge != NULL)
+ break;
+ }
+
+ // No tip if no edge was found
+ if (pEdge == NULL)
+ return QString::null;
+
+ // Set the rectangle for the tip (the tip is closed when the mouse leaves
+ // this area)
+ rc = pEdge->tipRect();
+ ptTopLeft = rc.topLeft();
+ ptBottomRight = rc.bottomRight();
+ ptTopLeft *= m_dZoom;
+ ptBottomRight *= m_dZoom;
+ ptTopLeft = contentsToViewport(ptTopLeft);
+ ptBottomRight = contentsToViewport(ptBottomRight);
+ rc = QRect(ptTopLeft, ptBottomRight);
+
+ // Create a tip for this edge
+ return pEdge->getTip();
+}
+
+/**
+ * Resizes the canvas.
+ * @param nWidth The new width
+ * @param nHiehgt The new height
+ */
+void GraphWidget::resize(int nWidth, int nHeight)
+{
+ canvas()->resize(nWidth + 2, nHeight + 2);
+}
+
+/**
+ * Displays a node on the canvas.
+ * Sets the parameters used for drawing the node on the canvas.
+ * @param sFunc The function corresponding to the node to draw
+ * @param rect The coordinates of the node's rectangle
+ */
+void GraphWidget::drawNode(const QString& sFunc, const QRect& rect)
+{
+ GraphNode* pNode;
+
+ // Find the node
+ pNode = addNode(sFunc);
+
+ // Set the visual aspects of the node
+ pNode->setRect(rect);
+ pNode->setZ(2.0);
+ pNode->setPen(QPen(Qt::black));
+ pNode->setFont(Config().getFont(KScopeConfig::Graph));
+
+ if (pNode->isMultiCall())
+ pNode->setBrush(Config().getColor(KScopeConfig::GraphMultiCall));
+ else
+ pNode->setBrush(Config().getColor(KScopeConfig::GraphNode));
+
+ // Draw the node
+ pNode->show();
+}
+
+/**
+ * Displays an edge on the canvas.
+ * Sets the parameters used for drawing the edge on the canvas.
+ * @param sCaller Identifies the edge's head node
+ * @param sCallee Identifies the edge's tail node
+ * @param arrCurve Control points for the edge's spline
+ */
+void GraphWidget::drawEdge(const QString& sCaller, const QString& sCallee,
+ const QPointArray& arrCurve)
+{
+ GraphNode* pCaller, * pCallee;
+ GraphEdge* pEdge;
+
+ // Find the edge
+ pCaller = addNode(sCaller);
+ pCallee = addNode(sCallee);
+ pEdge = pCaller->addOutEdge(pCallee);
+
+ // Set the visual aspects of the edge
+ pEdge->setPoints(arrCurve, s_ai);
+ pEdge->setZ(1.0);
+ pEdge->setPen(QPen(Qt::black));
+ pEdge->setBrush(QBrush(Qt::black));
+
+ // Draw the edge
+ pEdge->show();
+}
+
+#define PI 3.14159265
+
+/**
+ * Sets and computes values used for drawing arrows.
+ * Initialises the static ArroInfo structure, which is passed in drawEdge().
+ * @param nLength The arrow head length
+ * @param nDegrees The angle, in degrees, between the base line and each
+ * of the arrow head's sides
+ */
+void GraphWidget::setArrowInfo(int nLength, int nDegrees)
+{
+ double dRad;
+
+ // Turn degrees into radians
+ dRad = ((double)nDegrees) * PI / 180.0;
+
+ s_ai.m_dLength = (double)nLength;
+ s_ai.m_dTan = tan(dRad);
+ s_ai.m_dSqrt = sqrt(1 + s_ai.m_dTan * s_ai.m_dTan);
+}
+
+/**
+ * Draws the contents of the canvas on this view.
+ * NOTE: This method is overriden to fix a strange bug in Qt that leaves
+ * a border around the canvas part of the view. It should be deleted once
+ * this bug is fixed.
+ * TODO: Is there a better way of erasing the border?
+ * @param pPainter Used to paint on the view
+ * @param nX The horizontal origin of the area to draw
+ * @param nY The vertical origin of the area to draw
+ * @param nWidth The width of the area to draw
+ * @param nHeight The height of the area to draw
+ */
+void GraphWidget::drawContents(QPainter* pPainter, int nX, int nY,
+ int nWidth, int nHeight)
+{
+ // Draw the contents of the canvas
+ QCanvasView::drawContents(pPainter, nX, nY, nWidth, nHeight);
+
+ // Erase the canvas's area border
+ if (canvas() != NULL) {
+ QRect rect = canvas()->rect();
+ pPainter->setBrush(QBrush()); // Null brush
+ pPainter->setPen(Config().getColor(KScopeConfig::GraphBack));
+ pPainter->drawRect(-1, -1, rect.width() + 2, rect.height() + 2);
+ }
+}
+
+/**
+ * Handles mouse clicks over the graph view.
+ * @param pEvent Includes information on the mouse press event
+ */
+void GraphWidget::contentsMousePressEvent(QMouseEvent* pEvent)
+{
+ QPoint ptRealPos;
+ QCanvasItemList il;
+ QCanvasItemList::Iterator itr;
+ QString sFunc;
+ GraphNode* pNode;
+ GraphEdge* pEdge;
+
+ pNode = NULL;
+ pEdge = NULL;
+
+ // Handle right-clicks only
+ if (pEvent->button() != Qt::RightButton) {
+ QCanvasView::contentsMousePressEvent(pEvent);
+ return;
+ }
+
+ // Take the zoom factor into consideration
+ ptRealPos = pEvent->pos();
+ ptRealPos /= m_dZoom;
+
+ // Check if an item was clicked
+ il = canvas()->collisions(ptRealPos);
+ for (itr = il.begin(); itr != il.end(); ++itr) {
+ if (dynamic_cast<GraphNode*>(*itr) != NULL)
+ pNode = dynamic_cast<GraphNode*>(*itr);
+ else if (dynamic_cast<GraphEdge*>(*itr) != NULL)
+ pEdge = dynamic_cast<GraphEdge*>(*itr);
+ }
+
+ // Handle clicks over different types of items
+ if (pNode != NULL) {
+ // Show a context menu for nodes
+ showNodeMenu(pNode, pEvent->globalPos());
+ }
+ else if (pEdge != NULL) {
+ // Show a context menu for edges
+ showEdgeMenu(pEdge, pEvent->globalPos());
+ }
+ else {
+ // Take the default action
+ QCanvasView::contentsMousePressEvent(pEvent);
+ }
+}
+
+/**
+ * Writes a description of the graph to the given stream, using the Dot
+ * language.
+ * The method allows for both directed graphs and non-directed graphs, the
+ * latter are required for drawing purposes (since Dot will not produce the
+ * arrow heads and the splines terminate before reaching the nodes).
+ * @param str The stream to write to
+ * @param sType Either "graph" or "digraph"
+ * @param sEdge The edge connector ("--" or "->")
+ * @param bWriteCall true to write call information, false otherwise
+ */
+void GraphWidget::write(QTextStream& str, const QString& sType,
+ const QString& sEdge, bool bWriteCall)
+{
+ QFont font;
+ QDictIterator<GraphNode> itr(m_dictNodes);
+ GraphEdge* pEdge;
+ Encoder enc;
+
+ font = Config().getFont(KScopeConfig::Graph);
+
+ // Header
+ str << sType << " G {\n";
+
+ // Graph attributes
+ str << "\tgraph [rankdir=" << Config().getGraphOrientation() << ", "
+ << "kscope_zoom=" << m_dZoom
+ << "];\n";
+
+ // Default node attributes
+ str << "\tnode [shape=box, height=\"0.01\", style=filled, "
+ << "fillcolor=\"" << Config().getColor(KScopeConfig::GraphNode).name()
+ << "\", "
+ << "fontcolor=\"" << Config().getColor(KScopeConfig::GraphText).name()
+ << "\", "
+ << "fontname=\"" << font.family() << "\", "
+ << "fontsize=" << QString::number(font.pointSize())
+ << "];\n";
+
+ // Iterate over all nodes
+ for (; itr.current(); ++itr) {
+ // Write a node
+ str << "\t" << itr.current()->getFunc() << ";\n";
+
+ // Iterate over all edges leaving this node
+ QDictIterator<GraphEdge> itrEdge(itr.current()->getOutEdges());
+ for (; itrEdge.current(); ++itrEdge) {
+ pEdge = itrEdge.current();
+ str << "\t" << pEdge->getHead()->getFunc() << sEdge
+ << pEdge->getTail()->getFunc();
+
+ // Write call information
+ if (bWriteCall) {
+ str << " ["
+ << "kscope_file=\"" << pEdge->getFile() << "\","
+ << "kscope_line=" << pEdge->getLine() << ","
+ << "kscope_text=\"" << enc.encode(pEdge->getText()) << "\""
+ << "]";
+ }
+
+ str << ";\n";
+ }
+ }
+
+ // Close the graph
+ str << "}\n";
+}
+
+/**
+ * Removes all edges attached to a function node at the given direction.
+ * Any strongly connected components that are no longer connected to that
+ * function are deleted.
+ * @param pNode The node for which to remove the edges
+ * @param bOut true for outgoing edges, false for incoming
+ */
+void GraphWidget::removeEdges(GraphNode* pNode, bool bOut)
+{
+ // Remove the edges
+ if (bOut)
+ pNode->removeOutEdges();
+ else
+ pNode->removeInEdges();
+
+ // Remove all graph components no longer connected to this one
+ removeDisconnected(pNode);
+}
+
+/**
+ * Removes all edges and nodes that are not weakly connected to the given node.
+ * This function is called to clean up the graph after edges were removed from
+ * the given node.
+ * @param pNode The node to which all other nodes have to be connected
+ */
+void GraphWidget::removeDisconnected(GraphNode* pNode)
+{
+ QDictIterator<GraphNode> itr(m_dictNodes);
+
+ // Find all weakly connected components attached to this node
+ pNode->dfs();
+
+ // Delete all unmarked nodes, reset marked ones
+ while (itr.current()) {
+ if (!(*itr)->dfsVisited()) {
+ m_dictNodes.remove((*itr)->getFunc());
+ }
+ else {
+ (*itr)->dfsReset();
+ ++itr;
+ }
+ }
+}
+
+/**
+ * Shows a popup menu for a node.
+ * This menu is shown after a node has been right-clicked.
+ * @param pNode The node for which to show the menu
+ * @param ptPos The position of the menu
+ */
+void GraphWidget::showNodeMenu(GraphNode* pNode, const QPoint& ptPos)
+{
+ // Remember the node
+ m_pMenuItem = pNode;
+
+ // Show the popup menu.
+ if (pNode->isMultiCall())
+ m_pMultiCallPopup->popup(ptPos);
+ else
+ m_pNodePopup->popup(ptPos);
+}
+
+/**
+ * Shows a popup menu for an edge.
+ * This menu is shown after an edge has been right-clicked.
+ * @param pEdge The edge for which to show the menu
+ * @param ptPos The position of the menu
+ */
+void GraphWidget::showEdgeMenu(GraphEdge* pEdge, const QPoint& ptPos)
+{
+ // Remember the edge
+ m_pMenuItem = pEdge;
+
+ // Show the popup menu.
+ m_pEdgePopup->popup(ptPos);
+}
+
+/**
+ * Redraws the widget when new instructions are available.
+ * This slot is connected to the finished() signal emitted by the dot front-
+ * end.
+ */
+void GraphWidget::slotDotFinished()
+{
+ // Delete the temporary file
+ if (m_sDrawFilePath != "") {
+ QFile::remove(m_sDrawFilePath);
+ m_sDrawFilePath = "";
+ }
+
+ // Delete the progress dialogue
+ if (m_pProgressDlg) {
+ delete m_pProgressDlg;
+ m_pProgressDlg = NULL;
+ }
+
+ setUpdatesEnabled(true);
+ canvas()->update();
+}
+
+/**
+ * Adds an entry to the tree, as the child of the active item.
+ * Called by a CscopeFrontend object, when a new entry was received in its
+ * whole from the Cscope back-end process. The entry contains the data of a
+ * function calling the function described by the active item.
+ * @param pToken The first token in the entry
+ */
+void GraphWidget::slotDataReady(FrontendToken* pToken)
+{
+ CallData data;
+ QString sFunc;
+
+ // Get the file name
+ data.m_sFile = pToken->getData();
+ pToken = pToken->getNext();
+
+ // Get the function name
+ sFunc = pToken->getData();
+ pToken = pToken->getNext();
+
+ // Get the line number (do not accept global information on a call tree)
+ data.m_sLine = pToken->getData();
+ if (data.m_sLine.toUInt() == 0)
+ return;
+
+ pToken = pToken->getNext();
+
+ // Get the line's text
+ data.m_sText = pToken->getData();
+
+ // Determine the caller and the callee
+ if (m_bCalled) {
+ data.m_sCaller = m_sQueriedFunc;
+ data.m_sCallee = sFunc;
+ }
+ else {
+ data.m_sCaller = sFunc;
+ data.m_sCallee = m_sQueriedFunc;
+ }
+
+ // Add the call to the graph
+ addCall(data);
+}
+
+/**
+ * Displays search progress information.
+ * This slot is connected to the progress() signal emitted by a
+ * CscopeFrontend object.
+ * @param nProgress The current progress value
+ * @param nTotal The expected final value
+ */
+void GraphWidget::slotProgress(int nProgress, int nTotal)
+{
+ m_progress.setProgress(nProgress, nTotal);
+}
+
+/**
+ * Disables the expandability feature of an item, if no functions calling it
+ * were found.
+ * @param nRecords Number of records reported by the query
+ */
+void GraphWidget::slotFinished(uint /*nRecords*/)
+{
+ // Destroy the progress bar
+ m_progress.finished();
+
+ // Redraw the graph
+ draw();
+}
+
+/**
+ * Adds a multiple call node when a query results in too many entries.
+ * This slot is attached to the aborted() signal of the Cscope process.
+ */
+void GraphWidget::slotAborted()
+{
+ KMessageBox::information(this, i18n("The query produced too many results.\n"
+ "A multiple-call node will appear in the graph instead.\n"
+ "Hint: The maximum number of in/out edges\n"
+ "can be adjusted by clicking the dialogue's \"Preferences\" button"));
+
+ addMultiCall(m_sQueriedFunc, m_bCalled);
+ draw();
+}
+
+/**
+ * Shows functions called from the current function node.
+ * This slot is connected to the "Show Called Functions" popup menu
+ * action.
+ */
+void GraphWidget::slotShowCalled()
+{
+ GraphNode* pNode;
+
+ // Make sure the menu item is a node
+ pNode = dynamic_cast<GraphNode*>(m_pMenuItem);
+ if (pNode == NULL)
+ return;
+
+ // Run a query for called functions
+ m_sQueriedFunc = pNode->getFunc();
+ m_bCalled = true;
+ m_pCscope->query(CscopeFrontend::Called, m_sQueriedFunc, true,
+ Config().getGraphMaxNodeDegree());
+}
+
+/**
+ * Shows a list of function calls from the current node.
+ * The list is displayed in a query dialogue. The user can the select which
+ * calls should be displayed in the graph.
+ * This slot is connected to the "List Called Functions" popup menu
+ * action.
+ */
+void GraphWidget::slotListCalled()
+{
+ GraphNode* pNode;
+
+ // Make sure the menu item is a node
+ pNode = dynamic_cast<GraphNode*>(m_pMenuItem);
+ if (pNode == NULL)
+ return;
+
+ QueryViewDlg dlg(0, (QWidget*)parent());
+
+ // Show the query view dialogue
+ dlg.query(CscopeFrontend::Called, pNode->getFunc());
+ if (dlg.exec() != QDialog::Accepted)
+ return;
+
+ // The OK button was clicked, replace current calls with the listed ones
+ pNode->removeOutEdges();
+
+ QueryView::Iterator itr;
+ CallData data;
+
+ data.m_sCaller = pNode->getFunc();
+
+ // Add all listed calls
+ for (itr = dlg.getIterator(); !itr.isEOF(); itr.next()) {
+ data.m_sCallee = itr.getFunc();
+ data.m_sFile = itr.getFile();
+ data.m_sLine = itr.getLine();
+ data.m_sText = itr.getText();
+
+ addCall(data);
+ }
+
+ // Clean-up and redraw the graph
+ removeDisconnected(pNode);
+ draw();
+}
+
+/**
+ * Hides functions called from the current function node.
+ * This slot is connected to the "Hide Called Functions" popup menu
+ * action.
+ */
+void GraphWidget::slotHideCalled()
+{
+ GraphNode* pNode;
+
+ // Make sure the menu item is a node
+ pNode = dynamic_cast<GraphNode*>(m_pMenuItem);
+ if (pNode == NULL)
+ return;
+
+ // Remove edges and redraw the graph
+ removeEdges(pNode, true);
+ draw();
+}
+
+/**
+ * Shows functions calling tothe current function node.
+ * This slot is connected to the "Show Calling Functions" popup menu
+ * action.
+ */
+void GraphWidget::slotShowCalling()
+{
+ GraphNode* pNode;
+
+ // Make sure the menu item is a node
+ pNode = dynamic_cast<GraphNode*>(m_pMenuItem);
+ if (pNode == NULL)
+ return;
+
+ // Run a query for called functions
+ m_sQueriedFunc = pNode->getFunc();
+ m_bCalled = false;
+ m_pCscope->query(CscopeFrontend::Calling, m_sQueriedFunc, true,
+ Config().getGraphMaxNodeDegree());
+}
+
+/**
+ * Shows a list of function calls to the current node.
+ * The list is displayed in a query dialogue. The user can the select which
+ * calls should be displayed in the graph.
+ * This slot is connected to the "List Calling Functions" popup menu
+ * action.
+ */
+void GraphWidget::slotListCalling()
+{
+ GraphNode* pNode;
+
+ // Make sure the menu item is a node
+ pNode = dynamic_cast<GraphNode*>(m_pMenuItem);
+ if (pNode == NULL)
+ return;
+
+ QueryViewDlg dlg(0, (QWidget*)parent());
+
+ // Show the query view dialogue
+ dlg.query(CscopeFrontend::Calling, pNode->getFunc());
+ if (dlg.exec() != QDialog::Accepted)
+ return;
+
+ // The OK button was clicked, replace current calls with the listed ones
+ pNode->removeInEdges();
+
+ QueryView::Iterator itr;
+ CallData data;
+
+ data.m_sCallee = pNode->getFunc();
+
+ // Add all listed calls
+ for (itr = dlg.getIterator(); !itr.isEOF(); itr.next()) {
+ data.m_sCaller = itr.getFunc();
+ data.m_sFile = itr.getFile();
+ data.m_sLine = itr.getLine();
+ data.m_sText = itr.getText();
+
+ addCall(data);
+ }
+
+ // Clean-up and redraw the graph
+ removeDisconnected(pNode);
+ draw();
+}
+
+/**
+ * Hides functions calling to the current function node.
+ * This slot is connected to the "Hide CallingFunctions" popup menu
+ * action.
+ */
+void GraphWidget::slotHideCalling()
+{
+ GraphNode* pNode;
+
+ // Make sure the menu item is a node
+ pNode = dynamic_cast<GraphNode*>(m_pMenuItem);
+ if (pNode == NULL)
+ return;
+
+ // Remove edges and redraw the graph
+ removeEdges(pNode, false);
+ draw();
+}
+
+/**
+ * Looks up the definition of the current function node.
+ * This slot is connected to the "Find Definition" popup menu action.
+ */
+void GraphWidget::slotFindDef()
+{
+ GraphNode* pNode;
+ QueryViewDlg* pDlg;
+
+ // Make sure the menu item is a node
+ pNode = dynamic_cast<GraphNode*>(m_pMenuItem);
+ if (pNode == NULL)
+ return;
+
+ // Create a query view dialogue
+ pDlg = new QueryViewDlg(QueryViewDlg::DestroyOnSelect, this);
+
+ // Display a line when it is selected in the dialogue
+ connect(pDlg, SIGNAL(lineRequested(const QString&, uint)), this,
+ SIGNAL(lineRequested(const QString&, uint)));
+
+ // Start the query
+ pDlg->query(CscopeFrontend::Definition, pNode->getFunc());
+}
+
+/**
+ * Deletes a node from the graph (alogn with all edges connected to this
+ * node).
+ * The node removed is the one over which the context menu was invoked.
+ * This slot is connected to the "Remove" popup menu action.
+ */
+void GraphWidget::slotRemoveNode()
+{
+ GraphNode* pNode;
+
+ // Make sure the menu item is a node
+ pNode = dynamic_cast<GraphNode*>(m_pMenuItem);
+ if (pNode == NULL)
+ return;
+
+ // Remove all incoming edges
+ pNode->removeInEdges();
+
+ // Remove the node (also deletes the object and its outgoing edges)
+ m_dictNodes.remove(pNode->getFunc());
+
+ // Redraw the graph
+ draw();
+}
+
+/**
+ * Shows the list of calls that is represented by a single multi-call node.
+ * This slot handles the "Details..." command of the multi-call node menu.
+ */
+void GraphWidget::slotMultiCallDetails()
+{
+ GraphNode* pNode, * pParent;
+ bool bCalled;
+
+ // Make sure the menu item is a node
+ pNode = dynamic_cast<GraphNode*>(m_pMenuItem);
+ if (pNode == NULL || !pNode->isMultiCall())
+ return;
+
+ // Get the required information from the node
+ pNode->getFirstNeighbour(pParent, bCalled);
+ if (!pParent)
+ return;
+
+ QueryViewDlg dlg(0, (QWidget*)parent());
+
+ dlg.query(bCalled ? CscopeFrontend::Calling : CscopeFrontend::Called,
+ pParent->getFunc());
+ dlg.exec();
+}
+
+/**
+ * Emits a signal to open an editor at the file and line matching the call
+ * information of the current edge.
+ * This slot is connected to the "Open Call" popup menu action (for edges).
+ */
+void GraphWidget::slotOpenCall()
+{
+ GraphEdge* pEdge;
+ QString sFile, sLine;
+
+ // Make sure the menu item is an edge
+ pEdge = dynamic_cast<GraphEdge*>(m_pMenuItem);
+ if (pEdge != NULL && pEdge->getFile() != "")
+ emit lineRequested(pEdge->getFile(), pEdge->getLine());
+}
+
+#include "graphwidget.moc"
diff --git a/src/graphwidget.h b/src/graphwidget.h
new file mode 100644
index 0000000..119ddbb
--- /dev/null
+++ b/src/graphwidget.h
@@ -0,0 +1,213 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef GRAPHWIDGET_H
+#define GRAPHWIDGET_H
+
+#include <qcanvas.h>
+#include <qpopupmenu.h>
+#include <qdict.h>
+#include "cscopefrontend.h"
+#include "graphnode.h"
+#include "dotfrontend.h"
+
+class ProgressDlg;
+
+/**
+ * A widget that displays call tree graphs generated by graphviz.
+ * This class is based on a QCanvasView widget, and displays two types of
+ * canvas items: GraphNode, which draws the name of a function inside a
+ * polygon, and ArrowEdge, which is a directed graph edge shaped like an
+ * arrow.
+ * The call tree graph is populated using the addNode() method. The first
+ * call creates a root node. Subsequent calls add nodes which represent either
+ * functions called by a previously inserted node, or that are calling such
+ * a node. A directed edge is created to depict the relationship between a
+ * node and its parent.
+ * Drawing is done through the embedded Agraph_t object (a graph, as defined
+ * by the graphviz libraray). When the draw() method is called, the graph is
+ * layed out in memory. The class then uses the CodeGenerator class to
+ * obtain a set of instructions on how to actually draw the graph. These
+ * instructions are used to create the appropriate canvas items.
+ * An application _must_ call GraphWidget::init() before attempting to use
+ * this class. It should also call GraphWidget::fini() when it no longer needs
+ * any of these widgets.
+ * @author Elad Lahav
+ */
+class GraphWidget : public QCanvasView
+{
+ Q_OBJECT
+
+public:
+ GraphWidget(QWidget* pParent = 0, const char* szName = 0);
+ ~GraphWidget();
+
+ /**
+ * Information on a function call, as produced by a Cscope query.
+ * This structure is used for adding calls to the graph.
+ * @see addCall()
+ */
+ struct CallData
+ {
+ /** The name of the calling function. */
+ QString m_sCaller;
+
+ /** The name of the called function. */
+ QString m_sCallee;
+
+ /** Path of the file in which the call appears. */
+ QString m_sFile;
+
+ /** The line number of the call. */
+ QString m_sLine;
+
+ /** The call's text. */
+ QString m_sText;
+ };
+
+ /** Graph orientation values. */
+ enum Orientation { Portrait, Landscape };
+
+ void setRoot(const QString&);
+ GraphNode* addNode(const QString&, bool bMultiCall = false);
+ void addCall(const CallData&);
+ void addMultiCall(const QString&, bool);
+ void draw();
+ void save(FILE*);
+ void save(const QString&);
+ void zoom(bool);
+ void setZoom(double);
+ void rotate();
+ QString getTip(const QPoint&, QRect&);
+
+ void resize(int, int);
+ void drawNode(const QString&, const QRect&);
+ void drawEdge(const QString&, const QString&, const QPointArray&);
+
+ /**
+ * Adjusts the maximal number of calling/called functions shown for
+ * every node (@see m_nMaxNodeDegree).
+ * @param nMaxNodeDegree The new value to set
+ */
+ void setMaxNodeDegree(int nMaxNodeDegree) { m_nMaxNodeDegree =
+ nMaxNodeDegree; }
+
+ static void setArrowInfo(int, int);
+
+signals:
+ /**
+ * Emitted when the user makes a request to view the contents of a
+ * location in the source code.
+ * This can be the location of a call, the definition of a function,
+ * etc.
+ * @param sPath The full path of the file to show
+ * @param nLine The line number in this file
+ */
+ void lineRequested(const QString& sPath, uint nLine);
+
+protected:
+ virtual void drawContents(QPainter*, int, int, int, int);
+ virtual void contentsMousePressEvent(QMouseEvent*);
+
+private:
+ /** The graph is stored as a map of nodes indexed by their names.
+ Each node holds a list of outgoing edges. */
+ QDict<GraphNode> m_dictNodes;
+
+ /** A Cscope process to use for running queries. */
+ CscopeFrontend* m_pCscope;
+
+ /** Displays query progress information. */
+ CscopeProgress m_progress;
+
+ /** A Dot process used to draw the graph. */
+ DotFrontend m_dot;
+
+ /** Remembers the function the was last queried for calling/called
+ functions. */
+ QString m_sQueriedFunc;
+
+ /** Remembers whether the last query was for calling or called
+ functions. */
+ bool m_bCalled;
+
+ /** The node over which the popup menu has been invoked. */
+ QCanvasPolygonalItem* m_pMenuItem;
+
+ /** A popup menu that appears when a node is right-clicked. */
+ QPopupMenu* m_pNodePopup;
+
+ /** A popup menu that appears when a node is right-clicked. */
+ QPopupMenu* m_pMultiCallPopup;
+
+ /** A popup menu that appears when an edge is right-clicked. */
+ QPopupMenu* m_pEdgePopup;
+
+ /** The zoom factor for the graph. */
+ double m_dZoom;
+
+ /** Maximal number of in/out edges per node. If this number is exceeded,
+ the graph shows a single "multi-call" node. */
+ int m_nMaxNodeDegree;
+
+ /** Holds information used to draw arrow heads. */
+ static ArrowInfo s_ai;
+
+ /** Used for generating unique names for multi-call nodes. */
+ uint m_nMultiCallNum;
+
+ /** Holds the path of the temporary dot file used for drawing the graph. */
+ QString m_sDrawFilePath;
+
+ /** Allows lengthy drawing operations to be cancelled. */
+ ProgressDlg* m_pProgressDlg;
+
+ void write(QTextStream&, const QString&, const QString&, bool);
+ void removeEdges(GraphNode*, bool);
+ void removeDisconnected(GraphNode*);
+ void showNodeMenu(GraphNode*, const QPoint&);
+ void showEdgeMenu(GraphEdge*, const QPoint&);
+
+private slots:
+ void slotDotFinished();
+ void slotDataReady(FrontendToken*);
+ void slotProgress(int, int);
+ void slotFinished(uint);
+ void slotAborted();
+ void slotShowCalled();
+ void slotListCalled();
+ void slotHideCalled();
+ void slotShowCalling();
+ void slotListCalling();
+ void slotHideCalling();
+ void slotFindDef();
+ void slotRemoveNode();
+ void slotMultiCallDetails();
+ void slotOpenCall();
+};
+
+#endif
diff --git a/src/hi16-app-kscope.png b/src/hi16-app-kscope.png
new file mode 100644
index 0000000..7659966
--- /dev/null
+++ b/src/hi16-app-kscope.png
Binary files differ
diff --git a/src/hi32-app-kscope.png b/src/hi32-app-kscope.png
new file mode 100644
index 0000000..54d2af0
--- /dev/null
+++ b/src/hi32-app-kscope.png
Binary files differ
diff --git a/src/historypage.cpp b/src/historypage.cpp
new file mode 100644
index 0000000..eabd6b6
--- /dev/null
+++ b/src/historypage.cpp
@@ -0,0 +1,124 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <klocale.h>
+#include "historypage.h"
+#include "historyview.h"
+
+int HistoryPage::s_nMaxPageID = 0;
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+HistoryPage::HistoryPage(QWidget* pParent, const char* szName) :
+ QueryPageBase(pParent, szName),
+ m_nPageID(++s_nMaxPageID)
+{
+ m_pView = new HistoryView(this);
+
+ connect(m_pView, SIGNAL(lineRequested(const QString&, uint)), this,
+ SIGNAL(lineRequested(const QString&, uint)));
+
+ // Set colours and font
+ applyPrefs();
+}
+
+/**
+ * Class destructor.
+ */
+HistoryPage::~HistoryPage()
+{
+ if (s_nMaxPageID == m_nPageID)
+ s_nMaxPageID--;
+}
+
+/**
+ * Creates a new position history record at the top of the list.
+ * @param sFile The file name associated with the record
+ * @param nLine The line number
+ * @param sText The text of the file at the given line
+ */
+void HistoryPage::addRecord(const QString& sFile, uint nLine,
+ const QString& sText)
+{
+ HistoryItem* pItem, * pNextItem;
+
+ pItem = (HistoryItem*)m_pView->currentItem();
+ if (pItem != NULL) {
+ // Do not add duplicate items
+ if ((pItem->text(1) == sFile) && (pItem->text(2).toUInt() == nLine))
+ return;
+
+ // Remove all items above the current one, so the new item is added to
+ // the top of the list
+ pItem = pItem->m_pPrevSibling;
+ while (pItem != NULL) {
+ pNextItem = pItem;
+ pItem = pItem->m_pPrevSibling;
+ delete pNextItem;
+ }
+ }
+
+ // Create the new item at the top of the list
+ m_pView->addRecord("", sFile, QString::number(nLine), sText, NULL);
+}
+
+/**
+ * Creates a new history item.
+ * This version is used when history records are read from a file.
+ * @param sFile The file name
+ * @param sLine The line number
+ * @param sText The contents of the line
+ */
+void HistoryPage::addRecord(const QString&, const QString& sFile,
+ const QString& sLine, const QString& sText)
+{
+ m_pView->addRecord("", sFile, sLine, sText, NULL);
+}
+
+/**
+ * Creates a tab caption for this page, based on the unique page ID.
+ * @param bBrief true to use brief caption names, false otherwise
+ */
+QString HistoryPage::getCaption(bool bBrief) const
+{
+ return (bBrief ? QString(i18n("HIS ")) : QString(i18n("History "))) +
+ QString::number(m_nPageID);
+}
+
+/**
+ * Creates a unique file name for saving the contents of the history page.
+ * @return The unique file name to use
+ */
+QString HistoryPage::getFileName(const QString&) const
+{
+ return QString("History_") + QString::number(m_nPageID);
+}
+
+#include "historypage.moc"
diff --git a/src/historypage.h b/src/historypage.h
new file mode 100644
index 0000000..9ff614f
--- /dev/null
+++ b/src/historypage.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef HISTORYPAGE_H
+#define HISTORYPAGE_H
+
+#include "querypagebase.h"
+
+/**
+ * A QueryWidget page for holding position history.
+ * @author Elad Lahav
+ */
+class HistoryPage : public QueryPageBase
+{
+ Q_OBJECT
+
+public:
+ HistoryPage(QWidget* pParent = 0, const char* szName = 0);
+ ~HistoryPage();
+
+ void addRecord(const QString&, uint, const QString&);
+
+ virtual QString getCaption(bool bBrief = false) const;
+
+protected:
+ virtual void addRecord(const QString&, const QString&, const QString&,
+ const QString&);
+ virtual QString getFileName(const QString&) const;
+
+ /**
+ * @return Always true, since History files do not contain a header
+ */
+ virtual bool readHeader(QTextStream&) { return true; }
+
+ /**
+ * This method does nothing, since History files do not contain a header.
+ */
+ virtual void writeHeader(QTextStream&) {}
+
+private:
+ /** A unique ID used to create a tab caption for this page. */
+ int m_nPageID;
+
+ /** Used to generate the unique page ID for each object. */
+ static int s_nMaxPageID;
+};
+
+#endif
diff --git a/src/historyview.cpp b/src/historyview.cpp
new file mode 100644
index 0000000..519c4dc
--- /dev/null
+++ b/src/historyview.cpp
@@ -0,0 +1,124 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include "historyview.h"
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+HistoryView::HistoryView(QWidget* pParent, const char* szName) :
+ QueryView(pParent, szName)
+{
+ // Disable sorting
+ setSortColumn(-1);
+
+ // Don't show the "Function" column
+ setColumnWidthMode(0, QListView::Manual);
+ setColumnWidth(0, 0);
+}
+
+/**
+ * Class destructor.
+ */
+HistoryView::~HistoryView()
+{
+}
+
+/**
+ * Creates a new list item showing a history record.
+ * @param sFunc The name of the function
+ * @param sFile The file path
+ * @param sLine The line number in the above file
+ * @param sText The line's text
+ */
+void HistoryView::addRecord(const QString& /* sFunc */, const QString& sFile,
+ const QString& sLine, const QString& sText, QListViewItem*)
+{
+ HistoryItem* pItem;
+
+ pItem = new HistoryItem(this, sFile, sLine, sText);
+ setSelected(pItem, true);
+}
+
+/**
+ * Moves to the previous item in the history, selecting it for display.
+ * Note that this function move to the item which chronologically precedes
+ * the current one, which, in list view terms, is the next item.
+ */
+void HistoryView::selectPrev()
+{
+ QListViewItem* pItem;
+
+ // Get the current item
+ pItem = currentItem();
+
+ // Select the next item in the list
+ if (pItem != NULL && pItem->nextSibling() != NULL) {
+ pItem = pItem->nextSibling();
+ select(pItem);
+ }
+}
+
+/**
+ * Moves to the next item in the history, selecting it for display.
+ * Note that this function move to the item which chronologically succedes
+ * the current one, which, in list view terms, is the previous item.
+ */
+void HistoryView::selectNext()
+{
+ HistoryItem* pItem;
+
+ // Get the current item
+ pItem = (HistoryItem*)currentItem();
+
+ // Select the previous item in the list
+ if (pItem != NULL && pItem->m_pPrevSibling != NULL) {
+ pItem = pItem->m_pPrevSibling;
+ select(pItem);
+ }
+}
+
+/**
+ * Deletes the item on which a popup-menu has been invoked.
+ * This slot is connected to the remove() signal of the QueryResultsMenu
+ * object.
+ * @param pItem The item to remove
+ */
+void HistoryView::slotRemoveItem(QListViewItem* pItem)
+{
+ HistoryItem* pCurItem, * pNextItem;
+
+ pCurItem = (HistoryItem*)pItem;
+ if ((pNextItem = (HistoryItem*)pCurItem->nextSibling()) != NULL)
+ pNextItem->m_pPrevSibling = pCurItem->m_pPrevSibling;
+
+ delete pCurItem;
+}
+
+#include "historyview.moc"
diff --git a/src/historyview.h b/src/historyview.h
new file mode 100644
index 0000000..38a0c46
--- /dev/null
+++ b/src/historyview.h
@@ -0,0 +1,91 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef HISTORYVIEW_H
+#define HISTORYVIEW_H
+
+#include "queryview.h"
+
+/**
+ * A list view item for holding position history records.
+ * A QListViewItem cannot reference its preceding item, which is required to
+ * create a stack-like history list. Therefore a HistoryItem object
+ * stores a pointer to the item just above it in the list. The pointer is
+ * persistent, since the list cannot be sorted.
+ * @author Elad Lahav
+ */
+
+class HistoryItem : public QListViewItem
+{
+public:
+ /**
+ * Class constructor.
+ * @param pList The parent list view
+ * @param sFile The file path in this record
+ * @param sLine The line number
+ * @param sText The contents of the line in the given file
+ */
+ HistoryItem(QListView* pList, QString sFile, QString sLine,
+ QString sText) :
+ QListViewItem(pList, "", sFile, sLine, sText),
+ m_pPrevSibling(NULL) {
+ HistoryItem* pNext;
+
+ // Mark the new item as the predecessor of its next sibling
+ if ((pNext = (HistoryItem*)nextSibling()) != NULL)
+ pNext->m_pPrevSibling = this;
+ }
+
+ /** The item immediately above this one in the list. */
+ HistoryItem* m_pPrevSibling;
+};
+
+/**
+ * A list view widget for holding position history.
+ * Position history is kept in a stack-like list. Positions are always added
+ * to the top of the list, immediately before the current item. If the
+ * current item is not the top one, all items above it are purged first.
+ * To keep the stack-like structure, the list cannot be sorted.
+ * @author Elad Lahav
+ */
+class HistoryView : public QueryView
+{
+Q_OBJECT
+public:
+ HistoryView(QWidget* pParent = 0, const char* szName = 0);
+ ~HistoryView();
+
+ virtual void addRecord(const QString&, const QString&, const QString&,
+ const QString&, QListViewItem*);
+ virtual void selectNext();
+ virtual void selectPrev();
+
+protected slots:
+ virtual void slotRemoveItem(QListViewItem*);
+};
+
+#endif
diff --git a/src/kscope.cpp b/src/kscope.cpp
new file mode 100644
index 0000000..4a4ab60
--- /dev/null
+++ b/src/kscope.cpp
@@ -0,0 +1,1754 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qfile.h>
+#include <kfiledialog.h>
+#include <kmenubar.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <klineedit.h>
+#include <kinputdialog.h>
+#include <kxmlguifactory.h>
+#include <kstatusbar.h>
+#include <kurldrag.h>
+#include <kkeydialog.h>
+#include "kscope.h"
+#include "kscopeconfig.h"
+#include "projectmanager.h"
+#include "editortabs.h"
+#include "fileview.h"
+#include "filelist.h"
+#include "querywidget.h"
+#include "editormanager.h"
+#include "cscopefrontend.h"
+#include "ctagslist.h"
+#include "newprojectdlg.h"
+#include "openprojectdlg.h"
+#include "preferencesdlg.h"
+#include "dirscanner.h"
+#include "querypage.h"
+#include "calltreedlg.h"
+#include "calltreemanager.h"
+#include "kscopepixmaps.h"
+#include "progressdlg.h"
+#include "projectfilesdlg.h"
+#include "cscopemsgdlg.h"
+#include "symboldlg.h"
+#include "symbolcompletion.h"
+#include "queryviewdlg.h"
+#include "graphwidget.h"
+#include "makedlg.h"
+#include "welcomedlg.h"
+#include "bookmarksdlg.h"
+#include "kscopeactions.h"
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+KScope::KScope(QWidget* pParent, const char* szName) :
+ KParts::DockMainWindow(pParent, szName),
+ m_pCscopeBuild(NULL),
+ m_sCurFilePath(""),
+ m_nCurLine(0),
+ m_pProgressDlg(NULL),
+ m_bUpdateGUI(true),
+ m_bCscopeVerified(false),
+ m_bRebuildDB(false),
+ m_pMakeDlg(NULL)
+{
+ QString sPath;
+
+ // Load configuration
+ Config().load();
+
+ // Create the main child widgets
+ m_pEditTabs = new EditorTabs(this, NULL);
+ m_pQueryWidget = new QueryWidget(this);
+ m_pFileView = new FileView(this);
+ m_pFileList = m_pFileView->getFileList();
+ m_pMsgDlg = new CscopeMsgDlg(this);
+ m_pQueryDock = createDockWidget("Query Window", QPixmap());
+ m_pFileViewDock = createDockWidget("File List Window", QPixmap());
+
+ // Connect menu and toolbar items with the object's slots
+ m_pActions = new KScopeActions(this);
+ m_pActions->init();
+ m_pActions->slotEnableProjectActions(false);
+
+ // Show a toolbar show/hide menu
+ setStandardToolBarMenuEnabled(true);
+
+ // Create the initial GUI (no active part)
+ setXMLFile("kscopeui.rc");
+ createShellGUI();
+
+ // Create all child widgets
+ initMainWindow();
+
+ // Create control objects
+ m_pProjMgr = new ProjectManager();
+ m_pEditMgr = new EditorManager(this);
+ m_pCallTreeMgr = new CallTreeManager(this);
+
+ // Initialise the icon manager
+ Pixmaps().init();
+
+ // Open a file for editing when selected in the project's file list or the
+ // file tree
+ connect(m_pFileView, SIGNAL(fileRequested(const QString&, uint)), this,
+ SLOT(slotShowEditor(const QString&, uint)));
+
+ // Delete an editor page object after it is removed
+ connect(m_pEditTabs, SIGNAL(editorRemoved(EditorPage*)),
+ this, SLOT(slotDeleteEditor(EditorPage*)));
+
+ connect(m_pEditTabs, SIGNAL(filesDropped(QDropEvent*)), this,
+ SLOT(slotDropEvent(QDropEvent*)));
+
+ // Set an editor as the active part whenever its owner tab is selected
+ connect(m_pEditTabs, SIGNAL(editorChanged(EditorPage*, EditorPage*)),
+ this, SLOT(slotChangeEditor(EditorPage*, EditorPage*)));
+
+ // Display a file at a specific line when selected in a query list
+ connect(m_pQueryWidget, SIGNAL(lineRequested(const QString&, uint)),
+ this, SLOT(slotQueryShowEditor(const QString&, uint)));
+
+ // Display the symbol dialogue when the user opens a new query page
+ connect(m_pQueryWidget, SIGNAL(newQuery()),
+ this, SLOT(slotQueryReference()));
+
+ // Rebuild the project database after a certain time period has elapsed
+ // since the last save
+ connect(&m_timerRebuild, SIGNAL(timeout()), this, SLOT(slotRebuildDB()));
+
+ // Display a file at a specific line when selected in a call tree dialogue
+ connect(m_pCallTreeMgr, SIGNAL(lineRequested(const QString&, uint)),
+ this, SLOT(slotQueryShowEditor(const QString&, uint)));
+
+ // Store main window settings when closed
+ setAutoSaveSettings();
+
+ // Initialise arrow head drawing
+ GraphWidget::setArrowInfo(20, 15);
+
+ // Use a maximised window the first time
+ if (Config().isFirstTime())
+ showMaximized();
+
+ // Show the Welcome message
+ if (Config().showWelcomeDlg()) {
+ show();
+ slotShowWelcome();
+ }
+
+ // If this is the first time the user has launched KScope, prompt him/her
+ // to configure the global parameters
+ if (Config().isFirstTime())
+ slotConfigure();
+}
+
+/**
+ * Class destructor.
+ */
+KScope::~KScope()
+{
+ // Save configuration
+ Config().store();
+ Config().storeWorkspace(this);
+
+ delete m_pCallTreeMgr;
+ delete m_pEditMgr;
+ delete m_pCscopeBuild;
+ delete m_pProjMgr;
+
+ if (m_pMakeDlg != NULL)
+ delete m_pMakeDlg;
+}
+
+/**
+ * Positions child widgets into their docking stations, and performs some
+ * other main window initialisation.
+ */
+void KScope::initMainWindow()
+{
+ KStatusBar* pStatus;
+ KDockWidget* pMainDock;
+ QPopupMenu* pPopup;
+
+ // Create the status bar
+ pStatus = statusBar();
+ pStatus->insertItem(i18n(" Line: N/A Col: N/A "), 0, 0, true);
+
+ // Create the main dock for the editor tabs widget
+ pMainDock = createDockWidget("Editors Window", QPixmap());
+ pMainDock->setWidget(m_pEditTabs);
+ pMainDock->setDockSite(KDockWidget::DockCorner);
+ setMainDockWidget(pMainDock);
+ setView(pMainDock);
+ pMainDock->setEnableDocking(KDockWidget::DockNone);
+
+ // Create the query window dock
+ m_pQueryDock->setWidget(m_pQueryWidget);
+ m_pQueryDock->manualDock(pMainDock, KDockWidget::DockBottom, 65);
+
+ // Update the relevant shell action when the dock is hidden through its
+ // close button
+ connect(m_pQueryDock, SIGNAL(headerCloseButtonClicked()), m_pActions,
+ SLOT(slotQueryDockClosed()));
+
+ // Create the file view dock
+ m_pFileViewDock->setWidget(m_pFileView);
+ m_pFileViewDock->manualDock(pMainDock, KDockWidget::DockRight, 80);
+
+ // Update the relevant shell action when the dock is hidden through its
+ // close button
+ connect(m_pFileViewDock, SIGNAL(headerCloseButtonClicked()), m_pActions,
+ SLOT(slotFileViewDockClosed()));
+
+ // Associate the "Window" menu with the editor tabs widdget
+ pPopup = (QPopupMenu*)factory()->container("window", this);
+ m_pEditTabs->setWindowMenu(pPopup);
+
+ // Associate the "Query" popup menu with the query widget
+ pPopup = (QPopupMenu*)factory()->container("query_popup", this);
+ m_pQueryWidget->setPageMenu(pPopup, m_pActions->getLockAction());
+
+ // Restore dock configuration
+ Config().loadWorkspace(this);
+ m_bHideQueryOnSelection = m_pQueryDock->isHidden();
+ m_pActions->initLayoutActions();
+}
+
+/**
+ * Handles the "File->Quit" command. Closes the main window, which terminates
+ * the application.
+ */
+void KScope::slotClose()
+{
+ // Destroy the main window
+ KParts::DockMainWindow::close();
+}
+
+/**
+ * Called when a request has been issued to close the main window.
+ * Tries to close the active project.
+ * @return true if the main window can be closed, false otherwise
+ */
+bool KScope::queryClose()
+{
+ bool bResult;
+
+ m_bUpdateGUI = false;
+ bResult = slotCloseProject();
+ m_bUpdateGUI = true;
+
+ return bResult;
+}
+
+/**
+ * Handles the "Project->New..." command.
+ * Prompts the user for the name and folder for the project, and then creates
+ * the project.
+ */
+void KScope::slotCreateProject()
+{
+ NewProjectDlg dlg(true, this);
+ ProjectBase::Options opt;
+ QString sProjPath;
+
+ // Prompt the user to close any active projects
+ if (m_pProjMgr->curProject()) {
+ if (KMessageBox::questionYesNo(0,
+ i18n("The current project needs to be closed before a new one is"
+ " created.\nWould you like to close it now?")) !=
+ KMessageBox::Yes) {
+ return;
+ }
+
+ // Try to close the project.
+ if (!slotCloseProject())
+ return;
+ }
+
+ // Display the "New Project" dialog
+ if (dlg.exec() != QDialog::Accepted)
+ return;
+
+ // Create and open the new project
+ dlg.getOptions(opt);
+ if (m_pProjMgr->create(dlg.getName(), dlg.getPath(), opt, sProjPath))
+ openProject(sProjPath);
+}
+
+/**
+ * Handles the "Project->Open..." command.
+ * Prompts the user for a project file ("cscope.proj"), and opens the
+ * selected project.
+ */
+void KScope::slotOpenProject()
+{
+ OpenProjectDlg dlg;
+ QString sPath;
+
+ if (dlg.exec() == QDialog::Rejected)
+ return;
+
+ sPath = dlg.getPath();
+
+ // Check if the path refers to a permanent or temporary project
+ if (QFileInfo(sPath).isDir())
+ openProject(sPath);
+ else
+ openCscopeOut(sPath);
+}
+
+/**
+ * Handles the "Project->Add/Remove Files..." command.
+ * Opens the project's files dialog, which allows the user to add and remove
+ * source files.
+ */
+void KScope::slotProjectFiles()
+{
+ ProjectBase* pProj;
+
+ // A project must be open
+ pProj = m_pProjMgr->curProject();
+ if (!pProj)
+ return;
+
+ // Cannot update the file list of a temporary project
+ if (pProj->isTemporary()) {
+ KMessageBox::error(0, i18n("The Add/Remove Files dialogue is not "
+ "available for temporary projects."));
+ return;
+ }
+
+ // Display the files dialog
+ ProjectFilesDlg dlg((Project*)pProj, this);
+ if (dlg.exec() != QDialog::Accepted)
+ return;
+
+ // Update the project's file list
+ if (pProj->storeFileList(&dlg))
+ slotProjectFilesChanged();
+}
+
+/**
+ * Handles the "Project->Properties..." command.
+ * Opens the project's properties dialog, which allows the user to change
+ * some attributes of the current project.
+ * source files.
+ */
+void KScope::slotProjectProps()
+{
+ ProjectBase* pProj;
+ ProjectBase::Options opt;
+
+ // A project must be open
+ pProj = m_pProjMgr->curProject();
+ if (!pProj)
+ return;
+
+ // No properties for a temporary project
+ if (pProj->isTemporary()) {
+ KMessageBox::error(0, i18n("The Project Properties dialogue is not "
+ "available for temporary projects."));
+ return;
+ }
+
+ // Create the properties dialog
+ NewProjectDlg dlg(false, this);
+ pProj->getOptions(opt);
+ dlg.setProperties(pProj->getName(), pProj->getPath(), opt);
+
+ // Display the properties dialog
+ if (dlg.exec() != QDialog::Accepted)
+ return;
+
+ // Set new properties
+ dlg.getOptions(opt);
+ pProj->setOptions(opt);
+
+ // Reset the CscopeFrontend class and the builder object
+ initCscope();
+
+ // Set auto-completion parameters
+ SymbolCompletion::initAutoCompletion(opt.bACEnabled, opt.nACMinChars,
+ opt.nACDelay, opt.nACMaxEntries);
+
+ // Set per-project command-line arguments for Ctags
+ CtagsFrontend::setExtraArgs(opt.sCtagsCmd);
+
+ // Set the source root
+ m_pFileView->setRoot(pProj->getSourceRoot());
+}
+
+/**
+ * Handles the "Cscope->Open Cscope.out..." menu command.
+ * Prompts the user for a Cscope.out file, and, if successful, opens a new
+ * session for working with this file.
+ */
+void KScope::slotProjectCscopeOut()
+{
+ QString sFilePath;
+
+ // Prompt for a Cscope.out file
+ sFilePath = KFileDialog::getOpenFileName();
+ if (sFilePath.isEmpty())
+ return;
+
+ // Open a temporary project
+ openCscopeOut(sFilePath);
+}
+
+/**
+ * Handles the "Cscope->References..." menu command.
+ * Prompts the user for a symbol name, and initiates a query to find all
+ * references to that symbol.
+ */
+void KScope::slotQueryReference()
+{
+ slotQuery(SymbolDlg::Reference, true);
+}
+
+/**
+ * Handles the "Cscope->Definition..." menu command.
+ * Prompts the user for a symbol name, and initiates a query to find the
+ * global definition of that symbol.
+ */
+void KScope::slotQueryDefinition()
+{
+ slotQuery(SymbolDlg::Definition, true);
+}
+
+/**
+ * Handles the "Cscope->Called Functions..." menu command.
+ * Prompts the user for a function name, and initiates a query to find all
+ * function calls from that function.
+ */
+void KScope::slotQueryCalled()
+{
+ slotQuery(SymbolDlg::Called, true);
+}
+
+/**
+ * Handles the "Cscope->Calling Functions..." menu command.
+ * Prompts the user for a function name, and initiates a query to find all
+ * functions calling that function.
+ */
+void KScope::slotQueryCalling()
+{
+ slotQuery(SymbolDlg::Calling, true);
+}
+
+/**
+ * Handles the "Cscope->Find Text..." menu command.
+ * Prompts the user for a string, and initiates a query to find all
+occurances
+ * of that string.
+ */
+void KScope::slotQueryText()
+{
+ slotQuery(SymbolDlg::Text, true);
+}
+
+/**
+ * Handles the "Cscope->Find EGrep Pattern..." menu command.
+ * Prompts the user for a regular expression, and initiates a query to find
+ * all strings matching that pattern.
+ */
+void KScope::slotQueryPattern()
+{
+ slotQuery(SymbolDlg::Pattern, true);
+}
+
+/**
+ * Handles the "Cscope->Find File..." menu command.
+ * Prompts the user for a file name, and initiates a query to find all files
+ * having that name.
+ */
+void KScope::slotQueryFile()
+{
+ slotQuery(SymbolDlg::FileName, true);
+}
+
+/**
+ * Handles the "Cscope->Find Including Files..." menu command.
+ * Prompts the user for a file name, and initiates a query to find all files
+ * having an '#include' directive to that file.
+ */
+void KScope::slotQueryIncluding()
+{
+ slotQuery(SymbolDlg::Including, true);
+}
+
+/**
+ * Handles the "Cscope->Quick Definition" menu command.
+ * Initiates a query to find the global definition of the symbol currently
+ * selected or under the cursor. The user is prompted only if no symbol can
+ * be found.
+ */
+void KScope::slotQueryQuickDef()
+{
+ QString sSymbol;
+ QueryViewDlg* pDlg;
+ uint nType;
+ bool bCase;
+
+ // Get the requested symbol and query type
+ nType = SymbolDlg::Definition;
+ if (!getSymbol(nType, sSymbol, bCase, false))
+ return;
+
+ // Create a modeless query view dialogue
+ pDlg = new QueryViewDlg(QueryViewDlg::DestroyOnSelect, this);
+
+ // Display a line when it is selected in the dialogue
+ connect(pDlg, SIGNAL(lineRequested(const QString&, uint)), this,
+ SLOT(slotShowEditor(const QString&, uint)));
+
+ // Start the query
+ pDlg->query(nType, sSymbol);
+}
+
+/**
+ * Handles the "Cscope->Call Tree..." menu command.
+ * Displays a tree of functions calling the requested function.
+ */
+void KScope::slotCallTree()
+{
+ slotQuery(SymbolDlg::CallTree, true);
+}
+
+/**
+ * Handles the "Cscope->Rebuild Database..." command.
+ * Rebuilds Cscope's database for the current project.
+ */
+void KScope::slotRebuildDB()
+{
+ ProjectBase* pProj;
+
+ pProj = m_pProjMgr->curProject();
+ if (!pProj)
+ return;
+
+ if (!pProj->dbExists()) {
+ m_pProgressDlg = new ProgressDlg(i18n("KScope"), i18n("Please wait "
+ "while KScope builds the database"), this);
+ m_pProgressDlg->setAllowCancel(false);
+ m_pProgressDlg->setValue(0);
+ }
+
+ m_pCscopeBuild->rebuild();
+}
+
+/**
+ * Handles the "Settings->Configure Shortcuts..." command.
+ * Displays the prferences dialog, which allows the user
+ * to change the shortcuts for KScope.
+ */
+void KScope::slotShortcuts()
+{
+ KKeyDialog::configure(actionCollection(), this);
+}
+
+/**
+ * Handles the "Settings->Configure KScope..." command.
+ * Displays the prferences dialog, which allows the user to set different
+ * configuration parameters for KScope.
+ */
+void KScope::slotConfigure()
+{
+ PreferencesDlg dlg;
+
+ // Apply the preferences if either the "Apply" or the "OK" buttons are
+ // clicked
+ connect(&dlg, SIGNAL(applyPref()), this, SLOT(slotApplyPref()));
+
+ // Show the dialog
+ if (dlg.exec() == QDialog::Accepted) {
+ // Verify Cscope's installation
+ verifyCscope();
+ }
+}
+
+/**
+ * Refreshes the file list when files are added to or removed from a project,
+ * and rebuilds the Cscope database.
+ * This slot is attached to the fileListChanged() signal emitted by
+ * the ProjectManager object.
+ */
+void KScope::slotProjectFilesChanged()
+{
+ QStringList slArgs;
+
+ // Refresh the file list
+ m_pFileList->setUpdatesEnabled(false);
+ m_pFileList->clear();
+ m_pProjMgr->curProject()->loadFileList(m_pFileList);
+ m_pFileList->setUpdatesEnabled(true);
+
+ // Rebuild the symbol database
+ if (isAutoRebuildEnabled())
+ slotRebuildDB();
+}
+
+/**
+ * Adds a list of files to the current project.
+ * This slot is connected to the filesAdded() signal of the ProjectManager
+ * object. Once files are added to the project, they are also added to the
+ * file list, and the project's database is rebuilt.
+ * @param slFiles The list of file paths added to the project
+ */
+void KScope::slotFilesAdded(const QStringList& slFiles)
+{
+ QStringList::const_iterator itr;
+
+ // Add the file paths to the project's file list
+ for (itr = slFiles.begin(); itr != slFiles.end(); ++itr)
+ m_pFileList->addItem(*itr);
+
+ // Rebuild the database
+ if (isAutoRebuildEnabled())
+ slotRebuildDB();
+}
+
+/**
+ * Promts the user for a symbol, an starts a new Cscope query.
+ * @param nType The numeric query type code
+ * @param bPrompt true to always prompt for a symbol, false to try to
+ * obtain the symbol automatically
+ */
+void KScope::slotQuery(uint nType, bool bPrompt)
+{
+ QString sSymbol;
+ CallTreeDlg* pCallTreeDlg;
+ bool bCase;
+
+ // Get the requested symbol and query type
+ if (!getSymbol(nType, sSymbol, bCase, bPrompt))
+ return;
+
+ if (nType == SymbolDlg::CallTree) {
+ // Create and display a call tree dialogue
+ pCallTreeDlg = m_pCallTreeMgr->addDialog();
+ pCallTreeDlg->setRoot(sSymbol);
+ pCallTreeDlg->show();
+ }
+ else {
+ // Run the requested query
+ nType = SymbolDlg::getQueryType(nType);
+ m_pQueryWidget->initQuery(nType, sSymbol, bCase);
+
+ // Ensure Query Window is visible
+ toggleQueryWindow(true);
+ }
+}
+
+/**
+ * Opens a project.
+ * If another project is currently active, it is closed first.
+ * @param sDir The directory of the project to open.
+ */
+void KScope::openProject(const QString& sDir)
+{
+ QString sProjDir;
+ ProjectBase* pProj;
+ QStringList slQueryFiles;
+ QStringList slCallTreeFiles;
+ QStringList slArgs;
+ ProjectBase::Options opt;
+
+ // Close the current project (may return false if the user clicks on the
+ // "Cancel" button while prompted to save a file)
+ if (!slotCloseProject())
+ return;
+
+ // Open the project in the project manager
+ sProjDir = QDir::cleanDirPath(sDir);
+ if (!m_pProjMgr->open(sProjDir))
+ return;
+
+ // Change main window title
+ pProj = m_pProjMgr->curProject();
+ setCaption(pProj->getName());
+
+ // Set the root of the file tree
+ m_pFileView->setRoot(pProj->getSourceRoot());
+
+ // Initialise Cscope and create a builder object
+ initCscope();
+
+ // Set auto-completion parameters
+ pProj->getOptions(opt);
+ SymbolCompletion::initAutoCompletion(opt.bACEnabled, opt.nACMinChars,
+ opt.nACDelay, opt.nACMaxEntries);
+
+ // Set per-project command-line arguments for Ctags
+ CtagsFrontend::setExtraArgs(opt.sCtagsCmd);
+
+ // Create an initial query page
+ m_pQueryWidget->addQueryPage();
+
+ // Enable project-related actions
+ m_pActions->slotEnableProjectActions(true);
+
+ // If this is a new project (i.e., no source files are yet included),
+ // display the project files dialogue
+ if (pProj->isEmpty()) {
+ slotProjectFiles();
+ return;
+ }
+
+ // Fill the file list with all files in the project.
+ m_pFileList->setUpdatesEnabled(false);
+ pProj->loadFileList(m_pFileList);
+ m_pFileList->setUpdatesEnabled(true);
+
+ // Restore the last session
+ restoreSession();
+
+ // Rebuild the cross-reference database
+ if (isAutoRebuildEnabled()) {
+ // If Cscope installation was not yet verified, postpone the build
+ // process
+ if (m_bCscopeVerified)
+ slotRebuildDB();
+ else
+ m_bRebuildDB = true;
+ }
+}
+
+/**
+ * Opens a temporary project for a Cscope.out file.
+ * @param sFilePath The full path of the Cscope.out file
+ * @return true if successful, false otherwise
+ */
+bool KScope::openCscopeOut(const QString& sFilePath)
+{
+ ProjectBase* pProj;
+
+ // Close the current project (may return false if the user clicks on the
+ // "Cancel" button while prompted to save a file)
+ if (!slotCloseProject())
+ return false;
+
+ // Open a temporary project for this cscope.out file
+ if (!m_pProjMgr->openCscopeOut(sFilePath))
+ return false;
+
+ // Change main window title
+ pProj = m_pProjMgr->curProject();
+ setCaption(pProj->getName());
+
+ // Set the root folder in the file tree
+ m_pFileView->setRoot(pProj->getSourceRoot());
+
+ // Initialise Cscope and create a builder object
+ initCscope();
+
+ // Create an initial query page
+ m_pQueryWidget->addQueryPage();
+
+ // Enable project-related actions
+ m_pActions->slotEnableProjectActions(true);
+
+ // Fill the file list with all files in the project.
+ m_pFileList->setUpdatesEnabled(false);
+ pProj->loadFileList(m_pFileList);
+ m_pFileList->setUpdatesEnabled(true);
+
+ return true;
+}
+
+/**
+ * Opens the most recently used project.
+ * This method is called when KScope starts, but only if the relevant
+ * configuration flag (Reload Last Project) is set.
+ */
+void KScope::openLastProject()
+{
+ const QStringList slProjects = Config().getRecentProjects();
+ QString sPath;
+
+ if (slProjects.empty())
+ return;
+
+ // Get the project's path
+ sPath = *slProjects.begin();
+
+ // Check if the path refers to a temporary project
+ if (!QFileInfo(sPath).isDir()) {
+ openCscopeOut(sPath);
+ return;
+ }
+
+ openProject(sPath);
+}
+
+/**
+ * Reopens all files which were open when the project was last closed.
+ * In order to reduce the time required by this operation, the GUI of all
+ * but the last editor part is not merged with that of the main window.
+ */
+void KScope::restoreSession()
+{
+ ProjectBase* pProj;
+ Project::Session sess;
+ FileLocation* pLoc;
+ EditorPage* pPage;
+
+ // A session is available for persistent projects only
+ pProj = m_pProjMgr->curProject();
+ if (!pProj || pProj->isTemporary())
+ return;
+
+ // Make sure all FileLocation objects are deleted
+ sess.fllOpenFiles.setAutoDelete(true);
+ sess.fllBookmarks.setAutoDelete(true);
+
+ // Load the session
+ ((Project*)pProj)->loadSession(sess);
+
+ // Do not update the GUI when loading the editor parts of the initially
+ // hidden windows
+ m_bUpdateGUI = false;
+
+ for (pLoc = sess.fllOpenFiles.first(); pLoc != NULL;
+ pLoc = sess.fllOpenFiles.next()) {
+ if (QFile::exists(pLoc->m_sPath)) {
+ pPage = addEditor(pLoc->m_sPath);
+ pPage->setCursorPos(pLoc->m_nLine, pLoc->m_nCol);
+ }
+ }
+
+ // Merge the GUI of the visible editor part
+ m_bUpdateGUI = true;
+
+ // Set the active editor (or choose a default one)
+ if (m_pEditTabs->findEditorPage(sess.sLastFile, true) == NULL)
+ m_pEditTabs->findEditorPage(sess.fllOpenFiles.last()->m_sPath, true);
+
+ // Reload bookmarks
+ m_pEditTabs->setBookmarks(sess.fllBookmarks);
+
+ // Load previously stored queries and call trees
+ m_pQueryWidget->loadPages(pProj->getPath(), sess.slQueryFiles);
+ m_pCallTreeMgr->loadOpenDialogs(pProj->getPath(), sess.slCallTreeFiles);
+}
+
+/**
+ * Shows or hides the query dock window.
+ * This function is only called internally, not as a result of a user's
+ * workspace action (e.g., clicking the "Show/Hide Query Window" toolbar
+ * button). Therefore it does not reflect the user's preference, which is
+ * kept through the m_bHideQueryOnSelection variable.
+ * @param bShow true to show the window, false to hide it
+ */
+void KScope::toggleQueryWindow(bool bShow)
+{
+ // Remember the user's preferences
+ if (bShow)
+ m_bHideQueryOnSelection = m_pQueryDock->isHidden();
+ else
+ m_bHideQueryOnSelection = false;
+
+ // Change the visibility state of the widget, if required
+ if (m_pQueryDock->isShown() != bShow)
+ m_pQueryDock->changeHideShowState();
+
+ // Synchronise with the menu command's state
+ m_pActions->slotQueryDockToggled(bShow);
+}
+
+/**
+ * Parses the command line, after it was stripped of its KDE options.
+ * The command line may contain one of the following options:
+ * 1. A project file (named cscope.proj)
+ * 2. A Cscope cross-reference database
+ * 3. A list of source files
+ * @param pArgs Command line arguments
+ */
+void KScope::parseCmdLine(KCmdLineArgs* pArgs)
+{
+ QString sArg;
+ QFileInfo fi;
+ int i;
+
+ // Loop over all arguments
+ for (i = 0; i < pArgs->count(); i++) {
+ // Verify the argument is a file or directory name
+ sArg = pArgs->arg(i);
+ fi.setFile(sArg);
+ if (!fi.exists())
+ continue;
+
+ // Handle the current argument
+ if (fi.isFile()) {
+ if (fi.fileName() == "cscope.proj") {
+ // Open a project file
+ openProject(fi.dirPath(true));
+ return;
+ } else if (openCscopeOut(sArg)) {
+ // Opened the file as a cross-reference database
+ return;
+ } else {
+ // Assume this is a source file
+ slotShowEditor(sArg, 0);
+ }
+ } else if (fi.isDir()) {
+ // Treat the given path as a project directory
+ openProject(fi.absFilePath());
+ return;
+ }
+ }
+}
+
+/**
+ * Starts a shell script to ensure that Cscope is properly installed and to
+ * extract the supported command-line arguments.
+ */
+void KScope::verifyCscope()
+{
+ CscopeVerifier* pVer;
+
+ statusBar()->message(i18n("Verifying Cscope installation..."));
+
+ pVer = new CscopeVerifier();
+ connect(pVer, SIGNAL(done(bool, uint)), this,
+ SLOT(slotCscopeVerified(bool, uint)));
+
+ pVer->verify();
+}
+
+/**
+ * Initialises the CscopeFrontend class with the current project arguments,
+ * and creates an object used for rebuilding the symbol database.
+ */
+void KScope::initCscope()
+{
+ ProjectBase* pProj;
+
+ // Delete the current object, if one exists
+ if (m_pCscopeBuild)
+ delete m_pCscopeBuild;
+
+ // Initialise CscopeFrontend
+ pProj = m_pProjMgr->curProject();
+ CscopeFrontend::init(pProj->getPath(), pProj->getArgs());
+
+ // Create a persistent Cscope process
+ m_pCscopeBuild = new CscopeFrontend();
+
+ // Show build progress information in the main status bar
+ connect(m_pCscopeBuild, SIGNAL(progress(int, int)), this,
+ SLOT(slotBuildProgress(int, int)));
+ connect(m_pCscopeBuild, SIGNAL(buildInvIndex()), this,
+ SLOT(slotBuildInvIndex()));
+ connect(m_pCscopeBuild, SIGNAL(finished(uint)), this,
+ SLOT(slotBuildFinished(uint)));
+ connect(m_pCscopeBuild, SIGNAL(aborted()), this,
+ SLOT(slotBuildAborted()));
+
+ // Show errors in a modeless dialogue
+ connect(m_pCscopeBuild, SIGNAL(error(const QString&)), this,
+ SLOT(slotCscopeError(const QString&)));
+}
+
+/**
+ * Closes the active project.
+ * Closing a project involves closing all of the editor windows (prompting
+ * the user for unsaved changes); terminating the Cscope process; and further
+ * clean-up of the project's data.
+ */
+bool KScope::slotCloseProject()
+{
+ ProjectBase* pProj;
+ Project::Session sess;
+
+ // Do nothing if no project is open
+ pProj = m_pProjMgr->curProject();
+ if (!pProj)
+ return true;
+
+ // Make sure all FileLocation objects are deleted
+ sess.fllOpenFiles.setAutoDelete(true);
+ sess.fllBookmarks.setAutoDelete(true);
+
+ // Close all open editor pages
+ if (m_pEditTabs->count() > 0) {
+ // Save session information for persistent projects
+ if (!pProj->isTemporary()) {
+ sess.sLastFile = m_pEditTabs->getCurrentPage()->getFilePath();
+ m_pEditTabs->getOpenFiles(sess.fllOpenFiles);
+ m_pEditTabs->getBookmarks(sess.fllBookmarks);
+ }
+
+ if (!m_pEditTabs->removeAllPages())
+ return false;
+ }
+
+ // Disable project-related actions
+ m_pActions->slotEnableProjectActions(false);
+
+ // Destroy the make dialogue
+ if (m_pMakeDlg != NULL) {
+ // Save session information for persistent projects
+ if (!pProj->isTemporary()) {
+ sess.sMakeCmd = m_pMakeDlg->getCommand();
+ sess.sMakeRoot = m_pMakeDlg->getDir();
+ }
+
+ delete m_pMakeDlg;
+ m_pMakeDlg = NULL;
+ }
+
+ // Save session information for persistent projects
+ if (!pProj->isTemporary()) {
+ m_pQueryWidget->savePages(pProj->getPath(), sess.slQueryFiles);
+ m_pCallTreeMgr->saveOpenDialogs(pProj->getPath(), sess.slCallTreeFiles);
+ }
+
+ // Close all query pages and call trees
+ m_pQueryWidget->slotCloseAll();
+ m_pCallTreeMgr->closeAll();
+
+ // Store session information for persistent projects
+ if (!pProj->isTemporary())
+ ((Project*)pProj)->storeSession(sess);
+
+ // Close the project in the project manager, and terminate the Cscope
+ // process
+ m_pProjMgr->close();
+ delete m_pCscopeBuild;
+ m_pCscopeBuild = NULL;
+ setCaption(QString::null);
+
+ // Clear the contents of the file list
+ m_pFileView->clear();
+
+ // Reset queried symbols history
+ SymbolDlg::resetHistory();
+
+ // Remove any remaining status bar messages
+ statusBar()->message("");
+
+ return true;
+}
+
+/**
+ * Handles the "Edit->Edit in External Editor" menu command.
+ * Invokes an external editor for the current file and line number.
+ */
+void KScope::slotExtEdit()
+{
+ QString sCmdLine;
+ KProcess proc;
+
+ // Create the command line for the external editor
+ sCmdLine = Config().getExtEditor();
+ sCmdLine.replace("%F", m_sCurFilePath);
+ sCmdLine.replace("%L", QString::number(m_nCurLine));
+
+ // Run the external editor
+ proc.setUseShell(true);
+ proc << sCmdLine;
+ proc.start(KProcess::DontCare);
+}
+
+/**
+ * Handles the "Edit->Complete Symbol" menu command.
+ * Creates a list of possible completions for the symbol currently under the
+ * cursor.
+ */
+void KScope::slotCompleteSymbol()
+{
+ EditorPage* pPage;
+
+ pPage = m_pEditTabs->getCurrentPage();
+ if (pPage != NULL)
+ pPage->slotCompleteSymbol();
+}
+
+/**
+ * Handles the "Help->Show Welcome Message..." menu command.
+ * Displays the "Welcome" dialogue.
+ */
+void KScope::slotShowWelcome()
+{
+ WelcomeDlg dlg;
+ dlg.exec();
+}
+
+/**
+ * Handles the "Edit->Go To Tag" menu command.
+ * Sets the cursor to the edit box of the current tag list.
+ */
+void KScope::slotGotoTag()
+{
+ EditorPage* pPage;
+
+ pPage = m_pEditTabs->getCurrentPage();
+ if (pPage)
+ pPage->setTagListFocus();
+}
+
+/**
+ * Reports the results of the Cscope verification script.
+ * This slot is connected to the done() signal emitted by the CscopeVerifier
+ * object constructed in verifyCscope().
+ */
+void KScope::slotCscopeVerified(bool bResult, uint nArgs)
+{
+ statusBar()->message(i18n("Verifying Cscope installation...Done"), 3000);
+
+ // Mark the flag even if Cscope was not found, to avoid nagging the user
+ // (who may wish to use KScope even with Cscope disabled)
+ m_bCscopeVerified = true;
+
+ // Prompt the user in case Cscope is not properly installed
+ if (!bResult) {
+ KMessageBox::error(0, i18n("Cscope may not be properly installed on "
+ "this system.\nPlease check the Cscope path specified in KScope's "
+ "configuration dialogue."));
+ slotConfigure();
+ return;
+ }
+
+ // Set the discoverred supported command-line arguments
+ CscopeFrontend::setSupArgs(nArgs);
+
+ // Build the database, if required
+ if (m_bRebuildDB) {
+ m_bRebuildDB = false;
+ slotRebuildDB();
+ }
+}
+
+/**
+ * Handles the "Project->Make..." menu command.
+ * Displays the make dialogue.
+ */
+void KScope::slotProjectMake()
+{
+ QString sCmd, sDir;
+
+ // Create the make dialogue, if it does not exist
+ if (m_pMakeDlg == NULL) {
+ // Create the dialogue
+ m_pMakeDlg = new MakeDlg();
+
+ // Set make parameters for this project
+ m_pProjMgr->curProject()->getMakeParams(sCmd, sDir);
+ m_pMakeDlg->setCommand(sCmd);
+ m_pMakeDlg->setDir(sDir);
+
+ // Show the relevant source location when an error link is clicked
+ connect(m_pMakeDlg, SIGNAL(fileRequested(const QString&, uint)), this,
+ SLOT(slotShowEditor(const QString&, uint)));
+
+ // Show the dialogue
+ m_pMakeDlg->show();
+ }
+ else if (m_pMakeDlg->isShown()) {
+ // The dialogue exists, and is visible, just raise it
+ m_pMakeDlg->raise();
+ m_pMakeDlg->setActiveWindow();
+ }
+ else {
+ // The dialogue exists but is closed, show it
+ m_pMakeDlg->show();
+ }
+}
+
+/**
+ * Handles the "Project->Remake..." menu command.
+ * Displays the make dialogue and runs the make command.
+ */
+void KScope::slotProjectRemake()
+{
+ // Make sure the make dialogue exists and is displayed
+ slotProjectMake();
+
+ // Run the make command
+ m_pMakeDlg->slotMake();
+}
+
+/**
+ * Handles the "Go->Global Bookmarks" menu command.
+ * Displays a dialogue with the set of all bookmarks currently set in this
+ * project.
+ */
+void KScope::slotShowBookmarks()
+{
+ BookmarksDlg dlg;
+ QString sPath;
+ uint nLine;
+
+ // Load the bookmark list
+ m_pEditTabs->showBookmarks(dlg.getView());
+
+ // Show the dialogue
+ if (dlg.exec() != QDialog::Accepted)
+ return;
+
+ // Go to the selected bookmark
+ dlg.getBookmark(sPath, nLine);
+ slotShowEditor(sPath, nLine);
+}
+
+/**
+ * Prompts the user for a symbol to query.
+ * Shows a dialog with a line edit widget, where the user can enter a symbol
+ * on which to query Cscope. The meaning of the symbol depends on the type of
+ * query.
+ * @param nType The requested type of query (may be changed in the
+ * dialogue)
+ * @param sSymbol Holds the requested symbol, upon successful return
+ * @param bPrompt If false, the user is prompted only if a symbol cannot be
+ * determined automatically
+ * @return true if the user hs enetered a symbol, false otherwise
+ */
+bool KScope::getSymbol(uint& nType, QString& sSymbol, bool& bCase,
+ bool bPrompt)
+{
+ EditorPage* pPage;
+ QString sSuggested;
+
+ // Set the currently selected text, if any
+ if ((pPage = m_pEditTabs->getCurrentPage()) != NULL)
+ sSuggested = pPage->getSuggestedText();
+
+ // Return if a symbol was found, and prompting is turned off
+ if (!sSuggested.isEmpty() && !bPrompt) {
+ sSymbol = sSuggested;
+ return true;
+ }
+
+ // Show the symbol dialogue
+ sSymbol = SymbolDlg::promptSymbol(this, nType, sSuggested, bCase);
+
+ // Cannot accept empty strings
+ if (sSymbol.isEmpty())
+ return false;
+
+ return true;
+}
+
+/**
+ * Opens a file in a new editor tab.
+ * If an editor page already exists for the requested file, it is selected.
+ * Otherwise, a new page is created, and the requested file is loaded.
+ * @param sFilePath The path of the file to open
+ * @return A pointer to the found or newly created editor page
+ */
+EditorPage* KScope::addEditor(const QString& sFilePath)
+{
+ EditorPage* pPage;
+ QString sAbsFilePath;
+ ProjectBase* pProj;
+
+ // If the file name is given using a relative path, we need to convert
+ // it to an absolute one
+ // TODO: Project needs a translatePath() method
+ pProj = m_pProjMgr->curProject();
+ if (sFilePath[0] != '/' && pProj) {
+ sAbsFilePath = QDir::cleanDirPath(pProj->getSourceRoot() + "/" +
+ sFilePath);
+ }
+ else {
+ sAbsFilePath = QDir::cleanDirPath(sFilePath);
+ }
+
+ // Do not open a new editor if one exists for this file
+ pPage = m_pEditTabs->findEditorPage(sAbsFilePath);
+ if (pPage != NULL)
+ return pPage;
+
+ // Create a new page
+ pPage = createEditorPage();
+
+ // Open the requested file
+ pPage->open(sAbsFilePath);
+
+ return pPage;
+}
+
+/**
+ * Creates a new editor page, and adds it to the editors tab widget.
+ * @return A pointer to the new page
+ */
+EditorPage* KScope::createEditorPage()
+{
+ KTextEditor::Document* pDoc;
+ EditorPage* pPage;
+ QPopupMenu* pMenu;
+ ProjectBase* pProj;
+
+ // Load a new document part
+ pDoc = m_pEditMgr->add();
+ if (pDoc == NULL)
+ return NULL;
+
+ // Create the new editor page
+ pMenu = (QPopupMenu*)factory()->container(Config().getEditorPopupName(),
+ this);
+ pPage = new EditorPage(pDoc, pMenu, m_pEditTabs);
+ m_pEditTabs->addEditorPage(pPage);
+
+ // Show the file's path in the main title
+ connect(pPage, SIGNAL(fileOpened(EditorPage*, const QString&)), this,
+ SLOT(slotFileOpened(EditorPage*, const QString&)));
+
+ // Show cursor position in the status bar
+ connect(pPage, SIGNAL(cursorPosChanged(uint, uint)), this,
+ SLOT(slotShowCursorPos(uint, uint)));
+
+ // Rebuild the database after a file has changed
+ connect(pPage, SIGNAL(fileSaved(const QString&, bool)), this,
+ SLOT(slotFileSaved(const QString&, bool)));
+
+ // Handle file drops
+ connect(pPage->getView(), SIGNAL(dropEventPass(QDropEvent*)), this,
+ SLOT(slotDropEvent(QDropEvent*)));
+
+ // Apply per-project configuration
+ pProj = m_pProjMgr->curProject();
+ if (pProj && pProj->getTabWidth() > 0)
+ pPage->setTabWidth(pProj->getTabWidth());
+
+ return pPage;
+}
+
+/**
+ * @return true if database auto-rebuild is enabled for the current project,
+ * false otherwise
+ */
+inline bool KScope::isAutoRebuildEnabled()
+{
+ ProjectBase* pProj;
+
+ pProj = m_pProjMgr->curProject();
+ return (pProj && pProj->getAutoRebuildTime() >= 0);
+}
+
+/**
+ * Deletes an editor page after it has been removed.
+ * The document object associated with the page is removed from the part
+ * manager, and the view object is removed from the GUI manager.
+ * This slot is connected to the editorRemoved() signal of the EditorTabs
+ * object.
+ * @param pPage The editor page to delete
+ */
+void KScope::slotDeleteEditor(EditorPage* pPage)
+{
+ guiFactory()->removeClient(pPage->getView());
+ m_pEditMgr->remove(pPage->getDocument());
+ delete pPage;
+}
+
+/**
+ * Sets an editor part as active when its owner tab is chosen.
+ * Whenever a different editor tab is chosen, its editor part should become
+ * the active part. This means that this part's GUI is merged with the
+ * application's, and that it responds to actions.
+ * @param pOldPage The editor page that has ceased to be active
+ * @param pNewPage The newly chosen editor page
+ */
+void KScope::slotChangeEditor(EditorPage* pOldPage, EditorPage* pNewPage)
+{
+ KXMLGUIFactory* pFactory = guiFactory();
+
+ // Remove the current GUI
+ if (pOldPage)
+ pFactory->removeClient(pOldPage->getView());
+
+ // Set the new active part and create its GUI
+ if (m_bUpdateGUI && pNewPage) {
+ m_pEditMgr->setActivePart(pNewPage->getDocument());
+ pFactory->addClient(pNewPage->getView());
+ m_sCurFilePath = pNewPage->getFilePath();
+ setCaption(m_pProjMgr->getProjName() + " - " + m_sCurFilePath);
+ }
+
+ // Enable/disable file-related actions, if necessary
+ if (pOldPage && !pNewPage)
+ m_pActions->slotEnableFileActions(false);
+ else if (!pOldPage && pNewPage)
+ m_pActions->slotEnableFileActions(true);
+}
+
+/**
+ * Opens an editor for the given file and sets the cursor to the beginning of
+ * the requested line.
+ * @param sFilePath The full path of the file to open for editing
+ * @param nLine The number of the line on which to position the
+ * cursor, or 0 to maintain the cursor in its current
+ * position (which does not affect the position history)
+ */
+void KScope::slotShowEditor(const QString& sFilePath, uint nLine)
+{
+ EditorPage* pPage;
+
+ // Save current position in the position history
+ if (nLine != 0 && (pPage = m_pEditTabs->getCurrentPage())) {
+ m_pQueryWidget->addHistoryRecord(m_sCurFilePath, m_nCurLine,
+ pPage->getLineContents(m_nCurLine));
+ }
+
+ // Open the requested file (or select an already-open editor page)
+ pPage = addEditor(sFilePath);
+ if (pPage == NULL)
+ return;
+
+ // Make sure the main window is visible
+ raise();
+ setWindowState(windowState() & ~WindowMinimized | WindowActive);
+
+ if (nLine != 0) {
+ // Set the cursor to the requested line
+ pPage->slotGotoLine(nLine);
+
+ // Add the new position to the position history
+ m_pQueryWidget->addHistoryRecord(m_sCurFilePath, m_nCurLine,
+ pPage->getLineContents(m_nCurLine));
+ }
+}
+
+/**
+ * A wrapper around slotShowEditor, that enables auto-hiding of the query
+ * widget after a query result has been chosen.
+ * This slot is connected to the lineRequested() signal emitted by a QueryPage
+ * object.
+ * @param sFilePath The full path of the file to open for editing
+ * @param nLine The number of the line on which to position the cursor
+ */
+void KScope::slotQueryShowEditor(const QString& sFilePath, uint nLine)
+{
+ // Hide the query window, if it was hidden before a query was initiated
+ if (m_bHideQueryOnSelection)
+ toggleQueryWindow(false);
+
+ // Open an editor at the requested line
+ slotShowEditor(sFilePath, nLine);
+}
+
+/**
+ * Handles the "Go->Position History" menu command.
+ * Ensures that the query window is visible, and selects the active history
+ * page.
+ */
+void KScope::slotHistoryShow()
+{
+ toggleQueryWindow(true);
+ m_pQueryWidget->selectActiveHistory();
+}
+
+/**
+ * Handles the "File->New" menu command.
+ * Creates an editor page for a new unnamed file.
+ */
+void KScope::slotNewFile()
+{
+ EditorPage* pPage;
+
+ // Create the new editor page
+ pPage = createEditorPage();
+
+ // Mark the page as containing a new file
+ pPage->setNewFile();
+}
+
+/**
+ * Handles the "File->Open" menu command.
+ * Prompts the user for a file name, and opens it in a new editor page.
+ */
+void KScope::slotOpenFile()
+{
+ ProjectBase* pProj;
+ QStringList slFiles;
+ QStringList::Iterator itr;
+
+ // Prompt the user for the file(s) to open.
+ pProj = m_pProjMgr->curProject();
+ slFiles = KFileDialog::getOpenFileNames(pProj ? pProj->getSourceRoot() :
+ QString::null);
+
+ // Open all selected files.
+ for (itr = slFiles.begin(); itr != slFiles.end(); ++itr) {
+ if (!(*itr).isEmpty())
+ slotShowEditor(*itr, 0);
+ }
+}
+
+/**
+ * Handles the "File->Close" menu command.
+ * Closes the currently active editor page.
+ */
+void KScope::slotCloseEditor()
+{
+ m_pEditTabs->removeCurrentPage();
+}
+
+/**
+ * Handles the "Window->Close All" menu command.
+ * Closes all open editor pages.
+ */
+void KScope::slotCloseAllWindows()
+{
+ m_bUpdateGUI = false;
+ m_pEditTabs->removeAllPages();
+ m_bUpdateGUI = true;
+}
+
+/**
+ * Displays error messages from a Cscope process.
+ * This slot is connected to the progress() signal emitted by the any
+ * Cscope process.
+ * @param sMsg The error message
+ */
+void KScope::slotCscopeError(const QString& sMsg)
+{
+ m_pMsgDlg->addText(sMsg);
+}
+
+/**
+ * Reports progress information from the Cscope process responsible for
+ * rebuilding the cross-reference database.
+ * This slot is connected to the progress() signal emitted by the builder
+ * process.
+ * Progress information is displayed in the status bar.
+ * @param nFiles The number of files scanned
+ * @param nTotal The total number of files in the project
+ */
+void KScope::slotBuildProgress(int nFiles, int nTotal)
+{
+ QString sMsg;
+
+ // Use the progress dialogue, if it exists (first time builds)
+ if (m_pProgressDlg) {
+ m_pProgressDlg->setValue((nFiles * 100) / nTotal);
+ return;
+ }
+
+ // Show progress information
+ sMsg = i18n("Rebuilding the cross reference database...") + " " +
+ QString::number((nFiles * 100) / nTotal) + "%";
+ statusBar()->message(sMsg);
+}
+
+/**
+ * Reports to the user that Cscope has started building the inverted index.
+ * This slot is connected to the buildInvIndex() signal emitted by the
+ * builder process.
+ */
+void KScope::slotBuildInvIndex()
+{
+ if (m_pProgressDlg) {
+ m_pProgressDlg->setLabel(i18n("Please wait while KScope builds the "
+ "inverted index"));
+ m_pProgressDlg->setIdle();
+ return;
+ }
+
+ statusBar()->message(i18n("Rebuilding inverted index..."));
+}
+
+/**
+ * Informs the user the database rebuild process has finished.
+ * This slot is connected to the finished() signal emitted by the builder
+ * process.
+ */
+void KScope::slotBuildFinished(uint)
+{
+ // Delete the progress dialogue, if it exists (first time builds)
+ if (m_pProgressDlg) {
+ delete m_pProgressDlg;
+ m_pProgressDlg = NULL;
+ return;
+ }
+
+ // Show a message in the status bar
+ statusBar()->message(i18n("Rebuilding the cross reference database..."
+ "Done!"), 3000);
+}
+
+/**
+ * Called if the build process failed to complete.
+ * This slot is connected to the aborted() signal emitted by the builder
+ * process.
+ */
+void KScope::slotBuildAborted()
+{
+ // Delete the progress dialogue, if it exists (first time builds)
+ if (m_pProgressDlg) {
+ delete m_pProgressDlg;
+ m_pProgressDlg = NULL;
+
+ // Display a failure message
+ KMessageBox::error(0, i18n("The database could not be built.\n"
+ "Cross-reference information will not be available for this "
+ "project.\n"
+ "Please ensure that the Cscope parameters were correctly "
+ "entered in the \"Settings\" dialogue."));
+ return;
+ }
+
+ // Show a message in the status bar
+ statusBar()->message(i18n("Rebuilding the cross reference database..."
+ "Failed"), 3000);
+}
+
+/**
+ * Applies the selected user preferences once the "Apply" or "OK" buttons in
+ * the preferences dialog is clicked.
+ */
+void KScope::slotApplyPref()
+{
+ m_pQueryWidget->applyPrefs();
+ m_pFileList->applyPrefs();
+ m_pEditTabs->applyPrefs();
+ m_pEditMgr->applyPrefs();
+
+ // Enable/disable the external editor menu item
+ m_pActions->enableExtEditor(Config().useExtEditor());
+}
+
+/**
+ * Displays the current cursor position, whenever it is moved by the user.
+ * This slot is connected to the cursorPosChanged() signal emitted by an
+ * EditorPage object.
+ * @param nLine The new line number
+ * @param nCol The new column number
+ */
+void KScope::slotShowCursorPos(uint nLine, uint nCol)
+{
+ KStatusBar* pStatus = statusBar();
+ QString sText;
+
+ /* Show the line and column numbers. */
+ QTextOStream(&sText) << " Line: " << nLine << " Col: " << nCol << " ";
+ pStatus->changeItem(sText, 0);
+
+ /* Store the current line. */
+ m_nCurLine = nLine;
+}
+
+/**
+ * Stores the path of a newly opened file.
+ * This slot is connected to the fileOpened() signal emitted by an
+ * EditorPage object.
+ * @param sFilePath The full path of the opened file
+ */
+void KScope::slotFileOpened(EditorPage*, const QString& sFilePath)
+{
+ m_sCurFilePath = sFilePath;
+ setCaption(m_pProjMgr->getProjName() + " - " + m_sCurFilePath);
+}
+
+/**
+ * Sets a timer for rebuilding the database after a file has been saved.
+ * This slot is connected to the fileSaved() signal emitted by an EditorPage
+ * object.
+ * The time period before rebuilding is determined on a per-project basis.
+ * @param sPath The full path of the modified file that caused this event
+ * @param bIsNew true if this is a new file, false otherwise
+ */
+void KScope::slotFileSaved(const QString& sPath, bool bIsNew)
+{
+ ProjectBase* pProj;
+ int nTime;
+
+ pProj = m_pProjMgr->curProject();
+ if (!pProj)
+ return;
+
+ // Prompt the user to add this file to the current project
+ if (bIsNew && !pProj->isTemporary()) {
+ if (KMessageBox::questionYesNo(0,
+ i18n("Whould you like to add this file to the active project?")) ==
+ KMessageBox::Yes) {
+
+ // Add the path to the 'cscope.files' file
+ if (!((Project*)pProj)->addFile(sPath)) {
+ KMessageBox::error(0, i18n("Failed to write the file list."));
+ return;
+ }
+
+ // Add the path to the file list widget
+ m_pFileList->addItem(sPath);
+
+ // Rebuild immediately
+ slotRebuildDB();
+ return;
+ }
+ }
+
+ // Get the project's auto-rebuild time
+ nTime = pProj->getAutoRebuildTime();
+
+ // Do nothing if the time is set to -1
+ if (nTime == -1)
+ return;
+
+ // Check if the file is included in the project (external files should
+ // not trigger the timer)
+ if (!m_pFileList->findFile(sPath))
+ return;
+
+ // Rebuild immediately for a time set to 0
+ if (nTime == 0) {
+ slotRebuildDB();
+ return;
+ }
+
+ // Reset the rebuild timer
+ m_timerRebuild.start(nTime * 1000, true);
+}
+
+/**
+ * Handles file drops inside the editors tab widget.
+ * Opens all files dropped over the widget.
+ * @param pEvent Pointer to an object containing the list of dropped files
+ */
+void KScope::slotDropEvent(QDropEvent* pEvent)
+{
+ KURL::List list;
+ KURL::List::Iterator itr;
+
+ // Create a list of file URLs
+ if (!KURLDrag::decode(pEvent, list))
+ return;
+
+ // Open all files in the list
+ for (itr = list.begin(); itr != list.end(); ++itr)
+ addEditor((*itr).path());
+}
+
+#include "kscope.moc"
diff --git a/src/kscope.desktop b/src/kscope.desktop
new file mode 100644
index 0000000..453a4fc
--- /dev/null
+++ b/src/kscope.desktop
@@ -0,0 +1,12 @@
+[Desktop Entry]
+Encoding=UTF-8
+Name=KScope
+Exec=kscope
+Icon=kscope
+Type=Application
+Comment=Source-editing environment for large C projects
+Comment[fr]=Editeur de codes sources pour de gros projets en C
+GenericName=Source editing environment
+GenericName[fr]=Editeur de code source
+Categories=Qt;KDE;Development
+
diff --git a/src/kscope.h b/src/kscope.h
new file mode 100644
index 0000000..f1b646e
--- /dev/null
+++ b/src/kscope.h
@@ -0,0 +1,235 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef KSCOPE_H
+#define KSCOPE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qtimer.h>
+#include <kcmdlineargs.h>
+#include <kapp.h>
+#include <kparts/dockmainwindow.h>
+#include <kparts/part.h>
+
+class ProjectManager;
+class EditorTabs;
+class FileView;
+class FileList;
+class QueryWidget;
+class EditorManager;
+class CscopeFrontend;
+class EditorPage;
+class ProgressDlg;
+class CscopeMsgDlg;
+class MakeDlg;
+class CallTreeManager;
+class KScopeActions;
+
+/**
+ * Defines the main window of KScope.
+ * The main window has both UI and functional tasks. As a window, it is
+ * composed of three parts:
+ * 1. The editing area (EditorTabs - a tab widget with editor pages)
+ * 2. The project pane (FileList - listing the files in the project)
+ * 3. The query pane (QueryWidget - a tab widget with pages displaying query
+ * results in lists)
+ * The main window also maintains the main menu, the toolbar and the status-
+ * bar, and is responsible for handling all the actions connected to these
+ * bars.
+ * As the application's main class, it is responsible for managing projects
+ * (using a ProjectManager object) and for running instances of Cscope
+ * (through a CscopeFrontend object).
+ * @author Elad Lahav
+ */
+class KScope : public KParts::DockMainWindow
+{
+ Q_OBJECT
+
+public:
+ KScope(QWidget* pParent = 0, const char* szName = 0);
+ ~KScope();
+
+ void openProject(const QString&);
+ void openLastProject();
+ bool openCscopeOut(const QString&);
+ void parseCmdLine(KCmdLineArgs *pArgs);
+ void verifyCscope();
+
+public slots:
+ void slotClose();
+
+protected:
+ virtual bool queryClose();
+
+private:
+ /** A project manager used to load projects and read their properties. */
+ ProjectManager* m_pProjMgr;
+
+ /** The editors tabbed window. */
+ EditorTabs* m_pEditTabs;
+
+ /** The file selection widget (project file list and OS file system
+ tree.) */
+ FileView* m_pFileView;
+
+ /** Pointer to the file list part of the FileView widget. */
+ FileList* m_pFileList;
+
+ /** The query results tabbed window. */
+ QueryWidget* m_pQueryWidget;
+
+ /** A KDE editor part manager, responsible for creating KTextEditor
+ parts. */
+ EditorManager* m_pEditMgr;
+
+ /** A Cscope process for building the database. */
+ CscopeFrontend* m_pCscopeBuild;
+
+ /** A timer for rebuilding the database after a file has been saved. */
+ QTimer m_timerRebuild;
+
+ /** Whether the query window should be hidden after the user selects an
+ item. */
+ bool m_bHideQueryOnSelection;
+
+ /** The file view docking area. */
+ KDockWidget* m_pFileViewDock;
+
+ /** The query window docking area. */
+ KDockWidget* m_pQueryDock;
+
+ /** A persistent dialog used to display error messages from Cscope. */
+ CscopeMsgDlg* m_pMsgDlg;
+
+ /** The path of the file currently being edited. */
+ QString m_sCurFilePath;
+
+ /** The line number of the current cursor position. */
+ int m_nCurLine;
+
+ /** Creates and maintains call tree dialogues. */
+ CallTreeManager* m_pCallTreeMgr;
+
+ /** A progress dialogue that is displayed when building the database for
+ the first time. */
+ ProgressDlg* m_pProgressDlg;
+
+ /** A flag indicating whether the GUI of the embedded editor should be
+ merged with that of KScope's. Can be turned off to save time when
+ loading/closing a number of editor parts. */
+ bool m_bUpdateGUI;
+
+ /** Set to true after a shell script has verified that Cscope is installed
+ and correctly configured on this system.
+ No Cscope operations should be run if this flag is set to false. */
+ bool m_bCscopeVerified;
+
+ /**
+ * Used to postpone rebuilding of the database, until Cscope is ready.
+ */
+ bool m_bRebuildDB;
+
+ /**
+ * A widget for running make.
+ */
+ MakeDlg* m_pMakeDlg;
+
+ /**
+ * Manages menu and tool-bar commands.
+ */
+ KScopeActions* m_pActions;
+
+ void initMainWindow();
+ void initCscope();
+ bool getSymbol(uint&, QString&, bool&, bool bPrompt = true);
+ EditorPage* addEditor(const QString&s);
+ EditorPage* createEditorPage();
+ inline bool isAutoRebuildEnabled();
+ void restoreSession();
+ void toggleQueryWindow(bool);
+
+ friend class KScopeActions;
+
+private slots:
+ // Menu actions
+ void slotNewFile();
+ void slotOpenFile();
+ void slotCloseEditor();
+ void slotCreateProject();
+ void slotOpenProject();
+ void slotProjectFiles();
+ void slotProjectProps();
+ void slotProjectCscopeOut();
+ bool slotCloseProject();
+ void slotQueryReference();
+ void slotQueryDefinition();
+ void slotQueryCalled();
+ void slotQueryCalling();
+ void slotQueryText();
+ void slotQueryPattern();
+ void slotQueryFile();
+ void slotQueryIncluding();
+ void slotQueryQuickDef();
+ void slotCallTree();
+ void slotRebuildDB();
+ void slotHistoryShow();
+ void slotShortcuts();
+ void slotConfigure();
+ void slotCloseAllWindows();
+ void slotExtEdit();
+ void slotCompleteSymbol();
+ void slotShowWelcome();
+ void slotGotoTag();
+ void slotProjectMake();
+ void slotProjectRemake();
+ void slotShowBookmarks();
+
+ // Other slots
+ void slotProjectFilesChanged();
+ void slotFilesAdded(const QStringList&);
+ void slotQuery(uint, bool);
+ void slotDeleteEditor(EditorPage*);
+ void slotChangeEditor(EditorPage*, EditorPage*);
+ void slotShowEditor(const QString&, uint);
+ void slotFileOpened(EditorPage*, const QString&);
+ void slotFileSaved(const QString&, bool);
+ void slotCscopeError(const QString&);
+ void slotBuildProgress(int, int);
+ void slotBuildInvIndex();
+ void slotBuildFinished(uint);
+ void slotBuildAborted();
+ void slotApplyPref();
+ void slotShowCursorPos(uint, uint);
+ void slotQueryShowEditor(const QString&, uint);
+ void slotDropEvent(QDropEvent*);
+ void slotCscopeVerified(bool, uint);
+};
+
+#endif
diff --git a/src/kscope.lsm b/src/kscope.lsm
new file mode 100644
index 0000000..1062526
--- /dev/null
+++ b/src/kscope.lsm
@@ -0,0 +1,16 @@
+Begin4
+Title: KScope
+Version: 1.4.0
+Entered-date: ?
+Description: A source-editing environment for KDE bsaed on Cscope
+Keywords: KDE Cscope Source Browser Editor IDE C
+Author: elad_lahav@users.sourceforge.net (Elad Lahav)
+Maintained-by: elad_lahav@users.sourceforge.net (Elad Lahav)
+Home-page: http://kscope.sourceforge.net
+Alternate-site:
+Primary-site: http://download.sourceforge.net/kscope/
+ ?M kscope-1.4.0.tar.gz
+ ? kscope-1.4.0.lsm
+Platform: Linux/Unix. Requires KDE.
+Copying-policy: BSD
+End
diff --git a/src/kscope_config b/src/kscope_config
new file mode 100644
index 0000000..25fad0f
--- /dev/null
+++ b/src/kscope_config
@@ -0,0 +1,165 @@
+# Configures KScope parameters
+
+# Checks that the given executable is indeed a Cscope-compatible application
+# and determines which options it supports.
+verifyCscope()
+{
+ CSCOPE_EXE=`basename $CSCOPE_PATH`
+
+ if [ $DEBUG ]
+ then
+ echo -n Checking $CSCOPE_EXE version...
+ fi
+
+ # Get the executable's version
+ CSCOPE_VER_MAJOR=`$CSCOPE_PATH -V 2>&1 | grep -i $CSCOPE_EXE | sed -e "s/.*version \([1-9][0-9]*\)\.\([0-9]\).*/\1/"`
+ CSCOPE_VER_MINOR=`$CSCOPE_PATH -V 2>&1 | grep -i $CSCOPE_EXE | sed -e "s/.*version \([1-9][0-9]*\)\.\([0-9]\).*/\2/"`
+
+ if [ -n "$CSCOPE_VER_MAJOR" -a "$CSCOPE_VER_MINOR" ]
+ then
+ echo $CSCOPE_VER_MAJOR.$CSCOPE_VER_MINOR
+
+ if [ $DEBUG ]
+ then
+ echo -n Cscope support for line mode verbose output...
+ fi
+
+ # Check for verbose output
+ if [ "`$CSCOPE_PATH -h 2>&1 | grep "\-v"`" ]
+ then
+ CSCOPE_VERBOSE=Yes
+ else
+ CSCOPE_VERBOSE=No
+ fi
+ echo $CSCOPE_VERBOSE
+
+ if [ $DEBUG ]
+ then
+ echo -n Cscope support slow path definitions...
+ fi
+
+ # Check for slow-path definitions
+ if [ "`$CSCOPE_PATH -h 2>&1 | grep "\-D"`" ]
+ then
+ CSCOPE_SLOWPATH=Yes
+ else
+ CSCOPE_SLOWPATH=No
+ fi
+ echo $CSCOPE_SLOWPATH
+ else
+ echo ERROR
+ if [ $DEBUG ]
+ then
+ echo -e "\n *** ERROR *** The \"cscope\" executable does not appear to be a Cscope compatible programme"
+ fi
+ fi
+}
+
+DEBUG=0
+CSCOPE_OPTIONS_ONLY=
+
+# Parse command-line parameters
+# Supported options:
+# -d: Debug mode
+# -co: Check Cscope options only
+for opt in $@
+do
+ case "$opt" in
+ "-d") DEBUG=1
+ ;;
+ "-co") CSCOPE_OPTIONS_ONLY=1
+ ;;
+ esac
+done
+
+if [ $DEBUG ]
+then
+ echo -n Looking for cscope...
+fi
+
+if [ -z "$CSCOPE_PATH" ]
+then
+ CSCOPE_PATH=`which cscope`
+fi
+
+if [ -n "$CSCOPE_PATH" -a -x "$CSCOPE_PATH" ]
+then
+ echo $CSCOPE_PATH
+ verifyCscope
+else
+ echo ERROR
+ if [ $DEBUG ]
+ then
+ echo -e "\n *** ERROR *** No Cscope executable found"
+ fi
+fi
+
+if [ -n "$CSCOPE_OPTIONS_ONLY" ]
+then
+ exit
+fi
+
+if [ $DEBUG ]
+then
+ echo -n Looking for Ctags...
+fi
+
+if [ -z "$CTAGS_PATH" ]
+then
+ for CTAGS_NAME in exctags ctags-exuberant exuberant-ctags ctags
+ do
+ CTAGS_PATH=`which $CTAGS_NAME`
+ if [ -n "$CTAGS_PATH" -a -x "$CTAGS_PATH" ]
+ then
+ break
+ fi
+ done
+fi
+
+if [ -n "$CTAGS_PATH" ]
+then
+ echo $CTAGS_PATH
+
+ # echo -n Checking for Exuberant-Ctags compatibility...
+
+ CTAGS_EXUB=`$CTAGS_PATH --help | grep -c "\-\-excmd=number"`
+ if [ $CTAGS_EXUB -gt 0 ]
+ then
+ CTAGS_EXUB_PATH=$CTAGS_PATH
+ echo Yes
+ else
+ echo ERROR
+ # echo -e "\n *** ERROR *** The \"ctags\" executable does not appear to be compatible with Exuberant Ctags"
+ fi
+
+else
+ echo ERROR
+ # echo -e "\n *** ERROR *** No Ctags executable found"
+fi
+
+# echo -n Looking for Dot...
+
+if [ -z "$DOT_PATH" ]
+then
+ DOT_PATH=`which dot`
+fi
+
+if [ -n "$DOT_PATH" -a -x "$DOT_PATH" ]
+then
+ echo $DOT_PATH
+
+ # echo -n Checking if dot handles the -Tplain option...
+
+ echo "digraph G {Hello->World}" | $DOT_PATH -Tplain 2>&1 /dev/null
+ if [ $? -eq 0 ]
+ then
+ echo Yes
+ else
+ echo ERROR
+ # echo -e "\n *** ERROR *** The \"dot\" executable does not support -Tplain"
+ fi
+
+else
+ echo ERROR
+ # echo -e "\n *** ERROR *** No Dot executable found"
+fi
diff --git a/src/kscopeactions.cpp b/src/kscopeactions.cpp
new file mode 100644
index 0000000..d5c64fc
--- /dev/null
+++ b/src/kscopeactions.cpp
@@ -0,0 +1,533 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2007 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, m_pWindow list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, m_pWindow list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <klocale.h>
+#include "kscope.h"
+#include "kscopeactions.h"
+#include "kscopeconfig.h"
+#include "filelist.h"
+#include "editortabs.h"
+#include "querywidget.h"
+
+KScopeActions::KScopeActions(KScope* pWindow) : QObject(),
+ m_pWindow(pWindow),
+ m_pCollection(pWindow->actionCollection())
+{
+}
+
+KScopeActions::~KScopeActions()
+{
+}
+
+/**
+ * Connects menu bar and toolbar commands with class members. These members
+ * handle the actions associated with each command.
+ */
+void KScopeActions::init()
+{
+ // File menu
+ KStdAction::openNew(m_pWindow, SLOT(slotNewFile()), m_pCollection);
+ KStdAction::open(m_pWindow, SLOT(slotOpenFile()), m_pCollection);
+ KStdAction::close(m_pWindow, SLOT(slotCloseEditor()), m_pCollection);
+ KStdAction::quit(m_pWindow, SLOT(slotClose()), m_pCollection);
+
+ addAction(i18n("Go to File List"),
+ NULL,
+ "Ctrl+Shift+O",
+ m_pWindow->m_pFileList,
+ SLOT(slotSetFocus()),
+ "file_open_file_from_list",
+ SIGNAL(toggleProject(bool)));
+
+ addAction(i18n("Save Al&l"),
+ "save_all",
+ "Ctrl+L",
+ m_pWindow->m_pEditTabs,
+ SLOT(slotSaveAll()),
+ "file_save_all",
+ NULL);
+
+ // Edit menu
+ m_pExtEditAction = addAction(i18n("Edit in E&xternal Editor"),
+ NULL,
+ "Ctrl+E",
+ m_pWindow,
+ SLOT(slotExtEdit()),
+ "edit_external_editor",
+ SIGNAL(toggleFile(bool)));
+
+ addAction(i18n("Go To Tag"),
+ NULL,
+ "Ctrl+Shift+T",
+ m_pWindow,
+ SLOT(slotGotoTag()),
+ "edit_goto_tag",
+ SIGNAL(toggleFile(bool)));
+
+ addAction(i18n("Complete Symbol"),
+ NULL,
+ "Ctrl+Space",
+ m_pWindow,
+ SLOT(slotCompleteSymbol()),
+ "edit_comp_symbol",
+ SIGNAL(toggleFile(bool)));
+
+ // Project menu
+ addAction(i18n("&New Project..."),
+ NULL,
+ NULL,
+ m_pWindow,
+ SLOT(slotCreateProject()),
+ "project_new",
+ NULL);
+
+ addAction(i18n("&Open Project..."),
+ "project_open",
+ NULL,
+ m_pWindow,
+ SLOT(slotOpenProject()),
+ "project_open",
+ NULL);
+
+ addAction(i18n("Open &Cscope.out..."),
+ NULL,
+ NULL,
+ m_pWindow,
+ SLOT(slotProjectCscopeOut()),
+ "project_cscope_out",
+ NULL);
+
+ addAction(i18n("Add/Remove &Files..."),
+ NULL,
+ NULL,
+ m_pWindow,
+ SLOT(slotProjectFiles()),
+ "project_add_rem_files",
+ SIGNAL(toggleProject(bool)));
+
+ addAction(i18n("&Properties..."),
+ NULL,
+ NULL,
+ m_pWindow,
+ SLOT(slotProjectProps()),
+ "project_properties",
+ SIGNAL(toggleProject(bool)));
+
+ addAction(i18n("&Make Project"),
+ "make_kdevelop",
+ "Ctrl+M",
+ m_pWindow,
+ SLOT(slotProjectMake()),
+ "project_make",
+ SIGNAL(toggleProject(bool)));
+
+ addAction(i18n("&Remake Project"),
+ "rebuild",
+ "Ctrl+Shift+M",
+ m_pWindow,
+ SLOT(slotProjectRemake()),
+ "project_remake",
+ SIGNAL(toggleProject(bool)));
+
+ addAction(i18n("&Close Project"),
+ "fileclose",
+ NULL,
+ m_pWindow,
+ SLOT(slotCloseProject()),
+ "project_close",
+ SIGNAL(toggleProject(bool)));
+
+ // Cscope menu
+ addAction(i18n("&References..."),
+ NULL,
+ "Ctrl+0",
+ m_pWindow,
+ SLOT(slotQueryReference()),
+ "cscope_references",
+ SIGNAL(toggleProject(bool)));
+
+ addAction(i18n("&Definition..."),
+ NULL,
+ "Ctrl+1",
+ m_pWindow,
+ SLOT(slotQueryDefinition()),
+ "cscope_definition",
+ SIGNAL(toggleProject(bool)));
+
+ addAction(i18n("&Called Functions..."),
+ NULL,
+ "Ctrl+2",
+ m_pWindow,
+ SLOT(slotQueryCalled()),
+ "cscope_called",
+ SIGNAL(toggleProject(bool)));
+
+ addAction(i18n("C&alling Functions..."),
+ NULL,
+ "Ctrl+3",
+ m_pWindow,
+ SLOT(slotQueryCalling()),
+ "cscope_calling",
+ SIGNAL(toggleProject(bool)));
+
+ addAction(i18n("Find &Text..."),
+ NULL,
+ "Ctrl+4",
+ m_pWindow,
+ SLOT(slotQueryText()),
+ "cscope_text",
+ SIGNAL(toggleProject(bool)));
+
+ addAction(i18n("Find &EGrep Pattern..."),
+ NULL,
+ "Ctrl+5",
+ m_pWindow,
+ SLOT(slotQueryPattern()),
+ "cscope_pattern",
+ SIGNAL(toggleProject(bool)));
+
+ addAction(i18n("Find &File..."),
+ NULL,
+ "Ctrl+7",
+ m_pWindow,
+ SLOT(slotQueryFile()),
+ "cscope_file",
+ SIGNAL(toggleProject(bool)));
+
+ addAction(i18n("&Including Files..."),
+ NULL,
+ "Ctrl+8",
+ m_pWindow,
+ SLOT(slotQueryIncluding()),
+ "cscope_including",
+ SIGNAL(toggleProject(bool)));
+
+ addAction(i18n("&Quick Definition"),
+ NULL,
+ "Ctrl+]",
+ m_pWindow,
+ SLOT(slotQueryQuickDef()),
+ "cscope_quick_def",
+ SIGNAL(toggleProject(bool)));
+
+ addAction(i18n("Call &Graph..."),
+ NULL,
+ "Ctrl+\\",
+ m_pWindow,
+ SLOT(slotCallTree()),
+ "cscope_call_tree",
+ SIGNAL(toggleProject(bool)));
+
+ addAction(i18n("Re&build database"),
+ "vcs_update",
+ NULL,
+ m_pWindow,
+ SLOT(slotRebuildDB()),
+ "cscope_rebuild",
+ SIGNAL(toggleProject(bool)));
+
+ // Go menu
+ addAction(i18n("P&revious Result"),
+ "up",
+ "Alt+Up",
+ m_pWindow->m_pQueryWidget,
+ SLOT(slotPrevResult()),
+ "go_prev_result",
+ SIGNAL(toggleProject(bool)));
+
+ addAction(i18n("N&ext Result"),
+ "down",
+ "Alt+Down",
+ m_pWindow->m_pQueryWidget,
+ SLOT(slotNextResult()),
+ "go_next_result",
+ SIGNAL(toggleProject(bool)));
+
+ addAction(i18n("&Previous Position"),
+ "back",
+ "Alt+Left",
+ m_pWindow->m_pQueryWidget,
+ SLOT(slotHistoryPrev()),
+ "go_prev_pos",
+ NULL);
+
+ addAction(i18n("&Next Position"),
+ "forward",
+ "Alt+Right",
+ m_pWindow->m_pQueryWidget,
+ SLOT(slotHistoryNext()),
+ "go_next_pos",
+ NULL);
+
+ addAction(i18n("Position &History"),
+ "history",
+ "Ctrl+h",
+ m_pWindow,
+ SLOT(slotHistoryShow()),
+ "go_history",
+ NULL);
+
+ addAction(i18n("Global &Bookmarks"),
+ "bookmark",
+ "Ctrl+Shift+G",
+ m_pWindow,
+ SLOT(slotShowBookmarks()),
+ "go_bookmarks",
+ NULL);
+
+ // View menu
+ m_pToggleFileViewAction = addToggle(i18n("Toggle File List"),
+ "view_sidetree",
+ "Ctrl+/",
+ m_pWindow->m_pFileViewDock,
+ SLOT(changeHideShowState()),
+ "view_toggle_filelist_dock",
+ NULL);
+
+ m_pToggleQueryWindowAction = addToggle(i18n("Toggle Query Window"),
+ "view_top_bottom",
+ "Ctrl+.",
+ m_pWindow->m_pQueryDock,
+ SLOT(changeHideShowState()),
+ "view_toggle_query_dock",
+ NULL);
+
+ m_pToggleTagListAction = addToggle(i18n("Toggle Tag List"),
+ "view_detailed",
+ "Ctrl+'",
+ m_pWindow->m_pEditTabs,
+ SLOT(slotToggleTagList()),
+ "view_toggle_tag_list",
+ NULL);
+
+ // Window menu
+ addAction(i18n("Close &All"),
+ "fileclose",
+ NULL,
+ m_pWindow,
+ SLOT(slotCloseAllWindows()),
+ "window_close_all",
+ NULL);
+
+ addAction(i18n("Go &Left"),
+ "back",
+ "Alt+Shift+Left",
+ m_pWindow->m_pEditTabs,
+ SLOT(slotGoLeft()),
+ "window_go_left",
+ NULL);
+
+ addAction(i18n("Go &Right"),
+ "forward",
+ "Alt+Shift+Right",
+ m_pWindow->m_pEditTabs,
+ SLOT(slotGoRight()),
+ "window_go_right",
+ NULL);
+
+ // Settings menu
+ KStdAction::preferences(m_pWindow, SLOT(slotConfigure()), m_pCollection);
+ KStdAction::keyBindings(m_pWindow, SLOT(slotShortcuts()), m_pCollection);
+
+ // Help menu
+ addAction(i18n("Show &Welcome Message..."),
+ NULL,
+ NULL,
+ m_pWindow,
+ SLOT(slotShowWelcome()),
+ "help_welcome",
+ NULL);
+
+ // Query widget popup menu
+ addAction(i18n("&New"),
+ "filenew",
+ NULL,
+ m_pWindow->m_pQueryWidget,
+ SLOT(slotNewQueryPage()),
+ "query_new",
+ SIGNAL(toggleProject(bool)));
+
+ addAction(i18n("&Refresh"),
+ "reload",
+ NULL,
+ m_pWindow->m_pQueryWidget,
+ SLOT(slotRefreshCurrent()),
+ "query_refresh",
+ SIGNAL(toggleProject(bool)));
+
+ m_pLockAction = addToggle(i18n("&Lock/Unlock"),
+ "encrypted",
+ NULL,
+ m_pWindow->m_pQueryWidget,
+ SLOT(slotLockCurrent()),
+ "query_toggle_locked",
+ SIGNAL(toggleProject(bool)));
+
+ addAction(i18n("&Close"),
+ "fileclose",
+ NULL,
+ m_pWindow->m_pQueryWidget,
+ SLOT(slotCloseCurrent()),
+ "query_close",
+ SIGNAL(toggleProject(bool)));
+
+ m_pExtEditAction->setEnabled(Config().useExtEditor());
+}
+
+void KScopeActions::initLayoutActions()
+{
+ m_pToggleFileViewAction->setChecked(m_pWindow->m_pFileViewDock->isShown());
+ m_pToggleQueryWindowAction->setChecked(m_pWindow->m_pQueryDock->isShown());
+ m_pToggleTagListAction->setChecked(Config().getShowTagList());
+}
+
+/**
+ * Enables/disables the "Edit in External Editor" command.
+ * @param bEnable true to enable the command, false to disable it
+ */
+void KScopeActions::enableExtEditor(bool bEnable)
+{
+ m_pExtEditAction->setEnabled(bEnable);
+}
+
+void KScopeActions::slotQueryDockToggled(bool bVisible)
+{
+ m_pToggleQueryWindowAction->setChecked(bVisible);
+}
+
+/**
+ * Ensures the "Show/Hide Query Window" action is unchecked when the dock
+ * is closed through its close button.
+ * This slot is conncted to the headerCloseButtonClicked() signal of the
+ * query window dock widget.
+ */
+void KScopeActions::slotQueryDockClosed()
+{
+ m_pToggleQueryWindowAction->setChecked(false);
+}
+
+/**
+ * Ensures the "Show/Hide File View" action is unchecked when the dock
+ * is closed through its close button.
+ * This slot is conncted to the headerCloseButtonClicked() signal of the
+ * file view dock widget.
+ */
+void KScopeActions::slotFileViewDockClosed()
+{
+ m_pToggleFileViewAction->setChecked(false);
+}
+
+/**
+ * Enables/disables all actions related to open projects.
+ * This slot should be called whenever a project is opened or closed.
+ * @param bEnable true to enable actions, false to disable
+ */
+void KScopeActions::slotEnableProjectActions(bool bEnable)
+{
+ emit toggleProject(bEnable);
+}
+
+/**
+ * Enables/disables all actions related to open files.
+ * This slot should be called the first file is opened, or when the last one
+ * is closed.
+ * @param bEnable true to enable actions, false to disable
+ */
+void KScopeActions::slotEnableFileActions(bool bEnable)
+{
+ emit toggleFile(bEnable);
+}
+
+/**
+ * Creates a new action.
+ * @param sCaption The text to display in the menu item
+ * @param szIcon Optional icon associated with the action
+ * @param szShortcut Optional key-combination string
+ * @param pReceiver The widget to receive the action's signal
+ * @param szSlot The widget's slot that connect to the signal
+ * @param szName The XML entry corresponding to the action
+ * @param szSignal Optional signal to connect to the setEnabled() slot of
+ * the action
+ * @return The newly created action object
+ */
+KAction* KScopeActions::addAction(const QString& sCaption, const char* szIcon,
+ const char* szShortcut, QWidget* pReceiver, const char* szSlot,
+ const char* szName, const char* szSignal)
+{
+ KAction* pAction;
+
+ // Create the action
+ pAction = new KAction(sCaption,
+ szIcon,
+ szShortcut == NULL ? KShortcut() : KShortcut(szShortcut),
+ pReceiver,
+ szSlot,
+ m_pCollection,
+ szName);
+
+ // Add to the given action list, if any
+ if (szSignal)
+ connect(this, szSignal, pAction, SLOT(setEnabled(bool)));
+
+ return pAction;
+}
+
+/**
+ * Creates a new toggle action.
+ * @param sCaption The text to display in the menu item
+ * @param szIcon Optional icon associated with the action
+ * @param szShortcut Optional key-combination string
+ * @param pReceiver The widget to receive the action's signal
+ * @param szSlot The widget's slot that connect to the signal
+ * @param szName The XML entry corresponding to the action
+ * @param szSignal Optional signal to connect to the setEnabled() slot of
+ * the action
+ * @return The newly created action object
+ */
+KToggleAction* KScopeActions::addToggle(const QString& sCaption,
+ const char* szIcon, const char* szShortcut, QWidget* pReceiver,
+ const char* szSlot, const char* szName, const char* szSignal)
+{
+ KToggleAction* pAction;
+
+ // Create the action
+ pAction = new KToggleAction(sCaption,
+ szIcon,
+ szShortcut == NULL ? KShortcut() : KShortcut(szShortcut),
+ pReceiver,
+ szSlot,
+ m_pCollection,
+ szName);
+
+ // Add to the given action list, if any
+ if (szSignal)
+ connect(this, szSignal, pAction, SLOT(setEnabled(bool)));
+
+ return pAction;
+}
+
+#include "kscopeactions.moc"
diff --git a/src/kscopeactions.h b/src/kscopeactions.h
new file mode 100644
index 0000000..4836310
--- /dev/null
+++ b/src/kscopeactions.h
@@ -0,0 +1,98 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2007 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef KSCOPEACTIONS_H
+#define KSCOPEACTIONS_H
+
+#include <kaction.h>
+
+class KScope;
+
+typedef QPtrList<KAction> ActionList;
+
+/**
+ * A helper class for managing KScope's menu commands.
+ * @author Elad Lahav
+ */
+class KScopeActions : public QObject
+{
+ Q_OBJECT
+
+public:
+ KScopeActions(KScope*);
+ ~KScopeActions();
+
+ void init();
+ void initPopups();
+ void initLayoutActions();
+ void enableExtEditor(bool);
+
+ KToggleAction* getLockAction() { return m_pLockAction; }
+
+public slots:
+ void slotQueryDockToggled(bool);
+ void slotQueryDockClosed();
+ void slotFileViewDockClosed();
+ void slotEnableProjectActions(bool);
+ void slotEnableFileActions(bool);
+
+signals:
+ void toggleProject(bool bEnable);
+ void toggleFile(bool bEnable);
+
+private:
+ KScope* m_pWindow;
+ KActionCollection* m_pCollection;
+
+ /** A list of actions that require an active project. */
+ ActionList m_lstProjActions;
+
+ /** A list of actions that require an active file. */
+ ActionList m_lstFileActions;
+
+ /** A toggle menu item for locking/unlocking query pages. */
+ KToggleAction* m_pLockAction;
+
+ /** The "Edit in External Editor" menu command. */
+ KAction* m_pExtEditAction;
+
+ /** The "Show/Hide File View" menu command. */
+ KToggleAction* m_pToggleFileViewAction;
+
+ /** The "Show/Hide Query Window" menu command. */
+ KToggleAction* m_pToggleQueryWindowAction;
+
+ /** The "Show/Hide Tag List" menu command. */
+ KToggleAction* m_pToggleTagListAction;
+
+ KAction* addAction(const QString&, const char*, const char*, QWidget*,
+ const char*, const char*, const char*);
+ KToggleAction* addToggle(const QString&, const char*, const char*,
+ QWidget*, const char*, const char*, const char*);
+};
+
+#endif
diff --git a/src/kscopeconfig.cpp b/src/kscopeconfig.cpp
new file mode 100644
index 0000000..3cc5094
--- /dev/null
+++ b/src/kscopeconfig.cpp
@@ -0,0 +1,768 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <kconfig.h>
+#include <kapplication.h>
+#include <kglobalsettings.h>
+#include "kscopeconfig.h"
+
+// NOTE:
+// This configuration file entry controls whether the welcome dialogue is
+// displayed. Normally it only needs to be shown once, but the entry's name
+// can be changed across versions to force the display of new information.
+#define SHOW_WELCOME_ENTRY "ShowWelcomeDlg"
+
+/**
+ * Stores the display name and the configuration file entry for a configurable
+ * GUI element.
+ * @author Elad Lahav
+ */
+struct ElementInfo
+{
+ /** The display name of the element. */
+ const char* szName;
+
+ /** The configuration file entry. */
+ const char* szEntry;
+};
+
+/**
+ * A list of GUI elements for which the colour can be configured.
+ */
+const ElementInfo eiColors[] = {
+ { "File List (Foreground)", "FileListFore" },
+ { "File List (Background)", "FileListBack" },
+ { "Tag List (Foreground)", "TagListFore" },
+ { "Tag List (Background)", "TagListBack" },
+ { "Query Window (Foreground)", "QueryListFore" },
+ { "Query Window (Background)", "QueryListBack" },
+ { "Call Graph (Background)", "GraphBack" },
+ { "Call Graph (Nodes)", "GraphNode" },
+ { "Call Graph (Text)", "GraphText" },
+ { "Call Graph (Multi-Call Nodes)", "GraphMultiCall" }
+};
+
+/**
+ * A list of GUI elements for which the font can be configured.
+ */
+const ElementInfo eiFonts[] = {
+ { "File List", "FileList" },
+ { "Tag List", "TagList" },
+ { "Query Page", "QueryList" },
+ { "Call Graph", "Graph" }
+};
+
+#define COLOR_NAME(_i) eiColors[_i].szName
+#define COLOR_ENTRY(_i) eiColors[_i].szEntry
+#define FONT_NAME(_i) eiFonts[_i].szName
+#define FONT_ENTRY(_i) eiFonts[_i].szEntry
+
+KScopeConfig::ConfParams KScopeConfig::s_cpDef = {
+ "/usr/bin/cscope", // Cscope path
+ "/usr/bin/ctags", // Ctags path
+ "/usr/bin/dot", // Dot path
+ true, // Show the tag list
+ SPLIT_SIZES(), // Tag list width
+ {
+ QColor(black), // File list foreground
+ QColor(white), // File list background
+ QColor(black), // Tag list foreground
+ QColor(white), // Tag list background
+ QColor(black), // Query page foreground
+ QColor(white), // Query page background
+ QColor("#c0c0c0"), // Call graph background
+ QColor("#c0ff80"), // Call graph nodes
+ QColor(black), // Call graph text
+ QColor("#ff8000")
+ },
+ {
+ QFont(), // Font definitions are overriden in load()
+ QFont(),
+ QFont(),
+ QFont()
+ },
+ NameAsc, // Ctags sort order
+ false, // Read-only mode
+ true, // Load last project
+ true, // Automatic tag highlighting
+ false, // Brief query captions
+ true, // Warn when file is modified on the disk
+ true, // Sort files when a project is loaded
+ "kate --line %L %F", // External editor example
+ Fast, // System profile
+ Embedded, // Editor context menu
+ "TB", // Call graph orientation
+ 10, // Maximum calls per graph node
+ 0 // Default graph view
+};
+
+/**
+ * Class constructor.
+ */
+KScopeConfig::KScopeConfig() : m_bFontsChanged(false)
+{
+}
+
+/**
+ * Class destructor.
+ */
+KScopeConfig::~KScopeConfig()
+{
+}
+
+/**
+ * Reads KScope's parameters from the standard configuration file.
+ */
+void KScopeConfig::load()
+{
+ uint i;
+
+ KConfig* pConf = kapp->config();
+
+ // Need a working instance to get the system's default font (cannot be
+ // initialised statically)
+ s_cpDef.fonts[FileList] = KGlobalSettings::generalFont();
+ s_cpDef.fonts[TagList] = KGlobalSettings::generalFont();
+ s_cpDef.fonts[QueryWindow] = KGlobalSettings::generalFont();
+ s_cpDef.fonts[Graph] = KGlobalSettings::generalFont();
+
+ // Read the paths to required executables
+ pConf->setGroup("Programs");
+ m_cp.sCscopePath = pConf->readEntry("CScope");
+ m_cp.sCtagsPath = pConf->readEntry("CTags");
+ m_cp.sDotPath = pConf->readEntry("Dot");
+
+ // Read size and position parameters
+ pConf->setGroup("Geometry");
+ m_cp.bShowTagList = pConf->readBoolEntry("ShowTagList",
+ s_cpDef.bShowTagList);
+ m_cp.siEditor = pConf->readIntListEntry("Editor");
+ if (m_cp.siEditor.empty())
+ m_cp.siEditor << 200 << 800;
+
+ // Read the recent projects list
+ pConf->setGroup("Projects");
+ m_slProjects = pConf->readListEntry("Recent");
+
+ // Read colour settings
+ pConf->setGroup("Colors");
+ for (i = 0; i <= LAST_COLOR; i++) {
+ m_cp.clrs[i] = pConf->readColorEntry(COLOR_ENTRY(i),
+ &s_cpDef.clrs[i]);
+ }
+
+ // Read font settings
+ pConf->setGroup("Fonts");
+ for (i = 0; i <= LAST_FONT; i++) {
+ m_cp.fonts[i] = pConf->readFontEntry(FONT_ENTRY(i),
+ &s_cpDef.fonts[i]);
+ }
+
+ // Other options
+ pConf->setGroup("Options");
+ m_cp.ctagSortOrder =
+ (CtagSort)pConf->readUnsignedNumEntry("CtagSortOrder",
+ s_cpDef.ctagSortOrder);
+ m_cp.bReadOnlyMode = pConf->readBoolEntry("ReadOnlyMode",
+ s_cpDef.bReadOnlyMode);
+ m_cp.bLoadLastProj = pConf->readBoolEntry("LoadLastProj",
+ s_cpDef.bLoadLastProj);
+ m_cp.bAutoTagHl = pConf->readBoolEntry("AutoTagHl",
+ s_cpDef.bAutoTagHl);
+ m_cp.bBriefQueryCaptions = pConf->readBoolEntry("BriefQueryCaptions",
+ s_cpDef.bBriefQueryCaptions);
+ m_cp.bWarnModifiedOnDisk = pConf->readBoolEntry("WarnModifiedOnDisk",
+ s_cpDef.bWarnModifiedOnDisk);
+ m_cp.bAutoSortFiles = pConf->readBoolEntry("AutoSortFiles",
+ s_cpDef.bAutoSortFiles);
+ m_cp.sExtEditor = pConf->readEntry("ExternalEditor", s_cpDef.sExtEditor);
+ m_cp.profile = (SysProfile)pConf->readUnsignedNumEntry("SystemProfile",
+ s_cpDef.profile);
+ m_cp.popup = (EditorPopup)pConf->readUnsignedNumEntry("EditorPopup",
+ s_cpDef.popup);
+ m_cp.sGraphOrient = pConf->readEntry("GraphOrientation",
+ s_cpDef.sGraphOrient);
+ m_cp.nGraphMaxNodeDegree = pConf->readNumEntry("GraphMaxNodeDegree",
+ s_cpDef.nGraphMaxNodeDegree);
+ m_cp.nDefGraphView = pConf->readNumEntry("DefGraphView",
+ s_cpDef.nDefGraphView);
+}
+
+/**
+ * Sets default values to he configuration parameters (except for those where
+ * a default value has no meaning, such as the recent projects list).
+ */
+void KScopeConfig::loadDefault()
+{
+ m_cp = s_cpDef;
+}
+
+/**
+ * Loads the layout of the main window.
+ * @param pMainWindow Pointer to the main docking window
+ */
+void KScopeConfig::loadWorkspace(KDockMainWindow* pMainWindow)
+{
+ pMainWindow->readDockConfig(kapp->config(), "Workspace");
+}
+
+/**
+ * Writes KScope's parameters from the standard configuration file.
+ */
+void KScopeConfig::store()
+{
+ uint i;
+
+ KConfig* pConf = kapp->config();
+
+ // Write the paths to required executables
+ pConf->setGroup("Programs");
+ pConf->writeEntry("CScope", m_cp.sCscopePath);
+ pConf->writeEntry("CTags", m_cp.sCtagsPath);
+ pConf->writeEntry("Dot", m_cp.sDotPath);
+
+ // Write size and position parameters
+ pConf->setGroup("Geometry");
+ pConf->writeEntry("ShowTagList", m_cp.bShowTagList);
+ pConf->writeEntry("Editor", m_cp.siEditor);
+
+ // Write the recent projects list
+ pConf->setGroup("Projects");
+ pConf->writeEntry("Recent", m_slProjects);
+
+ // Write colour settings
+ pConf->setGroup("Colors");
+ for (i = 0; i <= LAST_COLOR; i++)
+ pConf->writeEntry(COLOR_ENTRY(i), m_cp.clrs[i]);
+
+ // Write font settings
+ if (m_bFontsChanged) {
+ pConf->setGroup("Fonts");
+ for (i = 0; i <= LAST_FONT; i++)
+ pConf->writeEntry(FONT_ENTRY(i), m_cp.fonts[i]);
+
+ m_bFontsChanged = false;
+ }
+
+ // Other options
+ pConf->setGroup("Options");
+ pConf->writeEntry("CtagSortOrder", (uint)m_cp.ctagSortOrder);
+ pConf->writeEntry("ReadOnlyMode", m_cp.bReadOnlyMode);
+ pConf->writeEntry("LoadLastProj", m_cp.bLoadLastProj);
+ pConf->writeEntry("AutoTagHl", m_cp.bAutoTagHl);
+ pConf->writeEntry("BriefQueryCaptions", m_cp.bBriefQueryCaptions);
+ pConf->writeEntry("WarnModifiedOnDisk", m_cp.bWarnModifiedOnDisk);
+ pConf->writeEntry("AutoSortFiles", m_cp.bAutoSortFiles);
+ pConf->writeEntry("ExternalEditor", m_cp.sExtEditor);
+ pConf->writeEntry("SystemProfile", (uint)m_cp.profile);
+ pConf->writeEntry("EditorPopup", (uint)m_cp.popup);
+ pConf->writeEntry("GraphOrientation", m_cp.sGraphOrient);
+ pConf->writeEntry("GraphMaxNodeDegree", m_cp.nGraphMaxNodeDegree);
+ pConf->writeEntry("DefGraphView", m_cp.nDefGraphView);
+
+ // Do not report it's the first time on the next run
+ pConf->setGroup("General");
+ pConf->writeEntry("FirstTime", false);
+ pConf->writeEntry(SHOW_WELCOME_ENTRY, false);
+}
+
+/**
+ * Stores the layout of the main window.
+ * @param pMainWindow Pointer to the main docking window
+ */
+void KScopeConfig::storeWorkspace(KDockMainWindow* pMainWindow)
+{
+ pMainWindow->writeDockConfig(kapp->config(), "Workspace");
+}
+
+/**
+ * Determines if this is the first time KScope was launched by the current
+ * user.
+ * @return true if this is the first time, false otherwise
+ */
+bool KScopeConfig::isFirstTime()
+{
+ KConfig* pConf = kapp->config();
+
+ pConf->setGroup("General");
+ return pConf->readBoolEntry("FirstTime", true);
+}
+
+/**
+ * Determines if the welcome dialogue should be displayed.
+ * Note that while the dialogue is displayed on the first invocation of KScope,
+ * it may be required on other occasions (e.g., to display important information
+ * on a per-version basis) and thus it is separated from isFirstTime().
+ * @return true if the dialogue should be shown, false otherwise
+ */
+bool KScopeConfig::showWelcomeDlg()
+{
+ KConfig* pConf = kapp->config();
+
+ pConf->setGroup("General");
+ return pConf->readBoolEntry(SHOW_WELCOME_ENTRY, true);
+}
+
+/**
+ * @return The full path of the Cscope executable
+ */
+const QString& KScopeConfig::getCscopePath() const
+{
+ return m_cp.sCscopePath;
+}
+
+/**
+ * @param sPath The full path of the Cscope executable
+ */
+void KScopeConfig::setCscopePath(const QString& sPath)
+{
+ m_cp.sCscopePath = sPath;
+}
+
+/**
+ * @return The full path of the Ctags executable
+ */
+const QString& KScopeConfig::getCtagsPath() const
+{
+ return m_cp.sCtagsPath;
+}
+
+/**
+ * @param sPath The full path of the Ctags executable
+ */
+void KScopeConfig::setCtagsPath(const QString& sPath)
+{
+ m_cp.sCtagsPath = sPath;
+}
+
+/**
+ * @return The full path of the Dot executable
+ */
+const QString& KScopeConfig::getDotPath() const
+{
+ return m_cp.sDotPath;
+}
+
+/**
+ * @param sPath The full path of the Dot executable
+ */
+void KScopeConfig::setDotPath(const QString& sPath)
+{
+ m_cp.sDotPath = sPath;
+}
+
+/**
+ * @return A sorted list of recently used project paths.
+ */
+const QStringList& KScopeConfig::getRecentProjects() const
+{
+ return m_slProjects;
+}
+
+/**
+ * Adds the given project path to the beginning of the recently used projects
+ * list.
+ * @param sProjPath The path of the project to add
+ */
+void KScopeConfig::addRecentProject(const QString& sProjPath)
+{
+ QStringList::Iterator itr;
+
+ itr = m_slProjects.find(sProjPath);
+ if (itr != m_slProjects.end())
+ m_slProjects.remove(itr);
+
+ m_slProjects.prepend(sProjPath);
+}
+
+/**
+ * Removes the given project path from recently used projects list.
+ * @param sProjPath The path of the project to remove
+ */
+void KScopeConfig::removeRecentProject(const QString& sProjPath)
+{
+ m_slProjects.remove(sProjPath);
+}
+
+/**
+ * @return true if the tag list should be visible, false otherwise
+ */
+bool KScopeConfig::getShowTagList() const
+{
+ return m_cp.bShowTagList;
+}
+
+/**
+ * @param bShowTagList true to make the tag list visible, false otherwise
+ */
+void KScopeConfig::setShowTagList(bool bShowTagList)
+{
+ m_cp.bShowTagList = bShowTagList;
+}
+
+/**
+ * @return A list containing the widths of the Ctags list part and the
+ * editor part in an editor page.
+ */
+const SPLIT_SIZES& KScopeConfig::getEditorSizes() const
+{
+ return m_cp.siEditor;
+}
+
+/**
+ * @param siEditor A list containing the widths of the Ctags list part
+ * and the editor part in an editor page.
+ */
+void KScopeConfig::setEditorSizes(const SPLIT_SIZES& siEditor)
+{
+ m_cp.siEditor = siEditor;
+}
+
+/**
+ * Finds a colour to use for a GUI element.
+ * @param ce Identifies the GUI element
+ * @return A reference to the colour object to use
+ */
+const QColor& KScopeConfig::getColor(ColorElement ce) const
+{
+ return m_cp.clrs[ce];
+}
+
+/**
+ * Returns the display name of a GUI element whose colour can be configured.
+ * @param ce The GUI element
+ * @return A name used in the colour configuration page
+ */
+QString KScopeConfig::getColorName(ColorElement ce) const
+{
+ return COLOR_NAME(ce);
+}
+
+/**
+ * Sets a new colour to a GUI element.
+ * @param ce Identifies the GUI element
+ * @param clr The colour to use
+ */
+void KScopeConfig::setColor(ColorElement ce, const QColor& clr)
+{
+ m_cp.clrs[ce] = clr;
+}
+
+/**
+ * Finds a font to use for a GUI element.
+ * @param fe Identifies the GUI element
+ * @return A reference to the font object to use
+ */
+const QFont& KScopeConfig::getFont(FontElement fe) const
+{
+ return m_cp.fonts[fe];
+}
+
+/**
+ * Returns the display name of a GUI element whose font can be configured.
+ * @param ce The GUI element
+ * @return A name used in the font configuration page
+ */
+QString KScopeConfig::getFontName(FontElement ce) const
+{
+ return FONT_NAME(ce);
+}
+
+/**
+ * Sets a new font to a GUI element.
+ * @param fe Identifies the GUI element
+ * @param font The font to use
+ */
+void KScopeConfig::setFont(FontElement fe, const QFont& font)
+{
+ m_bFontsChanged = true;
+ m_cp.fonts[fe] = font;
+}
+
+/**
+ * @return The column and direction by which the tags should be sorted
+ */
+KScopeConfig::CtagSort KScopeConfig::getCtagSortOrder()
+{
+ return m_cp.ctagSortOrder;
+}
+
+/**
+ * @param ctagSortOrder The column and direction by which the tags should
+ * be sorted
+ */
+void KScopeConfig::setCtagSortOrder(CtagSort ctagSortOrder)
+{
+ m_cp.ctagSortOrder = ctagSortOrder;
+}
+
+/**
+ * @return true to work in Read-Only mode, false otherwise
+ */
+bool KScopeConfig::getReadOnlyMode()
+{
+ return m_cp.bReadOnlyMode;
+}
+
+/**
+ * @param bReadOnlyMode true to work in Read-Only mode, false otherwise
+ */
+void KScopeConfig::setReadOnlyMode(bool bReadOnlyMode)
+{
+ m_cp.bReadOnlyMode = bReadOnlyMode;
+}
+
+/**
+ * @return true to load the last project on start-up, false otherwise
+ */
+bool KScopeConfig::getLoadLastProj()
+{
+ return m_cp.bLoadLastProj;
+}
+
+/**
+ * @param bLoadLastProj true to load the last project on start-up, false
+ * otherwise
+ */
+void KScopeConfig::setLoadLastProj(bool bLoadLastProj)
+{
+ m_cp.bLoadLastProj = bLoadLastProj;
+}
+
+/**
+ * @return true to enable tag highlighting based on cursor position, false
+ * to disable this feature
+ */
+bool KScopeConfig::getAutoTagHl()
+{
+ return m_cp.bAutoTagHl;
+}
+
+/**
+ * @param bAutoTagHl true to enable tag highlighting based on cursor
+ * position, false to disable this feature
+ */
+void KScopeConfig::setAutoTagHl(bool bAutoTagHl)
+{
+ m_cp.bAutoTagHl = bAutoTagHl;
+}
+
+/**
+ * @return true to use the short version of the query captions, false to use
+ * the long version
+ */
+bool KScopeConfig::getUseBriefQueryCaptions()
+{
+ return m_cp.bBriefQueryCaptions;
+}
+
+/**
+ * @param bBrief true to use the short version of the query captions, false
+ * to use the long version
+ */
+void KScopeConfig::setUseBriefQueryCaptions(bool bBrief)
+{
+ m_cp.bBriefQueryCaptions = bBrief;
+}
+
+/**
+ * @return true to warn user when file is modified on disk, false
+ * otherwise
+ */
+bool KScopeConfig::getWarnModifiedOnDisk()
+{
+ return m_cp.bWarnModifiedOnDisk;
+}
+
+/**
+ * @param bWarn true to warn user when file is modified on disk,
+ * false otherwise
+ */
+void KScopeConfig::setWarnModifiedOnDisk(bool bWarn)
+{
+ m_cp.bWarnModifiedOnDisk = bWarn;
+}
+
+/**
+ * @return true to sort files when a project is loaded, false otherwise
+ */
+bool KScopeConfig::getAutoSortFiles()
+{
+ return m_cp.bAutoSortFiles;
+}
+
+/**
+ * @param bSort true to sort files when a project is loaded, false
+ * otherwise
+ */
+void KScopeConfig::setAutoSortFiles(bool bSort)
+{
+ m_cp.bAutoSortFiles = bSort;
+}
+
+/**
+ * @return A command line for launching an external editor
+ */
+const QString& KScopeConfig::getExtEditor()
+{
+ return m_cp.sExtEditor;
+}
+
+/**
+ * @param sExtEditor A command line for launching an external editor
+ */
+void KScopeConfig::setExtEditor(const QString& sExtEditor)
+{
+ m_cp.sExtEditor = sExtEditor;
+}
+
+/**
+ * Determines if an external editor should be used.
+ * An external editor is used if KScope is in Read-Only mode, and a command-
+ * line for the editor was specified.
+ * @return true to use an external editor, false otherwise
+ */
+bool KScopeConfig::useExtEditor()
+{
+ return !m_cp.sExtEditor.isEmpty();
+}
+
+/**
+ * @return The chosen profile for this system (@see SysProfile)
+ */
+KScopeConfig::SysProfile KScopeConfig::getSysProfile() const
+{
+ return m_cp.profile;
+}
+
+/**
+ * @param profile The system profile to use (@see SysProfile)
+ */
+void KScopeConfig::setSysProfile(KScopeConfig::SysProfile profile)
+{
+ m_cp.profile = profile;
+}
+
+/**
+ * @return The chosen popup menu type for the embedded editor (@see
+ * EditorPopup)
+ */
+KScopeConfig::EditorPopup KScopeConfig::getEditorPopup() const
+{
+ return m_cp.popup;
+}
+
+/**
+ * @return The name of the popup menu to use in the embedded editor
+ */
+QString KScopeConfig::getEditorPopupName() const
+{
+ switch (m_cp.popup) {
+ case Embedded:
+ return "ktexteditor_popup";
+
+ case KScopeOnly:
+ return "kscope_popup";
+ }
+
+ // Will not happen, but the compiler complains if no return statement is
+ // given here
+ return "";
+}
+
+/**
+ * @param popup The popup menu to use for the embedded editor (@see
+ * EditorPopup)
+ */
+void KScopeConfig::setEditorPopup(KScopeConfig::EditorPopup popup)
+{
+ m_cp.popup = popup;
+}
+
+/**
+ * @return The default orientation for call graphs
+ */
+QString KScopeConfig::getGraphOrientation() const
+{
+ return m_cp.sGraphOrient;
+}
+
+/**
+ * @param sOrient The default orientation for call graphs
+ */
+void KScopeConfig::setGraphOrientation(const QString& sOrient)
+{
+ m_cp.sGraphOrient = sOrient;
+}
+
+/**
+ * @return The maximal number of calls per graph node
+ */
+int KScopeConfig::getGraphMaxNodeDegree() const
+{
+ return m_cp.nGraphMaxNodeDegree;
+}
+
+/**
+ * @param nMaxNodeDegree The maximal number of calls per graph node
+ */
+void KScopeConfig::setGraphMaxNodeDegree(int nMaxNodeDegree)
+{
+ m_cp.nGraphMaxNodeDegree = nMaxNodeDegree;
+}
+
+/**
+ * @return The default view in the call graph dialogue
+ */
+int KScopeConfig::getDefGraphView() const
+{
+ return m_cp.nDefGraphView;
+}
+
+/**
+ * @param nDefGraphView The default view in the call graph dialogue
+ */
+void KScopeConfig::setDefGraphView(int nDefGraphView)
+{
+ m_cp.nDefGraphView = nDefGraphView;
+}
+
+/**
+ * Returns a reference to a global configuration object.
+ * The static object defined is this function should be the only KSCopeConfig
+ * object in this programme. Any code that wishes to get or set global
+ * configuration parameters, should call Config(), instead of defining its
+ * own object.
+ * @return Reference to a statically allocated configuration object
+ */
+KScopeConfig& Config()
+{
+ static KScopeConfig conf;
+ return conf;
+}
+
+#include "kscopeconfig.moc"
diff --git a/src/kscopeconfig.h b/src/kscopeconfig.h
new file mode 100644
index 0000000..8a047cf
--- /dev/null
+++ b/src/kscopeconfig.h
@@ -0,0 +1,218 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef KSCOPECONFIG_H
+#define KSCOPECONFIG_H
+
+#include <qobject.h>
+#include <qstringlist.h>
+#include <qcolor.h>
+#include <kdockwidget.h>
+
+typedef QValueList<int> SPLIT_SIZES;
+
+/**
+ * Loads and stores global configuration parameters.
+ * @author Elad Lahav
+ */
+
+class KScopeConfig : public QObject
+{
+ Q_OBJECT
+
+public:
+ KScopeConfig();
+ ~KScopeConfig();
+
+ /** GUI elements whose colours can be set. */
+ enum ColorElement { FileListFore = 0, FileListBack, TagListFore,
+ TagListBack, QueryWindowFore, QueryWindowBack, GraphBack,
+ GraphNode, GraphText, GraphMultiCall, LAST_COLOR = GraphMultiCall };
+
+ /** GUI elements whose fonts can be set. */
+ enum FontElement { FileList = 0, TagList, QueryWindow, Graph,
+ LAST_FONT = Graph };
+
+ /** Sort order values for the tags list. */
+ enum CtagSort { NameAsc = 0, NameDes, LineAsc, LineDes, TypeAsc,
+ TypeDes };
+
+ /** Types of systems that determine certain aspects in KScope's
+ behaviour.
+ For fast systems, certain time-consuming operations, such as
+ rebuilding the database, may be performed automatically. Such
+ behaviour, however, is not desired on slow systems, in which the user
+ should handle such operations manually. */
+ enum SysProfile { Fast, Slow };
+
+ /** The different options for a popup menu to be installed in the editor
+ parts. */
+ enum EditorPopup { Embedded, KScopeOnly };
+
+ void load();
+ void loadDefault();
+ void loadWorkspace(KDockMainWindow*);
+ void store();
+ void storeWorkspace(KDockMainWindow*);
+ bool isFirstTime();
+ bool showWelcomeDlg();
+
+ const QString& getCscopePath() const;
+ void setCscopePath(const QString&);
+ const QString& getCtagsPath() const;
+ void setCtagsPath(const QString&);
+ const QString& getDotPath() const;
+ void setDotPath(const QString&);
+ const QStringList& getRecentProjects() const;
+ void addRecentProject(const QString&);
+ void removeRecentProject(const QString&);
+ bool getShowTagList() const;
+ void setShowTagList(bool);
+ const SPLIT_SIZES& getEditorSizes() const;
+ void setEditorSizes(const SPLIT_SIZES&);
+ const QColor& getColor(ColorElement) const;
+ QString getColorName(ColorElement) const;
+ void setColor(ColorElement, const QColor&);
+ const QFont& getFont(FontElement) const;
+ QString getFontName(FontElement) const;
+ void setFont(FontElement, const QFont&);
+ CtagSort getCtagSortOrder();
+ void setCtagSortOrder(CtagSort);
+ bool getReadOnlyMode();
+ void setReadOnlyMode(bool);
+ bool getLoadLastProj();
+ void setLoadLastProj(bool);
+ bool getAutoTagHl();
+ void setAutoTagHl(bool);
+ bool getUseBriefQueryCaptions();
+ void setUseBriefQueryCaptions(bool);
+ bool getWarnModifiedOnDisk();
+ void setWarnModifiedOnDisk(bool);
+ bool getAutoSortFiles();
+ void setAutoSortFiles(bool);
+ const QString& getExtEditor();
+ void setExtEditor(const QString&);
+ bool useExtEditor();
+ SysProfile getSysProfile() const;
+ void setSysProfile(SysProfile);
+ EditorPopup getEditorPopup() const;
+ QString getEditorPopupName() const;
+ void setEditorPopup(EditorPopup);
+ QString getGraphOrientation() const;
+ void setGraphOrientation(const QString&);
+ int getGraphMaxNodeDegree() const;
+ void setGraphMaxNodeDegree(int);
+ int getDefGraphView() const;
+ void setDefGraphView(int);
+
+private:
+ /** A list of previously loaded projects. */
+ QStringList m_slProjects;
+
+ /** Defines the list of all configurable parameters in KScope.
+ The use of a structure helps define default values (@see s_cpDef) */
+ struct ConfParams {
+ /** The full path of the Cscope executable. */
+ QString sCscopePath;
+
+ /** The full path of the Ctags executable. */
+ QString sCtagsPath;
+
+ /** The full path of the Dot executable. */
+ QString sDotPath;
+
+ /** Whether the tag list should be visible. */
+ bool bShowTagList;
+
+ /** The widths of the tag list and editor panes inside an editor
+ page. */
+ SPLIT_SIZES siEditor;
+
+ /** Colours for GUI elements. */
+ QColor clrs[LAST_COLOR + 1];
+
+ /** Fonts for GUI elements. */
+ QFont fonts[LAST_FONT + 1];
+
+ /** Sort order of the tag lists. */
+ CtagSort ctagSortOrder;
+
+ /** Whether KScope should operate in code read-only mode. */
+ bool bReadOnlyMode;
+
+ /** Whether the last open project should be reloaded on start-up. */
+ bool bLoadLastProj;
+
+ /** Whether tags should be highlighted based on the current cursor
+ position. */
+ bool bAutoTagHl;
+
+ /** Whether query page captions should use mnemonics for query types,
+ instead of the full description. */
+ bool bBriefQueryCaptions;
+
+ /** Whether the warning should be displayed when file is modified on
+ disk by external process. */
+ bool bWarnModifiedOnDisk;
+
+ /** Should files be sorted automatically when a project is loaded. */
+ bool bAutoSortFiles;
+
+ /** A command line pattern for an external editor (in read-only
+ mode.)*/
+ QString sExtEditor;
+
+ /** How KScope should treat time-consuming operations. */
+ SysProfile profile;
+
+ /** The type of popup menu to use in the embedded editor. */
+ EditorPopup popup;
+
+ /** The default orientation of call graphs. */
+ QString sGraphOrient;
+
+ /** Maximal number of called/calling functions per call graph node. */
+ int nGraphMaxNodeDegree;
+
+ /** Default view for the call graph dialogue. */
+ int nDefGraphView;
+ };
+
+ /** The current configuration parameters */
+ ConfParams m_cp;
+
+ /** Holds default values for the configuration parameters */
+ static ConfParams s_cpDef;
+
+ /** Write font preferences only if modified by the user (keep default
+ setting otherwise) */
+ bool m_bFontsChanged;
+};
+
+extern KScopeConfig& Config();
+
+#endif
diff --git a/src/kscopepixmaps.cpp b/src/kscopepixmaps.cpp
new file mode 100644
index 0000000..495d756
--- /dev/null
+++ b/src/kscopepixmaps.cpp
@@ -0,0 +1,376 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <kglobal.h>
+#include <kiconloader.h>
+#include "kscopepixmaps.h"
+
+static const char* XPM_FUNC[] = {
+ "12 12 2 1",
+ ". c #000000",
+ "# c #58a8ff",
+ "............",
+ ".##########.",
+ ".###....###.",
+ ".###.######.",
+ ".###.######.",
+ ".###.######.",
+ ".###....###.",
+ ".###.######.",
+ ".###.######.",
+ ".###.######.",
+ ".##########.",
+ "............"
+};
+
+static const char* XPM_VAR[] = {
+ "12 12 3 1",
+ ". c #000000",
+ "a c #c00000",
+ "# c #ff0000",
+ "............",
+ ".##########.",
+ ".##########.",
+ ".##.####.##.",
+ ".##.####.##.",
+ ".##.a##a.##.",
+ ".##a.##.a##.",
+ ".###.aa.###.",
+ ".###a..a###.",
+ ".####..####.",
+ ".##########.",
+ "............"
+};
+
+static const char* XPM_STRUCT[] = {
+ "12 12 2 1",
+ ". c #000000",
+ "# c #ffff00",
+ "............",
+ ".##########.",
+ ".####...###.",
+ ".###.###.##.",
+ ".###.######.",
+ ".####.#####.",
+ ".#####.####.",
+ ".######.###.",
+ ".##.###.###.",
+ ".###...####.",
+ ".##########.",
+ "............"
+};
+
+static const char* XPM_MACRO[] = {
+ "12 12 2 1",
+ ". c #000000",
+ "# c #00c000",
+ "............",
+ ".##########.",
+ ".##.####.##.",
+ ".##..##..##.",
+ ".##.#..#.##.",
+ ".##.####.##.",
+ ".##.####.##.",
+ ".##.####.##.",
+ ".##.####.##.",
+ ".##.####.##.",
+ ".##########.",
+ "............"
+};
+
+static const char* XPM_MEMBER[] = {
+ "12 12 3 1",
+ ". c #000000",
+ "a c #0000c0",
+ "# c #c0c0ff",
+ "............",
+ ".##########.",
+ ".##########.",
+ ".##########.",
+ ".##a.##.a##.",
+ ".##.a..a.##.",
+ ".##.#aa#.##.",
+ ".##.####.##.",
+ ".##.####.##.",
+ ".##########.",
+ ".##########.",
+ "............"
+};
+
+static const char* XPM_ENUM[] = {
+ "12 12 2 1",
+ ". c #000000",
+ "# c #ff00ff",
+ "............",
+ ".##########.",
+ ".##########.",
+ ".##......##.",
+ ".##.#######.",
+ ".##.#######.",
+ ".##.....###.",
+ ".##.#######.",
+ ".##.#######.",
+ ".##......##.",
+ ".##########.",
+ "............"
+};
+
+static const char* XPM_ENUMERATOR[] = {
+ "12 12 2 1",
+ ". c #000000",
+ "# c #ffc0c0",
+ "............",
+ ".##########.",
+ ".##########.",
+ ".###...####.",
+ ".##.###.###.",
+ ".##.###.###.",
+ ".##.....###.",
+ ".##.#######.",
+ ".##.###.###.",
+ ".###...####.",
+ ".##########.",
+ "............"
+};
+
+static const char* XPM_TYPEDEF[] = {
+ "12 12 2 1",
+ ". c #000000",
+ "# c #c0ffc0",
+ "............",
+ ".##########.",
+ ".#.......##.",
+ ".####.#####.",
+ ".####.#####.",
+ ".####.#####.",
+ ".####.#####.",
+ ".####.#####.",
+ ".####.#####.",
+ ".####.#####.",
+ ".##########.",
+ "............"
+};
+
+static const char* XPM_LABEL[] = {
+ "12 12 2 1",
+ ". c #000000",
+ "# c #c0ff00",
+ "............",
+ ".##########.",
+ ".#.########.",
+ ".#.########.",
+ ".#.########.",
+ ".#.########.",
+ ".#.########.",
+ ".#.########.",
+ ".#.########.",
+ ".#.......##.",
+ ".##########.",
+ "............"
+};
+
+static const char* XPM_INCLUDE[] = {
+ "12 12 2 1",
+ ". c #000000",
+ "# c #c0c0c0",
+ "............",
+ ".##########.",
+ ".##.....###.",
+ ".####.#####.",
+ ".####.#####.",
+ ".####.#####.",
+ ".####.#####.",
+ ".####.#####.",
+ ".####.#####.",
+ ".##.....###.",
+ ".##########.",
+ "............"
+};
+
+static const char* XPM_UNKNOWN[] = {
+ "12 12 2 1",
+ ". c #000000",
+ "# c #ffffff",
+ "............",
+ ".##########.",
+ ".##.....###.",
+ ".#.#####.##.",
+ ".########.#.",
+ ".########.#.",
+ ".#######.##.",
+ ".######.###.",
+ ".####.#####.",
+ ".##########.",
+ ".####.#####.",
+ "............"
+};
+
+/**
+ * Class constructor.
+ */
+KScopePixmaps::KScopePixmaps() :
+ m_pPixArray(NULL),
+ m_loader()
+{
+}
+
+/**
+ * Class destructor.
+ */
+KScopePixmaps::~KScopePixmaps()
+{
+ int i;
+
+ for (i = 0; i < PIX_ARRAY_SIZE; i++)
+ delete m_pPixArray[i];
+
+ delete [] m_pPixArray;
+}
+
+/**
+ * Creates the array of embedded pixmaps.
+ * This function is separated from the constructor since QPixmap objects
+ * cannot be created at the time the static KScopePixmaps object is
+ * allocated.
+ */
+void KScopePixmaps::init()
+{
+ // Create the pixmap array
+ m_pPixArray = new QPixmap * [PIX_ARRAY_SIZE];
+
+ // Create all pixmaps
+ m_pPixArray[SymFunc] = new QPixmap(XPM_FUNC);
+ m_pPixArray[SymVar] = new QPixmap(XPM_VAR);
+ m_pPixArray[SymStruct] = new QPixmap(XPM_STRUCT);
+ m_pPixArray[SymMacro] = new QPixmap(XPM_MACRO);
+ m_pPixArray[SymMember] = new QPixmap(XPM_MEMBER);
+ m_pPixArray[SymEnum] = new QPixmap(XPM_ENUM);
+ m_pPixArray[SymEnumerator] = new QPixmap(XPM_ENUMERATOR);
+ m_pPixArray[SymTypedef] = new QPixmap(XPM_TYPEDEF);
+ m_pPixArray[SymLabel] = new QPixmap(XPM_LABEL);
+ m_pPixArray[SymInclude] = new QPixmap(XPM_INCLUDE);
+ m_pPixArray[SymUnknown] = new QPixmap(XPM_UNKNOWN);
+}
+
+/**
+ * Returns a reference to an embedded pixmap.
+ * @param name The pixmap's identifier
+ * @return A reference to the requested pixmap
+ */
+const QPixmap& KScopePixmaps::getPixmap(PixName name) const
+{
+ return *m_pPixArray[name];
+}
+
+/**
+ * Loads a pixmap with the KIconLoader mechanism.
+ * @param name The pixmap's identifier
+ * @return The requested pixmap
+ */
+QPixmap KScopePixmaps::getPixmap(LoadPixName name)
+{
+ switch (name) {
+ case TabUnlocked:
+ return m_loader.loadIcon("query_unlocked", KIcon::Small, 0,
+ false);
+
+ case TabLocked:
+ return m_loader.loadIcon("query_locked", KIcon::Small, 0,
+ false);
+
+ case TabBookmark:
+ return m_loader.loadIcon("bookmark", KIcon::Small, 0,
+ false);
+
+ case TabRW:
+ return m_loader.loadIcon("file_rw", KIcon::Small, 0,
+ false);
+
+ case TabRO:
+ return m_loader.loadIcon("file_ro", KIcon::Small, 0,
+ false);
+
+ case TabSave:
+ return m_loader.loadIcon("file_save", KIcon::Small, 0,
+ false);
+
+ case TabFileList:
+ return m_loader.loadIcon("view_detailed", KIcon::Small, 0,
+ false);
+
+ case TabFileTree:
+ return m_loader.loadIcon("view_tree", KIcon::Small, 0,
+ false);
+
+ case TabList:
+ return m_loader.loadIcon("tab_list", KIcon::Small, 0,
+ false);
+
+ case ButtonSaveAs:
+ return m_loader.loadIcon("filesaveas", KIcon::Toolbar,
+ 0, false);
+
+ case ButtonZoomIn:
+ return m_loader.loadIcon("viewmag+", KIcon::Toolbar,
+ 0, false);
+
+ case ButtonZoomOut:
+ return m_loader.loadIcon("viewmag-", KIcon::Toolbar,
+ 0, false);
+
+ case ButtonRotate:
+ return m_loader.loadIcon("rotate", KIcon::Toolbar,
+ 0, false);
+
+ case ButtonPref:
+ return m_loader.loadIcon("configure", KIcon::Toolbar,
+ 0, false);
+
+ case CalledTree:
+ return m_loader.loadIcon("called_tree", KIcon::Toolbar,
+ 0, false);
+
+ case CallingTree:
+ return m_loader.loadIcon("calling_tree", KIcon::Toolbar,
+ 0, false);
+
+ case CallGraph:
+ return m_loader.loadIcon("call_graph", KIcon::Toolbar,
+ 0, false);
+ }
+
+ return QPixmap();
+}
+
+/**
+ * @return A reference to a global KScopePixmaps object
+ */
+KScopePixmaps& Pixmaps()
+{
+ static KScopePixmaps pix;
+ return pix;
+}
diff --git a/src/kscopepixmaps.h b/src/kscopepixmaps.h
new file mode 100644
index 0000000..e5f321b
--- /dev/null
+++ b/src/kscopepixmaps.h
@@ -0,0 +1,77 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef KSCOPEPIXMAPS_H
+#define KSCOPEPIXMAPS_H
+
+#include <qpixmap.h>
+#include <kiconloader.h>
+
+#define GET_PIXMAP(_pix) \
+ Pixmaps().getPixmap(KScopePixmaps::_pix)
+
+/**
+ * Handles all pixmaps required by KScope.
+ * There are two types of pixmaps: embedded, i.e., pixmaps whose pixels are
+ * given by static two-dimensional arrays, and loadable, which are retrieved
+ * through the KIconLoader mechanism.
+ * The application uses a single global instance of this class.
+ * @author Elad Lahav
+ */
+
+class KScopePixmaps
+{
+public:
+ KScopePixmaps();
+ ~KScopePixmaps();
+
+ /** Identifiers for embedded pixmaps. */
+ enum PixName { SymFunc, SymVar, SymStruct, SymMacro, SymMember, SymEnum,
+ SymEnumerator, SymTypedef, SymLabel, SymInclude, SymUnknown,
+ PIX_ARRAY_SIZE };
+
+ /** Identifiers for loadable pixmaps. */
+ enum LoadPixName { TabUnlocked, TabLocked, TabBookmark, TabRW, TabRO,
+ TabSave, TabFileList, TabFileTree, TabList, ButtonSaveAs, ButtonZoomIn,
+ ButtonZoomOut, ButtonRotate, ButtonPref, CalledTree,
+ CallingTree, CallGraph };
+
+ void init();
+ const QPixmap& getPixmap(PixName name) const;
+ QPixmap getPixmap(LoadPixName name);
+
+private:
+ /** An array of pointers to the embedded pixmaps. */
+ QPixmap** m_pPixArray;
+
+ /** An icon loader used to retrieve pixmaps through the KDE mechanism. */
+ KIconLoader m_loader;
+};
+
+extern KScopePixmaps& Pixmaps();
+
+#endif
diff --git a/src/kscopeui.rc b/src/kscopeui.rc
new file mode 100644
index 0000000..81d3646
--- /dev/null
+++ b/src/kscopeui.rc
@@ -0,0 +1,141 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="kscope">
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Merge/>
+ </Menu>
+ <Menu name="edit"><text>&amp;Edit</text>
+ <Action name="edit_external_editor"/>
+ <Separator/>
+ <Merge/>
+ <Action name="edit_goto_tag"/>
+ <Action name="edit_comp_symbol"/>
+ </Menu>
+ <Menu name="view"><text>&amp;View</text>
+ <Action name="view_toggle_filelist_dock"/>
+ <Action name="view_toggle_query_dock"/>
+ <Action name="view_toggle_tag_list"/>
+ <Separator/>
+ <Merge/>
+ </Menu>
+ <Menu name="project"><text>&amp;Project</text>
+ <Action name="project_new"/>
+ <Action name="project_open"/>
+ <Action name="project_cscope_out"/>
+ <Action name="project_add_rem_files"/>
+ <Action name="project_properties"/>
+ <Separator/>
+ <Action name="project_make"/>
+ <Action name="project_remake"/>
+ <Separator/>
+ <Action name="project_close"/>
+ </Menu>
+ <Menu name="cscope"><text>&amp;Cscope</text>
+ <Action name="cscope_rebuild"/>
+ <Separator/>
+ <Action name="cscope_references"/>
+ <Action name="cscope_definition"/>
+ <Action name="cscope_called"/>
+ <Action name="cscope_calling"/>
+ <Action name="cscope_text"/>
+ <Action name="cscope_pattern"/>
+ <Action name="cscope_file"/>
+ <Action name="cscope_including"/>
+ <Separator/>
+ <Action name="cscope_quick_def"/>
+ <Action name="cscope_call_tree"/>
+ </Menu>
+ <Menu name="go"><text>&amp;Go</text>
+ <Action name="go_prev_result"/>
+ <Action name="go_next_result"/>
+ <Separator/>
+ <Action name="go_prev_pos"/>
+ <Action name="go_next_pos"/>
+ <Action name="go_history"/>
+ <Separator/>
+ <Action name="go_bookmarks"/>
+ </Menu>
+ <Merge/>
+ <Menu name="window"><text>&amp;Window</text>
+ <Action name="window_close_all"/>
+ <Action name="window_go_left"/>
+ <Action name="window_go_right"/>
+ <Separator/>
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Merge/>
+ </Menu>
+ <Menu name="help"><text>&amp;Help</text>
+ <Action name="help_welcome"/>
+ <Merge/>
+ </Menu>
+</MenuBar>
+<Menu name="query_popup"><text>&amp;Query</text>
+ <Action name="query_new"/>
+ <Action name="query_refresh"/>
+ <Action name="query_toggle_locked"/>
+ <Separator/>
+ <Action name="query_close"/>
+</Menu>
+<Menu name="ktexteditor_popup">
+ <Merge/>
+ <Menu name="cscope"><text>Cscope</text>
+ <Action name="cscope_references"/>
+ <Action name="cscope_definition"/>
+ <Action name="cscope_called"/>
+ <Action name="cscope_calling"/>
+ <Action name="cscope_text"/>
+ <Action name="cscope_pattern"/>
+ <Action name="cscope_file"/>
+ <Action name="cscope_including"/>
+ <Separator/>
+ <Action name="cscope_quick_def"/>
+ <Action name="cscope_call_tree"/>
+ </Menu>
+ <Action name="edit_external_editor"/>
+ <Action name="file_close"/>
+</Menu>
+<Menu name="kscope_popup">
+ <Action name="cscope_references"/>
+ <Action name="cscope_definition"/>
+ <Action name="cscope_called"/>
+ <Action name="cscope_calling"/>
+ <Action name="cscope_text"/>
+ <Action name="cscope_pattern"/>
+ <Action name="cscope_file"/>
+ <Action name="cscope_including"/>
+ <Separator/>
+ <Action name="cscope_quick_def"/>
+ <Action name="cscope_call_tree"/>
+ <Action name="edit_external_editor"/>
+ <Separator/>
+ <Action name="file_close"/>
+</Menu>
+<ToolBar fullWidth="true" name="mainToolBar">
+ <Action name="file_close"/>
+</ToolBar>
+<ToolBar fullWidth="true" name="projectToolBar"><text>Project</text>
+ <Action name="project_open"/>
+ <Action name="cscope_rebuild"/>
+</ToolBar>
+<ToolBar fullWidth="true" name="navigateToolBar"><text>Navigation</text>
+ <Action name="go_prev_pos"/>
+ <Action name="go_next_pos"/>
+ <Action name="go_history"/>
+ <Action name="go_bookmarks"/>
+</ToolBar>
+<ToolBar fullWidth="true" name="queryToolBar"><text>Query</text>
+ <Action name="query_new"/>
+ <Action name="query_refresh"/>
+ <Action name="query_toggle_locked"/>
+ <Action name="query_close"/>
+ <Separator/>
+ <Action name="go_prev_result"/>
+ <Action name="go_next_result"/>
+</ToolBar>
+<ToolBar fullWidth="true" name="workspaceToolBar"><text>Workspace</text>
+ <Action name="view_toggle_tag_list"/>
+ <Action name="view_toggle_query_dock"/>
+ <Action name="view_toggle_filelist_dock"/>
+</ToolBar>
+</kpartgui>
diff --git a/src/lo16-app-kscope.png b/src/lo16-app-kscope.png
new file mode 100644
index 0000000..fd8ef48
--- /dev/null
+++ b/src/lo16-app-kscope.png
Binary files differ
diff --git a/src/lo32-app-kscope.png b/src/lo32-app-kscope.png
new file mode 100644
index 0000000..5bb28f8
--- /dev/null
+++ b/src/lo32-app-kscope.png
Binary files differ
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..ffa7b55
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,97 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+
+#include "kscope.h"
+#include "kscopeconfig.h"
+
+static const char *description =
+ I18N_NOOP("KScope\nA source-editing environment for KDE, based on "
+ "Cscope");
+
+static KCmdLineOptions options[] =
+{
+ { "+[CSCOPE.OUT path]",
+ I18N_NOOP("Opens a cscope.out file in a temporary project"), 0 },
+ { "+[CSCOPE.PROJ path | KScope project directory path]",
+ I18N_NOOP("Opens a KScope project"), 0 },
+ KCmdLineLastOption
+};
+
+/**
+ * Defines the programme's entry point.
+ * Creates KScope's main window, and starts the event loop.
+ * @param argc Number of command line arguments
+ * @param argv Command line arguments
+ * @return Programme's exit value
+ */
+int main(int argc, char *argv[])
+{
+ // Create the "About" dialogue
+ KAboutData aboutData( "kscope", I18N_NOOP("KScope"),
+ VERSION, description, KAboutData::License_BSD,
+ "(c) 2003-2007, Elad Lahav", 0, "http://kscope.sourceforge.net",
+ "elad_lahav@users.sf.net");
+ aboutData.addAuthor("Elad Lahav", "Developer",
+ "elad_lahav@users.sf.net");
+ aboutData.addCredit("Albert Yosher",
+ "Code completion, patches and bug fixes", "ayosher@users.sf.net");
+ aboutData.addCredit("Gabor Fekete", "Bug fixes and patches",
+ "feketgai@index.hu");
+
+ // Initialise command-line argument parsing
+ KCmdLineArgs::init(argc, argv, &aboutData);
+ KCmdLineArgs::addCmdLineOptions(options);
+
+ // Parse command line arguments
+ KCmdLineArgs* pArgs = KCmdLineArgs::parsedArgs();
+
+ // Create the main window
+ KApplication a;
+ KScope* pKScope = new KScope();
+ a.setMainWidget(pKScope);
+
+ // Display the main window
+ pKScope->show();
+
+ // Handle command-line arguments
+ if (pArgs->count() > 0) {
+ pKScope->parseCmdLine(pArgs);
+ } else if (Config().getLoadLastProj()) {
+ // No arguments given, load the most recent project
+ pKScope->openLastProject();
+ }
+
+ // Make sure Cscope is properly installed
+ pKScope->verifyCscope();
+
+ // Start the event loop
+ return a.exec();
+}
diff --git a/src/makedlg.cpp b/src/makedlg.cpp
new file mode 100644
index 0000000..ac60129
--- /dev/null
+++ b/src/makedlg.cpp
@@ -0,0 +1,267 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2006 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qtextcodec.h>
+#include <ktextbrowser.h>
+#include <kcombobox.h>
+#include <kurlrequester.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include "makedlg.h"
+#include "makefrontend.h"
+#include "queryview.h"
+
+/** Window flags for call-tree widgets. */
+#define MAKE_DLG_W_FLAGS \
+ WStyle_Customize | \
+ WStyle_NormalBorder | \
+ WStyle_Title
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+MakeDlg::MakeDlg(QWidget* pParent, const char* szName) :
+ MakeLayout(pParent, szName, MAKE_DLG_W_FLAGS)
+{
+ // Don't show the "Function" column
+ m_pErrorView->setColumnWidthMode(0, QListView::Manual);
+ m_pErrorView->setColumnWidth(0, 0);
+
+ // Create a new make front-end
+ m_pMake = new MakeFrontend();
+ connect(m_pMake, SIGNAL(dataReady(FrontendToken*)), this,
+ SLOT(slotShowOutput(FrontendToken*)));
+ connect(m_pMake, SIGNAL(finished(uint)), this, SLOT(slotFinished(uint)));
+ connect(m_pMake,
+ SIGNAL(error(const QString&, const QString&, const QString&)),
+ this,
+ SLOT(slotAddError(const QString&, const QString&, const QString&)));
+
+ // The Root URL control should browse directories
+ m_pRootURL->setMode(KFile::Directory);
+
+ // Handle URL links in the browser
+ m_pOutputBrowser->setNotifyClick(true);
+ connect(m_pOutputBrowser, SIGNAL(urlClick(const QString&)), this,
+ SLOT(slotBrowserClicked(const QString&)));
+
+ // Handle selections in the error view
+ connect(m_pErrorView, SIGNAL(lineRequested(const QString& , uint)), this,
+ SIGNAL(fileRequested(const QString&, uint)));
+
+ // Do not allow duplicates in the command history
+ m_pCommandHistory->setDuplicatesEnabled(false);
+}
+
+/**
+ * Class destructor.
+ */
+MakeDlg::~ MakeDlg()
+{
+ delete m_pMake;
+}
+
+/**
+ * @return The currently set make command
+ */
+QString MakeDlg::getCommand() const
+{
+ return m_pCommandHistory->currentText();
+}
+
+/**
+ * @param sCmd The new make command to use
+ */
+void MakeDlg::setCommand(const QString& sCmd)
+{
+ m_pCommandHistory->setCurrentText(sCmd);
+ m_pCommandHistory->addToHistory(sCmd);
+}
+
+/**
+ * @return The directory in which to run the make command
+ */
+QString MakeDlg::getDir() const
+{
+ return m_pRootURL->url();
+}
+
+/**
+ * @param sURL The new root directory to use
+ */
+void MakeDlg::setDir(const QString& sURL)
+{
+ m_pRootURL->setURL(sURL);
+}
+
+/**
+ * Overrides the default close behaviour.
+ * Makes sure that a window is not closed while a make process is running,
+ * unless the user explicitly requests it. In this case, the make process
+ * is killed.
+ * @param pEvent The close event descriptor
+ */
+void MakeDlg::closeEvent(QCloseEvent* pEvent)
+{
+ // Check if a process is currently running
+ if (m_pMake->isRunning()) {
+ // Prompt the user
+ switch (KMessageBox::questionYesNoCancel(this,
+ i18n("A make process is running. Would you like to stop it first?"),
+ i18n("Close Make Window"))) {
+ case KMessageBox::Yes:
+ // Stop the process first
+ m_pMake->kill();
+ break;
+
+ case KMessageBox::No:
+ // Do nothing
+ break;
+
+ case KMessageBox::Cancel:
+ // Abort closing
+ pEvent->ignore();
+ return;
+ }
+ }
+
+ QWidget::closeEvent(pEvent);
+}
+
+/**
+ * Starts a make process using the user-supplied command.
+ * This slot is connected to the clicked() signal of the "Make" button.
+ */
+void MakeDlg::slotMake()
+{
+ QString sCommand;
+
+ // Clear the current contents
+ m_pOutputBrowser->clear();
+ m_pErrorView->clear();
+
+ // Run the make command
+ sCommand = m_pCommandHistory->currentText();
+ if (!m_pMake->run("make", QStringList::split(" ", sCommand),
+ m_pRootURL->url())) {
+ KMessageBox::error(this, m_pMake->getRunError());
+ return;
+ }
+
+ // Add the command to the command history
+ m_pCommandHistory->addToHistory(sCommand);
+
+ // Disbale the make button
+ m_pMakeButton->setEnabled(false);
+ m_pStopButton->setEnabled(true);
+}
+
+/**
+ * Terminates the current make process.
+ * This slot is connected to the clicked() signal of the stop button.
+ */
+void MakeDlg::slotStop()
+{
+ m_pMake->kill();
+}
+
+/**
+ * Displays the parsed output, as generated by the MakeFrontend object.
+ * This slot is connected to the dataReady() signal of the make front-end.
+ * @param pToken Holds the parsed data
+ */
+void MakeDlg::slotShowOutput(FrontendToken* pToken)
+{
+ QString sData;
+
+ // GCC uses unicode quote characters - this should ensure that they are
+ // treated correctly by the text browser widget
+ sData = QTextCodec::codecForLocale()->toUnicode(pToken->getData());
+ m_pOutputBrowser->append(sData);
+}
+
+/**
+ * Displays the results of the make command.
+ * This slot is connected to the finished() signal of the make front-end.
+ */
+void MakeDlg::slotFinished(uint)
+{
+ // Add "Success" or "Error" at the end of the output
+ if (m_pMake->exitStatus() == 0) {
+ m_pOutputBrowser->append("<font color=\"#008000\"><b>Success</b>"
+ "</font>");
+ }
+ else {
+ m_pOutputBrowser->append("<font color=\"#ff0000\"><b>Error</b></font>");
+ }
+
+ // Re-enable the "Make" button
+ m_pMakeButton->setEnabled(true);
+ m_pStopButton->setEnabled(false);
+}
+
+/**
+ * Emits the fileRequested() signal when a browser link is clicked.
+ * This slot is connected to the urlClick() signal of the browser.
+ * @param sURL The requested URL
+ */
+void MakeDlg::slotBrowserClicked(const QString& sURL)
+{
+ QString sFile;
+ QString sLine;
+
+ // Exract the file name and the line number from the URL
+ sFile = sURL.section('&', 0, 0);
+ sLine = sURL.section('&', 1, 1);
+
+ // Add root path for relative paths
+ if (!sFile.startsWith("/"))
+ sFile = m_pRootURL->url() + "/" + sFile;
+
+ // Emit the signal
+ emit fileRequested(sFile, sLine.toUInt());
+}
+
+/**
+ * Show an error/warning on a deidicated list.
+ * This slot is connected to the error() signal of the make front-end.
+ * @param sFile The file name containing the error/warning
+ * @param sLine The line number
+ * @param sText An explanation of the error
+ */
+void MakeDlg::slotAddError(const QString& sFile, const QString& sLine,
+ const QString& sText)
+{
+ QString sUniText;
+
+ sUniText = QTextCodec::codecForLocale()->toUnicode(sText);
+ m_pErrorView->addRecord("", sFile, sLine, sUniText);
+}
+
+#include "makedlg.moc"
diff --git a/src/makedlg.h b/src/makedlg.h
new file mode 100644
index 0000000..3120b95
--- /dev/null
+++ b/src/makedlg.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2006 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef MAKEDLG_H
+#define MAKEDLG_H
+
+#include "makelayout.h"
+
+class MakeFrontend;
+class FrontendToken;
+
+/**
+ * A window that displays the output of make-like commands.
+ * The window contains a text browser showing errors as links to source
+ * locations.
+ * The make process is determined by a user-specified command, and is run in
+ * a user-specified directory. Controls are provided for modifying these values.
+ * @author Elad Lahav
+ */
+class MakeDlg: public MakeLayout
+{
+ Q_OBJECT
+
+public:
+ MakeDlg(QWidget* pParent = 0, const char* szName = 0);
+ virtual ~MakeDlg();
+
+ QString getCommand() const;
+ void setCommand(const QString&);
+ QString getDir() const;
+ void setDir(const QString&);
+
+public slots:
+ virtual void slotMake();
+
+signals:
+ void fileRequested(const QString&, uint);
+
+protected:
+ virtual void closeEvent(QCloseEvent*);
+
+protected slots:
+ virtual void slotStop();
+ void slotShowOutput(FrontendToken*);
+ void slotFinished(uint);
+ void slotBrowserClicked(const QString&);
+ void slotAddError(const QString&, const QString&, const QString&);
+
+private:
+ /** Handles the make process. */
+ MakeFrontend* m_pMake;
+};
+
+#endif
diff --git a/src/makefrontend.cpp b/src/makefrontend.cpp
new file mode 100644
index 0000000..80ea9b8
--- /dev/null
+++ b/src/makefrontend.cpp
@@ -0,0 +1,134 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2006 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qregexp.h>
+#include "makefrontend.h"
+
+// TODO:
+// This should probably be configurable on a per-project basis.
+#define PATH_ELEM "[a-zA-Z0-9_\\.\\-]+"
+
+#define RE_FILE_LINE \
+ "((?:\\/)?(?:"PATH_ELEM"\\/)*"PATH_ELEM"):([0-9]+)(:[0-9]+)?: (.*)"
+#define RE_ENTER_DIR \
+ "Entering directory " \
+ "\\`((\\/)?("PATH_ELEM"\\/)*"PATH_ELEM")"
+#define RE_EXIT_DIR "Leaving directory"
+
+/**
+ * Class constructor.
+ * @param bAutoDelete If true, the object is deleted when the process
+ * terminates (false by default)
+ */
+MakeFrontend::MakeFrontend(bool bAutoDelete) : Frontend(1, bAutoDelete)
+{
+ // Execute inside a shell
+ setUseShell(true);
+
+ // Each token represent a complete line
+ m_delim = Newline;
+}
+
+/**
+ * Class destructor.
+ */
+MakeFrontend::~MakeFrontend()
+{
+}
+
+/**
+ * Executes the make command.
+ * @param sName The name of the process (for error messages)
+ * @param slArgs A list containing the command-line arguments
+ * @param sWorkDir Initial build directory
+ * @param bBlock (Optional) true to block, false otherwise
+ * @return true if the process was executed successfully, false otherwise
+ */
+bool MakeFrontend::run(const QString& sName, const QStringList& slArgs,
+ const QString& sWorkDir, bool bBlock)
+{
+ QStringList slShellArgs;
+
+ // Store the current build directory
+ m_slPathStack.push_back(sWorkDir);
+
+ // Join the output streams, so that they can both be parsed by
+ // parseStdout()
+ slShellArgs = slArgs;
+ slShellArgs << "2>&1";
+
+ // Execute the command
+ return Frontend::run(sName, slShellArgs, sWorkDir, bBlock);
+}
+
+/**
+ * Parses lines of output produced by the make command.
+ * @param sToken A single line of output
+ */
+Frontend::ParseResult MakeFrontend::parseStdout(QString& sToken, ParserDelim)
+{
+ static QRegExp reErrWarn(RE_FILE_LINE);
+ static QRegExp reEntDir(RE_ENTER_DIR);
+ static QRegExp reExtDir(RE_EXIT_DIR);
+ QString sRep;
+ int nPos;
+ QString sFile, sLine, sText;
+
+ if ((nPos = reErrWarn.search(sToken)) >= 0) {
+ // An error/warning message
+ if (sToken.at(nPos) == '/') {
+ sFile = reErrWarn.capturedTexts()[1];
+ }
+ else {
+ sFile = m_slPathStack.last() + "/" +
+ reErrWarn.capturedTexts()[1];
+ }
+
+ sLine = reErrWarn.capturedTexts()[2];
+ sText = reErrWarn.capturedTexts()[4];
+ emit error(sFile, sLine, sText);
+
+ sRep = QString("<a href=\"") + sFile + "&\\2\">\\1:\\2</a>\\3: \\4";
+ sToken.replace(reErrWarn, sRep);
+ }
+ else if ((nPos = reEntDir.search(sToken)) >= 0) {
+ // Recursing into a directory
+ m_slPathStack.push_back(reEntDir.capturedTexts()[1]);
+ sToken = QString("<b>Entering directory</b> ") +
+ m_slPathStack.last();
+ }
+ else if ((nPos = reExtDir.search(sToken)) >= 0) {
+ // Leaving a directory
+ sToken = QString("<b>Leaving directory</b> ") +
+ m_slPathStack.last();
+ m_slPathStack.pop_back();
+ }
+
+ return RecordReady;
+}
+
+#include "makefrontend.moc"
diff --git a/src/makefrontend.h b/src/makefrontend.h
new file mode 100644
index 0000000..4ed575f
--- /dev/null
+++ b/src/makefrontend.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2006 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef MAKEFRONTEND_H
+#define MAKEFRONTEND_H
+
+#include <frontend.h>
+
+/**
+ * A shell-process front-end intended for running make-like tasks.
+ * Records are single-line tokens delimited by newline characters. The parser
+ * replaces references to source lines (e.g., filename:123) with hypertext
+ * links for use in a browser.
+ * @author Elad Lahav
+ */
+class MakeFrontend : public Frontend
+{
+ Q_OBJECT
+
+public:
+ MakeFrontend(bool bAutoDelete = false);
+ ~MakeFrontend();
+
+ virtual bool run(const QString&, const QStringList&,
+ const QString&, bool bBlock = false);
+ virtual ParseResult parseStdout(QString&, ParserDelim);
+
+signals:
+ void error(const QString& sFile, const QString& sLine,
+ const QString& sText);
+
+private:
+ /** A stack of paths used to track the current build directory. */
+ QStringList m_slPathStack;
+};
+
+#endif
diff --git a/src/makelayout.ui b/src/makelayout.ui
new file mode 100644
index 0000000..e47acf8
--- /dev/null
+++ b/src/makelayout.ui
@@ -0,0 +1,245 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>MakeLayout</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>MakeLayout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>768</width>
+ <height>642</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>KScope - Make</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout10</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Root Directory:</string>
+ </property>
+ </widget>
+ <widget class="KHistoryCombo" row="1" column="1">
+ <property name="name">
+ <cstring>m_pCommandHistory</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="0" column="1">
+ <property name="name">
+ <cstring>m_pRootURL</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Command:</string>
+ </property>
+ </widget>
+ </grid>
+ </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>Output</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KTextBrowser">
+ <property name="name">
+ <cstring>m_pOutputBrowser</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Errors a&amp;nd Warnings</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QueryView">
+ <property name="name">
+ <cstring>m_pErrorView</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</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>520</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pMakeButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Make</string>
+ </property>
+ <property name="accel">
+ <string>Alt+M</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pStopButton</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Stop</string>
+ </property>
+ <property name="accel">
+ <string>Alt+S</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pCloseButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Close</string>
+ </property>
+ <property name="accel">
+ <string>Alt+C</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>QueryView</class>
+ <header location="local">queryview.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="XBM.GZ" length="79">789c534e494dcbcc4b554829cdcdad8c2fcf4c29c95030e0524611cd48cd4ccf28010a1797249664262b2467241641a592324b8aa363156c15aab914146aadb90067111b1f</data>
+ </image>
+</images>
+<connections>
+ <connection>
+ <sender>m_pCloseButton</sender>
+ <signal>clicked()</signal>
+ <receiver>MakeLayout</receiver>
+ <slot>close()</slot>
+ </connection>
+ <connection>
+ <sender>m_pMakeButton</sender>
+ <signal>clicked()</signal>
+ <receiver>MakeLayout</receiver>
+ <slot>slotMake()</slot>
+ </connection>
+ <connection>
+ <sender>m_pStopButton</sender>
+ <signal>clicked()</signal>
+ <receiver>MakeLayout</receiver>
+ <slot>slotStop()</slot>
+ </connection>
+ <connection>
+ <sender>m_pCommandHistory</sender>
+ <signal>returnPressed()</signal>
+ <receiver>MakeLayout</receiver>
+ <slot>slotMake()</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>m_pRootURL</tabstop>
+ <tabstop>m_pCommandHistory</tabstop>
+ <tabstop>m_pMakeButton</tabstop>
+ <tabstop>m_pStopButton</tabstop>
+ <tabstop>m_pCloseButton</tabstop>
+</tabstops>
+<slots>
+ <slot access="protected">slotStop()</slot>
+ <slot access="protected">slotMake()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kcombobox.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>ktextbrowser.h</includehint>
+ <includehint>queryview.h</includehint>
+</includehints>
+</UI>
diff --git a/src/newprojectdlg.cpp b/src/newprojectdlg.cpp
new file mode 100644
index 0000000..ec8fbca
--- /dev/null
+++ b/src/newprojectdlg.cpp
@@ -0,0 +1,354 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qregexp.h>
+#include <qpushbutton.h>
+#include <qspinbox.h>
+#include <qlabel.h>
+#include <qtextedit.h>
+#include <kurlrequester.h>
+#include <klineedit.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include "newprojectdlg.h"
+
+/**
+ * Class constructor.
+ * @param bNewProj true to create a new project dialog, false to display
+ * the properties of an existing project
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+NewProjectDlg::NewProjectDlg(bool bNewProj, QWidget* pParent,
+ const char* szName) :
+ NewProjectLayout(pParent, szName),
+ m_bNewProj(bNewProj)
+{
+ ProjectBase::Options opt;
+
+ // Create the auto-completion sub-dialogue
+ m_pAutoCompDlg = new AutoCompletionDlg(this);
+
+ // Restrict the path requester to existing directories.
+ m_pPathRequester->setMode(KFile::Directory | KFile::ExistingOnly |
+ KFile::LocalOnly);
+ m_pSrcRootRequester->setMode(KFile::Directory | KFile::ExistingOnly |
+ KFile::LocalOnly);
+
+ // Set up the Create/Cancel buttons
+ connect(m_pCreateButton, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(m_pCancelButton, SIGNAL(clicked()), this, SLOT(reject()));
+
+ // Show the auto-completion properties dialogue
+ connect(m_pACButton, SIGNAL(clicked()), m_pAutoCompDlg, SLOT(exec()));
+
+ // Perform actions specific to the type of dialog (new project or
+ // project properties)
+ if (bNewProj) {
+ // Set default project properties
+ ProjectBase::getDefOptions(opt);
+ setProperties("", "", opt);
+ }
+ else {
+ // Give appropriate titles to the dialog and the accept button
+ setCaption(i18n("Project Properties"));
+ m_pCreateButton->setText(i18n("OK"));
+
+ // Disable the non-relevant widgets
+ m_pNameEdit->setEnabled(false);
+ m_pPathRequester->setEnabled(false);
+ }
+}
+
+/**
+ * Class destructor.
+ */
+NewProjectDlg::~NewProjectDlg()
+{
+}
+
+/**
+ * Configures the dialog's widget to display the properties of the current
+ * project.
+ * @param sName The project's name
+ * @param sPath The project's path
+ * @param opt Project parameters configurable in this dialogue
+ */
+void NewProjectDlg::setProperties(const QString& sName, const QString& sPath,
+ const ProjectBase::Options& opt)
+{
+ QStringList::ConstIterator itr;
+
+ // Set values for current project
+ m_pNameEdit->setText(sName);
+ m_pPathRequester->setURL(sPath);
+ m_pSrcRootRequester->setURL(opt.sSrcRootPath);
+ m_pKernelCheck->setChecked(opt.bKernel);
+ m_pInvCheck->setChecked(opt.bInvIndex);
+ m_pNoCompCheck->setChecked(opt.bNoCompress);
+ m_pSlowPathCheck->setChecked(opt.bSlowPathDef);
+
+ if (opt.nAutoRebuildTime >= 0) {
+ m_pAutoRebuildCheck->setChecked(true);
+ m_pAutoRebuildSpin->setValue(opt.nAutoRebuildTime);
+ }
+
+ if (opt.bACEnabled) {
+ m_pACCheck->setChecked(true);
+ }
+
+ if (opt.nTabWidth > 0) {
+ m_pTabWidthCheck->setChecked(true);
+ m_pTabWidthSpin->setValue(opt.nTabWidth);
+ }
+
+ // Initialise the auto-completion sub-dialogue
+ m_pAutoCompDlg->m_nMinChars = opt.nACMinChars;
+ m_pAutoCompDlg->m_nDelay = opt.nACDelay;
+ m_pAutoCompDlg->m_nMaxEntries = opt.nACMaxEntries;
+
+ // Add type strings to the types list box
+ for (itr = opt.slFileTypes.begin(); itr != opt.slFileTypes.end(); ++itr)
+ m_pTypesList->insertItem(*itr);
+
+ m_pCtagsCmdEdit->setText(opt.sCtagsCmd);
+}
+
+/**
+ * Retrieves the text entered by the user in the dialog's "Project Name" edit
+ * box.
+ * @return The name of the new project
+ */
+QString NewProjectDlg::getName()
+{
+ return m_pNameEdit->text();
+}
+
+/**
+ * Retrieves the text entered by the user in the dialog's "Project Path" edit
+ * box.
+ * Note that the chosen path will be the parent of the new project's
+ * directory, created under it using the project's name.
+ * @return The full path of the parent directory for the new project
+ */
+QString NewProjectDlg::getPath()
+{
+ if (m_pHiddenDirCheck->isChecked())
+ return QString(m_pSrcRootRequester->url()) + "/.cscope";
+
+ return m_pPathRequester->url();
+}
+
+/**
+ * Fills a structure with all user-configured project options.
+ * @param opt The structure to fill
+ */
+void NewProjectDlg::getOptions(ProjectBase::Options& opt)
+{
+ opt.sSrcRootPath = m_pSrcRootRequester->url();
+ opt.slFileTypes = m_slTypes;
+ opt.bKernel = m_pKernelCheck->isChecked();
+ opt.bInvIndex = m_pInvCheck->isChecked();
+ opt.bNoCompress = m_pNoCompCheck->isChecked();
+ opt.bSlowPathDef = m_pSlowPathCheck->isChecked();
+
+ if (m_pAutoRebuildCheck->isChecked())
+ opt.nAutoRebuildTime = m_pAutoRebuildSpin->value();
+ else
+ opt.nAutoRebuildTime = -1;
+
+ if (m_pTabWidthCheck->isChecked())
+ opt.nTabWidth = m_pTabWidthSpin->value();
+ else
+ opt.nTabWidth = 0;
+
+ opt.bACEnabled = m_pACCheck->isChecked();
+ opt.nACMinChars = m_pAutoCompDlg->m_nMinChars;
+ opt.nACDelay = m_pAutoCompDlg->m_nDelay;
+ opt.nACMaxEntries = m_pAutoCompDlg->m_nMaxEntries;
+
+ opt.sCtagsCmd = m_pCtagsCmdEdit->text();
+}
+
+/**
+ * Ends the dialog after the user has clicked the "OK" button.
+ */
+void NewProjectDlg::accept()
+{
+ int i, nCount;
+
+ // Validate the name of a new project
+ if (m_bNewProj) {
+ QRegExp re("[^ \\t\\n]+");
+ if (!re.exactMatch(m_pNameEdit->text())) {
+ KMessageBox::error(0, i18n("Project names must not contain "
+ "whitespace."));
+ return;
+ }
+ }
+
+ // Fill the string list with all file types
+ nCount = (int)m_pTypesList->count();
+ for (i = 0; i < nCount; i++)
+ m_slTypes.append(m_pTypesList->text(i));
+
+ // Clean-up the source root
+ QDir dir(m_pSrcRootRequester->url());
+ if (dir.exists())
+ m_pSrcRootRequester->setURL(dir.absPath());
+ else
+ m_pSrcRootRequester->setURL("/");
+
+ // Close the dialog
+ QDialog::accept();
+}
+
+/**
+ * Adds the the file type string in the edit-box to the list of project types.
+ * This slot is called when the "Add.." button is clicked.
+ */
+void NewProjectDlg::slotAddType()
+{
+ QString sType;
+
+ // Try the custom type edit-box first.
+ sType = m_pTypesEdit->text();
+ sType.stripWhiteSpace();
+ if (sType.isEmpty())
+ return;
+
+ // Validate the type string
+ QRegExp reg("[ \\t\\n\\|\\\\\\/]");
+ if (sType.contains(reg)) {
+ KMessageBox::error(0, i18n("This is not a valid file type!"));
+ return;
+ }
+
+ // Do not add an existing type.
+ if (m_pTypesList->findItem(sType, Qt::CaseSensitive | Qt::ExactMatch) !=
+ NULL) {
+ return;
+ }
+
+ // Add the file type to the list
+ m_pTypesList->insertItem(sType);
+ m_pTypesEdit->clear();
+}
+
+/**
+ * Removes the selected item from the list of file types.
+ * This slot is called when the "Remove" button is clicked.
+ */
+void NewProjectDlg::slotRemoveType()
+{
+ int nItem;
+ QString sType;
+
+ // Verify an item is selected
+ nItem = m_pTypesList->currentItem();
+ if (nItem == -1)
+ return;
+
+ // Remove the selected item
+ sType = m_pTypesList->currentText();
+ m_pTypesList->removeItem(nItem);
+
+ // Add to the list of available types.
+ if (m_pAvailTypesList->findItem(sType, Qt::CaseSensitive | Qt::ExactMatch)
+ == NULL) {
+ m_pAvailTypesList->insertItem(sType);
+ }
+
+}
+
+/**
+ * Changes the text in the types edit-box to reflect the current selection in
+ * the list of available types.
+ * This slot is called whenever a new item is highlighted in the list of
+ * available types.
+ * @param sType The newly selected type
+ */
+void NewProjectDlg::slotAvailTypesChanged(const QString& sType)
+{
+ m_pTypesEdit->setText(sType);
+}
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+AutoCompletionDlg::AutoCompletionDlg(QWidget* pParent,
+ const char* szName ) :
+ AutoCompletionLayout(pParent, szName)
+{
+ connect(m_pOKButton, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(m_pCancelButton, SIGNAL(clicked()), this, SLOT(reject()));
+}
+
+/**
+ * Class destructor.
+ */
+AutoCompletionDlg::~AutoCompletionDlg()
+{
+}
+
+/**
+ * Displays the dialogue, and waits for either the "OK" or "Cancel" button to
+ * be clicked.
+ * Before the dialogue is displayed, the stored values are set to the widgets.
+ * @return The dialogue's termination code
+ */
+int AutoCompletionDlg::exec()
+{
+ // Set current values
+ m_pMinCharsSpin->setValue(m_nMinChars);
+ m_pDelaySpin->setValue(m_nDelay);
+ m_pMaxEntriesSpin->setValue(m_nMaxEntries);
+
+ // Show the dialogue
+ return QDialog::exec();
+}
+
+/**
+ * Stores the values set by the user in the dialogue widgets, and terminates
+ * the dialogue.
+ * This slot is connected to the clicked() signal of the "OK" button.
+ */
+void AutoCompletionDlg::accept()
+{
+ // Store widget values
+ m_nMinChars = m_pMinCharsSpin->value();
+ m_nDelay = m_pDelaySpin->value();
+ m_nMaxEntries = m_pMaxEntriesSpin->value();
+
+ // Close the dialogue, indicating acceptance
+ QDialog::accept();
+}
+
+
+#include "newprojectdlg.moc"
diff --git a/src/newprojectdlg.h b/src/newprojectdlg.h
new file mode 100644
index 0000000..5d8e556
--- /dev/null
+++ b/src/newprojectdlg.h
@@ -0,0 +1,112 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef NEWPROJECTDLG_H
+#define NEWPROJECTDLG_H
+
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <newprojectlayout.h>
+#include <autocompletionlayout.h>
+#include "projectbase.h"
+
+/**
+ * A sub-dialogue of the New Project dialogue.
+ * Allows the user to configure auto-completion parameters.
+ * @author Elad Lahav
+ */
+class AutoCompletionDlg : public AutoCompletionLayout
+{
+ Q_OBJECT
+
+public:
+ AutoCompletionDlg(QWidget* pParent, const char* szName = NULL);
+ ~AutoCompletionDlg();
+
+public slots:
+ int exec();
+
+protected slots:
+ virtual void accept();
+
+private:
+ /** The minimum number of characters in a symbol required for automatic
+ completion. */
+ uint m_nMinChars;
+
+ /** The time, in seconds, to wait before automatic completion is
+ attempted. */
+ uint m_nDelay;
+
+ /** The maximal number of results. */
+ uint m_nMaxEntries;
+
+ friend class NewProjectDlg;
+};
+
+/**
+ * A dialog for creating new projects.
+ * Prompts the user for the project's name, the directory for Cscope's files,
+ * the types of files included in the project and several options.
+ * Can also be used to change some of the properties of a project after it
+ * has been created.
+ * @author Elad Lahav
+ */
+
+class NewProjectDlg : public NewProjectLayout
+{
+ Q_OBJECT
+
+public:
+ NewProjectDlg(bool, QWidget* pParent = NULL, const char* szName = NULL);
+ ~NewProjectDlg();
+
+ void setProperties(const QString&, const QString&,
+ const ProjectBase::Options&);
+
+ QString getName();
+ QString getPath();
+ void getOptions(ProjectBase::Options&);
+
+protected slots:
+ virtual void accept();
+ virtual void slotAddType();
+ virtual void slotRemoveType();
+ virtual void slotAvailTypesChanged(const QString&);
+
+private:
+ /** The file MIME-types associated with the new project. */
+ QStringList m_slTypes;
+
+ /** A sub-dialogue for configuring symbol auto-completion parameters. */
+ AutoCompletionDlg* m_pAutoCompDlg;
+
+ /** Whether the dialogue represents a new or existing project. */
+ bool m_bNewProj;
+};
+
+#endif
diff --git a/src/newprojectlayout.ui b/src/newprojectlayout.ui
new file mode 100644
index 0000000..841b059
--- /dev/null
+++ b/src/newprojectlayout.ui
@@ -0,0 +1,778 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>NewProjectLayout</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>NewProjectLayout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>539</width>
+ <height>383</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Create Project</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>tabWidget2</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Detai&amp;ls</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout18</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Path</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_pNameEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter a name for this project.
+The name must conform to the file system's naming conventions for directories (e.g., no spaces, exclamaion marks, etc.).</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="1" column="1">
+ <property name="name">
+ <cstring>m_pPathRequester</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The path to hold this project.
+KScope will create a directory with the given name under this project, and populate it with the project configuration and database files.
+This does not need to be the path in which the source files reside.</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pHiddenDirCheck</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Use a hidden folder under the source root directory</string>
+ </property>
+ <property name="accel">
+ <string>Alt+U</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout19</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Source Root (Optional)</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>m_pSrcRootRequester</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;blockquote&gt;A project consists of several files located in a directory
+ with the given name and path. The project's name needs to be a valid directory
+name and must not contain any whitespace.&lt;/blockquote&gt;
+&lt;br&gt;
+&lt;blockquote&gt;The Source Root is a convinient way to specify a common
+path for all source files, but is not required.&lt;/blockquote&gt;</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer29</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>31</width>
+ <height>50</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>File T&amp;ypes</string>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>This Project</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QListBox">
+ <property name="name">
+ <cstring>m_pTypesList</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>KScope uses these filters to locate source files to include in this project.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>61</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pAddButton</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;&lt; &amp;Add</string>
+ </property>
+ <property name="accel">
+ <string>Alt+A</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Adds the selected file type to the current project.</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pRemoveButton</cstring>
+ </property>
+ <property name="text">
+ <string>&gt;&gt; &amp;Remove</string>
+ </property>
+ <property name="accel">
+ <string>Alt+R</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Remove the selected file type from the project.</string>
+ </property>
+ </widget>
+ <spacer>
+ <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>21</width>
+ <height>50</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Available Types</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>m_pTypesEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>You can enter custom file types here.</string>
+ </property>
+ </widget>
+ <widget class="QListBox">
+ <item>
+ <property name="text">
+ <string>*.c</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>*.h</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>*.l</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>*.y</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>*.S</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>*.cc</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>*.cpp</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>*.cxx</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>*.C</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>*.hh</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>*.hpp</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>*.hxx</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>*.H</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_pAvailTypesList</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>A list of standard file types.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer8_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>61</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>&amp;Options</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pKernelCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Kernel project (-k)</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>For kernel projects, symbols are not looked up in the standard include path.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pInvCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Build inverted inde&amp;x (-q)</string>
+ </property>
+ <property name="accel">
+ <string>Alt+X</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>An inverted index may greatly speed up searches in a large project. The project's building process is longer, though.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pNoCompCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Do not compress the database (-c)</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pSlowPathCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Slower, but more accurate, function definition detection (-D)</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout31</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pAutoRebuildCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Refresh data&amp;base automatically</string>
+ </property>
+ <property name="accel">
+ <string>Alt+B</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Rebuild the database after changed files are saved to disk.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer32</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>125</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_pAutoRebuildLabel</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>(Seconds)</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>m_pAutoRebuildSpin</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Wait this number of seconds after the last save before rebuilding the database.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout30</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pACCheck</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Use symbol auto-completion</string>
+ </property>
+ <property name="accel">
+ <string>Alt+U</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>As-you-type symbol completion.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer33</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>61</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pACButton</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Options...</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pTabWidthCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Override default tab width (Kate only)</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Overrides the editor's configured tab width</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer9</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>211</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>m_pTabWidthSpin</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer31</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>&amp;Advanced</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_4</cstring>
+ </property>
+ <property name="text">
+ <string>Ctags command line (Do not change unless you know what you are doing!)</string>
+ </property>
+ </widget>
+ <widget class="QTextEdit">
+ <property name="name">
+ <cstring>m_pCtagsCmdEdit</cstring>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ <property name="autoFormatting">
+ <set>AutoAll</set>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout19</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>141</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pCreateButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Create</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pCancelButton</cstring>
+ </property>
+ <property name="text">
+ <string>Ca&amp;ncel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>m_pAddButton</sender>
+ <signal>clicked()</signal>
+ <receiver>NewProjectLayout</receiver>
+ <slot>slotAddType()</slot>
+ </connection>
+ <connection>
+ <sender>m_pRemoveButton</sender>
+ <signal>clicked()</signal>
+ <receiver>NewProjectLayout</receiver>
+ <slot>slotRemoveType()</slot>
+ </connection>
+ <connection>
+ <sender>m_pAutoRebuildCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_pAutoRebuildSpin</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_pACCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_pACButton</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_pAvailTypesList</sender>
+ <signal>highlighted(const QString&amp;)</signal>
+ <receiver>NewProjectLayout</receiver>
+ <slot>slotAvailTypesChanged(const QString&amp;)</slot>
+ </connection>
+ <connection>
+ <sender>m_pTabWidthCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_pTabWidthSpin</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_pAutoRebuildCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_pAutoRebuildLabel</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_pHiddenDirCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_pPathRequester</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>m_pNameEdit</tabstop>
+ <tabstop>m_pPathRequester</tabstop>
+ <tabstop>m_pHiddenDirCheck</tabstop>
+ <tabstop>m_pSrcRootRequester</tabstop>
+ <tabstop>m_pAddButton</tabstop>
+ <tabstop>m_pRemoveButton</tabstop>
+ <tabstop>m_pKernelCheck</tabstop>
+ <tabstop>m_pInvCheck</tabstop>
+ <tabstop>m_pNoCompCheck</tabstop>
+ <tabstop>m_pSlowPathCheck</tabstop>
+ <tabstop>m_pAutoRebuildCheck</tabstop>
+ <tabstop>m_pAutoRebuildSpin</tabstop>
+ <tabstop>m_pACCheck</tabstop>
+ <tabstop>m_pACButton</tabstop>
+ <tabstop>m_pTabWidthCheck</tabstop>
+ <tabstop>m_pTabWidthSpin</tabstop>
+ <tabstop>m_pCreateButton</tabstop>
+ <tabstop>m_pCancelButton</tabstop>
+ <tabstop>tabWidget2</tabstop>
+ <tabstop>m_pTypesList</tabstop>
+ <tabstop>m_pTypesEdit</tabstop>
+ <tabstop>m_pAvailTypesList</tabstop>
+ <tabstop>m_pCtagsCmdEdit</tabstop>
+</tabstops>
+<slots>
+ <slot access="protected">slotAddType()</slot>
+ <slot access="protected">slotRemoveType()</slot>
+ <slot access="protected">slotAutoRebuildChanged(bool)</slot>
+ <slot access="protected">slotAutoCompletionChanged(bool)</slot>
+ <slot access="protected">slotAvailTypesChanged(const QString&amp;)</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/src/openprojectdlg.cpp b/src/openprojectdlg.cpp
new file mode 100644
index 0000000..722fde6
--- /dev/null
+++ b/src/openprojectdlg.cpp
@@ -0,0 +1,131 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qpushbutton.h>
+#include <qlineedit.h>
+#include <qlistbox.h>
+#include <kurlrequester.h>
+#include "openprojectdlg.h"
+#include "kscopeconfig.h"
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+OpenProjectDlg::OpenProjectDlg(QWidget* pParent, const char* szName) :
+ OpenProjectLayout(pParent, szName)
+{
+ loadRecent();
+ m_pProjPathRequester->setFilter("cscope.proj");
+}
+
+/**
+ * Class destructor.
+ */
+OpenProjectDlg::~OpenProjectDlg()
+{
+}
+
+/**
+ * @return The selected project path
+ */
+QString OpenProjectDlg::getPath() const
+{
+ return m_pProjPathRequester->url();
+}
+
+/**
+ * Sets the requester to reflect the selected project's directory, instead of
+ * the cscope.proj file.
+ * @param sProjPath The full path of the selected cscope.proj file
+ */
+void OpenProjectDlg::slotProjectSelected(const QString& sProjPath)
+{
+ QFileInfo fi(sProjPath);
+ m_pProjPathRequester->setURL(fi.dirPath(true));
+}
+
+/**
+ * Removes a project from the recent projects list.
+ * This slot is connected to the clicked() signal of the "Remove" button.
+ */
+void OpenProjectDlg::slotRemoveRecent()
+{
+ QListBoxItem* pItem;
+
+ // Remove the selected item, if any
+ pItem = m_pRecentList->selectedItem();
+ if (pItem != NULL) {
+ Config().removeRecentProject(pItem->text());
+ m_pRecentList->removeItem(m_pRecentList->currentItem());
+ }
+}
+
+/**
+ * Selects a project for opening when an item is highlighted in the recent
+ * projects list.
+ * This slot is connected to the highlighted() signal of the recent projects
+ * list box.
+ * @param pItem The selected project item
+ */
+void OpenProjectDlg::slotSelectRecent(QListBoxItem* pItem)
+{
+ if (pItem != NULL)
+ m_pProjPathRequester->setURL(pItem->text());
+}
+
+/**
+ * Selects a project for opening and closes the dialogue when an item in the
+ * recent projects list is double-clicked.
+ * This slot is connected to the doubleClicked() signal of the recent
+ * projects list box.
+ * @param pItem The selected project item
+ */
+void OpenProjectDlg::slotOpenRecent(QListBoxItem* pItem)
+{
+ if (pItem != NULL) {
+ m_pProjPathRequester->setURL(pItem->text());
+ accept();
+ }
+}
+
+/**
+ * Fills the recent projects list box with the project paths read from the
+ * configuration file.
+ */
+void OpenProjectDlg::loadRecent()
+{
+ const QStringList& slProjects = Config().getRecentProjects();
+ QStringList::const_iterator itr;
+
+ // Create a list item for each project in the list
+ for (itr = slProjects.begin(); itr != slProjects.end(); ++itr)
+ m_pRecentList->insertItem(*itr);
+}
+
+#include "openprojectdlg.moc"
diff --git a/src/openprojectdlg.h b/src/openprojectdlg.h
new file mode 100644
index 0000000..cf492ad
--- /dev/null
+++ b/src/openprojectdlg.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef OPENPROJECTDLG_H
+#define OPENPROJECTDLG_H
+
+#include <qwidget.h>
+#include <openprojectlayout.h>
+
+/**
+ * A dialogue for selecting a project to open.
+ * Allows projects to be searched, and displays a list of previosuly loaded
+ * projects.
+ * @author Elad Lahav
+ */
+
+class OpenProjectDlg : public OpenProjectLayout
+{
+ Q_OBJECT
+
+public:
+ OpenProjectDlg(QWidget* pParent = 0, const char* szName = 0);
+ ~OpenProjectDlg();
+
+ QString getPath() const;
+
+protected slots:
+ virtual void slotProjectSelected(const QString&);
+ virtual void slotRemoveRecent();
+ virtual void slotSelectRecent(QListBoxItem*);
+ virtual void slotOpenRecent(QListBoxItem*);
+
+private:
+ void loadRecent();
+};
+
+#endif
diff --git a/src/openprojectlayout.ui b/src/openprojectlayout.ui
new file mode 100644
index 0000000..88d52be
--- /dev/null
+++ b/src/openprojectlayout.ui
@@ -0,0 +1,202 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>OpenProjectLayout</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>OpenProjectLayout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>417</width>
+ <height>384</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Open Project</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup5</cstring>
+ </property>
+ <property name="title">
+ <string>Project Path</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>m_pProjPathRequester</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup6</cstring>
+ </property>
+ <property name="title">
+ <string>Recent Projects</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QListBox">
+ <property name="name">
+ <cstring>m_pRecentList</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>281</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pRemoveButton</cstring>
+ </property>
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>201</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pOpenButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Open</string>
+ </property>
+ <property name="accel">
+ <string>Alt+O</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pCancelButton</cstring>
+ </property>
+ <property name="text">
+ <string>C&amp;ancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>m_pOpenButton</sender>
+ <signal>clicked()</signal>
+ <receiver>OpenProjectLayout</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>m_pCancelButton</sender>
+ <signal>clicked()</signal>
+ <receiver>OpenProjectLayout</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>m_pRemoveButton</sender>
+ <signal>clicked()</signal>
+ <receiver>OpenProjectLayout</receiver>
+ <slot>slotRemoveRecent()</slot>
+ </connection>
+ <connection>
+ <sender>m_pRecentList</sender>
+ <signal>highlighted(QListBoxItem*)</signal>
+ <receiver>OpenProjectLayout</receiver>
+ <slot>slotSelectRecent(QListBoxItem*)</slot>
+ </connection>
+ <connection>
+ <sender>m_pRecentList</sender>
+ <signal>doubleClicked(QListBoxItem*)</signal>
+ <receiver>OpenProjectLayout</receiver>
+ <slot>slotOpenRecent(QListBoxItem*)</slot>
+ </connection>
+ <connection>
+ <sender>m_pProjPathRequester</sender>
+ <signal>urlSelected(const QString&amp;)</signal>
+ <receiver>OpenProjectLayout</receiver>
+ <slot>slotProjectSelected(const QString&amp;)</slot>
+ </connection>
+ <connection>
+ <sender>m_pRecentList</sender>
+ <signal>returnPressed(QListBoxItem*)</signal>
+ <receiver>OpenProjectLayout</receiver>
+ <slot>slotOpenRecent(QListBoxItem*)</slot>
+ </connection>
+</connections>
+<slots>
+ <slot access="protected">slotRemoveRecent()</slot>
+ <slot access="protected">slotSelectRecent(QListBoxItem*)</slot>
+ <slot access="protected">slotOpenRecent(QListBoxItem*)</slot>
+ <slot access="protected">slotProjectSelected(const QString&amp;)</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/src/prefcolor.cpp b/src/prefcolor.cpp
new file mode 100644
index 0000000..85beb4b
--- /dev/null
+++ b/src/prefcolor.cpp
@@ -0,0 +1,172 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qlistview.h>
+#include <qpainter.h>
+#include <kcolordialog.h>
+#include "prefcolor.h"
+#include "kscopeconfig.h"
+
+/**
+ * A list view item that shows the name of a GUI element and the colour
+ * associated with it.
+ * The colour is presented in the form of a rectangle filled with that
+ * colour.
+ * @author Elad Lahav
+ */
+class ColorListItem : public QListViewItem
+{
+public:
+ /**
+ * Class constructor.
+ * @param pList The owner list view
+ * @param ce The GUI element shown by this item
+ */
+ ColorListItem(QListView* pList, KScopeConfig::ColorElement ce) :
+ QListViewItem(pList, Config().getColorName(ce), ""),
+ m_ce(ce) {
+ setColor(Config().getColor(ce));
+ }
+
+ /**
+ * @return The GUI element shown by this item
+ */
+ KScopeConfig::ColorElement getElement() { return m_ce; }
+
+ /**
+ * Changes the colour associated with this item.
+ * The function assigns a pixmap to the item which shows a rectangle
+ * filled with the requested colour.
+ * The colour set by this function is returned by getColor().
+ * @param clr The colour to set
+ */
+ void setColor(QColor clr) {
+ QPixmap pix;
+ QPainter painter;
+ int nWidth, nHeight;
+
+ // Remember the colour
+ m_clr = clr;
+
+ // Set the pixmap's size to fit into the list field
+ nWidth = listView()->columnWidth(1) - 1;
+ nHeight = height();
+ pix.resize(nWidth, nHeight);
+
+ // Draw on the pixmap
+ painter.begin(&pix);
+ painter.setBrush(clr);
+ painter.drawRect(0, 0, nWidth, nHeight);
+ painter.end();
+
+ // Set the pixmap to the item
+ setPixmap(1, pix);
+ }
+
+ /**
+ * @return The colour associated with this item
+ */
+ QColor getColor() { return m_clr; }
+
+private:
+ /** The GUI element shown by this item. */
+ KScopeConfig::ColorElement m_ce;
+
+ /** The colour associated with this item. */
+ QColor m_clr;
+};
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+PrefColor::PrefColor(QWidget* pParent, const char* szName) :
+ PrefColorLayout(pParent, szName)
+{
+ m_pList->setColumnWidthMode(1, QListView::Manual);
+
+ // Set initial values
+ load();
+}
+
+/**
+ * Class destructor.
+ */
+PrefColor::~PrefColor()
+{
+}
+
+/**
+ * Reads the current settings from the configuration object, and applies them
+ * the the page's widget.
+ */
+void PrefColor::load()
+{
+ uint i;
+ ColorListItem* pItem;
+
+ // Create a list item for every GUI element
+ for (i = 0; i <= KScopeConfig::LAST_COLOR; i++)
+ pItem = new ColorListItem(m_pList, (KScopeConfig::ColorElement)i);
+}
+
+/**
+ * Commits settings changes to the configuration object.
+ */
+void PrefColor::apply()
+{
+ ColorListItem* pItem;
+
+ // Create a list item for every GUI element
+ for (pItem = (ColorListItem*)m_pList->firstChild(); pItem != NULL;
+ pItem = (ColorListItem*)pItem->nextSibling()) {
+ Config().setColor(pItem->getElement(), pItem->getColor());
+ }
+}
+
+/**
+ * Displays a colour selection dialogue when an item is selected.
+ * If the user chooses a new colour, it is set to the selected item.
+ * This slot is connected to both the doubleClicked() and the returnPressed()
+ * signals of the list view.
+ * @param pItem The selected item
+ */
+void PrefColor::slotItemSelected(QListViewItem* pItem)
+{
+ ColorListItem* pClrItem;
+ QColor clr;
+
+ pClrItem = (ColorListItem*)pItem;
+ if (KColorDialog::getColor(clr, pClrItem->getColor()) ==
+ QDialog::Accepted) {
+ pClrItem->setColor(clr);
+ emit modified();
+ }
+}
+
+#include "prefcolor.moc"
diff --git a/src/prefcolor.h b/src/prefcolor.h
new file mode 100644
index 0000000..b26bed2
--- /dev/null
+++ b/src/prefcolor.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef PREFCOLORDLG_H
+#define PREFCOLORDLG_H
+
+#include <prefcolorlayout.h>
+
+/**
+ * A widget for selecting colours for KScope's main child-windows.
+ * @author Elad Lahav
+ */
+class PrefColor : public PrefColorLayout
+{
+ Q_OBJECT
+
+public:
+ PrefColor(QWidget* pParent = 0, const char* szName = 0);
+ ~PrefColor();
+
+ void load();
+ void apply();
+
+signals:
+ /**
+ * Emitted whenever the user makes a change to the dialogue's input
+ * widgets.
+ */
+ void modified();
+
+protected slots:
+ void slotItemSelected(QListViewItem*);
+};
+
+#endif
diff --git a/src/prefcolorlayout.ui b/src/prefcolorlayout.ui
new file mode 100644
index 0000000..8e15bda
--- /dev/null
+++ b/src/prefcolorlayout.ui
@@ -0,0 +1,69 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>PrefColorLayout</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>PrefColorLayout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>350</width>
+ <height>210</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Form4</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QListView">
+ <column>
+ <property name="text">
+ <string>GUI Element</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Colour</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_pList</cstring>
+ </property>
+ </widget>
+ </hbox>
+</widget>
+<connections>
+ <connection>
+ <sender>m_pList</sender>
+ <signal>doubleClicked(QListViewItem*)</signal>
+ <receiver>PrefColorLayout</receiver>
+ <slot>slotItemSelected(QListViewItem*)</slot>
+ </connection>
+ <connection>
+ <sender>m_pList</sender>
+ <signal>returnPressed(QListViewItem*)</signal>
+ <receiver>PrefColorLayout</receiver>
+ <slot>slotItemSelected(QListViewItem*)</slot>
+ </connection>
+</connections>
+<slots>
+ <slot access="protected">slotItemSelected(QListViewItem*)</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/src/preferencesdlg.cpp b/src/preferencesdlg.cpp
new file mode 100644
index 0000000..ab13c33
--- /dev/null
+++ b/src/preferencesdlg.cpp
@@ -0,0 +1,206 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qlayout.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kurlrequester.h>
+#include <klineedit.h>
+#include <qcheckbox.h>
+#include <kcolorbutton.h>
+#include <kmessagebox.h>
+#include <kfontrequester.h>
+#include "preferencesdlg.h"
+#include "preffrontend.h"
+#include "prefcolor.h"
+#include "preffont.h"
+#include "prefopt.h"
+#include "kscopeconfig.h"
+#include "cscopefrontend.h"
+#include "ctagsfrontend.h"
+#include "dotfrontend.h"
+
+
+/**
+ * Class constructor.
+ * @param nPage The initial page to show
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+PreferencesDlg::PreferencesDlg(uint nPage, QWidget* pParent,
+ const char* szName) :
+ KDialogBase(IconList, i18n("Preferences"), Default | Ok | Apply | Cancel,
+ Ok, pParent, szName, 0)
+{
+ QFrame* pFrame;
+ QVBoxLayout* pLayout;
+
+ // Create and add the "Frontend" page
+ pFrame = addPage(i18n("Programmes"),
+ i18n("Paths to back-end programmes"),
+ KGlobal::iconLoader()->loadIcon("run", KIcon::Panel, 0, false));
+ pLayout = new QVBoxLayout(pFrame, 0, 0);
+ m_pPrefFrontend = new PrefFrontend(pFrame);
+ pLayout->addWidget(m_pPrefFrontend);
+
+ // Create and add the "Colours" page
+ pFrame = addPage(i18n("Colours"), i18n("Window colours"),
+ KGlobal::iconLoader()->loadIcon("colors", KIcon::Panel, 0, false));
+ pLayout = new QVBoxLayout(pFrame, 0, 0);
+ m_pPrefColor = new PrefColor(pFrame);
+ pLayout->addWidget(m_pPrefColor);
+
+ // Create and add the "Fonts" page
+ pFrame = addPage(i18n("Fonts"), i18n("Window fonts"),
+ KGlobal::iconLoader()->loadIcon("fonts", KIcon::Panel, 0, false));
+ pLayout = new QVBoxLayout(pFrame, 0, 0);
+ m_pPrefFont = new PrefFont(pFrame);
+ pLayout->addWidget(m_pPrefFont);
+
+ // Create and add the "Options" page
+ pFrame = addPage(i18n("Options"), i18n("Misc. Options"),
+ KGlobal::iconLoader()->loadIcon("package_settings",
+ KIcon::Panel, 0, false));
+ pLayout = new QVBoxLayout(pFrame, 0, 0);
+ m_pPrefOpt = new PrefOpt(pFrame);
+ pLayout->addWidget(m_pPrefOpt);
+
+ // Make sure the "Apply" button is initially disabled
+ enableButtonApply(false);
+
+ // Enable the "Apply" button when a parameter changes its value
+ connect(m_pPrefFrontend, SIGNAL(modified()), this,
+ SLOT(slotModified()));
+ connect(m_pPrefColor, SIGNAL(modified()), this, SLOT(slotModified()));
+ connect(m_pPrefFont, SIGNAL(modified()), this, SLOT(slotModified()));
+ connect(m_pPrefOpt, SIGNAL(modified()), this, SLOT(slotModified()));
+
+ // Set the active page
+ showPage(nPage);
+}
+
+/**
+ * Class destructor.
+ */
+PreferencesDlg::~PreferencesDlg()
+{
+}
+
+/**
+ * Updates the dialog's widgets with the current configuration parameters.
+ */
+void PreferencesDlg::loadConfig()
+{
+ m_pPrefFrontend->load();
+ m_pPrefColor->load();
+ m_pPrefFont->load();
+ m_pPrefOpt->load();
+}
+
+/**
+ * Sets the configured parameters to the global configuration object.
+ * This method is called when either the "OK" or the "Apply" button are
+ * clicked. Before the new settings are applied, their values are verified.
+ * @return true if the new parameters were applied successfully, false
+ * otherwise
+ */
+bool PreferencesDlg::updateConfig()
+{
+ // Verify configured paths lead to the executables
+ if (!verifyPaths())
+ return false;
+
+ // Apply the changes
+ m_pPrefFrontend->apply();
+ m_pPrefColor->apply();
+ m_pPrefFont->apply();
+ m_pPrefOpt->apply();
+
+ emit applyPref();
+ return true;
+}
+
+/**
+ * Tests whether the paths set for Cscope and Ctags lead to executables.
+ * Cscope is verified by a different process.
+ */
+bool PreferencesDlg::verifyPaths()
+{
+ return (CtagsFrontend::verify(m_pPrefFrontend->m_pCtagsURL->url()) &&
+ DotFrontend::verify(m_pPrefFrontend->m_pDotURL->url()));
+}
+
+/**
+ * Updates the global configuration based on the values given in the
+ * preferences dialogue, and then closes the dialogue.
+ * This function is called after the user clicks the dialogue's "OK" button.
+ */
+void PreferencesDlg::accept()
+{
+ if (updateConfig())
+ KDialogBase::accept();
+}
+
+/**
+ * Updates the global configuration based on the values given in the
+ * preferences dialogue, leaving the dialogue open.
+ * This function is called after the user clicks the dialogue's "Apply"
+ * button.
+ */
+void PreferencesDlg::slotApply()
+{
+ if (updateConfig())
+ enableButtonApply(false);
+}
+
+/**
+ * Resets all configuration parameters to their default values.
+ * This slot is called when the user clicks the "Default" button.
+ */
+void PreferencesDlg::slotDefault()
+{
+ // Prompt the user before applying default values
+ if (KMessageBox::questionYesNo(0, i18n("This would reset all your "
+ "configuration settings! Continue?")) == KMessageBox::Yes) {
+ // Load the default values
+ Config().loadDefault();
+ loadConfig();
+
+ // Apply the default values
+ slotApply();
+ }
+}
+
+/**
+ * Enables the "Apply" button.
+ */
+void PreferencesDlg::slotModified()
+{
+ enableButtonApply(true);
+}
+
+#include "preferencesdlg.moc"
diff --git a/src/preferencesdlg.h b/src/preferencesdlg.h
new file mode 100644
index 0000000..51fa2cb
--- /dev/null
+++ b/src/preferencesdlg.h
@@ -0,0 +1,93 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef PREFERENCESDLG_H
+#define PREFERENCESDLG_H
+
+#include <qwidget.h>
+#include <kdialogbase.h>
+
+class PrefFrontend;
+class PrefColor;
+class PrefFont;
+class PrefOpt;
+
+/**
+ * The main configuration dialog for KScope.
+ * This dialog displays a set of configuration pages, each dedicated to a
+ * different subject (frontend programme paths, colours, etc.)
+ * This code is based on a tutorial by Andreas Nicolai which can be found at
+ * http://www.kdevelop.org/doc/tutorial_settings
+ * @author Elad Lahav
+ */
+
+class PreferencesDlg : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ PreferencesDlg(uint nPage = Frontend, QWidget* pParent = 0, const char*
+ szName = 0);
+ ~PreferencesDlg();
+
+ /** Available pages. */
+ enum { Frontend = 0, Colors, Fonts, Options };
+
+signals:
+ /**
+ * Emitted when the global configuration changes as a result of using
+ * this dialogue.
+ */
+ void applyPref();
+
+protected slots:
+ virtual void accept();
+ virtual void slotApply();
+ virtual void slotDefault();
+
+private:
+ /** The front-end programmes page. */
+ PrefFrontend* m_pPrefFrontend;
+
+ /** The colours preference page. */
+ PrefColor* m_pPrefColor;
+
+ /** The fonts preference page. */
+ PrefFont* m_pPrefFont;
+
+ /** The additional options page. */
+ PrefOpt* m_pPrefOpt;
+
+ void loadConfig();
+ bool updateConfig();
+ bool verifyPaths();
+
+private slots:
+ void slotModified();
+};
+
+#endif
diff --git a/src/preffont.cpp b/src/preffont.cpp
new file mode 100644
index 0000000..288c699
--- /dev/null
+++ b/src/preffont.cpp
@@ -0,0 +1,174 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qlistview.h>
+#include <qpainter.h>
+#include <kfontdialog.h>
+#include <klocale.h>
+#include "preffont.h"
+#include "kscopeconfig.h"
+
+/**
+ * A list view item that shows the name of a GUI element and the font
+ * associated with it.
+ * The font is presented in the form of a sample text drawn using this font.
+ * @author Elad Lahav
+ */
+class FontListItem : public QListViewItem
+{
+public:
+ /**
+ * Class constructor.
+ * @param pList The owner list view
+ * @param fe The GUI element shown by this item
+ */
+ FontListItem(QListView* pList, KScopeConfig::FontElement fe) :
+ QListViewItem(pList, Config().getFontName(fe), ""),
+ m_fe(fe) {
+ setFont(Config().getFont(fe));
+ }
+
+ /**
+ * @return The GUI element shown by this item
+ */
+ KScopeConfig::FontElement getElement() { return m_fe; }
+
+ /**
+ * Changes the font associated with this item.
+ * The function a sample text on a pixmap using this font, and then
+ * assigns the pixmap to the list item.
+ * The font set by this function is returned by getFont().
+ * @param font The font to set
+ */
+ void setFont(QFont font) {
+ QPixmap pix;
+ QFontMetrics fm(font);
+ QPainter painter;
+ QRect rc;
+
+ // Remember the font
+ m_font = font;
+
+ // Set the pixmap's size so it can contain the sample text
+ rc = fm.boundingRect(i18n("Sample"));
+ rc.moveTopLeft(QPoint(0, 0));
+ pix.resize(rc.width(), rc.height());
+
+ // Draw on the pixmap
+ pix.fill();
+ painter.begin(&pix);
+ painter.setFont(font);
+ painter.setPen(black);
+ painter.drawText(rc, Qt::AlignHCenter | Qt::AlignVCenter,
+ i18n("Sample"));
+ painter.end();
+
+ // Set the pixmap to the item
+ setPixmap(1, pix);
+ }
+
+ /**
+ * @return The font associated with this item
+ */
+ QFont getFont() { return m_font; }
+
+private:
+ /** The GUI element shown by this item. */
+ KScopeConfig::FontElement m_fe;
+
+ /** The font associated with this item. */
+ QFont m_font;
+};
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+PrefFont::PrefFont(QWidget* pParent, const char* szName) :
+ PrefFontLayout(pParent, szName)
+{
+ // Set initial values
+ load();
+}
+
+/**
+ * Class destructor.
+ */
+PrefFont::~PrefFont()
+{
+}
+
+/**
+ * Reads the current settings from the configuration object, and applies them
+ * the the page's widget.
+ */
+void PrefFont::load()
+{
+ uint i;
+ FontListItem* pItem;
+
+ // Create a list item for every GUI element
+ for (i = 0; i <= KScopeConfig::LAST_FONT; i++)
+ pItem = new FontListItem(m_pList, (KScopeConfig::FontElement)i);
+}
+
+/**
+ * Commits settings changes to the configuration object.
+ */
+void PrefFont::apply()
+{
+ FontListItem* pItem;
+
+ // Create a list item for every GUI element
+ for (pItem = (FontListItem*)m_pList->firstChild(); pItem != NULL;
+ pItem = (FontListItem*)pItem->nextSibling()) {
+ Config().setFont(pItem->getElement(), pItem->getFont());
+ }
+}
+
+/**
+ * Displays a font selection dialogue when an item is selected.
+ * If the user chooses a new font, it is set to the selected item.
+ * This slot is connected to both the doubleClicked() and the returnPressed()
+ * signals of the list view.
+ * @param pItem The selected item
+ */
+void PrefFont::slotItemSelected(QListViewItem* pItem)
+{
+ FontListItem* pFontItem;
+ QFont font;
+
+ pFontItem = (FontListItem*)pItem;
+ font = pFontItem->getFont();
+ if (KFontDialog::getFont(font) == QDialog::Accepted) {
+ pFontItem->setFont(font);
+ emit modified();
+ }
+}
+
+#include "preffont.moc"
diff --git a/src/preffont.h b/src/preffont.h
new file mode 100644
index 0000000..66fdebc
--- /dev/null
+++ b/src/preffont.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef PREFFONT_H
+#define PREFFONT_H
+
+#include "preffontlayout.h"
+
+/**
+ * A widget for selecting fonts for KScope's main child-windows.
+ * @author Elad Lahav
+ */
+
+class PrefFont : public PrefFontLayout
+{
+ Q_OBJECT
+
+public:
+ PrefFont(QWidget* pParent = 0, const char* szName = 0);
+ ~PrefFont();
+
+ void load();
+ void apply();
+
+signals:
+ /**
+ * Emitted whenever the user makes a change to the dialogue's input
+ * widgets.
+ */
+ void modified();
+
+protected slots:
+ void slotItemSelected(QListViewItem*);
+};
+
+#endif
diff --git a/src/preffontlayout.ui b/src/preffontlayout.ui
new file mode 100644
index 0000000..983da52
--- /dev/null
+++ b/src/preffontlayout.ui
@@ -0,0 +1,69 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>PrefFontLayout</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>PrefFontLayout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>363</width>
+ <height>210</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Form4</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QListView">
+ <column>
+ <property name="text">
+ <string>GUI Element</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Font</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_pList</cstring>
+ </property>
+ </widget>
+ </hbox>
+</widget>
+<connections>
+ <connection>
+ <sender>m_pList</sender>
+ <signal>doubleClicked(QListViewItem*)</signal>
+ <receiver>PrefFontLayout</receiver>
+ <slot>slotItemSelected(QListViewItem*)</slot>
+ </connection>
+ <connection>
+ <sender>m_pList</sender>
+ <signal>returnPressed(QListViewItem*)</signal>
+ <receiver>PrefFontLayout</receiver>
+ <slot>slotItemSelected(QListViewItem*)</slot>
+ </connection>
+</connections>
+<slots>
+ <slot access="protected">slotItemSelected(QListViewItem*)</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/src/preffrontend.cpp b/src/preffrontend.cpp
new file mode 100644
index 0000000..3bedda7
--- /dev/null
+++ b/src/preffrontend.cpp
@@ -0,0 +1,238 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qcheckbox.h>
+#include <qtextedit.h>
+#include <kurlrequester.h>
+#include <klineedit.h>
+#include <kstandarddirs.h>
+#include <klocale.h>
+#include "preffrontend.h"
+#include "kscopeconfig.h"
+#include "configfrontend.h"
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+PrefFrontend::PrefFrontend(QWidget* pParent, const char* szName) :
+ PrefFrontendLayout(pParent, szName)
+{
+ // Set initial values
+ load();
+
+ // Attempt to guess paths based on the user's PATH environment variable
+ connect(m_pGuessButton, SIGNAL(clicked()), this,
+ SLOT(slotGuessPaths()));
+
+ // Emit the modified() signal when a new path is set
+ connect(m_pCscopeURL, SIGNAL(textChanged(const QString&)), this,
+ SIGNAL(modified()));
+ connect(m_pCtagsURL, SIGNAL(textChanged(const QString&)), this,
+ SIGNAL(modified()));
+ connect(m_pDotURL, SIGNAL(textChanged(const QString&)), this,
+ SIGNAL(modified()));
+}
+
+/**
+ * Class destructor.
+ */
+PrefFrontend::~PrefFrontend()
+{
+}
+
+/**
+ * Reads the current settings from the configuration object, and applies them
+ * the the page's widget.
+ */
+void PrefFrontend::load()
+{
+ m_pCscopeURL->lineEdit()->setText(Config().getCscopePath());
+ m_pCtagsURL->lineEdit()->setText(Config().getCtagsPath());
+ m_pDotURL->lineEdit()->setText(Config().getDotPath());
+}
+
+/**
+ * Commits settings changes to the configuration object.
+ */
+void PrefFrontend::apply()
+{
+ Config().setCscopePath(m_pCscopeURL->url());
+ Config().setCtagsPath(m_pCtagsURL->url());
+ Config().setDotPath(m_pDotURL->url());
+}
+
+/**
+ * Emits the modified() signal whenever any of the paths edit widgets changes
+ * its contents.
+ * This slot is connected to the textChanged() signal of each of the path
+ * edit widgets. By emitting the modified() signal, the widget notifies the
+ * parent dialog it should enable the "Apply" button.
+ */
+void PrefFrontend::slotChanged(const QString&)
+{
+ emit modified();
+}
+
+/**
+ * Checks the user's PATH environment variable for a Cscope and Ctags
+ * executables.
+ * This is done by running the kscope_config script.
+ */
+void PrefFrontend::slotGuessPaths()
+{
+ ConfigFrontend* pConf;
+
+ // Start with an empty results text widget
+ m_pScriptText->clear();
+
+ // Create a frontend object for the script
+ pConf = new ConfigFrontend(true);
+
+ // Show tests and results in the text widget
+ connect(pConf, SIGNAL(test(uint)), this,
+ SLOT(slotAutoConfigTest(uint)));
+ connect(pConf, SIGNAL(result(uint, const QString&)), this,
+ SLOT(slotAutoConfigResult(uint, const QString&)));
+
+ // Run the script
+ pConf->run(m_pCscopeURL->url(), m_pCtagsURL->url(),
+ m_pDotURL->url());
+}
+
+/**
+ * Shows the test being executed by the script in the text widget.
+ * This slot is connected to the test() signal of the ConfigFrontend object.
+ * @param nType The type of test being executed
+ */
+void PrefFrontend::slotAutoConfigTest(uint nType)
+{
+ switch (nType) {
+ case ConfigFrontend::CscopePath:
+ m_pScriptText->insert(i18n("Looking for Cscope..."));
+ break;
+
+ case ConfigFrontend::CscopeVersion:
+ m_pScriptText->insert(i18n("Checking Cscope version..."));
+ break;
+
+ case ConfigFrontend::CscopeVerbose:
+ m_pScriptText->insert(i18n("Cscope support for line mode verbose "
+ "output..."));
+ break;
+
+ case ConfigFrontend::CscopeSlowPath:
+ m_pScriptText->insert(i18n("Cscope support slow path definitions... "));
+ break;
+
+ case ConfigFrontend::CtagsPath:
+ m_pScriptText->insert(i18n("Looking for Ctags..."));
+ break;
+
+ case ConfigFrontend::CtagsExub:
+ m_pScriptText->insert(i18n("Ctags compatibilty with ctags-exuberant"
+ "..."));
+ break;
+
+ case ConfigFrontend::DotPath:
+ m_pScriptText->insert(i18n("Looking for Dot..."));
+ break;
+
+ case ConfigFrontend::DotPlain:
+ m_pScriptText->insert(i18n("Checking -Tplain..."));
+ break;
+ }
+}
+
+/**
+ * Shows the result of a test executed by the configuration script, and
+ * adjusts the configuration widgets accordingly.
+ * @param nType The type of test that was executed
+ * @param sResult The test's result
+ */
+void PrefFrontend::slotAutoConfigResult(uint nType, const QString& sResult)
+{
+ QString sLine;
+
+ sLine = sResult + "\n";
+
+ switch (nType) {
+ case ConfigFrontend::CscopePath:
+ m_pScriptText->insert(sLine);
+ if (sResult == "ERROR")
+ m_pCscopeURL->lineEdit()->setText("");
+ else
+ m_pCscopeURL->lineEdit()->setText(sResult);
+
+ break;
+
+ case ConfigFrontend::CscopeVersion:
+ m_pScriptText->insert(sLine);
+ if (sResult == "ERROR")
+ m_pCscopeURL->lineEdit()->setText("");
+ break;
+
+ case ConfigFrontend::CscopeVerbose:
+ m_pScriptText->insert(sLine);
+ break;
+
+ case ConfigFrontend::CscopeSlowPath:
+ m_pScriptText->insert(sLine);
+ break;
+
+ case ConfigFrontend::CtagsPath:
+ m_pScriptText->insert(sLine);
+ if (sResult == "ERROR")
+ m_pCtagsURL->lineEdit()->setText("");
+ else
+ m_pCtagsURL->lineEdit()->setText(sResult);
+ break;
+
+ case ConfigFrontend::CtagsExub:
+ m_pScriptText->insert(sLine);
+ if (sResult == "ERROR")
+ m_pCtagsURL->lineEdit()->setText("");
+ break;
+
+ case ConfigFrontend::DotPath:
+ m_pScriptText->insert(sLine);
+ if (sResult == "ERROR")
+ m_pDotURL->lineEdit()->setText("");
+ else
+ m_pDotURL->lineEdit()->setText(sResult);
+ break;
+
+ case ConfigFrontend::DotPlain:
+ m_pScriptText->insert(sLine);
+ if (sResult == "ERROR")
+ m_pDotURL->lineEdit()->setText("");
+ break;
+ }
+}
+
+#include "preffrontend.moc"
diff --git a/src/preffrontend.h b/src/preffrontend.h
new file mode 100644
index 0000000..fb46242
--- /dev/null
+++ b/src/preffrontend.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef PREFFRONTENDDLG_H
+#define PREFFRONTENDDLG_H
+
+#include <qwidget.h>
+#include <preffrontendlayout.h>
+
+/**
+ * A widget for setting the paths to various programmes to which KScope
+ * provides a front-end.
+ * @author Elad Lahav
+ */
+
+class PrefFrontend : public PrefFrontendLayout
+{
+ Q_OBJECT
+
+public:
+ PrefFrontend(QWidget* pParent = 0, const char* szName = 0);
+ ~PrefFrontend();
+
+ void load();
+ void apply();
+
+signals:
+ /**
+ * Emitted whenever the user makes a change to the dialogue's input
+ * widgets.
+ */
+ void modified();
+
+private slots:
+ void slotChanged(const QString&);
+ void slotGuessPaths();
+ void slotAutoConfigTest(uint);
+ void slotAutoConfigResult(uint, const QString&);
+};
+
+#endif
diff --git a/src/preffrontendlayout.ui b/src/preffrontendlayout.ui
new file mode 100644
index 0000000..e6b00c9
--- /dev/null
+++ b/src/preffrontendlayout.ui
@@ -0,0 +1,193 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>PrefFrontendLayout</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>PrefFrontendLayout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>415</width>
+ <height>368</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Form3</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout20</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout19</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Cscope path:</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Ctags path:</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Dot path:</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout18</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>m_pCscopeURL</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>m_pCtagsURL</cstring>
+ </property>
+ </widget>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>m_pDotURL</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>261</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pGuessButton</cstring>
+ </property>
+ <property name="text">
+ <string>G&amp;uess</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QTextEdit">
+ <property name="name">
+ <cstring>m_pScriptText</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<tabstops>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/src/prefopt.cpp b/src/prefopt.cpp
new file mode 100644
index 0000000..7b52d8f
--- /dev/null
+++ b/src/prefopt.cpp
@@ -0,0 +1,145 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qcheckbox.h>
+#include <qradiobutton.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include "prefopt.h"
+#include "kscopeconfig.h"
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+PrefOpt::PrefOpt(QWidget* pParent, const char* szName)
+ : PrefOptLayout(pParent, szName)
+{
+ // Set initial values
+ load();
+
+ // Emit the "modified" signal whenever any of the widgets changes its
+ // its. This will notify the parent dialogue to enable its "Apply"
+ // button
+ connect(m_pReadOnlyCheck, SIGNAL(toggled(bool)), this,
+ SIGNAL(modified()));
+ connect(m_pLastProjCheck, SIGNAL(toggled(bool)), this,
+ SIGNAL(modified()));
+ connect(m_pTagHlCheck, SIGNAL(toggled(bool)), this,
+ SIGNAL(modified()));
+ connect(m_pBriefQueryCaptCheck, SIGNAL(toggled(bool)), this,
+ SIGNAL(modified()));
+ connect(m_pWarnModifiedOnDiskCheck, SIGNAL(toggled(bool)), this,
+ SIGNAL(modified()));
+ connect(m_pAutoSortCheck, SIGNAL(toggled(bool)), this,
+ SIGNAL(modified()));
+ connect(m_pExtEditorEdit, SIGNAL(textChanged(const QString&)), this,
+ SIGNAL(modified()));
+ connect(m_pSysProfileCB, SIGNAL(activated(int)), this,
+ SIGNAL(modified()));
+ connect(m_pEditorPopupCB, SIGNAL(activated(int)), this,
+ SIGNAL(modified()));
+}
+
+/**
+ * Class destructor.
+ */
+PrefOpt::~PrefOpt()
+{
+}
+
+/**
+ * Reads the current settings from the configuration object, and applies them
+ * the the page's widget.
+ */
+void PrefOpt::load()
+{
+ m_pReadOnlyCheck->setChecked(Config().getReadOnlyMode());
+ m_pLastProjCheck->setChecked(Config().getLoadLastProj());
+ m_pTagHlCheck->setChecked(Config().getAutoTagHl());
+ m_pBriefQueryCaptCheck->setChecked(Config().getUseBriefQueryCaptions());
+ m_pWarnModifiedOnDiskCheck->setChecked(Config().getWarnModifiedOnDisk());
+ m_pAutoSortCheck->setChecked(Config().getAutoSortFiles());
+ m_pExtEditorEdit->setText(Config().getExtEditor());
+
+ switch (Config().getSysProfile()) {
+ case KScopeConfig::Fast:
+ m_pSysProfileCB->setCurrentItem(0);
+ break;
+
+ case KScopeConfig::Slow:
+ m_pSysProfileCB->setCurrentItem(1);
+ break;
+ }
+
+ switch (Config().getEditorPopup()) {
+ case KScopeConfig::Embedded:
+ m_pEditorPopupCB->setCurrentItem(0);
+ break;
+
+ case KScopeConfig::KScopeOnly:
+ m_pEditorPopupCB->setCurrentItem(1);
+ break;
+ }
+}
+
+/**
+ * Commits settings changes to the configuration object.
+ */
+void PrefOpt::apply()
+{
+ Config().setReadOnlyMode(m_pReadOnlyCheck->isChecked());
+ Config().setLoadLastProj(m_pLastProjCheck->isChecked());
+ Config().setAutoTagHl(m_pTagHlCheck->isChecked());
+ Config().setUseBriefQueryCaptions(m_pBriefQueryCaptCheck->isChecked());
+ Config().setWarnModifiedOnDisk(m_pWarnModifiedOnDiskCheck->isChecked());
+ Config().setAutoSortFiles(m_pAutoSortCheck->isChecked());
+ Config().setExtEditor(m_pExtEditorEdit->text());
+
+ switch (m_pSysProfileCB->currentItem()) {
+ case 0 :
+ Config().setSysProfile(KScopeConfig::Fast);
+ break;
+
+ case 1:
+ Config().setSysProfile(KScopeConfig::Slow);
+ break;
+ }
+
+ switch (m_pEditorPopupCB->currentItem()) {
+ case 0:
+ Config().setEditorPopup(KScopeConfig::Embedded);
+ break;
+
+ case 1:
+ Config().setEditorPopup(KScopeConfig::KScopeOnly);
+ break;
+ }
+}
+
+#include "prefopt.moc"
diff --git a/src/prefopt.h b/src/prefopt.h
new file mode 100644
index 0000000..26e2572
--- /dev/null
+++ b/src/prefopt.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef PREFOPT_H
+#define PREFOPT_H
+
+#include "prefoptlayout.h"
+
+/**
+ * A widget for setting different global options.
+ * @author Elad Lahav
+ */
+
+class PrefOpt : public PrefOptLayout
+{
+ Q_OBJECT
+
+public:
+ PrefOpt(QWidget* pParent = 0, const char* szName = 0);
+ ~PrefOpt();
+
+ void load();
+ void apply();
+
+signals:
+ /**
+ * Emitted whenever the user makes a change to the dialogue's input
+ * widgets.
+ */
+ void modified();
+};
+
+#endif
+
diff --git a/src/prefoptlayout.ui b/src/prefoptlayout.ui
new file mode 100644
index 0000000..cbc8d07
--- /dev/null
+++ b/src/prefoptlayout.ui
@@ -0,0 +1,217 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>PrefOptLayout</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>PrefOptLayout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>354</width>
+ <height>312</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Form4</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Determines whether KScope should automatically load the last project when started.</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_pExtEditorLabel</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>External Editor</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>m_pExtEditorEdit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pReadOnlyCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Read-Onl&amp;y Mode</string>
+ </property>
+ <property name="accel">
+ <string>Alt+Y</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Forces all editor windows to work in a read-only mode, so that the user cannot modify the displayed files.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pLastProjCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Open Last Project on Start-Up</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pTagHlCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Automatic Tag Highlighting</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Determines whether the tag list should highlight the relevant tag based on the cursor's position.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pBriefQueryCaptCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Brief Tab Captions for &amp;Query Pages</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If set, the tab captions for query pages will be shortened, by using aliases for the query types.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pWarnModifiedOnDiskCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Warn When a File is Modified Outside KScope</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If set, the user is prompted whenever the currently edited file is changed by an external programme.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pAutoSortCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Automatically Sort Files in the File List</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Sorts files in the project's file list when a project is loaded. This may be too slow for large projects on older machines.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>System Profile</string>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <item>
+ <property name="text">
+ <string>Fast</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Slow</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_pSysProfileCB</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Editor Popup Menu</string>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <item>
+ <property name="text">
+ <string>Embedded</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>KScope Only</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_pEditorPopupCB</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer11</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/src/progressdlg.cpp b/src/progressdlg.cpp
new file mode 100644
index 0000000..418a3c9
--- /dev/null
+++ b/src/progressdlg.cpp
@@ -0,0 +1,116 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include "progressdlg.h"
+
+/**
+ * Class constructor.
+ * @param sCaption The dialogue's title
+ * @param sText The text to display
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+ProgressDlg::ProgressDlg(const QString& sCaption, const QString& sText,
+ QWidget* pParent, const char* szName) :
+ KProgressDialog(pParent, szName, sCaption, sText, true),
+ m_nIdleValue(-1)
+{
+ setAutoClose(false);
+ setAllowCancel(false);
+
+ // Create the idle-progress timer
+ m_pIdleTimer = new QTimer(this);
+
+ // Display a busy indicator by increasing the value of the idle counter
+ connect (m_pIdleTimer, SIGNAL(timeout()), this, SLOT(slotShowBusy()));
+}
+
+/**
+ * Class destructor.
+ */
+ProgressDlg::~ProgressDlg()
+{
+}
+
+/**
+ * Sets a new value to the progress bar.
+ * If the new value is non-zero, the progress bar is advanced. Otherwise, the
+ * idle timer is initiated to display a busy indicator.
+ * @param nValue The new value to set.
+ */
+void ProgressDlg::setValue(int nValue)
+{
+ KProgress* pProgress;
+
+ pProgress = progressBar();
+
+ if (nValue != 0) {
+ // Do nothing if the value hasn't changed
+ if (nValue == pProgress->progress())
+ return;
+
+ // Handle first non-zero value
+ if (m_nIdleValue >= 0) {
+ m_pIdleTimer->stop();
+ m_nIdleValue = -1;
+ pProgress->setPercentageVisible(true);
+ }
+
+ // Set the new value
+ pProgress->setValue(nValue);
+ }
+ else if (m_nIdleValue == -1) {
+ // Handle first 0 value
+ pProgress->setValue(0);
+ pProgress->setPercentageVisible(false);
+ m_nIdleValue = 0;
+ m_pIdleTimer->start(200);
+ }
+}
+
+void ProgressDlg::setIdle()
+{
+ m_nIdleValue = -1;
+ setValue(0);
+}
+
+/**
+ * Increaes the value of the dummy counter by 1.
+ * This slot is called by the timeout() event of the idle timer.
+ */
+void ProgressDlg::slotShowBusy()
+{
+ // Increase the counter
+ m_nIdleValue += 5;
+ if (m_nIdleValue == 100)
+ m_nIdleValue = 0;
+
+ // Set the value of the progress-bar
+ progressBar()->setValue(m_nIdleValue);
+}
+
+#include "progressdlg.moc"
diff --git a/src/progressdlg.h b/src/progressdlg.h
new file mode 100644
index 0000000..d5f0e6b
--- /dev/null
+++ b/src/progressdlg.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef PROGRESSDLG_H
+#define PROGRESSDLG_H
+
+#include <qwidget.h>
+#include <qtimer.h>
+#include <kprogress.h>
+
+/**
+ * An improved progress dialog.
+ * This variation of the standard KDE progress dialog displays a busy
+ * indicator while waiting for the first value greater than 0.
+ * @author Elad Lahav
+ */
+
+class ProgressDlg : public KProgressDialog
+{
+ Q_OBJECT
+
+public:
+ ProgressDlg(const QString&, const QString&, QWidget* pParent = 0, const
+ char* szName = 0);
+ ~ProgressDlg();
+
+ void setValue(int);
+ void setIdle();
+
+private:
+ /** When the value is 0, this timer initiates value changes that cause
+ the progress-bar to move. */
+ QTimer* m_pIdleTimer;
+
+ /** A dummy value used to move the progress-bar while the value is 0. */
+ int m_nIdleValue;
+
+private slots:
+ void slotShowBusy();
+};
+
+#endif
diff --git a/src/project.cpp b/src/project.cpp
new file mode 100644
index 0000000..06e1332
--- /dev/null
+++ b/src/project.cpp
@@ -0,0 +1,442 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2007 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include "project.h"
+#include "kscopeconfig.h"
+#include "cscopefrontend.h"
+
+#define PROJECT_CONFIG_VER 2
+
+inline void flListFromStringList(FileLocationList& fll, const QStringList& sl)
+{
+ QStringList::ConstIterator itr;
+ QString sPath;
+ uint nLine, nCol;
+
+ // Transform the string into a list of file locations
+ for (itr = sl.begin(); itr != sl.end(); ++itr) {
+ sPath = (*itr).section(':', 0, 0);
+ nLine = (*itr).section(':', 1, 1).toUInt();
+ nCol = (*itr).section(':', 2, 2).toUInt();
+ fll.append(new FileLocation(sPath, nLine, nCol));
+ }
+}
+
+inline void stringListFromFlList(QStringList& sl, const FileLocationList& fll)
+{
+ FileLocationList* pList;
+ FileLocation* pLoc;
+ QString sLoc;
+
+ // Nasty...
+ pList = (FileLocationList*)&fll;
+ sl.clear();
+
+ // Turn the object list into a string list, so that it can be written in
+ // the configuration file
+ for (pLoc = pList->first(); pLoc != NULL; pLoc = pList->next()) {
+ sLoc = "";
+ QTextOStream(&sLoc) << pLoc->m_sPath << ":" << pLoc->m_nLine << ":"
+ << pLoc->m_nCol;
+ sl.append(sLoc);
+ }
+}
+
+/**
+ */
+Project::Project() : ProjectBase(),
+ m_pConf(NULL)
+{
+}
+
+/**
+ */
+Project::~Project()
+{
+ close();
+}
+
+/**
+ */
+bool Project::open(const QString& sPath)
+{
+ QString sConfFile;
+ Options opt;
+
+ // Associate the object with the project directory
+ m_dir.setPath(sPath);
+ if (!m_dir.exists()) {
+ KMessageBox::error(0, i18n("Project directory does not exist"));
+ return false;
+ }
+
+ // Initialise the file-list file object
+ m_fiFileList.setName(sPath + "/cscope.files");
+
+ // Open the configuration files
+ m_pConf = new KConfig(sPath + "/cscope.proj");
+
+ // Verify the configuration file's version is compatible
+ m_pConf->setGroup("");
+ if (m_pConf->readUnsignedNumEntry("Version", 0) != PROJECT_CONFIG_VER) {
+ KMessageBox::error(0, i18n("Your project is not compatible with this "
+ "version of KScope.\nPlease re-create the project."));
+ return false;
+ }
+
+ // Get the project name
+ m_pConf->setGroup("Project");
+ m_sName = m_pConf->readEntry("Name");
+ if (m_sName == QString::null) {
+ KMessageBox::error(0, i18n("Cannot read project name"));
+ return false;
+ }
+
+ // Get stored options
+ initOptions();
+
+ // Set default make values for new projects (overriden in loadSession(),
+ // which is not called for new projects)
+ m_sMakeRoot = getSourceRoot();
+ m_sMakeCmd = "make";
+
+ return true;
+}
+
+/**
+ */
+void Project::close()
+{
+ if (m_pConf)
+ delete m_pConf;
+
+ m_fiFileList.close();
+}
+
+/**
+ * Returns a semi-colon separated list of the file types included in the
+ * current project.
+ */
+QString Project::getFileTypes() const
+{
+ QString sTypes;
+
+ m_pConf->setGroup("Project");
+ return m_pConf->readEntry("FileTypes");
+}
+
+/**
+ * Reads the project's options from the configuration file.
+ * @param opt A structure to fill with the read options
+ */
+void Project::getOptions(Options& opt) const
+{
+ // Get project properties
+ m_pConf->setGroup("Project");
+ opt.sSrcRootPath = m_pConf->readEntry("RootPath", "/");
+ opt.slFileTypes = m_pConf->readListEntry("FileTypes", ' ');
+ opt.bKernel = m_pConf->readBoolEntry("Kernel", DEF_IS_KERNEL);
+ opt.bInvIndex = m_pConf->readBoolEntry("InvIndex", DEF_INV_INDEX);
+ opt.bNoCompress = m_pConf->readBoolEntry("NoCompress", DEF_NO_COMPRESS);
+ opt.bSlowPathDef = m_pConf->readBoolEntry("SlowPathDef", DEF_SLOW_PATH);
+ opt.nAutoRebuildTime = m_pConf->readNumEntry("AutoRebuildTime");
+ opt.nTabWidth = m_pConf->readUnsignedNumEntry("TabWidth");
+ opt.sCtagsCmd = m_pConf->readEntry("CtagsCommand", DEF_CTAGS_COMMAND);
+
+ // Get auto-completion options
+ m_pConf->setGroup("AutoCompletion");
+ opt.bACEnabled = m_pConf->readBoolEntry("Enabled");
+ opt.nACMinChars = m_pConf->readUnsignedNumEntry("MinChars",
+ DEF_AC_MIN_CHARS);
+ opt.nACDelay = m_pConf->readUnsignedNumEntry("Delay", DEF_AC_DELAY);
+ opt.nACMaxEntries = m_pConf->readUnsignedNumEntry("MaxEntries",
+ DEF_AC_MAX_ENTRIES);
+}
+
+/**
+ * Sets project options.
+ * @param opt A structure containing the new parameters to set
+ */
+void Project::setOptions(const Options& opt)
+{
+ // Write the options to the configuration nfile
+ writeOptions(m_pConf, opt);
+
+ // Update project parameters
+ initOptions();
+}
+
+/**
+ */
+void Project::loadSession(Session& sess)
+{
+ QStringList slEntry;
+
+ m_pConf->setGroup("Session");
+
+ // Read the list of open file locations
+ slEntry = m_pConf->readListEntry("OpenFiles");
+ flListFromStringList(sess.fllOpenFiles, slEntry);
+
+ // Get the path of the last viewed file
+ sess.sLastFile = m_pConf->readEntry("LastOpenFile");
+
+ // Read the lists of locked query files and call-tree/graph files
+ sess.slQueryFiles = m_pConf->readListEntry("QueryFiles");
+ sess.slCallTreeFiles = m_pConf->readListEntry("CallTreeFiles");
+
+ // Read the list of bookmarks
+ slEntry = m_pConf->readListEntry("Bookmarks");
+ flListFromStringList(sess.fllBookmarks, slEntry);
+
+ // Read make-related information
+ sess.sMakeCmd = m_pConf->readEntry("MakeCommand", "make");
+ sess.sMakeRoot = m_pConf->readEntry("MakeRoot", getSourceRoot());
+
+ // Cache make values
+ m_sMakeCmd = sess.sMakeCmd;
+ m_sMakeRoot = sess.sMakeRoot;
+}
+
+/**
+ * Saves session-related information in the project's configuration file.
+ * @param sess Session parameters
+ */
+void Project::storeSession(const Session& sess)
+{
+ QStringList slEntry;
+
+ m_pConf->setGroup("Session");
+
+ // Write the list of open file locations
+ stringListFromFlList(slEntry, sess.fllOpenFiles);
+ m_pConf->writeEntry("OpenFiles", slEntry);
+
+ // Write the path of the last viewed file
+ m_pConf->writeEntry("LastOpenFile", sess.sLastFile);
+
+ // Write the lists of locked query files and call-tree/graph files
+ m_pConf->writeEntry("QueryFiles", sess.slQueryFiles);
+ m_pConf->writeEntry("CallTreeFiles", sess.slCallTreeFiles);
+
+ // Write the list of bookmarks
+ stringListFromFlList(slEntry, sess.fllBookmarks);
+ m_pConf->writeEntry("Bookmarks", slEntry);
+
+ // Write make-related information
+ // Be careful not to write empty strings, as they may occur if the make
+ // dialogue was not invoked during this session
+ if (!sess.sMakeCmd.isEmpty())
+ m_pConf->writeEntry("MakeCommand", sess.sMakeCmd);
+ if (!sess.sMakeRoot.isEmpty())
+ m_pConf->writeEntry("MakeRoot", sess.sMakeRoot);
+}
+
+/**
+ * Fills a list object with all files in the project.
+ * List items are created by reading and parsing all file name entries from
+ * the project's 'cscope.files' file.
+ * Note that the file may contain option lines, beginning with a dash. These
+ * should be ignored.
+ * @param pList Pointer to the object to fill
+ */
+bool Project::loadFileList(FileListTarget* pList)
+{
+ QString sFilePath;
+
+ // Open the 'cscope.files' file
+ if (!m_fiFileList.open(IO_ReadOnly))
+ return false;
+
+ // Read all file names from the file
+ QTextStream str(&m_fiFileList);
+ while ((sFilePath = str.readLine()) != QString::null) {
+ // Skip option lines
+ if (sFilePath.at(0) == '-')
+ continue;
+
+ // Set the new list item
+ pList->addItem(sFilePath);
+ }
+
+ m_fiFileList.close();
+ return true;
+}
+
+/**
+ * Writes all file entries in a list view widget to the project's
+ * 'cscope.files' file (replacing current file contents.)
+ * @param pList Pointer to the object from which to take the new entries
+ */
+bool Project::storeFileList(FileListSource* pList)
+{
+ QString sFilePath;
+
+ // Open the 'cscope.files' file
+ if (!m_fiFileList.open(IO_WriteOnly | IO_Truncate))
+ return false;
+
+ QTextStream str(&m_fiFileList);
+
+ // Write all file names
+ if (pList->firstItem(sFilePath)) {
+ do {
+ str << sFilePath << "\n";
+ } while (pList->nextItem(sFilePath));
+ }
+
+ m_fiFileList.close();
+ return true;
+}
+
+/**
+ * Adds a single file to the file list.
+ * @param sPath The path of the file to add
+ * @return true if successful, false otherwise
+ */
+bool Project::addFile(const QString& sPath)
+{
+ // Open the 'cscope.files' file
+ if (!m_fiFileList.open(IO_WriteOnly | IO_Append))
+ return false;
+
+ // Write the file path
+ QTextStream str(&m_fiFileList);
+ str << sPath << "\n";
+
+ m_fiFileList.close();
+ return true;
+}
+
+/**
+ * Determines whether the project includes any files.
+ * Reads the 'cscope.files' file and looks for any file names in it. If none
+ * is present, then the project is considered empty.
+ * Note that the file may contain option lines, beginning with a dash. These
+ * should be ignored.
+ * @return true if no files are included in the project, false otherwise
+ */
+bool Project::isEmpty()
+{
+ QString sPath, sFileName;
+ bool bResult = true;
+
+ // Open the 'cscope.files' file
+ if (!m_fiFileList.open(IO_ReadOnly))
+ return true;
+
+ // Find at least one file name entry in the file
+ QTextStream str(&m_fiFileList);
+ while ((sPath = str.readLine()) != QString::null) {
+ if (sPath.at(0) != '-') {
+ bResult = false;
+ break;
+ }
+ }
+
+ m_fiFileList.close();
+ return bResult;
+}
+
+/**
+ * Copies the list of previously queried symbols to the target object.
+ * @param slSymHistory The list object to copy into
+ */
+void Project::getSymHistory(QStringList& slSymHistory) const
+{
+ slSymHistory = m_slSymHistory;
+}
+
+/**
+ * Copies the list of previously queried symbols from the target object.
+ * @param slSymHistory The list object to copy from
+ */
+void Project::setSymHistory(QStringList& slSymHistory)
+{
+ m_slSymHistory = slSymHistory;
+}
+
+void Project::getMakeParams(QString& sCmd, QString& sDir) const
+{
+ sCmd = m_sMakeCmd;
+ sDir = m_sMakeRoot;
+}
+
+/**
+ * Creates a project by writing a configuration file inside the given
+ * directory.
+ * @param sName The project's name
+ * @param sPath The full path of the project's directory
+ * @param opt Project options
+ */
+bool Project::create(const QString& sName, const QString& sPath,
+ const Options& opt)
+{
+ // Prepare the project's files
+ KConfig conf(sPath + "/cscope.proj");
+
+ // Write the configuration file version
+ conf.setGroup("");
+ conf.writeEntry("Version", PROJECT_CONFIG_VER);
+
+ // Write project properties in the configuration file
+ conf.setGroup("Project");
+ conf.writeEntry("Name", sName);
+ writeOptions(&conf, opt);
+
+ // Flush the config file data, so the project is created even if KScope
+ // crashes...
+ conf.sync();
+
+ return true;
+}
+
+void Project::writeOptions(KConfig* pConf, const Options& opt)
+{
+ pConf->setGroup("Project");
+ pConf->writeEntry("RootPath", opt.sSrcRootPath);
+ pConf->writeEntry("FileTypes", opt.slFileTypes.join(" "));
+ pConf->writeEntry("Kernel", opt.bKernel);
+ pConf->writeEntry("InvIndex", opt.bInvIndex);
+ pConf->writeEntry("NoCompress", opt.bNoCompress);
+ pConf->writeEntry("SlowPathDef", opt.bSlowPathDef);
+ pConf->writeEntry("AutoRebuildTime", opt.nAutoRebuildTime);
+ pConf->writeEntry("TabWidth", opt.nTabWidth);
+ pConf->writeEntry("CtagsCommand", opt.sCtagsCmd);
+
+ // Set auto-completion options
+ pConf->setGroup("AutoCompletion");
+ pConf->writeEntry("Enabled", opt.bACEnabled);
+ pConf->writeEntry("MinChars", opt.nACMinChars);
+ pConf->writeEntry("Delay", opt.nACDelay);
+ pConf->writeEntry("MaxEntries", opt.nACMaxEntries);
+}
diff --git a/src/project.h b/src/project.h
new file mode 100644
index 0000000..a2679b2
--- /dev/null
+++ b/src/project.h
@@ -0,0 +1,92 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2007 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef PROJECT_H
+#define PROJECT_H
+
+#include <projectbase.h>
+
+/**
+ * @author Elad Lahav
+ */
+class Project : public ProjectBase
+{
+public:
+ Project();
+ virtual ~Project();
+
+ struct Session {
+ FileLocationList fllOpenFiles;
+ QString sLastFile;
+ QStringList slQueryFiles;
+ QStringList slCallTreeFiles;
+ FileLocationList fllBookmarks;
+ QString sMakeCmd;
+ QString sMakeRoot;
+ };
+
+ virtual bool open(const QString&);
+ virtual bool loadFileList(FileListTarget*);
+ virtual bool storeFileList(FileListSource*);
+ virtual bool addFile(const QString&);
+ virtual bool isEmpty();
+ virtual void close();
+
+ virtual QString getFileTypes() const;
+ virtual void getOptions(Options&) const;
+ virtual void setOptions(const Options&);
+ virtual void loadSession(Session&);
+ virtual void storeSession(const Session&);
+ virtual void getSymHistory(QStringList&) const;
+ virtual void setSymHistory(QStringList&);
+ virtual void getMakeParams(QString&, QString&) const;
+
+ /**
+ * Determines whether a project is based on a Cscope.out file, and is
+ * therefore considered as a temporary project.
+ * @return true if this is a temporary project, false otherwise
+ */
+ virtual bool isTemporary() { return false; }
+
+ static bool create(const QString&, const QString&, const Options&);
+
+private:
+ /** The configuration file ("cscope.proj") */
+ KConfig* m_pConf;
+
+ /** The file that holds the paths of all source files in this project
+ ("cscope.files") */
+ QFile m_fiFileList;
+
+ QString m_sMakeCmd;
+
+ QString m_sMakeRoot;
+
+ static void writeOptions(KConfig*, const Options&);
+};
+
+#endif
diff --git a/src/projectbase.cpp b/src/projectbase.cpp
new file mode 100644
index 0000000..f99c045
--- /dev/null
+++ b/src/projectbase.cpp
@@ -0,0 +1,190 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2007 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include "projectbase.h"
+#include "kscopeconfig.h"
+#include "cscopefrontend.h"
+
+ProjectBase::ProjectBase()
+{
+}
+
+ProjectBase::~ProjectBase()
+{
+}
+
+bool ProjectBase::open(const QString& sPath)
+{
+ QFileInfo fi(sPath);
+
+ // Make sure the file exists, and that is is a cross-reference file
+ if (!fi.exists() || !isCscopeOut(fi.absFilePath()))
+ return false;
+
+ // Set the project's directory
+ m_dir = fi.dirPath(true);
+
+ // Set the name of the project to be the full path of the file
+ m_sName = fi.absFilePath();
+
+ // Initialise project options (assume source root is the folder holding the
+ // cscope.out file)
+ getDefOptions(m_opt);
+ m_opt.sSrcRootPath = m_dir.absPath();
+
+ return true;
+}
+
+/**
+ * Determines if the cscope.out file for this project exists.
+ * @return true if the database exists, false otherwise
+ */
+bool ProjectBase::dbExists()
+{
+ return m_dir.exists("cscope.out");
+}
+
+void ProjectBase::getOptions(Options& opt) const
+{
+ getDefOptions(opt);
+}
+
+void ProjectBase::getMakeParams(QString& sCmd, QString& sDir) const
+{
+ sCmd = "make";
+ sDir = getSourceRoot();
+}
+
+/**
+ * Fills a structure with default properties for a new project.
+ * Default properties are partly based on the system profile.
+ * @param opt The structure to fill
+ */
+void ProjectBase::getDefOptions(Options& opt)
+{
+ // Set default source path to file-system root
+ opt.sSrcRootPath = "/";
+
+ // Initialise MIME-type list
+ opt.slFileTypes.append("*.c");
+ opt.slFileTypes.append("*.h");
+
+ // Set other options
+ opt.bKernel = DEF_IS_KERNEL;
+ opt.bInvIndex = DEF_INV_INDEX;
+ opt.bNoCompress = DEF_NO_COMPRESS;
+ opt.bSlowPathDef = DEF_SLOW_PATH;
+ opt.nACMinChars = DEF_AC_MIN_CHARS;
+ opt.nACDelay = DEF_AC_DELAY;
+ opt.nACMaxEntries = DEF_AC_MAX_ENTRIES;
+ opt.nTabWidth = DEF_TAB_WIDTH;
+
+ // Set profile-dependant options
+ if (Config().getSysProfile() == KScopeConfig::Fast) {
+ opt.nAutoRebuildTime = 10;
+ opt.bACEnabled = true;
+ }
+ else {
+ opt.nAutoRebuildTime = -1;
+ opt.bACEnabled = false;
+ }
+}
+
+void ProjectBase::initOptions()
+{
+ // Load the options
+ getOptions(m_opt);
+
+ // Create the argument list for invoking Cscope
+ m_nArgs = 0;
+ if (m_opt.bKernel)
+ m_nArgs |= CscopeFrontend::Kernel;
+ if (m_opt.bInvIndex)
+ m_nArgs |= CscopeFrontend::InvIndex;
+ if (m_opt.bNoCompress)
+ m_nArgs |= CscopeFrontend::NoCompression;
+ if (m_opt.bSlowPathDef)
+ m_nArgs |= CscopeFrontend::SlowPathDef;
+}
+
+/**
+ * Determines if the given file is a Cscope cross-reference database.
+ * @param sPath The full path of the file to check
+ * @return true if the given file is a cscope.out file, false otherwise
+ */
+bool ProjectBase::isCscopeOut(const QString& sPath)
+{
+ QFile file(sPath);
+ QString sLine;
+ int nVer;
+ char szDir[PATH_MAX];
+
+ // Try to open the file
+ if (!file.open(IO_ReadOnly))
+ return false;
+
+ // Check if the first line matches the expected format
+ sLine = QTextStream(&file).readLine();
+ return sscanf(sLine.latin1(), "cscope %d %s", &nVer, szDir) == 2;
+}
+
+/**
+ * Fills a list object with all files in the project.
+ * List items are created by reading and parsing all file name entries from
+ * the project's 'cscope.files' file.
+ * Note that the file may contain option lines, beginning with a dash. These
+ * should be ignored.
+ * @param pList Pointer to the object to fill
+ */
+bool ProjectBase::loadFileList(FileListTarget* pList)
+{
+ QString sFilePath;
+ QFile file;
+
+ // Make sure the file exists
+ if (!m_dir.exists("cscope.files"))
+ return false;
+
+ // Open the file
+ file.setName(m_dir.absPath() + "/cscope.files");
+ if (!file.open(IO_ReadOnly))
+ return false;
+
+ // Read all file names from the file
+ QTextStream str(&file);
+ while ((sFilePath = str.readLine()) != QString::null) {
+ // Skip option lines
+ if (sFilePath.at(0) == '-')
+ continue;
+
+ // Set the new list item
+ pList->addItem(sFilePath);
+ }
+
+ file.close();
+ return true;
+}
diff --git a/src/projectbase.h b/src/projectbase.h
new file mode 100644
index 0000000..4170652
--- /dev/null
+++ b/src/projectbase.h
@@ -0,0 +1,281 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2007 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef PROJECTBASE_H
+#define PROJECTBASE_H
+
+#include <qstringlist.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <kconfig.h>
+
+#define DEF_IS_KERNEL false
+#define DEF_INV_INDEX true
+#define DEF_NO_COMPRESS false
+#define DEF_SLOW_PATH false
+#define DEF_AC_MIN_CHARS 3
+#define DEF_AC_DELAY 500
+#define DEF_AC_MAX_ENTRIES 100
+#define DEF_TAB_WIDTH 0 /* Use editor's default */
+#define DEF_CTAGS_COMMAND \
+ "--regex-c=\"/^[ \\t]*([_a-zA-Z][_a-zA-Z0-9]*):/\\1/l,label/\" " \
+ "--regex-c=\"/^[ \\t]*#[ \\t]*include[ \\t]*[\\\"<]" \
+ "([_a-zA-Z0-9\\.\\/]*)[\\\">]/\\1/i,include/\" " \
+ "--regex-c++=\"/^[ \\t]*#[ \\t]*include[ \\t]*[\\\"<]" \
+ "([_a-zA-Z0-9\\.\\/]*)[\\\">]/\\1/i,include/\""
+
+/**
+ * Abstract base class for classes that need the list of project files.
+ * Objects of classes derived from this one are used as a parameter to
+ * ProjectManager::fillList(), which reads all file entries in the project,
+ * and calls addItem() for each.
+ * Any class that wishes to retrieve the project's file list, should inherit
+ * from this class, and implement addItem().
+ * @author Elad Lahav
+ */
+
+class FileListTarget
+{
+public:
+ /**
+ * Class constructor.
+ */
+ FileListTarget() {}
+
+ /**
+ * Class destructor.
+ */
+ virtual ~FileListTarget() {}
+
+ /**
+ * Appends a file to the list.
+ * @param sFilePath The full path of the file to add
+ */
+ virtual void addItem(const QString& sFilePath) = 0;
+};
+
+/**
+ * Abstract base class for classes that need the list of project files.
+ * Objects of classes derived from this one are used as a parameter to
+ * ProjectManager::writeList(), which calls getFirstItem() and getNextItem(),
+ * and writes the returned values to the project's 'cscope.files' file.
+ * Any class that wishes to retrieve the project's file list, should inherit
+ * from this class, and implement firstItem() and nextItem().
+ * @author Elad Lahav
+ */
+
+class FileListSource
+{
+public:
+ /**
+ * Class constructor.
+ */
+ FileListSource() {}
+
+ /**
+ * Class destructor.
+ */
+ virtual ~FileListSource() {}
+
+ /**
+ * Returns the first file in the list, and initiates a new iteration.
+ * @param sFilePath Holds the path of the first file, upon return
+ * @return true if there are more files, false otherwise
+ */
+ virtual bool firstItem(QString& sFilePath) = 0;
+
+ /**
+ * Returns the next file in the list.
+ * @param sFilePath Holds the path of the file, upon return
+ * @return true if there are more files, false otherwise
+ */
+ virtual bool nextItem(QString& sFilePath) = 0;
+};
+
+/**
+ * Defines a cursor location inside a file.
+ * This structure is used to store project session information.
+ * @author Elad Lahav
+ */
+struct FileLocation
+{
+ /**
+ * Struct constructor.
+ * @param sPath The full path of the file
+ * @param nLine The line position of the cursor
+ * @param nCol The column position of the cursor
+ */
+ FileLocation(QString sPath, uint nLine, uint nCol) : m_sPath(sPath),
+ m_nLine(nLine), m_nCol(nCol) {}
+
+ /** The full path of the file. */
+ QString m_sPath;
+
+ /** The line position of the cursor. */
+ uint m_nLine;
+
+ /** The column position of the cursor. */
+ uint m_nCol;
+};
+
+/**
+ * A list of file locations used for restoring a session.
+ */
+typedef QPtrList<FileLocation> FileLocationList;
+
+class FileSemaphore;
+
+/**
+ * @author Elad Lahav
+ */
+class ProjectBase
+{
+public:
+ ProjectBase();
+ virtual ~ProjectBase();
+
+ /**
+ * Configurable project options.
+ */
+ struct Options {
+ QString sSrcRootPath;
+
+ /** A list of MIME-types that determines which files are included in
+ the project. */
+ QStringList slFileTypes;
+
+ /** true if the -k option for CScope should be used. */
+ bool bKernel;
+
+ /** true if Cscope should build an inverted index. */
+ bool bInvIndex;
+
+ /** true if the -c option for CScope should be used. */
+ bool bNoCompress;
+
+ /** true if the -D option for CScope should be used. */
+ bool bSlowPathDef;
+
+ /** The time, in milliseconds, after which the database should be
+ automatically rebuilt (-1 if this option is disabled). */
+ int nAutoRebuildTime;
+
+ /** true to use auto-completion. */
+ bool bACEnabled;
+
+ /** Minimum number of characters in a symbol for auto-completion. */
+ uint nACMinChars;
+
+ /** Time interval, in milliseconds, before auto-completion is
+ started. */
+ uint nACDelay;
+
+ /** Maximal number of entries for auto-completion. */
+ uint nACMaxEntries;
+
+ /** Per-project tab width (overrides editor settings). */
+ uint nTabWidth;
+
+ /** Ctags command line. */
+ QString sCtagsCmd;
+ };
+
+ virtual bool open(const QString&);
+ virtual bool loadFileList(FileListTarget*);
+ virtual bool storeFileList(FileListSource*) { return false; }
+ virtual bool isEmpty() { return false; }
+ bool dbExists();
+ virtual void close() {}
+
+ virtual QString getFileTypes() const { return QString::null; }
+ virtual void getOptions(Options&) const;
+ virtual void setOptions(const Options&) {}
+ virtual void getSymHistory(QStringList&) const {}
+ virtual void setSymHistory(QStringList&) {}
+ virtual void getMakeParams(QString&, QString&) const;
+
+ /**
+ * Determines whether a project is based on a Cscope.out file, and is
+ * therefore considered as a temporary project.
+ * @return true if this is a temporary project, false otherwise
+ */
+ virtual bool isTemporary() { return true; }
+
+ /**
+ * @return The name of the current project
+ */
+ QString getName() const { return m_sName; }
+
+ /**
+ * @return The full path of the project's directory
+ */
+ QString getPath() const { return m_dir.absPath(); }
+
+ /**
+ * @return Command-line arguments to pass to a Cscope object, based on
+ * project's options
+ */
+ uint getArgs() const { return m_nArgs; }
+
+ const QString& getSourceRoot() const { return m_opt.sSrcRootPath; }
+
+ /**
+ * @return The time, in seconds, to wait before rebuilding the
+ * cross-refernce database.
+ */
+ int getAutoRebuildTime() const { return m_opt.nAutoRebuildTime; }
+
+ /**
+ * @return The tab width to use (0 to use the editor's default)
+ */
+ uint getTabWidth() const { return m_opt.nTabWidth; }
+
+ static void getDefOptions(Options&);
+
+protected:
+ /** The name of the project, as written in the configuration file */
+ QString m_sName;
+
+ /** The directory associated with the project */
+ QDir m_dir;
+
+ /** A cached version of the project's options. */
+ Options m_opt;
+
+ /** A list of Cscope command-line arguments based on the project's
+ options. */
+ uint m_nArgs;
+
+ /** A list of symbols previously queried. */
+ QStringList m_slSymHistory;
+
+ void initOptions();
+
+ static bool isCscopeOut(const QString&);
+};
+
+#endif
diff --git a/src/projectfilesdlg.cpp b/src/projectfilesdlg.cpp
new file mode 100644
index 0000000..de84417
--- /dev/null
+++ b/src/projectfilesdlg.cpp
@@ -0,0 +1,439 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qpushbutton.h>
+#include <qlistview.h>
+#include <qlineedit.h>
+#include <qregexp.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+#include "projectfilesdlg.h"
+#include "dirscanner.h"
+#include "scanprogressdlg.h"
+#include "kscopeconfig.h"
+
+/**
+ * Class constructor.
+ * @param pProjMgr Pointer the KScope's project manager object
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+ProjectFilesDlg::ProjectFilesDlg(Project* pProj, QWidget* pParent,
+ const char* szName) :
+ ProjectFilesLayout(pParent, szName),
+ m_pProj(pProj),
+ m_pScanDlg(NULL),
+ m_pItrItem(NULL),
+ m_pLastItem(NULL)
+{
+ // Create the scanner object
+ m_pScanner = new DirScanner(this, &m_dicFiles);
+
+ // Initialise the list view
+ m_pFileList->setSelectionMode(QListView::Extended);
+ m_pFileList->addColumn("File Path");
+
+ // Sort only when asked to by the user
+ if (Config().getAutoSortFiles())
+ m_pFileList->setSortColumn(0);
+ else
+ m_pFileList->setSortColumn(m_pFileList->columns() + 1);
+
+ // Add file/directory/tree when the appropriate button is clicked
+ connect(m_pAddFilesButton, SIGNAL(clicked()), this,
+ SLOT(slotAddFiles()));
+ connect(m_pAddDirButton, SIGNAL(clicked()), this, SLOT(slotAddDir()));
+ connect(m_pAddTreeButton, SIGNAL(clicked()), this, SLOT(slotAddTree()));
+
+ // Remove selected files/directory/tree when the appropriate button is
+ // clicked
+ connect(m_pRemSelButton, SIGNAL(clicked()), this, SLOT(slotRemSel()));
+ connect(m_pRemDirButton, SIGNAL(clicked()), this, SLOT(slotRemDir()));
+ connect(m_pRemTreeButton, SIGNAL(clicked()), this, SLOT(slotRemTree()));
+
+ // Hide/show files according to filter
+ connect(m_pFilterButton, SIGNAL(clicked()), this, SLOT(slotFilter()));
+ connect(m_pShowAllButton, SIGNAL(clicked()), this, SLOT(slotShowAll()));
+
+ // Close the dialog when OK/Cancel are clicked
+ connect(m_pOKButton, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(m_pCancelButton, SIGNAL(clicked()), this, SLOT(reject()));
+
+ // Fill the list with the project's files
+ m_pFileList->setUpdatesEnabled(false);
+ m_pProj->loadFileList(this);
+ m_pFileList->setUpdatesEnabled(true);
+ m_pFileList->triggerUpdate();
+}
+
+/**
+ * Class destructor.
+ */
+ProjectFilesDlg::~ProjectFilesDlg()
+{
+ delete m_pScanner;
+}
+
+/**
+ * Adds a single entry to the file list.
+ * Implements the addItem() virtual method of the FileListTarget base
+ * class. When a ProjectFilesDlg object is given as a parameter to
+ * ProjectManager::fillList(), this method is called for each file included
+ * in the project. A new list item is created, containing the file's path,
+ * and is added to the list.
+ * @param sFilePath The full path of a source file
+ */
+void ProjectFilesDlg::addItem(const QString& sFilePath)
+{
+ QListViewItem* pItem;
+
+ pItem = new QListViewItem(m_pFileList, m_pLastItem);
+ pItem->setText(0, sFilePath);
+ m_pLastItem = pItem;
+ m_dicFiles.insert(sFilePath, pItem);
+}
+
+/**
+ * Retrieves the first file path in the list.
+ * Imlpements the firstItem() virtual method of the FileListSource base
+ * class.
+ * @param sFilePath Contains the file path, upon successful return
+ * @return bool true if successful, false if the list is empty
+ */
+bool ProjectFilesDlg::firstItem(QString& sFilePath)
+{
+ m_pItrItem = m_pFileList->firstChild();
+ return nextItem(sFilePath);
+}
+
+/**
+ * Retrieves the next file path in the list.
+ * Imlpements the nextItem() virtual method of the FileListSource base
+ * class. The function requires that firstItem() will be called to begin an
+ * iteration through the file paths.
+ * @param sFilePath Contains the file path, upon successful return
+ * @return bool true if successful, false if no more items are
+ * available
+ */
+bool ProjectFilesDlg::nextItem(QString& sFilePath)
+{
+ if (m_pItrItem == NULL)
+ return false;
+
+ sFilePath = m_pItrItem->text(0);
+ m_pItrItem = m_pItrItem->nextSibling();
+ return true;
+}
+
+/**
+ * Notifies the user on the progress of a directory scan (when adding a new
+ * directory), and, if finished, allows the user to add these files to the
+ * project.
+ * @param pEvent The event object
+ */
+void ProjectFilesDlg::customEvent(QCustomEvent* pEvent)
+{
+ DirScanEvent* pDSE;
+ QString sMsg;
+
+ // Process only directory scan progress events
+ if (((uint)pEvent->type()) != DirScanEvent::EventId)
+ return;
+
+ pDSE = (DirScanEvent*)pEvent;
+
+ // Check if the scan has terminated
+ if (!pDSE->m_bFinished) {
+ // Create the scan progress dialog, if required
+ if (m_pScanDlg == NULL) {
+ m_pScanDlg = new ScanProgressDlg(this);
+ connect(m_pScanDlg, SIGNAL(cancelled()), this,
+ SLOT(slotCancelDirScan()));
+ }
+
+ // Set progress indication
+ m_pScanDlg->addFiles(pDSE->m_nFiles);
+ return;
+ }
+
+ // Destroy the scan progress dialog
+ delete m_pScanDlg;
+ m_pScanDlg = NULL;
+
+ // Verify the thread has terminated
+ m_pScanner->wait(500);
+ if (!m_pScanner->finished())
+ m_pScanner->terminate();
+
+ // Do nothing if the operation was cancelled
+ if (m_pScanner->wasCancelled())
+ return;
+
+ // Abort if no files were found
+ if (pDSE->m_nFiles == 0) {
+ KMessageBox::sorry(0, "No files were found");
+ return;
+ }
+
+ // Prompt the user for the files to add
+ sMsg.sprintf(i18n("Would you like to add %d files to your project?"),
+ pDSE->m_nFiles);
+ if (KMessageBox::questionYesNo(0, sMsg) == KMessageBox::No)
+ return;
+
+ // Add the files to the list
+ const QStringList& slFiles = m_pScanner->getFiles();
+ QStringList::const_iterator itr;
+
+ for (itr = slFiles.begin(); itr != slFiles.end(); ++itr)
+ addItem(*itr);
+}
+
+/**
+ * Removes a single item from the file list.
+ */
+void ProjectFilesDlg::removeItem(QListViewItem* pItem)
+{
+ m_dicFiles.remove(pItem->text(0));
+ delete pItem;
+}
+
+/**
+ * Adds a list of files to the project.
+ * Prompts the user for source files, and adds the selected files to the
+ * current project.
+ */
+void ProjectFilesDlg::slotAddFiles()
+{
+ QStringList slFiles;
+ QStringList::const_iterator itr;
+
+ // Prompt the user
+ slFiles = KFileDialog::getOpenFileNames(m_pProj->getSourceRoot(),
+ m_pProj->getFileTypes());
+
+ // Add the selected files, skipping existing entries
+ for (itr = slFiles.begin(); itr != slFiles.end(); ++itr) {
+ if (m_dicFiles.find(*itr) == NULL)
+ addItem(*itr);
+ }
+}
+
+/**
+ * Adds all source files in a given directory to the project.
+ * Prompts the user for a directory, and adds all files matching the
+ * project's pattern to the current project.
+ * Note that only source files in the selected directory are added, i.e., the
+ * search does not descend to sub-directories.
+ */
+void ProjectFilesDlg::slotAddDir()
+{
+ QString sDir;
+ QStringList slFiles;
+ QStringList::const_iterator itr;
+
+ // Prompt the user for a directory
+ sDir = KFileDialog::getExistingDirectory(m_pProj->getSourceRoot());
+ if (sDir.isEmpty())
+ return;
+
+ // Search for source files in this directory
+ m_pScanner->start(sDir, m_pProj->getFileTypes(), false);
+}
+
+/**
+ * Adds all source files in a given file system tree to the project.
+ * Prompts the user for a directory, and adds all files matching the
+ * project's pattern to the current project.
+ * Note that source files are searched for in the given directory, as well as
+ * in any of its sub-directories.
+ */
+void ProjectFilesDlg::slotAddTree()
+{
+ QString sDir;
+ QStringList slFiles;
+ QStringList::const_iterator itr;
+
+ // Prompt the user for a directory
+ sDir = KFileDialog::getExistingDirectory(m_pProj->getSourceRoot());
+ if (sDir.isEmpty())
+ return;
+
+ // Search for source files in this directory
+ m_pScanner->start(sDir, m_pProj->getFileTypes(), true);
+}
+
+/**
+ * Removes the selected files from the project.
+ */
+void ProjectFilesDlg::slotRemSel()
+{
+ QListViewItem* pItem, * pPrevItem;
+
+ // Prompt the user before removing the files
+ if (KMessageBox::questionYesNo(0, i18n("Are you sure you want to remove "
+ "the selected files from the project?")) == KMessageBox::No) {
+ return;
+ }
+
+ // Remove the selected files
+ pItem = m_pFileList->firstChild();
+ while (pItem != NULL) {
+ pPrevItem = pItem;
+ pItem = pItem->nextSibling();
+
+ if (pPrevItem->isSelected())
+ removeItem(pPrevItem);
+ }
+}
+
+/**
+ * Removes all source files in a directory from the project.
+ */
+void ProjectFilesDlg::slotRemDir()
+{
+ QString sDir, sFilePath;
+ QListViewItem* pItem, * pPrevItem;
+
+ // Prompt the user for a directory
+ sDir = KFileDialog::getExistingDirectory(m_pProj->getSourceRoot());
+ if (sDir.isEmpty())
+ return;
+
+ // Confirm the directory removal
+ if (KMessageBox::questionYesNo(0, i18n("Are you sure you want to remove "
+ "the selected directory from the project?")) == KMessageBox::No) {
+ return;
+ }
+
+ // Remove the files under the selected directory
+ pItem = m_pFileList->firstChild();
+ while (pItem != NULL) {
+ pPrevItem = pItem;
+ pItem = pItem->nextSibling();
+
+ // Check if the file is under the selected directory
+ sFilePath = pPrevItem->text(0);
+ if (sFilePath.left(sFilePath.findRev('/') + 1) == sDir)
+ removeItem(pPrevItem);
+ }
+}
+
+/**
+ * Removes all source files in a directory or any of its sub-directories from
+ * the project.
+ */
+void ProjectFilesDlg::slotRemTree()
+{
+ QString sDir, sFilePath;
+ QListViewItem* pItem, * pPrevItem;
+
+ // Prompt the user for a directory
+ sDir = KFileDialog::getExistingDirectory(m_pProj->getSourceRoot());
+ if (sDir.isEmpty())
+ return;
+
+ // Confirm the directory removal
+ if (KMessageBox::questionYesNo(0, i18n("Are you sure you want to remove "
+ "all files in the selected tree from the project?")) ==
+ KMessageBox::No) {
+ return;
+ }
+
+ // Remove the files under the selected directory
+ pItem = m_pFileList->firstChild();
+ while (pItem != NULL) {
+ pPrevItem = pItem;
+ pItem = pItem->nextSibling();
+
+ // Check if the file is under the selected directory
+ sFilePath = pPrevItem->text(0);
+ if (sFilePath.startsWith(sDir))
+ removeItem(pPrevItem);
+ }
+}
+
+/**
+ * Filter files according to a pattern.
+ * Hides all entries in the file list, except for those that match a given
+ * pattern.
+ */
+void ProjectFilesDlg::slotFilter()
+{
+ QString sFilter;
+ QListViewItem* pItem;
+
+ // Get the user's filter string
+ sFilter = m_pFilterEdit->text().stripWhiteSpace();
+ if (sFilter.isEmpty())
+ return;
+
+ // Create the regular expression
+ QRegExp reFilter(sFilter);
+ reFilter.setWildcard(true);
+
+ // Iterate over the list entries, and hide all items not matching the
+ // filter string
+ pItem = m_pFileList->firstChild();
+ while (pItem != NULL) {
+ if (reFilter.search(pItem->text(0)) == -1) {
+ pItem->setVisible(false);
+ pItem->setSelectable(false);
+ }
+
+ pItem = pItem->nextSibling();
+ }
+}
+
+/**
+ * Shows all entries in the file list, after a filter has been applied.
+ */
+void ProjectFilesDlg::slotShowAll()
+{
+ QListViewItem* pItem;
+
+ // Iterate over the list entries, and make all items visible
+ pItem = m_pFileList->firstChild();
+ while (pItem != NULL) {
+ pItem->setVisible(true);
+ pItem->setSelectable(true);
+ pItem = pItem->nextSibling();
+ }
+}
+
+/**
+ * Stops a directory scan process.
+ * This slot is called when the user clicks on the "Cancel" button in the
+ * scan progress dialog.
+ */
+void ProjectFilesDlg::slotCancelDirScan()
+{
+ m_pScanner->cancel();
+}
+
+#include "projectfilesdlg.moc"
diff --git a/src/projectfilesdlg.h b/src/projectfilesdlg.h
new file mode 100644
index 0000000..9c6d791
--- /dev/null
+++ b/src/projectfilesdlg.h
@@ -0,0 +1,104 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef PROJECTFILESDLG_H
+#define PROJECTFILESDLG_H
+
+#include <qwidget.h>
+#include <projectfileslayout.h>
+#include <qdict.h>
+#include "project.h"
+
+class DirScanner;
+class ScanProgressDlg;
+
+/**
+ * A dialog to manipulate the project's files.
+ * The dialog allows the user to add source files to the current project, or
+ * remove files from it. The main widget of the dialog is a list view, that
+ * displays all files currently in the project. When files are added or
+ * removed, this list view is updated. The project, however, is only modified
+ * if the user closes the dialog using the "OK" button.
+ * Since searches through a list view are very slow, the class also maintains
+ * a QDict object, that connects file names with their respective list items.
+ * This dictionary is used to ensure duplicated items are not added to the
+ * list.
+ * @author Elad Lahav
+ */
+
+class ProjectFilesDlg : public ProjectFilesLayout, public FileListTarget,
+ public FileListSource
+{
+ Q_OBJECT
+
+public:
+ ProjectFilesDlg(Project*, QWidget* pParent = 0, const char* szName = 0);
+ ~ProjectFilesDlg();
+
+ virtual void addItem(const QString&);
+ virtual bool firstItem(QString&);
+ virtual bool nextItem(QString&);
+
+protected:
+ virtual void customEvent(QCustomEvent*);
+
+private:
+ /** The project to manipulate. */
+ Project* m_pProj;
+
+ /** Holds all file paths in a quickly searchable format (for duplicate
+ entries lookup). */
+ QDict<QListViewItem> m_dicFiles;
+
+ /** A thread object to a-synchronously scan directories for source files
+ to add to the project. */
+ DirScanner* m_pScanner;
+
+ /** Displays the progress of a directory scan operation. */
+ ScanProgressDlg* m_pScanDlg;
+
+ /** A file list item that serves as an iterator. */
+ QListViewItem* m_pItrItem;
+
+ /** The last item added. */
+ QListViewItem* m_pLastItem;
+
+ void removeItem(QListViewItem*);
+
+private slots:
+ void slotAddFiles();
+ void slotAddDir();
+ void slotAddTree();
+ void slotRemSel();
+ void slotRemDir();
+ void slotRemTree();
+ void slotFilter();
+ void slotShowAll();
+ void slotCancelDirScan();
+};
+
+#endif
diff --git a/src/projectfileslayout.ui b/src/projectfileslayout.ui
new file mode 100644
index 0000000..a78af7e
--- /dev/null
+++ b/src/projectfileslayout.ui
@@ -0,0 +1,201 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>ProjectFilesLayout</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>ProjectFilesLayout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>585</width>
+ <height>480</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Project Files</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>m_pFilterEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pFilterButton</cstring>
+ </property>
+ <property name="text">
+ <string>Filter</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pShowAllButton</cstring>
+ </property>
+ <property name="text">
+ <string>Show All</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QListView">
+ <property name="name">
+ <cstring>m_pFileList</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Add</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pAddFilesButton</cstring>
+ </property>
+ <property name="text">
+ <string>Files...</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pAddDirButton</cstring>
+ </property>
+ <property name="text">
+ <string>Directory...</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pAddTreeButton</cstring>
+ </property>
+ <property name="text">
+ <string>Tree...</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Remove</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pRemSelButton</cstring>
+ </property>
+ <property name="text">
+ <string>Selected</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pRemDirButton</cstring>
+ </property>
+ <property name="text">
+ <string>Directory...</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pRemTreeButton</cstring>
+ </property>
+ <property name="text">
+ <string>Tree...</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>118</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox3</cstring>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pOKButton</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pCancelButton</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/src/projectmanager.cpp b/src/projectmanager.cpp
new file mode 100644
index 0000000..998b4a5
--- /dev/null
+++ b/src/projectmanager.cpp
@@ -0,0 +1,180 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <kmessagebox.h>
+#include <klocale.h>
+#include "projectmanager.h"
+#include "project.h"
+#include "kscopeconfig.h"
+
+/**
+ * Class constructor.
+ */
+ProjectManager::ProjectManager() : m_pCurProj(NULL)
+{
+}
+
+/**
+ * Class destructor.
+ */
+ProjectManager::~ProjectManager()
+{
+ close();
+}
+
+/**
+ * Creates a project's directory, and associates this directory with the
+ * current object. This directory is created under the given path, and using
+ * the project's name (which, thus, has to be a legal file name).
+ * Note: this function attempts to create a new directory, so the given path
+ * and name must not lead to an existing one.
+ * @param sName The project's name
+ * @param sPath The parent directory under which to create the
+ * project's directory
+ * @param opt A structure containing project options
+ * @return true if successful, false otherwise
+ */
+bool ProjectManager::create(const QString& sName, const QString& sPath,
+ const ProjectBase::Options& opt, QString& sProjDir)
+{
+ QDir dir(sPath);
+ QString sParentPath;
+ QString sDirName = sName;
+ QString sMsg;
+
+ // Handle requests for a hidden .cscope directory
+ if (dir.dirName() == ".cscope") {
+ sParentPath = QDir::cleanDirPath(dir.absPath());
+ sParentPath = sParentPath.section('/', 0, -2);
+ dir.cd(sParentPath);
+ sDirName = ".cscope";
+ }
+
+ // The parent directory must exist
+ if (!dir.exists()) {
+ sMsg = i18n("The requested parent directory (%1) does not exist").
+ arg(sParentPath);
+ KMessageBox::error(0, sMsg);
+ return false;
+ }
+
+ // Make sure the directory doesn't exist
+ if (dir.exists(sDirName)) {
+ sMsg = i18n("Cannot create a project inside an existing directory "
+ "(%1/%2)").arg(dir.canonicalPath()).arg(sDirName);
+ KMessageBox::error(0, sMsg);
+ return false;
+ }
+
+ // Try to create the projcet's directory
+ if (!dir.mkdir(sDirName, false) || !dir.cd(sDirName, false)) {
+ sMsg = i18n("Failed to create the project directory (%1/%2)").
+ arg(dir.canonicalPath()).arg(sDirName);
+ KMessageBox::error(0, sMsg);
+ return false;
+ }
+
+ if (!Project::create(sName, dir.absPath(), opt))
+ return false;
+
+ sProjDir = dir.path();
+ return true;
+}
+
+/**
+ * Opens a project and makes it the current one.
+ * @param sPath The directory containing the project's files
+ * @return true if successful, false otherwise
+ */
+bool ProjectManager::open(const QString& sPath)
+{
+ Project* pProj;
+
+ // Close the current project
+ close();
+
+ // Try to open the new project
+ pProj = new Project();
+ if (!pProj->open(sPath)) {
+ delete pProj;
+ return false;
+ }
+
+ // Add to the list of recently opened projects
+ Config().addRecentProject(sPath);
+
+ // Project opened successfully
+ m_pCurProj = pProj;
+ return true;
+}
+
+/**
+ * Opens a Cscope.out file as a temporary project.
+ * @param sFilePath The full path of the Cscope.out file
+ * @return true if successful, false otherwise
+ */
+bool ProjectManager::openCscopeOut(const QString& sFilePath)
+{
+ ProjectBase* pProj;
+
+ // Close the current project
+ close();
+
+ // Try to open the new project
+ pProj = new ProjectBase();
+ if (!pProj->open(sFilePath)) {
+ delete pProj;
+ return false;
+ }
+
+ // Add to the list of recently opened projects
+ Config().addRecentProject(sFilePath);
+
+ // Project opened successfully
+ m_pCurProj = pProj;
+ return true;
+}
+
+/**
+ * Performs clean-up on the project's variables, and detaches the associated
+ * directory.
+ */
+void ProjectManager::close()
+{
+ if (m_pCurProj) {
+ delete m_pCurProj;
+ m_pCurProj = NULL;
+ }
+}
+
+QString ProjectManager::getProjName() const
+{
+ if (!m_pCurProj)
+ return i18n("No Project");
+
+ return m_pCurProj->getName();
+}
diff --git a/src/projectmanager.h b/src/projectmanager.h
new file mode 100644
index 0000000..c78a2c9
--- /dev/null
+++ b/src/projectmanager.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef PROJECTMANAGER_H
+#define PROJECTMANAGER_H
+
+#include "projectbase.h"
+
+/**
+ * @author Elad Lahav
+ */
+class ProjectManager : public QObject
+{
+public:
+ ProjectManager();
+ virtual ~ProjectManager();
+
+ bool create(const QString&, const QString&, const ProjectBase::Options&,
+ QString&);
+ bool open(const QString&);
+ bool openCscopeOut(const QString&);
+ void close();
+ QString getProjName() const;
+
+ ProjectBase* curProject() const { return m_pCurProj; }
+
+private:
+ /** The current project (NULL if no project is open). */
+ ProjectBase* m_pCurProj;
+};
+
+#endif
diff --git a/src/query_locked.png b/src/query_locked.png
new file mode 100644
index 0000000..25db6b2
--- /dev/null
+++ b/src/query_locked.png
Binary files differ
diff --git a/src/query_unlocked.png b/src/query_unlocked.png
new file mode 100644
index 0000000..3a1a0d3
--- /dev/null
+++ b/src/query_unlocked.png
Binary files differ
diff --git a/src/querypage.cpp b/src/querypage.cpp
new file mode 100644
index 0000000..502747b
--- /dev/null
+++ b/src/querypage.cpp
@@ -0,0 +1,211 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qfile.h>
+#include <klocale.h>
+#include "querypage.h"
+#include "queryview.h"
+#include "queryviewdriver.h"
+
+const char* QUERY_TYPES[][2] = {
+ { "References to ", "REF " },
+ { "Definition of ", "DEF " },
+ { "Functions called by ", "<-- " },
+ { "Functions calling ", "-->" },
+ { "Search for ", "TXT " },
+ { "", "" },
+ { "EGrep Search for ", "GRP " },
+ { "Files named ", "FIL " },
+ { "Files #including ", "INC " },
+ { "Query", "Query" }
+};
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+QueryPage::QueryPage(QWidget* pParent, const char * szName) :
+ QueryPageBase(pParent, szName),
+ m_nType(CscopeFrontend::None)
+{
+ m_pView = new QueryView(this);
+ m_pDriver = new QueryViewDriver(m_pView, this);
+
+ connect(m_pView, SIGNAL(lineRequested(const QString&, uint)), this,
+ SIGNAL(lineRequested(const QString&, uint)));
+
+ // Set colours and font
+ applyPrefs();
+}
+
+/**
+ * Class destructor.
+ */
+QueryPage::~QueryPage()
+{
+}
+
+/**
+ * Runs a query, using the current page to display the results.
+ * @param nType The type of the query
+ * @param sText The text of the query
+ * @param bCase true for case-sensitive queries, false otherwise
+ */
+void QueryPage::query(uint nType, const QString& sText, bool bCase)
+{
+ m_nType = nType;
+ m_sText = sText;
+ m_bCase = bCase;
+ m_sName = getCaption();
+
+ m_pDriver->query(nType, sText, bCase);
+}
+
+/**
+ * Re-runs the last query.
+ */
+void QueryPage::refresh()
+{
+ m_pView->clear();
+ if (!m_sText.isEmpty())
+ m_pDriver->query(m_nType, m_sText, m_bCase);
+}
+
+/**
+ * Resets the query page by deleting all records.
+ */
+void QueryPage::clear()
+{
+ m_pView->clear();
+ m_nType = CscopeFrontend::None;
+ m_sText = QString();
+ m_sName = QString();
+}
+
+/**
+ * @return true if a query is currently running in this page, false otherwise
+ */
+bool QueryPage::isRunning()
+{
+ return m_pDriver->isRunning();
+}
+
+/**
+ * Constructs a caption for this page, based on the query's type and text.
+ * @param bBrief true to use a shortened version of the caption, false
+ * (default) for the full version
+ * @return The caption for this page
+ */
+QString QueryPage::getCaption(bool bBrief) const
+{
+ return QString(QUERY_TYPES[m_nType][bBrief ? 1 : 0] + m_sText);
+}
+
+/**
+ * Creates a new query result item.
+ * @param sFile The file name
+ * @param sFunc The function defining the scope of the result
+ * @param sLine The line number
+ * @param sText The contents of the line
+ */
+void QueryPage::addRecord(const QString& sFile, const QString& sFunc,
+ const QString& sLine, const QString& sText)
+{
+ new QListViewItem(m_pView, sFile, sFunc, sLine, sText);
+}
+
+/**
+ * Creates a unique file name for saving the contents of the query page.
+ * @param sProjPath The full path of the project directory
+ * @return The unique file name to use
+ */
+QString QueryPage::getFileName(const QString& sProjPath) const
+{
+ QString sFileName, sFileNameBase;
+ int i = 0;
+
+ // Do nothing if not initialised
+ if (m_sName.isEmpty())
+ return "";
+
+ // Create a unique file name
+ sFileNameBase = m_sName;
+ sFileNameBase.replace(' ', '_');
+ do {
+ sFileName = sFileNameBase + QString::number(++i);
+ } while (QFile(sProjPath + "/" + sFileName).exists());
+
+ return sFileName;
+}
+
+/**
+ * Reads query parameters from a file.
+ * This mehtod is used as part of the loading process.
+ * @param str A text stream set to the correct place in the file
+ * @return true if successful, false otherwise
+ */
+bool QueryPage::readHeader(QTextStream& str)
+{
+ QString sTemp;
+
+ // Read the query name
+ m_sName = str.readLine();
+ if (m_sName == QString::null || m_sName.isEmpty())
+ return false;
+
+ // Read the query's type
+ sTemp = str.readLine();
+ if (sTemp == QString::null || sTemp.isEmpty())
+ return false;
+
+ // Convert the type string to an integer
+ m_nType = sTemp.toUInt();
+ if (m_nType >= CscopeFrontend::None) {
+ m_nType = CscopeFrontend::None;
+ return false;
+ }
+
+ // Read the query's text
+ m_sText = str.readLine();
+ if (m_sText == QString::null || m_sText.isEmpty())
+ return false;
+
+ return true;
+}
+
+/**
+ * Writes query parameters to a file.
+ * This mehtod is used as part of the storing process.
+ * @param str A text stream set to the correct place in the file
+ */
+void QueryPage::writeHeader(QTextStream& str)
+{
+ str << m_sName << "\n" << m_nType << "\n" << m_sText << "\n";
+}
+
+#include "querypage.moc"
diff --git a/src/querypage.h b/src/querypage.h
new file mode 100644
index 0000000..59d6ea2
--- /dev/null
+++ b/src/querypage.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef QUERYPAGE_H
+#define QUERYPAGE_H
+
+#include <qwidget.h>
+#include <qlistview.h>
+#include <qregexp.h>
+#include "querypagebase.h"
+#include "cscopefrontend.h"
+
+class QueryViewDriver;
+
+/**
+ * A QueryWidget page that runs and displays Cscope queries.
+ * The page uses a QueryViewDriver object to run queries, and an embedded
+ * QueryView widget for displaying query results.
+ * @author Elad Lahav
+ */
+class QueryPage : public QueryPageBase
+{
+ Q_OBJECT
+
+public:
+ QueryPage(QWidget* pParent = 0, const char* szName = 0);
+ ~QueryPage();
+
+ void query(uint, const QString&, bool);
+ void refresh();
+ void clear();
+ bool isRunning();
+
+ virtual QString getCaption(bool bBrief = false) const;
+
+protected:
+ virtual void addRecord(const QString&, const QString&, const QString&,
+ const QString&);
+ virtual QString getFileName(const QString&) const;
+ virtual bool readHeader(QTextStream&);
+ virtual void writeHeader(QTextStream&);
+
+private:
+ /** The type of query whose results are listed on this page. */
+ uint m_nType;
+
+ /** The text given as a parameter to the query. */
+ QString m_sText;
+
+ /** Whether the query is case-sensitive. */
+ bool m_bCase;
+
+ /** A formatted caption for this query, including the type of query and
+ its text. */
+ QString m_sName;
+
+private:
+ /** Runs Cscope queries whose results are displayed in this page. */
+ QueryViewDriver* m_pDriver;
+};
+
+#endif
diff --git a/src/querypagebase.cpp b/src/querypagebase.cpp
new file mode 100644
index 0000000..08cbe6d
--- /dev/null
+++ b/src/querypagebase.cpp
@@ -0,0 +1,194 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qfile.h>
+#include "querypagebase.h"
+#include "queryview.h"
+#include "kscopeconfig.h"
+
+#define FILE_VERSION "VERSION=2"
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+QueryPageBase::QueryPageBase(QWidget* pParent, const char* szName) :
+ QHBox(pParent, szName),
+ m_bLocked(false)
+{
+}
+
+/**
+ * Class destructor.
+ */
+QueryPageBase::~QueryPageBase()
+{
+}
+
+/**
+ * Sets the list's colours and font, according the user's preferences.
+ */
+void QueryPageBase::applyPrefs()
+{
+ // Apply colour settings
+ m_pView->setPaletteBackgroundColor(Config().getColor(
+ KScopeConfig::QueryWindowBack));
+ m_pView->setPaletteForegroundColor(Config().getColor(
+ KScopeConfig::QueryWindowFore));
+ m_pView->setFont(Config().getFont(KScopeConfig::QueryWindow));
+}
+
+/**
+ * Restores a locked query from the given query file.
+ * NOTE: The query file is deleted when loading is complete.
+ * @param sProjPath The full path of the project directory
+ * @param sFileName The name of the query file to load
+ * @return true if successful, false otherwise
+ */
+bool QueryPageBase::load(const QString& sProjPath, const QString& sFileName)
+{
+ QString sTemp, sFile, sFunc, sLine, sText;
+ int nState;
+
+ // Try to open the query file for reading
+ QFile file(sProjPath + "/" + sFileName);
+ if (!file.open(IO_ReadOnly))
+ return false;
+
+ {
+ // Use a new scope for the QTextStream object, to ensure its
+ // destruction before the file is deleted
+ QTextStream str(&file);
+
+ // Make sure the file's version is correct
+ sTemp = str.readLine();
+ if (sTemp != FILE_VERSION) {
+ file.remove();
+ return false;
+ }
+
+ // Try to read the file header
+ if (!readHeader(str))
+ return false;
+
+ // Read query records
+ sTemp = str.readLine();
+ nState = 0;
+ while (sTemp != QString::null) {
+ switch (nState) {
+ // File path
+ case 0:
+ sFile = sTemp;
+ break;
+
+ // Function name
+ case 1:
+ sFunc = sTemp;
+ break;
+
+ // Line number
+ case 2:
+ sLine = sTemp;
+ break;
+
+ // Text string
+ case 3:
+ sText = sTemp;
+ addRecord(sFile, sFunc, sLine, sText);
+ break;
+ }
+
+ nState = (nState + 1) % 4;
+ sTemp = str.readLine();
+ }
+ }
+
+ // Delete the query file
+ file.remove();
+
+ return true;
+}
+
+/**
+ * Writes the contents of the page to a file.
+ * This method is called for pages that shoukld be stored before the owner
+ * project is closed (@see shouldSave()).
+ * @param sProjPath The full path of the project directory
+ * @param sFileName Holds the file name to which the page was saved, upon
+ * return
+ * @return true if successful, false otherwise
+ */
+bool QueryPageBase::save(const QString& sProjPath, QString& sFileName)
+{
+ QListViewItemIterator itr(m_pView);
+
+ // Get the file name to use
+ sFileName = getFileName(sProjPath);
+ if (sFileName.isEmpty())
+ return false;
+
+ // Open the query file for writing
+ QFile file(sProjPath + "/" + sFileName);
+ if (!file.open(IO_WriteOnly))
+ return false;
+
+ QTextStream str(&file);
+
+ // Write the version string
+ str << FILE_VERSION << "\n";
+
+ writeHeader(str);
+
+ // Write all records
+ for(; itr.current(); ++itr) {
+ str << itr.current()->text(0) << "\n"
+ << itr.current()->text(1) << "\n"
+ << itr.current()->text(2) << "\n"
+ << itr.current()->text(3) << "\n";
+ }
+
+ return true;
+}
+
+/**
+ * Selects the next record in the view.
+ */
+void QueryPageBase::selectNext()
+{
+ m_pView->selectNext();
+}
+
+/**
+ * Selects the previous record in the view.
+ */
+void QueryPageBase::selectPrev()
+{
+ m_pView->selectPrev();
+}
+
+#include "querypagebase.moc"
diff --git a/src/querypagebase.h b/src/querypagebase.h
new file mode 100644
index 0000000..8603874
--- /dev/null
+++ b/src/querypagebase.h
@@ -0,0 +1,148 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef QUERYPAGEBASE_H
+#define QUERYPAGEBASE_H
+
+#include <qhbox.h>
+
+class QueryView;
+
+/**
+ * Defines a page in a QueryWidget's tab widget.
+ * This is a abstract base class for QueryPage and HistoryPage. It defines
+ * the common behaviour for all pages, which includes appearance, display
+ * of tab text, page locking, storage and retrieval of information to
+ * and from files and basic navigation.
+ * Each page embeds a list widget derived from QueryView. The actual type
+ * of widget is defined by the different page classes.
+ * @author Elad Lahav
+ */
+class QueryPageBase : public QHBox
+{
+Q_OBJECT
+public:
+ QueryPageBase(QWidget* pParent = 0, const char* szName = 0);
+ ~QueryPageBase();
+
+ void applyPrefs();
+ bool load(const QString&, const QString&);
+ bool save(const QString&, QString&);
+ void selectNext();
+ void selectPrev();
+
+
+ /**
+ * Determines whether this page can be locked.
+ * Can be used by inheriting classes to define non-lockable pages.
+ * @return Always true
+ */
+ virtual bool canLock() { return true; }
+
+ /**
+ * Locks or unlocks this page.
+ * @param bLocked true to lock the page, false to unlock it.
+ */
+ void setLocked(bool bLocked) { m_bLocked = bLocked; }
+
+ /**
+ * Determines whether this page is locked.
+ * @return true if the page is locked, false otherwise
+ */
+ bool isLocked() { return m_bLocked; }
+
+ /**
+ * Determines whether this page should be saved when the project is closed.
+ * By default, pages are saved if and only if they are locked.
+ * @return true to save the page, false otherwise
+ */
+ virtual bool shouldSave() const { return m_bLocked; };
+
+ /**
+ * Constructs a caption for this page.
+ * The caption appears in the page's tab button and as the page's
+ * tooltip.
+ * @param bBrief true to generate a brief caption, false otherwise
+ * @return The page's title
+ */
+ virtual QString getCaption(bool bBrief = false) const = 0;
+
+signals:
+ /**
+ * Emitted when a record is selected in the view widget.
+ * @param sFile The "File" field of the selected record
+ * @param nLine The "Line" field of the selected record
+ */
+ void lineRequested(const QString& sFile, uint nLine);
+
+protected:
+ /** The embedded list. */
+ QueryView* m_pView;
+
+ /** Indicates whether this page is locked. A locked page is never
+ overriden by new data, and is also saved to a disc file when the
+ session is closed. */
+ bool m_bLocked;
+
+ /**
+ * Creates a new list item and adds it to the embedded view.
+ * This method is used to add records read from a stored file.
+ * @param sFile The "File" field of the record
+ * @param sFunc The "Function" field of the record
+ * @param sLine The "Line" field of the record
+ * @param sText The "Text" field of the record
+ */
+ virtual void addRecord(const QString& sFile, const QString& sFunc,
+ const QString& sLine, const QString& sText) = 0;
+
+ /**
+ * Creates a file path to store this page.
+ * The path is composed of the project's path and a unique file name
+ * in that directory.
+ * @param sProjPath The project's directory
+ * @return The page's file path
+ */
+ virtual QString getFileName(const QString& sProjPath) const = 0;
+
+ /**
+ * Tries to read the file header of a stored page.
+ * The contents of the header differ among inheriting classes.
+ * @param str A text stream initialised to the open page file
+ * @return true if the header was read successfully and contains the
+ * expected information, false otherwise
+ */
+ virtual bool readHeader(QTextStream& str) = 0;
+
+ /**
+ * Writes a header to a page's file.
+ * The contents of the header differ among inheriting classes.
+ * @param str A text stream initialised to the open page file
+ */
+ virtual void writeHeader(QTextStream& str) = 0;
+};
+
+#endif
diff --git a/src/queryresultsmenu.cpp b/src/queryresultsmenu.cpp
new file mode 100644
index 0000000..74bcdb4
--- /dev/null
+++ b/src/queryresultsmenu.cpp
@@ -0,0 +1,170 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <klocale.h>
+#include "queryresultsmenu.h"
+
+/**
+ * Class constructor.
+ * @param pParent Parent widget
+ * @param szName Optional object name
+ */
+QueryResultsMenu::QueryResultsMenu(QWidget* pParent, const char* szName) :
+ QPopupMenu(pParent, szName),
+ m_pItem(NULL)
+{
+ // Create the menu
+ insertItem(i18n("&View Source"), this, SLOT(slotViewSource()), 0,
+ ViewSource);
+ insertItem(i18n("Find &Definition"), this, SLOT(slotFindDef()), 0,
+ FindDef);
+ insertSeparator();
+ insertItem(i18n("&Copy"), this, SLOT(slotCopy()), 0, Copy);
+ insertSeparator();
+ insertItem(i18n("&Filter..."), this, SLOT(slotFilter()), 0, Filter);
+ insertItem(i18n("&Show All"), this, SIGNAL(showAll()), 0, ShowAll);
+ insertSeparator();
+ insertItem(i18n("&Remove Item"), this, SLOT(slotRemove()), 0, Remove);
+}
+
+/**
+ * Class destructor.
+ */
+QueryResultsMenu::~QueryResultsMenu()
+{
+}
+
+/**
+ * Displays the popup-menu at the requested coordinates.
+ * @param pItem The item on which the menu was requested
+ * @param ptPos The requested position for the menu
+ * @param nCol The column over which the menu was requested, -1 if no
+ * column is associated with the request
+ */
+void QueryResultsMenu::slotShow(QListViewItem* pItem, const QPoint& ptPos,
+ int nCol)
+{
+ // Save the requested item and column number to use in signals
+ m_pItem = pItem;
+ m_nCol = nCol;
+
+ if (m_pItem == NULL) {
+ // No item selected, disable everything but the "Filter" and "Show All"
+ // items
+ setItemEnabled(ViewSource, false);
+ setItemEnabled(FindDef, false);
+ setItemEnabled(Copy, false);
+ setItemEnabled(Remove, false);
+ }
+ else {
+ // Item selected, enable record-specific actions
+ setItemEnabled(ViewSource, true);
+ setItemEnabled(Copy, true);
+ setItemEnabled(Remove, true);
+
+ // The "Find Definition" item should only be enabled if the mouse
+ // was clicked over a valid function name
+ setItemEnabled(FindDef, (m_nCol == 0) &&
+ (m_pItem->text(0) != "<global>"));
+
+ // Set menu contents according to the column number
+ switch (m_nCol) {
+ case 0:
+ changeItem(Copy, "&Copy Function");
+ break;
+
+ case 1:
+ changeItem(Copy, "&Copy File");
+ break;
+
+ case 2:
+ changeItem(Copy, "&Copy Line Number");
+ break;
+
+ case 3:
+ changeItem(Copy, "&Copy Text");
+ break;
+
+ default:
+ m_nCol = 0;
+ }
+ }
+
+ // Show the menu
+ popup(ptPos);
+}
+
+/**
+ * Emits the viewSource() signal.
+ * This slot is activated when the "View Source" item is selected.
+ */
+void QueryResultsMenu::slotViewSource()
+{
+ if (m_pItem != NULL)
+ emit viewSource(m_pItem);
+}
+
+/**
+ * Emits the findDef() signal.
+ * This slot is activated when the "Find Definition" item is selected.
+ */
+void QueryResultsMenu::slotFindDef()
+{
+ if (m_pItem != NULL)
+ emit findDef(m_pItem->text(0));
+}
+
+/**
+ * Emits the copy() signal.
+ * This slot is activated when the "Copy [Column]" item is selected.
+ */
+void QueryResultsMenu::slotCopy()
+{
+ if (m_pItem != NULL)
+ emit copy(m_pItem, m_nCol);
+}
+
+/**
+ * Emits the filter() signal.
+ * This slot is activated when the "Filter..." item is selected.
+ */
+void QueryResultsMenu::slotFilter()
+{
+ emit filter(m_nCol);
+}
+
+/**
+ * Emits the remove() signal.
+ * This slot is activated when the "Remove" item is selected.
+ */
+void QueryResultsMenu::slotRemove()
+{
+ if (m_pItem != NULL)
+ emit remove(m_pItem);
+}
+
+#include "queryresultsmenu.moc"
diff --git a/src/queryresultsmenu.h b/src/queryresultsmenu.h
new file mode 100644
index 0000000..099dd2e
--- /dev/null
+++ b/src/queryresultsmenu.h
@@ -0,0 +1,110 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef QUERYRESULTSMENU_H
+#define QUERYRESULTSMENU_H
+
+#include <qpopupmenu.h>
+#include <qlistview.h>
+#include <qregexp.h>
+
+/**
+ * Provides a popup-menu for list views containing query results.
+ * The popup menu contains commands for copying field text out of items and
+ * for removing items.
+ * This class assumes a certain ordering of the list columns. If an owner
+ * object uses a different configuration, it needs to call setColumns() after
+ * constructing the object.
+ * @author Elad Lahav
+ */
+class QueryResultsMenu : public QPopupMenu
+{
+ Q_OBJECT
+
+public:
+ QueryResultsMenu(QWidget* pParent = 0, const char* szName = 0);
+ ~QueryResultsMenu();
+
+public slots:
+ void slotShow(QListViewItem*, const QPoint&, int nCol);
+
+signals:
+ /**
+ * Indicates that the "View Source" menu item was selected.
+ * @param pItem The item for which the menu was displayed
+ */
+ void viewSource(QListViewItem* pItem);
+
+ /**
+ * Indicates that the "Find Definition" menu item was selected.
+ * @param sFunc The function to look for
+ */
+ void findDef(const QString& sFunc);
+
+ /**
+ * Indicates that the "Copy [Column]" menu item was selected.
+ * @param pItem The item for which the menu was displayed
+ * @param nCol The requested column
+ */
+ void copy(QListViewItem* pItem, int nCol);
+
+ /**
+ * Indicates that the "Filter..." menu item was selected.
+ * @param nCol The column in which to search
+ */
+ void filter(int nCol);
+
+ /**
+ * Indicates that the "Show All" menu item was selected.
+ */
+ void showAll();
+
+ /**
+ * Indicates that the "Remove Item" menu item was selected.
+ * @param pItem The item for which the menu was displayed
+ */
+ void remove(QListViewItem* pItem);
+
+private:
+ /** Menu item IDs. */
+ enum { ViewSource, FindDef, Copy, Filter, ShowAll, Remove };
+
+ /** The item for which the popup menu is provided (cannot be NULL). */
+ QListViewItem* m_pItem;
+
+ /** The list column for which the query was invoked. */
+ int m_nCol;
+
+private slots:
+ void slotViewSource();
+ void slotFindDef();
+ void slotCopy();
+ void slotFilter();
+ void slotRemove();
+};
+
+#endif
diff --git a/src/queryview.cpp b/src/queryview.cpp
new file mode 100644
index 0000000..c56a2b0
--- /dev/null
+++ b/src/queryview.cpp
@@ -0,0 +1,444 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qapplication.h>
+#include <qclipboard.h>
+#include <klocale.h>
+#include "queryview.h"
+#include "queryresultsmenu.h"
+#include "queryviewdlg.h"
+#include "cscopefrontend.h"
+#include "searchresultsdlg.h"
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The name of the widget
+ */
+QueryView::QueryView(QWidget* pParent, const char* szName) :
+ QListView(pParent, szName),
+ m_pLastItem(NULL)
+{
+ // Create the popup-menu
+ m_pQueryMenu = new QueryResultsMenu(this);
+
+ // Initialise the list's columns
+ setAllColumnsShowFocus(true);
+ addColumn(i18n("Function"));
+ addColumn(i18n("File"));
+ addColumn(i18n("Line"));
+ addColumn(i18n("Text"));
+ setColumnAlignment(2, Qt::AlignRight);
+
+ setShowSortIndicator(true);
+
+ // A record is selected if it is either double-clicked, or the ENTER
+ // key is pressed while the record is highlighted
+ connect(this, SIGNAL(doubleClicked(QListViewItem*)), this,
+ SLOT(slotRecordSelected(QListViewItem*)));
+ connect(this, SIGNAL(returnPressed(QListViewItem*)), this,
+ SLOT(slotRecordSelected(QListViewItem*)));
+
+ // Show the popup-menu when requested
+ connect(this,
+ SIGNAL(contextMenuRequested(QListViewItem*, const QPoint&, int)),
+ m_pQueryMenu, SLOT(slotShow(QListViewItem*, const QPoint&, int)));
+
+ // Handle popup-menu commands
+ connect(m_pQueryMenu, SIGNAL(viewSource(QListViewItem*)), this,
+ SLOT(slotRecordSelected(QListViewItem*)));
+ connect(m_pQueryMenu, SIGNAL(findDef(const QString&)), this,
+ SLOT(slotFindDef(const QString&)));
+ connect(m_pQueryMenu, SIGNAL(copy(QListViewItem*, int)), this,
+ SLOT(slotCopy(QListViewItem*, int)));
+ connect(m_pQueryMenu, SIGNAL(filter(int)), this, SLOT(slotFilter(int)));
+ connect(m_pQueryMenu, SIGNAL(showAll()), this,
+ SLOT(slotShowAll()));
+ connect(m_pQueryMenu, SIGNAL(remove(QListViewItem*)), this,
+ SLOT(slotRemoveItem(QListViewItem*)));
+}
+
+/**
+ * Class destructor.
+ */
+QueryView::~QueryView()
+{
+}
+
+/**
+ * Creates a new list item showing a query result record.
+ * @param sFunc The name of the function
+ * @param sFile The file path
+ * @param sLine The line number in the above file
+ * @param sText The line's text
+ * @param pParent The parent item (ignored)
+ */
+void QueryView::addRecord(const QString& sFunc, const QString& sFile,
+ const QString& sLine, const QString& sText, QListViewItem* /* pParent */)
+{
+ QListViewItem* pItem;
+
+ pItem = new QueryViewItem(this, m_pLastItem, 2);
+ pItem->setText(0, sFunc);
+ pItem->setText(1, sFile);
+ pItem->setText(2, sLine);
+ pItem->setText(3, sText);
+
+ m_pLastItem = pItem;
+}
+
+/**
+ * Selects an item.
+ * When an item is selected, it is highlighted and made visible. By
+ * definition, the lineRequested() signal is also emitted.
+ * This method is used for selecting records programmatically (@see
+ * selectNext() for example). It has nothing to do with user selection.
+ * @param pItem The list item to select
+ */
+void QueryView::select(QListViewItem* pItem)
+{
+ ensureItemVisible(pItem);
+ setSelected(pItem, true);
+ slotRecordSelected(pItem);
+}
+
+/**
+ * Selects the next record in the list (if one exists).
+ * The function selects the next item as follows:
+ * - The first item in the list, if there is no current item
+ * - The current item, if it is not selected
+ * - The item immediately below the current item, otherwise
+ */
+void QueryView::selectNext()
+{
+ QListViewItem* pItem;
+
+ // Do nothing if the list is empty
+ if (firstChild() == NULL)
+ return;
+
+ // Find the next record
+ pItem = currentItem();
+ if (pItem == NULL) {
+ pItem = firstChild();
+ }
+ else if (pItem->isSelected()) {
+ pItem = pItem->itemBelow();
+ if (pItem == NULL)
+ return;
+ }
+
+ // Select the new item
+ select(pItem);
+}
+
+/**
+ * Selects the previous record in the list (if one exists).
+ * The function selects the previous item as follows:
+ * - The first item in the list, if there is no current item
+ * - The current item, if it is not selected
+ * - The item immediately above the current item, otherwise
+ */
+void QueryView::selectPrev()
+{
+ QListViewItem* pItem;
+
+ // Do nothing if the list is empty
+ if (firstChild() == NULL)
+ return;
+
+ // Find the item immediately above this one
+ pItem = currentItem();
+ if (pItem == NULL) {
+ pItem = firstChild();
+ }
+ else if (pItem->isSelected()) {
+ pItem = pItem->itemAbove();
+ if (pItem == NULL)
+ return;
+ }
+
+ // Select the new item
+ select(pItem);
+}
+
+/**
+ * Informs the view that query progress information has been received.
+ * The view emits the needToShow() signal telling its parent that the widget
+ * should become visible (if not already so).
+ */
+void QueryView::queryProgress()
+{
+ if (!isVisible())
+ emit needToShow();
+}
+
+/**
+ * Called when a query using this view terminates.
+ * @param nRecords Number of records generated by the query
+ */
+void QueryView::queryFinished(uint nRecords, QListViewItem*)
+{
+ // Auto-select a single record (no need to emit the show() signal in
+ // that case)
+ if (nRecords == 1) {
+ emit select(firstChild());
+ return;
+ }
+
+ // Report a query that has returned an empty record set
+ if (nRecords == 0)
+ addRecord(i18n("No results"), "", "", "", NULL);
+
+ // Data is available, instruct the owner object to show the view
+ emit needToShow();
+}
+
+/**
+ * Creates an iterator and initialises it to point to the first _visible_
+ * item in the list.
+ * @return A new iterator initialised to the beginning of the list
+ */
+QueryView::Iterator QueryView::getIterator()
+{
+ QListViewItem* pItem;
+
+ for (pItem = firstChild(); pItem != NULL && !pItem->isVisible();
+ pItem = pItem->nextSibling());
+
+ return Iterator(pItem);
+}
+
+/**
+ * Handles double-click events over the view.
+ * NOTE: We override this method since the QListView implementation opens
+ * expandable items. This is undesired for tree-like query views (such as the
+ * call tree.
+ * @param pEvent Event description object
+ */
+void QueryView::contentsMouseDoubleClickEvent(QMouseEvent* pEvent)
+{
+ QListViewItem* pItem;
+
+ // Handle only left button double-clicks
+ if (pEvent == NULL || pEvent->button() != LeftButton)
+ return;
+
+ // Find the clicked item
+ pItem = itemAt(contentsToViewport(pEvent->pos()));
+ if (pItem == NULL)
+ return;
+
+ // Emit the doubleClicked() signal
+ emit doubleClicked(pItem);
+}
+
+/**
+ * Emits the lineRequested() signal when a list item is selected.
+ * This slot is connected to the doubleClicked() and returnPressed()
+ * signals of the list view.
+ * @param pItem The selected item
+ */
+void QueryView::slotRecordSelected(QListViewItem* pItem)
+{
+ QString sFileName, sLine;
+
+ // Get the file name and line number
+ sFileName = pItem->text(1);
+ sLine = pItem->text(2);
+
+ // Do not process the "No results" item
+ if (!sLine.isEmpty())
+ emit lineRequested(sFileName, sLine.toUInt());
+}
+
+/**
+ * Looks up the definition of a given function.
+ * Results are displayed in a popup window.
+ * This slot is connected to the findDef() signal emitted by the results menu.
+ * @param sFunc The function to look for
+ */
+void QueryView::slotFindDef(const QString& sFunc)
+{
+ QueryViewDlg* pDlg;
+
+ // Create a query view dialogue
+ pDlg = new QueryViewDlg(QueryViewDlg::DestroyOnSelect, this);
+
+ // Display a line when it is selected in the dialogue
+ connect(pDlg, SIGNAL(lineRequested(const QString&, uint)), this,
+ SIGNAL(lineRequested(const QString&, uint)));
+
+ // Start the query
+ pDlg->query(CscopeFrontend::Definition, sFunc);
+}
+
+/**
+ * Copies the text of the requested field (item+column) to the clipboard.
+ * This slot is connected to the copy() signal of the QueryResultsMenu object.
+ * @param pItem The item from which to copy
+ * @param nCol The index of the item field to copy
+ */
+void QueryView::slotCopy(QListViewItem* pItem, int nCol)
+{
+ QApplication::clipboard()->setText(pItem->text(nCol),
+ QClipboard::Clipboard);
+}
+
+/**
+ * Hides all items in the page that do not meet the given search criteria.
+ * This slot is connected to the search() signal of the QueryResultsMenu
+ * object.
+ * The search is incremental: only visible items are checked, so that a new
+ * search goes over the results of the previous one.
+ * @param nCol The list column to search in
+ */
+void QueryView::slotFilter(int nCol)
+{
+ SearchResultsDlg dlg(this);
+ QRegExp re;
+ QListViewItem* pItem;
+ bool bNegate;
+
+ // Prepare the dialogue
+ dlg.setColumn(nCol);
+
+ // Show the dialogue
+ if (dlg.exec() != QDialog::Accepted)
+ return;
+
+ // Get the selected regular expression
+ dlg.getPattern(re);
+ bNegate = dlg.isNegated();
+
+ // Disable visual updates while search is in progress
+ setUpdatesEnabled(false);
+
+ // Iterate over all items in the list
+ pItem = firstChild();
+ while (pItem != NULL) {
+ // Filter visible items only
+ if (pItem->isVisible() &&
+ (re.search(pItem->text(nCol)) == -1) != bNegate) {
+ pItem->setVisible(false);
+ }
+
+ pItem = pItem->nextSibling();
+ }
+
+ // Redraw the list
+ setUpdatesEnabled(true);
+ triggerUpdate();
+}
+
+/**
+ * Makes all list items visible.
+ * This slot is connected to the showAll() signal of the QueryResultsMenu
+ * object.
+ */
+void QueryView::slotShowAll()
+{
+ QListViewItem* pItem;
+
+ // Iterate over all items in the list
+ pItem = firstChild();
+ while (pItem != NULL) {
+ pItem->setVisible(true);
+ pItem = pItem->nextSibling();
+ }
+}
+
+/**
+ * Deletes the item on which a popup-menu has been invoked.
+ * This slot is connected to the remove() signal of the QueryResultsMenu
+ * object.
+ * @param pItem The item to remove
+ */
+void QueryView::slotRemoveItem(QListViewItem* pItem)
+{
+ delete pItem;
+}
+
+/**
+ * Moves the iterator to the next _visible_ item in the list.
+ */
+void QueryView::Iterator::next()
+{
+ if (m_pItem == NULL)
+ return;
+
+ do {
+ m_pItem = m_pItem->nextSibling();
+ } while (m_pItem != NULL && !m_pItem->isVisible());
+}
+
+/**
+ * @return The function associated with the list item the iterator points to
+ */
+QString QueryView::Iterator::getFunc()
+{
+ if (m_pItem == NULL)
+ return "";
+
+ return m_pItem->text(0);
+}
+
+/**
+ * @return The file associated with the list item the iterator points to
+ */
+QString QueryView::Iterator::getFile()
+{
+ if (m_pItem == NULL)
+ return "";
+
+ return m_pItem->text(1);
+}
+
+/**
+ * @return The line number associated with the list item the iterator points
+ * to
+ */
+QString QueryView::Iterator::getLine()
+{
+ if (m_pItem == NULL)
+ return "";
+
+ return m_pItem->text(2);
+}
+
+/**
+ * @return The text associated with the list item the iterator points to
+ */
+QString QueryView::Iterator::getText()
+{
+ if (m_pItem == NULL)
+ return "";
+
+ return m_pItem->text(3);
+}
+
+#include "queryview.moc"
diff --git a/src/queryview.h b/src/queryview.h
new file mode 100644
index 0000000..c896d6b
--- /dev/null
+++ b/src/queryview.h
@@ -0,0 +1,217 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef QUERYVIEW_H
+#define QUERYVIEW_H
+
+#include <qlistview.h>
+#include <qregexp.h>
+
+class QueryResultsMenu;
+
+/**
+ * Items in a query view.
+ * The sole purpose for creating a new class is to be able to sort query
+ * results numerically by line number.
+ * @author Elad Lahav
+ */
+class QueryViewItem : public QListViewItem
+{
+public:
+ /**
+ * Class constructor.
+ * Used for list views.
+ * @param pView The view widget
+ * @param pAfter The item to preceed the new one
+ * @param nLineCol The index of the line column
+ */
+ QueryViewItem(QListView* pView, QListViewItem* pAfter,
+ int nLineCol) : QListViewItem(pView, pAfter), m_nLineCol(nLineCol)
+ {}
+
+ /**
+ * Class constructor.
+ * Used for tree views.
+ * @param pParent The parent item
+ * @param pAfter The item to preceed the new one
+ * @param nLineCol The index of the line column
+ */
+ QueryViewItem(QListViewItem* pParent, QListViewItem* pAfter,
+ int nLineCol) : QListViewItem(pParent, pAfter), m_nLineCol(nLineCol)
+ {}
+
+ /**
+ * Compares two items.
+ * If the given column holds line numbers, than the items are compared
+ * by their numeric values. Otherwise, a standard text comparison is
+ * performed.
+ * @param pItem The item to compare to
+ * @param nCol The column by which to compare
+ * @param bAscend Whether sorting in ascending or descending order
+ * @return 0 if the items are equal, 1 if the current item is greater,
+ * -1 if the current item is smaller
+ */
+ virtual int compare(QListViewItem* pItem, int nCol, bool bAscend) const {
+ if (nCol == m_nLineCol) {
+ uint nLineCur, nLineOther;
+ int nResult;
+
+ // Get the line numbers of each item
+ nLineCur = text(nCol).toUInt();
+ nLineOther = pItem->text(nCol).toUInt();
+
+ // Compare the line numbers
+ nResult = nLineCur - nLineOther;
+ if (nResult == 0)
+ return 0; // Items are equal
+ else if (nResult > 0)
+ return 1; // The first item is greater
+ else
+ return -1; // The second item is greater
+ }
+
+ return QListViewItem::compare(pItem, nCol, bAscend);
+ }
+
+private:
+ /** The index of the column holding the line numbers. */
+ int m_nLineCol;
+};
+
+/**
+ * A list view widget for displaying locations in the source code. Each record
+ * (list item) represents a single line of code.
+ * The main purpose of this class is for showing query results (@see
+ * QueryViewDriver), but is can also serve as a base class for any widget
+ * which needs to refer to locations in the source code (@see
+ * HistoryView).
+ * The view has 4 columns, for showing the file path, function name, line
+ * number and line text of a code location.
+ * The widget owns a popup menu which allows users to copy information
+ * from records, filter records, and more.
+ * @author Elad Lahav
+ */
+class QueryView : public QListView
+{
+ Q_OBJECT
+
+public:
+ QueryView(QWidget* pParent = 0, const char* szName = 0);
+ ~QueryView();
+
+ virtual void addRecord(const QString&, const QString&, const QString&,
+ const QString&, QListViewItem* pParent = NULL);
+ virtual void select(QListViewItem*);
+ virtual void selectNext();
+ virtual void selectPrev();
+ virtual void queryProgress();
+ virtual void queryFinished(uint, QListViewItem* pParent = NULL);
+
+ /**
+ * Provides an iterator over the list of query results.
+ * @author Elad Lahav
+ */
+ class Iterator
+ {
+ public:
+ /**
+ * Default constructor.
+ */
+ Iterator() : m_pItem(NULL) {}
+
+ /**
+ * Copy constructor.
+ * @param itr The copied object
+ */
+ Iterator(const Iterator& itr) : m_pItem(itr.m_pItem) {}
+
+ /**
+ * @return true if the iterator points _beyond_ the end of the list,
+ * false otherwise
+ */
+ bool isEOF() { return m_pItem == NULL; }
+
+ void next();
+
+ QString getFunc();
+ QString getFile();
+ QString getLine();
+ QString getText();
+
+ private:
+ /** Points to the current list item. */
+ QListViewItem* m_pItem;
+
+ /**
+ * Private constructor used to return initialised iterators.
+ * This constructor can only be called from within QueryView.
+ * @param pItem The initial list item
+ */
+ Iterator(QListViewItem* pItem) : m_pItem(pItem) {}
+
+ friend class QueryView;
+ };
+
+ Iterator getIterator();
+
+signals:
+ /**
+ * Notifies the owner widget that it needs to be visible since some
+ * information is available to display.
+ * This information may be an advancement of the progress bar,
+ * availability of query results, etc.
+ */
+ void needToShow();
+
+ /**
+ * Emitted when a list record is selected.
+ * Selection is done by either double-clicking a query or by highlighting
+ * it and then pressing the ENTER key.
+ * @param sFile The "File" field of the selected record
+ * @param nLine The "Line" field of the selected record
+ */
+ void lineRequested(const QString& sFile, uint nLine);
+
+protected:
+ /** A popup-menu for manipulating query result items. */
+ QueryResultsMenu* m_pQueryMenu;
+
+ /** A pointer to the last item (used for appending results). */
+ QListViewItem* m_pLastItem;
+
+ void contentsMouseDoubleClickEvent(QMouseEvent*);
+
+protected slots:
+ virtual void slotRecordSelected(QListViewItem*);
+ virtual void slotFindDef(const QString&);
+ virtual void slotCopy(QListViewItem*, int);
+ virtual void slotFilter(int);
+ virtual void slotShowAll();
+ virtual void slotRemoveItem(QListViewItem*);
+};
+
+#endif
diff --git a/src/queryviewdlg.cpp b/src/queryviewdlg.cpp
new file mode 100644
index 0000000..93cd85e
--- /dev/null
+++ b/src/queryviewdlg.cpp
@@ -0,0 +1,111 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include "queryviewdlg.h"
+#include "queryviewdriver.h"
+
+/**
+ * Class constructor.
+ * @param nFlags Controls the behaviour of the diaogue
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+QueryViewDlg::QueryViewDlg(uint nFlags, QWidget* pParent,
+ const char* szName) :
+ QueryViewLayout(pParent, szName),
+ m_nFlags(nFlags)
+{
+ // Set the destructive flag, if required
+ if (nFlags & DestroyOnClose)
+ setWFlags(getWFlags() | WDestructiveClose);
+
+ // Create a driver for running queries
+ m_pDriver = new QueryViewDriver(m_pView, this);
+
+ // Show the dialogue when instructed by the driver
+ connect(m_pView, SIGNAL(needToShow()), this, SLOT(slotShow()));
+
+ // Propagate the lineRequested() signal from the QueryView object
+ connect(m_pView, SIGNAL(lineRequested(const QString&, uint)), this,
+ SLOT(slotLineRequested(const QString&, uint)));
+
+ // Make the dialogue modal
+ setModal(true);
+}
+
+/**
+ * Class destructor.
+ */
+QueryViewDlg::~QueryViewDlg()
+{
+}
+
+/**
+ * Starts a query.
+ * @param nType The type of the query
+ * @param sText The query's text
+ * @param bCase true for case-sensitive queries, false otherwise
+ */
+void QueryViewDlg::query(uint nType, const QString& sText, bool bCase)
+{
+ m_pDriver->query(nType, sText, bCase);
+}
+
+/**
+ * Make the dialogue visible when instructed by the driver.
+ * This slot is connected to the show() signal emitted by the QueryViewDriver
+ * object.
+ */
+void QueryViewDlg::slotShow()
+{
+ show();
+}
+
+/**
+ * Propagates the lineRequested() signal from the view object.
+ * If the CloseOnSelect flag is set, the dialogue is closed.
+ * This slot is connected to the lineRequested() signal emitted by the
+ * QueryView widget.
+ */
+void QueryViewDlg::slotLineRequested(const QString& sFileName, uint nLine)
+{
+ emit lineRequested(sFileName, nLine);
+
+ if (m_nFlags & CloseOnSelect)
+ close();
+}
+
+/**
+ * @return A QueryView iterator initialised to the beginning of the result
+ * list
+ */
+QueryView::Iterator QueryViewDlg::getIterator()
+{
+ return m_pView->getIterator();
+}
+
+#include "queryviewdlg.moc"
diff --git a/src/queryviewdlg.h b/src/queryviewdlg.h
new file mode 100644
index 0000000..fc1c2f7
--- /dev/null
+++ b/src/queryviewdlg.h
@@ -0,0 +1,88 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef QUERYVIEWDLG_H
+#define QUERYVIEWDLG_H
+
+#include "queryviewlayout.h"
+#include "queryview.h"
+
+class QueryViewDriver;
+
+/**
+ * A dialogue for running and displaying queries.
+ * The dialogue is built around a QueryView widget, and uses a QueryViewDriver
+ * object to run a query. The dialogue is used in different contexts, such
+ * as executing quick definitions, displaying multiple call nodes in a graph,
+ * etc.
+ * The dialogue is always modal, but should not be launched using exec().
+ * Instead, it is created as a modeless, hidden, dialogue. It then becomes
+ * modal (and visible) only if and when information is available (@see
+ * QueryViewDriver::show()).
+ * @author Elad Lahav
+ */
+class QueryViewDlg : public QueryViewLayout
+{
+ Q_OBJECT
+
+public:
+ QueryViewDlg(uint nFlags = 0, QWidget* pParent = 0,
+ const char* szName = 0);
+ ~QueryViewDlg();
+
+ /** These flags control the behaviour of the dialogue. */
+ enum { CloseOnSelect = 0x1, DestroyOnClose = 0x2,
+ DestroyOnSelect = CloseOnSelect | DestroyOnClose };
+
+ void query(uint, const QString&, bool bCase = true);
+
+ QueryView::Iterator getIterator();
+
+signals:
+ /**
+ * Propagates the lineRequested() signal of the embedded QueryView
+ * widget.
+ * @param sFile The "File" field of the selected record
+ * @param nLine The "Line" field of the selected record
+ */
+ void lineRequested(const QString& sFile, uint nLine);
+
+private:
+ /** Flags the control the behaviour of the dialogue. */
+ uint m_nFlags;
+
+ /** Used for running Cscope queries and displaying their results in the
+ view. */
+ QueryViewDriver* m_pDriver;
+
+private slots:
+ void slotShow();
+ void slotLineRequested(const QString&, uint);
+};
+
+#endif
+
diff --git a/src/queryviewdriver.cpp b/src/queryviewdriver.cpp
new file mode 100644
index 0000000..f04c44d
--- /dev/null
+++ b/src/queryviewdriver.cpp
@@ -0,0 +1,180 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <klocale.h>
+#include "queryviewdriver.h"
+#include "queryview.h"
+
+/**
+ * Class constructor.
+ * Creates a driver that adds new records as root items in the given view.
+ * @param pView The view to which this driver should add records
+ * @param pParent The parent object of the driver
+ * @param szName The name of the object
+ */
+QueryViewDriver::QueryViewDriver(QueryView* pView, QObject* pParent,
+ const char* szName) : QObject(pParent, szName),
+ m_pView(pView),
+ m_pItem(NULL),
+ m_progress(pView),
+ m_bRunning(false)
+{
+ m_pCscope = new CscopeFrontend();
+
+ // Add records to the page when Cscope outputs them
+ connect(m_pCscope, SIGNAL(dataReady(FrontendToken*)), this,
+ SLOT(slotDataReady(FrontendToken*)));
+
+ // Report progress information
+ connect(m_pCscope, SIGNAL(progress(int, int)), this,
+ SLOT(slotProgress(int, int)));
+
+ // Perform tasks when the query process terminates
+ connect(m_pCscope, SIGNAL(finished(uint)), this,
+ SLOT(slotFinished(uint)));
+
+ connect(m_pView, SIGNAL(destroyed()), this, SLOT(slotViewClosed()));
+}
+
+/**
+ * Class destructor.
+ */
+QueryViewDriver::~QueryViewDriver()
+{
+ delete m_pCscope;
+}
+
+/**
+ * Executes a query.
+ * @param nType The type of the query (@see CscopeFrontend)
+ * @param sText The query's text
+ * @param bCase true for case-sensitive queries, false otherwise
+ * @param pItem If non-null, represents an view item passed back to
+ * the view in a call to addRecord()
+ */
+void QueryViewDriver::query(uint nType, const QString& sText, bool bCase,
+ QListViewItem* pItem)
+{
+ m_pItem = pItem;
+
+ // Make sure sorting is disabled while entries are added
+ m_pView->setSorting(100);
+
+ // Execute the query
+ m_pCscope->query(nType, sText, bCase);
+ m_bRunning = true;
+ m_pView->setEnabled(false);
+ m_pView->setUpdatesEnabled(false);
+}
+
+/**
+ * Adds a query entry to the view.
+ * Called by a CscopeFrontend object, when a new entry was received in its
+ * whole from the Cscope back-end process.
+ * @param pToken The first token in the entry
+ */
+void QueryViewDriver::slotDataReady(FrontendToken* pToken)
+{
+ QString sFile, sFunc, sLine, sText;
+
+ // Get the file name
+ sFile = pToken->getData();
+ pToken = pToken->getNext();
+
+ // Get the function name
+ sFunc = pToken->getData();
+ pToken = pToken->getNext();
+
+ // Get the line number
+ sLine = pToken->getData();
+ if (!sLine.toInt()) {
+ // Line number could not be 0!
+ // means that function name was empty
+ sLine = sFunc;
+ sFunc = "<global>";
+ }
+ else {
+ pToken = pToken->getNext();
+ }
+
+ // Get the line's text
+ sText = pToken->getData();
+ pToken = pToken->getNext();
+
+ // Add a new item at the end of the list
+ m_pView->addRecord(sFunc, sFile, sLine, sText, m_pItem);
+}
+
+/**
+ * Handles a finished query event, reported by the Cscope frontend object.
+ * If no resutls are available, a proper message is displayed. If only one
+ * record was generated by Cscope, it is automatically selected for viewing.
+ * @param nRecords The number of records the query has generated
+ */
+void QueryViewDriver::slotFinished(uint nRecords)
+{
+ // The query is no longer running
+ m_bRunning = false;
+ m_pView->setEnabled(true);
+ m_pView->setUpdatesEnabled(true);
+ m_pView->triggerUpdate();
+
+ // Destroy the progress bar
+ m_progress.finished();
+
+ // Let owner widget decide what to do based on the number of records
+ m_pView->queryFinished(nRecords, m_pItem);
+}
+
+/**
+ * Displays search progress information.
+ * This slot is connected to the progress() signal emitted by a
+ * CscopeFrontend object.
+ * @param nFiles The number of files scanned
+ * @param nTotal The total number of files in the project
+ */
+void QueryViewDriver::slotProgress(int nFiles, int nTotal)
+{
+ // A progress report is available, instruct the owner object to show the
+ // view
+ if (nTotal > 1)
+ m_pView->queryProgress();
+
+ // Set the progress bar
+ m_progress.setProgress(nFiles, nTotal);
+}
+
+/**
+ * Called when the owner view is destroyed.
+ */
+void QueryViewDriver::slotViewClosed()
+{
+ m_pView = NULL;
+ m_pCscope->kill();
+}
+
+#include "queryviewdriver.moc"
diff --git a/src/queryviewdriver.h b/src/queryviewdriver.h
new file mode 100644
index 0000000..77ff9ed
--- /dev/null
+++ b/src/queryviewdriver.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef QUERYVIEWDRIVER_H
+#define QUERYVIEWDRIVER_H
+
+#include <qobject.h>
+#include <qlistview.h>
+#include "cscopefrontend.h"
+
+class QueryView;
+
+/**
+ * Executes a Cscope query and displays the results in a QueryView widget.
+ * This class is used in conjunction with QueryView to create a query
+ * display object. The driver uses the view widget to display result records
+ * of an executed query. It also uses the view as a parent widget for the
+ * query progress bar.
+ * @author Elad Lahav
+ */
+class QueryViewDriver : public QObject
+{
+ Q_OBJECT
+
+public:
+ QueryViewDriver(QueryView*, QObject* pParent = 0, const char* szName = 0);
+ ~QueryViewDriver();
+
+ void query(uint, const QString&, bool bCase, QListViewItem* pItem = NULL);
+
+ /**
+ * @return true if a query is currently running, false otherwise
+ */
+ bool isRunning() { return m_bRunning; }
+
+private:
+ /** Cscope object for running queries. */
+ CscopeFrontend* m_pCscope;
+
+ /** The view to which this object adds result records. */
+ QueryView* m_pView;
+
+ /** QueryView item passed to addRecord(). */
+ QListViewItem* m_pItem;
+
+ /** Displays query progress information. */
+ CscopeProgress m_progress;
+
+ /** This flag is set to true when a query is executed, and back to false
+ when the the CscopeFrontend object emits the finished() signal. */
+ bool m_bRunning;
+
+private slots:
+ void slotDataReady(FrontendToken*);
+ void slotFinished(uint);
+ void slotProgress(int, int);
+ void slotViewClosed();
+};
+
+#endif
diff --git a/src/queryviewlayout.ui b/src/queryviewlayout.ui
new file mode 100644
index 0000000..ae097c5
--- /dev/null
+++ b/src/queryviewlayout.ui
@@ -0,0 +1,167 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>QueryViewLayout</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>QueryViewLayout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>654</width>
+ <height>499</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Query Results</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QueryView">
+ <property name="name">
+ <cstring>m_pView</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Right-click inside the list for more options.</string>
+ </property>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>QueryView</class>
+ <header location="local">queryview.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="1003">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b249444154388db5944d4c5c5518869f73ce9db9cc40f929cc30300e18129a50685268a28291982e1a2175212eaab1c49d3f8971e7aec6aedb54a32b435dd8685cb8c0c4b8b0feb421b7bd8186a069d23209144b18cb0c02f3732ff3c3ccbdd705a571941213f1dd9d93739ef37e6fbeef08d334d9d5d0d090c701c8344d2176c1a6697a5d5d5dd8b64d2a95c2b2ac7f05b12c8b783c8e6118d8b6fd685fdb753a39394928e2a7c55724d693a7e214104220242805520a84d8b9e4790f0b1302c7751958f1e30534be9fa41a0c60db362dbe227f64af91b6e7719c2dfc0117a71c603da591de2882a7d3d4ec27122b10acad50aeb88044d542b84de3af7ab44aa55274f4e449dbf354bc347aa096fbf37e7efa2ecbad1b36907d78b289de8120232f37726250c3f52cf0a026a0f6065b9645d929e038167aa096d91b307171059034b5f8e9e9eb44fa052b4b25eeccd9dc99cb71f6ad082fbea2e351c075bdbdc13b9109fc01b83fef63e2e232e03076b68393231a0dcd024daf502c1e66e67a89cb971ef0e5a74bb4b61e6378248094b92ab0ac024b70ca017ef8360394187b2dc6d8b89ffa500e4d4f93d9083275d5e6f9913ade3dd70ee87c7d25c95646a25415aadab152b09ed4f8c5cc130a853839eac3951b684a61e70ef3f9c739668c24eba912afbfddc6d4d506e6a6d7b8b7d082aa8eb8dab19482cdcd220e36dd3dc19df23545de0a71f952861923493456cfd3cf36123c54a0b7bf0e8064621b21f7712c040857071ca4eea0f40a99f510573ec971cb48030e811a1faded3e94be85f2fb00703d1ff26f96ab9f011a5b04d0c4f26fdb948a754c1b25668c2491483d5d5d611617d6b8f0fe32cb779b492ce65168b4c774a4701eefd8f3a02d56e6e8f13aeefe9a63fa5a89d1970e91d908f3d46003e1480d173e28b37827c9b977348ab92ce16890237d1ec907ee3e8e3d8f60d0e1f4583d009f7d9860662acff89bad1c1faad0717493f7ce7713ed8cb0995c255f2a317a26427b67198f6a70f51c0a41b902279ed1187f23cc17130b7c74de65eac77a7a8f05517e41e2deefa4930576db60fa7a8ee1535134df3e93e7b82e0817476439fd6a9070a49f6fbe4a3077739db99b15c001146dd13a46cf1cc1f83943c62e51de76b0738fc9381e8f3390f0236b252e124999e11724fd833196164bacadb87848224fe874f779b43fe9f2dca928956d505a96dbb3f9bdc18661e00534c26d1a7a40e13912a11c9454280da41048a9915c75585df500074d53d816dc9edd229528ef0db66dbbea3ffdaffa471f1f28d8344df1bf800f1a6e9aa6f813c39885bc050f269c0000000049454e44ae426082</data>
+ </image>
+</images>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>QueryViewLayout</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>QueryViewLayout</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>queryview.h</includehint>
+</includehints>
+</UI>
diff --git a/src/querywidget.cpp b/src/querywidget.cpp
new file mode 100644
index 0000000..113f216
--- /dev/null
+++ b/src/querywidget.cpp
@@ -0,0 +1,601 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qtoolbutton.h>
+#include <qtooltip.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include "querywidget.h"
+#include "kscopepixmaps.h"
+#include "kscopeconfig.h"
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+QueryWidget::QueryWidget(QWidget* pParent, const char* szName) :
+ QueryWidgetLayout(pParent, szName),
+ m_pPageMenu(NULL),
+ m_pLockAction(NULL),
+ m_pHistPage(NULL),
+ m_bHistEnabled(true),
+ m_nQueryPages(0)
+{
+ // Pages can be closed by clicking their tabs
+ m_pQueryTabs->setHoverCloseButton(true);
+
+ // Change the lock action state according to the current page
+ connect(m_pQueryTabs, SIGNAL(currentChanged(QWidget*)), this,
+ SLOT(slotCurrentChanged(QWidget*)));
+
+ // Close a query when its tab button is clicked
+ connect(m_pQueryTabs, SIGNAL(closeRequest(QWidget*)), this,
+ SLOT(slotClosePage(QWidget*)));
+
+ // Show the menu when requested
+ connect(m_pQueryTabs, SIGNAL(contextMenu(const QPoint&)), this,
+ SLOT(slotContextMenu(const QPoint&)));
+ connect(m_pQueryTabs, SIGNAL(contextMenu(QWidget*, const QPoint&)), this,
+ SLOT(slotContextMenu(QWidget*, const QPoint&)));
+}
+
+/**
+ * Class destructor.
+ */
+QueryWidget::~QueryWidget()
+{
+}
+
+/**
+ * Runs a query in a query page.
+ * A query page is first selected, with a new one created if required. The
+ * method then creates a Cscope process and runs the query.
+ * @param nType The query's numeric type code
+ * @param sText The query's text, as entered by the user
+ * @param bCase true for case-sensitive queries, false otherwise
+ */
+void QueryWidget::initQuery(uint nType, const QString& sText, bool bCase)
+{
+ QueryPage* pPage;
+
+ // Make sure we have a query page
+ findQueryPage();
+ pPage = (QueryPage*)currentPage();
+
+ // Use the current page, or a new page if the current one is locked
+ if (pPage->isLocked()) {
+ addQueryPage();
+ pPage = (QueryPage*)currentPage();
+ }
+
+ // Reset the page's results list
+ pPage->clear();
+ pPage->query(nType, sText, bCase);
+
+ // Set the page's tab text according to the new query
+ setPageCaption(pPage);
+}
+
+/**
+ * Applies the user's colour and font preferences to all pages.
+ */
+void QueryWidget::applyPrefs()
+{
+ QueryPage* pPage;
+ int nPages, i;
+
+ // Iterate query pages
+ nPages = m_pQueryTabs->count();
+ for (i = 0; i < nPages; i++) {
+ pPage = (QueryPage*)m_pQueryTabs->page(i);
+ pPage->applyPrefs();
+ setPageCaption(pPage);
+ }
+}
+
+/**
+ * Loads all pages saved when the project was closed.
+ * @param sProjPath The full path of the project directory
+ * @param slFiles The list of query file names to load
+ */
+void QueryWidget::loadPages(const QString& sProjPath,
+ const QStringList& slFiles)
+{
+ QStringList::ConstIterator itr;
+ QueryPageBase* pPage;
+ QString sName;
+
+ // Iterate through query files
+ for (itr = slFiles.begin(); itr != slFiles.end(); ++itr) {
+ // Set the target page, based on the file type (query or history)
+ if ((*itr).startsWith("History")) {
+ findHistoryPage();
+ pPage = m_pHistPage;
+ }
+ else {
+ findQueryPage();
+ pPage = (QueryPage*)currentPage();
+ }
+
+ // Load a query file to this page, and lock the page
+ if (pPage->load(sProjPath, *itr)) {
+ setPageCaption(pPage);
+ setPageLocked(pPage, true);
+ }
+ }
+}
+
+/**
+ * Stores all pages marked for saving into files in the project directory.
+ * @param sProjPath The full path of the project directory
+ * @param slFiles Holds a list of query file names, upon return
+ */
+void QueryWidget::savePages(const QString& sProjPath, QStringList& slFiles)
+{
+ int nPageCount, i;
+ QueryPage* pPage;
+ QString sFileName;
+
+ // Iterate pages
+ nPageCount = m_pQueryTabs->count();
+ for (i = 0; i < nPageCount; i++) {
+ pPage = (QueryPage*)m_pQueryTabs->page(i);
+ if (pPage->shouldSave()) {
+ // Store this query page
+ if (pPage->save(sProjPath, sFileName) && !sFileName.isEmpty())
+ slFiles.append(sFileName);
+ }
+ }
+}
+
+/**
+ * Adds a new position record to the active history page.
+ * @param sFile The file path
+ * @param nLine The line number
+ * @param sText The contents of the line pointed to by the file path and
+ * line number
+ */
+void QueryWidget::addHistoryRecord(const QString& sFile, uint nLine,
+ const QString& sText)
+{
+ // Validate file name and line number
+ if (sFile.isEmpty() || nLine == 0)
+ return;
+
+ // Do nothing if history logging is disabled
+ if (!m_bHistEnabled)
+ return;
+
+ // Make sure there is an active history page
+ findHistoryPage();
+
+ // Add the position entry to the active page
+ m_pHistPage->addRecord(sFile, nLine, sText);
+}
+
+/**
+ * Sets the tab caption and tool-tip for the given page.
+ * @param pPage The page whose tab needs to be changed
+ */
+void QueryWidget::setPageCaption(QueryPageBase* pPage)
+{
+ m_pQueryTabs->changeTab(pPage,
+ pPage->getCaption(Config().getUseBriefQueryCaptions()));
+ m_pQueryTabs->setTabToolTip(pPage, pPage->getCaption());
+}
+
+/**
+ * Creates a new query page, and adds it to the tab widget.
+ * The new page is set as the current one.
+ */
+void QueryWidget::addQueryPage()
+{
+ QueryPage* pPage;
+ QString sTitle;
+
+ // Create the page
+ pPage = new QueryPage(this);
+
+ // Add the page, and set it as the current one
+ m_pQueryTabs->insertTab(pPage, GET_PIXMAP(TabUnlocked), "Query",
+ m_nQueryPages++);
+ setCurrentPage(pPage);
+
+ // Emit the lineRequested() signal when a query record is selected on
+ // this page
+ connect(pPage, SIGNAL(lineRequested(const QString&, uint)), this,
+ SLOT(slotRequestLine(const QString&, uint)));
+}
+
+/**
+ * Creates a new query page, and emits signal about it.
+ */
+void QueryWidget::slotNewQueryPage()
+{
+ addQueryPage();
+ emit newQuery();
+}
+
+/**
+ * Locks or unlocks a query.
+ * This slot is connected to the toggled() signal of the lock query button.
+ * @param bOn true if the new state of the button is "on", false if it is
+ * "off"
+ */
+void QueryWidget::slotLockCurrent(bool bOn)
+{
+ QueryPageBase* pPage;
+
+ pPage = currentPage();
+
+ if (pPage != NULL)
+ setPageLocked(currentPage(), bOn);
+}
+
+/**
+ * Locks or unlocks a query, by toggling the current state.
+ */
+void QueryWidget::slotLockCurrent()
+{
+ QueryPageBase* pPage;
+
+ pPage = currentPage();
+ if (pPage != NULL)
+ setPageLocked(pPage, !pPage->isLocked());
+}
+
+/**
+ * Reruns the query whose results are displayed in the current page.
+ */
+void QueryWidget::slotRefreshCurrent()
+{
+ QueryPage* pPage;
+
+ // Make sure the current page is a valid, non-empty one
+ pPage = dynamic_cast<QueryPage*>(currentPage());
+ if (pPage == NULL)
+ return;
+
+ // Clear the current page contents
+ pPage->refresh();
+}
+
+/**
+ * Selects the next query result record in the current query page.
+ */
+void QueryWidget::slotNextResult()
+{
+ QueryPage* pPage;
+
+ // Select the next record in the current page
+ pPage = dynamic_cast<QueryPage*>(currentPage());
+ if (pPage != NULL)
+ pPage->selectNext();
+}
+
+/**
+ * Selects the next query result record in the current query page.
+ */
+void QueryWidget::slotPrevResult()
+{
+ QueryPage* pPage;
+
+ // Select the next record in the current page
+ pPage = dynamic_cast<QueryPage*>(currentPage());
+ if (pPage != NULL)
+ pPage->selectPrev();
+}
+
+/**
+ * Closes the current query page.
+ */
+void QueryWidget::slotCloseCurrent()
+{
+ QWidget* pPage;
+
+ // Close the current page
+ pPage = currentPage();
+ if (pPage != NULL)
+ slotClosePage(pPage);
+}
+
+/**
+ * Closes all query pages.
+ */
+void QueryWidget::slotCloseAll()
+{
+ int nPageCount, i;
+ QueryPage* pPage;
+
+ // Close all pages
+ nPageCount = m_pQueryTabs->count();
+ for (i = 0; i < nPageCount; i++) {
+ pPage = (QueryPage*)m_pQueryTabs->page(0);
+ m_pQueryTabs->removePage(pPage);
+ delete pPage;
+ }
+
+ m_pHistPage = NULL;
+}
+
+/**
+ * Handles the "Go->Back" menu command.
+ * Moves to the previous position in the position history.
+ */
+void QueryWidget::slotHistoryPrev()
+{
+ if (m_pHistPage != NULL) {
+ m_bHistEnabled = false;
+ m_pHistPage->selectPrev();
+ m_bHistEnabled = true;
+ }
+}
+
+/**
+ * Handles the "Go->Forward" menu command.
+ * Moves to the next position in the position history.
+ */
+void QueryWidget::slotHistoryNext()
+{
+ if (m_pHistPage != NULL) {
+ m_bHistEnabled = false;
+ m_pHistPage->selectNext();
+ m_bHistEnabled = true;
+ }
+}
+
+/**
+ * Sets the active history page, if any, as the current page.
+ */
+void QueryWidget::selectActiveHistory()
+{
+ if (m_pHistPage)
+ setCurrentPage(m_pHistPage);
+}
+
+/**
+ * Attaches the page operations menu to this widget.
+ * The page menu is a popup menu that handles such operations as opening a
+ * new page, closing a page, locking a page, etc.
+ * @param pMenu Pointer to the popup menu
+ * @param pAction Pointer to the "Lock/Unlock" toggle action
+ */
+void QueryWidget::setPageMenu(QPopupMenu* pMenu, KToggleAction* pAction)
+{
+ m_pPageMenu = pMenu;
+ m_pLockAction = pAction;
+}
+
+/**
+ * Emits a signal indicating a certain source file and line number are
+ * requested.
+ * This slot is connected to the recordSelected() signal emitted by any of
+ * the query pages. The signal emitted by this slot is used to display an
+ * editor page at the requested line.
+ * @param sFileName The file's path
+ * @param nLine The requested line in the file
+ */
+void QueryWidget::slotRequestLine(const QString& sFileName, uint nLine)
+{
+ // Disable history if the request came from the active history page
+ if (currentPage() == m_pHistPage)
+ m_bHistEnabled = false;
+
+ // Emit the signal
+ emit lineRequested(sFileName, nLine);
+
+ // Re-enable history
+ if (currentPage() == m_pHistPage)
+ m_bHistEnabled = true;
+}
+
+/**
+ * Update the lock button when the current query page changes.
+ * @param pWidget The new current page
+ */
+void QueryWidget::slotCurrentChanged(QWidget* pWidget)
+{
+ QueryPage* pPage;
+
+ pPage = (QueryPage*)pWidget;
+ m_pLockAction->setChecked(pPage->isLocked());
+}
+
+/**
+ * Removes the given page from the tab widget.
+ * This slot is connected to the closeRequest() signal of the KTabBar object.
+ * @param pPage The page to close
+ */
+void QueryWidget::slotClosePage(QWidget* pPage)
+{
+ // Prompt the user before closing a locked query
+ if (((QueryPage*)pPage)->isLocked()) {
+ if (KMessageBox::questionYesNo(NULL, i18n("You about about to close"
+ " a locked page.\nAre you sure?")) == KMessageBox::No) {
+ return;
+ }
+ }
+
+ // Check if the closed page is the active history page
+ if (pPage == m_pHistPage)
+ m_pHistPage = NULL;
+ // Update the number of open history pages
+ else if (dynamic_cast<HistoryPage*>(pPage) == NULL)
+ m_nQueryPages--;
+
+ // Remove the page and delete the object
+ m_pQueryTabs->removePage(pPage);
+ delete pPage;
+}
+
+/**
+ * Displays a context menu for page operations.
+ * This slot is connected to the contextMenu() signal, emitted by
+ * m_pQueryTabs.
+ * NOTE: We assume that the first item in the menu is "New".
+ * @param pt The point over which the mouse was clicked in request for the
+ * context menu
+ */
+void QueryWidget::slotContextMenu(const QPoint& pt)
+{
+ uint i;
+
+ // Disable everything but the "new" action (clicked outside any widget)
+ for (i = 1; i < m_pPageMenu->count(); i++)
+ m_pPageMenu->setItemEnabled(m_pPageMenu->idAt(i), false);
+
+ // Show the menu
+ m_pPageMenu->popup(pt);
+}
+
+/**
+ * Displays a context menu for page operations.
+ * This slot is connected to the contextMenu() signal, emitted by
+ * m_pQueryTabs.
+ * @param pWidget The page under the mouse
+ * @param pt The point over which the mouse was clicked in request for
+ * the context menu
+ */
+void QueryWidget::slotContextMenu(QWidget* pWidget, const QPoint& pt)
+{
+ uint i;
+
+ // Operations are on the current page, so we must ensure the clicked
+ // tab becomes the current one
+ setCurrentPage(pWidget);
+
+ // Enable all operations
+ for (i = 1; i < m_pPageMenu->count(); i++)
+ m_pPageMenu->setItemEnabled(m_pPageMenu->idAt(i), true);
+
+ // Show the menu
+ m_pPageMenu->popup(pt);
+}
+
+/**
+ * Locks/unlocks the give page.
+ * @param pPage The page to lock or unlock
+ * @param bLock true to lock the page, false to unlock it
+ */
+void QueryWidget::setPageLocked(QueryPageBase* pPage, bool bLock)
+{
+ if (!pPage->canLock())
+ return;
+
+ // Set the locking state of the current page
+ pPage->setLocked(bLock);
+ m_pQueryTabs->setTabIconSet(pPage, bLock ? GET_PIXMAP(TabLocked) :
+ GET_PIXMAP(TabUnlocked));
+
+ // There can only be one unlocked history page. Check if a non-active
+ // query page is being unlocked
+ if (isHistoryPage(pPage) && (pPage != m_pHistPage) && !bLock) {
+ // Lock the active history page (may be NULL)
+ if (m_pHistPage != NULL)
+ setPageLocked(m_pHistPage, true);
+
+ // Set the unlock page as the new active history page
+ m_pHistPage = (HistoryPage*)pPage;
+ }
+}
+
+/**
+ * Ensures the current page is a query page that is ready to accept new
+ * queries.
+ * The function first checks the current page. If it is an unlocked query
+ * page, then nothing needs to be done. Otherwise, it checks for the first
+ * unlocked query page by iterating over all pages in the tab widget. If this
+ * fails as well, a new query page is created.
+ */
+void QueryWidget::findQueryPage()
+{
+ QueryPage* pPage;
+ int nPages, i;
+
+ // First check if the current page is an unlocked query page
+ pPage = dynamic_cast<QueryPage*>(currentPage());
+ if (pPage != NULL) {
+ if (!pPage->isLocked() && !pPage->isRunning())
+ return;
+ }
+
+ // Look for the first unlocked query page
+ nPages = m_pQueryTabs->count();
+ for (i = 0; i < nPages; i++) {
+ pPage = dynamic_cast<QueryPage*>(m_pQueryTabs->page(i));
+ if (pPage != NULL) {
+ if (!pPage->isLocked() && !pPage->isRunning()) {
+ setCurrentPage(pPage);
+ return;
+ }
+ }
+ }
+
+ // Couldn't find an unlocked query page, create a new one
+ addQueryPage();
+}
+
+/**
+ * Ensures an active history page exists.
+ * The active history page is the only unlocked history page. If one does not
+ * exist, it is created.
+ */
+void QueryWidget::findHistoryPage()
+{
+ HistoryPage* pPage;
+ int nPages, i;
+ QString sTitle;
+
+ // First check if the active history page is unlocked
+ if (m_pHistPage != NULL && !m_pHistPage->isLocked())
+ return;
+
+ // Look for the first unlocked history page
+ nPages = m_pQueryTabs->count();
+ for (i = 0; i < nPages; i++) {
+ pPage = dynamic_cast<HistoryPage*>(m_pQueryTabs->page(i));
+ if (pPage != NULL && !pPage->isLocked()) {
+ m_pHistPage = pPage;
+ return;
+ }
+ }
+
+ // Couldn't find an unlocked query page, create a new one
+ m_pHistPage = new HistoryPage(this);
+
+ // Add the page, and set it as the current one
+ m_pQueryTabs->insertTab(m_pHistPage, GET_PIXMAP(TabUnlocked), "");
+ setPageCaption(m_pHistPage);
+
+ // Emit the lineRequested() signal when a query record is selected on
+ // this page
+ connect(m_pHistPage, SIGNAL(lineRequested(const QString&, uint)), this,
+ SLOT(slotRequestLine(const QString&, uint)));
+}
+
+#include "querywidget.moc"
diff --git a/src/querywidget.h b/src/querywidget.h
new file mode 100644
index 0000000..a798ec0
--- /dev/null
+++ b/src/querywidget.h
@@ -0,0 +1,152 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef QUERYWIDGET_H
+#define QUERYWIDGET_H
+
+#include <qlistview.h>
+#include <qpopupmenu.h>
+#include <kaction.h>
+#include "querywidgetlayout.h"
+#include "tabwidget.h"
+#include "querypage.h"
+#include "historypage.h"
+#include "projectmanager.h"
+
+/**
+ * A tabbed-window holding Cscope query results pages.
+ * @author Elad Lahav
+ */
+
+class QueryWidget : public QueryWidgetLayout
+{
+ Q_OBJECT
+
+public:
+ QueryWidget(QWidget* pParent = 0, const char* szName = 0);
+ ~QueryWidget();
+
+ void addQueryPage();
+ void initQuery(uint, const QString&, bool);
+ void applyPrefs();
+ void loadPages(const QString&, const QStringList&);
+ void savePages(const QString&, QStringList&);
+ void addHistoryRecord(const QString&, uint, const QString&);
+ void selectActiveHistory();
+ void setPageMenu(QPopupMenu*, KToggleAction*);
+ void getBookmarks(FileLocationList&);
+
+ /**
+ * Enables/disables new history items.
+ * @param bEnabled true to enable new history items, false to
+ * disable
+ */
+ void setHistoryEnabled(bool bEnabled) { m_bHistEnabled = bEnabled; }
+
+public slots:
+ void slotNewQueryPage();
+ void slotLockCurrent(bool);
+ void slotLockCurrent();
+ void slotRefreshCurrent();
+ void slotNextResult();
+ void slotPrevResult();
+ void slotCloseCurrent();
+ void slotCloseAll();
+ void slotHistoryPrev();
+ void slotHistoryNext();
+
+signals:
+ /**
+ * Emitted when the a lineRequested() signal is received from any of the
+ * currently open query pages.
+ * @param sPath The full path of the requested source file
+ * @param nLine The requested line number
+ */
+ void lineRequested(const QString& sPath, uint nLine);
+
+ /**
+ * Emitted when new query page is requested by user
+ */
+ void newQuery();
+
+private:
+ /** A popup menu with query page commands (new query, lock/unlock, close
+ query, etc.). */
+ QPopupMenu* m_pPageMenu;
+
+ /** A toggle-like action for changing the locked state of a query. */
+ KToggleAction* m_pLockAction;
+
+ /** The active history page. */
+ HistoryPage* m_pHistPage;
+
+ /** Determines whether history items should be added to the active
+ history page. */
+ bool m_bHistEnabled;
+
+ /** The number of query pages currently open. */
+ int m_nQueryPages;
+
+ void setPageCaption(QueryPageBase*);
+
+ /**
+ * @return The active page in the tab widget
+ */
+ inline QueryPageBase* currentPage() {
+ return (QueryPageBase*)m_pQueryTabs->currentPage();
+ }
+
+ /**
+ * @param pWidget A query page to set as the current one
+ */
+ inline void setCurrentPage(QWidget* pWidget) {
+ if (pWidget)
+ m_pQueryTabs->setCurrentPage(m_pQueryTabs->indexOf(pWidget));
+ }
+
+ /**
+ * Determines if a page is a history page.
+ * @param pPage The page to check
+ * @return true if the given page is a history page
+ */
+ inline bool isHistoryPage(QWidget* pPage) {
+ return (dynamic_cast<HistoryPage*>(pPage) != NULL);
+ }
+
+ void setPageLocked(QueryPageBase*, bool);
+ void findQueryPage();
+ void findHistoryPage();
+
+private slots:
+ void slotRequestLine(const QString&, uint);
+ void slotCurrentChanged(QWidget*);
+ void slotClosePage(QWidget*);
+ void slotContextMenu(const QPoint&);
+ void slotContextMenu(QWidget*, const QPoint&);
+};
+
+#endif
diff --git a/src/querywidgetlayout.ui b/src/querywidgetlayout.ui
new file mode 100644
index 0000000..52e7fb3
--- /dev/null
+++ b/src/querywidgetlayout.ui
@@ -0,0 +1,62 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>QueryWidgetLayout</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>QueryWidgetLayout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>740</width>
+ <height>343</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Form2</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="TabWidget">
+ <property name="name">
+ <cstring>m_pQueryTabs</cstring>
+ </property>
+ </widget>
+ </hbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>TabWidget</class>
+ <header location="local">tabwidget.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>1</container>
+ <sizepolicy>
+ <hordata>7</hordata>
+ <verdata>7</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="437">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000017c49444154388dad95db71c32010458f322e652966f3ef325031a68bf8df14c3f6e27c80c4338927e39df1182474b85c2ed2465f4fde53db76b4bcbf3e55af98414af79709c778b3815cfe9f8fc7576e39803b249afe1ff074e716c062bd76696716cd83a0519c2019dd444e66b8035ad12738a53ba274d0142146a6658a802a386d2ff6632e5d2fd5668c10430f3b56660621801a783fab9fc1add20255cdbf56d131698c45fd0ec49ef1d1f55c7df084fa19eab52a0d012c31d5a43859f554b5bf77dbcbbd62c1e17fb291322a86d367915ee90925a70707aeac70a578062faa854213b745ec7e061f2a0a6815b77dcf2a53d90b591ca2c96327d906b30c5505cae17192a118ec9ff5191508831d4b2b8e4d8b21abf23e5f1307b7db30d6b33cf6cb1cab56c5a1e4d53940eaf28f4a114c67bbbb77c5d926ab142939b5d967f5bdff63e2ceb79b08ecc332c5954db21a2971d9535c1fb331392718ca0691978cf16b9cda6169919c0efcce7ae980fca7b6a6fd56d5dbd07fdbc7f41bcb78aa0bdc5b1e190000000049454e44ae426082</data>
+ </image>
+</images>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>tabwidget.h</includehint>
+</includehints>
+</UI>
diff --git a/src/scanprogressdlg.cpp b/src/scanprogressdlg.cpp
new file mode 100644
index 0000000..e380c60
--- /dev/null
+++ b/src/scanprogressdlg.cpp
@@ -0,0 +1,82 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <klocale.h>
+#include "scanprogressdlg.h"
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+ScanProgressDlg::ScanProgressDlg(QWidget* pParent, const char* szName) :
+ ScanProgressLayout(pParent, szName),
+ m_nFiles(0),
+ m_nCurFiles(0)
+{
+ show();
+
+ // Emit the cancelled() signal when the "Cancel" button is clicked
+ connect(m_pCancelButton, SIGNAL(clicked()), this, SIGNAL(cancelled()));
+}
+
+/**
+ * Class destructor.
+ */
+ScanProgressDlg::~ScanProgressDlg()
+{
+}
+
+/**
+ * Adds the given number of files to the total count of files already scanned.
+ * A visual indication of the progress is given in intervals of more than 100
+ * files (to prevent too-frequent GUI updates.)
+ * @param nFiles The number of files scanned since the last call
+ */
+void ScanProgressDlg::addFiles(int nFiles)
+{
+ QString sText;
+
+ // Do nothing if no files were scanned
+ if (nFiles <= 0)
+ return;
+
+ // Update the total number of files scanned
+ m_nFiles += nFiles;
+
+ // Update progress only if more than 100 files were scanned since the last
+ // update
+ if ((m_nFiles - m_nCurFiles) > 100) {
+ sText.sprintf(i18n("Scanned %d files..."), m_nFiles);
+ m_pText->setText(sText);
+ m_nCurFiles = m_nFiles;
+ }
+}
+
+#include "scanprogressdlg.moc"
diff --git a/src/scanprogressdlg.h b/src/scanprogressdlg.h
new file mode 100644
index 0000000..84564de
--- /dev/null
+++ b/src/scanprogressdlg.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef SCANPROGRESSDLG_H
+#define SCANPROGRESSDLG_H
+
+#include <qwidget.h>
+#include <scanprogresslayout.h>
+
+/**
+ * Displays the progress of a file scan operation.
+ * This dialogue is displayed while a ProjectFilesDlg dialogue scans a
+ * directory tree for all files matching the patterns defined for the
+ * project's source files.
+ * @author Elad Lahav
+ */
+
+class ScanProgressDlg : public ScanProgressLayout
+{
+ Q_OBJECT
+
+public:
+ ScanProgressDlg(QWidget* pParent = 0, const char* szName = 0);
+ ~ScanProgressDlg();
+
+ void addFiles(int);
+
+signals:
+ /**
+ * Indicates that the dialogue's "Cancel" button hsa been clicked by the
+ * user.
+ */
+ void cancelled();
+
+private:
+ /** The total number of files scanned thus far. */
+ int m_nFiles;
+
+ /** The number of files currently displayed in the progress report (which
+ may be smaller than m_nFiles since not every call to addFiles() updates
+ the progress display.)*/
+ int m_nCurFiles;
+};
+
+#endif
diff --git a/src/scanprogresslayout.ui b/src/scanprogresslayout.ui
new file mode 100644
index 0000000..85482a8
--- /dev/null
+++ b/src/scanprogresslayout.ui
@@ -0,0 +1,115 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>ScanProgressLayout</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>ScanProgressLayout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>198</width>
+ <height>103</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Scanning Directory</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_pText</cstring>
+ </property>
+ <property name="text">
+ <string>Scanned 0 files...</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</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>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pCancelButton</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <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>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/src/searchlist.cpp b/src/searchlist.cpp
new file mode 100644
index 0000000..ccff869
--- /dev/null
+++ b/src/searchlist.cpp
@@ -0,0 +1,270 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qheader.h>
+#include "searchlist.h"
+
+/**
+ * Intercepting additional key events of QLineEdit to browse the list
+ * @param pKey The pressed key event
+ */
+void SearchLineEdit::keyPressEvent(QKeyEvent* pKey)
+{
+ switch(pKey->key()) {
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ case Qt::Key_PageUp:
+ case Qt::Key_PageDown:
+ emit keyPressed(pKey);
+ break;
+
+ default:
+ QLineEdit::keyPressEvent(pKey);
+ break;
+ }
+}
+
+/**
+ * Class constructor.
+ * @param pParent Owner list view widget
+ */
+ListToolTip::ListToolTip(SearchList* pParent) :
+ QToolTip(pParent->getList()->viewport()),
+ m_pList(pParent)
+{
+}
+
+/**
+ * Displays a tool-tip according to the current location of the mouse
+ * pointer.
+ * @param pt The mouse pointer coordinates
+ */
+void ListToolTip::maybeTip(const QPoint& pt)
+{
+ QString str;
+ QListView* pList;
+ QListViewItem* pItem;
+
+ // Get the item at the given point
+ pList = m_pList->getList();
+ pItem = pList->itemAt(pt);
+ if (pItem == NULL)
+ return;
+
+ // Get the tip string for this item
+ if (!m_pList->getTip(pItem, str))
+ return;
+
+ // Get the bounding rectangle of the item
+ const QRect rcItem = pList->itemRect(pItem);
+ if (!rcItem.isValid())
+ return;
+
+ // Get the header coordinates
+ const QRect rcHead = pList->header()->rect();
+ if (!rcHead.isValid())
+ return;
+
+ // Calculate the tool-tip rectangle
+ QRect rcCell(rcHead.left(), rcItem.top(), rcItem.width(), rcItem.height());
+
+ // Display the tool-tip
+ tip(rcCell, str);
+}
+
+/**
+ * Class constructor.
+ * @param nSearchCol The list column on which to perform string look-ups
+ * @param pParent The parent widget
+ * @param szName The widget's name
+ */
+SearchList::SearchList(int nSearchCol, QWidget* pParent, const char* szName) :
+ QVBox(pParent, szName),
+ m_nSearchCol(nSearchCol)
+{
+ // Create the child widgets
+ m_pEdit = new SearchLineEdit(this);
+ m_pList = new QListView(this);
+
+ // Set up the tooltip generator
+ QToolTip::remove(m_pList);
+ m_pToolTip = new ListToolTip(this);
+
+ connect(m_pEdit, SIGNAL(textChanged(const QString&)), this,
+ SLOT(slotFindItem(const QString&)));
+ connect(m_pList, SIGNAL(doubleClicked(QListViewItem*)), this,
+ SLOT(slotItemSelected(QListViewItem*)));
+ connect(m_pList, SIGNAL(returnPressed(QListViewItem*)), this,
+ SLOT(slotItemSelected(QListViewItem*)));
+ connect(m_pEdit, SIGNAL(returnPressed()), this,
+ SLOT(slotItemSelected()));
+ connect(m_pEdit, SIGNAL(keyPressed(QKeyEvent*)), this,
+ SLOT(slotKeyPressed(QKeyEvent*)));
+}
+
+/**
+ * Class destructor.
+ */
+SearchList::~SearchList()
+{
+ delete m_pToolTip;
+}
+
+/**
+ * Sets the keyboad focus to the search box.
+ */
+void SearchList::slotSetFocus()
+{
+ m_pEdit->setFocus();
+}
+
+/**
+ * Selects a list item whose string begins with the text entered in the edit
+ * widget.
+ * This slot is connected to the textChanged() signal of the line edit widget.
+ * @param sText The new text in the edit widget
+ */
+void SearchList::slotFindItem(const QString& sText)
+{
+ QListViewItem* pItem;
+
+ // Try to find an item that contains this text
+ // Priority to exactly matched,
+ // then try to find line begins with the text,
+ // and if not found, then try to find the line contains the text
+ pItem = m_pList->findItem(sText, m_nSearchCol,
+ ExactMatch | BeginsWith | Contains);
+
+ // Select this item
+ if (pItem != 0) {
+ m_pList->setSelected(pItem, true);
+ m_pList->ensureItemVisible(pItem);
+ }
+}
+
+/**
+ * Lets inheriting classes process an item selection made through the list
+ * widget.
+ * This slot is connected to the doubleClicked() and returnPressed()
+ * signals of the list widget.
+ */
+void SearchList::slotItemSelected(QListViewItem* pItem)
+{
+ processItemSelected(pItem);
+ m_pEdit->setText("");
+}
+
+/**
+ * Lets inheriting classes process an item selection made through the edit
+ * widget.
+ * This slot is connected to the returnPressed() signal of the edit widget.
+ */
+void SearchList::slotItemSelected()
+{
+ QListViewItem* pItem;
+
+ if ((pItem = m_pList->selectedItem()) != NULL) {
+ m_pEdit->setText(pItem->text(m_nSearchCol));
+ processItemSelected(pItem);
+ }
+
+ m_pEdit->setText("");
+}
+
+#define SEARCH_MATCH(pItem) \
+ pItem->text(m_nSearchCol).startsWith(m_pEdit->text())
+
+/**
+ * Sets a new current item based on key events in the edit box.
+ * This slot is connected to the keyPressed() signal of the edit widget.
+ * @param pKey The key evant passed by the edit box
+ */
+void SearchList::slotKeyPressed(QKeyEvent* pKey)
+{
+ QListViewItem* pItem, * pNewItem;
+ int nPageSize, nPos;
+
+ // Select the current item, or the first one if there is no current item
+ pItem = m_pList->currentItem();
+
+ // Set a new current item based on the pressed key
+ switch (pKey->key()) {
+ case Qt::Key_Up:
+ if (pItem) {
+ for (pNewItem = pItem->itemAbove();
+ pNewItem && !SEARCH_MATCH(pNewItem);
+ pNewItem = pNewItem->itemAbove());
+
+ if (pNewItem)
+ pItem = pNewItem;
+ }
+ break;
+
+ case Qt::Key_Down:
+ if (pItem) {
+ for (pNewItem = pItem->itemBelow();
+ pNewItem && !SEARCH_MATCH(pNewItem);
+ pNewItem = pNewItem->itemBelow());
+
+ if (pNewItem)
+ pItem = pNewItem;
+ }
+ break;
+
+ case Qt::Key_PageUp:
+ nPageSize = m_pList->visibleHeight() / pItem->height();
+ for (nPos = 0;
+ pItem && pItem->itemAbove() && (nPos < nPageSize);
+ nPos++)
+ pItem = pItem->itemAbove();
+ break;
+
+ case Qt::Key_PageDown:
+ nPageSize = m_pList->visibleHeight() / pItem->height();
+ for (nPos = 0;
+ pItem && pItem->itemBelow() && (nPos < nPageSize);
+ nPos++)
+ pItem = pItem->itemBelow();
+ break;
+
+ default:
+ pKey->ignore();
+ return;
+ }
+
+ // Select the first item if no other item was selected
+ if (pItem == NULL)
+ pItem = m_pList->firstChild();
+
+ // Select the new item
+ if (pItem) {
+ m_pList->setSelected(pItem, true);
+ m_pList->ensureItemVisible(pItem);
+ }
+}
+
+#include "searchlist.moc"
diff --git a/src/searchlist.h b/src/searchlist.h
new file mode 100644
index 0000000..ffa7ac8
--- /dev/null
+++ b/src/searchlist.h
@@ -0,0 +1,144 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef SEARCHLIST_H
+#define SEARCHLIST_H
+
+#include <qwidget.h>
+#include <qvbox.h>
+#include <qlineedit.h>
+#include <qlistview.h>
+#include <qtooltip.h>
+
+class SearchList;
+
+/**
+ * Defines a line text edit for searchable list view.
+ * The widget is based on QLineEdit with additional key functions
+ * Supported key events (up and down) are emitted as signals
+ * @author Albert Yosher
+ */
+class SearchLineEdit : public QLineEdit
+{
+ Q_OBJECT
+public:
+ SearchLineEdit(QWidget* pParent) : QLineEdit(pParent) {};
+ ~SearchLineEdit() {};
+
+signals:
+ /**
+ * Emitted when one of the up/down or page up/page down keys were pressed
+ * inside this edit widget.
+ * @param pEvent The event received for this key press
+ */
+ void keyPressed(QKeyEvent* pEvent);
+
+private:
+ virtual void keyPressEvent(QKeyEvent*);
+};
+
+/**
+ * A tool-tip class for the search list.
+ * Enables sub-classes of the list to provide a customised tool-tip for each
+ * list item.
+ * @author Gabor Fekete
+ */
+class ListToolTip : public QToolTip
+{
+public:
+ ListToolTip(SearchList* pParent);
+
+protected:
+ virtual void maybeTip(const QPoint& pt);
+
+private:
+ /** The owner widget. */
+ SearchList* m_pList;
+};
+
+
+/**
+ * Defines a searchable list view.
+ * The widget is composed of a list view, and an edit box used to enter
+ * search data. Whenever the text in the edit box changes, the list view is
+ * set to point to the first item that matches the new text.
+ * @author Elad Lahav
+ */
+class SearchList : public QVBox
+{
+ Q_OBJECT
+
+public:
+ SearchList(int nSearchCol, QWidget* pParent = 0, const char* szName = 0);
+ ~SearchList();
+
+ /**
+ * @return A pointer to the list part of the widget.
+ */
+ QListView* getList() { return m_pList; }
+
+ /**
+ * Constructs a tool-tip for the given item.
+ * @param pItem The item for which a tip is required
+ * @param sTip The constructed tip string (on return)
+ * @return True to display the tip, false otherwise
+ */
+ virtual bool getTip(QListViewItem* pItem, QString& sTip) = 0;
+
+public slots:
+ void slotSetFocus();
+
+protected:
+ /** The search edit-box. */
+ QLineEdit* m_pEdit;
+
+ /** The list part of the widget. */
+ QListView* m_pList;
+
+ /**
+ * Called whenever the user selects an item in the list by either double-
+ * clicking it, or by highlighting the item and pressing the ENTER key.
+ * @param pItem The selected list item
+ */
+ virtual void processItemSelected(QListViewItem* pItem) = 0;
+
+protected slots:
+ void slotFindItem(const QString&);
+ void slotItemSelected(QListViewItem*);
+ void slotItemSelected();
+ void slotKeyPressed(QKeyEvent*);
+
+private:
+ /** Specifies the search column, i.e., the list column whose strings are
+ compared with the text in the search edit-box. */
+ int m_nSearchCol;
+
+ /** A tool-tip for the list entries. */
+ ListToolTip* m_pToolTip;
+};
+
+#endif
diff --git a/src/searchresultsdlg.cpp b/src/searchresultsdlg.cpp
new file mode 100644
index 0000000..bb63fa5
--- /dev/null
+++ b/src/searchresultsdlg.cpp
@@ -0,0 +1,160 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qpushbutton.h>
+#include <qlineedit.h>
+#include <qcombobox.h>
+#include <qradiobutton.h>
+#include "searchresultsdlg.h"
+
+int SearchResultsDlg::s_nType = PlainText;
+bool SearchResultsDlg::s_bCaseSensitive = true;
+bool SearchResultsDlg::s_bNegate = false;
+
+/**
+ * Class constructor.
+ * @param pParent The parent widget
+ * @param szName Optional widget name
+ */
+SearchResultsDlg::SearchResultsDlg(QWidget* pParent, const char* szName) :
+ SearchResultsLayout(pParent, szName, true, 0)
+{
+ // Select the last selected type radio button
+ switch (s_nType) {
+ case PlainText:
+ m_pTextRadio->setChecked(true);
+ break;
+
+ case RegExp:
+ m_pRegExpRadio->setChecked(true);
+ break;
+
+ case SimpRegExp:
+ m_pSimpRegExpRadio->setChecked(true);
+ break;
+ }
+
+ // Set the default value of the check-boxes
+ m_pCaseSenCheck->setChecked(s_bCaseSensitive);
+ m_pNegateCheck->setChecked(s_bNegate);
+
+ // Terminate the dialogue when either the "OK" or "Cancel" buttons are
+ // clicked
+ connect(m_pOKButton, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(m_pCancelButton, SIGNAL(clicked()), this, SLOT(reject()));
+}
+
+/**
+ * Class destructor.
+ */
+SearchResultsDlg::~SearchResultsDlg()
+{
+}
+
+/**
+ * Determines the default column on which to search.
+ * The column's name appears in the column combo-box.
+ */
+void SearchResultsDlg::setColumn(int nCol)
+{
+ m_pColumnCB->setCurrentItem(nCol);
+}
+
+/**
+ * @return The selected column on which to perform the search
+ */
+int SearchResultsDlg::getColumn()
+{
+ return m_pColumnCB->currentItem();
+}
+
+/**
+ * Creates a regular expression based on the given pattern and type of search.
+ * @param re A regular expression object to set
+ */
+void SearchResultsDlg::getPattern(QRegExp& re)
+{
+ QString sPattern;
+
+ sPattern = m_pSearchEdit->text();
+
+ // Create the regular expression
+ switch (s_nType) {
+ case PlainText:
+ re.setPattern(QRegExp::escape(sPattern));
+ re.setWildcard(false);
+ break;
+
+ case RegExp:
+ re.setPattern(sPattern);
+ re.setWildcard(false);
+ break;
+
+ case SimpRegExp:
+ re.setPattern(sPattern);
+ re.setWildcard(true);
+ break;
+ }
+
+ // Set the case-(in)sensitive parameter
+ re.setCaseSensitive(s_bCaseSensitive);
+}
+
+/**
+ * Reads user values from the widgets, and closes the dialogue.
+ * This slot is connected to the clicked() signal emitted by the "OK" button.
+ */
+void SearchResultsDlg::accept()
+{
+ QString sText;
+
+ // Determine the selected type and store its value for the next invocation
+ if (m_pTextRadio->isChecked())
+ s_nType = PlainText;
+ else if (m_pRegExpRadio->isChecked())
+ s_nType = RegExp;
+ else if (m_pSimpRegExpRadio->isChecked())
+ s_nType = SimpRegExp;
+
+ // Determine search parameters
+ s_bCaseSensitive = m_pCaseSenCheck->isChecked();
+ s_bNegate = m_pNegateCheck->isChecked();
+
+ // Remove white space from the search text
+ sText = m_pSearchEdit->text();
+ sText.stripWhiteSpace();
+ if (sText.isEmpty()) {
+ QDialog::reject();
+ return;
+ }
+
+ // Close the dialogue
+ QDialog::accept();
+}
+
+#include "searchresultsdlg.moc"
+
diff --git a/src/searchresultsdlg.h b/src/searchresultsdlg.h
new file mode 100644
index 0000000..d636f8f
--- /dev/null
+++ b/src/searchresultsdlg.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef SEARCHRESULTSDLG_H
+#define SEARCHRESULTSDLG_H
+
+#include <qregexp.h>
+#include <qcheckbox.h>
+#include "searchresultslayout.h"
+
+/**
+ * A dialogue for defining searches on query results.
+ * The dialogue is activated from the query results menu.
+ * @author Elad Lahav
+ */
+class SearchResultsDlg : public SearchResultsLayout
+{
+ Q_OBJECT
+
+public:
+ SearchResultsDlg(QWidget* pParent = 0, const char* szName = 0);
+ ~SearchResultsDlg();
+
+ void setColumn(int);
+ int getColumn();
+ void getPattern(QRegExp&);
+
+ /**
+ * @return true if the search pattern should be negated, false otherwise
+ */
+ bool isNegated() { return m_pNegateCheck->isChecked(); }
+
+protected slots:
+ virtual void accept();
+
+private:
+ /** Possible search types. */
+ enum { PlainText = 0, RegExp, SimpRegExp };
+
+ /** Remembers the last search type. */
+ static int s_nType;
+
+ /** Remembers the last value of the Case Sensitive check-box. */
+ static bool s_bCaseSensitive;
+
+ /** Remembers the last value of the Negate Search check-box. */
+ static bool s_bNegate;
+};
+
+#endif
diff --git a/src/searchresultslayout.ui b/src/searchresultslayout.ui
new file mode 100644
index 0000000..cdcde53
--- /dev/null
+++ b/src/searchresultslayout.ui
@@ -0,0 +1,214 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>SearchResultsLayout</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>SearchResultsLayout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>361</width>
+ <height>307</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Filter Query Results</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Search For:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>m_pSearchEdit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Search In:</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>171</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QComboBox">
+ <item>
+ <property name="text">
+ <string>Function</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>File</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Line</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Text</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_pColumnCB</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>Search Type</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_pTextRadio</cstring>
+ </property>
+ <property name="text">
+ <string>Plain Text</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_pRegExpRadio</cstring>
+ </property>
+ <property name="text">
+ <string>RegE&amp;xp</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_pSimpRegExpRadio</cstring>
+ </property>
+ <property name="text">
+ <string>Simplified RegExp</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pCaseSenCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Case Sensitive</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pNegateCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Negate Search</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>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>201</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pOKButton</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pCancelButton</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<tabstops>
+ <tabstop>m_pSearchEdit</tabstop>
+ <tabstop>m_pColumnCB</tabstop>
+ <tabstop>m_pTextRadio</tabstop>
+ <tabstop>m_pRegExpRadio</tabstop>
+ <tabstop>m_pSimpRegExpRadio</tabstop>
+ <tabstop>m_pCaseSenCheck</tabstop>
+ <tabstop>m_pOKButton</tabstop>
+ <tabstop>m_pCancelButton</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/src/symbolcompletion.cpp b/src/symbolcompletion.cpp
new file mode 100644
index 0000000..2ec8194
--- /dev/null
+++ b/src/symbolcompletion.cpp
@@ -0,0 +1,344 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qtimer.h>
+#include <klocale.h>
+#include "symbolcompletion.h"
+
+bool SymbolCompletion::s_bACEnabled;
+uint SymbolCompletion::s_nACMinChars;
+uint SymbolCompletion::s_nACDelay;
+uint SymbolCompletion::s_nACMaxEntries;
+
+/**
+ * Class constructor.
+ * @param pEditor The editor object for which symbol completion is required
+ * @param pParent Parent object
+ * @param szName Optional object name
+ */
+SymbolCompletion::SymbolCompletion(SymbolCompletion::Interface* pEditor,
+ QObject* pParent, const char* szName) :
+ QObject(pParent, szName),
+ m_pEditor(pEditor),
+ m_pCCObject(NULL)
+{
+ // Initialise member objects
+ m_pCscope = new CscopeFrontend();
+ m_pAutoCompTimer = new QTimer(this);
+
+ // Add entries to the completion list when they are available
+ connect(m_pCscope, SIGNAL(dataReady(FrontendToken*)), this,
+ SLOT(slotAddEntry(FrontendToken*)));
+
+ // Show the completion list when the query finishes
+ connect(m_pCscope, SIGNAL(finished(uint)), this,
+ SLOT(slotQueryFinished(uint)));
+
+ // Initiate automatic symbol completion when timer expires
+ connect(m_pAutoCompTimer, SIGNAL(timeout()), this,
+ SLOT(slotAutoCompleteTimeout()));
+}
+
+/**
+ * Class destructor.
+ */
+SymbolCompletion::~SymbolCompletion()
+{
+ delete m_pCscope;
+}
+
+/**
+ * Stops a completion process.
+ * This includes killing a running query, and stoping the auto-completion
+ * timer.
+ */
+void SymbolCompletion::abort()
+{
+ if (m_pCscope->isRunning())
+ m_pCscope->kill();
+
+ m_pAutoCompTimer->stop();
+}
+
+/**
+ * Configures auto-completion parameters.
+ * @param bEnabled true to enable auto-completion, false otherwise
+ * @param nMinChars Minimal number of characters a symbol needs to start
+ * auto-completion
+ * @param nDelay Auto-completion time interval (in milliseconds)
+ * @param nMaxEntries The maximal number of completion entries
+ */
+void SymbolCompletion::initAutoCompletion(bool bEnabled, uint nMinChars,
+ uint nDelay, uint nMaxEntries)
+{
+ s_bACEnabled = bEnabled;
+ s_nACMinChars = nMinChars;
+ s_nACDelay = nDelay;
+ s_nACMaxEntries = nMaxEntries;
+}
+
+/**
+ * Starts a completion process immediately for the symbol currently under the
+ * cursor in the editor object.
+ * Symbol completion is only available if the cursor is positioned at the end
+ * of the symbol.
+ */
+void SymbolCompletion::slotComplete()
+{
+ QString sSymbol;
+ uint nPosInWord;
+
+ // Read the symbol currently under the cursor
+ sSymbol = m_pEditor->getWordUnderCursor(&nPosInWord);
+
+ // The completion was triggered by user
+ m_bAutoCompletion = false;
+
+ // start completion process, prefix is only on the left from the cursor
+ complete(sSymbol.left(nPosInWord));
+}
+
+/**
+ * Initiates an auto-completion timer.
+ * When the timer times-out, is starts the symbol completion process.
+ */
+void SymbolCompletion::slotAutoComplete()
+{
+ if (s_bACEnabled)
+ m_pAutoCompTimer->start(s_nACDelay, true);
+}
+
+/**
+ * Creates a list of possible completions to the symbol currently being
+ * edited.
+ * @param sPrefix The symbol to complete
+ * @param nMaxEntries The maximal number of entries to display
+ */
+void SymbolCompletion::complete(const QString& sPrefix, int nMaxEntries)
+{
+ // Create a regular expression to extract symbol names from the query
+ // results
+ m_reSymbol.setPattern(sPrefix + "[a-zA-Z0-9_]*");
+
+ // If the new prefix is itself a prefix of the old one, we only need to
+ // filter the current entries
+ if (!m_sPrefix.isEmpty() && sPrefix.startsWith(m_sPrefix)) {
+ filterEntries();
+ m_sPrefix = sPrefix;
+ slotQueryFinished(0);
+ return;
+ }
+
+ // Prepare member variables
+ m_sPrefix = sPrefix;
+ m_nMaxEntries = nMaxEntries;
+ m_elEntries.clear();
+
+ // Run the code-completion query
+ m_pCscope->query(CscopeFrontend::Definition, sPrefix + ".*");
+}
+
+/**
+ * Removes from the current completion list all symbols that do not match
+ * the current regular expression.
+ * This function is used to aviod requerying the database on certain
+ * situations.
+ */
+void SymbolCompletion::filterEntries()
+{
+ EntryList::Iterator itr;
+
+ // Iterate over the list and check each entry against the current RE
+ for (itr = m_elEntries.begin(); itr != m_elEntries.end();) {
+ if (m_reSymbol.search((*itr).text) == -1)
+ itr = m_elEntries.erase(itr);
+ else
+ ++itr;
+ }
+}
+
+/**
+ * Conevrts the completion list into a single-entry one, containing the given
+ * message.
+ * @param sMsg The text of the message to include in the list.
+ */
+void SymbolCompletion::makeErrMsg(const QString& sMsg)
+{
+ Entry entry;
+
+ // Clear the current list
+ m_elEntries.clear();
+
+ // Create the message item and add it to the list
+ entry.text = sMsg;
+ entry.userdata = "NO_INSERT"; // The message should not be insertable
+ m_elEntries.append(entry);
+
+ // Make sure a new completion request will start a new query
+ m_sPrefix = "";
+}
+
+/**
+ * Creates a new entry in the list when a query record is available.
+ * This slot is connected to the dataReady() signal of the CscopeFrontend
+ * object.
+ * @param pToken Points to the head of a record's linked-list
+ */
+void SymbolCompletion::slotAddEntry(FrontendToken* pToken)
+{
+ Entry entry;
+ QString sText;
+
+ // Do not add entries beyond the requested limit
+ if (m_elEntries.count() > m_nMaxEntries)
+ return;
+
+ // Get the line text
+ pToken = pToken->getNext()->getNext()->getNext();
+ sText = pToken->getData();
+
+ // Find the symbol within the line
+ if (m_reSymbol.search(sText) == -1)
+ return;
+
+ // Add the new entry to the completion list
+ entry.text = m_reSymbol.capturedTexts().first();
+ entry.userdata = "";
+ entry.comment = sText;
+
+ m_elEntries.append(entry);
+}
+
+/**
+ * Displays a code completion list, based on the results of the last query.
+ * @param nRecords (ingnored)
+ */
+void SymbolCompletion::slotQueryFinished(uint /* nRecords */)
+{
+ KTextEditor::CodeCompletionInterface* pCCI;
+ uint nEntryCount;
+ EntryList::Iterator itr;
+ QString sPrevText;
+
+ // Get the number of entries
+ nEntryCount = m_elEntries.count();
+
+ // Do not show the box the only completion option is the prefix itself
+ if (m_bAutoCompletion && (nEntryCount == 1) &&
+ (m_elEntries.first().text == m_sPrefix)) {
+ return;
+ }
+
+ // Get a pointer to the CC interface
+ m_pCCObject = m_pEditor->getCCObject();
+ pCCI = dynamic_cast<KTextEditor::CodeCompletionInterface*>(m_pCCObject);
+ if (!pCCI)
+ return;
+
+ // Insert the correct part of the completed symbol, when chosen by the
+ // user
+ connect(m_pCCObject,
+ SIGNAL(filterInsertString(KTextEditor::CompletionEntry*, QString*)),
+ this,
+ SLOT(slotFilterInsert(KTextEditor::CompletionEntry*, QString*)));
+
+ // Check the number of entries in the list
+ if (nEntryCount == 0) {
+ // No completion options, display an appropriate message
+ makeErrMsg(i18n("No matching completion found..."));
+ }
+ else if (nEntryCount > m_nMaxEntries) {
+ // The query has resulted in too many entries, display an
+ // appropriate message
+ makeErrMsg(i18n("Too many options..."));
+ }
+ else {
+ // Sort the entries
+ m_elEntries.sort();
+
+ // Make sure entries are unique
+ for (itr = m_elEntries.begin(); itr != m_elEntries.end();) {
+ if ((*itr).text == sPrevText) {
+ itr = m_elEntries.erase(itr);
+ }
+ else {
+ sPrevText = (*itr).text;
+ ++itr;
+ }
+ }
+ }
+
+ // Display the completion list
+ pCCI->showCompletionBox(m_elEntries);
+}
+
+/**
+ * Determines which part of the completion entry should be added to the code
+ * when that entry is selected.
+ * @param pEntry Points to the selected entry
+ * @param pTextToInsert Contains the string to insert, upon return
+ */
+void SymbolCompletion::slotFilterInsert(KTextEditor::CompletionEntry* pEntry,
+ QString* pTextToInsert)
+{
+ // Insert the completed entry, unless it contains an error message
+ if (pEntry->userdata.isEmpty())
+ *pTextToInsert = pEntry->text.mid(m_sPrefix.length());
+ else
+ *pTextToInsert = "";
+
+ // Disconnect the CC object signals
+ disconnect(m_pCCObject, 0, this, 0);
+ m_pCCObject = NULL;
+}
+
+/**
+ * Checks if the current symbol is eligible for auto-completion, and if so,
+ * starts the completion process.
+ * Auto-completion is performed for symbols that have the required minimal
+ * number of entries, and the cursor is positioned at the end of the word.
+ * This slot is connected to the timeout() signal of the auto-completion
+ * timer.
+ */
+void SymbolCompletion::slotAutoCompleteTimeout()
+{
+ QString sPrefix;
+ uint nPosInWord, nLength;
+
+ // Read the symbol currently under the cursor
+ sPrefix = m_pEditor->getWordUnderCursor(&nPosInWord);
+ nLength = sPrefix.length();
+
+ // Check conditions, and start the completion process
+ if ((nLength >= s_nACMinChars) && (nPosInWord == nLength)) {
+ // The completion was triggered by auto-completion
+ m_bAutoCompletion = true;
+ complete(sPrefix, s_nACMaxEntries);
+ }
+}
+
+#include "symbolcompletion.moc"
diff --git a/src/symbolcompletion.h b/src/symbolcompletion.h
new file mode 100644
index 0000000..6fe57e2
--- /dev/null
+++ b/src/symbolcompletion.h
@@ -0,0 +1,195 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef SYMBOLCOMPLETION_H
+#define SYMBOLCOMPLETION_H
+
+#include <qobject.h>
+#include <qregexp.h>
+#include <ktexteditor/codecompletioninterface.h>
+#include <ktexteditor/view.h>
+#include "cscopefrontend.h"
+
+/**
+ * This class executes symbol definition queries based on symbol prefixes.
+ * The results can then be displayed as symbol completion lists.
+ * @author Albert Yosher
+ */
+class SymbolCompletion : public QObject
+{
+ Q_OBJECT
+
+public:
+ /**
+ * A pure-virtual class that allows a SymbolCompletion object access to
+ * text-editing objects.
+ * Classes that wish to utilise SymbolCompletion need to inplement this
+ * interface.
+ * @author Albert Yosher
+ */
+ struct Interface
+ {
+ /**
+ * Class destructor.
+ * NOTE: A virtual destructor is required by GCC 4.0
+ */
+ virtual ~Interface() {}
+
+ /**
+ * Returns the word currently under the editing cursor.
+ * Symbol completion will be provided for this word only if the cursor
+ * is positioned at the end of this word.
+ * @param pPosInWord Set this value to the offset in the word on
+ * which the cursor is positioned
+ */
+ virtual QString getWordUnderCursor(uint* pPosInWord) = 0;
+
+ /**
+ * Returns a target object for displaying the completion list.
+ * @return A pointer to an object implementing
+ * KTextEditor::CodeCompletionInterface, or NULL if the
+ * implementation does not support this interface.
+ */
+ virtual QObject* getCCObject() = 0;
+ };
+
+ SymbolCompletion(SymbolCompletion::Interface*, QObject* pParent = 0,
+ const char* szName = 0);
+ ~SymbolCompletion();
+
+ void abort();
+
+ static void initAutoCompletion(bool, uint, uint, uint);
+
+public slots:
+ void slotComplete();
+ void slotAutoComplete();
+
+private:
+ /**
+ * Symbol completion entry object, used in the completion list.
+ * Implements operators required for sorting the completion list.
+ * @author Albert Yosher
+ */
+ class Entry : public KTextEditor::CompletionEntry
+ {
+ public:
+ /**
+ * Determines whether a given entry is smaller than this one.
+ * @param entry The entry to compare with
+ * @return true if the given entry is smaller, false otherwise
+ */
+ bool operator < (const SymbolCompletion::Entry& entry) const {
+ return (text < entry.text);
+ }
+
+ /**
+ * Determines whether a given entry is equal to this one.
+ * @param entry The entry to compare with
+ * @return true if the given entry equals this one, false otherwise
+ */
+ bool operator == (const SymbolCompletion::Entry& entry) const {
+ return (text == entry.text);
+ }
+ };
+
+ /**
+ * A sortable version of the value list used by CodeCompletionInterface.
+ * @author Albert Yosher
+ */
+ class EntryList : public QValueList<Entry>
+ {
+ public:
+ /**
+ * Sorts completion list.
+ */
+ void sort() { qHeapSort(*this); }
+
+ /**
+ * Type casting support required for calling showCompletionBox().
+ * @return A casted reference to this object
+ */
+ operator QValueList<KTextEditor::CompletionEntry>()
+ { return *(QValueList<KTextEditor::CompletionEntry>*)this; }
+ };
+
+ /** Editor object for which symbol completion is provided. */
+ Interface* m_pEditor;
+
+ /** An object that supports KTextEditor::CodeCompletionInterface, as
+ supplied by the editor. */
+ QObject* m_pCCObject;
+
+ /** Cscope process used to run completion queries. */
+ CscopeFrontend* m_pCscope;
+
+ /** The prefix used for the current query. */
+ QString m_sPrefix;
+
+ /** A list of possible completions for the given prefix. */
+ EntryList m_elEntries;
+
+ /** The maximal number of completions to accept. */
+ uint m_nMaxEntries;
+
+ /** Regular expression for extracting a symbol out of Cscope's text field.
+ NOTE: This member is required due to a bug in Cscope that renders the
+ symbol field useless. */
+ QRegExp m_reSymbol;
+
+ /** Auto-completion timer. */
+ QTimer* m_pAutoCompTimer;
+
+ /** Auto-completion flag */
+ bool m_bAutoCompletion;
+
+ void complete(const QString&, int nMaxEntries = 1000);
+ void filterEntries();
+ void makeErrMsg(const QString&);
+
+ /** true if auto-completion is enabled, false otherwise. */
+ static bool s_bACEnabled;
+
+ /** The minimum number of characters a symbol must have for
+ auto-completion. */
+ static uint s_nACMinChars;
+
+ /** The interval between the time slotAutoComplete() is called and the
+ time the completion process begins (in milliseconds). */
+ static uint s_nACDelay;
+
+ /** The maximal number of entries for auto-completion. */
+ static uint s_nACMaxEntries;
+
+private slots:
+ void slotAutoCompleteTimeout();
+ void slotAddEntry(FrontendToken*);
+ void slotQueryFinished(uint);
+ void slotFilterInsert(KTextEditor::CompletionEntry*, QString*);
+};
+
+#endif
diff --git a/src/symboldlg.cpp b/src/symboldlg.cpp
new file mode 100644
index 0000000..3301678
--- /dev/null
+++ b/src/symboldlg.cpp
@@ -0,0 +1,334 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qlabel.h>
+#include <qlistview.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <kcombobox.h>
+#include <klocale.h>
+#include "symboldlg.h"
+#include "cscopefrontend.h"
+#include "kscopeconfig.h"
+
+QStringList SymbolDlg::s_slHistory;
+
+/**
+ * Class constructor.
+ * @param pParent Parent widget
+ * @param szName This widget's name
+ */
+SymbolDlg::SymbolDlg(QWidget* pParent, const char* szName) :
+ SymbolLayout(pParent, szName, true, 0),
+ m_progress(m_pHintList)
+{
+ // Create a persistent Cscope process
+ m_pCscope = new CscopeFrontend();
+
+ // Initialise the hint list (hidden by default)
+ m_pHintList->addColumn(i18n("Suggested Symbols"));
+ m_pHintList->hide();
+ ((QWidget*)m_pHintGroup)->hide();
+ m_pBeginWithRadio->toggle();
+ adjustSize();
+
+ // Close the dialogue when either the "OK" or "Cancel" button are clicked
+ connect(m_pOKButton, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(m_pCancelButton, SIGNAL(clicked()), this, SLOT(reject()));
+
+ // Run a symbol completion query when the "Hint" button is clicked
+ connect(m_pHintButton, SIGNAL(clicked()), this, SLOT(slotHintClicked()));
+
+ // Add results to the hint list
+ connect(m_pCscope, SIGNAL(dataReady(FrontendToken*)), this,
+ SLOT(slotHintDataReady(FrontendToken*)));
+
+ // Set hint button availability based on the type of query
+ connect(m_pTypeCombo, SIGNAL(activated(int)), this,
+ SLOT(slotTypeChanged(int)));
+
+ // Selecting an item in the hint list sets it as the current text
+ connect(m_pHintList, SIGNAL(selectionChanged(QListViewItem*)), this,
+ SLOT(slotHintItemSelected(QListViewItem*)));
+
+ // Double-clicking an item in the hint list accepts that item as the
+ // result of the query (i.e., the item is selcted and the dialogue is
+ // closed)
+ connect(m_pHintList, SIGNAL(doubleClicked(QListViewItem*)), this,
+ SLOT(accept()));
+
+ // Refresh the hint list when the hint options change
+ connect(m_pBeginWithRadio, SIGNAL(toggled(bool)), this,
+ SLOT(slotHintOptionChanged(bool)));
+ connect(m_pContainRadio, SIGNAL(toggled(bool)), this,
+ SLOT(slotHintOptionChanged(bool)));
+
+ // Show hint query progress information
+ connect(m_pCscope, SIGNAL(progress(int, int)), this,
+ SLOT(slotHintProgress(int, int)));
+ connect(m_pCscope, SIGNAL(finished(uint)), this,
+ SLOT(slotHintFinished(uint)));
+}
+
+/**
+ * Class destructor.
+ */
+SymbolDlg::~SymbolDlg()
+{
+ delete m_pCscope;
+}
+
+/**
+ * Displays the requested type of query in the type combo-box.
+ * @param nType The requested type
+ */
+void SymbolDlg::setType(uint nType)
+{
+ m_pTypeCombo->setCurrentItem(nType);
+ slotTypeChanged(nType);
+}
+
+/**
+ * @param sSymbol The initial text of the combo-box
+ */
+void SymbolDlg::setSymbol(const QString& sSymbol)
+{
+ m_pSymbolHC->setCurrentText(sSymbol);
+}
+
+/**
+ * @param slSymHistory A list of previously queried symbols
+ */
+void SymbolDlg::setHistory(QStringList& slSymHistory)
+{
+ m_pSymbolHC->setHistoryItems(slSymHistory);
+}
+
+/**
+ * @return The current text of the symbol combo-box
+ */
+QString SymbolDlg::getSymbol() const
+{
+ QString sResult;
+
+ sResult = m_pSymbolHC->currentText().stripWhiteSpace();
+ if (m_pSubStringCheck->isChecked())
+ sResult = ".*" + sResult + ".*";
+
+ return sResult;
+}
+
+/**
+ * @return The type of query requested by the user
+ * @note The returned value does not conform to the type used for running
+ * Cscope queries. Use getQueryType() to translate between these
+ * values.
+ */
+uint SymbolDlg::getType() const
+{
+ return m_pTypeCombo->currentItem();
+}
+
+bool SymbolDlg::getCase() const
+{
+ return !m_pCaseCheck->isChecked();
+}
+
+/**
+ * A convinience static function for creating and showing SymbolDlg dialogue.
+ * @param pParent The parent widget
+ * @param nType The type of query requested by the user (may be
+ * changed in the dialogue)
+ * @param sSymbol The initial text of the combo-box
+ * @return The text entered by the user in the symbol combo-box, or an empty
+ * string if the dialogue was cancelled
+ */
+QString SymbolDlg::promptSymbol(QWidget* pParent, uint& nType,
+ const QString& sSymbol, bool& bCase)
+{
+ SymbolDlg dlg(pParent);
+
+ // Initialise the dialogue
+ dlg.setType(nType);
+ dlg.setHistory(s_slHistory);
+ dlg.setSymbol(sSymbol);
+
+ // Display the dialogue
+ if (dlg.exec() != QDialog::Accepted)
+ return "";
+
+ // Return the text entered by the user
+ nType = dlg.getType();
+ bCase = dlg.getCase();
+ dlg.m_pSymbolHC->addToHistory(dlg.getSymbol());
+ s_slHistory = dlg.m_pSymbolHC->historyItems();
+ return dlg.getSymbol();
+}
+
+/**
+ * Translates a symbol dialogue type into a Cscope query type.
+ * @param nType The type to translate
+ * @return A query type matching the symbol dialogue type
+ */
+uint SymbolDlg::getQueryType(uint nType)
+{
+ if (nType == CallTree)
+ return CscopeFrontend::None;
+
+ if (nType <= Text)
+ return nType;
+
+ return nType + 1;
+}
+
+/**
+ * Runs a symbol definition query, looking for symbols starting with the
+ * currently entered text.
+ * If the hint list is not visible, it is shown first.
+ * This slot is connected to the clicked() signal of the "Hint" button.
+ */
+void SymbolDlg::slotHintClicked()
+{
+ QString sText, sRegExp;
+
+ // Show the hint list if necessary
+ if (!m_pHintList->isVisible()) {
+ m_pHintList->show();
+ ((QWidget*)m_pHintGroup)->show();
+ adjustSize();
+ }
+
+ // Clear the previous contents
+ m_pHintList->clear();
+
+ // Get the currently entered text (must have at least one character)
+ sText = m_pSymbolHC->currentText().stripWhiteSpace();
+ if (sText.isEmpty())
+ return;
+
+ // Create the regular expression
+ if (m_pBeginWithRadio->isOn())
+ sRegExp = sText + "[a-zA-Z0-9_]*";
+ else
+ sRegExp = "[a-zA-Z0-9_]*" + sText + "[a-zA-Z0-9_]*";
+
+ m_reHint.setPattern(sRegExp);
+
+ // Run a Cscope symbol definition query using a regular expression
+ m_pCscope->query(CscopeFrontend::Definition, sRegExp);
+}
+
+/**
+ * Called when a new record is ready to be added to the hint list.
+ * NOTE: Cscope 15.5 has a bug where the "function" field of the record
+ * displays the regular expression instead of the matched symbol name. For
+ * this reason, we need to extract the symbol from the "Text" field.
+ * @param pToken The head of the record's token list
+ */
+void SymbolDlg::slotHintDataReady(FrontendToken* pToken)
+{
+ QString sText;
+
+ // Get the line text
+ pToken = pToken->getNext()->getNext()->getNext();
+ sText = pToken->getData();
+
+ // Find the symbol within the line
+ if (m_reHint.search(sText) == -1)
+ return;
+
+ // Find the symbol within the list, if found - do not add
+ if (m_pHintList->findItem(m_reHint.capturedTexts().first(), 0))
+ return;
+
+ // Add a list item
+ (void)new QListViewItem(m_pHintList, m_reHint.capturedTexts().first());
+
+}
+
+/**
+ * Sets the text of a selected hint list item as the current text of the
+ * symbol combo-box.
+ * This slot is connected to the doubleClicked() signal of the hint list-view.
+ * @param pItem The clicked list item
+ */
+void SymbolDlg::slotHintItemSelected(QListViewItem* pItem)
+{
+ m_pSymbolHC->setCurrentText(pItem->text(0));
+}
+
+/**
+ * Refreshes the hint list based on the newly selected option.
+ * This slot is connected to the toggled() signal of the hint options radio
+ * buttons.
+ * NOTE: The list is only refreshed if the system profile is set to Fast.
+ * @param bOn true if the button was toggled on
+ */
+void SymbolDlg::slotHintOptionChanged(bool bOn)
+{
+ if (bOn && Config().getSysProfile() == KScopeConfig::Fast)
+ slotHintClicked();
+}
+
+/**
+ * Display a progress bar while the hint query is working.
+ * This slot is connected to the progress() signal emitted by the Cscope
+ * frontend object.
+ * @param nProgress Progress value
+ * @param nTotal The final expected value
+ */
+void SymbolDlg::slotHintProgress(int nProgress, int nTotal)
+{
+ m_progress.setProgress(nProgress, nTotal);
+}
+
+/**
+ * Destroys all progress information widget when the query process terminates.
+ * This slot is connected to the finished() signal emitted by the Cscope
+ * process.
+ */
+void SymbolDlg::slotHintFinished(uint /* ignored */)
+{
+ m_progress.finished();
+}
+
+/**
+ * Enables/disables the hint button, based on the newly selected type.
+ * This slot is connected to the activated() signal of the type combo-box.
+ * @param nType The newly selected type
+ */
+void SymbolDlg::slotTypeChanged(int nType)
+{
+ if (nType == FileName || nType == Including)
+ m_pHintButton->setEnabled(false);
+ else
+ m_pHintButton->setEnabled(true);
+}
+
+#include "symboldlg.moc"
diff --git a/src/symboldlg.h b/src/symboldlg.h
new file mode 100644
index 0000000..4360213
--- /dev/null
+++ b/src/symboldlg.h
@@ -0,0 +1,91 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef SYMBOLDLG_H
+#define SYMBOLDLG_H
+
+#include <qregexp.h>
+#include "symbollayout.h"
+#include "cscopefrontend.h"
+
+/**
+ * A dialogue that prompts the user for the text of a query.
+ * When a query is requested, the user needs to fill in the required
+ * information (usually a symbol name). This dialogue allows the user to
+ * enter this information, as well as complete a symbol name, and use
+ * previously entered text.
+ * @author Elad Lahav
+ */
+
+class SymbolDlg : public SymbolLayout
+{
+ Q_OBJECT
+
+public:
+ SymbolDlg(QWidget* pParent = 0, const char* szName = 0);
+ ~SymbolDlg();
+
+ enum { Reference = 0, Definition, Called, Calling, Text, Pattern,
+ FileName, Including, CallTree };
+
+ void setType(uint);
+ void setSymbol(const QString&);
+ void setHistory(QStringList&);
+ QString getSymbol() const;
+ uint getType() const;
+ bool getCase() const;
+
+ static QString promptSymbol(QWidget*, uint&, const QString&, bool&);
+ static uint getQueryType(uint);
+ static void resetHistory() { s_slHistory.clear(); }
+
+private:
+ /** A cscope process used for symbol completion. */
+ CscopeFrontend* m_pCscope;
+
+ /** A regular expression for extracting the symbol name out of the text
+ token of a Cscope record.
+ @see note in slotHintDataReady(). */
+ QRegExp m_reHint;
+
+ /** Displays query progress information. */
+ CscopeProgress m_progress;
+
+ static QStringList s_slHistory;
+
+private slots:
+ void slotHintClicked();
+ void slotHintDataReady(FrontendToken*);
+ void slotHintItemSelected(QListViewItem*);
+ void slotHintOptionChanged(bool);
+ void slotHintProgress(int, int);
+ void slotHintFinished(uint);
+ void slotTypeChanged(int);
+};
+
+#endif
+
diff --git a/src/symbollayout.ui b/src/symbollayout.ui
new file mode 100644
index 0000000..09b2885
--- /dev/null
+++ b/src/symbollayout.ui
@@ -0,0 +1,297 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>SymbolLayout</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>SymbolLayout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>343</width>
+ <height>456</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>KScope Query</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout15</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout14</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Type</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Symbol</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout13</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QComboBox">
+ <item>
+ <property name="text">
+ <string>References to</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Definition of</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Functions called by</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Functions calling</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Find text</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Find EGrep pattern</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Find file</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Files #including</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Call graph for</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_pTypeCombo</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KHistoryCombo">
+ <property name="name">
+ <cstring>m_pSymbolHC</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="insertionPolicy">
+ <enum>AtTop</enum>
+ </property>
+ <property name="duplicatesEnabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pSubStringCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Search for &amp;a Sub-String</string>
+ </property>
+ <property name="accel">
+ <string>Alt+A</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pCaseCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Case Insensitive</string>
+ </property>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </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>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>71</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pOKButton</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pHintButton</cstring>
+ </property>
+ <property name="text">
+ <string>Hi&amp;nt</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pCancelButton</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QListView">
+ <property name="name">
+ <cstring>m_pHintList</cstring>
+ </property>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>m_pHintGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Hint Options</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_pBeginWithRadio</cstring>
+ </property>
+ <property name="text">
+ <string>S&amp;ymbols Beginning With...</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_pContainRadio</cstring>
+ </property>
+ <property name="text">
+ <string>Sym&amp;bols Containing...</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+</widget>
+<tabstops>
+ <tabstop>m_pSymbolHC</tabstop>
+ <tabstop>m_pTypeCombo</tabstop>
+ <tabstop>m_pSubStringCheck</tabstop>
+ <tabstop>m_pOKButton</tabstop>
+ <tabstop>m_pHintButton</tabstop>
+ <tabstop>m_pCancelButton</tabstop>
+ <tabstop>m_pHintList</tabstop>
+ <tabstop>m_pBeginWithRadio</tabstop>
+ <tabstop>m_pContainRadio</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kcombobox.h</includehint>
+ <includehint>klineedit.h</includehint>
+</includehints>
+</UI>
diff --git a/src/tab_list.png b/src/tab_list.png
new file mode 100644
index 0000000..b0cb478
--- /dev/null
+++ b/src/tab_list.png
Binary files differ
diff --git a/src/tabwidget.cpp b/src/tabwidget.cpp
new file mode 100644
index 0000000..2795a84
--- /dev/null
+++ b/src/tabwidget.cpp
@@ -0,0 +1,84 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include <qtooltip.h>
+#include <klocale.h>
+#include "tabwidget.h"
+#include "kscopepixmaps.h"
+
+/**
+ * Class constructor.
+ * @param pParent A pointer to the parent widget
+ * @param szName Optional widget name
+ */
+TabWidget::TabWidget(QWidget* pParent, const char* szName) :
+ KTabWidget(pParent, szName)
+{
+ // Create a popup menu
+ m_pMenu = new QPopupMenu(this);
+
+ // Set the current tab based on the menu selection
+ connect(m_pMenu, SIGNAL(activated(int)), this, SLOT(setCurrentPage(int)));
+
+ // Create a button at the top-right corner of the tab widget
+ m_pButton = new QToolButton(this);
+ m_pButton->setIconSet(Pixmaps().getPixmap(KScopePixmaps::TabList));
+ QToolTip::add(m_pButton, i18n("Shows a list of all open tabs"));
+ m_pButton->adjustSize();
+ setCornerWidget(m_pButton, TopRight);
+
+ // Show the popup-menu when the button is clicked
+ connect(m_pButton, SIGNAL(clicked()), this, SLOT(slotShowTabList()));
+}
+
+/**
+ * Class destructor.
+ */
+TabWidget::~TabWidget()
+{
+}
+
+/**
+ * Creates and displays a popup-menu containing all tab labels.
+ * This slot is connected to the clicked() signal emitted by the list button.
+ */
+void TabWidget::slotShowTabList()
+{
+ int i;
+
+ // Delete the previous menu
+ m_pMenu->clear();
+
+ // Create and populate the menu
+ for (i = 0; i < count(); i++)
+ m_pMenu->insertItem(label(i), i);
+
+ // Show the menu
+ m_pMenu->popup(mapToGlobal(m_pButton->pos()));
+}
+
+#include "tabwidget.moc"
diff --git a/src/tabwidget.h b/src/tabwidget.h
new file mode 100644
index 0000000..74672ae
--- /dev/null
+++ b/src/tabwidget.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef TABWIDGET_H
+#define TABWIDGET_H
+
+
+#include <qtoolbutton.h>
+#include <qpopupmenu.h>
+#include <ktabwidget.h>
+
+/**
+ * An extension to the standard KDE tab widget that allows the user to select
+ * a tab from a list displayed as a popup menu.
+ * @author Elad Lahav
+ */
+class TabWidget : public KTabWidget
+{
+Q_OBJECT
+public:
+ TabWidget(QWidget* pParent = 0, const char* szName = 0);
+ ~TabWidget();
+
+private:
+ /** The list button. */
+ QToolButton* m_pButton;
+
+ /** A popup-menu containing all tab labels. */
+ QPopupMenu* m_pMenu;
+
+private slots:
+ void slotShowTabList();
+};
+
+#endif
diff --git a/src/treewidget.cpp b/src/treewidget.cpp
new file mode 100644
index 0000000..b303194
--- /dev/null
+++ b/src/treewidget.cpp
@@ -0,0 +1,260 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include "treewidget.h"
+#include "queryviewdriver.h"
+
+/**
+ * Class constructor.
+ * @param pParent Parent widget
+ * @param szName The name of the widget
+ */
+TreeWidget::TreeWidget(QWidget* pParent, const char* szName) :
+ QueryView(pParent, szName),
+ m_nQueryType(CscopeFrontend::Called)
+{
+ setRootIsDecorated(true);
+
+ // Create a driver object
+ m_pDriver = new QueryViewDriver(this, this);
+
+ // Query a tree item when it is expanded for the first time
+ connect(this, SIGNAL(expanded(QListViewItem*)), this,
+ SLOT(slotQueryItem(QListViewItem*)));
+}
+
+/**
+ * Class destructor.
+ */
+TreeWidget::~TreeWidget()
+{
+}
+
+/**
+ * Determines the mode of the tree.
+ * @param mode The new mode (@see Mode)
+ */
+void TreeWidget::setMode(Mode mode)
+{
+ m_nQueryType = (mode == Called) ? CscopeFrontend::Called :
+ CscopeFrontend::Calling;
+}
+
+/**
+ * Sets a new root item for the tree.
+ * @param sFunc The name of the function to serve as root
+ */
+void TreeWidget::setRoot(const QString& sFunc)
+{
+ QListViewItem* pRoot;
+
+ // Remove the current root, if any
+ if ((pRoot = firstChild()) != NULL)
+ delete pRoot;
+
+ // Create a new root item
+ pRoot = new QListViewItem(this, sFunc);
+ pRoot->setExpandable(true);
+}
+
+/**
+ * Runs a query on the root item.
+ */
+void TreeWidget::queryRoot()
+{
+ QListViewItem* pRoot;
+
+ if ((pRoot = firstChild()) != NULL)
+ slotQueryItem(pRoot);
+}
+
+/**
+ * Stores the tree contents in the given file.
+ * @param pFile An open file to write to
+ */
+void TreeWidget::save(FILE* pFile)
+{
+ QTextStream str(pFile, IO_WriteOnly);
+ QListViewItem* pRoot;
+ Encoder enc;
+
+ if (m_nQueryType == CscopeFrontend::Called)
+ str << "calltree {" << endl;
+ else
+ str << "callingtree {" << endl;
+
+ // Write the tree to the file
+ pRoot = firstChild();
+ str << pRoot->text(0) << endl;
+ str << '{' << endl;
+ saveItems(pRoot->firstChild(), str, enc);
+ str << '}' << endl;
+ str << '}' << endl;
+}
+
+/**
+ * Recursively writes tree items to a file.
+ * Given an item, the method writes this item and all of its siblings.
+ * Child items are written recursively.
+ * @param pItem The first item to write
+ * @param str An initialised text stream to use for writing
+ * @param enc An encoder for free-text strings
+ */
+void TreeWidget::saveItems(QListViewItem* pItem, QTextStream& str, Encoder& enc)
+{
+ // Iterate over all items in this level
+ for (; pItem != NULL; pItem = pItem->nextSibling()) {
+ // Write function parameters
+ str << pItem->text(0) << " [ "
+ << "kscope_file=\"" << pItem->text(1) << "\", "
+ << "kscope_line=" << pItem->text(2) << ", "
+ << "kscope_text=\"" << enc.encode(pItem->text(3)) << "\""
+ << "]" << endl;
+
+ // Write child items
+ str << "{" << endl;
+ saveItems(pItem->firstChild(), str, enc);
+ str << "}" << endl;
+ }
+}
+
+/**
+ * Creates a new tree item showing a query result record.
+ * @param sFunc The name of the function
+ * @param sFile The file path
+ * @param sLine The line number in the above file
+ * @param sText The line's text
+ * @param pParent The parent for the new item
+ */
+void TreeWidget::addRecord(const QString& sFunc, const QString& sFile,
+ const QString& sLine, const QString& sText, QListViewItem* pParent)
+{
+ QListViewItem* pItem;
+
+ pItem = new QueryViewItem(pParent, m_pLastItem, 2);
+ pItem->setText(0, sFunc);
+ pItem->setText(1, sFile);
+ pItem->setText(2, sLine);
+ pItem->setText(3, sText);
+
+ pItem->setExpandable(true);
+ m_pLastItem = pItem;
+}
+
+/**
+ * Called when a query running on the tree terminates.
+ * If there were no results, the item becomes non-expandable.
+ * NOTE: On top of its current behaviour, this function is required in order to
+ * override the default behaviour, as specified by QueryView.
+ * @param nResults Number of results
+ * @param pParent The item for which the query was executed
+ */
+void TreeWidget::queryFinished(uint nResults, QListViewItem* pParent)
+{
+ if (nResults == 0)
+ pParent->setExpandable(false);
+ else
+ pParent->setOpen(true);
+}
+
+/**
+ * Runs a query on the given item, unless it was queried before.
+ * This slot is connected to the expanded() signal of the list view.
+ * @param pItem The item to query
+ */
+void TreeWidget::slotQueryItem(QListViewItem* pItem)
+{
+ // Do nothing if the item was already queried
+ // An item has been queried if it has children or marked as non-expandable
+ if (pItem->firstChild() != NULL || !pItem->isExpandable())
+ return;
+
+ // Run the query
+ m_pDriver->query(m_nQueryType, pItem->text(0), true, pItem);
+}
+
+/**
+ * Hides all descendant that do not meet the given search criteria.
+ * This slot is connected to the search() signal of the QueryResultsMenu
+ * object.
+ * The search is incremental: only visible items are checked, so that a new
+ * search goes over the results of the previous one.
+ * @param pParent The parent item whose child are searched
+ * @param re The pattern to search
+ * @param nCol The list column to search in
+ */
+void TreeWidget::slotSearch(QListViewItem* pParent, const QRegExp& re,
+ int nCol)
+{
+ QListViewItem* pItem;
+
+ // Get the first child
+ if (pParent != NULL)
+ pItem = pParent->firstChild();
+ else
+ pItem = firstChild();
+
+ // Iterate over all child items
+ while (pItem != NULL) {
+ // Filter visible items only
+ if (pItem->isVisible() && re.search(pItem->text(nCol)) == -1)
+ pItem->setVisible(false);
+
+ // Search child items recursively
+ slotSearch(pItem, re, nCol);
+
+ pItem = pItem->nextSibling();
+ }
+}
+
+/**
+ * Makes all descendants of the given item visible.
+ * This slot is connected to the showAll() signal of the QueryResultsMenu
+ * object.
+ */
+void TreeWidget::slotShowAll(QListViewItem* pParent)
+{
+ QListViewItem* pItem;
+
+ // Get the first child
+ if (pParent != NULL)
+ pItem = pParent->firstChild();
+ else
+ pItem = firstChild();
+
+ // Iterate over all child items
+ while (pItem != NULL) {
+ pItem->setVisible(true);
+
+ // Show child items recursively
+ slotShowAll(pItem);
+
+ pItem = pItem->nextSibling();
+ }
+}
+
+#include "treewidget.moc"
diff --git a/src/treewidget.h b/src/treewidget.h
new file mode 100644
index 0000000..57c2a98
--- /dev/null
+++ b/src/treewidget.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef TREEWIDGET_H
+#define TREEWIDGET_H
+
+#include "queryview.h"
+#include "encoder.h"
+
+class QueryViewDriver;
+
+/**
+ * A tree-like widget displaying a hierarchical list of functions.
+ * The widget has two modes: called functions and calling functions. Depending
+ * on this mode, child items represent functions called by or calling their
+ * parent item.
+ * @author Elad Lahav
+ */
+class TreeWidget : public QueryView
+{
+ Q_OBJECT
+
+public:
+ TreeWidget(QWidget* pParent = 0, const char* szName = 0);
+ ~TreeWidget();
+
+ /**
+ * The type of tree to display.
+ */
+ enum Mode { Called, Calling };
+
+ void setMode(Mode);
+ void setRoot(const QString&);
+ void queryRoot();
+ void save(FILE*);
+
+ virtual void addRecord(const QString&, const QString&, const QString&,
+ const QString&, QListViewItem*);
+ virtual void queryFinished(uint, QListViewItem*);
+
+protected slots:
+ virtual void slotSearch(QListViewItem*, const QRegExp&, int);
+ virtual void slotShowAll(QListViewItem*);
+
+private:
+ /** The CscopeFrontend query type to use (based on the current mode). */
+ uint m_nQueryType;
+
+ /** Runs queries and outputs the results as tree items. */
+ QueryViewDriver* m_pDriver;
+
+ void saveItems(QListViewItem*, QTextStream&, Encoder&);
+
+private slots:
+ void slotQueryItem(QListViewItem*);
+};
+
+#endif
diff --git a/src/welcomedlg.ui b/src/welcomedlg.ui
new file mode 100644
index 0000000..44c385c
--- /dev/null
+++ b/src/welcomedlg.ui
@@ -0,0 +1,126 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>WelcomeDlg</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>WelcomeDlg</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>519</width>
+ <height>386</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Welcome</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KTextBrowser">
+ <property name="name">
+ <cstring>m_pBrowser</cstring>
+ </property>
+ <property name="paletteBackgroundColor">
+ <color>
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </property>
+ <property name="text">
+ <string>&lt;h1&gt;Welcome to &lt;font color="#c00000"&gt;KScope&lt;/font&gt;!&lt;/h1&gt;
+
+If this is the first time you are running Kscope, please follow these steps (click on the links for detailed instructions):
+&lt;p&gt;
+1. &lt;a href="help:/kscope/configuration.html#config-progs"&gt;Configure&lt;/a&gt; paths to the required back-end executables&lt;br&gt;
+2. &lt;a href="help:/kscope/projects.html#project-create"&gt;Create&lt;/a&gt; a new project&lt;br&gt;
+3. &lt;a href="help:/kscope/projects.html#project-files"&gt;Populate&lt;/a&gt; the project with source files&lt;br&gt;
+4. &lt;a href="help:/kscope/queries.html"&gt;Browse&lt;/a&gt; the project and &lt;a href="help:/kscope/editing.html"&gt;edit&lt;/a&gt; files&lt;br&gt;
+
+&lt;/p&gt;
+
+&lt;p&gt;
+For more information, please take a look at KScope's &lt;a href="help:/kscope"&gt;manual&lt;/a&gt;, or visit the KScope &lt;a href="http://kscope.sourceforge.net"&gt;website&lt;/a&gt;.
+&lt;/p&gt;
+
+&lt;p&gt;
+Enjoy!
+&lt;/p&gt;
+
+&lt;p&gt;
+&lt;font size="-1"&gt;This message will only appear once. Use the "&lt;b&gt;Help-&gt;Show Welcome Message...&lt;/b&gt;" menu command to show it again at any time.&lt;/font&gt;
+&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </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>381</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pCloseButton</cstring>
+ </property>
+ <property name="text">
+ <string>Close</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>m_pCloseButton</sender>
+ <signal>clicked()</signal>
+ <receiver>WelcomeDlg</receiver>
+ <slot>accept()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>ktextbrowser.h</includehint>
+</includehints>
+</UI>