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.
kscope/src/querywidget.cpp

602 lines
16 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 <tqtoolbutton.h>
#include <tqtooltip.h>
#include <tdelocale.h>
#include <tdemessagebox.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(TQWidget* 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(TQWidget*)), this,
SLOT(slotCurrentChanged(TQWidget*)));
// Close a query when its tab button is clicked
connect(m_pQueryTabs, SIGNAL(closeRequest(TQWidget*)), this,
SLOT(slotClosePage(TQWidget*)));
// Show the menu when requested
connect(m_pQueryTabs, SIGNAL(contextMenu(const TQPoint&)), this,
SLOT(slotContextMenu(const TQPoint&)));
connect(m_pQueryTabs, SIGNAL(contextMenu(TQWidget*, const TQPoint&)), this,
SLOT(slotContextMenu(TQWidget*, const TQPoint&)));
}
/**
* 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 TQString& 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 TQString& sProjPath,
const TQStringList& slFiles)
{
TQStringList::ConstIterator itr;
QueryPageBase* pPage;
TQString 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 TQString& sProjPath, TQStringList& slFiles)
{
int nPageCount, i;
QueryPage* pPage;
TQString 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 TQString& sFile, uint nLine,
const TQString& 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;
TQString 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 TQString&, uint)), this,
SLOT(slotRequestLine(const TQString&, 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()
{
TQWidget* 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(TQPopupMenu* pMenu, TDEToggleAction* 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 TQString& 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(TQWidget* 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(TQWidget* 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 TQPoint& 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(TQWidget* pWidget, const TQPoint& 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;
TQString 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 TQString&, uint)), this,
SLOT(slotRequestLine(const TQString&, uint)));
}
#include "querywidget.moc"