summaryrefslogtreecommitdiffstats
path: root/src/kscope.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/kscope.cpp')
-rw-r--r--src/kscope.cpp1754
1 files changed, 1754 insertions, 0 deletions
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"