/*************************************************************************** * * 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 #include #include "ctagslist.h" #include "kscopeconfig.h" #include "kscopepixmaps.h" /** * Defines a special list item for the tag list. * This special definition allows the tag list to be sorted according to * symbol line numbers. By default, all items are treated as text, hence the * comparison of line numbers such as "123" and "24" sets "24" to be the * larger item. By overriding the comparison function, this class allows for * correct sorting. * @author Elad Lahav */ class CtagsListItem : public TQListViewItem { public: /** * Class constructor. * @param pParent The owning list view widget * @param sName The name of the tag * @param sLine The line in which the tag is defined * @param sType The type of the tag */ CtagsListItem(TQListView* pParent, TQString sName, TQString sLine, TQString sType) : TQListViewItem(pParent, sName, sLine, sType), m_nPendLine (sLine.toUInt()) {} /** * Compares two tag list items, and determines their order. * If comparison is based on a text-column, the default behaviour is * used. Otherwise, the text is converted to unsigned integers, and then * compared as numbers. * @param pItem The item to compare against the local object * @param nCol The column index by which to compare * @param bAscend true if sorting in ascending order, false otherwise * @return 0 if the items are equal, 1 if the local item is greater, -1 * if the local item is lesser */ virtual int compare(TQListViewItem* pItem, int nCol, bool bAscend) const { if (nCol == 1) { uint nLineCur, nLineOther; int nResult; // Get the line numbers of each item nLineCur = text(1).toUInt(); nLineOther = pItem->text(1).toUInt(); // Compare the line numbers nResult = nLineCur - nLineOther; if (nResult == 0) return 0; // Items are equal else if (nResult > 0) return 1; // The first item is greater else return -1; // The second item is greater } // Use default comparison for text columns return TQListViewItem::compare(pItem, nCol, bAscend); } /** * @return The line number associated with this item */ inline uint getLine() { return m_nPendLine; } private: /** The numeric value of the line number column of this item. */ uint m_nPendLine; }; /** * Class constructor. * @param pParent The parent widget * @param szName The widget's name */ CtagsList::CtagsList(TQWidget* pParent, const char* szName) : SearchList(0, pParent, szName), m_arrLines(16), m_nItems(0), m_nCurItem(0), m_bReady(false), m_nCurLine(0), m_nPendLine(0) { m_pList->setShowSortIndicator(true); connect(m_pList->header(), TQ_SIGNAL(clicked(int)), this, TQ_SLOT(slotSortChanged(int))); // Determine the default sorting order switch (Config().getCtagSortOrder()) { case KScopeConfig::NameAsc: m_pList->setSorting(0, true); break; case KScopeConfig::NameDes: m_pList->setSorting(0, false); break; case KScopeConfig::LineAsc: m_pList->setSorting(1, true); break; case KScopeConfig::LineDes: m_pList->setSorting(1, false); break; case KScopeConfig::TypeAsc: m_pList->setSorting(2, true); break; case KScopeConfig::TypeDes: m_pList->setSorting(2, false); break; } // Add the list columns m_pList->addColumn(i18n("Name")); m_pList->addColumn(i18n("Line")); m_pList->addColumn(i18n("Type")); m_pList->setColumnAlignment(1, TQt::AlignRight); // Set colours and font applyPrefs(); } /** * Class destructor. */ CtagsList::~CtagsList() { } /** * Adds a Ctags output entry to the list. * This slot is connected to the dataReady() signal of a CtagsFrontend object. * @param pToken The first token in the entry */ void CtagsList::slotDataReady(FrontendToken* pToken) { TQString sName, sType, sLine; CtagsListItem* pItem; KScopePixmaps::PixName pix; // Get the name of the symbol sName = pToken->getData(); pToken = pToken->getNext(); // Get the line number sLine = pToken->getData(); pToken = pToken->getNext(); // Get the type of the symbol sType = pToken->getData(); pToken = pToken->getNext(); // Set the appropriate pixmap switch (sType[0].latin1()) { case 'f': sType = i18n("Function"); pix = KScopePixmaps::SymFunc; break; case 'v': sType = i18n("Variable"); pix = KScopePixmaps::SymVar; break; case 's': sType = i18n("Struct"); pix = KScopePixmaps::SymStruct; break; case 'd': sType = i18n("Macro"); pix = KScopePixmaps::SymMacro; break; case 'm': sType = i18n("Member"); pix = KScopePixmaps::SymMember; break; case 'g': sType = i18n("Enum"); pix = KScopePixmaps::SymEnum; break; case 'e': sType = i18n("Enumerator"); pix = KScopePixmaps::SymEnumerator; break; case 't': sType = i18n("Typedef"); pix = KScopePixmaps::SymTypedef; break; case 'l': sType = i18n("Label"); pix = KScopePixmaps::SymLabel; break; case 'i': sType = i18n("Include"); pix = KScopePixmaps::SymInclude; break; default: sType = "Unknown"; pix = KScopePixmaps::SymUnknown; } // Add a new item to the list pItem = new CtagsListItem(m_pList, sName, sLine, sType); pItem->setPixmap(0, Pixmaps().getPixmap(pix)); m_nItems++; // Resize the line array, if required if (m_arrLines.size() < m_nItems) m_arrLines.resize(m_nItems, TQGArray::SpeedOptim); // Add the new item to the line array m_arrLines[m_nItems - 1] = pItem; } /** * Handles the "resize" event, which occurs when the size of the widget * changes. * @param pEvent The event data */ void CtagsList::resizeEvent(TQResizeEvent* pEvent) { SearchList::resizeEvent(pEvent); emit resized(); } /** * Emits the lineRequested() signal when a list item is selected. * This function is called if either an item is double-clicked, or an item is * highlighted and the ENTER key is pressed. * @param pItem The selected list item */ void CtagsList::processItemSelected(TQListViewItem* pItem) { TQString sLine; sLine = pItem->text(1); emit lineRequested(sLine.toUInt()); } /** * Constructs a tool-tip for the given item. * @param pItem The item for which a tip is required * @param sTip The constructed tip string (on return) * @return Always true */ bool CtagsList::getTip(TQListViewItem* pItem, TQString& sTip) { sTip = TQString("Type: %1
Name: %2
Line: %3"). arg(pItem->text(2)).arg(pItem->text(0)).arg(pItem->text(1)); return true; } /** * Sets the list's colours and font, according the user's preferences. */ void CtagsList::applyPrefs() { // Apply colour settings m_pList->setPaletteBackgroundColor(Config().getColor( KScopeConfig::TagListBack)); m_pList->setPaletteForegroundColor(Config().getColor( KScopeConfig::TagListFore)); m_pList->setFont(Config().getFont(KScopeConfig::TagList)); } /** * Selects the symbol that dominates the given line in the source file. * @param nLine The requested line */ void CtagsList::gotoLine(uint nLine) { CtagsListItem* pItem; int nFrom, nTo, nItem, nDiff; // Wait until Ctags finishes if (!m_bReady) { m_nPendLine = nLine; return; } // Do nothing if no tags are available if (m_nItems == 0) return; // Calculate the difference from the current line nDiff = (int)(nLine - m_nCurLine); m_nCurLine = nLine; // In most cases, all the user does is move to the next or prevuious lines // Handle these simple cases first if (nDiff == 1) { if ((m_nCurItem < m_nItems - 1) && (m_arrLines[m_nCurItem + 1]->getLine() == nLine)) { m_nCurItem++; } else { return; // New line corresponds to the same tag } } else if (nDiff == -1) { if ((m_nCurItem > 0) && (m_arrLines[m_nCurItem]->getLine() > nLine)) { m_nCurItem--; } else { return; // New line corresponds to the same tag } } else { // Initialise binary search nFrom = 0; nTo = m_nItems - 1; m_nCurItem = 0; // use the first item if nothing else works // Perform a binary search // This algorithm finds the greatest line that is smaller or equal to // the requested line do { nItem = (nFrom + nTo) / 2; pItem = m_arrLines[nItem]; if (pItem->getLine() == nLine) { m_nCurItem = nItem; break; } else if (nLine > pItem->getLine()) { m_nCurItem = nItem; nFrom = nItem + 1; } else { nTo = nItem - 1; } } while (nFrom <= nTo); } // Mark the selected item pItem = m_arrLines[m_nCurItem]; m_pList->setSelected(pItem, true); m_pList->ensureItemVisible(pItem); m_nPendLine = 0; } /** * Deletes all items in the list. */ void CtagsList::clear() { m_pList->clear(); m_nItems = 0; m_nCurItem = 0; m_nCurLine = 0; m_nPendLine = 0; m_bReady = false; } /** * Indicates Ctags has finished processing the current file. * If a goto operation has been scheduled, it is processed. * @param nRecords The number of records generated by Ctags */ void CtagsList::slotCtagsFinished(uint nRecords) { if (nRecords) { m_bReady = true; if (m_nPendLine) gotoLine(m_nPendLine); } } /** * Determines the new sort order in the tags list. * This slot is connected to the clicked() signal of the tag list's header. * @param nSection Identifies the column whose header button was clicked. */ void CtagsList::slotSortChanged(int nSection) { TQt::SortOrder order; // Determine whether the new order is ascending or descending order = m_pList->sortOrder(); // Translate the section number into the order constant switch (nSection) { case 0: // Sort by name Config().setCtagSortOrder(order == TQt::Ascending ? KScopeConfig::NameAsc : KScopeConfig::NameDes); break; case 1: // Sort by line Config().setCtagSortOrder(order == TQt::Ascending ? KScopeConfig::LineAsc : KScopeConfig::LineDes); break; case 2: // Sort by type Config().setCtagSortOrder(order == TQt::Ascending ? KScopeConfig::TypeAsc : KScopeConfig::TypeDes); break; } } #include "ctagslist.moc"