diff options
Diffstat (limited to 'src/querywidget.cpp')
-rw-r--r-- | src/querywidget.cpp | 601 |
1 files changed, 601 insertions, 0 deletions
diff --git a/src/querywidget.cpp b/src/querywidget.cpp new file mode 100644 index 0000000..113f216 --- /dev/null +++ b/src/querywidget.cpp @@ -0,0 +1,601 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav ([email protected]) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qtoolbutton.h> +#include <qtooltip.h> +#include <klocale.h> +#include <kmessagebox.h> +#include "querywidget.h" +#include "kscopepixmaps.h" +#include "kscopeconfig.h" + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +QueryWidget::QueryWidget(QWidget* pParent, const char* szName) : + QueryWidgetLayout(pParent, szName), + m_pPageMenu(NULL), + m_pLockAction(NULL), + m_pHistPage(NULL), + m_bHistEnabled(true), + m_nQueryPages(0) +{ + // Pages can be closed by clicking their tabs + m_pQueryTabs->setHoverCloseButton(true); + + // Change the lock action state according to the current page + connect(m_pQueryTabs, SIGNAL(currentChanged(QWidget*)), this, + SLOT(slotCurrentChanged(QWidget*))); + + // Close a query when its tab button is clicked + connect(m_pQueryTabs, SIGNAL(closeRequest(QWidget*)), this, + SLOT(slotClosePage(QWidget*))); + + // Show the menu when requested + connect(m_pQueryTabs, SIGNAL(contextMenu(const QPoint&)), this, + SLOT(slotContextMenu(const QPoint&))); + connect(m_pQueryTabs, SIGNAL(contextMenu(QWidget*, const QPoint&)), this, + SLOT(slotContextMenu(QWidget*, const QPoint&))); +} + +/** + * Class destructor. + */ +QueryWidget::~QueryWidget() +{ +} + +/** + * Runs a query in a query page. + * A query page is first selected, with a new one created if required. The + * method then creates a Cscope process and runs the query. + * @param nType The query's numeric type code + * @param sText The query's text, as entered by the user + * @param bCase true for case-sensitive queries, false otherwise + */ +void QueryWidget::initQuery(uint nType, const QString& sText, bool bCase) +{ + QueryPage* pPage; + + // Make sure we have a query page + findQueryPage(); + pPage = (QueryPage*)currentPage(); + + // Use the current page, or a new page if the current one is locked + if (pPage->isLocked()) { + addQueryPage(); + pPage = (QueryPage*)currentPage(); + } + + // Reset the page's results list + pPage->clear(); + pPage->query(nType, sText, bCase); + + // Set the page's tab text according to the new query + setPageCaption(pPage); +} + +/** + * Applies the user's colour and font preferences to all pages. + */ +void QueryWidget::applyPrefs() +{ + QueryPage* pPage; + int nPages, i; + + // Iterate query pages + nPages = m_pQueryTabs->count(); + for (i = 0; i < nPages; i++) { + pPage = (QueryPage*)m_pQueryTabs->page(i); + pPage->applyPrefs(); + setPageCaption(pPage); + } +} + +/** + * Loads all pages saved when the project was closed. + * @param sProjPath The full path of the project directory + * @param slFiles The list of query file names to load + */ +void QueryWidget::loadPages(const QString& sProjPath, + const QStringList& slFiles) +{ + QStringList::ConstIterator itr; + QueryPageBase* pPage; + QString sName; + + // Iterate through query files + for (itr = slFiles.begin(); itr != slFiles.end(); ++itr) { + // Set the target page, based on the file type (query or history) + if ((*itr).startsWith("History")) { + findHistoryPage(); + pPage = m_pHistPage; + } + else { + findQueryPage(); + pPage = (QueryPage*)currentPage(); + } + + // Load a query file to this page, and lock the page + if (pPage->load(sProjPath, *itr)) { + setPageCaption(pPage); + setPageLocked(pPage, true); + } + } +} + +/** + * Stores all pages marked for saving into files in the project directory. + * @param sProjPath The full path of the project directory + * @param slFiles Holds a list of query file names, upon return + */ +void QueryWidget::savePages(const QString& sProjPath, QStringList& slFiles) +{ + int nPageCount, i; + QueryPage* pPage; + QString sFileName; + + // Iterate pages + nPageCount = m_pQueryTabs->count(); + for (i = 0; i < nPageCount; i++) { + pPage = (QueryPage*)m_pQueryTabs->page(i); + if (pPage->shouldSave()) { + // Store this query page + if (pPage->save(sProjPath, sFileName) && !sFileName.isEmpty()) + slFiles.append(sFileName); + } + } +} + +/** + * Adds a new position record to the active history page. + * @param sFile The file path + * @param nLine The line number + * @param sText The contents of the line pointed to by the file path and + * line number + */ +void QueryWidget::addHistoryRecord(const QString& sFile, uint nLine, + const QString& sText) +{ + // Validate file name and line number + if (sFile.isEmpty() || nLine == 0) + return; + + // Do nothing if history logging is disabled + if (!m_bHistEnabled) + return; + + // Make sure there is an active history page + findHistoryPage(); + + // Add the position entry to the active page + m_pHistPage->addRecord(sFile, nLine, sText); +} + +/** + * Sets the tab caption and tool-tip for the given page. + * @param pPage The page whose tab needs to be changed + */ +void QueryWidget::setPageCaption(QueryPageBase* pPage) +{ + m_pQueryTabs->changeTab(pPage, + pPage->getCaption(Config().getUseBriefQueryCaptions())); + m_pQueryTabs->setTabToolTip(pPage, pPage->getCaption()); +} + +/** + * Creates a new query page, and adds it to the tab widget. + * The new page is set as the current one. + */ +void QueryWidget::addQueryPage() +{ + QueryPage* pPage; + QString sTitle; + + // Create the page + pPage = new QueryPage(this); + + // Add the page, and set it as the current one + m_pQueryTabs->insertTab(pPage, GET_PIXMAP(TabUnlocked), "Query", + m_nQueryPages++); + setCurrentPage(pPage); + + // Emit the lineRequested() signal when a query record is selected on + // this page + connect(pPage, SIGNAL(lineRequested(const QString&, uint)), this, + SLOT(slotRequestLine(const QString&, uint))); +} + +/** + * Creates a new query page, and emits signal about it. + */ +void QueryWidget::slotNewQueryPage() +{ + addQueryPage(); + emit newQuery(); +} + +/** + * Locks or unlocks a query. + * This slot is connected to the toggled() signal of the lock query button. + * @param bOn true if the new state of the button is "on", false if it is + * "off" + */ +void QueryWidget::slotLockCurrent(bool bOn) +{ + QueryPageBase* pPage; + + pPage = currentPage(); + + if (pPage != NULL) + setPageLocked(currentPage(), bOn); +} + +/** + * Locks or unlocks a query, by toggling the current state. + */ +void QueryWidget::slotLockCurrent() +{ + QueryPageBase* pPage; + + pPage = currentPage(); + if (pPage != NULL) + setPageLocked(pPage, !pPage->isLocked()); +} + +/** + * Reruns the query whose results are displayed in the current page. + */ +void QueryWidget::slotRefreshCurrent() +{ + QueryPage* pPage; + + // Make sure the current page is a valid, non-empty one + pPage = dynamic_cast<QueryPage*>(currentPage()); + if (pPage == NULL) + return; + + // Clear the current page contents + pPage->refresh(); +} + +/** + * Selects the next query result record in the current query page. + */ +void QueryWidget::slotNextResult() +{ + QueryPage* pPage; + + // Select the next record in the current page + pPage = dynamic_cast<QueryPage*>(currentPage()); + if (pPage != NULL) + pPage->selectNext(); +} + +/** + * Selects the next query result record in the current query page. + */ +void QueryWidget::slotPrevResult() +{ + QueryPage* pPage; + + // Select the next record in the current page + pPage = dynamic_cast<QueryPage*>(currentPage()); + if (pPage != NULL) + pPage->selectPrev(); +} + +/** + * Closes the current query page. + */ +void QueryWidget::slotCloseCurrent() +{ + QWidget* pPage; + + // Close the current page + pPage = currentPage(); + if (pPage != NULL) + slotClosePage(pPage); +} + +/** + * Closes all query pages. + */ +void QueryWidget::slotCloseAll() +{ + int nPageCount, i; + QueryPage* pPage; + + // Close all pages + nPageCount = m_pQueryTabs->count(); + for (i = 0; i < nPageCount; i++) { + pPage = (QueryPage*)m_pQueryTabs->page(0); + m_pQueryTabs->removePage(pPage); + delete pPage; + } + + m_pHistPage = NULL; +} + +/** + * Handles the "Go->Back" menu command. + * Moves to the previous position in the position history. + */ +void QueryWidget::slotHistoryPrev() +{ + if (m_pHistPage != NULL) { + m_bHistEnabled = false; + m_pHistPage->selectPrev(); + m_bHistEnabled = true; + } +} + +/** + * Handles the "Go->Forward" menu command. + * Moves to the next position in the position history. + */ +void QueryWidget::slotHistoryNext() +{ + if (m_pHistPage != NULL) { + m_bHistEnabled = false; + m_pHistPage->selectNext(); + m_bHistEnabled = true; + } +} + +/** + * Sets the active history page, if any, as the current page. + */ +void QueryWidget::selectActiveHistory() +{ + if (m_pHistPage) + setCurrentPage(m_pHistPage); +} + +/** + * Attaches the page operations menu to this widget. + * The page menu is a popup menu that handles such operations as opening a + * new page, closing a page, locking a page, etc. + * @param pMenu Pointer to the popup menu + * @param pAction Pointer to the "Lock/Unlock" toggle action + */ +void QueryWidget::setPageMenu(QPopupMenu* pMenu, KToggleAction* pAction) +{ + m_pPageMenu = pMenu; + m_pLockAction = pAction; +} + +/** + * Emits a signal indicating a certain source file and line number are + * requested. + * This slot is connected to the recordSelected() signal emitted by any of + * the query pages. The signal emitted by this slot is used to display an + * editor page at the requested line. + * @param sFileName The file's path + * @param nLine The requested line in the file + */ +void QueryWidget::slotRequestLine(const QString& sFileName, uint nLine) +{ + // Disable history if the request came from the active history page + if (currentPage() == m_pHistPage) + m_bHistEnabled = false; + + // Emit the signal + emit lineRequested(sFileName, nLine); + + // Re-enable history + if (currentPage() == m_pHistPage) + m_bHistEnabled = true; +} + +/** + * Update the lock button when the current query page changes. + * @param pWidget The new current page + */ +void QueryWidget::slotCurrentChanged(QWidget* pWidget) +{ + QueryPage* pPage; + + pPage = (QueryPage*)pWidget; + m_pLockAction->setChecked(pPage->isLocked()); +} + +/** + * Removes the given page from the tab widget. + * This slot is connected to the closeRequest() signal of the KTabBar object. + * @param pPage The page to close + */ +void QueryWidget::slotClosePage(QWidget* pPage) +{ + // Prompt the user before closing a locked query + if (((QueryPage*)pPage)->isLocked()) { + if (KMessageBox::questionYesNo(NULL, i18n("You about about to close" + " a locked page.\nAre you sure?")) == KMessageBox::No) { + return; + } + } + + // Check if the closed page is the active history page + if (pPage == m_pHistPage) + m_pHistPage = NULL; + // Update the number of open history pages + else if (dynamic_cast<HistoryPage*>(pPage) == NULL) + m_nQueryPages--; + + // Remove the page and delete the object + m_pQueryTabs->removePage(pPage); + delete pPage; +} + +/** + * Displays a context menu for page operations. + * This slot is connected to the contextMenu() signal, emitted by + * m_pQueryTabs. + * NOTE: We assume that the first item in the menu is "New". + * @param pt The point over which the mouse was clicked in request for the + * context menu + */ +void QueryWidget::slotContextMenu(const QPoint& pt) +{ + uint i; + + // Disable everything but the "new" action (clicked outside any widget) + for (i = 1; i < m_pPageMenu->count(); i++) + m_pPageMenu->setItemEnabled(m_pPageMenu->idAt(i), false); + + // Show the menu + m_pPageMenu->popup(pt); +} + +/** + * Displays a context menu for page operations. + * This slot is connected to the contextMenu() signal, emitted by + * m_pQueryTabs. + * @param pWidget The page under the mouse + * @param pt The point over which the mouse was clicked in request for + * the context menu + */ +void QueryWidget::slotContextMenu(QWidget* pWidget, const QPoint& pt) +{ + uint i; + + // Operations are on the current page, so we must ensure the clicked + // tab becomes the current one + setCurrentPage(pWidget); + + // Enable all operations + for (i = 1; i < m_pPageMenu->count(); i++) + m_pPageMenu->setItemEnabled(m_pPageMenu->idAt(i), true); + + // Show the menu + m_pPageMenu->popup(pt); +} + +/** + * Locks/unlocks the give page. + * @param pPage The page to lock or unlock + * @param bLock true to lock the page, false to unlock it + */ +void QueryWidget::setPageLocked(QueryPageBase* pPage, bool bLock) +{ + if (!pPage->canLock()) + return; + + // Set the locking state of the current page + pPage->setLocked(bLock); + m_pQueryTabs->setTabIconSet(pPage, bLock ? GET_PIXMAP(TabLocked) : + GET_PIXMAP(TabUnlocked)); + + // There can only be one unlocked history page. Check if a non-active + // query page is being unlocked + if (isHistoryPage(pPage) && (pPage != m_pHistPage) && !bLock) { + // Lock the active history page (may be NULL) + if (m_pHistPage != NULL) + setPageLocked(m_pHistPage, true); + + // Set the unlock page as the new active history page + m_pHistPage = (HistoryPage*)pPage; + } +} + +/** + * Ensures the current page is a query page that is ready to accept new + * queries. + * The function first checks the current page. If it is an unlocked query + * page, then nothing needs to be done. Otherwise, it checks for the first + * unlocked query page by iterating over all pages in the tab widget. If this + * fails as well, a new query page is created. + */ +void QueryWidget::findQueryPage() +{ + QueryPage* pPage; + int nPages, i; + + // First check if the current page is an unlocked query page + pPage = dynamic_cast<QueryPage*>(currentPage()); + if (pPage != NULL) { + if (!pPage->isLocked() && !pPage->isRunning()) + return; + } + + // Look for the first unlocked query page + nPages = m_pQueryTabs->count(); + for (i = 0; i < nPages; i++) { + pPage = dynamic_cast<QueryPage*>(m_pQueryTabs->page(i)); + if (pPage != NULL) { + if (!pPage->isLocked() && !pPage->isRunning()) { + setCurrentPage(pPage); + return; + } + } + } + + // Couldn't find an unlocked query page, create a new one + addQueryPage(); +} + +/** + * Ensures an active history page exists. + * The active history page is the only unlocked history page. If one does not + * exist, it is created. + */ +void QueryWidget::findHistoryPage() +{ + HistoryPage* pPage; + int nPages, i; + QString sTitle; + + // First check if the active history page is unlocked + if (m_pHistPage != NULL && !m_pHistPage->isLocked()) + return; + + // Look for the first unlocked history page + nPages = m_pQueryTabs->count(); + for (i = 0; i < nPages; i++) { + pPage = dynamic_cast<HistoryPage*>(m_pQueryTabs->page(i)); + if (pPage != NULL && !pPage->isLocked()) { + m_pHistPage = pPage; + return; + } + } + + // Couldn't find an unlocked query page, create a new one + m_pHistPage = new HistoryPage(this); + + // Add the page, and set it as the current one + m_pQueryTabs->insertTab(m_pHistPage, GET_PIXMAP(TabUnlocked), ""); + setPageCaption(m_pHistPage); + + // Emit the lineRequested() signal when a query record is selected on + // this page + connect(m_pHistPage, SIGNAL(lineRequested(const QString&, uint)), this, + SLOT(slotRequestLine(const QString&, uint))); +} + +#include "querywidget.moc" |