You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1759 lines
46 KiB
1759 lines
46 KiB
/***************************************************************************
|
|
*
|
|
* 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())
|
|
{
|
|
Config().loadDefault();
|
|
Config().store();
|
|
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"
|