/*************************************************************************** * * 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 #include #include #include #include "calltreedlg.h" #include "graphwidget.h" #include "treewidget.h" #include "kscopepixmaps.h" #include "kscopeconfig.h" #include "graphprefdlg.h" /** The currently supported version of saved call-tree files. */ #define FILE_VERSION 5 /** Window flags for call-tree widgets. */ #define CALL_TREE_W_FLAGS \ WStyle_Customize | \ WStyle_NormalBorder | \ WStyle_Title | \ WDestructiveClose /** File Name index for the file name generation */ int CallTreeDlg::s_nFileNameIndex = 0; /** * Class constructor. * @param pParent The parent widget * @param szName The widget's name */ CallTreeDlg::CallTreeDlg(TQWidget* pParent, const char* szName) : CallTreeLayout(pParent, szName, CALL_TREE_W_FLAGS) { // Set button pixmaps m_pCalledButton->setPixmap(GET_PIXMAP(CalledTree)); m_pCallingButton->setPixmap(GET_PIXMAP(CallingTree)); m_pGraphButton->setPixmap(GET_PIXMAP(CallGraph)); m_pSaveButton->setPixmap(GET_PIXMAP(ButtonSaveAs)); m_pZoomInButton->setPixmap(GET_PIXMAP(ButtonZoomIn)); m_pZoomOutButton->setPixmap(GET_PIXMAP(ButtonZoomOut)); m_pRotateButton->setPixmap(GET_PIXMAP(ButtonRotate)); m_pPrefButton->setPixmap(GET_PIXMAP(ButtonPref)); // Open the location of a call connect(m_pGraphWidget, TQ_SIGNAL(lineRequested(const TQString&, uint)), this, TQ_SIGNAL(lineRequested(const TQString&, uint))); connect(m_pCalledWidget, TQ_SIGNAL(lineRequested(const TQString&, uint)), this, TQ_SIGNAL(lineRequested(const TQString&, uint))); connect(m_pCallingWidget, TQ_SIGNAL(lineRequested(const TQString&, uint)), this, TQ_SIGNAL(lineRequested(const TQString&, uint))); m_pCallingWidget->setMode(TreeWidget::Calling); // Get the default view from KScope's configuration m_nDefView = Config().getDefGraphView(); } /** * Class destructor. */ CallTreeDlg::~CallTreeDlg() { } /** * @param sFunc The function to use as the root of the call tree */ void CallTreeDlg::setRoot(const TQString& sFunc) { m_sRoot = sFunc; // Generate unique file name to save call tree later m_sFileName = sFunc; m_sFileName.replace(' ', '_'); m_sFileName += TQString::number(++s_nFileNameIndex); // Set the root item in all views m_pGraphWidget->setRoot(sFunc); m_pCalledWidget->setRoot(sFunc); m_pCallingWidget->setRoot(sFunc); } /** * Displays the dialogue. */ void CallTreeDlg::show() { // Set the default view. m_pViewGroup->setButton(m_nDefView); m_pStack->raiseWidget(m_nDefView); slotViewChanged(m_nDefView); CallTreeLayout::show(); } /** * Informs the call tree manager that this object should be removed from the * list of call tree dialogues. * The close event is received when the dialogue is explicitly closed by the * user. This dialogue will not appear when the project is reopened, and it * is therefore safe to delete the graph file at this point. * @param pEvent Information on the closing event */ void CallTreeDlg::closeEvent(TQCloseEvent* pEvent) { if (!m_sFilePath.isEmpty()) TQFile::remove(m_sFilePath); emit closed(this); TQWidget::closeEvent(pEvent); } extern void yyinit(CallTreeDlg*, FILE*, Encoder*); extern int yyparse(); /** * Restores a call tree from the given call tree file. * NOTE: The call tree file is deleted when loading is complete. * @param sProjPath The full path of the project directory * @param sFileName The name of the call tree file to load * @return true if successful, false otherwise */ bool CallTreeDlg::load(const TQString& sProjPath, const TQString& sFileName) { TQString sPath; FILE* pFile; int nVersion, nView, nResult; Encoder enc; // Create the full path name sPath = sProjPath + "/" + sFileName; // Open the file for reading pFile = fopen(sPath.latin1(), "r"); if (pFile == NULL) return false; // Check file version if ((fscanf(pFile, "VERSION=%d\n", &nVersion) != 1) || (nVersion != FILE_VERSION)) { fclose(pFile); return false; } // Get default view if ((fscanf(pFile, "View=%d\n", &nView) == 1) && (nView >= 0) && (nView <= 2)) { m_nDefView = nView; } // Read the call trees and the graph stored on this file yyinit(this, pFile, &enc); nResult = yyparse(); // Close the file fclose(pFile); // Check the result returned by the parser if (nResult != 0) return false; // Store the file name m_sFileName = sFileName; m_sFilePath = sPath; // Draw the graph m_pGraphWidget->draw(); return true; } /** * Writes the contents of the call tree dialog to a call tree file. * This method is called for call trees before the owner project is * closed. * @param sProjPath The full path of the project directory */ void CallTreeDlg::store(const TQString& sProjPath) { TQString sPath; FILE* pFile; // Create the full file path sPath = sProjPath + "/" + m_sFileName; m_sFilePath = sPath; // Open a file for writing (create if necessary) pFile = fopen(sPath.latin1(), "w+"); if (pFile == NULL) return; // Write header fprintf(pFile, "VERSION=%d\n", FILE_VERSION); fprintf(pFile, "View=%d\n", m_pViewGroup->selectedId()); // Save the contents of all widgets m_pCalledWidget->save(pFile); m_pCallingWidget->save(pFile); m_pGraphWidget->save(pFile); // Close the file fclose(pFile); } /** * Saves the graph to a dot file. * The user is prompted for a name to use for the file, and then graph * widget writes its information to this file (using the dot language). * This slot is connected to the clicked() signal of the "Save As..." button. */ void CallTreeDlg::slotSaveClicked() { TQString sFile; // Prompt the user for a file name sFile = KFileDialog::getSaveFileName(":kscope"); // Save the graph to a file (unless the user did not give a file name) if (!sFile.isEmpty()) m_pGraphWidget->save(sFile); } /** * Increases the zoom factor of the graph. * This slot is connected to the clicked() signal of the "Zoom In" button. */ void CallTreeDlg::slotZoomInClicked() { m_pGraphWidget->zoom(true); m_pGraphWidget->draw(); } /** * Decreases the zoom factor of the graph. * This slot is connected to the clicked() signal of the "Zoom Out" button. */ void CallTreeDlg::slotZoomOutClicked() { m_pGraphWidget->zoom(false); m_pGraphWidget->draw(); } /** * Changes the graph's layout direction. * This slot is connected to the clicked() signal of the "Rotate" button. */ void CallTreeDlg::slotRotateClicked() { m_pGraphWidget->rotate(); m_pGraphWidget->draw(); } /** * Opens the call graph preferences dialogue. * This slot is connected to the clicked() signal of the "Preferences" button. */ void CallTreeDlg::slotPrefClicked() { GraphPrefDlg dlg(this); int nMaxNodeDegree; if (dlg.exec() == TQDialog::Accepted) { nMaxNodeDegree = dlg.getMaxNodeDegree(); Config().setGraphMaxNodeDegree(nMaxNodeDegree); m_pGraphWidget->setMaxNodeDegree(nMaxNodeDegree); } } /** * Prepares the selected view. * This slot is called when the user chooses a different view through the * toggle buttons in the dialogue's toolbar. * @param nView Identifies the selected view */ void CallTreeDlg::slotViewChanged(int nView) { switch (nView) { case 0: // Call graph setCaption(i18n("Call Graph")); m_pGraphGroup->setEnabled(true); m_pHelpLabel->setText(i18n("Right-click a function node or an arrow " "head for more options.")); break; case 1: // Called functions tree setCaption(i18n("Called Functions Tree")); m_pGraphGroup->setEnabled(false); m_pHelpLabel->setText(i18n("Right-click a tree item for more " "options.")); m_pCalledWidget->queryRoot(); break; case 2: // Calling functions tree setCaption(i18n("Calling Functions Tree")); m_pGraphGroup->setEnabled(false); m_pHelpLabel->setText(i18n("Right-click a tree item for more " "options.")); m_pCallingWidget->queryRoot(); break; } Config().setDefGraphView(nView); } #include "calltreedlg.moc"