|
|
|
/***************************************************************************
|
|
|
|
*
|
|
|
|
* 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 <ntqfile.h>
|
|
|
|
#include <ntqtoolbutton.h>
|
|
|
|
#include <ntqbuttongroup.h>
|
|
|
|
#include <ntqwidgetstack.h>
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <tdefiledialog.h>
|
|
|
|
#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, SIGNAL(lineRequested(const TQString&, uint)),
|
|
|
|
this, SIGNAL(lineRequested(const TQString&, uint)));
|
|
|
|
connect(m_pCalledWidget, SIGNAL(lineRequested(const TQString&, uint)),
|
|
|
|
this, SIGNAL(lineRequested(const TQString&, uint)));
|
|
|
|
connect(m_pCallingWidget, SIGNAL(lineRequested(const TQString&, uint)),
|
|
|
|
this, 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"
|