cscopefrontend.cpp
来自「This a source insight software in Linux.」· C++ 代码 · 共 475 行
CPP
475 行
/*************************************************************************** * * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***************************************************************************/#include <qfileinfo.h>#include <qtimer.h>#include <kconfig.h>#include <kmessagebox.h>#include <klocale.h>#include <kglobalsettings.h>#include "cscopefrontend.h"#include "kscopeconfig.h"#define BUILD_STR "Building symbol database %d of %d"#define SEARCH_STR "Search %d of %d"#define INV_STR "Possible references retrieved %d of %d"#define REGEXP_STR "Symbols matched %d of %d"#define SEARCHEND_STR "%d lines"QString CscopeFrontend::s_sProjPath;QStringList CscopeFrontend::s_slProjArgs;/** * Class constructor. * @param bAutoDelete true to delete the object once the process has * terminated, false otherwise */CscopeFrontend::CscopeFrontend(bool bAutoDelete) : Frontend(CSCOPE_RECORD_SIZE, bAutoDelete), m_state(Unknown), m_sErrMsg(""), m_bRebuildOnExit(false){}/** * Class destructor. */CscopeFrontend::~CscopeFrontend(){}/** * Executes a Cscope process using the given command line arguments. * The full path to the Cscope executable should be set in the "Path" key * under the "Cscope" group. * @param slArgs Command line arguments for Cscope * @return true if successful, false otherwise */bool CscopeFrontend::run(const QStringList& slArgs){ QStringList slCmdLine; // Set the command line arguments slCmdLine.append(Config().getCscopePath()); slCmdLine += s_slProjArgs; slCmdLine += slArgs; if (Config().useVerboseCscope()) slCmdLine.append("-v"); // Run a new process if (!Frontend::run(slCmdLine, s_sProjPath)) return false; return true;}/** * Executes a Cscope query. * A query is composed of a numeric type and a query text, which are written * to the stndard input of the currently running Cscope process. * @param nType The type of query to run * @param sText The query's text * @param nMaxRecords The maximal number of records to return (abort if this * number is exceeded) */void CscopeFrontend::query(uint nType, const QString& sText, uint nMaxRecords){ QString sQuery; QStringList slArgs; m_nMaxRecords = nMaxRecords; // Create the Cscope command line slArgs.append(QString("-L") + QString::number(nType)); slArgs.append(sText); slArgs.append("-d"); run(slArgs); // Initialise stdout parsing m_state = SearchSymbol; m_delim = WSpace; emit progress(0, 1);}/** * Rebuilds the symbol database of the current project. */void CscopeFrontend::rebuild(){ QStringList slArgs; // If a process is already running, kill it start a new one if (isRunning()) { m_bRebuildOnExit = true; kill(); return; } // Run the database building process slArgs.append("-b"); run(slArgs); // Initialise output parsing m_state = BuildStart; m_delim = Newline; emit progress(0, 1);}/** * Sets default parameters for all CscopeFrontend projects based on the * current project. * @param sProjPath The full path of the project's directory * @param slArgs Project-specific command-line arguments for Cscope */void CscopeFrontend::init(const QString& sProjPath, const QStringList& slArgs){ s_sProjPath = sProjPath; s_slProjArgs = slArgs;}/** * Tests that the given file path leads to an executable. * @param sPath The path to check * @return true if the file in the given path exists and has executable * permissions, false otherwise */bool CscopeFrontend::verify(const QString& sPath){ QFileInfo fi(sPath); if (!fi.exists() || !fi.isFile() || !fi.isExecutable() || fi.fileName() != "cscope") { KMessageBox::error(0, i18n("Cscope cannot be found in the given " "path")); return false; } return true;}/** * Stops a Cscope action. */void CscopeFrontend::slotCancel(){ kill();}/** * Parses the output of a Cscope process. * Implements a state machine, where states correspond to the output of the * controlled Cscope process. * @param sToken The current token read (the token delimiter is determined * by the current state) * @return A value indicating the way this token should be treated: dropped, * added to the token queue, or finishes a new record */Frontend::ParseResult CscopeFrontend::parseStdout(QString& sToken, ParserDelim /* ignored */){ int nFiles, nTotal, nRecords; ParseResult result = DiscardToken; ParserState stPrev; // Remember previous state stPrev = m_state; // Handle the token according to the current state switch (m_state) { case BuildStart: if (sToken == "Building cross-reference...") { m_state = BuildSymbol; m_delim = WSpace; } result = DiscardToken; break; case BuildSymbol: // A single angle bracket is the prefix of a progress indication, // while double brackets is Cscope's prompt for a new query if (sToken == ">") { m_state = Building; m_delim = Newline; } result = DiscardToken; break; case Building: // Try to get building progress if (sscanf(sToken.latin1(), BUILD_STR, &nFiles, &nTotal) == 2) emit progress(nFiles, nTotal); // Wait for another progress line or the "ready" symbol m_state = BuildSymbol; m_delim = WSpace; result = DiscardToken; break; case SearchSymbol: // Check for more search progress, or the end of the search, // designated by a line in the format of "cscope: X lines" if (sToken == ">") { m_state = Searching; m_delim = Newline; result = DiscardToken; break; } else if (sToken == "cscope:") { m_state = SearchEnd; m_delim = Newline; result = DiscardToken; break; } case File: // Is this the first entry? If so, signal that the query is complete if (stPrev != LineText) emit progress(1, 1); // Treat the token as the name of the file in this record m_state = Func; result = AcceptToken; break; case Searching: // Try to get the search progress value (ignore other messages) if ((sscanf(sToken.latin1(), SEARCH_STR, &nFiles, &nTotal) == 2) || (sscanf(sToken.latin1(), INV_STR, &nFiles, &nTotal) == 2) || (sscanf(sToken.latin1(), REGEXP_STR, &nFiles, &nTotal) == 2)) { emit progress(nFiles, nTotal); } m_state = SearchSymbol; m_delim = WSpace; result = DiscardToken; break; case SearchEnd: // Get the number of results found in this search if ((sscanf(sToken.latin1(), SEARCHEND_STR, &nRecords) == 1) && (m_nMaxRecords > 0) && (nRecords > m_nMaxRecords)) { result = Abort; } else { m_state = File; m_delim = WSpace; result = DiscardToken; } break; case Func: // Treat the token as the name of the function in this record if (sToken.toInt()) { // If it is number, then it is line number already m_state = LineText; m_delim = Newline; } m_state = Line; result = AcceptToken; break; case Line: // Treat the token as the line number in this record m_state = LineText; m_delim = Newline; result = AcceptToken; break; case LineText: // Treat the token as the text of this record, and report a new // record m_state = File; m_delim = WSpace; result = RecordReady; break; default: // Do nothing (prevents a compilation warning for unused enum values) break; } return result;}/** * Handles Cscope messages sent to the standard error stream. * @param sText The error message text */void CscopeFrontend::parseStderr(const QString& sText){ // Wait for a complete line to arrive m_sErrMsg += sText; if (!sText.endsWith("\n")) return; // Display the error message emit error(m_sErrMsg); // Line displayed, reset the text accumulator m_sErrMsg = "";}/** * Called when the underlying process exits. * Checks if the rebuild flag was raised, and if so restarts the building * process. */void CscopeFrontend::finalize(){ // Reset the parser state machine m_state = Unknown; // Restart the building process, if required if (m_bRebuildOnExit) { m_bRebuildOnExit = false; rebuild(); }}/** * Class constructor. * @param pMainWidget The parent widget to use for the progress bar and * label */CscopeProgress::CscopeProgress(QWidget* pMainWidget) : QObject(), m_pMainWidget(pMainWidget), m_pProgressBar(NULL), m_pLabel(NULL){}/** * Class destructor. */CscopeProgress::~CscopeProgress(){ delete m_pProgressBar; delete m_pLabel;}/** * Displays query progress information. * If the progress value is below the expected final value, a progress bar is * used to show the advance of the query process. Otherwise, a label is * displayed asking the user to wait ahile the query output is processed. * @param nProgress The current progress value * @param nTotal The expected final value */void CscopeProgress::setProgress(int nProgress, int nTotal){ // Was the final value is reached? if (nProgress == nTotal) { // Destroy the progress bar if (m_pProgressBar != NULL) { delete m_pProgressBar; m_pProgressBar = NULL; } // Show the "Please wait..." label if (m_pLabel == NULL) { m_pLabel = new QLabel(i18n("Processing query results, " "please wait..."), m_pMainWidget); m_pLabel->setFrameStyle(QFrame::Box | QFrame::Plain); m_pLabel->setLineWidth(1); m_pLabel->adjustSize(); m_pLabel->setPaletteBackgroundColor( KGlobalSettings::highlightColor()); m_pLabel->setPaletteForegroundColor( KGlobalSettings::highlightedTextColor()); QTimer::singleShot(1000, this, SLOT(slotShowLabel())); } return; } // Create the progress bar, if it does not exist. // Note that the progress bar will only be displayed one second after the // first progress signal is received. Thus the bar will not be displayed // on very short queries. if (m_pProgressBar == NULL) { m_pProgressBar = new QProgressBar(m_pMainWidget); QTimer::singleShot(1000, this, SLOT(slotShowProgressBar())); } // Set the current progress value m_pProgressBar->setProgress(nProgress, nTotal);}/** * detsroys any progress widgets when the process is terminated. */void CscopeProgress::finished(){ // Destroy the progress bar if (m_pProgressBar != NULL) { delete m_pProgressBar; m_pProgressBar = NULL; } // Destroy the label if (m_pLabel != NULL) { delete m_pLabel; m_pLabel = NULL; }}/** * Shows the progress bar. * This slot is connected to a timer activated when the first progress signal * is received. */void CscopeProgress::slotShowProgressBar(){ if (m_pProgressBar != NULL) m_pProgressBar->show();}/** * Shows the "Please wait...". * This slot is connected to a timer activated when the progress bar * reaches its final value. */void CscopeProgress::slotShowLabel(){ if (m_pLabel != NULL) m_pLabel->show();}#include "cscopefrontend.moc"
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?