summaryrefslogtreecommitdiffstats
path: root/redhat/kdesdk
diff options
context:
space:
mode:
authorFrancois Andriot <francois.andriot@free.fr>2013-01-03 20:17:46 +0100
committerFrancois Andriot <francois.andriot@free.fr>2013-01-03 20:17:46 +0100
commitb566058ccb7fa94c6e34fb1e1349b093d4482d6a (patch)
tree34f3d392092770893605fc03cfce42726c445e0b /redhat/kdesdk
parent4398af173f2663445e824a79c6367adab62c83e1 (diff)
downloadtde-packaging-b566058ccb7fa94c6e34fb1e1349b093d4482d6a.tar.gz
tde-packaging-b566058ccb7fa94c6e34fb1e1349b093d4482d6a.zip
RPM packaging: lots of updates
Diffstat (limited to 'redhat/kdesdk')
-rw-r--r--redhat/kdesdk/kdesdk-3.5.13.1-fix_kdecachegrind_ftbfs.patch39683
-rw-r--r--redhat/kdesdk/kdesdk-3.5.13.1-fix_various_cmake_issues.patch159
2 files changed, 39842 insertions, 0 deletions
diff --git a/redhat/kdesdk/kdesdk-3.5.13.1-fix_kdecachegrind_ftbfs.patch b/redhat/kdesdk/kdesdk-3.5.13.1-fix_kdecachegrind_ftbfs.patch
new file mode 100644
index 000000000..80ca10ff8
--- /dev/null
+++ b/redhat/kdesdk/kdesdk-3.5.13.1-fix_kdecachegrind_ftbfs.patch
@@ -0,0 +1,39683 @@
+commit cfccedd9c8db3af36d7c5635ca212fa170bb6ff5
+Author: Timothy Pearson <kb9vqf@pearsoncomputing.net>
+Date: 1327976424 -0600
+
+ Part 2 of prior commit
+
+diff --git a/kdecachegrind/AUTHORS b/kdecachegrind/AUTHORS
+new file mode 100644
+index 0000000..ded6005
+--- /dev/null
++++ b/kdecachegrind/AUTHORS
+@@ -0,0 +1 @@
++Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+diff --git a/kdecachegrind/COPYING b/kdecachegrind/COPYING
+new file mode 100644
+index 0000000..c13faf0
+--- /dev/null
++++ b/kdecachegrind/COPYING
+@@ -0,0 +1,340 @@
++ GNU GENERAL PUBLIC LICENSE
++ Version 2, June 1991
++
++ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
++ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ Everyone is permitted to copy and distribute verbatim copies
++ of this license document, but changing it is not allowed.
++
++ Preamble
++
++ The licenses for most software are designed to take away your
++freedom to share and change it. By contrast, the GNU General Public
++License is intended to guarantee your freedom to share and change free
++software--to make sure the software is free for all its users. This
++General Public License applies to most of the Free Software
++Foundation's software and to any other program whose authors commit to
++using it. (Some other Free Software Foundation software is covered by
++the GNU Library General Public License instead.) You can apply it to
++your programs, too.
++
++ When we speak of free software, we are referring to freedom, not
++price. Our General Public Licenses are designed to make sure that you
++have the freedom to distribute copies of free software (and charge for
++this service if you wish), that you receive source code or can get it
++if you want it, that you can change the software or use pieces of it
++in new free programs; and that you know you can do these things.
++
++ To protect your rights, we need to make restrictions that forbid
++anyone to deny you these rights or to ask you to surrender the rights.
++These restrictions translate to certain responsibilities for you if you
++distribute copies of the software, or if you modify it.
++
++ For example, if you distribute copies of such a program, whether
++gratis or for a fee, you must give the recipients all the rights that
++you have. You must make sure that they, too, receive or can get the
++source code. And you must show them these terms so they know their
++rights.
++
++ We protect your rights with two steps: (1) copyright the software, and
++(2) offer you this license which gives you legal permission to copy,
++distribute and/or modify the software.
++
++ Also, for each author's protection and ours, we want to make certain
++that everyone understands that there is no warranty for this free
++software. If the software is modified by someone else and passed on, we
++want its recipients to know that what they have is not the original, so
++that any problems introduced by others will not reflect on the original
++authors' reputations.
++
++ Finally, any free program is threatened constantly by software
++patents. We wish to avoid the danger that redistributors of a free
++program will individually obtain patent licenses, in effect making the
++program proprietary. To prevent this, we have made it clear that any
++patent must be licensed for everyone's free use or not licensed at all.
++
++ The precise terms and conditions for copying, distribution and
++modification follow.
++
++ GNU GENERAL PUBLIC LICENSE
++ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
++
++ 0. This License applies to any program or other work which contains
++a notice placed by the copyright holder saying it may be distributed
++under the terms of this General Public License. The "Program", below,
++refers to any such program or work, and a "work based on the Program"
++means either the Program or any derivative work under copyright law:
++that is to say, a work containing the Program or a portion of it,
++either verbatim or with modifications and/or translated into another
++language. (Hereinafter, translation is included without limitation in
++the term "modification".) Each licensee is addressed as "you".
++
++Activities other than copying, distribution and modification are not
++covered by this License; they are outside its scope. The act of
++running the Program is not restricted, and the output from the Program
++is covered only if its contents constitute a work based on the
++Program (independent of having been made by running the Program).
++Whether that is true depends on what the Program does.
++
++ 1. You may copy and distribute verbatim copies of the Program's
++source code as you receive it, in any medium, provided that you
++conspicuously and appropriately publish on each copy an appropriate
++copyright notice and disclaimer of warranty; keep intact all the
++notices that refer to this License and to the absence of any warranty;
++and give any other recipients of the Program a copy of this License
++along with the Program.
++
++You may charge a fee for the physical act of transferring a copy, and
++you may at your option offer warranty protection in exchange for a fee.
++
++ 2. You may modify your copy or copies of the Program or any portion
++of it, thus forming a work based on the Program, and copy and
++distribute such modifications or work under the terms of Section 1
++above, provided that you also meet all of these conditions:
++
++ a) You must cause the modified files to carry prominent notices
++ stating that you changed the files and the date of any change.
++
++ b) You must cause any work that you distribute or publish, that in
++ whole or in part contains or is derived from the Program or any
++ part thereof, to be licensed as a whole at no charge to all third
++ parties under the terms of this License.
++
++ c) If the modified program normally reads commands interactively
++ when run, you must cause it, when started running for such
++ interactive use in the most ordinary way, to print or display an
++ announcement including an appropriate copyright notice and a
++ notice that there is no warranty (or else, saying that you provide
++ a warranty) and that users may redistribute the program under
++ these conditions, and telling the user how to view a copy of this
++ License. (Exception: if the Program itself is interactive but
++ does not normally print such an announcement, your work based on
++ the Program is not required to print an announcement.)
++
++These requirements apply to the modified work as a whole. If
++identifiable sections of that work are not derived from the Program,
++and can be reasonably considered independent and separate works in
++themselves, then this License, and its terms, do not apply to those
++sections when you distribute them as separate works. But when you
++distribute the same sections as part of a whole which is a work based
++on the Program, the distribution of the whole must be on the terms of
++this License, whose permissions for other licensees extend to the
++entire whole, and thus to each and every part regardless of who wrote it.
++
++Thus, it is not the intent of this section to claim rights or contest
++your rights to work written entirely by you; rather, the intent is to
++exercise the right to control the distribution of derivative or
++collective works based on the Program.
++
++In addition, mere aggregation of another work not based on the Program
++with the Program (or with a work based on the Program) on a volume of
++a storage or distribution medium does not bring the other work under
++the scope of this License.
++
++ 3. You may copy and distribute the Program (or a work based on it,
++under Section 2) in object code or executable form under the terms of
++Sections 1 and 2 above provided that you also do one of the following:
++
++ a) Accompany it with the complete corresponding machine-readable
++ source code, which must be distributed under the terms of Sections
++ 1 and 2 above on a medium customarily used for software interchange; or,
++
++ b) Accompany it with a written offer, valid for at least three
++ years, to give any third party, for a charge no more than your
++ cost of physically performing source distribution, a complete
++ machine-readable copy of the corresponding source code, to be
++ distributed under the terms of Sections 1 and 2 above on a medium
++ customarily used for software interchange; or,
++
++ c) Accompany it with the information you received as to the offer
++ to distribute corresponding source code. (This alternative is
++ allowed only for noncommercial distribution and only if you
++ received the program in object code or executable form with such
++ an offer, in accord with Subsection b above.)
++
++The source code for a work means the preferred form of the work for
++making modifications to it. For an executable work, complete source
++code means all the source code for all modules it contains, plus any
++associated interface definition files, plus the scripts used to
++control compilation and installation of the executable. However, as a
++special exception, the source code distributed need not include
++anything that is normally distributed (in either source or binary
++form) with the major components (compiler, kernel, and so on) of the
++operating system on which the executable runs, unless that component
++itself accompanies the executable.
++
++If distribution of executable or object code is made by offering
++access to copy from a designated place, then offering equivalent
++access to copy the source code from the same place counts as
++distribution of the source code, even though third parties are not
++compelled to copy the source along with the object code.
++
++ 4. You may not copy, modify, sublicense, or distribute the Program
++except as expressly provided under this License. Any attempt
++otherwise to copy, modify, sublicense or distribute the Program is
++void, and will automatically terminate your rights under this License.
++However, parties who have received copies, or rights, from you under
++this License will not have their licenses terminated so long as such
++parties remain in full compliance.
++
++ 5. You are not required to accept this License, since you have not
++signed it. However, nothing else grants you permission to modify or
++distribute the Program or its derivative works. These actions are
++prohibited by law if you do not accept this License. Therefore, by
++modifying or distributing the Program (or any work based on the
++Program), you indicate your acceptance of this License to do so, and
++all its terms and conditions for copying, distributing or modifying
++the Program or works based on it.
++
++ 6. Each time you redistribute the Program (or any work based on the
++Program), the recipient automatically receives a license from the
++original licensor to copy, distribute or modify the Program subject to
++these terms and conditions. You may not impose any further
++restrictions on the recipients' exercise of the rights granted herein.
++You are not responsible for enforcing compliance by third parties to
++this License.
++
++ 7. If, as a consequence of a court judgment or allegation of patent
++infringement or for any other reason (not limited to patent issues),
++conditions are imposed on you (whether by court order, agreement or
++otherwise) that contradict the conditions of this License, they do not
++excuse you from the conditions of this License. If you cannot
++distribute so as to satisfy simultaneously your obligations under this
++License and any other pertinent obligations, then as a consequence you
++may not distribute the Program at all. For example, if a patent
++license would not permit royalty-free redistribution of the Program by
++all those who receive copies directly or indirectly through you, then
++the only way you could satisfy both it and this License would be to
++refrain entirely from distribution of the Program.
++
++If any portion of this section is held invalid or unenforceable under
++any particular circumstance, the balance of the section is intended to
++apply and the section as a whole is intended to apply in other
++circumstances.
++
++It is not the purpose of this section to induce you to infringe any
++patents or other property right claims or to contest validity of any
++such claims; this section has the sole purpose of protecting the
++integrity of the free software distribution system, which is
++implemented by public license practices. Many people have made
++generous contributions to the wide range of software distributed
++through that system in reliance on consistent application of that
++system; it is up to the author/donor to decide if he or she is willing
++to distribute software through any other system and a licensee cannot
++impose that choice.
++
++This section is intended to make thoroughly clear what is believed to
++be a consequence of the rest of this License.
++
++ 8. If the distribution and/or use of the Program is restricted in
++certain countries either by patents or by copyrighted interfaces, the
++original copyright holder who places the Program under this License
++may add an explicit geographical distribution limitation excluding
++those countries, so that distribution is permitted only in or among
++countries not thus excluded. In such case, this License incorporates
++the limitation as if written in the body of this License.
++
++ 9. The Free Software Foundation may publish revised and/or new versions
++of the General Public License from time to time. Such new versions will
++be similar in spirit to the present version, but may differ in detail to
++address new problems or concerns.
++
++Each version is given a distinguishing version number. If the Program
++specifies a version number of this License which applies to it and "any
++later version", you have the option of following the terms and conditions
++either of that version or of any later version published by the Free
++Software Foundation. If the Program does not specify a version number of
++this License, you may choose any version ever published by the Free Software
++Foundation.
++
++ 10. If you wish to incorporate parts of the Program into other free
++programs whose distribution conditions are different, write to the author
++to ask for permission. For software which is copyrighted by the Free
++Software Foundation, write to the Free Software Foundation; we sometimes
++make exceptions for this. Our decision will be guided by the two goals
++of preserving the free status of all derivatives of our free software and
++of promoting the sharing and reuse of software generally.
++
++ NO WARRANTY
++
++ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
++PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
++REPAIR OR CORRECTION.
++
++ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
++POSSIBILITY OF SUCH DAMAGES.
++
++ END OF TERMS AND CONDITIONS
++
++ How to Apply These Terms to Your New Programs
++
++ If you develop a new program, and you want it to be of the greatest
++possible use to the public, the best way to achieve this is to make it
++free software which everyone can redistribute and change under these terms.
++
++ To do so, attach the following notices to the program. It is safest
++to attach them to the start of each source file to most effectively
++convey the exclusion of warranty; and each file should have at least
++the "copyright" line and a pointer to where the full notice is found.
++
++ <one line to give the program's name and a brief idea of what it does.>
++ Copyright (C) <year> <name of author>
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++
++
++Also add information on how to contact you by electronic and paper mail.
++
++If the program is interactive, make it output a short notice like this
++when it starts in an interactive mode:
++
++ Gnomovision version 69, Copyright (C) year name of author
++ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
++ This is free software, and you are welcome to redistribute it
++ under certain conditions; type `show c' for details.
++
++The hypothetical commands `show w' and `show c' should show the appropriate
++parts of the General Public License. Of course, the commands you use may
++be called something other than `show w' and `show c'; they could even be
++mouse-clicks or menu items--whatever suits your program.
++
++You should also get your employer (if you work as a programmer) or your
++school, if any, to sign a "copyright disclaimer" for the program, if
++necessary. Here is a sample; alter the names:
++
++ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
++ `Gnomovision' (which makes passes at compilers) written by James Hacker.
++
++ <signature of Ty Coon>, 1 April 1989
++ Ty Coon, President of Vice
++
++This General Public License does not permit incorporating your program into
++proprietary programs. If your program is a subroutine library, you may
++consider it more useful to permit linking proprietary applications with the
++library. If this is what you want to do, use the GNU Library General
++Public License instead of this License.
+diff --git a/kdecachegrind/ChangeLog b/kdecachegrind/ChangeLog
+new file mode 100644
+index 0000000..05f3081
+--- /dev/null
++++ b/kdecachegrind/ChangeLog
+@@ -0,0 +1,89 @@
++2004/06/30
++ * Leak fixes
++ * Crash fixes on reload (make setData() synchroneous)
++ * Some update fixes in the data model (tracedata.cpp)
++ * Fix update problems in Function Profile
++ * Reselect active function on refresh in function profile
++ with grouping on
++
++2004/04/28
++ * toplevel.h/cpp, kdecachegrindui.rc
++ - Switching Layouts
++ * multiview.cpp: Removed some qDebug's
++ * Same term fixes
++
++2004/04/26
++ * cachegrindloader.cpp, fixcost.cpp:
++ - Allow Ranges in Subposition Spec, currently not used
++ - Correctly parse "Desc: Trigger:"
++ - Allow Event Spec (Long Name, Formula) with "event:"
++ * listutils.cpp:
++ - make level meters for costs only 1 bar
++ (2 with upper from 0..50%, lower 50%..100% is really confusing)
++ - Besides from Call graph and Tree maps, truncate bars to
++ only use needed size (removes lots of empty rectangles)
++ * CallGraphView:
++ - some fixes when no data is loaded
++ * functionselection.cpp (Function Profile)
++ - activation on mouse release to allow for context menu
++ * tracedata.cpp
++ - more robust parsing of events lists
++ - Introduction of Ranges (not currently used)
++ * utils.cpp:
++ - more robust parsing functions
++
++2004/04/05
++ * CallGraphView:
++ - Add Context menu item "Export as Image"
++ - Hide Birdseye-View if call-graph fits into widget
++ - Error messages in Canvas when something goes wrong
++ * Some Fixes, qDebug->kdDebug
++
++2004/04/02
++ * In most views columns for 2nd Event Type added
++ * Context menus modified to allow quick change of 2nd Event Type
++ * Toolbar simplified (only most used actions)
++ * Terminology fixes ("cost type"->"event type",
++ "trace data"->"profile data", long names of Ir,Dr,...)
++ * Sorting costs in lists is always descending now
++ * New File menu item: "Add..." other profile data to current window
++ * Detect Cachegrind format by "events:" content, not file name
++ Allows for arbitrary names of profile data files.
++
++2004/03/25
++ * New Class Addr as wrapper for memory addresses. Use 64bit
++ to allow loading of data produced on 64bit architectures
++
++2004/03/17
++
++ * costtypeview.cpp, tracedata.h/cpp:
++ Fixed deletion of custom types
++ * cachegrindloader.cpp, tracedata.h/cpp:
++ Moved String compression handling in Cachegrind files
++ to CachegrindLoader
++ * Do not show inclusive cost column in FunctionSelection
++ side bar if not available
++ * Remove "isPartOfTrace" from Loader interface
++ (we allow parts from multiple experiments for comp.)
++ * partview.cpp, partlistitem.h/cpp:
++ Remove Column Callees, add Trigger
++
++2003/05/10
++
++ * Status progress on loading and cycle calculation
++ * Corrected order of trace parts (PID/PartNo/ThreadID)
++ * Allow adding traces (BUGGY...)
++
++2003/02/06
++
++ * Version 0.3a
++ * Bugfixes:
++ - Compiles with KDE 3.0.x
++ - Always select a first cost type
++ - Loading from another directory
++
++
++2002/11/28
++
++ * Version 0.3
++
+diff --git a/kdecachegrind/INSTALL b/kdecachegrind/INSTALL
+new file mode 100644
+index 0000000..02a4a07
+--- /dev/null
++++ b/kdecachegrind/INSTALL
+@@ -0,0 +1,167 @@
++Basic Installation
++==================
++
++ These are generic installation instructions.
++
++ The `configure' shell script attempts to guess correct values for
++various system-dependent variables used during compilation. It uses
++those values to create a `Makefile' in each directory of the package.
++It may also create one or more `.h' files containing system-dependent
++definitions. Finally, it creates a shell script `config.status' that
++you can run in the future to recreate the current configuration, a file
++`config.cache' that saves the results of its tests to speed up
++reconfiguring, and a file `config.log' containing compiler output
++(useful mainly for debugging `configure').
++
++ If you need to do unusual things to compile the package, please try
++to figure out how `configure' could check whether to do them, and mail
++diffs or instructions to the address given in the `README' so they can
++be considered for the next release. If at some point `config.cache'
++contains results you don't want to keep, you may remove or edit it.
++
++ The file `configure.in' is used to create `configure' by a program
++called `autoconf'. You only need `configure.in' if you want to change
++it or regenerate `configure' using a newer version of `autoconf'.
++
++The simplest way to compile this package is:
++
++ 1. `cd' to the directory containing the package's source code and type
++ `./configure' to configure the package for your system. If you're
++ using `csh' on an old version of System V, you might need to type
++ `sh ./configure' instead to prevent `csh' from trying to execute
++ `configure' itself.
++
++ Running `configure' takes a while. While running, it prints some
++ messages telling which features it is checking for.
++
++ 2. Type `make' to compile the package.
++
++ 3. Type `make install' to install the programs and any data files and
++ documentation.
++
++ 4. You can remove the program binaries and object files from the
++ source code directory by typing `make clean'.
++
++Compilers and Options
++=====================
++
++ Some systems require unusual options for compilation or linking that
++the `configure' script does not know about. You can give `configure'
++initial values for variables by setting them in the environment. Using
++a Bourne-compatible shell, you can do that on the command line like
++this:
++ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
++
++Or on systems that have the `env' program, you can do it like this:
++ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
++
++Compiling For Multiple Architectures
++====================================
++
++ You can compile the package for more than one kind of computer at the
++same time, by placing the object files for each architecture in their
++own directory. To do this, you must use a version of `make' that
++supports the `VPATH' variable, such as GNU `make'. `cd' to the
++directory where you want the object files and executables to go and run
++the `configure' script. `configure' automatically checks for the
++source code in the directory that `configure' is in and in `..'.
++
++ If you have to use a `make' that does not supports the `VPATH'
++variable, you have to compile the package for one architecture at a time
++in the source code directory. After you have installed the package for
++one architecture, use `make distclean' before reconfiguring for another
++architecture.
++
++Installation Names
++==================
++
++ By default, `make install' will install the package's files in
++`/usr/local/bin', `/usr/local/man', etc. You can specify an
++installation prefix other than `/usr/local' by giving `configure' the
++option `--prefix=PATH'.
++
++ You can specify separate installation prefixes for
++architecture-specific files and architecture-independent files. If you
++give `configure' the option `--exec-prefix=PATH', the package will use
++PATH as the prefix for installing programs and libraries.
++Documentation and other data files will still use the regular prefix.
++
++ If the package supports it, you can cause programs to be installed
++with an extra prefix or suffix on their names by giving `configure' the
++option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
++
++Optional Features
++=================
++
++ Some packages pay attention to `--enable-FEATURE' options to
++`configure', where FEATURE indicates an optional part of the package.
++They may also pay attention to `--with-PACKAGE' options, where PACKAGE
++is something like `gnu-as' or `x' (for the X Window System). The
++`README' should mention any `--enable-' and `--with-' options that the
++package recognizes.
++
++ For packages that use the X Window System, `configure' can usually
++find the X include and library files automatically, but if it doesn't,
++you can use the `configure' options `--x-includes=DIR' and
++`--x-libraries=DIR' to specify their locations.
++
++Specifying the System Type
++==========================
++
++ There may be some features `configure' can not figure out
++automatically, but needs to determine by the type of host the package
++will run on. Usually `configure' can figure that out, but if it prints
++a message saying it can not guess the host type, give it the
++`--host=TYPE' option. TYPE can either be a short name for the system
++type, such as `sun4', or a canonical name with three fields:
++ CPU-COMPANY-SYSTEM
++
++See the file `config.sub' for the possible values of each field. If
++`config.sub' isn't included in this package, then this package doesn't
++need to know the host type.
++
++ If you are building compiler tools for cross-compiling, you can also
++use the `--target=TYPE' option to select the type of system they will
++produce code for and the `--build=TYPE' option to select the type of
++system on which you are compiling the package.
++
++Sharing Defaults
++================
++
++ If you want to set default values for `configure' scripts to share,
++you can create a site shell script called `config.site' that gives
++default values for variables like `CC', `cache_file', and `prefix'.
++`configure' looks for `PREFIX/share/config.site' if it exists, then
++`PREFIX/etc/config.site' if it exists. Or, you can set the
++`CONFIG_SITE' environment variable to the location of the site script.
++A warning: not all `configure' scripts look for a site script.
++
++Operation Controls
++==================
++
++ `configure' recognizes the following options to control how it
++operates.
++
++`--cache-file=FILE'
++ Use and save the results of the tests in FILE instead of
++ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
++ debugging `configure'.
++
++`--help'
++ Print a summary of the options to `configure', and exit.
++
++`--quiet'
++`--silent'
++`-q'
++ Do not print messages saying which checks are being made.
++
++`--srcdir=DIR'
++ Look for the package's source code in directory DIR. Usually
++ `configure' can determine that directory automatically.
++
++`--version'
++ Print the version of Autoconf used to generate the `configure'
++ script, and exit.
++
++`configure' also accepts some other, not widely useful, options.
++
+diff --git a/kdecachegrind/Makefile.am b/kdecachegrind/Makefile.am
+new file mode 100644
+index 0000000..e93f6af
+--- /dev/null
++++ b/kdecachegrind/Makefile.am
+@@ -0,0 +1,6 @@
++SUBDIRS = kdecachegrind pics converters
++
++EXTRA_DIST = \
++ AUTHORS COPYING NEWS ChangeLog INSTALL README TODO \
++ kdecachegrind.lsm kdecachegrind.spec version.h
++
+diff --git a/kdecachegrind/NEWS b/kdecachegrind/NEWS
+new file mode 100644
+index 0000000..e69de29
+diff --git a/kdecachegrind/README b/kdecachegrind/README
+new file mode 100644
+index 0000000..0866eb8
+--- /dev/null
++++ b/kdecachegrind/README
+@@ -0,0 +1,62 @@
++KCachegrind
++===========
++
++
++What is all this about ?
++-------------------------
++
++Profiling, i.e. determinating most time consuming execution parts,
++is an important last step when developing applications.
++KCachegrind visualizes traces, generated by profiling, in various ways;
++most notable is the TreeMap visualization of the calls happening
++and a condensed version of it, the Coverage analysis.
++KCachegrind is designed to allow fast browsing and to provide a quick
++overview of very large programs, such as KDE applications (but not
++limited to!).
++
++At the moment, it uses Cachegrind as profiling backend, which is using
++the excellent CPU simulator in Valgrind. Thus, profiling does not
++need any preparation, can cope with shared libraries and plugin
++architectures, and allows for profile runs to not influence the measuring
++by the profile itself (all in contrast to e.g. GProf). Disadvantage is
++slower profile runs, unfortunately.
++
++For Cachegrind to provide call tree information, a patch is provided.
++This enables the most interesting visualization features of KCachegrind.
++
++
++Requirements
++------------
++
++A call-tree version of Cachegrind:
++ - X86 Linux
++ - Valgrind 1.0.x with call-tree patch from KCachegrind Website
++ - Valgrind 2.0.x with call-tree skin installed
++
++Cachegrind runs on x86 platforms, KCachegrind on all KDE enabled
++platforms (KDE 3.0.x).
++
++
++Compilation and Installation
++----------------------------
++
++Simple do the command sequence
++
++ ./configure --prefix=<KDE base directory>
++ make
++ make install
++
++
++
++KCachegrind features
++--------------------
++
++Most important: TreeMap calltree visualisation.
++For the rest, see the detailed "What's this?" help for
++each part of KCachegrind and the quick starter on the
++WWW page ( http://kcachegrind.sourceforge.net/cgi-bin/show.cgi )
++
++
++
++Happy Profiling,
++ Josef Weidendorfer
+diff --git a/kdecachegrind/TODO b/kdecachegrind/TODO
+new file mode 100644
+index 0000000..1eca67e
+--- /dev/null
++++ b/kdecachegrind/TODO
+@@ -0,0 +1,100 @@
++TODO/Wishlist Items
++===================
++
++
++KCachegrind
++-----------
++
++All cost Lists:
++* Show up to a number of items, not down to a threadshold.
++ If more, add a "..." with number of items not shown, and context option
++ to show more
++* "Copy from Top" converts lists into ASCII, puts into clipboard
++
++
++Configuration:
++ Source dirs per ELF object
++
++Layout:
++* 1/2/3/4 vertical/horizontal FunctionInfos
++ with Shift/Wraparound selection mode
++* Inside each FunctionInfo different Layouts
++ - tabbed layout
++ - top: info, bottom left: calls/coverage, bottom right: graph/source
++* Long/short info tab
++
++General:
++* Selected Item can be a object/file/class/function/line
++* Configuration Dlg
++ - Local config (?)
++ - Cost Types
++ - function colors
++ - Try to reload source after config.
++* Session Management
++
++
++
++Annotation Views:
++
++ BUGS:
++ * Draw problem with multiple srcs to one target
++ * REP case...
++
++ TODO:
++ * Selectable Jumps (Arrows)
++ * Tooltip for Jumps (Kind, from/to, jump count)
++ * Show direction (arrows) on jump lines
++
++ Source view TODO:
++ * Implicit jumps (green) [needs support from the tool?]
++
++
++
++Callgraph:
++* Fix Arrows for back-arcs
++* Less "Jumps" for minimap
++* Correct Keyboard navigation (how?)
++
++Types:
++* Ratios
++* Automatic subtypes
++
++WISHS:
++* Support for Data tracing
++ Which variables are touched how often from which function?
++ - Some graphical visualisation...
++
++* GCC -pg (gmon.out) as Profiling Backend
++* Demangler (use c++filt)
++* Calculation of call weights (if not given)
++* OProfile, DynaProf
++
++Support for KCachegrind in Calltree
++-----------------------------------
++
++WISHS:
++- store more details of calltree
++ - for every function call: executed from shared lib
++ (Not needed, if function names are unique in whole app)
++ - adaptive call chain context (Really needed ? MUCH Data!)
++- dump at
++ - breakpoints
++ - watchpoints (with data tracing!)
++ - every xxx BBs (DONE)
++- dump around
++ - function invocation
++ - KAction event
++ - DCOP event
++
++- data accesses from (instr address/count)
++ stack: -> (function, stackframe-offset)
++ dynamic: -> (mem region start, [type], offset)
++ type can be get when a constructor is called for region
++ static: -> (mem region start, type, offset)
++
++* Generate full instr/data access trace for offline analysis.
++
++* Appending mode
++
++
++
+diff --git a/kdecachegrind/configure.in.in b/kdecachegrind/configure.in.in
+new file mode 100644
+index 0000000..dfc8508
+--- /dev/null
++++ b/kdecachegrind/configure.in.in
+@@ -0,0 +1,8 @@
++KCACHEGRIND_VERSION=0.4.6kde
++AC_SUBST(KCACHEGRIND_VERSION)
++
++AC_FUNC_MMAP
++
++dnl AC_OUTPUT( kdecachegrind/version.h )
++dnl AC_OUTPUT( kdecachegrind/kdecachegrind.spec )
++dnl AC_OUTPUT( kdecachegrind/kdecachegrind.lsm )
+diff --git a/kdecachegrind/converters/Makefile.am b/kdecachegrind/converters/Makefile.am
+new file mode 100644
+index 0000000..08b3696
+--- /dev/null
++++ b/kdecachegrind/converters/Makefile.am
+@@ -0,0 +1,2 @@
++bin_SCRIPTS = hotshot2calltree op2calltree pprof2calltree dprof2calltree \
++ memprof2calltree
+diff --git a/kdecachegrind/converters/README b/kdecachegrind/converters/README
+new file mode 100644
+index 0000000..c27d3c6
+--- /dev/null
++++ b/kdecachegrind/converters/README
+@@ -0,0 +1,24 @@
++This directory contains some scripts to convert output of different
++profiling tools into the format which can be loaded by KCachegrind.
++See the comment at start of every script for details.
++
++In the long run, these should be replaced by import filters in
++KCachegrind directly, but I can't promise anything. Partly, this
++is because some scripts are provided as contribution from others.
++
++hotshot2calltree Converter from Python Hotshot Profiler.
++op2calltree Converter from OProfile sampling data.
++dprof2calltree Converter from PERL::DProf Profiler.
++pprof2calltree Converter from APD PHP Profiler.
++
++Thanks go to
++* George Schlossnagle <george@omniti.com> for
++ dprof2calltree and pprof2calltree,
++* Jörg Beyer <job@webde-ag.de> for
++ hotshot2calltree
++
++If you want to write a converter, have a look at the calltree format
++description on the web site (kdecachegrind.sf.net).
++
++Josef
++
+diff --git a/kdecachegrind/converters/dprof2calltree b/kdecachegrind/converters/dprof2calltree
+new file mode 100644
+index 0000000..f276e18
+--- /dev/null
++++ b/kdecachegrind/converters/dprof2calltree
+@@ -0,0 +1,199 @@
++#!/usr/bin/perl
++#
++# Redistribution and use in source and binary forms, with or without
++# modification, are permitted provided that the following conditions are met:
++#
++# - Redistributions of source code must retain the above copyright notice,
++# this list of conditions and the following disclaimer.
++#
++# - 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.
++#
++# - All advertising materials mentioning features or use of this software
++# must display the following acknowledgement: This product includes software
++# developed by OmniTI Computer Consulting.
++#
++# - Neither name of the company nor the names of its contributors may be
++# used to endorse or promote products derived from this software without
++# specific prior written permission.
++#
++# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS `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 REGENTS OR CONTRIBUTORS 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.
++#
++# Copyright (c) 2004 OmniTI Computer Consulting
++# All rights reserved
++# The following code was written by George Schlossnagle <george@omniti.com>
++# and is provided completely free and without any warranty.
++#
++
++#
++# This script is designed to convert the tmon.out output emitted
++# from Perl's Devel::DProf profiling package. To use this:
++#
++# 1) Run your perl script as
++# > perl -d:DProf yoursript.pl
++# This will create a file called tmon.out. If you want to
++# inspect it on the command line, look at the man page
++# for dprofp for details.
++#
++# 2) Run
++# > dprof2calltree -f tmon.out
++# or
++# > dprof2calltree -f tmon.out -o cachegrind.out.foo
++#
++# This creates a cachegrind-style file called cachgrind.out.tmon.out or
++# cachegrind.out.foo, respecitvely.
++#
++# 3) Run kdecachegrind cachegrind.out.foo
++#
++# 4) Enjoy!
++
++use strict;
++use Config;
++use Getopt::Std;
++use IO::File;
++
++my @callstack;
++my %function_info;
++my $tree = {};
++my $total_cost = 0;
++my %opts;
++
++getopt('f:o:', \%opts);
++
++my $infd;
++usage() unless ($opts{'f'} && ($infd = IO::File->new($opts{'f'}, "r")));
++
++my $outfd;
++my $outfile = $opts{'o'};
++unless($outfile) {
++ $opts{'f'} =~ m!([^/]+)$!;
++ $outfile = "cachegrind.out.$1";
++}
++$outfd = new IO::File $outfile, "w";
++usage() unless defined $outfd;
++
++while(<$infd>) {
++ last if /^PART2/;
++}
++while(<$infd>) {
++ chomp;
++ my @args = split;
++ if($args[0] eq '@') {
++ # record timing event
++ my $call_element = pop @callstack;
++ if($call_element) {
++ $call_element->{'cost'} += $args[3];
++ $call_element->{'cumm_cost'} += $args[3];
++ $total_cost += $args[3];
++ push @callstack, $call_element;
++ }
++ }
++ elsif($args[0] eq '&') {
++ # declare function
++ $function_info{$args[1]}->{'package'} = $args[2];
++ if($args[2] ne 'main') {
++ $function_info{$args[1]}->{'name'} = $args[2]."::".$args[3];
++ } else {
++ $function_info{$args[1]}->{'name'} = $args[3];
++ }
++ }
++ elsif($args[0] eq '+') {
++ # push myself onto the stack
++ my $call_element = { 'specifier' => $args[1], 'cost' => 0 };
++ push @callstack, $call_element;
++ }
++ elsif($args[0] eq '-') {
++ my $called = pop @callstack;
++ my $called_id = $called->{'specifier'};
++ my $caller = pop @callstack;
++ if (exists $tree->{$called_id}) {
++ $tree->{$called_id}->{'cost'} += $called->{'cost'};
++ }
++ else {
++ $tree->{$called_id} = $called;
++ }
++ if($caller) {
++ $caller->{'child_calls'}++;
++ my $caller_id = $caller->{'specifier'};
++ if(! exists $tree->{$caller_id} ) {
++ $tree->{$caller_id} = { 'specifier' => $caller_id, 'cost' => 0 };
++# $tree->{$caller_id} = $caller;
++ }
++ $caller->{'cumm_cost'} += $called->{'cumm_cost'};
++ $tree->{$caller_id}->{'called_funcs'}->[$tree->{$caller_id}->{'call_counter'}++]->{$called_id} += $called->{'cumm_cost'};
++ push @callstack, $caller;
++ }
++ }
++ elsif($args[0] eq '*') {
++ # goto &func
++ # replace last caller with self
++ my $call_element = pop @callstack;
++ $call_element->{'specifier'} = $args[1];
++ push @callstack, $call_element;
++ }
++ else {print STDERR "Unexpected line: $_\n";}
++}
++
++#
++# Generate output
++#
++my $output = '';
++$output .= "events: Tick\n";
++$output .= "summary: $total_cost\n";
++$output .= "cmd: your script\n\n";
++foreach my $specifier ( keys %$tree ) {
++ my $caller_package = $function_info{$specifier}->{'package'} || '???';
++ my $caller_name = $function_info{$specifier}->{'name'} || '???';
++ my $include = find_include($caller_package);
++ $output .= "ob=\n";
++ $output .= sprintf "fl=%s\n", find_include($caller_package);
++ $output .= sprintf "fn=%s\n", $caller_name;
++ $output .= sprintf "1 %d\n", $tree->{$specifier}->{'cost'};
++ if(exists $tree->{$specifier}->{'called_funcs'}) {
++ foreach my $items (@{$tree->{$specifier}->{'called_funcs'}}) {
++ while(my ($child_specifier, $costs) = each %$items) {
++ $output .= sprintf "cfn=%s\n", $function_info{$child_specifier}->{'name'};
++ $output .= sprintf "cfi=%s\n", find_include($function_info{$child_specifier}->{'package'});
++ $output .= "calls=1\n";
++ $output .= sprintf "1 %d\n", $costs;
++ }
++ }
++ }
++ $output .= "\n";
++}
++print STDERR "Writing kdecachegrind output to $outfile\n";
++$outfd->print($output);
++
++
++
++sub find_include {
++ my $module = shift;
++ $module =~ s!::!/!g;
++ for (@INC) {
++ if ( -f "$_/$module.pm" ) {
++ return "$_/$module.pm";
++ }
++ if ( -f "$_/$module.so" ) {
++ return "$_/$module.so";
++ }
++ }
++ return "???";
++}
++
++sub usage() {
++ print STDERR "dprof2calltree -f <tmon.out> [-o outfile]\n";
++ exit -1;
++}
++
++
++# vim: set sts=2 ts=2 bs ai expandtab :
+diff --git a/kdecachegrind/converters/hotshot2calltree b/kdecachegrind/converters/hotshot2calltree
+new file mode 100644
+index 0000000..f62a46e
+--- /dev/null
++++ b/kdecachegrind/converters/hotshot2calltree
+@@ -0,0 +1,394 @@
++#!/usr/bin/env python
++# _*_ coding: latin1 _*_
++
++#
++# Copyright (c) 2003 by WEB.DE, Karlsruhe
++# Autor: Jörg Beyer <job@webde-ag.de>
++#
++# hotshot2cachegrind is free software; you can redistribute it and/or
++# modify it under the terms of the GNU General Public
++# License as published by the Free Software Foundation, version 2.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++# General Public License for more details.
++
++# You should have received a copy of the GNU General Public License
++# along with this program; see the file COPYING. If not, write to
++# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++# Boston, MA 02110-1301, USA.
++#
++#
++# This script transforms the pstat output of the hotshot
++# python profiler into the input of kdecachegrind.
++#
++# example usage:
++# modify you python script to run this code:
++#
++# import hotshot
++# filename = "pythongrind.prof"
++# prof = hotshot.Profile(filename, lineevents=1)
++# prof.runcall(run) # assuming that "run" should be called.
++# prof.close()
++#
++# it will run the "run"-method under profiling and write
++# the results in a file, called "pythongrind.prof".
++#
++# then call this script:
++# hotshot2cachegrind -o <output> <input>
++# or here:
++# hotshot2cachegrind cachegrind.out.0 pythongrind.prof
++#
++# then call kdecachegrind:
++# kdecachegrind cachegrind.out.0
++#
++# TODO:
++# * es gibt Probleme mit rekursiven (direkt und indirekt) Aufrufen - dann
++# stimmen die Kosten nicht.
++#
++# * einige Funktionen werden mit "?" als Name angezeigt. Evtl sind
++# das nur die C/C++ extensions.
++#
++# * es fehlt noch ein Funktionsnamen Mangling, dass die Filenamen berücksichtigt,
++# zZ sind alle __init__'s und alle run's schwer unterscheidbar :-(
++#
++version = "$Revision$"
++progname = "hotshot2cachegrind"
++
++import os, sys
++from hotshot import stats,log
++import os.path
++
++file_limit=0
++
++what2text = {
++ log.WHAT_ADD_INFO : "ADD_INFO",
++ log.WHAT_DEFINE_FUNC : "DEFINE_FUNC",
++ log.WHAT_DEFINE_FILE : "DEFINE_FILE",
++ log.WHAT_LINENO : "LINENO",
++ log.WHAT_EXIT : "EXIT",
++ log.WHAT_ENTER : "ENTER"}
++
++# a pseudo caller on the caller stack. This represents
++# the Python interpreter that executes the given python
++# code.
++root_caller = ("PythonInterpreter",0,"execute")
++
++class CallStack:
++ """A tiny Stack implementation, based on python lists"""
++ def __init__(self):
++ self.stack = []
++ self.recursion_counter = {}
++ def push(self, elem):
++ """put something on the stack"""
++ self.stack.append(elem)
++ rc = self.recursion_counter.get(elem, 0)
++ self.recursion_counter[elem] = rc + 1
++
++ def pop(self):
++ """get the head element of the stack and remove it from teh stack"""
++ elem = self.stack[-1:][0]
++ rc = self.recursion_counter.get(elem) - 1
++ if rc>0:
++ self.recursion_counter[elem] = rc
++ else:
++ del self.recursion_counter[elem]
++ return self.stack.pop()
++
++ def top(self):
++ """get the head element of the stack, stack is unchanged."""
++ return self.stack[-1:][0]
++ def handleLineCost(self, tdelta):
++ p, c = self.stack.pop()
++ self.stack.append( (p,c + tdelta) )
++ def size(self):
++ """ return how many elements the stack has"""
++ return len(self.stack)
++
++ def __str__(self):
++ return "[stack: %s]" % self.stack
++
++ def recursion(self, pos):
++ return self.recursion_counter.get(pos, 0)
++ #return self.recursion_dict.has_key((entry[0][0], entry[0][2]))
++
++def return_from_call(caller_stack, call_dict, cost_now):
++ """return from a function call
++ remove the function from the caller stack,
++ add the costs to the calling function.
++ """
++ called, cost_at_enter = caller_stack.pop()
++ caller, caller_cost = caller_stack.top()
++
++ #print "return_from_call: %s ruft %s" % (caller, called,)
++
++ per_file_dict = call_dict.get(called[0], {})
++ per_caller_dict = per_file_dict.get(called[2], {})
++ cost_so_far, call_counter = per_caller_dict.get(caller, (0, 0))
++
++ if caller_stack.recursion(called):
++ per_caller_dict[caller] = (cost_so_far, call_counter + 1)
++ else:
++ per_caller_dict[caller] = (cost_so_far + cost_now - cost_at_enter, call_counter + 1)
++
++ per_file_dict[called[2]] = per_caller_dict
++ call_dict[called[0]] = per_file_dict
++
++
++def updateStatus(filecount):
++ sys.stdout.write("reading File #%d \r" % filecount)
++ sys.stdout.flush()
++def convertProfFiles(output, inputfilenames):
++ """convert all the given input files into one kdecachegrind
++ input file.
++ """
++ call_dict = {}
++ cost_per_pos = {}
++ cost_per_function = {}
++ caller_stack = CallStack()
++ caller_stack.push((root_caller, 0))
++
++ total_cost = 0
++ filecount = 1
++ number_of_files = len(inputfilenames)
++ for inputfilename in inputfilenames:
++ updateStatus(filecount)
++ cost, filecount = convertHandleFilename(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount)
++ total_cost += cost
++ if (file_limit > 0) and (filecount > file_limit):
++ break
++
++ print
++ print "total_cost: % d Ticks",total_cost
++ dumpResults(output, call_dict, total_cost, cost_per_pos, cost_per_function)
++
++def convertHandleFilename(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount):
++ updateStatus(filecount)
++ if not ((file_limit > 0) and (filecount > file_limit)):
++ if os.path.isdir(inputfilename):
++ cost, filecount = convertProfDir(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount)
++ elif os.path.isfile(inputfilename):
++ cost = convertProfFile(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function)
++ filecount += 1
++ else:
++ sys.stderr.write("warn: ignoring '%s', is no file and no directory\n" % inputfilename)
++ cost = 0
++ return (cost, filecount)
++
++def convertProfDir(start, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount):
++ cost = 0
++ filenames = os.listdir(start)
++ for f in filenames:
++ if (file_limit > 0) and (filecount > file_limit):
++ break
++ full = os.path.join(start, f)
++ c, filecount = convertHandleFilename(full, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount)
++ cost += c;
++ return (cost, filecount)
++
++def handleCostPerPos(cost_per_pos, pos, current_cost):
++ """
++ the cost per source position are managed in a dict in a dict.
++
++ the cost are handled per file and there per function.
++ so, the per-file-dict contains some per-function-dicts
++ which sum up the cost per line (in this function and in
++ this file).
++ """
++ filename = pos[0]
++ lineno = pos[1]
++ funcname = pos[2]
++ file_dict = cost_per_pos.get(filename, {})
++ func_dict = file_dict.get(funcname, {})
++ func_dict.setdefault(lineno, 0)
++ func_dict[lineno] += current_cost
++ file_dict[funcname] = func_dict
++ cost_per_pos[filename] = file_dict
++
++def convertProfFile(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function):
++ """convert a single input file into one kdecachegrind
++ data.
++
++ this is the most expensive function in this python source :-)
++ """
++
++ total_cost = 0
++ try:
++ logreader = log.LogReader(inputfilename)
++ current_cost = 0
++ hc = handleCostPerPos # shortcut
++ for item in logreader:
++ what, pos ,tdelta = item
++ (file, lineno, func) = pos
++ #line = "%s %s %d %s %d" % (what2text[what], file, lineno, func, tdelta)
++ #print line
++ # most common cases first
++ if what == log.WHAT_LINENO:
++ # add the current cost to the current function
++ hc(cost_per_pos, pos, tdelta)
++ total_cost += tdelta
++ elif what == log.WHAT_ENTER:
++ caller_stack.push((pos, total_cost))
++ hc(cost_per_pos, pos, tdelta)
++ total_cost += tdelta
++ elif what == log.WHAT_EXIT:
++ hc(cost_per_pos, pos, tdelta)
++ total_cost += tdelta
++ return_from_call(caller_stack, call_dict, total_cost)
++ else:
++ assert 0, "duh: %d" % what
++
++
++ # I have no idea, why sometimes the stack is not empty - we
++ # have to rewind the stack to get 100% for the root_caller
++ while caller_stack.size() > 1:
++ return_from_call(caller_stack, call_dict, total_cost)
++
++ except IOError:
++ print "could not open inputfile '%s', ignore this." % inputfilename
++ except EOFError, m:
++ print "EOF: %s" % (m,)
++ return total_cost
++
++def pretty_name(file, function):
++ #pfile = os.path.splitext(os.path.basename(file)) [0]
++ #return "%s_[%s]" % (function, file)
++ return "%s" % function
++ #return "%s::%s" % (file, function)
++ #return "%s_%s" % (pfile, function)
++
++class TagWriter:
++ def __init__(self, output):
++ self.output = output
++ self.last_values = {}
++
++ def clearTag(self, tag):
++ if self.last_values.has_key(tag):
++ del self.last_values[ tag ]
++ def clear(self):
++ self.last_values = {}
++
++ def write(self, tag, value):
++ self.output.write("%s=%s\n" % (tag, value))
++ #if (not self.last_values.has_key(tag)) or self.last_values[tag] != value:
++ # self.last_values[ tag ] = value
++ # self.output.write("%s=%s\n" % (tag, value))
++
++def dumpResults(output, call_dict, total_cost, cost_per_pos, cost_per_function):
++ """write the collected results in the format kdecachegrind
++ could read.
++ """
++ # the intro
++ output.write("events: Tick\n")
++ output.write("summary: %d\n" % total_cost)
++ output.write("cmd: your python script\n")
++ output.write("\n")
++ tagwriter = TagWriter(output)
++
++ # now the costs per line
++ for file in cost_per_pos.keys():
++ func_dict = cost_per_pos[file]
++ for func in func_dict.keys():
++ line_dict = func_dict[func]
++ tagwriter.write("ob", file)
++ tagwriter.write("fn", func)# pretty_name(file, func)) ; output.write("# ^--- 2\n")
++ tagwriter.write("fl", file)
++ for line in line_dict:
++ output.write("%d %d\n" %( line, line_dict[line] ))
++
++ output.write("\n\n")
++ # now the function calls. For each caller all the called
++ # functions and their costs are written.
++ for file in call_dict.keys():
++ per_file_dict = call_dict[file]
++ #print "file %s -> %s" % (file, per_file_dict)
++ for called_x in per_file_dict.keys():
++ #print "called_x:",called_x
++ per_caller_dict = per_file_dict[called_x]
++ #print "called_x %s wird gerufen von: %s" % (called_x, per_caller_dict)
++ for caller_x in per_caller_dict.keys():
++ tagwriter.write("ob", caller_x[0])
++ tagwriter.write("fn", caller_x[2])# pretty_name(caller_x[2], caller_x[0])) ; output.write("# ^--- 1\n")
++ tagwriter.write("fl", caller_x[0])
++ tagwriter.write("cob", file)
++ tagwriter.write("cfn", called_x) #pretty_name(file, called_x))
++ tagwriter.write("cfl", file)
++ cost, count = per_caller_dict[caller_x]
++ #print "called_x:",called_x
++ output.write("calls=%d\n%d %d\n" % (count, caller_x[1], cost))
++ tagwriter.clear()
++ #tagwriter.clearTag("cob")
++ # is it a bug in kdecachegrind, that the "cob=xxx" line has
++ # to be rewritten after a calls entry with costline ?
++ #assert cost <= total_cost, "caller_x: %s, per_caller_dict: %s " % (caller_x, per_caller_dict, )
++ #output.write("calls=%d\n%d %d\n" % (count, caller_x[1], cost))
++ output.write("\n")
++
++def run_without_optparse():
++ """parse the options without optparse, use sys.argv"""
++ if len(sys.argv) < 4 or sys.argv[1] != "-o" :
++ print "usage: hotshot2cachegrind -o outputfile in1 [in2 [in3 [...]]]"
++ return
++ outputfilename = sys.argv[2]
++ try:
++ output = file(outputfilename, "w")
++ args = sys.argv[3:]
++ convertProfFiles(output, args)
++ output.close()
++ except IOError:
++ print "could not open '%s' for writing." % outputfilename
++
++def run_with_optparse():
++ """parse the options with optparse"""
++
++ global file_limit
++
++ versiontext = "%s version: %s" % ( progname, version.split()[1], )
++ parser = OptionParser(version=versiontext)
++ parser.add_option("-o", "--output",
++ action="store", type="string", dest="outputfilename",
++ help="write output into FILE")
++ parser.add_option("--file-limit",
++ action="store", dest="file_limit", default=0,
++ help="stop after given number of input files")
++ output = sys.stdout
++ close_output = 0
++ (options, args) = parser.parse_args()
++ file_limit = int(options.file_limit)
++ try:
++ if options.outputfilename and options.outputfilename != "-":
++ output = file(options.outputfilename, "w")
++ close_output = 1
++ except IOError:
++ print "could not open '%s' for writing." % options.outputfilename
++ if output:
++ convertProfFiles(output, args)
++ if close_output:
++ output.close()
++
++
++def profile_myself():
++ import hotshot
++ filename = "self.prof"
++ if not os.path.exists(filename):
++ prof = hotshot.Profile(filename, lineevents=1)
++ prof.runcall(run)
++ prof.close()
++ else:
++ print "not profiling myself, since '%s' exists, running normal" % filename
++ run()
++
++# check if optparse is available.
++try:
++ from optparse import OptionParser
++ run = run_with_optparse
++except ImportError:
++ run = run_without_optparse
++
++if __name__ == "__main__":
++ try:
++ run()
++ #profile_myself()
++ except KeyboardInterrupt:
++ sys.exit(1)
+diff --git a/kdecachegrind/converters/memprof2calltree b/kdecachegrind/converters/memprof2calltree
+new file mode 100755
+index 0000000..e82d6e8
+--- /dev/null
++++ b/kdecachegrind/converters/memprof2calltree
+@@ -0,0 +1,38 @@
++#!/usr/bin/perl
++#
++# Convert the memory profiles of memprof to calltree format,
++# loadable with KCachegrind
++#
++# (C) 2004, Josef Weidendorfer
++
++print "events: Allocated\n";
++
++while(<>) {
++ if (/^(\S.*)$/) {
++ $next = 0;
++ print "\nfn=$1\n";
++ next;
++ }
++ if (/^ children:/) {
++ $next = 1; #children
++ next;
++ }
++ if (/^ inherited:/) {
++ $next = 2; #inherited
++ next;
++ }
++ if (/^ total:/) {
++ # ignore, is calculated
++ next;
++ }
++ if (/^ self:\s*(\d+)/) {
++ if ($1 ne "0") {
++ print "0 $1\n";
++ }
++ next;
++ }
++ if (/^\s+(\S.*?):\s*(\d+)$/) {
++ if ($next < 2) { next; }
++ print "cfn=$1\ncalls=0 0\n0 $2\n";
++ }
++}
+diff --git a/kdecachegrind/converters/op2calltree b/kdecachegrind/converters/op2calltree
+new file mode 100755
+index 0000000..ca121a2
+--- /dev/null
++++ b/kdecachegrind/converters/op2calltree
+@@ -0,0 +1,238 @@
++#!/usr/bin/perl
++#
++# Copyright (c) 2004
++# Author: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++#
++# op2calltree is free software; you can redistribute it and/or
++# modify it under the terms of the GNU General Public
++# License as published by the Free Software Foundation, version 2.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++# General Public License for more details.
++
++# You should have received a copy of the GNU General Public License
++# along with this program; see the file COPYING. If not, write to
++# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++# Boston, MA 02110-1301, USA.
++#
++#
++# Converter from OProfile's output of "opreport -gdf" (v 0.8)
++# into callgrind format.
++#
++# Generate a OProfile report with opreport and flags -gdf
++# and pipe this as standard input into this script.
++# This will generate separate cachegrind files for every application.
++#
++
++
++# parse symbol line. example (with 1 event type, $has_image==0):
++# 308 0.1491 /path/source.c:6 /path/app main
++sub parseSymSpec {
++ $e = 0;
++ while($e < $eventCount) {
++ ($line) = ($line =~ /\d+\s+\S+\s+(.*)/);
++ $e++;
++ }
++ if ($line =~ s/^\(no location information\)\s+//) {
++ $file = "???";
++ $linenr = 0;
++ }
++ else {
++ ($file,$linenr) = ($line =~ s/(\S+?):(\d+)\s+//);
++ }
++ if ($has_image) {
++ if ($line =~ s/^(\S+)\s+//) { $img = $1; }
++ }
++ if ($has_app) {
++ if ($line =~ s/^(\S+)\s+//) { $app = $1; }
++ if (!$has_image) { $img = $app; }
++ }
++ $sym = $line;
++
++ $app =~ s/^.*\///;
++ if ($sym eq "(no symbols)") { $sym = "???"; }
++ $file{$sym} = $file;
++ $linenr{$sym} = $linenr;
++ $app{$sym} = $app;
++ $img{$app,$sym} = $img;
++ $syms{$app}++;
++
++ if ($app ne $oldApp) {
++ $oldApp = $app;
++ print "\n\nApp $app\n";
++ }
++ print " Symbol $sym (Image $img)\n";
++}
++
++
++
++$eventCount = 0;
++$descCount = 0;
++$lnr = 0;
++$has_image = 0;
++$has_app = 0;
++$app = "unnamed";
++$img = "???";
++
++# first loop till first symbol specification
++while(<>) {
++ $lnr++;
++ chomp;
++ if (/^CPU:/) {
++ $desc[$descCount++] = $_;
++ next;
++ }
++ if (/^Counted\s*(\S+)/) {
++ $desc[$descCount++] = $_;
++ $eventCount++;
++ $events[$eventCount] = $1;
++ next;
++ }
++ if (/^(Profiling through timer.*)/) {
++ $desc[$descCount++] = $_;
++ $eventCount++;
++ $events[$eventCount] = "Timer";
++ next;
++ }
++ if (/^vma/) {
++ # title row: adapt to separation options of OProfile
++ if (/image/) { $has_image = 1; }
++ if (/app/) { $has_app = 1; }
++ next;
++ }
++ if (/^([0-9a-fA-F]+)\s*(.*)$/) {
++ $vmaSym = $1;
++ $line = $2;
++ last;
++ }
++}
++
++if ($eventCount == 0) {
++ die "No Events found";
++}
++
++print "Description:\n";
++foreach $d (@desc) { print " $d\n"; }
++print "\n";
++
++print "Events:";
++foreach $e (@events) { print " $e"; }
++print "\n";
++
++parseSymSpec;
++
++while(<>) {
++ $lnr++;
++ if (/^([0-9a-fA-F]+)\s*(.*)$/) {
++ $vmaSym = $1;
++ $line = $2;
++
++ parseSymSpec;
++ next;
++ }
++ if (/^\s+([0-9a-fA-F]+)\s*(.*)$/) {
++
++ $sampleCount{$app,$sym}++;
++ $sc = $sampleCount{$app,$sym};
++
++ $vma{$app,$sym,$sc} = $1;
++ $line = $2;
++
++ $e = 1;
++ while($e <= $eventCount) {
++ ($cost, $line) = ($line =~ /(\d+)\s+\S+\s+(.*)/);
++ $summary{$app,$e} += $cost;
++ $cost{"$app,$sym,$sc,$e"} = $cost;
++ $e++;
++ }
++ if ($line =~ /\(no location information\)/) {
++ $file = "???";
++ $linenr = 0;
++ }
++ else {
++ ($file,$linenr) = ($line =~ /(\S+?):(\d+)/);
++ }
++ $sFile{$app,$sym,$sc} = $file;
++ $linenr{$app,$sym,$sc} = $linenr;
++
++ $file =~ s/^.*\///;
++ print " Sample $sc: $vma{$app,$sym,$sc} ($file:$linenr):";
++ foreach $e (1 .. $eventCount) { $c = $cost{"$app,$sym,$sc,$e"} ; print " $c"; }
++ print "\n";
++ next;
++ }
++ die "ERROR: Reading line $lnr '$_'\n";
++}
++
++foreach $app (keys %syms) {
++ if ($app eq "") { next; }
++ print "Generating dump for App '$app'...\n";
++
++ $out = "# Generated by op2cg, using OProfile with opreport -gdf\n";
++ $out .= "positions: instr line\n";
++
++ $out .= "events:";
++ foreach $e (@events) { $out .= " $e"; }
++ $out .= "\n";
++
++ $out .= "summary:";
++ foreach $e (1 .. $eventCount) { $out .= " $summary{$app,$e}"; }
++ $out .= "\n\n";
++
++ %fileNum = ();
++ $fileNum = 1;
++ $sf = "";
++
++ $img = "";
++
++ foreach $sym (keys %file) {
++ if ($sampleCount{$app,$sym} eq "") { next; }
++
++ if ($img{$app,$sym} ne $img) {
++ $img = $img{$app,$sym};
++ $out .= "ob=$img\n";
++ }
++
++ $file = $file{$sym};
++ if ($sf ne $file) {
++ if ($fileNum{$file} eq "") {
++ $fileNum{$file} = $fileNum;
++ $out .= "fl=($fileNum) $file\n";
++ $fileNum++;
++ }
++ else {
++ $out .= "fl=($fileNum{$file})\n";
++ }
++ $sf = $file;
++ }
++
++ $out .= "fn=$sym\n";
++ foreach $sc (1 .. $sampleCount{$app,$sym}) {
++ if ($sf ne $sFile{$app,$sym,$sc}) {
++ $sf = $sFile{$app,$sym,$sc};
++ if ($sf eq $file) {
++ $out .= "fe=($fileNum{$file})\n";
++ }
++ else {
++ if ($fileNum{$sf} eq "") {
++ $fileNum{$sf} = $fileNum;
++ $out .= "fi=($fileNum) $sf\n";
++ $fileNum++;
++ }
++ else {
++ $out .= "fi=($fileNum{$sf})\n";
++ }
++ }
++ }
++ $out .= "0x$vma{$app,$sym,$sc} $linenr{$app,$sym,$sc}";
++ foreach $e (1 .. $eventCount) { $c = $cost{"$app,$sym,$sc,$e"} ; $out .= " $c"; }
++ $out .= "\n";
++ }
++ }
++
++ open OUT, ">oprof.out.$app";
++ print OUT $out;
++ close OUT;
++}
+diff --git a/kdecachegrind/converters/pprof2calltree b/kdecachegrind/converters/pprof2calltree
+new file mode 100644
+index 0000000..0e70e1c
+--- /dev/null
++++ b/kdecachegrind/converters/pprof2calltree
+@@ -0,0 +1,218 @@
++#!/usr/bin/env php
++# Redistribution and use in source and binary forms, with or without
++# modification, are permitted provided that the following conditions are met:
++#
++# - Redistributions of source code must retain the above copyright notice,
++# this list of conditions and the following disclaimer.
++#
++# - 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.
++#
++# - All advertising materials mentioning features or use of this software
++# must display the following acknowledgement: This product includes software
++# developed by OmniTI Computer Consulting.
++#
++# - Neither name of the company nor the names of its contributors may be
++# used to endorse or promote products derived from this software without
++# specific prior written permission.
++#
++# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS `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 REGENTS OR CONTRIBUTORS 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.
++#
++# Copyright (c) 2004 OmniTI Computer Consulting
++# All rights reserved
++# The following code was written by George Schlossnagle <george@omniti.com>
++# and is provided completely free and without any warranty.
++#
++# This script is designed to convert the pprof output from
++# APD (http://pecl.php.net/apd/) to one readable by kdecachegrind. To use
++# this script:
++#
++# 1) Install APD.
++# 2) Profile your script with APD accordingto the directions in it's
++# README file.
++# 3) Take the pprof trace file for your script (pprof.XXXXX.Y) and run it
++# through this script as follows:
++# > pprof2calltree -f pprof.12345.1
++# This creates a new file cachegrind.out.12345.1
++# 4) View your trace with pprof2calltree cachegrind.out.12345.1
++
++<?php
++
++require "Console/Getopt.php";
++
++$con = new Console_Getopt;
++$args = $con->readPHPArgv();
++array_shift($args);
++$shortoptions = 'f:';
++$retval = $con->getopt( $args, $shortoptions);
++if(is_object($retval)) {
++ usage();
++}
++foreach ($retval[0] as $kv_array) {
++ $opt[$kv_array[0]] = $kv_array[1];
++}
++if(!$opt['f']) {
++ usage();
++}
++if(!file_exists($opt['f'])) {
++ print "Trace file ${opt['f']} does not exist\n";
++ exit;
++}
++$IN = fopen($opt['f'], "r");
++if(!$IN) {
++ print "Trace file ${opt['f']} could not be opened\n";
++ exit;
++}
++
++$path_parts = pathinfo($opt['f']);
++$outfile = "cachegrind.out.".$path_parts['basename'];
++$OUT = fopen($outfile, "w");
++if(!$OUT) {
++ print "Destination file $outfile could not be opened.\n";
++ exit;
++}
++
++while(($line = fgets($IN)) !== false) {
++ $line = rtrim($line);
++ if($line == "END_HEADER") {
++ break;
++ }
++}
++$tree = array();
++$callstack = array();
++while(($line = fgets($IN)) !== false) {
++ $line = rtrim($line);
++ $args = explode(" ", $line);
++ if($args[0] == '!') {
++ $file_lookup[$args[1]] = $args[2];
++ }
++ else if($args[0] == '&') {
++ $function_lookup[$args[1]] = $args[2];
++ $function_type[$args[1]] = ($args[3] == 2)?"USER":"INTERNAL";
++ }
++ else if($args[0] == '+') {
++ $val = array(function_id => $args[1],
++ file_id => $args[2],
++ line => $args[3],
++ cost => 0);
++ array_push($callstack, $val);
++ }
++ else if($args[0] == '-') {
++ // retrieve $called to discard
++ $called = array_pop($callstack);
++ // retrieve $caller for reference
++ $caller = array_pop($callstack);
++ $called_id = $called['function_id'];
++
++ // Set meta data if not already set'
++ if(!array_key_exists($called_id, $tree)) {
++ $tree[$called_id] = $called;
++ // initialize these to 0
++ $tree[$called_id]['cost_per_line'] = array();
++ }
++ if($caller !== null) {
++ $caller['child_calls']++;
++ $caller_id = $caller['function_id'];
++ if(!array_key_exists($caller_id, $tree)) {
++ $tree[$caller_id] = $caller;
++ }
++ $caller['cost'] += $called['cost'];
++ $tree[$caller_id]['called_funcs'][$tree[$caller_id]['call_counter']++][$called_id][$called['file_id']][$called['line']] += $called['cost'];
++ array_push($callstack, $caller);
++ }
++ if(is_array($called['cost_per_line'])) {
++ foreach($called[cost_per_line] as $file => $lines) {
++ foreach($lines as $line => $cost) {
++ $tree[$called_id]['cost_per_line'][$file][$line] += $cost;
++ }
++ }
++ }
++ }
++ else if($args[0] == '@') {
++ $called = array_pop($callstack);
++ switch(count($args)) {
++ // support new and old-style pprof data
++ case 6:
++ $file = $args[1];
++ $line = $args[2];
++ $real_tm = $args[5];
++ break;
++ case 4:
++ $file = $called['file_id'];
++ $line = $called['line'];
++ $real_tm = $args[3];
++ break;
++
++ }
++ $called['cost_per_line'][$file][$line] += $real_tm;
++ $called['cost'] += $real_tm;
++ $total_cost += $real_tm;
++ array_push($callstack, $called);
++ }
++}
++
++ob_start();
++print "events: Tick\n";
++print "summary: $total_cost\n";
++printf("cmd: %s\n", $file_lookup[1]);
++print "\n";
++
++foreach($tree as $caller => $data) {
++ $filename = $file_lookup[$data['file_id']]?$file_lookup[$data['file_id']]:"???";
++ printf("ob=%s\n", $function_type[$caller]);
++ printf("fl=%s\n", $filename);
++ printf("fn=%s\n", $function_lookup[$caller]);
++ if(is_array($data['cost_per_line'])) {
++ foreach($data['cost_per_line'] as $file => $lines) {
++ foreach($lines as $line => $cost) {
++ print "$line $cost\n";
++ }
++ }
++ }
++ else if ($data['cost']) {
++ printf("COST %s %s\n", $items['line'], $items['cost']);
++ }
++ else {
++ print_r($items);
++ }
++ if(is_array($data['called_funcs'])) {
++ foreach($data['called_funcs'] as $counter => $items) {
++ foreach($items as $called_id => $costs) {
++ if(is_array($costs)) {
++ printf("cfn=%s\n", $function_lookup[$called_id]);
++ foreach($costs as $file => $lines) {
++ printf("cfi=%s\ncalls=1\n", $file_lookup[$file]);
++ foreach($lines as $line => $cost) {
++ print "$line $cost\n";
++ }
++ }
++ }
++ }
++ }
++ }
++ print "\n";
++}
++print "\ntotals=$total_cost\n";
++$buffer = ob_get_clean();
++print "Writing kdecachegrind compatible output to $outfile\n";
++fwrite($OUT, $buffer);
++
++function usage()
++{
++ print <<<EOD
++pprof2calltree -f <tracefile>
++
++EOD;
++ exit(1);
++}
++?>
+diff --git a/kdecachegrind/pics/Makefile.am b/kdecachegrind/pics/Makefile.am
+new file mode 100644
+index 0000000..f4a3186
+--- /dev/null
++++ b/kdecachegrind/pics/Makefile.am
+@@ -0,0 +1,3 @@
++kdecachegrindicondir = $(kde_datadir)/kdecachegrind/icons
++kdecachegrindicon_ICON = AUTO
++SUBDIRS = hicolor
+diff --git a/kdecachegrind/pics/hicolor/Makefile.am b/kdecachegrind/pics/hicolor/Makefile.am
+new file mode 100644
+index 0000000..068e319
+--- /dev/null
++++ b/kdecachegrind/pics/hicolor/Makefile.am
+@@ -0,0 +1,2 @@
++kdecachegrindicondir = $(kde_datadir)/kdecachegrind/icons
++kdecachegrindicon_ICON = AUTO
+diff --git a/kdecachegrind/pics/hicolor/hi16-action-fromrec.png b/kdecachegrind/pics/hicolor/hi16-action-fromrec.png
+new file mode 100644
+index 0000000..a5cb430
+Binary files /dev/null and b/kdecachegrind/pics/hicolor/hi16-action-fromrec.png differ
+diff --git a/kdecachegrind/pics/hicolor/hi16-action-percent.png b/kdecachegrind/pics/hicolor/hi16-action-percent.png
+new file mode 100644
+index 0000000..7a4ba47
+Binary files /dev/null and b/kdecachegrind/pics/hicolor/hi16-action-percent.png differ
+diff --git a/kdecachegrind/pics/hicolor/hi16-action-recrec.png b/kdecachegrind/pics/hicolor/hi16-action-recrec.png
+new file mode 100644
+index 0000000..ec11bfa
+Binary files /dev/null and b/kdecachegrind/pics/hicolor/hi16-action-recrec.png differ
+diff --git a/kdecachegrind/pics/hicolor/hi16-action-torec.png b/kdecachegrind/pics/hicolor/hi16-action-torec.png
+new file mode 100644
+index 0000000..c092c01
+Binary files /dev/null and b/kdecachegrind/pics/hicolor/hi16-action-torec.png differ
+diff --git a/kdecachegrind/pics/hicolor/hi22-action-percent.png b/kdecachegrind/pics/hicolor/hi22-action-percent.png
+new file mode 100644
+index 0000000..c64a378
+Binary files /dev/null and b/kdecachegrind/pics/hicolor/hi22-action-percent.png differ
+diff --git a/kdecachegrind/pics/hicolor/hi32-action-percent.png b/kdecachegrind/pics/hicolor/hi32-action-percent.png
+new file mode 100644
+index 0000000..e876c30
+Binary files /dev/null and b/kdecachegrind/pics/hicolor/hi32-action-percent.png differ
+diff --git a/kdecachegrind/kdecachegrind.lsm.in b/kdecachegrind/kdecachegrind.lsm.in
+new file mode 100644
+index 0000000..fab7ced
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind.lsm.in
+@@ -0,0 +1,11 @@
++Begin3
++Title: kdecachegrind
++Version: @KCACHEGRIND_VERSION@
++Description: KDE Profiling Visualisation Tool
++Keywords: Profiling, Performance Analysis, Visualisation, Development
++Author: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++Maintained-by: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++Home-page: http://kcachegrind.sourceforge.net
++Platforms: Linux and other Unices
++Copying-policy: GNU Public License
++End
+diff --git a/kdecachegrind/kdecachegrind.spec.in b/kdecachegrind/kdecachegrind.spec.in
+new file mode 100644
+index 0000000..42b3e24
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind.spec.in
+@@ -0,0 +1,55 @@
++Summary: KDE Profiling Visualisation Tool
++Name: kdecachegrind
++Version: @KCACHEGRIND_VERSION@
++Release: 1
++Copyright: GPL
++Group: Development/Tools
++Vendor: (none)
++URL: http://kcachegrind.sourceforge.net
++Packager: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++Source: kdecachegrind-@KCACHEGRIND_VERSION@.tar.gz
++BuildRoot: /var/tmp/build
++
++%description
++KCachegrind is a GPL'd tool for quick browsing in and visualisation
++of performance data of an application run. This data is produced by
++profiling tools and typically includes distribution of cost events
++to source code ranges (instructions, source lines, functions, C++ classes)
++and call relationship of functions.
++KCachegrind has a list of functions sorted according to different cost
++types, and can provide various performance views for a function like
++direct/indirect callers/callees, TreeMap visualisation of cost distribution
++among callees, call graph sectors centered around the function and
++annotated source/assembler.
++Currently, KCachegrind depends on data delivered by the profiling tool
++calltree, powered by the Valgrind runtime instrumentation framework.
++
++%prep
++%setup
++CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" ./configure \
++ \
++ $LOCALFLAGS
++%build
++# Setup for parallel builds
++numprocs=`egrep -c ^cpu[0-9]+ /proc/stat || :`
++if [ "$numprocs" = "0" ]; then
++ numprocs=1
++fi
++
++make -j$numprocs
++
++%install
++make install-strip DESTDIR=$RPM_BUILD_ROOT
++
++cd $RPM_BUILD_ROOT
++find . -type d | sed '1,2d;s,^\.,\%attr(-\,root\,root) \%dir ,' > $RPM_BUILD_DIR/file.list.kdecachegrind
++find . -type f | sed 's,^\.,\%attr(-\,root\,root) ,' >> $RPM_BUILD_DIR/file.list.kdecachegrind
++find . -type l | sed 's,^\.,\%attr(-\,root\,root) ,' >> $RPM_BUILD_DIR/file.list.kdecachegrind
++
++%clean
++rm -rf $RPM_BUILD_ROOT/*
++rm -rf $RPM_BUILD_DIR/kdecachegrind
++rm -rf ../file.list.kdecachegrind
++
++
++%files -f ../file.list.kdecachegrind
+diff --git a/kdecachegrind/kdecachegrind/Doxyfile b/kdecachegrind/kdecachegrind/Doxyfile
+new file mode 100644
+index 0000000..9d5d050
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/Doxyfile
+@@ -0,0 +1,157 @@
++# Doxygen configuration generated by Doxywizard version 0.1
++#---------------------------------------------------------------------------
++# General configuration options
++#---------------------------------------------------------------------------
++PROJECT_NAME = kdecachegrind
++PROJECT_NUMBER =
++OUTPUT_DIRECTORY =
++OUTPUT_LANGUAGE = English
++EXTRACT_ALL = YES
++EXTRACT_PRIVATE = YES
++EXTRACT_STATIC = YES
++HIDE_UNDOC_MEMBERS =
++HIDE_UNDOC_CLASSES =
++BRIEF_MEMBER_DESC =
++REPEAT_BRIEF =
++ALWAYS_DETAILED_SEC =
++FULL_PATH_NAMES =
++STRIP_FROM_PATH =
++INTERNAL_DOCS =
++CLASS_DIAGRAMS =
++SOURCE_BROWSER =
++INLINE_SOURCES =
++STRIP_CODE_COMMENTS =
++CASE_SENSE_NAMES =
++SHORT_NAMES =
++HIDE_SCOPE_NAMES =
++VERBATIM_HEADERS =
++SHOW_INCLUDE_FILES =
++JAVADOC_AUTOBRIEF =
++INHERIT_DOCS =
++INLINE_INFO =
++SORT_MEMBER_DOCS =
++DISTRIBUTE_GROUP_DOC =
++TAB_SIZE =
++ENABLED_SECTIONS =
++GENERATE_TODOLIST =
++GENERATE_TESTLIST =
++GENERATE_BUGLIST =
++ALIASES =
++MAX_INITIALIZER_LINES =
++OPTIMIZE_OUTPUT_FOR_C =
++SHOW_USED_FILES =
++#---------------------------------------------------------------------------
++# configuration options related to warning and progress messages
++#---------------------------------------------------------------------------
++QUIET =
++WARNINGS =
++WARN_IF_UNDOCUMENTED =
++WARN_FORMAT = "$file:$line: $text"
++WARN_LOGFILE =
++#---------------------------------------------------------------------------
++# configuration options related to the input files
++#---------------------------------------------------------------------------
++INPUT = .
++FILE_PATTERNS = *.cpp \
++ *.h
++RECURSIVE = no
++EXCLUDE =
++EXCLUDE_PATTERNS =
++EXAMPLE_PATH =
++EXAMPLE_PATTERNS =
++IMAGE_PATH =
++INPUT_FILTER =
++FILTER_SOURCE_FILES =
++#---------------------------------------------------------------------------
++# configuration options related to the alphabetical class index
++#---------------------------------------------------------------------------
++ALPHABETICAL_INDEX =
++COLS_IN_ALPHA_INDEX =
++IGNORE_PREFIX =
++#---------------------------------------------------------------------------
++# configuration options related to the HTML output
++#---------------------------------------------------------------------------
++GENERATE_HTML =
++HTML_OUTPUT = html
++HTML_HEADER =
++HTML_FOOTER =
++HTML_STYLESHEET =
++HTML_ALIGN_MEMBERS =
++GENERATE_HTMLHELP =
++GENERATE_CHI =
++BINARY_TOC =
++TOC_EXPAND =
++DISABLE_INDEX =
++ENUM_VALUES_PER_LINE =
++GENERATE_TREEVIEW =
++TREEVIEW_WIDTH =
++#---------------------------------------------------------------------------
++# configuration options related to the LaTeX output
++#---------------------------------------------------------------------------
++GENERATE_LATEX = NO
++LATEX_OUTPUT = latex
++COMPACT_LATEX =
++PAPER_TYPE = a4wide
++EXTRA_PACKAGES =
++LATEX_HEADER =
++PDF_HYPERLINKS =
++USE_PDFLATEX =
++LATEX_BATCHMODE =
++#---------------------------------------------------------------------------
++# configuration options related to the RTF output
++#---------------------------------------------------------------------------
++GENERATE_RTF = NO
++RTF_OUTPUT = rtf
++COMPACT_RTF =
++RTF_HYPERLINKS =
++RTF_STYLESHEET_FILE =
++RTF_EXTENSIONS_FILE =
++#---------------------------------------------------------------------------
++# configuration options related to the man page output
++#---------------------------------------------------------------------------
++GENERATE_MAN = NO
++MAN_OUTPUT = man
++MAN_EXTENSION = .3
++MAN_LINKS =
++#---------------------------------------------------------------------------
++# Configuration options related to the preprocessor
++#---------------------------------------------------------------------------
++ENABLE_PREPROCESSING =
++MACRO_EXPANSION =
++EXPAND_ONLY_PREDEF =
++SEARCH_INCLUDES =
++INCLUDE_PATH =
++INCLUDE_FILE_PATTERNS =
++PREDEFINED =
++EXPAND_AS_DEFINED =
++#---------------------------------------------------------------------------
++# Configuration::addtions related to external references
++#---------------------------------------------------------------------------
++TAGFILES =
++GENERATE_TAGFILE =
++ALLEXTERNALS =
++PERL_PATH = /usr/bin/perl
++#---------------------------------------------------------------------------
++# Configuration options related to the dot tool
++#---------------------------------------------------------------------------
++HAVE_DOT =
++CLASS_GRAPH =
++COLLABORATION_GRAPH =
++INCLUDE_GRAPH =
++INCLUDED_BY_GRAPH =
++GRAPHICAL_HIERARCHY =
++DOT_PATH =
++MAX_DOT_GRAPH_WIDTH =
++MAX_DOT_GRAPH_HEIGHT =
++GENERATE_LEGEND =
++DOT_CLEANUP =
++#---------------------------------------------------------------------------
++# Configuration::addtions related to the search engine
++#---------------------------------------------------------------------------
++SEARCHENGINE =
++CGI_NAME = search.cgi
++CGI_URL =
++DOC_URL =
++DOC_ABSPATH =
++BIN_ABSPATH = /usr/local/bin/
++EXT_DOC_PATHS =
+diff --git a/kdecachegrind/kdecachegrind/Makefile.am b/kdecachegrind/kdecachegrind/Makefile.am
+new file mode 100644
+index 0000000..53cd35d
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/Makefile.am
+@@ -0,0 +1,62 @@
++bin_PROGRAMS = kdecachegrind
++
++kdecachegrind_SOURCES = \
++ functionselectionbase.ui \
++ stackselectionbase.ui \
++ partselectionbase.ui \
++ configdlgbase.ui \
++ loader.cpp cachegrindloader.cpp treemap.cpp pool.cpp \
++ main.cpp configuration.cpp \
++ functionselection.cpp coverage.cpp partgraph.cpp \
++ toplevel.cpp stackselection.cpp stackbrowser.cpp \
++ subcost.cpp tracedata.cpp partselection.cpp configdlg.cpp \
++ utils.cpp fixcost.cpp \
++ traceitemview.cpp instrview.cpp tabview.cpp \
++ sourceview.cpp callmapview.cpp callview.cpp \
++ coverageview.cpp costtypeview.cpp partview.cpp \
++ listutils.cpp costtypeitem.cpp multiview.cpp \
++ callitem.cpp coverageitem.cpp sourceitem.cpp \
++ costlistitem.cpp partlistitem.cpp functionitem.cpp \
++ instritem.cpp stackitem.cpp callgraphview.cpp
++
++kdecachegrind_COMPILE_FIRST = ../version.h
++
++kdecachegrind_LDADD = $(LIB_KIO)
++
++KDE_ICON = AUTO
++
++xdg_apps_DATA = kdecachegrind.desktop
++
++mimeapplicationdir = $(kde_mimedir)/application
++mimeapplication_DATA = x-kcachegrind.desktop
++
++EXTRA_DIST = \
++ kdecachegrind.desktop \
++ x-kcachegrind.desktop \
++ hi32-app-kcachegrind.png \
++ hi48-app-kcachegrind.png \
++ Doxyfile \
++ kdecachegrindui.rc
++
++# set the include path for X, qt and KDE
++INCLUDES= $(all_includes)
++
++METASOURCES = AUTO
++
++# the library search path.
++kdecachegrind_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_KDECORE) $(LIB_KDEUI) -lkdefx $(LIB_KIO) -lktexteditor
++
++rcdir = $(kde_datadir)/kdecachegrind
++rc_DATA = kdecachegrindui.rc
++
++tipdir = $(kde_datadir)/kdecachegrind
++tip_DATA = tips
++
++messages: rc.cpp
++ $(PREPARETIPS) > tips.txt
++ LIST=`find . -name \*.h -o -name \*.cpp -o -name \*.txt`; \
++ if test -n "$$LIST"; then \
++ $(XGETTEXT) $$LIST -o $(podir)/kdecachegrind.pot; \
++ fi
++ rm -f tips.txt
++
+diff --git a/kdecachegrind/kdecachegrind/cachegrindloader.cpp b/kdecachegrind/kdecachegrind/cachegrindloader.cpp
+new file mode 100644
+index 0000000..4fe57d3
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/cachegrindloader.cpp
+@@ -0,0 +1,1323 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++#include <errno.h>
++
++#include <tqfile.h>
++#include <tqcstring.h>
++
++#include <klocale.h>
++#include <kdebug.h>
++
++#include "loader.h"
++#include "tracedata.h"
++#include "utils.h"
++#include "fixcost.h"
++
++
++#define TRACE_LOADER 0
++
++/*
++ * Loader for Callgrind Profile data (format based on Cachegrind format).
++ * See Callgrind documentation for the file format.
++ */
++
++class CachegrindLoader: public Loader
++{
++public:
++ CachegrindLoader();
++
++ bool canLoadTrace(TQFile* file);
++ bool loadTrace(TracePart*);
++ bool isPartOfTrace(TQString file, TraceData*);
++
++private:
++ bool loadTraceInternal(TracePart*);
++
++ enum lineType { SelfCost, CallCost, BoringJump, CondJump };
++
++ bool parsePosition(FixString& s, PositionSpec& newPos);
++
++ // position setters
++ void clearPosition();
++ void ensureObject();
++ void ensureFile();
++ void ensureFunction();
++ void setObject(const TQString&);
++ void setCalledObject(const TQString&);
++ void setFile(const TQString&);
++ void setCalledFile(const TQString&);
++ void setFunction(const TQString&);
++ void setCalledFunction(const TQString&);
++
++ TQString _emptyString;
++
++ // current line in file to read in
++ TQString _filename;
++ int _lineNo;
++
++ TraceSubMapping* subMapping;
++ TraceData* _data;
++ TracePart* _part;
++
++ // current position
++ lineType nextLineType;
++ bool hasLineInfo, hasAddrInfo;
++ PositionSpec currentPos;
++
++ // current function/line
++ TraceObject* currentObject;
++ TracePartObject* currentPartObject;
++ TraceFile* currentFile;
++ TracePartFile* currentPartFile;
++ TraceFunction* currentFunction;
++ TracePartFunction* currentPartFunction;
++ TraceFunctionSource* currentFunctionSource;
++ TraceInstr* currentInstr;
++ TracePartInstr* currentPartInstr;
++ TraceLine* currentLine;
++ TracePartLine* currentPartLine;
++
++ // current call
++ TraceObject* currentCalledObject;
++ TracePartObject* currentCalledPartObject;
++ TraceFile* currentCalledFile;
++ TracePartFile* currentCalledPartFile;
++ TraceFunction* currentCalledFunction;
++ TracePartFunction* currentCalledPartFunction;
++ SubCost currentCallCount;
++
++ // current jump
++ TraceFile* currentJumpToFile;
++ TraceFunction* currentJumpToFunction;
++ PositionSpec targetPos;
++ SubCost jumpsFollowed, jumpsExecuted;
++
++ /** Support for compressed string format
++ * This uses the following string compression model
++ * for objects, files, functions:
++ * If the name matches
++ * "(<Integer>) Name": this is a compression specification,
++ * mapping the integer number to Name and using Name.
++ * "(<Integer>)" : this is a compression reference.
++ * Assumes previous compression specification of the
++ * integer number to a name, uses this name.
++ * "Name" : Regular name
++ */
++ void clearCompression();
++ const TQString& checkUnknown(const TQString& n);
++ TraceObject* compressedObject(const TQString& name);
++ TraceFile* compressedFile(const TQString& name);
++ TraceFunction* compressedFunction(const TQString& name,
++ TraceFile*, TraceObject*);
++
++ TQPtrVector<TraceCostItem> _objectVector, _fileVector, _functionVector;
++};
++
++
++
++/**********************************************************
++ * Loader
++ */
++
++
++CachegrindLoader::CachegrindLoader()
++ : Loader("Callgrind",
++ i18n( "Import filter for Cachegrind/Callgrind generated profile data files") )
++{
++ _emptyString = TQString("");
++}
++
++bool CachegrindLoader::canLoadTrace(TQFile* file)
++{
++ if (!file) return false;
++
++ if (!file->isOpen()) {
++ if (!file->open( IO_ReadOnly ) ) {
++ kdDebug() << TQFile::encodeName(_filename).data() << ": "
++ << strerror( errno ) << endl;
++ return false;
++ }
++ }
++
++ /*
++ * We recognize this as cachegrind/callgrind format if in the first
++ * 2047 bytes we see the string "\nevents:"
++ */
++ char buf[2048];
++ int read = file->readBlock(buf,2047);
++ if (read < 0)
++ return false;
++ buf[read] = 0;
++
++ TQCString s;
++ s.setRawData(buf, read+1);
++ int pos = s.find("events:");
++ if (pos>0 && buf[pos-1] != '\n') pos = -1;
++ s.resetRawData(buf, read+1);
++ return (pos>=0);
++}
++
++bool CachegrindLoader::loadTrace(TracePart* p)
++{
++ /* do the loading in a new object so parallel load
++ * operations do not interfere each other.
++ */
++ CachegrindLoader l;
++
++ /* emit progress signals via the singleton loader */
++ connect(&l, TQT_SIGNAL(updateStatus(TQString, int)),
++ this, TQT_SIGNAL(updateStatus(TQString, int)));
++
++ return l.loadTraceInternal(p);
++}
++
++Loader* createCachegrindLoader()
++{
++ return new CachegrindLoader();
++}
++
++
++
++/**
++ * Return false if this is no position specification
++ */
++bool CachegrindLoader::parsePosition(FixString& line,
++ PositionSpec& newPos)
++{
++ char c;
++ uint diff;
++
++ if (hasAddrInfo) {
++
++ if (!line.first(c)) return false;
++
++ if (c == '*') {
++ // nothing changed
++ line.stripFirst(c);
++ newPos.fromAddr = currentPos.fromAddr;
++ newPos.toAddr = currentPos.toAddr;
++ }
++ else if (c == '+') {
++ line.stripFirst(c);
++ line.stripUInt(diff, false);
++ newPos.fromAddr = currentPos.fromAddr + diff;
++ newPos.toAddr = newPos.fromAddr;
++ }
++ else if (c == '-') {
++ line.stripFirst(c);
++ line.stripUInt(diff, false);
++ newPos.fromAddr = currentPos.fromAddr - diff;
++ newPos.toAddr = newPos.fromAddr;
++ }
++ else if (c >= '0') {
++ uint64 v;
++ line.stripUInt64(v, false);
++ newPos.fromAddr = Addr(v);
++ newPos.toAddr = newPos.fromAddr;
++ }
++ else return false;
++
++ // Range specification
++ if (line.first(c)) {
++ if (c == '+') {
++ line.stripFirst(c);
++ line.stripUInt(diff);
++ newPos.toAddr = newPos.fromAddr + diff;
++ }
++ else if ((c == '-') || (c == ':')) {
++ line.stripFirst(c);
++ uint64 v;
++ line.stripUInt64(v);
++ newPos.toAddr = Addr(v);
++ }
++ }
++ line.stripSpaces();
++
++#if TRACE_LOADER
++ if (newPos.fromAddr == newPos.toAddr)
++ kdDebug() << " Got Addr " << newPos.fromAddr.toString() << endl;
++ else
++ kdDebug() << " Got AddrRange " << newPos.fromAddr.toString()
++ << ":" << newPos.toAddr.toString() << endl;
++#endif
++
++ }
++
++ if (hasLineInfo) {
++
++ if (!line.first(c)) return false;
++
++ if (c > '9') return false;
++ else if (c == '*') {
++ // nothing changed
++ line.stripFirst(c);
++ newPos.fromLine = currentPos.fromLine;
++ newPos.toLine = currentPos.toLine;
++ }
++ else if (c == '+') {
++ line.stripFirst(c);
++ line.stripUInt(diff, false);
++ newPos.fromLine = currentPos.fromLine + diff;
++ newPos.toLine = newPos.fromLine;
++ }
++ else if (c == '-') {
++ line.stripFirst(c);
++ line.stripUInt(diff, false);
++ if (currentPos.fromLine < diff) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Negative line number "
++ << (int)currentPos.fromLine - (int)diff << endl;
++ diff = currentPos.fromLine;
++ }
++ newPos.fromLine = currentPos.fromLine - diff;
++ newPos.toLine = newPos.fromLine;
++ }
++ else if (c >= '0') {
++ line.stripUInt(newPos.fromLine, false);
++ newPos.toLine = newPos.fromLine;
++ }
++ else return false;
++
++ // Range specification
++ if (line.first(c)) {
++ if (c == '+') {
++ line.stripFirst(c);
++ line.stripUInt(diff);
++ newPos.toLine = newPos.fromLine + diff;
++ }
++ else if ((c == '-') || (c == ':')) {
++ line.stripFirst(c);
++ line.stripUInt(newPos.toLine);
++ }
++ }
++ line.stripSpaces();
++
++#if TRACE_LOADER
++ if (newPos.fromLine == newPos.toLine)
++ kdDebug() << " Got Line " << newPos.fromLine << endl;
++ else
++ kdDebug() << " Got LineRange " << newPos.fromLine
++ << ":" << newPos.toLine << endl;
++#endif
++
++ }
++
++ return true;
++}
++
++// Support for compressed strings
++void CachegrindLoader::clearCompression()
++{
++ // this doesn't delete previous contained objects
++ _objectVector.clear();
++ _fileVector.clear();
++ _functionVector.clear();
++
++ // reset to reasonable init size. We double lengths if needed.
++ _objectVector.resize(100);
++ _fileVector.resize(1000);
++ _functionVector.resize(10000);
++}
++
++const TQString& CachegrindLoader::checkUnknown(const TQString& n)
++{
++ if (n == "???") return _emptyString;
++ return n;
++}
++
++TraceObject* CachegrindLoader::compressedObject(const TQString& name)
++{
++ if ((name[0] != '(') || !name[1].isDigit()) return _data->object(checkUnknown(name));
++
++ // compressed format using _objectVector
++ int p = name.find(')');
++ if (p<2) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Invalid compressed ELF object ('"
++ << name << "')" << endl;
++ return 0;
++ }
++ unsigned index = name.mid(1, p-1).toInt();
++ TraceObject* o = 0;
++ p++;
++ if ((int)name.length()>p) {
++ while(name.at(p).isSpace()) p++;
++
++ if (_objectVector.size() <= index) {
++ int newSize = index * 2;
++#if TRACE_LOADER
++ kdDebug() << " CachegrindLoader: objectVector enlarged to "
++ << newSize << endl;
++#endif
++ _objectVector.resize(newSize);
++ }
++
++ TQString realName = checkUnknown(name.mid(p));
++ o = (TraceObject*) _objectVector.at(index);
++ if (o && (o->name() != realName)) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Redefinition of compressed ELF object index " << index
++ << " (was '" << o->name()
++ << "') to '" << realName << "'" << endl;
++ }
++
++ o = _data->object(realName);
++ _objectVector.insert(index, o);
++ }
++ else {
++ if ((_objectVector.size() <= index) ||
++ ( (o=(TraceObject*)_objectVector.at(index)) == 0)) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Undefined compressed ELF object index " << index << endl;
++ return 0;
++ }
++ }
++
++ return o;
++}
++
++
++// Note: Callgrind sometimes gives different IDs for same file
++// (when references to same source file come from different ELF objects)
++TraceFile* CachegrindLoader::compressedFile(const TQString& name)
++{
++ if ((name[0] != '(') || !name[1].isDigit()) return _data->file(checkUnknown(name));
++
++ // compressed format using _fileVector
++ int p = name.find(')');
++ if (p<2) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Invalid compressed file ('"
++ << name << "')" << endl;
++ return 0;
++ }
++ unsigned int index = name.mid(1, p-1).toUInt();
++ TraceFile* f = 0;
++ p++;
++ if ((int)name.length()>p) {
++ while(name.at(p).isSpace()) p++;
++
++ if (_fileVector.size() <= index) {
++ int newSize = index * 2;
++#if TRACE_LOADER
++ kdDebug() << " CachegrindLoader::fileVector enlarged to "
++ << newSize << endl;
++#endif
++ _fileVector.resize(newSize);
++ }
++
++ TQString realName = checkUnknown(name.mid(p));
++ f = (TraceFile*) _fileVector.at(index);
++ if (f && (f->name() != realName)) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Redefinition of compressed file index " << index
++ << " (was '" << f->name()
++ << "') to '" << realName << "'" << endl;
++ }
++
++ f = _data->file(realName);
++ _fileVector.insert(index, f);
++ }
++ else {
++ if ((_fileVector.size() <= index) ||
++ ( (f=(TraceFile*)_fileVector.at(index)) == 0)) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Undefined compressed file index " << index << endl;
++ return 0;
++ }
++ }
++
++ return f;
++}
++
++// Note: Callgrind gives different IDs even for same function
++// when parts of the function are from different source files.
++// Thus, it is no error when multiple indexes map to same function.
++TraceFunction* CachegrindLoader::compressedFunction(const TQString& name,
++ TraceFile* file,
++ TraceObject* object)
++{
++ if ((name[0] != '(') || !name[1].isDigit())
++ return _data->function(checkUnknown(name), file, object);
++
++ // compressed format using _functionVector
++ int p = name.find(')');
++ if (p<2) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Invalid compressed function ('"
++ << name << "')" << endl;
++ return 0;
++ }
++
++
++ unsigned int index = name.mid(1, p-1).toUInt();
++ TraceFunction* f = 0;
++ p++;
++ if ((int)name.length()>p) {
++ while(name.at(p).isSpace()) p++;
++
++ if (_functionVector.size() <= index) {
++ int newSize = index * 2;
++#if TRACE_LOADER
++ kdDebug() << " CachegrindLoader::functionVector enlarged to "
++ << newSize << endl;
++#endif
++ _functionVector.resize(newSize);
++ }
++
++ TQString realName = checkUnknown(name.mid(p));
++ f = (TraceFunction*) _functionVector.at(index);
++ if (f && (f->name() != realName)) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Redefinition of compressed function index " << index
++ << " (was '" << f->name()
++ << "') to '" << realName << "'" << endl;
++ }
++
++ f = _data->function(realName, file, object);
++ _functionVector.insert(index, f);
++
++#if TRACE_LOADER
++ kdDebug() << "compressedFunction: Inserted at Index " << index
++ << "\n " << f->fullName()
++ << "\n in " << f->cls()->fullName()
++ << "\n in " << f->file()->fullName()
++ << "\n in " << f->object()->fullName() << endl;
++#endif
++ }
++ else {
++ if ((_functionVector.size() <= index) ||
++ ( (f=(TraceFunction*)_functionVector.at(index)) == 0)) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Undefined compressed function index "
++ << index << endl;
++ return 0;
++ }
++
++ // there was a check if the used function (returned from KCachegrinds
++ // model) has the same object and file as here given to us, but that was wrong:
++ // that holds only if we make this assumption on the model...
++ }
++
++ return f;
++}
++
++
++// make sure that a valid object is set, at least dummy with empty name
++void CachegrindLoader::ensureObject()
++{
++ if (currentObject) return;
++
++ currentObject = _data->object(_emptyString);
++ currentPartObject = currentObject->partObject(_part);
++}
++
++void CachegrindLoader::setObject(const TQString& name)
++{
++ currentObject = compressedObject(name);
++ if (!currentObject) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Invalid object specification, setting to unknown" << endl;
++
++ currentObject = _data->object(_emptyString);
++ }
++
++ currentPartObject = currentObject->partObject(_part);
++ currentFunction = 0;
++ currentPartFunction = 0;
++}
++
++void CachegrindLoader::setCalledObject(const TQString& name)
++{
++ currentCalledObject = compressedObject(name);
++
++ if (!currentCalledObject) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Invalid called specification, setting to unknown" << endl;
++
++ currentCalledObject = _data->object(_emptyString);
++ }
++
++ currentCalledPartObject = currentCalledObject->partObject(_part);
++}
++
++
++// make sure that a valid file is set, at least dummy with empty name
++void CachegrindLoader::ensureFile()
++{
++ if (currentFile) return;
++
++ currentFile = _data->file(_emptyString);
++ currentPartFile = currentFile->partFile(_part);
++}
++
++void CachegrindLoader::setFile(const TQString& name)
++{
++ currentFile = compressedFile(name);
++
++ if (!currentFile) {
++ kdWarning() << _filename << ":" << _lineNo
++ << " - Invalid file specification, setting to unknown" << endl;
++
++ currentFile = _data->file(_emptyString);
++ }
++
++ currentPartFile = currentFile->partFile(_part);
++ currentLine = 0;
++ currentPartLine = 0;
++}
++
++void CachegrindLoader::setCalledFile(const TQString& name)
++{
++ currentCalledFile = compressedFile(name);
++
++ if (!currentCalledFile) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Invalid called file specification, setting to unknown" << endl;
++
++ currentCalledFile = _data->file(_emptyString);
++ }
++
++ currentCalledPartFile = currentCalledFile->partFile(_part);
++}
++
++// make sure that a valid function is set, at least dummy with empty name
++void CachegrindLoader::ensureFunction()
++{
++ if (currentFunction) return;
++
++ kdWarning() << _filename << ":" << _lineNo
++ << " - Function name not set" << endl;
++
++ ensureFile();
++ ensureObject();
++
++ currentFunction = _data->function(_emptyString,
++ currentFile,
++ currentObject);
++ currentPartFunction = currentFunction->partFunction(_part,
++ currentPartFile,
++ currentPartObject);
++}
++
++void CachegrindLoader::setFunction(const TQString& name)
++{
++ ensureFile();
++ ensureObject();
++
++ currentFunction = compressedFunction( name,
++ currentFile,
++ currentObject);
++
++ if (!currentFunction) {
++ kdWarning() << _filename << ":" << _lineNo
++ << " - Invalid function, setting to unknown" << endl;
++
++ currentFunction = _data->function(_emptyString,
++ currentFile,
++ currentObject);
++ }
++
++ currentPartFunction = currentFunction->partFunction(_part,
++ currentPartFile,
++ currentPartObject);
++
++ currentFunctionSource = 0;
++ currentLine = 0;
++ currentPartLine = 0;
++}
++
++void CachegrindLoader::setCalledFunction(const TQString& name)
++{
++ // if called object/file not set, use current object/file
++ if (!currentCalledObject) {
++ currentCalledObject = currentObject;
++ currentCalledPartObject = currentPartObject;
++ }
++
++ if (!currentCalledFile) {
++ // !=0 as functions needs file
++ currentCalledFile = currentFile;
++ currentCalledPartFile = currentPartFile;
++ }
++
++ currentCalledFunction = compressedFunction(name,
++ currentCalledFile,
++ currentCalledObject);
++ if (!currentCalledFunction) {
++ kdWarning() << _filename << ":" << _lineNo
++ << " - Invalid called function, setting to unknown" << endl;
++
++ currentCalledFunction = _data->function(_emptyString,
++ currentCalledFile,
++ currentCalledObject);
++ }
++
++ currentCalledPartFunction =
++ currentCalledFunction->partFunction(_part,
++ currentCalledPartFile,
++ currentCalledPartObject);
++}
++
++
++void CachegrindLoader::clearPosition()
++{
++ currentPos = PositionSpec();
++
++ // current function/line
++ currentFunction = 0;
++ currentPartFunction = 0;
++ currentFunctionSource = 0;
++ currentFile = 0;
++ currentPartFile = 0;
++ currentObject = 0;
++ currentPartObject = 0;
++ currentLine = 0;
++ currentPartLine = 0;
++ currentInstr = 0;
++ currentPartInstr = 0;
++
++ // current call
++ currentCalledObject = 0;
++ currentCalledPartObject = 0;
++ currentCalledFile = 0;
++ currentCalledPartFile = 0;
++ currentCalledFunction = 0;
++ currentCalledPartFunction = 0;
++ currentCallCount = 0;
++
++ // current jump
++ currentJumpToFile = 0;
++ currentJumpToFunction = 0;
++ targetPos = PositionSpec();
++ jumpsFollowed = 0;
++ jumpsExecuted = 0;
++
++ subMapping = 0;
++}
++
++
++/**
++ * The main import function...
++ */
++bool CachegrindLoader::loadTraceInternal(TracePart* part)
++{
++ clearCompression();
++ clearPosition();
++
++ _part = part;
++ _data = part->data();
++ TQFile* pFile = part->file();
++
++ if (!pFile) return false;
++
++ _filename = pFile->name();
++
++ FixFile file(pFile);
++ if (!file.exists()) {
++ kdError() << "File doesn't exist\n" << endl;
++ return false;
++ }
++ kdDebug() << "Loading " << _filename << " ..." << endl;
++ TQString statusMsg = i18n("Loading %1").arg(_filename);
++ int statusProgress = 0;
++ emit updateStatus(statusMsg,statusProgress);
++
++
++#if USE_FIXCOST
++ // FixCost Memory Pool
++ FixPool* pool = _data->fixPool();
++#endif
++
++ _lineNo = 0;
++ FixString line;
++ char c;
++ bool totalsSet = false;
++
++ // current position
++ nextLineType = SelfCost;
++ // default if there's no "positions:" line
++ hasLineInfo = true;
++ hasAddrInfo = false;
++
++ while (file.nextLine(line)) {
++
++ _lineNo++;
++
++#if TRACE_LOADER
++ kdDebug() << "[CachegrindLoader] " << _filename << ":" << _lineNo
++ << " - '" << TQString(line) << "'" << endl;
++#endif
++
++ // if we cannot strip a character, this was an empty line
++ if (!line.first(c)) continue;
++
++ if (c <= '9') {
++
++ if (c == '#') continue;
++
++ // parse position(s)
++ if (!parsePosition(line, currentPos)) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Invalid position specification ('"
++ << TQString(line) << "')" << endl;
++ continue;
++ }
++
++ // go through after big switch
++ }
++ else { // if (c > '9')
++
++ line.stripFirst(c);
++
++ /* in order of probability */
++ switch(c) {
++
++ case 'f':
++
++ // fl=, fi=, fe=
++ if (line.stripPrefix("l=") ||
++ line.stripPrefix("i=") ||
++ line.stripPrefix("e=")) {
++
++ setFile(line);
++ continue;
++ }
++
++ // fn=
++ if (line.stripPrefix("n=")) {
++
++ setFunction(line);
++
++ // on a new function, update status
++ int progress = (int)(100.0 * file.current() / file.len() +.5);
++ if (progress != statusProgress) {
++ statusProgress = progress;
++
++ /* When this signal is connected, it most probably
++ * should lead to GUI update. Thus, when multiple
++ * "long operations" (like file loading) are in progress,
++ * this can temporarly switch to another operation.
++ */
++ emit updateStatus(statusMsg,statusProgress);
++ }
++
++ continue;
++ }
++
++ break;
++
++ case 'c':
++ // cob=
++ if (line.stripPrefix("ob=")) {
++ setCalledObject(line);
++ continue;
++ }
++
++ // cfi= / cfl=
++ if (line.stripPrefix("fl=") ||
++ line.stripPrefix("fi=")) {
++ setCalledFile(line);
++ continue;
++ }
++
++ // cfn=
++ if (line.stripPrefix("fn=")) {
++
++ setCalledFunction(line);
++ continue;
++ }
++
++ // calls=
++ if (line.stripPrefix("alls=")) {
++ // ignore long lines...
++ line.stripUInt64(currentCallCount);
++ nextLineType = CallCost;
++ continue;
++ }
++
++ // cmd:
++ if (line.stripPrefix("md:")) {
++ TQString command = TQString(line).stripWhiteSpace();
++ if (!_data->command().isEmpty() &&
++ _data->command() != command) {
++
++ kdWarning() << _filename << ":" << _lineNo
++ << " - Redefined command, was '"
++ << _data->command()
++ << "'" << endl;
++ }
++ _data->setCommand(command);
++ continue;
++ }
++
++ // creator:
++ if (line.stripPrefix("reator:")) {
++ // ignore ...
++ continue;
++ }
++
++ break;
++
++ case 'j':
++
++ // jcnd=
++ if (line.stripPrefix("cnd=")) {
++ bool valid;
++
++ valid = line.stripUInt64(jumpsFollowed) &&
++ line.stripPrefix("/") &&
++ line.stripUInt64(jumpsExecuted) &&
++ parsePosition(line, targetPos);
++
++ if (!valid) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Invalid jcnd line" << endl;
++ }
++ else
++ nextLineType = CondJump;
++ continue;
++ }
++
++ if (line.stripPrefix("ump=")) {
++ bool valid;
++
++ valid = line.stripUInt64(jumpsExecuted) &&
++ parsePosition(line, targetPos);
++
++ if (!valid) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Invalid jump line" << endl;
++ }
++ else
++ nextLineType = BoringJump;
++ continue;
++ }
++
++ // jfi=
++ if (line.stripPrefix("fi=")) {
++ currentJumpToFile = compressedFile(line);
++ continue;
++ }
++
++ // jfn=
++ if (line.stripPrefix("fn=")) {
++
++ if (!currentJumpToFile) {
++ // !=0 as functions needs file
++ currentJumpToFile = currentFile;
++ }
++
++ currentJumpToFunction =
++ compressedFunction(line,
++ currentJumpToFile,
++ currentObject);
++ continue;
++ }
++
++ break;
++
++ case 'o':
++
++ // ob=
++ if (line.stripPrefix("b=")) {
++ setObject(line);
++ continue;
++ }
++
++ break;
++
++ case '#':
++ continue;
++
++ case 't':
++
++ // totals:
++ if (line.stripPrefix("otals:")) continue;
++
++ // thread:
++ if (line.stripPrefix("hread:")) {
++ part->setThreadID(TQString(line).toInt());
++ continue;
++ }
++
++ // timeframe (BB):
++ if (line.stripPrefix("imeframe (BB):")) {
++ part->setTimeframe(line);
++ continue;
++ }
++
++ break;
++
++ case 'd':
++
++ // desc:
++ if (line.stripPrefix("esc:")) {
++
++ line.stripSurroundingSpaces();
++
++ // desc: Trigger:
++ if (line.stripPrefix("Trigger:")) {
++ part->setTrigger(line);
++ }
++
++ continue;
++ }
++ break;
++
++ case 'e':
++
++ // events:
++ if (line.stripPrefix("vents:")) {
++ subMapping = _data->mapping()->subMapping(line);
++ part->setFixSubMapping(subMapping);
++ continue;
++ }
++
++ // event:<name>[=<formula>][:<long name>]
++ if (line.stripPrefix("vent:")) {
++ line.stripSurroundingSpaces();
++
++ FixString e, f, l;
++ if (!line.stripName(e)) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Invalid event" << endl;
++ continue;
++ }
++ line.stripSpaces();
++ if (!line.stripFirst(c)) continue;
++
++ if (c=='=') f = line.stripUntil(':');
++ line.stripSpaces();
++
++ // add to known cost types
++ if (line.isEmpty()) line = e;
++ TraceCostType::add(new TraceCostType(e,line,f));
++ continue;
++ }
++ break;
++
++ case 'p':
++
++ // part:
++ if (line.stripPrefix("art:")) {
++ part->setPartNumber(TQString(line).toInt());
++ continue;
++ }
++
++ // pid:
++ if (line.stripPrefix("id:")) {
++ part->setProcessID(TQString(line).toInt());
++ continue;
++ }
++
++ // positions:
++ if (line.stripPrefix("ositions:")) {
++ TQString positions(line);
++ hasLineInfo = (positions.find("line")>=0);
++ hasAddrInfo = (positions.find("instr")>=0);
++ continue;
++ }
++ break;
++
++ case 'v':
++
++ // version:
++ if (line.stripPrefix("ersion:")) {
++ part->setVersion(line);
++ continue;
++ }
++ break;
++
++ case 's':
++
++ // summary:
++ if (line.stripPrefix("ummary:")) {
++ if (!subMapping) {
++ kdError() << "No event line found. Skipping '" << _filename << endl;
++ return false;
++ }
++
++ part->totals()->set(subMapping, line);
++ continue;
++ }
++
++ case 'r':
++
++ // rcalls= (deprecated)
++ if (line.stripPrefix("calls=")) {
++ // handle like normal calls: we need the sum of call count
++ // recursive cost is discarded in cycle detection
++ line.stripUInt64(currentCallCount);
++ nextLineType = CallCost;
++
++ kdDebug() << "WARNING: This trace dump was generated by an old "
++ "version\n of the call-tree skin. Use a new one!" << endl;
++
++ continue;
++ }
++ break;
++
++ default:
++ break;
++ }
++
++ kdError() << _filename << ":" << _lineNo
++ << " - Invalid line '" << c << TQString(line) << "'" << endl;
++ continue;
++ }
++
++ if (!subMapping) {
++ kdError() << "No event line found. Skipping '" << _filename << "'" << endl;
++ return false;
++ }
++
++ // for a cost line, we always need a current function
++ ensureFunction();
++
++
++#if USE_FIXCOST
++ if (!currentFunctionSource ||
++ (currentFunctionSource->file() != currentFile))
++ currentFunctionSource = currentFunction->sourceFile(currentFile,
++ true);
++#else
++ if (hasAddrInfo) {
++ if (!currentInstr ||
++ (currentInstr->addr() != currentPos.fromAddr)) {
++ currentInstr = currentFunction->instr(currentPos.fromAddr,
++ true);
++
++ if (!currentInstr) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Invalid address "
++ << currentPos.fromAddr.toString() << endl;
++
++ continue;
++ }
++
++ currentPartInstr = currentInstr->partInstr(part,
++ currentPartFunction);
++ }
++ }
++
++ if (hasLineInfo) {
++ if (!currentLine ||
++ (currentLine->lineno() != currentPos.fromLine)) {
++
++ currentLine = currentFunction->line(currentFile,
++ currentPos.fromLine,
++ true);
++ currentPartLine = currentLine->partLine(part,
++ currentPartFunction);
++ }
++ if (hasAddrInfo && currentInstr)
++ currentInstr->setLine(currentLine);
++ }
++#endif
++
++#if TRACE_LOADER
++ kdDebug() << _filename << ":" << _lineNo
++ << endl << " currentInstr "
++ << (currentInstr ? currentInstr->toString().ascii() : ".")
++ << endl << " currentLine "
++ << (currentLine ? currentLine->toString().ascii() : ".")
++ << "( file " << currentFile->name() << ")"
++ << endl << " currentFunction "
++ << currentFunction->prettyName().ascii()
++ << endl << " currentCalled "
++ << (currentCalledFunction ? currentCalledFunction->prettyName().ascii() : ".")
++ << endl;
++#endif
++
++ // create cost item
++
++ if (nextLineType == SelfCost) {
++
++#if USE_FIXCOST
++ new (pool) FixCost(part, pool,
++ currentFunctionSource,
++ currentPos,
++ currentPartFunction,
++ line);
++#else
++ if (hasAddrInfo) {
++ TracePartInstr* partInstr;
++ partInstr = currentInstr->partInstr(part, currentPartFunction);
++
++ if (hasLineInfo) {
++ // we need to set <line> back after reading for the line
++ int l = line.len();
++ const char* s = line.ascii();
++
++ partInstr->addCost(subMapping, line);
++ line.set(s,l);
++ }
++ else
++ partInstr->addCost(subMapping, line);
++ }
++
++ if (hasLineInfo) {
++ TracePartLine* partLine;
++ partLine = currentLine->partLine(part, currentPartFunction);
++ partLine->addCost(subMapping, line);
++ }
++#endif
++
++ if (!line.isEmpty()) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Garbage at end of cost line ('"
++ << TQString(line) << "')" << endl;
++ }
++ }
++ else if (nextLineType == CallCost) {
++ nextLineType = SelfCost;
++
++ TraceCall* calling = currentFunction->calling(currentCalledFunction);
++ TracePartCall* partCalling =
++ calling->partCall(part, currentPartFunction,
++ currentCalledPartFunction);
++
++#if USE_FIXCOST
++ FixCallCost* fcc;
++ fcc = new (pool) FixCallCost(part, pool,
++ currentFunctionSource,
++ hasLineInfo ? currentPos.fromLine : 0,
++ hasAddrInfo ? currentPos.fromAddr : Addr(0),
++ partCalling,
++ currentCallCount, line);
++ fcc->setMax(_data->callMax());
++#else
++ if (hasAddrInfo) {
++ TraceInstrCall* instrCall;
++ TracePartInstrCall* partInstrCall;
++
++ instrCall = calling->instrCall(currentInstr);
++ partInstrCall = instrCall->partInstrCall(part, partCalling);
++ partInstrCall->addCallCount(currentCallCount);
++
++ if (hasLineInfo) {
++ // we need to set <line> back after reading for the line
++ int l = line.len();
++ const char* s = line.ascii();
++
++ partInstrCall->addCost(subMapping, line);
++ line.set(s,l);
++ }
++ else
++ partInstrCall->addCost(subMapping, line);
++
++ // update maximum of call cost
++ _data->callMax()->maxCost(partInstrCall);
++ }
++
++ if (hasLineInfo) {
++ TraceLineCall* lineCall;
++ TracePartLineCall* partLineCall;
++
++ lineCall = calling->lineCall(currentLine);
++ partLineCall = lineCall->partLineCall(part, partCalling);
++
++ partLineCall->addCallCount(currentCallCount);
++ partLineCall->addCost(subMapping, line);
++
++ // update maximum of call cost
++ _data->callMax()->maxCost(partLineCall);
++ }
++#endif
++ currentCalledFile = 0;
++ currentCalledPartFile = 0;
++ currentCalledObject = 0;
++ currentCalledPartObject = 0;
++ currentCallCount = 0;
++
++ if (!line.isEmpty()) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Garbage at end of call cost line ('"
++ << TQString(line) << "')" << endl;
++ }
++ }
++ else { // (nextLineType == BoringJump || nextLineType == CondJump)
++
++ TraceFunctionSource* targetSource;
++
++ if (!currentJumpToFunction)
++ currentJumpToFunction = currentFunction;
++
++ targetSource = (currentJumpToFile) ?
++ currentJumpToFunction->sourceFile(currentJumpToFile, true) :
++ currentFunctionSource;
++
++#if USE_FIXCOST
++ new (pool) FixJump(part, pool,
++ /* source */
++ hasLineInfo ? currentPos.fromLine : 0,
++ hasAddrInfo ? currentPos.fromAddr : 0,
++ currentPartFunction,
++ currentFunctionSource,
++ /* target */
++ hasLineInfo ? targetPos.fromLine : 0,
++ hasAddrInfo ? targetPos.fromAddr : Addr(0),
++ currentJumpToFunction,
++ targetSource,
++ (nextLineType == CondJump),
++ jumpsExecuted, jumpsFollowed);
++#endif
++
++ if (0) {
++ kdDebug() << _filename << ":" << _lineNo
++ << " - jump from 0x" << currentPos.fromAddr.toString()
++ << " (line " << currentPos.fromLine
++ << ") to 0x" << targetPos.fromAddr.toString()
++ << " (line " << targetPos.fromLine << ")" << endl;
++
++ if (nextLineType == BoringJump)
++ kdDebug() << " Boring Jump, count " << jumpsExecuted.pretty() << endl;
++ else
++ kdDebug() << " Cond. Jump, followed " << jumpsFollowed.pretty()
++ << ", executed " << jumpsExecuted.pretty() << endl;
++ }
++
++ nextLineType = SelfCost;
++ currentJumpToFunction = 0;
++ currentJumpToFile = 0;
++
++ if (!line.isEmpty()) {
++ kdError() << _filename << ":" << _lineNo
++ << " - Garbage at end of jump cost line ('"
++ << TQString(line) << "')" << endl;
++ }
++
++ }
++ }
++
++
++ emit updateStatus(statusMsg,100);
++
++ _part->invalidate();
++ if (!totalsSet) {
++ _part->totals()->clear();
++ _part->totals()->addCost(_part);
++ }
++
++ pFile->close();
++
++ return true;
++}
++
+diff --git a/kdecachegrind/kdecachegrind/callgraphview.cpp b/kdecachegrind/kdecachegrind/callgraphview.cpp
+new file mode 100644
+index 0000000..bc01da8
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/callgraphview.cpp
+@@ -0,0 +1,2734 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Callgraph View
++ */
++
++#include <stdlib.h>
++#include <math.h>
++
++#include <tqtooltip.h>
++#include <tqfile.h>
++#include <tqtextstream.h>
++#include <tqwhatsthis.h>
++#include <tqcanvas.h>
++#include <tqwmatrix.h>
++#include <tqpair.h>
++#include <tqpainter.h>
++#include <tqpopupmenu.h>
++#include <tqstyle.h>
++#include <tqprocess.h>
++
++#include <kdebug.h>
++#include <klocale.h>
++#include <kconfig.h>
++#include <ktempfile.h>
++#include <kapplication.h>
++#include <kiconloader.h>
++#include <kfiledialog.h>
++
++#include "configuration.h"
++#include "callgraphview.h"
++#include "toplevel.h"
++#include "listutils.h"
++
++
++/*
++ * TODO:
++ * - Zooming option for work canvas? (e.g. 1:1 - 1:3)
++ */
++
++#define DEBUG_GRAPH 0
++
++// CallGraphView defaults
++
++#define DEFAULT_FUNCLIMIT .05
++#define DEFAULT_CALLLIMIT .05
++#define DEFAULT_MAXCALLER 2
++#define DEFAULT_MAXCALLING -1
++#define DEFAULT_SHOWSKIPPED false
++#define DEFAULT_EXPANDCYCLES false
++#define DEFAULT_CLUSTERGROUPS false
++#define DEFAULT_DETAILLEVEL 1
++#define DEFAULT_LAYOUT GraphOptions::TopDown
++#define DEFAULT_ZOOMPOS Auto
++
++
++//
++// GraphEdgeList
++//
++
++GraphEdgeList::GraphEdgeList()
++ : _sortCallerPos(true)
++{}
++
++int GraphEdgeList::compareItems(Item item1, Item item2)
++{
++ CanvasEdge* e1 = ((GraphEdge*)item1)->canvasEdge();
++ CanvasEdge* e2 = ((GraphEdge*)item2)->canvasEdge();
++
++ // edges without arrow visualisations are sorted as low
++ if (!e1) return -1;
++ if (!e2) return 1;
++
++ int dx1, dy1, dx2, dy2;
++ int x, y;
++ if (_sortCallerPos) {
++ e1->controlPoints().point(0,&x,&y);
++ e2->controlPoints().point(0,&dx1,&dy1);
++ dx1 -= x; dy1 -= y;
++ }
++ else {
++ TQPointArray a1 = e1->controlPoints();
++ TQPointArray a2 = e2->controlPoints();
++ a1.point(a1.count()-2,&x,&y);
++ a2.point(a2.count()-1,&dx2,&dy2);
++ dx2 -= x; dy2 -= y;
++ }
++ double at1 = atan2(double(dx1), double(dy1));
++ double at2 = atan2(double(dx2), double(dy2));
++
++ return (at1 < at2) ? 1:-1;
++}
++
++
++
++
++//
++// GraphNode
++//
++
++GraphNode::GraphNode()
++{
++ _f=0;
++ self = incl = 0;
++ _cn = 0;
++
++ _visible = false;
++ _lastCallerIndex = _lastCallingIndex = -1;
++
++ callers.setSortCallerPos(false);
++ callings.setSortCallerPos(true);
++ _lastFromCaller = true;
++}
++
++TraceCall* GraphNode::visibleCaller()
++{
++ if (0) qDebug("GraphNode::visibleCaller %s: last %d, count %d",
++ _f->prettyName().ascii(), _lastCallerIndex, callers.count());
++
++ GraphEdge* e = callers.at(_lastCallerIndex);
++ if (e && !e->isVisible()) e = 0;
++ if (!e) {
++ double maxCost = 0.0;
++ GraphEdge* maxEdge = 0;
++ int idx = 0;
++ for(e = callers.first();e; e=callers.next(),idx++)
++ if (e->isVisible() && (e->cost > maxCost)) {
++ maxCost = e->cost;
++ maxEdge = e;
++ _lastCallerIndex = idx;
++ }
++ e = maxEdge;
++ }
++ return e ? e->call() : 0;
++}
++
++TraceCall* GraphNode::visibleCalling()
++{
++ if (0) qDebug("GraphNode::visibleCalling %s: last %d, count %d",
++ _f->prettyName().ascii(), _lastCallingIndex, callings.count());
++
++ GraphEdge* e = callings.at(_lastCallingIndex);
++ if (e && !e->isVisible()) e = 0;
++ if (!e) {
++ double maxCost = 0.0;
++ GraphEdge* maxEdge = 0;
++ int idx = 0;
++ for(e = callings.first();e; e=callings.next(),idx++)
++ if (e->isVisible() && (e->cost > maxCost)) {
++ maxCost = e->cost;
++ maxEdge = e;
++ _lastCallingIndex = idx;
++ }
++ e = maxEdge;
++ }
++ return e ? e->call() : 0;
++}
++
++void GraphNode::setCalling(GraphEdge* e)
++{
++ _lastCallingIndex = callings.findRef(e);
++ _lastFromCaller = false;
++}
++
++void GraphNode::setCaller(GraphEdge* e)
++{
++ _lastCallerIndex = callers.findRef(e);
++ _lastFromCaller = true;
++}
++
++TraceFunction* GraphNode::nextVisible()
++{
++ TraceCall* c;
++ if (_lastFromCaller) {
++ c = nextVisibleCaller(callers.at(_lastCallerIndex));
++ if (c) return c->called(true);
++ c = nextVisibleCalling(callings.at(_lastCallingIndex));
++ if (c) return c->caller(true);
++ }
++ else {
++ c = nextVisibleCalling(callings.at(_lastCallingIndex));
++ if (c) return c->caller(true);
++ c = nextVisibleCaller(callers.at(_lastCallerIndex));
++ if (c) return c->called(true);
++ }
++ return 0;
++}
++
++TraceFunction* GraphNode::priorVisible()
++{
++ TraceCall* c;
++ if (_lastFromCaller) {
++ c = priorVisibleCaller(callers.at(_lastCallerIndex));
++ if (c) return c->called(true);
++ c = priorVisibleCalling(callings.at(_lastCallingIndex));
++ if (c) return c->caller(true);
++ }
++ else {
++ c = priorVisibleCalling(callings.at(_lastCallingIndex));
++ if (c) return c->caller(true);
++ c = priorVisibleCaller(callers.at(_lastCallerIndex));
++ if (c) return c->called(true);
++ }
++ return 0;
++}
++
++TraceCall* GraphNode::nextVisibleCaller(GraphEdge* last)
++{
++ GraphEdge* e;
++ bool found = false;
++ int idx = 0;
++ for(e = callers.first();e; e=callers.next(),idx++) {
++ if (found && e->isVisible()) {
++ _lastCallerIndex = idx;
++ return e->call();
++ }
++ if (e == last) found = true;
++ }
++ return 0;
++}
++
++TraceCall* GraphNode::nextVisibleCalling(GraphEdge* last)
++{
++ GraphEdge* e;
++ bool found = false;
++ int idx = 0;
++ for(e = callings.first();e; e=callings.next(),idx++) {
++ if (found && e->isVisible()) {
++ _lastCallingIndex = idx;
++ return e->call();
++ }
++ if (e == last) found = true;
++ }
++ return 0;
++}
++
++TraceCall* GraphNode::priorVisibleCaller(GraphEdge* last)
++{
++ GraphEdge *e, *prev = 0;
++ int prevIdx = -1, idx = 0;
++ for(e = callers.first(); e; e=callers.next(),idx++) {
++ if (e == last) {
++ _lastCallerIndex = prevIdx;
++ return prev ? prev->call() : 0;
++ }
++ if (e->isVisible()) {
++ prev = e;
++ prevIdx = idx;
++ }
++ }
++ return 0;
++}
++
++TraceCall* GraphNode::priorVisibleCalling(GraphEdge* last)
++{
++ GraphEdge *e, *prev = 0;
++ int prevIdx = -1, idx = 0;
++ for(e = callings.first(); e; e=callings.next(),idx++) {
++ if (e == last) {
++ _lastCallingIndex = prevIdx;
++ return prev ? prev->call() : 0;
++ }
++ if (e->isVisible()) {
++ prev = e;
++ prevIdx = idx;
++ }
++ }
++ return 0;
++}
++
++//
++// GraphEdge
++//
++
++GraphEdge::GraphEdge()
++{
++ _c=0;
++ _from = _to = 0;
++ _fromNode = _toNode = 0;
++ cost = count = 0;
++ _ce = 0;
++
++ _visible = false;
++ _lastFromCaller = true;
++}
++
++TQString GraphEdge::prettyName()
++{
++ if (_c) return _c->prettyName();
++ if (_from) return i18n("Call(s) from %1").arg(_from->prettyName());
++ if (_to) return i18n("Call(s) to %1").arg(_to->prettyName());
++ return i18n("(unknown call)");
++}
++
++
++TraceFunction* GraphEdge::visibleCaller()
++{
++ if (_from) {
++ _lastFromCaller = true;
++ if (_fromNode) _fromNode->setCalling(this);
++ return _from;
++ }
++ return 0;
++}
++
++TraceFunction* GraphEdge::visibleCalling()
++{
++ if (_to) {
++ _lastFromCaller = false;
++ if (_toNode) _toNode->setCaller(this);
++ return _to;
++ }
++ return 0;
++}
++
++TraceCall* GraphEdge::nextVisible()
++{
++ TraceCall* res = 0;
++
++ if (_lastFromCaller && _fromNode) {
++ res = _fromNode->nextVisibleCalling(this);
++ if (!res && _toNode)
++ res = _toNode->nextVisibleCaller(this);
++ }
++ else if (_toNode) {
++ res = _toNode->nextVisibleCaller(this);
++ if (!res && _fromNode)
++ res = _fromNode->nextVisibleCalling(this);
++ }
++ return res;
++}
++
++TraceCall* GraphEdge::priorVisible()
++{
++ TraceCall* res = 0;
++
++ if (_lastFromCaller && _fromNode) {
++ res = _fromNode->priorVisibleCalling(this);
++ if (!res && _toNode)
++ res = _toNode->priorVisibleCaller(this);
++ }
++ else if (_toNode) {
++ res = _toNode->priorVisibleCaller(this);
++ if (!res && _fromNode)
++ res = _fromNode->priorVisibleCalling(this);
++ }
++ return res;
++}
++
++
++
++//
++// GraphOptions
++//
++
++TQString GraphOptions::layoutString(Layout l)
++{
++ if (l == Circular) return TQString("Circular");
++ if (l == LeftRight) return TQString("LeftRight");
++ return TQString("TopDown");
++}
++
++GraphOptions::Layout GraphOptions::layout(TQString s)
++{
++ if (s == TQString("Circular")) return Circular;
++ if (s == TQString("LeftRight")) return LeftRight;
++ return TopDown;
++}
++
++
++//
++// StorableGraphOptions
++//
++
++StorableGraphOptions::StorableGraphOptions()
++{
++ // default options
++ _funcLimit = DEFAULT_FUNCLIMIT;
++ _callLimit = DEFAULT_CALLLIMIT;
++ _maxCallerDepth = DEFAULT_MAXCALLER;
++ _maxCallingDepth = DEFAULT_MAXCALLING;
++ _showSkipped = DEFAULT_SHOWSKIPPED;
++ _expandCycles = DEFAULT_EXPANDCYCLES;
++ _detailLevel = DEFAULT_DETAILLEVEL;
++ _layout = DEFAULT_LAYOUT;
++}
++
++
++
++
++//
++// GraphExporter
++//
++
++GraphExporter::GraphExporter()
++{
++ _go = this;
++ _tmpFile = 0;
++ _item = 0;
++ reset(0, 0, 0, TraceItem::NoCostType, TQString());
++}
++
++
++GraphExporter::GraphExporter(TraceData* d, TraceFunction* f, TraceCostType* ct,
++ TraceItem::CostType gt, TQString filename)
++{
++ _go = this;
++ _tmpFile = 0;
++ _item = 0;
++ reset(d, f, ct, gt, filename);
++}
++
++
++GraphExporter::~GraphExporter()
++{
++ if (_item && _tmpFile) {
++#if DEBUG_GRAPH
++ _tmpFile->unlink();
++#endif
++ delete _tmpFile;
++ }
++}
++
++
++void GraphExporter::reset(TraceData*, TraceItem* i, TraceCostType* ct,
++ TraceItem::CostType gt, TQString filename)
++{
++ _graphCreated = false;
++ _nodeMap.clear();
++ _edgeMap.clear();
++
++ if (_item && _tmpFile) {
++ _tmpFile->unlink();
++ delete _tmpFile;
++ }
++
++ if (i) {
++ switch(i->type()) {
++ case TraceItem::Function:
++ case TraceItem::FunctionCycle:
++ case TraceItem::Call:
++ break;
++ default:
++ i = 0;
++ }
++ }
++
++ _item = i;
++ _costType = ct;
++ _groupType = gt;
++ if (!i) return;
++
++ if (filename.isEmpty()) {
++ _tmpFile = new KTempFile(TQString(), ".dot");
++ _dotName = _tmpFile->name();
++ _useBox = true;
++ }
++ else {
++ _tmpFile = 0;
++ _dotName = filename;
++ _useBox = false;
++ }
++}
++
++
++
++void GraphExporter::setGraphOptions(GraphOptions* go)
++{
++ if (go == 0) go = this;
++ _go = go;
++}
++
++void GraphExporter::createGraph()
++{
++ if (!_item) return;
++ if (_graphCreated) return;
++ _graphCreated = true;
++
++ if ((_item->type() == TraceItem::Function) ||
++ (_item->type() == TraceItem::FunctionCycle)) {
++ TraceFunction* f = (TraceFunction*) _item;
++
++ double incl = f->inclusive()->subCost(_costType);
++ _realFuncLimit = incl * _go->funcLimit();
++ _realCallLimit = incl * _go->callLimit();
++
++ buildGraph(f, 0, true, 1.0); // down to callings
++
++ // set costs of function back to 0, as it will be added again
++ GraphNode& n = _nodeMap[f];
++ n.self = n.incl = 0.0;
++
++ buildGraph(f, 0, false, 1.0); // up to callers
++ }
++ else {
++ TraceCall* c = (TraceCall*) _item;
++
++ double incl = c->subCost(_costType);
++ _realFuncLimit = incl * _go->funcLimit();
++ _realCallLimit = incl * _go->callLimit();
++
++ // create edge
++ TraceFunction *caller, *called;
++ caller = c->caller(false);
++ called = c->called(false);
++ TQPair<TraceFunction*,TraceFunction*> p(caller, called);
++ GraphEdge& e = _edgeMap[p];
++ e.setCall(c);
++ e.setCaller(p.first);
++ e.setCalling(p.second);
++ e.cost = c->subCost(_costType);
++ e.count = c->callCount();
++
++ SubCost s = called->inclusive()->subCost(_costType);
++ buildGraph(called, 0, true, e.cost / s); // down to callings
++ s = caller->inclusive()->subCost(_costType);
++ buildGraph(caller, 0, false, e.cost / s); // up to callers
++ }
++}
++
++void GraphExporter::writeDot()
++{
++ if (!_item) return;
++
++ TQFile* file = 0;
++ TQTextStream* stream = 0;
++
++ if (_tmpFile)
++ stream = _tmpFile->textStream();
++ else {
++ file = new TQFile(_dotName);
++ if ( !file->open( IO_WriteOnly ) ) {
++ kdError() << "Can't write dot file '" << _dotName << "'" << endl;
++ return;
++ }
++ stream = new TQTextStream(file);
++ }
++
++ if (!_graphCreated) createGraph();
++
++ /* Generate dot format...
++ * When used for the CallGraphView (in contrast to "Export Callgraph..."),
++ * the labels are only dummy placeholders to reserve space for our own
++ * drawings.
++ */
++
++ *stream << "digraph \"callgraph\" {\n";
++
++ if (_go->layout() == LeftRight) {
++ *stream << TQString(" rankdir=LR;\n");
++ }
++ else if (_go->layout() == Circular) {
++ TraceFunction *f = 0;
++ switch(_item->type()) {
++ case TraceItem::Function:
++ case TraceItem::FunctionCycle:
++ f = (TraceFunction*) _item;
++ break;
++ case TraceItem::Call:
++ f = ((TraceCall*)_item)->caller(true);
++ break;
++ default:
++ break;
++ }
++ if (f)
++ *stream << TQString(" center=F%1;\n").arg((long)f, 0, 16);
++ *stream << TQString(" overlap=false;\n splines=true;\n");
++ }
++
++ // for clustering
++ TQMap<TraceCostItem*,TQPtrList<GraphNode> > nLists;
++
++ GraphNodeMap::Iterator nit;
++ for ( nit = _nodeMap.begin();
++ nit != _nodeMap.end(); ++nit ) {
++ GraphNode& n = *nit;
++
++ if (n.incl <= _realFuncLimit) continue;
++
++ // for clustering: get cost item group of function
++ TraceCostItem* g;
++ TraceFunction* f = n.function();
++ switch(_groupType) {
++ case TraceItem::Object: g = f->object(); break;
++ case TraceItem::Class: g = f->cls(); break;
++ case TraceItem::File: g = f->file(); break;
++ case TraceItem::FunctionCycle: g = f->cycle(); break;
++ default: g = 0; break;
++ }
++ nLists[g].append(&n);
++ }
++
++ TQMap<TraceCostItem*,TQPtrList<GraphNode> >::Iterator lit;
++ int cluster = 0;
++ for ( lit = nLists.begin();
++ lit != nLists.end(); ++lit, cluster++ ) {
++ TQPtrList<GraphNode>& l = lit.data();
++ TraceCostItem* i = lit.key();
++
++ if (_go->clusterGroups() && i) {
++ TQString iabr = i->prettyName();
++ if ((int)iabr.length() > Configuration::maxSymbolLength())
++ iabr = iabr.left(Configuration::maxSymbolLength()) + "...";
++
++ *stream << TQString("subgraph \"cluster%1\" { label=\"%2\";\n")
++ .arg(cluster).arg(iabr);
++ }
++
++ GraphNode* np;
++ for(np = l.first(); np; np = l.next() ) {
++ TraceFunction* f = np->function();
++
++ TQString abr = f->prettyName();
++ if ((int)abr.length() > Configuration::maxSymbolLength())
++ abr = abr.left(Configuration::maxSymbolLength()) + "...";
++
++ *stream << TQString(" F%1 [").arg((long)f, 0, 16);
++ if (_useBox) {
++ // make label 3 lines for CallGraphView
++ *stream << TQString("shape=box,label=\"** %1 **\\n**\\n%2\"];\n")
++ .arg(abr)
++ .arg(SubCost(np->incl).pretty());
++ }
++ else
++ *stream << TQString("label=\"%1\\n%2\"];\n")
++ .arg(abr)
++ .arg(SubCost(np->incl).pretty());
++ }
++
++ if (_go->clusterGroups() && i)
++ *stream << TQString("}\n");
++ }
++
++ GraphEdgeMap::Iterator eit;
++ for ( eit = _edgeMap.begin();
++ eit != _edgeMap.end(); ++eit ) {
++ GraphEdge& e = *eit;
++
++ if (e.cost < _realCallLimit) continue;
++ if (!_go->expandCycles()) {
++ // don't show inner cycle calls
++ if (e.call()->inCycle()>0) continue;
++ }
++
++
++ GraphNode& from = _nodeMap[e.from()];
++ GraphNode& to = _nodeMap[e.to()];
++
++ e.setCallerNode(&from);
++ e.setCallingNode(&to);
++
++ if ((from.incl <= _realFuncLimit) ||
++ (to.incl <= _realFuncLimit)) continue;
++
++ // remove dumped edges from n.callers/n.callings
++ from.callings.removeRef(&e);
++ to.callers.removeRef(&e);
++ from.callingSet.remove(&e);
++ to.callerSet.remove(&e);
++
++ *stream << TQString(" F%1 -> F%2 [weight=%3")
++ .arg((long)e.from(), 0, 16)
++ .arg((long)e.to(), 0, 16)
++ .arg((long)log(log(e.cost)));
++
++ if (_go->detailLevel() ==1)
++ *stream << TQString(",label=\"%1\"")
++ .arg(SubCost(e.cost).pretty());
++ else if (_go->detailLevel() ==2)
++ *stream << TQString(",label=\"%3\\n%4 x\"")
++ .arg(SubCost(e.cost).pretty())
++ .arg(SubCost(e.count).pretty());
++
++ *stream << TQString("];\n");
++ }
++
++ if (_go->showSkipped()) {
++
++ // Create sum-edges for skipped edges
++ GraphEdge* e;
++ double costSum, countSum;
++ for ( nit = _nodeMap.begin();
++ nit != _nodeMap.end(); ++nit ) {
++ GraphNode& n = *nit;
++ if (n.incl <= _realFuncLimit) continue;
++
++ costSum = countSum = 0.0;
++ for (e=n.callers.first();e;e=n.callers.next()) {
++ costSum += e->cost;
++ countSum += e->count;
++ }
++ if (costSum > _realCallLimit) {
++
++ TQPair<TraceFunction*,TraceFunction*> p(0, n.function());
++ e = &(_edgeMap[p]);
++ e->setCalling(p.second);
++ e->cost = costSum;
++ e->count = countSum;
++
++ *stream << TQString(" R%1 [shape=point,label=\"\"];\n")
++ .arg((long)n.function(), 0, 16);
++ *stream << TQString(" R%1 -> F%2 [label=\"%3\\n%4 x\",weight=%5];\n")
++ .arg((long)n.function(), 0, 16)
++ .arg((long)n.function(), 0, 16)
++ .arg(SubCost(costSum).pretty())
++ .arg(SubCost(countSum).pretty())
++ .arg((int)log(costSum));
++ }
++
++ costSum = countSum = 0.0;
++ for (e=n.callings.first();e;e=n.callings.next()) {
++ costSum += e->cost;
++ countSum += e->count;
++ }
++ if (costSum > _realCallLimit) {
++
++ TQPair<TraceFunction*,TraceFunction*> p(n.function(), 0);
++ e = &(_edgeMap[p]);
++ e->setCaller(p.first);
++ e->cost = costSum;
++ e->count = countSum;
++
++ *stream << TQString(" S%1 [shape=point,label=\"\"];\n")
++ .arg((long)n.function(), 0, 16);
++ *stream << TQString(" F%1 -> S%2 [label=\"%3\\n%4 x\",weight=%5];\n")
++ .arg((long)n.function(), 0, 16)
++ .arg((long)n.function(), 0, 16)
++ .arg(SubCost(costSum).pretty())
++ .arg(SubCost(countSum).pretty())
++ .arg((int)log(costSum));
++ }
++ }
++ }
++
++ // clear edges here completely.
++ // Visible edges are inserted again on parsing in CallGraphView::refresh
++ for ( nit = _nodeMap.begin();
++ nit != _nodeMap.end(); ++nit ) {
++ GraphNode& n = *nit;
++ n.callers.clear();
++ n.callings.clear();
++ n.callerSet.clear();
++ n.callingSet.clear();
++ }
++
++ *stream << "}\n";
++
++ if (_tmpFile) {
++ _tmpFile->close();
++ }
++ else {
++ file->close();
++ delete file;
++ delete stream;
++ }
++}
++
++void GraphExporter::sortEdges()
++{
++ GraphNodeMap::Iterator nit;
++ for ( nit = _nodeMap.begin();
++ nit != _nodeMap.end(); ++nit ) {
++ GraphNode& n = *nit;
++
++ n.callers.sort();
++ n.callings.sort();
++ }
++}
++
++TraceFunction* GraphExporter::toFunc(TQString s)
++{
++ if (s[0] != 'F') return 0;
++ bool ok;
++ TraceFunction* f = (TraceFunction*) s.mid(1).toULong(&ok, 16);
++ if (!ok) return 0;
++
++ return f;
++}
++
++GraphNode* GraphExporter::node(TraceFunction* f)
++{
++ if (!f) return 0;
++
++ GraphNodeMap::Iterator it = _nodeMap.find(f);
++ if (it == _nodeMap.end()) return 0;
++
++ return &(*it);
++}
++
++GraphEdge* GraphExporter::edge(TraceFunction* f1, TraceFunction* f2)
++{
++ GraphEdgeMap::Iterator it = _edgeMap.find(tqMakePair(f1, f2));
++ if (it == _edgeMap.end()) return 0;
++
++ return &(*it);
++}
++
++
++/**
++ * We do a DFS and don't stop on already visited nodes/edges,
++ * but add up costs. We only stop if limits/max depth is reached.
++ *
++ * For a node/edge, it can happen that the first time visited the
++ * cost will below the limit, so the search is stopped.
++ * If on a further visit of the node/edge the limit is reached,
++ * we use the whole node/edge cost and continue search.
++ */
++void GraphExporter::buildGraph(TraceFunction* f, int d,
++ bool toCallings, double factor)
++{
++#if DEBUG_GRAPH
++ kdDebug() << "buildGraph(" << f->prettyName() << "," << d << "," << factor
++ << ") [to " << (toCallings ? "Callings":"Callers") << "]" << endl;
++#endif
++
++ double oldIncl = 0.0;
++ GraphNode& n = _nodeMap[f];
++ if (n.function() == 0) {
++ n.setFunction(f);
++ }
++ else
++ oldIncl = n.incl;
++
++ double incl = f->inclusive()->subCost(_costType) * factor;
++ n.incl += incl;
++ n.self += f->subCost(_costType) * factor;
++ if (0) qDebug(" Added Incl. %f, now %f", incl, n.incl);
++
++ // A negative depth limit means "unlimited"
++ int maxDepth = toCallings ? _go->maxCallingDepth() : _go->maxCallerDepth();
++ if ((maxDepth>=0) && (d >= maxDepth)) {
++ if (0) qDebug(" Cutoff, max depth reached");
++ return;
++ }
++
++ // if we just reached the limit by summing, do a DFS
++ // from here with full incl. cost because of previous cutoffs
++ if ((n.incl >= _realFuncLimit) && (oldIncl < _realFuncLimit)) incl = n.incl;
++
++ if (f->cycle()) {
++ // for cycles members, we never stop on first visit, but always on 2nd
++ // note: a 2nd visit never should happen, as we don't follow inner-cycle
++ // calls
++ if (oldIncl > 0.0) {
++ if (0) qDebug(" Cutoff, 2nd visit to Cycle Member");
++ // and takeback cost addition, as it's added twice
++ n.incl = oldIncl;
++ n.self -= f->subCost(_costType) * factor;
++ return;
++ }
++ }
++ else if (incl <= _realFuncLimit) {
++ if (0) qDebug(" Cutoff, below limit");
++ return;
++ }
++
++ TraceCall* call;
++ TraceFunction* f2;
++
++
++ // on entering a cycle, only go the FunctionCycle
++ TraceCallList l = toCallings ?
++ f->callings(false) : f->callers(false);
++
++ for (call=l.first();call;call=l.next()) {
++
++ f2 = toCallings ? call->called(false) : call->caller(false);
++
++ double count = call->callCount() * factor;
++ double cost = call->subCost(_costType) * factor;
++
++ // ignore function calls with absolute cost < 3 per call
++ // No: This would skip a lot of functions e.g. with L2 cache misses
++ // if (count>0.0 && (cost/count < 3)) continue;
++
++ double oldCost = 0.0;
++ TQPair<TraceFunction*,TraceFunction*> p(toCallings ? f:f2,
++ toCallings ? f2:f);
++ GraphEdge& e = _edgeMap[p];
++ if (e.call() == 0) {
++ e.setCall(call);
++ e.setCaller(p.first);
++ e.setCalling(p.second);
++ }
++ else
++ oldCost = e.cost;
++
++ e.cost += cost;
++ e.count += count;
++ if (0) qDebug(" Edge to %s, added cost %f, now %f",
++ f2->prettyName().ascii(), cost, e.cost);
++
++ // if this call goes into a FunctionCycle, we also show the real call
++ if (f2->cycle() == f2) {
++ TraceFunction* realF;
++ realF = toCallings ? call->called(true) : call->caller(true);
++ TQPair<TraceFunction*,TraceFunction*> realP(toCallings ? f:realF,
++ toCallings ? realF:f);
++ GraphEdge& e = _edgeMap[realP];
++ if (e.call() == 0) {
++ e.setCall(call);
++ e.setCaller(realP.first);
++ e.setCalling(realP.second);
++ }
++ e.cost += cost;
++ e.count += count;
++ }
++
++ // - don't do a DFS on calls in recursion/cycle
++ if (call->inCycle()>0) continue;
++ if (call->isRecursion()) continue;
++
++ if (toCallings) {
++ GraphEdgeSet::Iterator it = n.callingSet.find(&e);
++ if (it == n.callingSet.end()) {
++ n.callings.append(&e);
++ n.callingSet.insert(&e, 1 );
++ }
++ }
++ else {
++ GraphEdgeSet::Iterator it = n.callerSet.find(&e);
++ if (it == n.callerSet.end()) {
++ n.callers.append(&e);
++ n.callerSet.insert(&e, 1 );
++ }
++ }
++
++ // if we just reached the call limit (=func limit by summing, do a DFS
++ // from here with full incl. cost because of previous cutoffs
++ if ((e.cost >= _realCallLimit) && (oldCost < _realCallLimit)) cost = e.cost;
++ if (cost < _realCallLimit) {
++ if (0) qDebug(" Edge Cutoff, limit not reached");
++ continue;
++ }
++
++ SubCost s;
++ if (call->inCycle())
++ s = f2->cycle()->inclusive()->subCost(_costType);
++ else
++ s = f2->inclusive()->subCost(_costType);
++ SubCost v = call->subCost(_costType);
++ buildGraph(f2, d+1, toCallings, factor * v / s);
++ }
++}
++
++
++//
++// PannerView
++//
++PannerView::PannerView(TQWidget * parent, const char * name)
++ : TQCanvasView(parent, name, WNoAutoErase | WStaticContents)
++{
++ _movingZoomRect = false;
++
++ // why doesn't this avoid flicker ?
++ viewport()->setBackgroundMode(TQt::NoBackground);
++ setBackgroundMode(TQt::NoBackground);
++}
++
++void PannerView::setZoomRect(TQRect r)
++{
++ TQRect oldRect = _zoomRect;
++ _zoomRect = r;
++ updateContents(oldRect);
++ updateContents(_zoomRect);
++}
++
++void PannerView::drawContents(TQPainter * p, int clipx, int clipy, int clipw, int cliph)
++{
++ // save/restore around TQCanvasView::drawContents seems to be needed
++ // for QT 3.0 to get the red rectangle drawn correct
++ p->save();
++ TQCanvasView::drawContents(p,clipx,clipy,clipw,cliph);
++ p->restore();
++ if (_zoomRect.isValid()) {
++ p->setPen(red.dark());
++ p->drawRect(_zoomRect);
++ p->setPen(red);
++ p->drawRect(TQRect(_zoomRect.x()+1, _zoomRect.y()+1,
++ _zoomRect.width()-2, _zoomRect.height()-2));
++ }
++}
++
++void PannerView::contentsMousePressEvent(TQMouseEvent* e)
++{
++ if (_zoomRect.isValid()) {
++ if (!_zoomRect.contains(e->pos()))
++ emit zoomRectMoved(e->pos().x() - _zoomRect.center().x(),
++ e->pos().y() - _zoomRect.center().y());
++
++ _movingZoomRect = true;
++ _lastPos = e->pos();
++ }
++}
++
++void PannerView::contentsMouseMoveEvent(TQMouseEvent* e)
++{
++ if (_movingZoomRect) {
++ emit zoomRectMoved(e->pos().x() - _lastPos.x(), e->pos().y() - _lastPos.y());
++ _lastPos = e->pos();
++ }
++}
++
++void PannerView::contentsMouseReleaseEvent(TQMouseEvent*)
++{
++ _movingZoomRect = false;
++ emit zoomRectMoveFinished();
++}
++
++
++
++
++
++//
++// CanvasNode
++//
++
++CanvasNode::CanvasNode(CallGraphView* v, GraphNode* n,
++ int x, int y, int w, int h, TQCanvas* c)
++ : TQCanvasRectangle(x, y, w, h, c), _node(n), _view(v)
++{
++ setPosition(0, DrawParams::TopCenter);
++ setPosition(1, DrawParams::BottomCenter);
++
++ updateGroup();
++
++ if (!_node || !_view) return;
++
++ if (_node->function())
++ setText(0, _node->function()->prettyName());
++
++ TraceCost* totalCost;
++ if (_view->topLevel()->showExpanded()) {
++ if (_view->activeFunction()) {
++ if (_view->activeFunction()->cycle())
++ totalCost = _view->activeFunction()->cycle()->inclusive();
++ else
++ totalCost = _view->activeFunction()->inclusive();
++ }
++ else
++ totalCost = (TraceCost*) _view->activeItem();
++ }
++ else
++ totalCost = _view->TraceItemView::data();
++ double total = totalCost->subCost(_view->costType());
++ double inclP = 100.0 * n->incl / total;
++ if (_view->topLevel()->showPercentage())
++ setText(1, TQString("%1 %")
++ .arg(inclP, 0, 'f', Configuration::percentPrecision()));
++ else
++ setText(1, SubCost(n->incl).pretty());
++ setPixmap(1, percentagePixmap(25,10,(int)(inclP+.5), TQt::blue, true));
++}
++
++void CanvasNode::setSelected(bool s)
++{
++ StoredDrawParams::setSelected(s);
++ update();
++}
++
++void CanvasNode::updateGroup()
++{
++ if (!_view || !_node) return;
++
++ TQColor c = Configuration::functionColor(_view->groupType(),
++ _node->function());
++ setBackColor(c);
++ update();
++}
++
++void CanvasNode::drawShape(TQPainter& p)
++{
++ TQRect r = rect(), origRect = r;
++
++ r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
++
++ RectDrawing d(r);
++ d.drawBack(&p, this);
++ r.setRect(r.x()+2, r.y()+2, r.width()-4, r.height()-4);
++
++ if (StoredDrawParams::selected() && _view->hasFocus()) {
++ _view->style().tqdrawPrimitive( TQStyle::PE_FocusRect, &p, r,
++ _view->colorGroup());
++ }
++
++ // draw afterwards to always get a frame even when zoomed
++ p.setPen(StoredDrawParams::selected() ? red : black);
++ p.drawRect(origRect);
++
++ d.setRect(r);
++ d.drawField(&p, 0, this);
++ d.drawField(&p, 1, this);
++}
++
++
++//
++// CanvasEdgeLabel
++//
++
++CanvasEdgeLabel::CanvasEdgeLabel(CallGraphView* v, CanvasEdge* ce,
++ int x, int y, int w, int h, TQCanvas* c)
++ : TQCanvasRectangle(x, y, w, h, c), _ce(ce), _view(v)
++{
++ GraphEdge* e = ce->edge();
++ if (!e) return;
++
++ setPosition(1, DrawParams::TopCenter);
++ setText(1, TQString("%1 x").arg(SubCost(e->count).pretty()));
++
++ setPosition(0, DrawParams::BottomCenter);
++
++ TraceCost* totalCost;
++ if (_view->topLevel()->showExpanded()) {
++ if (_view->activeFunction()) {
++ if (_view->activeFunction()->cycle())
++ totalCost = _view->activeFunction()->cycle()->inclusive();
++ else
++ totalCost = _view->activeFunction()->inclusive();
++ }
++ else
++ totalCost = (TraceCost*) _view->activeItem();
++ }
++ else
++ totalCost = _view->TraceItemView::data();
++ double total = totalCost->subCost(_view->costType());
++ double inclP = 100.0 * e->cost / total;
++ if (_view->topLevel()->showPercentage())
++ setText(0, TQString("%1 %")
++ .arg(inclP, 0, 'f', Configuration::percentPrecision()));
++ else
++ setText(0, SubCost(e->cost).pretty());
++ setPixmap(0, percentagePixmap(25,10,(int)(inclP+.5), TQt::blue, true));
++
++ if (e->call() && (e->call()->isRecursion() || e->call()->inCycle())) {
++ TQString icon = "undo";
++ KIconLoader* loader = KApplication::kApplication()->iconLoader();
++ TQPixmap p= loader->loadIcon(icon, KIcon::Small, 0,
++ KIcon::DefaultState, 0, true);
++ setPixmap(0, p);
++ }
++}
++
++void CanvasEdgeLabel::drawShape(TQPainter& p)
++{
++ TQRect r = rect();
++ //p.setPen(blue);
++ //p.drawRect(r);
++ RectDrawing d(r);
++ d.drawField(&p, 0, this);
++ d.drawField(&p, 1, this);
++}
++
++//
++// CanvasEdgeArrow
++
++CanvasEdgeArrow::CanvasEdgeArrow(CanvasEdge* ce, TQCanvas* c)
++ : TQCanvasPolygon(c), _ce(ce)
++{}
++
++void CanvasEdgeArrow::drawShape(TQPainter& p)
++{
++ if (_ce->isSelected()) p.setBrush(TQt::red);
++
++ TQCanvasPolygon::drawShape(p);
++}
++
++//
++// CanvasEdge
++//
++
++CanvasEdge::CanvasEdge(GraphEdge* e, TQCanvas* c)
++ : TQCanvasSpline(c), _edge(e)
++{
++ _label = 0;
++ _arrow = 0;
++}
++
++void CanvasEdge::setSelected(bool s)
++{
++ TQCanvasItem::setSelected(s);
++ update();
++ if (_arrow) _arrow->setSelected(s);
++}
++
++TQPointArray CanvasEdge::areaPoints() const
++{
++ int minX = poly[0].x(), minY = poly[0].y();
++ int maxX = minX, maxY = minY;
++ int i;
++
++ if (0) qDebug("CanvasEdge::areaPoints\n P 0: %d/%d", minX, minY);
++ int len = poly.count();
++ for (i=1;i<len;i++) {
++ if (poly[i].x() < minX) minX = poly[i].x();
++ if (poly[i].y() < minY) minY = poly[i].y();
++ if (poly[i].x() > maxX) maxX = poly[i].x();
++ if (poly[i].y() > maxY) maxY = poly[i].y();
++ if (0) qDebug(" P %d: %d/%d", i, poly[i].x(), poly[i].y());
++ }
++ TQPointArray a = poly.copy(), b = poly.copy();
++ if (minX == maxX) {
++ a.translate(-2, 0);
++ b.translate(2, 0);
++ }
++ else {
++ a.translate(0, -2);
++ b.translate(0, 2);
++ }
++ a.resize(2*len);
++ for (i=0;i<len;i++)
++ a[2 * len - 1 -i] = b[i];
++
++ if (0) {
++ qDebug(" Result:");
++ for (i=0;i<2*len;i++)
++ qDebug(" P %d: %d/%d", i, a[i].x(), a[i].y());
++ }
++
++ return a;
++}
++
++void CanvasEdge::drawShape(TQPainter& p)
++{
++ if (isSelected()) p.setPen(TQt::red);
++
++ p.drawPolyline(poly);
++}
++
++
++//
++// CanvasFrame
++//
++
++TQPixmap* CanvasFrame::_p = 0;
++
++CanvasFrame::CanvasFrame(CanvasNode* n, TQCanvas* c)
++ : TQCanvasRectangle(c)
++{
++ if (!_p) {
++
++ int d = 5;
++ float v1 = 130.0, v2 = 10.0, v = v1, f = 1.03;
++
++ // calculate pix size
++ TQRect r(0, 0, 30, 30);
++ while (v>v2) {
++ r.setRect(r.x()-d, r.y()-d, r.width()+2*d, r.height()+2*d);
++ v /= f;
++ }
++
++ _p = new TQPixmap(r.size());
++ _p->fill(TQt::white);
++ TQPainter p(_p);
++ p.setPen(TQt::NoPen);
++
++ r.moveBy(-r.x(), -r.y());
++
++ while (v<v1) {
++ v *= f;
++ p.setBrush(TQColor(265-(int)v, 265-(int)v, 265-(int)v));
++
++ p.drawRect(TQRect(r.x(), r.y(), r.width(), d));
++ p.drawRect(TQRect(r.x(), r.bottom()-d, r.width(), d));
++ p.drawRect(TQRect(r.x(), r.y()+d, d, r.height()-2*d));
++ p.drawRect(TQRect(r.right()-d, r.y()+d, d, r.height()-2*d));
++
++ r.setRect(r.x()+d, r.y()+d, r.width()-2*d, r.height()-2*d);
++ }
++ }
++
++ setSize(_p->width(), _p->height());
++ move(n->rect().center().x()-_p->width()/2,
++ n->rect().center().y()-_p->height()/2);
++}
++
++
++void CanvasFrame::drawShape(TQPainter& p)
++{
++ p.drawPixmap( int(x()), int(y()), *_p );
++}
++
++
++
++
++//
++// Tooltips for CallGraphView
++//
++
++class CallGraphTip: public TQToolTip
++{
++public:
++ CallGraphTip( TQWidget* p ):TQToolTip(p) {}
++
++protected:
++ void maybeTip( const TQPoint & );
++};
++
++void CallGraphTip::maybeTip( const TQPoint& pos )
++{
++ if (!parentWidget()->inherits( "CallGraphView" )) return;
++ CallGraphView* cgv = (CallGraphView*)parentWidget();
++
++ TQPoint cPos = cgv->viewportToContents(pos);
++
++ if (0) qDebug("CallGraphTip for (%d/%d) -> (%d/%d) ?",
++ pos.x(), pos.y(), cPos.x(), cPos.y());
++
++ TQCanvasItemList l = cgv->canvas()->collisions(cPos);
++ if (l.count() == 0) return;
++ TQCanvasItem* i = l.first();
++
++ if (i->rtti() == CANVAS_NODE) {
++ CanvasNode* cn = (CanvasNode*)i;
++ GraphNode* n = cn->node();
++ if (0) qDebug("CallGraphTip: Mouse on Node '%s'",
++ n->function()->prettyName().ascii());
++
++ TQString tipStr = TQString("%1 (%2)").arg(cn->text(0)).arg(cn->text(1));
++ TQPoint vPosTL = cgv->contentsToViewport(i->boundingRect().topLeft());
++ TQPoint vPosBR = cgv->contentsToViewport(i->boundingRect().bottomRight());
++ tip(TQRect(vPosTL, vPosBR), tipStr);
++
++ return;
++ }
++
++ // redirect from label / arrow to edge
++ if (i->rtti() == CANVAS_EDGELABEL)
++ i = ((CanvasEdgeLabel*)i)->canvasEdge();
++ if (i->rtti() == CANVAS_EDGEARROW)
++ i = ((CanvasEdgeArrow*)i)->canvasEdge();
++
++ if (i->rtti() == CANVAS_EDGE) {
++ CanvasEdge* ce = (CanvasEdge*)i;
++ GraphEdge* e = ce->edge();
++ if (0) qDebug("CallGraphTip: Mouse on Edge '%s'",
++ e->prettyName().ascii());
++
++ TQString tipStr;
++ if (!ce->label())
++ tipStr = e->prettyName();
++ else
++ tipStr = TQString("%1 (%2)")
++ .arg(ce->label()->text(0)).arg(ce->label()->text(1));
++ tip(TQRect(pos.x()-5,pos.y()-5,pos.x()+5,pos.y()+5), tipStr);
++ }
++}
++
++
++
++
++//
++// CallGraphView
++//
++CallGraphView::CallGraphView(TraceItemView* parentView,
++ TQWidget* parent, const char* name)
++ : TQCanvasView(parent, name), TraceItemView(parentView)
++{
++ _zoomPosition = DEFAULT_ZOOMPOS;
++ _lastAutoPosition = TopLeft;
++
++ _canvas = 0;
++ _xMargin = _yMargin = 0;
++ _completeView = new PannerView(this);
++ _cvZoom = 1;
++ _selectedNode = 0;
++ _selectedEdge = 0;
++
++ _exporter.setGraphOptions(this);
++
++ _completeView->setVScrollBarMode(TQScrollView::AlwaysOff);
++ _completeView->setHScrollBarMode(TQScrollView::AlwaysOff);
++ _completeView->raise();
++ _completeView->hide();
++
++ setFocusPolicy(TQ_StrongFocus);
++ setBackgroundMode(TQt::NoBackground);
++
++ connect(this, TQT_SIGNAL(contentsMoving(int,int)),
++ this, TQT_SLOT(contentsMovingSlot(int,int)));
++ connect(_completeView, TQT_SIGNAL(zoomRectMoved(int,int)),
++ this, TQT_SLOT(zoomRectMoved(int,int)));
++ connect(_completeView, TQT_SIGNAL(zoomRectMoveFinished()),
++ this, TQT_SLOT(zoomRectMoveFinished()));
++
++ TQWhatsThis::add( this, whatsThis() );
++
++ // tooltips...
++ _tip = new CallGraphTip(this);
++
++ _renderProcess = 0;
++ _prevSelectedNode = 0;
++ connect(&_renderTimer, TQT_SIGNAL(timeout()),
++ this, TQT_SLOT(showRenderWarning()));
++}
++
++CallGraphView::~CallGraphView()
++{
++ delete _completeView;
++ delete _tip;
++
++ if (_canvas) {
++ setCanvas(0);
++ delete _canvas;
++ }
++}
++
++TQString CallGraphView::whatsThis() const
++{
++ return i18n( "<b>Call Graph around active Function</b>"
++ "<p>Depending on configuration, this view shows "
++ "the call graph environment of the active function. "
++ "Note: the shown cost is <b>only</b> the cost which is "
++ "spent while the active function was actually running; "
++ "i.e. the cost shown for main() - if it's visible - should "
++ "be the same as the cost of the active function, as that's "
++ "the part of inclusive cost of main() spent while the active "
++ "function was running.</p>"
++ "<p>For cycles, blue call arrows indicate that this is an "
++ "artificial call added for correct drawing which "
++ "actually never happened.</p>"
++ "<p>If the graph is larger than the widget area, an overview "
++ "panner is shown in one edge. "
++ "There are similar visualization options to the "
++ "Call Treemap; the selected function is highlighted.<p>");
++}
++
++void CallGraphView::updateSizes(TQSize s)
++{
++ if (!_canvas) return;
++
++ if (s == TQSize(0,0)) s = size();
++
++ // the part of the canvas that should be visible
++ int cWidth = _canvas->width() - 2*_xMargin + 100;
++ int cHeight = _canvas->height() - 2*_yMargin + 100;
++
++ // hide birds eye view if no overview needed
++ if (!_data || !_activeItem ||
++ ((cWidth < s.width()) && cHeight < s.height())) {
++ _completeView->hide();
++ return;
++ }
++ _completeView->show();
++
++ // first, assume use of 1/3 of width/height (possible larger)
++ double zoom = .33 * s.width() / cWidth;
++ if (zoom * cHeight < .33 * s.height()) zoom = .33 * s.height() / cHeight;
++
++ // fit to widget size
++ if (cWidth * zoom > s.width()) zoom = s.width() / (double)cWidth;
++ if (cHeight * zoom > s.height()) zoom = s.height() / (double)cHeight;
++
++ // scale to never use full height/width
++ zoom = zoom * 3/4;
++
++ // at most a zoom of 1/3
++ if (zoom > .33) zoom = .33;
++
++ if (zoom != _cvZoom) {
++ _cvZoom = zoom;
++ if (0) qDebug("Canvas Size: %dx%d, Visible: %dx%d, Zoom: %f",
++ _canvas->width(), _canvas->height(),
++ cWidth, cHeight, zoom);
++
++ TQWMatrix wm;
++ wm.scale( zoom, zoom );
++ _completeView->setWorldMatrix(wm);
++
++ // make it a little bigger to compensate for widget frame
++ _completeView->resize(int(cWidth * zoom) + 4,
++ int(cHeight * zoom) + 4);
++
++ // update ZoomRect in completeView
++ contentsMovingSlot(contentsX(), contentsY());
++ }
++
++ _completeView->setContentsPos(int(zoom*(_xMargin-50)),
++ int(zoom*(_yMargin-50)));
++
++ int cvW = _completeView->width();
++ int cvH = _completeView->height();
++ int x = width()- cvW - verticalScrollBar()->width() -2;
++ int y = height()-cvH - horizontalScrollBar()->height() -2;
++ TQPoint oldZoomPos = _completeView->pos();
++ TQPoint newZoomPos = TQPoint(0,0);
++ ZoomPosition zp = _zoomPosition;
++ if (zp == Auto) {
++ TQPoint tl1Pos = viewportToContents(TQPoint(0,0));
++ TQPoint tl2Pos = viewportToContents(TQPoint(cvW,cvH));
++ TQPoint tr1Pos = viewportToContents(TQPoint(x,0));
++ TQPoint tr2Pos = viewportToContents(TQPoint(x+cvW,cvH));
++ TQPoint bl1Pos = viewportToContents(TQPoint(0,y));
++ TQPoint bl2Pos = viewportToContents(TQPoint(cvW,y+cvH));
++ TQPoint br1Pos = viewportToContents(TQPoint(x,y));
++ TQPoint br2Pos = viewportToContents(TQPoint(x+cvW,y+cvH));
++ int tlCols = _canvas->collisions(TQRect(tl1Pos,tl2Pos)).count();
++ int trCols = _canvas->collisions(TQRect(tr1Pos,tr2Pos)).count();
++ int blCols = _canvas->collisions(TQRect(bl1Pos,bl2Pos)).count();
++ int brCols = _canvas->collisions(TQRect(br1Pos,br2Pos)).count();
++ int minCols = tlCols;
++ zp = _lastAutoPosition;
++ switch(zp) {
++ case TopRight: minCols = trCols; break;
++ case BottomLeft: minCols = blCols; break;
++ case BottomRight: minCols = brCols; break;
++ default:
++ case TopLeft: minCols = tlCols; break;
++ }
++ if (minCols > tlCols) { minCols = tlCols; zp = TopLeft; }
++ if (minCols > trCols) { minCols = trCols; zp = TopRight; }
++ if (minCols > blCols) { minCols = blCols; zp = BottomLeft; }
++ if (minCols > brCols) { minCols = brCols; zp = BottomRight; }
++
++ _lastAutoPosition = zp;
++ }
++
++ switch(zp) {
++ case TopRight:
++ newZoomPos = TQPoint(x,0);
++ break;
++ case BottomLeft:
++ newZoomPos = TQPoint(0,y);
++ break;
++ case BottomRight:
++ newZoomPos = TQPoint(x,y);
++ break;
++ default:
++ break;
++ }
++ if (newZoomPos != oldZoomPos) _completeView->move(newZoomPos);
++}
++
++void CallGraphView::focusInEvent(TQFocusEvent*)
++{
++ if (!_canvas) return;
++
++ if (_selectedNode && _selectedNode->canvasNode()) {
++ _selectedNode->canvasNode()->setSelected(true); // requests item update
++ _canvas->update();
++ }
++}
++
++void CallGraphView::focusOutEvent(TQFocusEvent* e)
++{
++ // trigger updates as in focusInEvent
++ focusInEvent(e);
++}
++
++void CallGraphView::keyPressEvent(TQKeyEvent* e)
++{
++ if (!_canvas) {
++ e->ignore();
++ return;
++ }
++
++ if ((e->key() == Key_Return) ||
++ (e->key() == Key_Space)) {
++ if (_selectedNode)
++ activated(_selectedNode->function());
++ else if (_selectedEdge && _selectedEdge->call())
++ activated(_selectedEdge->call());
++ return;
++ }
++
++ // move selected node/edge
++ if (!(e->state() & (ShiftButton | ControlButton)) &&
++ (_selectedNode || _selectedEdge) &&
++ ((e->key() == Key_Up) ||
++ (e->key() == Key_Down) ||
++ (e->key() == Key_Left) ||
++ (e->key() == Key_Right))) {
++
++ TraceFunction* f = 0;
++ TraceCall* c = 0;
++
++ // rotate arrow key meaning for LeftRight layout
++ int key = e->key();
++ if (_layout == LeftRight) {
++ switch(key) {
++ case Key_Up: key = Key_Left; break;
++ case Key_Down: key = Key_Right; break;
++ case Key_Left: key = Key_Up; break;
++ case Key_Right: key = Key_Down; break;
++ default: break;
++ }
++ }
++
++ if (_selectedNode) {
++ if (key == Key_Up) c = _selectedNode->visibleCaller();
++ if (key == Key_Down) c = _selectedNode->visibleCalling();
++ if (key == Key_Right) f = _selectedNode->nextVisible();
++ if (key == Key_Left) f = _selectedNode->priorVisible();
++ }
++ else if (_selectedEdge) {
++ if (key == Key_Up) f = _selectedEdge->visibleCaller();
++ if (key == Key_Down) f = _selectedEdge->visibleCalling();
++ if (key == Key_Right) c = _selectedEdge->nextVisible();
++ if (key == Key_Left) c = _selectedEdge->priorVisible();
++ }
++
++ if (c) selected(c);
++ if (f) selected(f);
++ return;
++ }
++
++ // move canvas...
++ if (e->key() == Key_Home)
++ scrollBy(-_canvas->width(),0);
++ else if (e->key() == Key_End)
++ scrollBy(_canvas->width(),0);
++ else if (e->key() == Key_Prior)
++ scrollBy(0,-visibleHeight()/2);
++ else if (e->key() == Key_Next)
++ scrollBy(0,visibleHeight()/2);
++ else if (e->key() == Key_Left)
++ scrollBy(-visibleWidth()/10,0);
++ else if (e->key() == Key_Right)
++ scrollBy(visibleWidth()/10,0);
++ else if (e->key() == Key_Down)
++ scrollBy(0,visibleHeight()/10);
++ else if (e->key() == Key_Up)
++ scrollBy(0,-visibleHeight()/10);
++ else e->ignore();
++}
++
++void CallGraphView::resizeEvent(TQResizeEvent* e)
++{
++ TQCanvasView::resizeEvent(e);
++ if (_canvas) updateSizes(e->size());
++}
++
++TraceItem* CallGraphView::canShow(TraceItem* i)
++{
++ if (i) {
++ switch(i->type()) {
++ case TraceItem::Function:
++ case TraceItem::FunctionCycle:
++ case TraceItem::Call:
++ return i;
++ default:
++ break;
++ }
++ }
++ return 0;
++}
++
++void CallGraphView::doUpdate(int changeType)
++{
++ // Special case ?
++ if (changeType == costType2Changed) return;
++
++ if (changeType == selectedItemChanged) {
++ if (!_canvas) return;
++
++ if (!_selectedItem) return;
++
++ GraphNode* n = 0;
++ GraphEdge* e = 0;
++ if ((_selectedItem->type() == TraceItem::Function) ||
++ (_selectedItem->type() == TraceItem::FunctionCycle)) {
++ n = _exporter.node((TraceFunction*)_selectedItem);
++ if (n == _selectedNode) return;
++ }
++ else if (_selectedItem->type() == TraceItem::Call) {
++ TraceCall* c = (TraceCall*)_selectedItem;
++ e = _exporter.edge(c->caller(false), c->called(false));
++ if (e == _selectedEdge) return;
++ }
++
++ // unselected any selected item
++ if (_selectedNode && _selectedNode->canvasNode()) {
++ _selectedNode->canvasNode()->setSelected(false);
++ }
++ _selectedNode = 0;
++ if (_selectedEdge && _selectedEdge->canvasEdge()) {
++ _selectedEdge->canvasEdge()->setSelected(false);
++ }
++ _selectedEdge = 0;
++
++ // select
++ CanvasNode* sNode = 0;
++ if (n && n->canvasNode()) {
++ _selectedNode = n;
++ _selectedNode->canvasNode()->setSelected(true);
++
++ if (!_isMoving) sNode = _selectedNode->canvasNode();
++ }
++ if (e && e->canvasEdge()) {
++ _selectedEdge = e;
++ _selectedEdge->canvasEdge()->setSelected(true);
++
++#if 0 // don't change position when selecting edge
++ if (!_isMoving) {
++ if (_selectedEdge->fromNode())
++ sNode = _selectedEdge->fromNode()->canvasNode();
++ if (!sNode && _selectedEdge->toNode())
++ sNode = _selectedEdge->toNode()->canvasNode();
++ }
++#endif
++ }
++ if (sNode) {
++ double x = sNode->x() + sNode->width()/2;
++ double y = sNode->y() + sNode->height()/2;
++
++ ensureVisible(int(x),int(y),
++ sNode->width()/2+50, sNode->height()/2+50);
++ }
++
++ _canvas->update();
++ return;
++ }
++
++ if (changeType == groupTypeChanged) {
++ if (!_canvas) return;
++
++ if (_clusterGroups) {
++ refresh();
++ return;
++ }
++
++ TQCanvasItemList l = _canvas->allItems();
++ TQCanvasItemList::iterator it;
++ for (it = l.begin();it != l.end(); ++it)
++ if ((*it)->rtti() == CANVAS_NODE)
++ ((CanvasNode*) (*it))->updateGroup();
++
++ _canvas->update();
++ return;
++ }
++
++ if (changeType & dataChanged) {
++ // invalidate old selection and graph part
++ _exporter.reset(_data, _activeItem, _costType, _groupType);
++ _selectedNode = 0;
++ _selectedEdge = 0;
++ }
++
++ refresh();
++}
++
++void CallGraphView::clear()
++{
++ if (!_canvas) return;
++
++ delete _canvas;
++ _canvas = 0;
++ _completeView->setCanvas(0);
++ setCanvas(0);
++}
++
++void CallGraphView::showText(TQString s)
++{
++ clear();
++ _renderTimer.stop();
++
++ _canvas = new TQCanvas(TQApplication::desktop()->width(),
++ TQApplication::desktop()->height());
++
++ TQCanvasText* t = new TQCanvasText(s, _canvas);
++ t->move(5, 5);
++ t->show();
++ center(0,0);
++ setCanvas(_canvas);
++ _canvas->update();
++ _completeView->hide();
++}
++
++void CallGraphView::showRenderWarning()
++{
++ TQString s;
++
++ if (_renderProcess)
++ s =i18n("Warning: a long lasting graph layouting is in progress.\n"
++ "Reduce node/edge limits for speedup.\n");
++ else
++ s = i18n("Layouting stopped.\n");
++
++ s.append(i18n("The call graph has %1 nodes and %2 edges.\n")
++ .arg(_exporter.nodeCount())
++ .arg(_exporter.edgeCount()));
++
++ showText(s);
++}
++
++void CallGraphView::stopRendering()
++{
++ if (!_renderProcess) return;
++
++ _renderProcess->kill();
++ delete _renderProcess;
++ _renderProcess = 0;
++ _unparsedOutput = TQString();
++
++ _renderTimer.start(200, true);
++}
++
++void CallGraphView::refresh()
++{
++ // trigger start of background rendering
++ if (_renderProcess) stopRendering();
++
++ // we want to keep a selected node item at the same global position
++ _prevSelectedNode = _selectedNode;
++ _prevSelectedPos = TQPoint(-1,-1);
++ if (_selectedNode) {
++ TQPoint center = _selectedNode->canvasNode()->boundingRect().center();
++ _prevSelectedPos = contentsToViewport(center);
++ }
++
++ if (!_data || !_activeItem) {
++ showText(i18n("No item activated for which to draw the call graph."));
++ return;
++ }
++
++ TraceItem::CostType t = _activeItem->type();
++ switch(t) {
++ case TraceItem::Function:
++ case TraceItem::FunctionCycle:
++ case TraceItem::Call:
++ break;
++ default:
++ showText(i18n("No call graph can be drawn for the active item."));
++ return;
++ }
++
++ if (1) kdDebug() << "CallGraphView::refresh" << endl;
++
++ _selectedNode = 0;
++ _selectedEdge = 0;
++ _exporter.reset(_data, _activeItem, _costType, _groupType);
++ _exporter.writeDot();
++
++ _renderProcess = new TQProcess(TQT_TQOBJECT(this));
++ if (_layout == GraphOptions::Circular)
++ _renderProcess->addArgument( "twopi" );
++ else
++ _renderProcess->addArgument( "dot" );
++ _renderProcess->addArgument(_exporter.filename());
++ _renderProcess->addArgument( "-Tplain" );
++
++ connect( _renderProcess, TQT_SIGNAL(readyReadStdout()),
++ this, TQT_SLOT(readDotOutput()) );
++ connect( _renderProcess, TQT_SIGNAL(processExited()),
++ this, TQT_SLOT(dotExited()) );
++
++ if (1) kdDebug() << "Running '"
++ << _renderProcess->arguments().join(" ")
++ << "'..." << endl;
++
++ if ( !_renderProcess->start() ) {
++ TQString e = i18n("No call graph is available because the following\n"
++ "command cannot be run:\n'%1'\n")
++ .arg(_renderProcess->arguments().join(" "));
++ e += i18n("Please check that 'dot' is installed (package GraphViz).");
++ showText(e);
++
++ delete _renderProcess;
++ _renderProcess = 0;
++
++ return;
++ }
++
++ _unparsedOutput = TQString();
++
++ // layouting of more than seconds is dubious
++ _renderTimer.start(1000, true);
++}
++
++void CallGraphView::readDotOutput()
++{
++ _unparsedOutput.append( _renderProcess->readStdout() );
++}
++
++void CallGraphView::dotExited()
++{
++ TQString line, cmd;
++ CanvasNode *rItem;
++ TQCanvasEllipse* eItem;
++ CanvasEdge* sItem;
++ CanvasEdgeLabel* lItem;
++ TQTextStream* dotStream;
++ double scale = 1.0, scaleX = 1.0, scaleY = 1.0;
++ double dotWidth, dotHeight;
++ GraphNode* activeNode = 0;
++ GraphEdge* activeEdge = 0;
++
++ _renderTimer.stop();
++ viewport()->setUpdatesEnabled(false);
++ clear();
++ dotStream = new TQTextStream(_unparsedOutput, IO_ReadOnly);
++
++ int lineno = 0;
++ while (1) {
++ line = dotStream->readLine();
++ if (line.isNull()) break;
++ lineno++;
++ if (line.isEmpty()) continue;
++
++ TQTextStream lineStream(line, IO_ReadOnly);
++ lineStream >> cmd;
++
++ if (0) qDebug("%s:%d - line '%s', cmd '%s'",
++ _exporter.filename().ascii(), lineno,
++ line.ascii(), cmd.ascii());
++
++ if (cmd == "stop") break;
++
++ if (cmd == "graph") {
++ TQString dotWidthString, dotHeightString;
++ lineStream >> scale >> dotWidthString >> dotHeightString;
++ dotWidth = dotWidthString.toDouble();
++ dotHeight = dotHeightString.toDouble();
++
++ if (_detailLevel == 0) { scaleX = scale * 70; scaleY = scale * 40; }
++ else if (_detailLevel == 1) { scaleX = scale * 80; scaleY = scale * 70; }
++ else { scaleX = scale * 60; scaleY = scale * 100; }
++
++ if (!_canvas) {
++ int w = (int)(scaleX * dotWidth);
++ int h = (int)(scaleY * dotHeight);
++
++ // We use as minimum canvas size the desktop size.
++ // Otherwise, the canvas would have to be resized on widget resize.
++ _xMargin = 50;
++ if (w < TQApplication::desktop()->width())
++ _xMargin += (TQApplication::desktop()->width()-w)/2;
++
++ _yMargin = 50;
++ if (h < TQApplication::desktop()->height())
++ _yMargin += (TQApplication::desktop()->height()-h)/2;
++
++ _canvas = new TQCanvas(int(w+2*_xMargin), int(h+2*_yMargin));
++
++#if DEBUG_GRAPH
++ kdDebug() << _exporter.filename().ascii() << ":" << lineno
++ << " - graph (" << dotWidth << " x " << dotHeight
++ << ") => (" << w << " x " << h << ")" << endl;
++#endif
++ }
++ else
++ kdWarning() << "Ignoring 2nd 'graph' from dot ("
++ << _exporter.filename() << ":" << lineno << ")" << endl;
++ continue;
++ }
++
++ if ((cmd != "node") && (cmd != "edge")) {
++ kdWarning() << "Ignoring unknown command '" << cmd << "' from dot ("
++ << _exporter.filename() << ":" << lineno << ")" << endl;
++ continue;
++ }
++
++ if (_canvas == 0) {
++ kdWarning() << "Ignoring '" << cmd << "' without 'graph' from dot ("
++ << _exporter.filename() << ":" << lineno << ")" << endl;
++ continue;
++ }
++
++ if (cmd == "node") {
++ // x, y are centered in node
++ TQString nodeName, label, nodeX, nodeY, nodeWidth, nodeHeight;
++ double x, y, width, height;
++ lineStream >> nodeName >> nodeX >> nodeY >> nodeWidth >> nodeHeight;
++ x = nodeX.toDouble();
++ y = nodeY.toDouble();
++ width = nodeWidth.toDouble();
++ height = nodeHeight.toDouble();
++
++ GraphNode* n = _exporter.node(_exporter.toFunc(nodeName));
++
++ int xx = (int)(scaleX * x + _xMargin);
++ int yy = (int)(scaleY * (dotHeight - y) + _yMargin);
++ int w = (int)(scaleX * width);
++ int h = (int)(scaleY * height);
++
++#if DEBUG_GRAPH
++ kdDebug() << _exporter.filename() << ":" << lineno
++ << " - node '" << nodeName << "' ( "
++ << x << "/" << y << " - "
++ << width << "x" << height << " ) => ("
++ << xx-w/2 << "/" << yy-h/2 << " - "
++ << w << "x" << h << ")" << endl;
++#endif
++
++
++ // Unnamed nodes with collapsed edges (with 'R' and 'S')
++ if (nodeName[0] == 'R' || nodeName[0] == 'S') {
++ w = 10, h = 10;
++ eItem = new TQCanvasEllipse(w, h, _canvas);
++ eItem->move(xx, yy);
++ eItem->setBrush(TQt::gray);
++ eItem->setZ(1.0);
++ eItem->show();
++ continue;
++ }
++
++ if (!n) {
++ qDebug("Warning: Unknown function '%s' ?!", nodeName.ascii());
++ continue;
++ }
++ n->setVisible(true);
++
++ rItem = new CanvasNode(this, n, xx-w/2, yy-h/2, w, h, _canvas);
++ n->setCanvasNode(rItem);
++
++ if (n) {
++ if (n->function() == activeItem()) activeNode = n;
++ if (n->function() == selectedItem()) _selectedNode = n;
++ rItem->setSelected(n == _selectedNode);
++ }
++
++ rItem->setZ(1.0);
++ rItem->show();
++
++ continue;
++ }
++
++ // edge
++
++ TQString node1Name, node2Name, label, edgeX, edgeY;
++ double x, y;
++ TQPointArray pa;
++ int points, i;
++ lineStream >> node1Name >> node2Name >> points;
++
++ GraphEdge* e = _exporter.edge(_exporter.toFunc(node1Name),
++ _exporter.toFunc(node2Name));
++ if (!e) {
++ kdWarning() << "Unknown edge '" << node1Name << "'-'"
++ << node2Name << "' from dot ("
++ << _exporter.filename() << ":" << lineno << ")" << endl;
++ continue;
++ }
++ e->setVisible(true);
++ if (e->fromNode()) e->fromNode()->callings.append(e);
++ if (e->toNode()) e->toNode()->callers.append(e);
++
++ if (0) qDebug(" Edge with %d points:", points);
++
++ pa.resize(points);
++ for (i=0;i<points;i++) {
++ if (lineStream.atEnd()) break;
++ lineStream >> edgeX >> edgeY;
++ x = edgeX.toDouble();
++ y = edgeY.toDouble();
++
++ int xx = (int)(scaleX * x + _xMargin);
++ int yy = (int)(scaleY * (dotHeight - y) + _yMargin);
++
++ if (0) qDebug(" P %d: ( %f / %f ) => ( %d / %d)",
++ i, x, y, xx, yy);
++
++ pa.setPoint(i, xx, yy);
++ }
++ if (i < points) {
++ qDebug("CallGraphView: Can't read %d spline points (%s:%d)",
++ points, _exporter.filename().ascii(), lineno);
++ continue;
++ }
++
++ // calls into/out of cycles are special: make them blue
++ TQColor arrowColor = TQt::black;
++ TraceFunction* caller = e->fromNode() ? e->fromNode()->function() : 0;
++ TraceFunction* called = e->toNode() ? e->toNode()->function() : 0;
++ if ( (caller && (caller->cycle() == caller)) ||
++ (called && (called->cycle() == called)) ) arrowColor = TQt::blue;
++
++ sItem = new CanvasEdge(e, _canvas);
++ e->setCanvasEdge(sItem);
++ sItem->setControlPoints(pa, false);
++ sItem->setPen(TQPen(arrowColor, 1 /*(int)log(log(e->cost))*/ ));
++ sItem->setZ(0.5);
++ sItem->show();
++
++ if (e->call() == selectedItem()) _selectedEdge = e;
++ if (e->call() == activeItem()) activeEdge = e;
++ sItem->setSelected(e == _selectedEdge);
++
++ // Arrow head
++ TQPoint arrowDir;
++ int indexHead = -1;
++
++ // check if head is at start of spline...
++ // this is needed because dot always gives points from top to bottom
++ CanvasNode* fromNode = e->fromNode() ? e->fromNode()->canvasNode() : 0;
++ if (fromNode) {
++ TQPoint toCenter = fromNode->rect().center();
++ int dx0 = pa.point(0).x() - toCenter.x();
++ int dy0 = pa.point(0).y() - toCenter.y();
++ int dx1 = pa.point(points-1).x() - toCenter.x();
++ int dy1 = pa.point(points-1).y() - toCenter.y();
++ if (dx0*dx0+dy0*dy0 > dx1*dx1+dy1*dy1) {
++ // start of spline is nearer to call target node
++ indexHead=-1;
++ while(arrowDir.isNull() && (indexHead<points-2)) {
++ indexHead++;
++ arrowDir = pa.point(indexHead) - pa.point(indexHead+1);
++ }
++ }
++ }
++
++ if (arrowDir.isNull()) {
++ indexHead = points;
++ // sometimes the last spline points from dot are the same...
++ while(arrowDir.isNull() && (indexHead>1)) {
++ indexHead--;
++ arrowDir = pa.point(indexHead) - pa.point(indexHead-1);
++ }
++ }
++
++ if (!arrowDir.isNull()) {
++ // arrow around pa.point(indexHead) with direction arrowDir
++ arrowDir *= 10.0/sqrt(double(arrowDir.x()*arrowDir.x() +
++ arrowDir.y()*arrowDir.y()));
++ TQPointArray a(3);
++ a.setPoint(0, pa.point(indexHead) + arrowDir);
++ a.setPoint(1, pa.point(indexHead) + TQPoint(arrowDir.y()/2,
++ -arrowDir.x()/2));
++ a.setPoint(2, pa.point(indexHead) + TQPoint(-arrowDir.y()/2,
++ arrowDir.x()/2));
++
++ if (0) qDebug(" Arrow: ( %d/%d, %d/%d, %d/%d)",
++ a.point(0).x(), a.point(0).y(),
++ a.point(1).x(), a.point(1).y(),
++ a.point(2).x(), a.point(2).y());
++
++ CanvasEdgeArrow* aItem = new CanvasEdgeArrow(sItem,_canvas);
++ aItem->setPoints(a);
++ aItem->setBrush(arrowColor);
++ aItem->setZ(1.5);
++ aItem->show();
++
++ sItem->setArrow(aItem);
++ }
++
++ if (lineStream.atEnd()) continue;
++
++ // parse quoted label
++ TQChar c;
++ lineStream >> c;
++ while (c.isSpace()) lineStream >> c;
++ if (c != '\"') {
++ lineStream >> label;
++ label = c + label;
++ }
++ else {
++ lineStream >> c;
++ while(!c.isNull() && (c != '\"')) {
++ //if (c == '\\') lineStream >> c;
++
++ label += c;
++ lineStream >> c;
++ }
++ }
++ lineStream >> edgeX >> edgeY;
++ x = edgeX.toDouble();
++ y = edgeY.toDouble();
++
++ int xx = (int)(scaleX * x + _xMargin);
++ int yy = (int)(scaleY * (dotHeight - y) + _yMargin);
++
++ if (0) qDebug(" Label '%s': ( %f / %f ) => ( %d / %d)",
++ label.ascii(), x, y, xx, yy);
++
++ // Fixed Dimensions for Label: 100 x 40
++ int w = 100;
++ int h = _detailLevel * 20;
++ lItem = new CanvasEdgeLabel(this, sItem, xx-w/2, yy-h/2, w, h, _canvas);
++ // edge labels above nodes
++ lItem->setZ(1.5);
++ sItem->setLabel(lItem);
++ if (h>0) lItem->show();
++
++ }
++ delete dotStream;
++
++ // for keyboard navigation
++ // TODO: Edge sorting. Better keep left-to-right edge order from dot now
++ // _exporter.sortEdges();
++
++ if (!_canvas) {
++ _canvas = new TQCanvas(size().width(),size().height());
++ TQString s = i18n("Error running the graph layouting tool.\n");
++ s += i18n("Please check that 'dot' is installed (package GraphViz).");
++ TQCanvasText* t = new TQCanvasText(s, _canvas);
++ t->move(5, 5);
++ t->show();
++ center(0,0);
++ }
++ else if (!activeNode && !activeEdge) {
++ TQString s = i18n("There is no call graph available for function\n"
++ "\t'%1'\n"
++ "because it has no cost of the selected event type.");
++ TQCanvasText* t = new TQCanvasText(s.arg(_activeItem->name()), _canvas);
++ // t->setTextFlags(TQt::AlignHCenter | TQt::AlignVCenter);
++ t->move(5,5);
++ t->show();
++ center(0,0);
++ }
++
++ _completeView->setCanvas(_canvas);
++ setCanvas(_canvas);
++
++ // if we don't have a selection, or the old selection is not
++ // in visible graph, make active function selected for this view
++ if ((!_selectedNode || !_selectedNode->canvasNode()) &&
++ (!_selectedEdge || !_selectedEdge->canvasEdge())) {
++ if (activeNode) {
++ _selectedNode = activeNode;
++ _selectedNode->canvasNode()->setSelected(true);
++ }
++ else if (activeEdge) {
++ _selectedEdge = activeEdge;
++ _selectedEdge->canvasEdge()->setSelected(true);
++ }
++ }
++
++ CanvasNode* sNode = 0;
++ if (_selectedNode)
++ sNode = _selectedNode->canvasNode();
++ else if (_selectedEdge) {
++ if (_selectedEdge->fromNode())
++ sNode = _selectedEdge->fromNode()->canvasNode();
++ if (!sNode && _selectedEdge->toNode())
++ sNode = _selectedEdge->toNode()->canvasNode();
++ }
++ if (sNode) {
++ int x = int(sNode->x() + sNode->width()/2);
++ int y = int(sNode->y() + sNode->height()/2);
++
++ if (_prevSelectedNode) {
++ if (rect().contains(_prevSelectedPos))
++ setContentsPos(x-_prevSelectedPos.x(),
++ y-_prevSelectedPos.y());
++ else
++ ensureVisible(x,y,
++ sNode->width()/2+50, sNode->height()/2+50);
++ }
++ else center(x,y);
++ }
++
++ if (activeNode) {
++ CanvasNode* cn = activeNode->canvasNode();
++ CanvasFrame* f = new CanvasFrame(cn, _canvas);
++ f->setZ(-1);
++ f->show();
++ }
++
++ _cvZoom = 0;
++ updateSizes();
++
++ _canvas->update();
++ viewport()->setUpdatesEnabled(true);
++
++ delete _renderProcess;
++ _renderProcess = 0;
++}
++
++void CallGraphView::contentsMovingSlot(int x, int y)
++{
++ TQRect z(int(x * _cvZoom), int(y * _cvZoom),
++ int(visibleWidth() * _cvZoom)-1, int(visibleHeight() * _cvZoom)-1);
++ if (0) qDebug("moving: (%d,%d) => (%d/%d - %dx%d)",
++ x, y, z.x(), z.y(), z.width(), z.height());
++ _completeView->setZoomRect(z);
++}
++
++void CallGraphView::zoomRectMoved(int dx, int dy)
++{
++ if (leftMargin()>0) dx = 0;
++ if (topMargin()>0) dy = 0;
++ scrollBy(int(dx/_cvZoom),int(dy/_cvZoom));
++}
++
++void CallGraphView::zoomRectMoveFinished()
++{
++ if (_zoomPosition == Auto) updateSizes();
++}
++
++void CallGraphView::contentsMousePressEvent(TQMouseEvent* e)
++{
++ // clicking on the viewport sets focus
++ setFocus();
++
++ _isMoving = true;
++
++ TQCanvasItemList l = canvas()->collisions(e->pos());
++ if (l.count()>0) {
++ TQCanvasItem* i = l.first();
++
++ if (i->rtti() == CANVAS_NODE) {
++ GraphNode* n = ((CanvasNode*)i)->node();
++ if (0) qDebug("CallGraphView: Got Node '%s'",
++ n->function()->prettyName().ascii());
++
++ selected(n->function());
++ }
++
++ // redirect from label / arrow to edge
++ if (i->rtti() == CANVAS_EDGELABEL)
++ i = ((CanvasEdgeLabel*)i)->canvasEdge();
++ if (i->rtti() == CANVAS_EDGEARROW)
++ i = ((CanvasEdgeArrow*)i)->canvasEdge();
++
++ if (i->rtti() == CANVAS_EDGE) {
++ GraphEdge* e = ((CanvasEdge*)i)->edge();
++ if (0) qDebug("CallGraphView: Got Edge '%s'",
++ e->prettyName().ascii());
++
++ if (e->call()) selected(e->call());
++ }
++ }
++ _lastPos = e->globalPos();
++}
++
++void CallGraphView::contentsMouseMoveEvent(TQMouseEvent* e)
++{
++ if (_isMoving) {
++ int dx = e->globalPos().x() - _lastPos.x();
++ int dy = e->globalPos().y() - _lastPos.y();
++ scrollBy(-dx, -dy);
++ _lastPos = e->globalPos();
++ }
++}
++
++void CallGraphView::contentsMouseReleaseEvent(TQMouseEvent*)
++{
++ _isMoving = false;
++ if (_zoomPosition == Auto) updateSizes();
++}
++
++void CallGraphView::contentsMouseDoubleClickEvent(TQMouseEvent* e)
++{
++ TQCanvasItemList l = canvas()->collisions(e->pos());
++ if (l.count() == 0) return;
++ TQCanvasItem* i = l.first();
++
++ if (i->rtti() == CANVAS_NODE) {
++ GraphNode* n = ((CanvasNode*)i)->node();
++ if (0) qDebug("CallGraphView: Double Clicked on Node '%s'",
++ n->function()->prettyName().ascii());
++
++ activated(n->function());
++ }
++
++ // redirect from label / arrow to edge
++ if (i->rtti() == CANVAS_EDGELABEL)
++ i = ((CanvasEdgeLabel*)i)->canvasEdge();
++ if (i->rtti() == CANVAS_EDGEARROW)
++ i = ((CanvasEdgeArrow*)i)->canvasEdge();
++
++ if (i->rtti() == CANVAS_EDGE) {
++ GraphEdge* e = ((CanvasEdge*)i)->edge();
++ if (e->call()) {
++ if (0) qDebug("CallGraphView: Double Clicked On Edge '%s'",
++ e->call()->prettyName().ascii());
++
++ activated(e->call());
++ }
++ }
++}
++
++void CallGraphView::contentsContextMenuEvent(TQContextMenuEvent* e)
++{
++ TQCanvasItemList l = canvas()->collisions(e->pos());
++ TQCanvasItem* i = (l.count() == 0) ? 0 : l.first();
++
++ TQPopupMenu popup;
++ TraceFunction *f = 0, *cycle = 0;
++ TraceCall* c = 0;
++
++ if (i) {
++ if (i->rtti() == CANVAS_NODE) {
++ GraphNode* n = ((CanvasNode*)i)->node();
++ if (0) qDebug("CallGraphView: Menu on Node '%s'",
++ n->function()->prettyName().ascii());
++ f = n->function();
++ cycle = f->cycle();
++
++ TQString name = f->prettyName();
++ popup.insertItem(i18n("Go to '%1'")
++ .arg(Configuration::shortenSymbol(name)), 93);
++ if (cycle && (cycle != f)) {
++ name = Configuration::shortenSymbol(cycle->prettyName());
++ popup.insertItem(i18n("Go to '%1'").arg(name), 94);
++ }
++ popup.insertSeparator();
++ }
++
++ // redirect from label / arrow to edge
++ if (i->rtti() == CANVAS_EDGELABEL)
++ i = ((CanvasEdgeLabel*)i)->canvasEdge();
++ if (i->rtti() == CANVAS_EDGEARROW)
++ i = ((CanvasEdgeArrow*)i)->canvasEdge();
++
++ if (i->rtti() == CANVAS_EDGE) {
++ GraphEdge* e = ((CanvasEdge*)i)->edge();
++ if (0) qDebug("CallGraphView: Menu on Edge '%s'",
++ e->prettyName().ascii());
++ c = e->call();
++ if (c) {
++ TQString name = c->prettyName();
++ popup.insertItem(i18n("Go to '%1'")
++ .arg(Configuration::shortenSymbol(name)), 95);
++
++ popup.insertSeparator();
++ }
++ }
++ }
++
++ if (_renderProcess) {
++ popup.insertItem(i18n("Stop Layouting"), 999);
++ popup.insertSeparator();
++ }
++
++ addGoMenu(&popup);
++ popup.insertSeparator();
++
++ TQPopupMenu epopup;
++ epopup.insertItem(i18n("As PostScript"), 201);
++ epopup.insertItem(i18n("As Image ..."), 202);
++
++ popup.insertItem(i18n("Export Graph"), &epopup, 200);
++ popup.insertSeparator();
++
++ TQPopupMenu gpopup1;
++ gpopup1.setCheckable(true);
++ gpopup1.insertItem(i18n("Unlimited"), 100);
++ gpopup1.setItemEnabled(100, (_funcLimit>0.005));
++ gpopup1.insertSeparator();
++ gpopup1.insertItem(i18n("None"), 101);
++ gpopup1.insertItem(i18n("max. 2"), 102);
++ gpopup1.insertItem(i18n("max. 5"), 103);
++ gpopup1.insertItem(i18n("max. 10"), 104);
++ gpopup1.insertItem(i18n("max. 15"), 105);
++ if (_maxCallerDepth<-1) _maxCallerDepth=-1;
++ switch(_maxCallerDepth) {
++ case -1: gpopup1.setItemChecked(100,true); break;
++ case 0: gpopup1.setItemChecked(101,true); break;
++ case 2: gpopup1.setItemChecked(102,true); break;
++ case 5: gpopup1.setItemChecked(103,true); break;
++ case 10: gpopup1.setItemChecked(104,true); break;
++ case 15: gpopup1.setItemChecked(105,true); break;
++ default:
++ gpopup1.insertItem(i18n("< %1").arg(_maxCallerDepth), 106);
++ gpopup1.setItemChecked(106,true); break;
++ }
++
++ TQPopupMenu gpopup2;
++ gpopup2.setCheckable(true);
++ gpopup2.insertItem(i18n("Unlimited"), 110);
++ gpopup2.setItemEnabled(110, (_funcLimit>0.005));
++ gpopup2.insertSeparator();
++ gpopup2.insertItem(i18n("None"), 111);
++ gpopup2.insertItem(i18n("max. 2"), 112);
++ gpopup2.insertItem(i18n("max. 5"), 113);
++ gpopup2.insertItem(i18n("max. 10"), 114);
++ gpopup2.insertItem(i18n("max. 15"), 115);
++ if (_maxCallingDepth<-1) _maxCallingDepth=-1;
++ switch(_maxCallingDepth) {
++ case -1: gpopup2.setItemChecked(110,true); break;
++ case 0: gpopup2.setItemChecked(111,true); break;
++ case 2: gpopup2.setItemChecked(112,true); break;
++ case 5: gpopup2.setItemChecked(113,true); break;
++ case 10: gpopup2.setItemChecked(114,true); break;
++ case 15: gpopup2.setItemChecked(115,true); break;
++ default:
++ gpopup2.insertItem(i18n("< %1").arg(_maxCallingDepth), 116);
++ gpopup2.setItemChecked(116,true); break;
++ }
++
++ TQPopupMenu gpopup3;
++ gpopup3.setCheckable(true);
++ gpopup3.insertItem(i18n("No Minimum"), 120);
++ gpopup3.setItemEnabled(120,
++ (_maxCallerDepth>=0) && (_maxCallingDepth>=0));
++ gpopup3.insertSeparator();
++ gpopup3.insertItem(i18n("50 %"), 121);
++ gpopup3.insertItem(i18n("20 %"), 122);
++ gpopup3.insertItem(i18n("10 %"), 123);
++ gpopup3.insertItem(i18n("5 %"), 124);
++ gpopup3.insertItem(i18n("3 %"), 125);
++ gpopup3.insertItem(i18n("2 %"), 126);
++ gpopup3.insertItem(i18n("1.5 %"), 127);
++ gpopup3.insertItem(i18n("1 %"), 128);
++ if (_funcLimit<0) _funcLimit = DEFAULT_FUNCLIMIT;
++ if (_funcLimit>.5) _funcLimit = .5;
++ if (_funcLimit == 0.0) gpopup3.setItemChecked(120,true);
++ else if (_funcLimit >= 0.5) gpopup3.setItemChecked(121,true);
++ else if (_funcLimit >= 0.2) gpopup3.setItemChecked(122,true);
++ else if (_funcLimit >= 0.1) gpopup3.setItemChecked(123,true);
++ else if (_funcLimit >= 0.05) gpopup3.setItemChecked(124,true);
++ else if (_funcLimit >= 0.03) gpopup3.setItemChecked(125,true);
++ else if (_funcLimit >= 0.02) gpopup3.setItemChecked(126,true);
++ else if (_funcLimit >= 0.015) gpopup3.setItemChecked(127,true);
++ else gpopup3.setItemChecked(128,true);
++ double oldFuncLimit = _funcLimit;
++
++ TQPopupMenu gpopup4;
++ gpopup4.setCheckable(true);
++ gpopup4.insertItem(i18n("Same as Node"), 160);
++ gpopup4.insertItem(i18n("50 % of Node"), 161);
++ gpopup4.insertItem(i18n("20 % of Node"), 162);
++ gpopup4.insertItem(i18n("10 % of Node"), 163);
++ if (_callLimit<0) _callLimit = DEFAULT_CALLLIMIT;
++ if (_callLimit >= _funcLimit) _callLimit = _funcLimit;
++ if (_callLimit == _funcLimit) gpopup4.setItemChecked(160,true);
++ else if (_callLimit >= 0.5 * _funcLimit) gpopup4.setItemChecked(161,true);
++ else if (_callLimit >= 0.2 * _funcLimit) gpopup4.setItemChecked(162,true);
++ else gpopup4.setItemChecked(163,true);
++
++ TQPopupMenu gpopup;
++ gpopup.setCheckable(true);
++ gpopup.insertItem(i18n("Caller Depth"), &gpopup1, 80);
++ gpopup.insertItem(i18n("Callee Depth"), &gpopup2, 81);
++ gpopup.insertItem(i18n("Min. Node Cost"), &gpopup3, 82);
++ gpopup.insertItem(i18n("Min. Call Cost"), &gpopup4, 83);
++ gpopup.insertSeparator();
++ gpopup.insertItem(i18n("Arrows for Skipped Calls"), 130);
++ gpopup.setItemChecked(130,_showSkipped);
++ gpopup.insertItem(i18n("Inner-cycle Calls"), 131);
++ gpopup.setItemChecked(131,_expandCycles);
++ gpopup.insertItem(i18n("Cluster Groups"), 132);
++ gpopup.setItemChecked(132,_clusterGroups);
++
++ TQPopupMenu vpopup;
++ vpopup.setCheckable(true);
++ vpopup.insertItem(i18n("Compact"), 140);
++ vpopup.insertItem(i18n("Normal"), 141);
++ vpopup.insertItem(i18n("Tall"), 142);
++ vpopup.setItemChecked(140,_detailLevel == 0);
++ vpopup.setItemChecked(141,_detailLevel == 1);
++ vpopup.setItemChecked(142,_detailLevel == 2);
++ vpopup.insertSeparator();
++ vpopup.insertItem(i18n("Top to Down"), 150);
++ vpopup.insertItem(i18n("Left to Right"), 151);
++ vpopup.insertItem(i18n("Circular"), 152);
++ vpopup.setItemChecked(150,_layout == TopDown);
++ vpopup.setItemChecked(151,_layout == LeftRight);
++ vpopup.setItemChecked(152,_layout == Circular);
++
++ TQPopupMenu opopup;
++ opopup.insertItem(i18n("TopLeft"), 170);
++ opopup.insertItem(i18n("TopRight"), 171);
++ opopup.insertItem(i18n("BottomLeft"), 172);
++ opopup.insertItem(i18n("BottomRight"), 173);
++ opopup.insertItem(i18n("Automatic"), 174);
++ opopup.setItemChecked(170,_zoomPosition == TopLeft);
++ opopup.setItemChecked(171,_zoomPosition == TopRight);
++ opopup.setItemChecked(172,_zoomPosition == BottomLeft);
++ opopup.setItemChecked(173,_zoomPosition == BottomRight);
++ opopup.setItemChecked(174,_zoomPosition == Auto);
++
++ popup.insertItem(i18n("Graph"), &gpopup, 70);
++ popup.insertItem(i18n("Visualization"), &vpopup, 71);
++ popup.insertItem(i18n("Birds-eye View"), &opopup, 72);
++
++ int r = popup.exec(e->globalPos());
++
++ switch(r) {
++ case 93: activated(f); break;
++ case 94: activated(cycle); break;
++ case 95: activated(c); break;
++
++ case 999: stopRendering(); break;
++
++ case 201:
++ {
++ TraceFunction* f = activeFunction();
++ if (!f) break;
++
++ GraphExporter ge(TraceItemView::data(), f, costType(), groupType(),
++ TQString("callgraph.dot"));
++ ge.setGraphOptions(this);
++ ge.writeDot();
++
++ system("(dot callgraph.dot -Tps > callgraph.ps; kghostview callgraph.ps)&");
++ }
++ break;
++
++ case 202:
++ // write current content of canvas as image to file
++ {
++ if (!_canvas) return;
++
++ TQString fn = KFileDialog::getSaveFileName(":","*.png");
++
++ if (!fn.isEmpty()) {
++ TQPixmap pix(_canvas->size());
++ TQPainter p(&pix);
++ _canvas->drawArea( _canvas->rect(), &p );
++ pix.save(fn,"PNG");
++ }
++ }
++ break;
++
++ case 100: _maxCallerDepth = -1; break;
++ case 101: _maxCallerDepth = 0; break;
++ case 102: _maxCallerDepth = 2; break;
++ case 103: _maxCallerDepth = 5; break;
++ case 104: _maxCallerDepth = 10; break;
++ case 105: _maxCallerDepth = 15; break;
++
++ case 110: _maxCallingDepth = -1; break;
++ case 111: _maxCallingDepth = 0; break;
++ case 112: _maxCallingDepth = 2; break;
++ case 113: _maxCallingDepth = 5; break;
++ case 114: _maxCallingDepth = 10; break;
++ case 115: _maxCallingDepth = 15; break;
++
++ case 120: _funcLimit = 0; break;
++ case 121: _funcLimit = 0.5; break;
++ case 122: _funcLimit = 0.2; break;
++ case 123: _funcLimit = 0.1; break;
++ case 124: _funcLimit = 0.05; break;
++ case 125: _funcLimit = 0.03; break;
++ case 126: _funcLimit = 0.02; break;
++ case 127: _funcLimit = 0.015; break;
++ case 128: _funcLimit = 0.01; break;
++
++ case 130: _showSkipped = !_showSkipped; break;
++ case 131: _expandCycles = !_expandCycles; break;
++ case 132: _clusterGroups = !_clusterGroups; break;
++
++ case 140: _detailLevel = 0; break;
++ case 141: _detailLevel = 1; break;
++ case 142: _detailLevel = 2; break;
++
++ case 150: _layout = TopDown; break;
++ case 151: _layout = LeftRight; break;
++ case 152: _layout = Circular; break;
++
++ case 160: _callLimit = _funcLimit; break;
++ case 161: _callLimit = .5 * _funcLimit; break;
++ case 162: _callLimit = .2 * _funcLimit; break;
++ case 163: _callLimit = .1 * _funcLimit; break;
++
++ case 170: _zoomPosition = TopLeft; break;
++ case 171: _zoomPosition = TopRight; break;
++ case 172: _zoomPosition = BottomLeft; break;
++ case 173: _zoomPosition = BottomRight; break;
++ case 174: _zoomPosition = Auto; break;
++
++ default: break;
++ }
++ if (r>=120 && r<130) _callLimit *= _funcLimit / oldFuncLimit;
++
++ if (r>99 && r<170) refresh();
++ if (r>169 && r<180) updateSizes();
++}
++
++CallGraphView::ZoomPosition CallGraphView::zoomPos(TQString s)
++{
++ if (s == TQString("TopLeft")) return TopLeft;
++ if (s == TQString("TopRight")) return TopRight;
++ if (s == TQString("BottomLeft")) return BottomLeft;
++ if (s == TQString("BottomRight")) return BottomRight;
++ if (s == TQString("Automatic")) return Auto;
++
++ return DEFAULT_ZOOMPOS;
++}
++
++TQString CallGraphView::zoomPosString(ZoomPosition p)
++{
++ if (p == TopRight) return TQString("TopRight");
++ if (p == BottomLeft) return TQString("BottomLeft");
++ if (p == BottomRight) return TQString("BottomRight");
++ if (p == Auto) return TQString("Automatic");
++
++ return TQString("TopLeft");
++}
++
++void CallGraphView::readViewConfig(KConfig* c,
++ TQString prefix, TQString postfix, bool)
++{
++ KConfigGroup* g = configGroup(c, prefix, postfix);
++
++ if (0) qDebug("CallGraphView::readViewConfig");
++
++ _maxCallerDepth = g->readNumEntry("MaxCaller", DEFAULT_MAXCALLER);
++ _maxCallingDepth = g->readNumEntry("MaxCalling", DEFAULT_MAXCALLING);
++ _funcLimit = g->readDoubleNumEntry("FuncLimit", DEFAULT_FUNCLIMIT);
++ _callLimit = g->readDoubleNumEntry("CallLimit", DEFAULT_CALLLIMIT);
++ _showSkipped = g->readBoolEntry("ShowSkipped", DEFAULT_SHOWSKIPPED);
++ _expandCycles = g->readBoolEntry("ExpandCycles", DEFAULT_EXPANDCYCLES);
++ _clusterGroups = g->readBoolEntry("ClusterGroups",
++ DEFAULT_CLUSTERGROUPS);
++ _detailLevel = g->readNumEntry("DetailLevel", DEFAULT_DETAILLEVEL);
++ _layout = GraphOptions::layout(g->readEntry("Layout",
++ layoutString(DEFAULT_LAYOUT)));
++ _zoomPosition = zoomPos(g->readEntry("ZoomPosition",
++ zoomPosString(DEFAULT_ZOOMPOS)));
++
++ delete g;
++}
++
++void CallGraphView::saveViewConfig(KConfig* c,
++ TQString prefix, TQString postfix, bool)
++{
++ KConfigGroup g(c, (prefix+postfix).ascii());
++
++ writeConfigEntry(&g, "MaxCaller", _maxCallerDepth, DEFAULT_MAXCALLER);
++ writeConfigEntry(&g, "MaxCalling", _maxCallingDepth, DEFAULT_MAXCALLING);
++ writeConfigEntry(&g, "FuncLimit", _funcLimit, DEFAULT_FUNCLIMIT);
++ writeConfigEntry(&g, "CallLimit", _callLimit, DEFAULT_CALLLIMIT);
++ writeConfigEntry(&g, "ShowSkipped", _showSkipped, DEFAULT_SHOWSKIPPED);
++ writeConfigEntry(&g, "ExpandCycles", _expandCycles, DEFAULT_EXPANDCYCLES);
++ writeConfigEntry(&g, "ClusterGroups", _clusterGroups,
++ DEFAULT_CLUSTERGROUPS);
++ writeConfigEntry(&g, "DetailLevel", _detailLevel, DEFAULT_DETAILLEVEL);
++ writeConfigEntry(&g, "Layout",
++ layoutString(_layout), layoutString(DEFAULT_LAYOUT).utf8().data());
++ writeConfigEntry(&g, "ZoomPosition",
++ zoomPosString(_zoomPosition),
++ zoomPosString(DEFAULT_ZOOMPOS).utf8().data());
++}
++
++#include "callgraphview.moc"
++
+diff --git a/kdecachegrind/kdecachegrind/callgraphview.h b/kdecachegrind/kdecachegrind/callgraphview.h
+new file mode 100644
+index 0000000..4db619d
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/callgraphview.h
+@@ -0,0 +1,501 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Callgraph View
++ */
++
++#ifndef CALLGRAPHVIEW_H
++#define CALLGRAPHVIEW_H
++
++#include <tqcanvas.h>
++#include <tqwidget.h>
++#include <tqmap.h>
++#include <tqtimer.h>
++
++#include "treemap.h" // for DrawParams
++#include "tracedata.h"
++#include "traceitemview.h"
++
++class TQProcess;
++
++class KTempFile;
++class CanvasNode;
++class CanvasEdge;
++class GraphEdge;
++class CallGraphView;
++
++// sorts according start/end position of a call arc
++// this depends on attached CanvasEdge's !
++class GraphEdgeList: public TQPtrList<GraphEdge>
++{
++ public:
++ GraphEdgeList();
++ void setSortCallerPos(bool b) { _sortCallerPos = b; }
++
++ protected:
++ int compareItems ( Item item1, Item item2 );
++
++ private:
++ bool _sortCallerPos;
++};
++
++
++typedef TQMap<GraphEdge*, int> GraphEdgeSet;
++
++// temporary parts of call graph to be shown
++class GraphNode
++{
++public:
++ GraphNode();
++
++ TraceFunction* function() { return _f; }
++ void setFunction(TraceFunction* f) { _f = f; }
++
++ CanvasNode* canvasNode() { return _cn; }
++ void setCanvasNode(CanvasNode* cn) { _cn = cn; }
++
++ bool isVisible() { return _visible; }
++ void setVisible(bool v) { _visible = v; }
++
++ // keyboard navigation
++ TraceCall* visibleCaller();
++ TraceCall* visibleCalling();
++ void setCalling(GraphEdge*);
++ void setCaller(GraphEdge*);
++ TraceFunction* nextVisible();
++ TraceFunction* priorVisible();
++ TraceCall* nextVisibleCaller(GraphEdge*);
++ TraceCall* nextVisibleCalling(GraphEdge*);
++ TraceCall* priorVisibleCaller(GraphEdge*);
++ TraceCall* priorVisibleCalling(GraphEdge*);
++
++ double self, incl;
++ GraphEdgeList callers, callings;
++ // for fast unique insertion of GraphEdges in above lists
++ GraphEdgeSet callerSet, callingSet;
++
++ private:
++ TraceFunction* _f;
++ CanvasNode* _cn;
++ bool _visible;
++
++ // for keyboard navigation
++ int _lastCallerIndex, _lastCallingIndex;
++ bool _lastFromCaller;
++};
++
++class GraphEdge
++{
++public:
++ GraphEdge();
++
++ CanvasEdge* canvasEdge() { return _ce; }
++ void setCanvasEdge(CanvasEdge* ce) { _ce = ce; }
++
++ TraceCall* call() { return _c; }
++ void setCall(TraceCall* c) { _c = c; }
++
++ bool isVisible() { return _visible; }
++ void setVisible(bool v) { _visible = v; }
++
++ GraphNode* fromNode() { return _fromNode; }
++ GraphNode* toNode() { return _toNode; }
++ TraceFunction* from() { return _from; }
++ TraceFunction* to() { return _to; }
++
++ // has special cases for collapsed edges
++ TQString prettyName();
++
++ void setCaller(TraceFunction* f) { _from = f; }
++ void setCalling(TraceFunction* f) { _to = f; }
++ void setCallerNode(GraphNode* n) { _fromNode = n; }
++ void setCallingNode(GraphNode* n) { _toNode = n; }
++
++ // keyboard navigation
++ TraceFunction* visibleCaller();
++ TraceFunction* visibleCalling();
++ TraceCall* nextVisible();
++ TraceCall* priorVisible();
++
++ double cost, count;
++
++ private:
++ // we have a _c *and* _from/_to because for collapsed edges,
++ // only _to or _from will be unequal NULL
++ TraceCall* _c;
++ TraceFunction * _from, * _to;
++ GraphNode *_fromNode, *_toNode;
++ CanvasEdge* _ce;
++ bool _visible;
++ // for keyboard navigation: have we last reached this edge via a caller?
++ bool _lastFromCaller;
++
++};
++
++
++typedef TQMap<TraceFunction*, GraphNode> GraphNodeMap;
++typedef TQMap<TQPair<TraceFunction*, TraceFunction*>, GraphEdge> GraphEdgeMap;
++
++
++/* Abstract Interface for graph options */
++class GraphOptions
++{
++ public:
++ enum Layout { TopDown, LeftRight, Circular};
++
++ virtual double funcLimit() = 0;
++ virtual double callLimit() = 0;
++ virtual int maxCallerDepth() = 0;
++ virtual int maxCallingDepth() = 0;
++ virtual bool showSkipped() = 0;
++ virtual bool expandCycles() = 0;
++ virtual bool clusterGroups() = 0;
++ virtual int detailLevel() = 0;
++ virtual Layout layout() = 0;
++
++ static TQString layoutString(Layout);
++ static Layout layout(TQString);
++};
++
++/* Graph Options Storage */
++class StorableGraphOptions: public GraphOptions
++{
++ public:
++ StorableGraphOptions();
++
++ // implementation of getters
++ virtual double funcLimit() { return _funcLimit; }
++ virtual double callLimit() { return _callLimit; }
++ virtual int maxCallerDepth() { return _maxCallerDepth; }
++ virtual int maxCallingDepth() { return _maxCallingDepth; }
++ virtual bool showSkipped() { return _showSkipped; }
++ virtual bool expandCycles() { return _expandCycles; }
++ virtual bool clusterGroups() { return _clusterGroups; }
++ virtual int detailLevel() { return _detailLevel; }
++ virtual Layout layout() { return _layout; }
++
++ // setters
++ void setMaxCallerDepth(int d) { _maxCallerDepth = d; }
++ void setMaxCallingDepth(int d) { _maxCallingDepth = d; }
++ void setFuncLimit(double l) { _funcLimit = l; }
++ void setCallLimit(double l) { _callLimit = l; }
++ void setShowSkipped(bool b) { _showSkipped = b; }
++ void setExpandCycles(bool b) { _expandCycles = b; }
++ void setClusterGroups(bool b) { _clusterGroups = b; }
++ void setDetailLevel(int l) { _detailLevel = l; }
++ void setLayout(Layout l) { _layout = l; }
++
++ protected:
++ double _funcLimit, _callLimit;
++ int _maxCallerDepth, _maxCallingDepth;
++ bool _showSkipped, _expandCycles, _clusterGroups;
++ int _detailLevel;
++ Layout _layout;
++};
++
++/**
++ * GraphExporter
++ *
++ * Generates a graph file for "dot"
++ * Create an instance and
++ */
++class GraphExporter: public StorableGraphOptions
++{
++public:
++ GraphExporter();
++ GraphExporter(TraceData*, TraceFunction*, TraceCostType*,
++ TraceItem::CostType, TQString filename = TQString());
++ virtual ~GraphExporter();
++
++ void reset(TraceData*, TraceItem*, TraceCostType*,
++ TraceItem::CostType, TQString filename = TQString());
++
++ TQString filename() { return _dotName; }
++ int edgeCount() { return _edgeMap.count(); }
++ int nodeCount() { return _nodeMap.count(); }
++
++ // Set the object from which to get graph options for creation.
++ // Default is this object itself (supply 0 for default)
++ void setGraphOptions(GraphOptions* go = 0);
++
++ // Create a subgraph with given limits/maxDepths
++ void createGraph();
++
++ // calls createGraph before dumping of not already created
++ void writeDot();
++
++ // to map back to structures when parsing a layouted graph
++
++ /* <toFunc> is a helper for node() and edge().
++ * Don't use the returned pointer directly, but only with
++ * node() or edge(), because it could be a dangling pointer.
++ */
++ TraceFunction* toFunc(TQString);
++ GraphNode* node(TraceFunction*);
++ GraphEdge* edge(TraceFunction*, TraceFunction*);
++
++ /* After CanvasEdges are attached to GraphEdges, we can
++ * sort the incoming and outgoing edges of all nodes
++ * regarding start/end points for keyboard navigation
++ */
++ void sortEdges();
++
++private:
++ void buildGraph(TraceFunction*, int, bool, double);
++
++ TQString _dotName;
++ TraceItem* _item;
++ TraceCostType* _costType;
++ TraceItem::CostType _groupType;
++ KTempFile* _tmpFile;
++ double _realFuncLimit, _realCallLimit;
++ int _maxDepth;
++ bool _graphCreated;
++
++ GraphOptions* _go;
++
++ // optional graph attributes
++ bool _useBox;
++
++ // graph parts written to file
++ GraphNodeMap _nodeMap;
++ GraphEdgeMap _edgeMap;
++};
++
++/**
++ * A panner layed over a TQCanvas
++ */
++class PannerView: public TQCanvasView
++{
++ Q_OBJECT
++ TQ_OBJECT
++
++public:
++ PannerView(TQWidget * parent = 0, const char * name = 0);
++
++ void setZoomRect(TQRect r);
++
++signals:
++ void zoomRectMoved(int dx, int dy);
++ void zoomRectMoveFinished();
++
++protected:
++ void contentsMousePressEvent(TQMouseEvent*);
++ void contentsMouseMoveEvent(TQMouseEvent*);
++ void contentsMouseReleaseEvent(TQMouseEvent*);
++ void drawContents(TQPainter * p, int clipx, int clipy, int clipw, int cliph);
++
++ TQRect _zoomRect;
++ bool _movingZoomRect;
++ TQPoint _lastPos;
++};
++
++
++/*
++ * Canvas Items:
++ * - CanvasNode (Rectangular Area)
++ * - CanvasEdge (Spline curve)
++ * - CanvasEdgeLabel (Label for edges)
++ * - CanvasEdgeArrow (Arrows at the end of the edge spline)
++ * - CanvasFrame (Grey background blending to show active node)
++ */
++
++enum {
++ CANVAS_NODE = 1122,
++ CANVAS_EDGE, CANVAS_EDGELABEL, CANVAS_EDGEARROW,
++ CANVAS_FRAME
++};
++
++class CanvasNode: public TQCanvasRectangle, public StoredDrawParams
++{
++public:
++ CanvasNode(CallGraphView*,GraphNode*, int, int, int, int, TQCanvas*);
++
++ void updateGroup();
++ void setSelected(bool);
++ void drawShape(TQPainter&);
++
++ GraphNode* node() { return _node; }
++ int rtti() const { return CANVAS_NODE; }
++
++private:
++ GraphNode* _node;
++ CallGraphView* _view;
++};
++
++class CanvasEdgeLabel: public TQCanvasRectangle, public StoredDrawParams
++{
++public:
++ CanvasEdgeLabel(CallGraphView*, CanvasEdge*, int, int, int, int, TQCanvas*);
++
++ void drawShape(TQPainter&);
++
++ CanvasEdge* canvasEdge() { return _ce; }
++ int rtti() const { return CANVAS_EDGELABEL; }
++
++private:
++ CanvasEdge* _ce;
++ CallGraphView* _view;
++};
++
++class CanvasEdgeArrow: public TQCanvasPolygon
++{
++public:
++ CanvasEdgeArrow(CanvasEdge*, TQCanvas*);
++
++ void drawShape(TQPainter&);
++
++ CanvasEdge* canvasEdge() { return _ce; }
++ int rtti() const { return CANVAS_EDGEARROW; }
++
++private:
++ CanvasEdge* _ce;
++};
++
++
++class CanvasEdge: public TQCanvasSpline
++{
++public:
++ CanvasEdge(GraphEdge*, TQCanvas*);
++
++ void setSelected(bool);
++ void drawShape(TQPainter&);
++ TQPointArray areaPoints() const;
++
++ CanvasEdgeLabel* label() { return _label; }
++ void setLabel(CanvasEdgeLabel* l) { _label = l; }
++ CanvasEdgeArrow* arrow() { return _arrow; }
++ void setArrow(CanvasEdgeArrow* a) { _arrow = a; }
++
++ GraphEdge* edge() { return _edge; }
++ int rtti() const { return CANVAS_EDGE; }
++
++private:
++ GraphEdge* _edge;
++ CanvasEdgeLabel* _label;
++ CanvasEdgeArrow* _arrow;
++};
++
++
++class CanvasFrame: public TQCanvasRectangle
++{
++public:
++ CanvasFrame( CanvasNode*, TQCanvas *canvas );
++ int rtti () const { return CANVAS_FRAME; }
++ bool hit( const TQPoint&) const { return false; }
++protected:
++ void drawShape( TQPainter & );
++private:
++ static TQPixmap* _p;
++};
++
++
++class CallGraphTip;
++
++/**
++ * A CanvasView showing a part of the call graph
++ * and another zoomed out CanvasView in a border acting as
++ * a panner to select to visible part (only if needed)
++ */
++class CallGraphView: public TQCanvasView, public TraceItemView,
++ public StorableGraphOptions
++{
++ Q_OBJECT
++ TQ_OBJECT
++
++public:
++ enum ZoomPosition { TopLeft, TopRight, BottomLeft, BottomRight, Auto };
++
++ CallGraphView(TraceItemView* parentView,
++ TQWidget* parent=0, const char* name=0);
++ ~CallGraphView();
++
++ void readViewConfig(KConfig*, TQString prefix, TQString postfix, bool);
++ void saveViewConfig(KConfig*, TQString prefix, TQString postfix, bool);
++
++ TQWidget* widget() { return this; }
++ TQString whatsThis() const;
++
++ ZoomPosition zoomPos() const { return _zoomPosition; }
++ static ZoomPosition zoomPos(TQString);
++ static TQString zoomPosString(ZoomPosition);
++
++public slots:
++ void contentsMovingSlot(int,int);
++ void zoomRectMoved(int,int);
++ void zoomRectMoveFinished();
++
++ void showRenderWarning();
++ void stopRendering();
++ void readDotOutput();
++ void dotExited();
++
++protected:
++ void resizeEvent(TQResizeEvent*);
++ void contentsMousePressEvent(TQMouseEvent*);
++ void contentsMouseMoveEvent(TQMouseEvent*);
++ void contentsMouseReleaseEvent(TQMouseEvent*);
++ void contentsMouseDoubleClickEvent(TQMouseEvent*);
++ void contentsContextMenuEvent(TQContextMenuEvent*);
++ void keyPressEvent(TQKeyEvent*);
++ void focusInEvent(TQFocusEvent*);
++ void focusOutEvent(TQFocusEvent*);
++
++private:
++ void updateSizes(TQSize s = TQSize(0,0));
++ TraceItem* canShow(TraceItem*);
++ void doUpdate(int);
++ void refresh();
++ void makeFrame(CanvasNode*, bool active);
++ void clear();
++ void showText(TQString);
++
++ TQCanvas *_canvas;
++ int _xMargin, _yMargin;
++ PannerView *_completeView;
++ double _cvZoom;
++
++ CallGraphTip* _tip;
++
++ bool _isMoving;
++ TQPoint _lastPos;
++
++ GraphExporter _exporter;
++
++ GraphNode* _selectedNode;
++ GraphEdge* _selectedEdge;
++
++ // widget options
++ ZoomPosition _zoomPosition, _lastAutoPosition;
++
++ // background rendering
++ TQProcess* _renderProcess;
++ TQTimer _renderTimer;
++ GraphNode* _prevSelectedNode;
++ TQPoint _prevSelectedPos;
++ TQString _unparsedOutput;
++};
++
++
++
++
++#endif
++
++
++
+diff --git a/kdecachegrind/kdecachegrind/callitem.cpp b/kdecachegrind/kdecachegrind/callitem.cpp
+new file mode 100644
+index 0000000..ebca490
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/callitem.cpp
+@@ -0,0 +1,185 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Items for caller/callee view.
++ */
++
++#include <tqpixmap.h>
++#include <klocale.h>
++#include <kapplication.h>
++#include <kiconloader.h>
++
++#include "configuration.h"
++#include "listutils.h"
++#include "callitem.h"
++#include "callview.h"
++#include "toplevel.h"
++
++// CallItem
++
++
++CallItem::CallItem(CallView* view, TQListView* parent, TraceCall* c)
++ : TQListViewItem(parent)
++{
++ _call = c;
++ _view = view;
++
++ _active = _view->activeFunction();
++ bool baseIsCycle = (_active && (_active == _active->cycle()));
++
++ TQString fName;
++ if (_view->showCallers()) {
++ _shown = _call->caller(true);
++ fName = c->callerName(!baseIsCycle);
++ }
++ else {
++ _shown = _call->called(true);
++ fName = c->calledName(!baseIsCycle);
++ }
++
++ _shown->addPrettyLocation(fName);
++
++ setText(3, fName);
++ updateGroup();
++ updateCost();
++}
++
++void CallItem::updateGroup()
++{
++ TQColor c = Configuration::functionColor(_view->groupType(), _shown);
++ setPixmap(3, colorPixmap(10, 10, c));
++}
++
++void CallItem::updateCost()
++{
++ bool sameCycle = _shown->cycle() && (_active->cycle() == _shown->cycle());
++ bool shownIsCycle = (_shown == _shown->cycle());
++ bool selectedIsCycle = (_active == _active->cycle());
++ if (_call->isRecursion()) sameCycle=true;
++
++ TQString cStr;
++ if ((selectedIsCycle || shownIsCycle) && sameCycle)
++ cStr = "-";
++ else {
++ _cc = _call->callCount();
++ if (_cc == 0)
++ cStr = i18n("(active)");
++ else
++ cStr = _call->prettyCallCount();
++ }
++ setText(2, cStr);
++
++ TraceCost* totalCost;
++ if (_view->topLevel()->showExpanded()) {
++ if (_active->cycle())
++ totalCost = _active->cycle()->inclusive();
++ else
++ totalCost = _active->inclusive();
++ }
++ else
++ totalCost = _active->data();
++
++ TraceCostType* ct = _view->costType();
++ _sum = _call->subCost(ct);
++ double total = totalCost->subCost(ct);
++
++ if (total == 0.0) {
++ TQString str = "-";
++
++ setText(0, str);
++ setPixmap(0, TQPixmap());
++ }
++ else {
++ double sum = 100.0 * _sum / total;
++
++ if (_view->topLevel()->showPercentage())
++ setText(0, TQString("%1")
++ .arg(sum, 0, 'f', Configuration::percentPrecision()));
++ else
++ setText(0, _call->prettySubCost(ct));
++
++ setPixmap(0, costPixmap(ct, _call, total, false));
++ }
++
++ // Cost Type 2
++ TraceCostType* ct2 = _view->costType2();
++ if (ct2) {
++ _sum2 = _call->subCost(ct2);
++ double total = totalCost->subCost(ct2);
++
++ if (total == 0.0) {
++ TQString str = "-";
++
++ setText(1, str);
++ setPixmap(1, TQPixmap());
++ }
++ else {
++ double sum = 100.0 * _sum2 / total;
++
++ if (_view->topLevel()->showPercentage())
++ setText(1, TQString("%1")
++ .arg(sum, 0, 'f', Configuration::percentPrecision()));
++ else
++ setText(1, _call->prettySubCost(ct2));
++
++ setPixmap(1, costPixmap(ct2, _call, total, false));
++ }
++ }
++
++ TQPixmap p;
++ if (sameCycle && !selectedIsCycle && !shownIsCycle) {
++
++ TQString icon = "undo";
++ KIconLoader* loader = KApplication::kApplication()->iconLoader();
++ p= loader->loadIcon(icon, KIcon::Small, 0,
++ KIcon::DefaultState, 0, true);
++ }
++ setPixmap(2, p);
++}
++
++
++int CallItem::compare(TQListViewItem * i, int col, bool ascending ) const
++{
++ const CallItem* ci1 = this;
++ const CallItem* ci2 = (CallItem*) i;
++
++ // we always want descending order
++ if (ascending) {
++ ci1 = ci2;
++ ci2 = this;
++ }
++
++ if (col==0) {
++ if (ci1->_sum < ci2->_sum) return -1;
++ if (ci1->_sum > ci2->_sum) return 1;
++ return 0;
++ }
++ if (col==1) {
++ if (ci1->_sum2 < ci2->_sum2) return -1;
++ if (ci1->_sum2 > ci2->_sum2) return 1;
++ return 0;
++ }
++ if (col==2) {
++ if (ci1->_cc < ci2->_cc) return -1;
++ if (ci1->_cc > ci2->_cc) return 1;
++ return 0;
++ }
++ return TQListViewItem::compare(i, col, ascending);
++}
++
+diff --git a/kdecachegrind/kdecachegrind/callitem.h b/kdecachegrind/kdecachegrind/callitem.h
+new file mode 100644
+index 0000000..94191b8
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/callitem.h
+@@ -0,0 +1,50 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Items of call view.
++ */
++
++#ifndef CALLITEM_H
++#define CALLITEM_H
++
++#include <tqlistview.h>
++#include "tracedata.h"
++
++class CallView;
++
++class CallItem: public TQListViewItem
++{
++public:
++ CallItem(CallView*, TQListView*, TraceCall* c);
++
++ int compare(TQListViewItem * i, int col, bool ascending ) const;
++ TraceCall* call() { return _call; }
++ CallView* view() { return _view; }
++ void updateCost();
++ void updateGroup();
++
++private:
++ SubCost _sum, _sum2;
++ SubCost _cc;
++ TraceCall* _call;
++ CallView* _view;
++ TraceFunction *_active, *_shown;
++};
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/callmapview.cpp b/kdecachegrind/kdecachegrind/callmapview.cpp
+new file mode 100644
+index 0000000..0e4d5e3
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/callmapview.cpp
+@@ -0,0 +1,999 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Call Map View
++ */
++
++#include <tqwhatsthis.h>
++#include <tqpopupmenu.h>
++
++#include <klocale.h>
++#include <kiconloader.h>
++#include <kapplication.h>
++#include <kconfig.h>
++
++#include "callmapview.h"
++#include "configuration.h"
++#include "listutils.h"
++#include "toplevel.h"
++
++//
++// CallMapView
++//
++
++
++// defaults
++#define DEFAULT_SPLITMODE "Rows"
++#define DEFAULT_DRAWNAME true
++#define DEFAULT_DRAWCOST true
++#define DEFAULT_DRAWLOCATION false
++#define DEFAULT_DRAWCALLS false
++#define DEFAULT_FORCESTRINGS false
++#define DEFAULT_ROTATION true
++#define DEFAULT_SHADING true
++#define DEFAULT_MAXAREA 100
++
++
++CallMapView::CallMapView(bool showCallers, TraceItemView* parentView,
++ TQWidget* parent, const char* name)
++ : TreeMapWidget(new CallMapBaseItem(), parent, name), TraceItemView(parentView)
++{
++ _showCallers = showCallers;
++
++ setFieldType(0, i18n( "Name" ));
++ setFieldType(1, i18n( "Cost" ));
++ setFieldType(2, i18n( "Location" ));
++ setFieldPosition(2, TreeMapItem::TopLeft);
++ setFieldType(3, i18n( "Calls" ));
++ setFieldPosition(3, TreeMapItem::TopRight);
++
++ setSplitMode(DEFAULT_SPLITMODE);
++ setFieldVisible(0, DEFAULT_DRAWNAME);
++ setFieldVisible(1, DEFAULT_DRAWCOST);
++ setFieldVisible(2, DEFAULT_DRAWLOCATION);
++ setFieldVisible(3, DEFAULT_DRAWCALLS);
++ setFieldForced(0, DEFAULT_FORCESTRINGS);
++ setFieldForced(1, DEFAULT_FORCESTRINGS);
++ setFieldForced(2, DEFAULT_FORCESTRINGS);
++ setFieldForced(3, DEFAULT_FORCESTRINGS);
++ setAllowRotation(DEFAULT_ROTATION);
++ setShadingEnabled(DEFAULT_SHADING);
++ setMinimalArea(DEFAULT_MAXAREA);
++
++ connect(this,
++ TQT_SIGNAL(doubleClicked(TreeMapItem*)),
++ TQT_SLOT(activatedSlot(TreeMapItem*)));
++ connect(this,
++ TQT_SIGNAL(returnPressed(TreeMapItem*)),
++ TQT_SLOT(activatedSlot(TreeMapItem*)));
++ connect(this,
++ TQT_SIGNAL(currentChanged(TreeMapItem*, bool)),
++ TQT_SLOT(selectedSlot(TreeMapItem*, bool)));
++ connect(this,
++ TQT_SIGNAL(contextMenuRequested(TreeMapItem*,const TQPoint &)),
++ TQT_SLOT(context(TreeMapItem*,const TQPoint &)));
++
++ TQWhatsThis::add( this, whatsThis());
++}
++
++TQString CallMapView::whatsThis() const
++{
++ TQString s = _showCallers ?
++ i18n( "<b>Caller Map</b>"
++ "<p>This graph shows the nested hierarchy of "
++ "all callers of the current activated function. "
++ "Each colored rectangle represents a function; "
++ "its size tries to be proportional to the cost spent "
++ "therein while the active function is running "
++ "(however, there are drawing constrains).</p>") :
++ i18n("<b>Call Map</b>"
++ "<p>This graph shows the nested hierarchy of "
++ "all callees of the current activated function. "
++ "Each colored rectangle represents a function; "
++ "its size tries to be proportional to the cost spent "
++ "therein while the active function is running "
++ "(however, there are drawing constrains).</p>");
++
++ s += i18n( "<p>Appearance options can be found in the "
++ "in the context menu. To get exact size proportions, "
++ "choose 'Hide incorrect borders'. As this mode can be "
++ "<em>very</em> time consuming, you may want to limit "
++ "the maximum drawn nesting level before. "
++ "'Best' determinates the split direction for children "
++ "from the aspect ratio of the parent. "
++ "'Always Best' decides on remaining space for each "
++ "sibling. "
++ "'Ignore Proportions' takes space for function name "
++ "drawing <em>before</em> drawing children. Note that "
++ "size proportions can get <em>heavily</em> wrong.</p>"
++
++ "<p>This is a <em>TreeMap</em> widget. "
++ "Keyboard navigation is available with the left/right arrow "
++ "keys for traversing siblings, and up/down arrow keys "
++ "to go a nesting level up/down. "
++ "<em>Return</em> activates the current item.</p>");
++
++ return s;
++}
++
++void CallMapView::setData(TraceData* d)
++{
++ TraceItemView::setData(d);
++
++ ((CallMapBaseItem*)base())->setFunction(0);
++}
++
++void CallMapView::context(TreeMapItem* i,const TQPoint & p)
++{
++ if (!i) return;
++
++ TQPopupMenu popup;
++ TQPopupMenu fpopup; // select function subpopup
++ TQPopupMenu vpopup; // visualisation subpopup
++ TQPopupMenu dpopup; // split direction
++ TQPopupMenu bpopup; // border subpopup
++ TQPopupMenu l1popup; // depth limit subpopup
++ TQPopupMenu l2popup; // function limit subpopup
++ TQPopupMenu l3popup; // area limit subpopup
++
++ TreeMapItem* item = i;
++ int count;
++
++ TQString shortCurrentName;
++ if (i) {
++ shortCurrentName = i->text(0);
++ if ((int)shortCurrentName.length() > Configuration::maxSymbolLength())
++ shortCurrentName =
++ shortCurrentName.left(Configuration::maxSymbolLength()) + "...";
++ }
++
++ if (item) {
++ popup.insertItem(i18n("Go To"), &fpopup, 100);
++ count = 0;
++ while (count<Configuration::maxSymbolCount() && item) {
++ TQString name = item->text(0);
++ if ((int)name.length()>Configuration::maxSymbolLength())
++ name = name.left(Configuration::maxSymbolLength()) + "...";
++ fpopup.insertItem(name, 101+count);
++ item = item->parent();
++ count++;
++ }
++ popup.insertSeparator();
++ }
++
++ addGoMenu(&popup);
++ popup.insertSeparator();
++
++ l1popup.setCheckable(true);
++ popup.insertItem(i18n("Stop at Depth"), &l1popup, 12);
++
++ int maxDepth = maxDrawingDepth();
++ l1popup.insertItem(i18n("No Depth Limit"), 50);
++ l1popup.setItemChecked(50, maxDepth==-1);
++ l1popup.insertSeparator();
++ l1popup.insertItem(i18n("Depth 10"), 51);
++ l1popup.setItemChecked(51, maxDepth==10);
++ l1popup.insertItem(i18n("Depth 15"), 52);
++ l1popup.setItemChecked(52, maxDepth==15);
++ l1popup.insertItem(i18n("Depth 20"), 53);
++ l1popup.setItemChecked(53, maxDepth==20);
++ if (i) {
++ l1popup.insertSeparator();
++ l1popup.insertItem(i18n("Depth of '%1' (%2)")
++ .arg(shortCurrentName).arg(i->depth()), 55);
++ l1popup.setItemChecked(55, maxDepth == i->depth());
++ }
++ if (maxDepth>0) {
++ l1popup.insertSeparator();
++ l1popup.insertItem(i18n("Decrement Depth (to %1)").arg(maxDepth-1), 56);
++ l1popup.insertItem(i18n("Increment Depth (to %1)").arg(maxDepth+1), 57);
++ }
++
++ l2popup.setCheckable(true);
++ popup.insertItem(i18n("Stop at Function"), &l2popup, 13);
++ l2popup.insertItem(i18n("No Function Limit"), 200);
++ l2popup.setItemChecked(200, fieldStop(0).isEmpty());
++ bool foundStopName = false;
++ item = i;
++ if (i) {
++ l2popup.insertSeparator();
++ count = 0;
++ while (count<Configuration::maxSymbolCount() && item) {
++ TQString name = item->text(0);
++ if ((int)name.length()>Configuration::maxSymbolLength())
++ name = name.left(Configuration::maxSymbolLength()) + "...";
++ l2popup.insertItem(name, 201+count);
++ if (item->text(0) == fieldStop(0)) {
++ l2popup.setItemChecked(201+count, true);
++ foundStopName = true;
++ }
++ item = item->parent();
++ count++;
++ }
++ }
++ if (!foundStopName && !fieldStop(0).isEmpty()) {
++ l2popup.insertSeparator();
++ TQString name = fieldStop(0);
++ if ((int)name.length()>Configuration::maxSymbolLength())
++ name = name.left(Configuration::maxSymbolLength()) + "...";
++ l2popup.insertItem(name, 199);
++ l2popup.setItemChecked(199, true);
++ }
++
++ l3popup.setCheckable(true);
++ popup.insertItem(i18n("Stop at Area"), &l3popup, 14);
++
++ int mArea = minimalArea();
++ l3popup.insertItem(i18n("No Area Limit"), 60);
++ l3popup.setItemChecked(60, mArea ==-1);
++ l3popup.insertSeparator();
++ l3popup.insertItem(i18n("50 Pixels"), 63);
++ l3popup.setItemChecked(63, mArea==50);
++ l3popup.insertItem(i18n("100 Pixels"), 64);
++ l3popup.setItemChecked(64, mArea==100);
++ l3popup.insertItem(i18n("200 Pixels"), 65);
++ l3popup.setItemChecked(65, mArea==200);
++ l3popup.insertItem(i18n("500 Pixels"), 66);
++ l3popup.setItemChecked(66, mArea==500);
++ int currentArea = 0;
++ if (i) {
++ currentArea = i->width() * i->height();
++ l3popup.insertSeparator();
++ l3popup.insertItem(i18n("Area of '%1' (%2)")
++ .arg(shortCurrentName).arg(currentArea), 67);
++ l3popup.setItemChecked(67, mArea == currentArea);
++ }
++ if (mArea>0) {
++ l3popup.insertSeparator();
++ l3popup.insertItem(i18n("Double Area Limit (to %1)")
++ .arg(mArea*2), 68);
++ l3popup.insertItem(i18n("Half Area Limit (to %1)")
++ .arg(mArea/2), 69);
++ }
++
++ popup.insertSeparator();
++
++ vpopup.setCheckable(true);
++ popup.insertItem(i18n("Visualisation"), &vpopup, 10);
++
++ TQPopupMenu splitpopup;
++ addSplitDirectionItems(&splitpopup, 1001);
++ vpopup.insertItem(i18n("Split Direction"), &splitpopup, 1000);
++
++ vpopup.insertItem(i18n("Skip Incorrect Borders"), 40);
++ vpopup.setItemEnabled(40, !_showCallers);
++ vpopup.setItemChecked(40, skipIncorrectBorder());
++
++ bpopup.setCheckable(true);
++ vpopup.insertItem(i18n("Border Width"), &bpopup, 41);
++ bpopup.insertItem(i18n("Border 0"), 42);
++ bpopup.setItemEnabled(42, !_showCallers);
++ bpopup.setItemChecked(42, borderWidth()==0);
++ bpopup.insertItem(i18n("Border 1"), 43);
++ bpopup.setItemChecked(43, borderWidth()==1);
++ bpopup.insertItem(i18n("Border 2"), 44);
++ bpopup.setItemChecked(44, borderWidth()==2);
++ bpopup.insertItem(i18n("Border 3"), 45);
++ bpopup.setItemChecked(45, borderWidth()==3);
++
++ vpopup.insertSeparator();
++
++ vpopup.insertItem(i18n("Draw Symbol Names"), 20);
++ vpopup.insertItem(i18n("Draw Cost"), 21);
++ vpopup.insertItem(i18n("Draw Location"), 22);
++ vpopup.insertItem(i18n("Draw Calls"), 23);
++ vpopup.insertSeparator();
++
++ vpopup.insertItem(i18n("Ignore Proportions"), 24);
++ vpopup.insertItem(i18n("Allow Rotation"), 25);
++ if (!fieldVisible(0) &&
++ !fieldVisible(1) &&
++ !fieldVisible(2) &&
++ !fieldVisible(3)) {
++ vpopup.setItemEnabled(24, false);
++ vpopup.setItemEnabled(25, false);
++ }
++ else {
++ vpopup.setItemChecked(20,fieldVisible(0));
++ vpopup.setItemChecked(21,fieldVisible(1));
++ vpopup.setItemChecked(22,fieldVisible(2));
++ vpopup.setItemChecked(23,fieldVisible(3));
++ vpopup.setItemChecked(24,fieldForced(0));
++ vpopup.setItemChecked(25,allowRotation());
++ }
++
++ vpopup.insertItem(i18n("Shading"), 26);
++ vpopup.setItemChecked(26,isShadingEnabled());
++
++ int r = popup.exec(mapToGlobal(p));
++
++ if (r>100 && r<150) {
++ r -= 100;
++ while (i && (r>1)) {
++ i=i->parent();
++ r--;
++ }
++ activatedSlot(i);
++ return;
++ }
++
++ if (r>200 && r<250) {
++ r -= 200;
++ while (i && (r>1)) {
++ i=i->parent();
++ r--;
++ }
++ if (i)
++ setFieldStop(0, i->text(0));
++
++ return;
++ }
++
++ switch(r) {
++ case 20:
++ setFieldVisible(0, !vpopup.isItemChecked(20));
++ break;
++
++ case 21:
++ setFieldVisible(1, !vpopup.isItemChecked(21));
++ break;
++
++ case 22:
++ setFieldVisible(2, !vpopup.isItemChecked(22));
++ break;
++
++ case 23:
++ setFieldVisible(3, !vpopup.isItemChecked(23));
++ break;
++
++ case 24:
++ setFieldForced(0, !vpopup.isItemChecked(24));
++ setFieldForced(1, !vpopup.isItemChecked(24));
++ setFieldForced(2, !vpopup.isItemChecked(24));
++ setFieldForced(3, !vpopup.isItemChecked(24));
++ break;
++
++ case 25: setAllowRotation(!vpopup.isItemChecked(25)); break;
++ case 26: setShadingEnabled(!vpopup.isItemChecked(26)); break;
++
++ case 40:
++ setSkipIncorrectBorder(!vpopup.isItemChecked(40));
++ break;
++
++ case 42: setBorderWidth(0); break;
++ case 43: setBorderWidth(1); break;
++ case 44: setBorderWidth(2); break;
++ case 45: setBorderWidth(3); break;
++
++ case 50: setMaxDrawingDepth(-1); break;
++ case 51: setMaxDrawingDepth(10); break;
++ case 52: setMaxDrawingDepth(15); break;
++ case 53: setMaxDrawingDepth(20); break;
++ case 55: setMaxDrawingDepth(i->depth()); break;
++ case 56: setMaxDrawingDepth(maxDepth-1); break;
++ case 57: setMaxDrawingDepth(maxDepth+1); break;
++
++ case 200: setFieldStop(0, TQString()); break;
++
++ case 60: setMinimalArea(-1); break;
++ case 61: setMinimalArea(10); break;
++ case 62: setMinimalArea(20); break;
++ case 63: setMinimalArea(50); break;
++ case 64: setMinimalArea(100); break;
++ case 65: setMinimalArea(200); break;
++ case 66: setMinimalArea(500); break;
++ case 67: setMinimalArea(currentArea); break;
++ case 68: setMinimalArea(mArea*2); break;
++ case 69: setMinimalArea(mArea/2); break;
++ }
++}
++
++void CallMapView::activatedSlot(TreeMapItem* item)
++{
++ if (!item) return;
++
++ if (item->rtti() == 1) {
++ CallMapBaseItem* bi = (CallMapBaseItem*)item;
++ activated(bi->function());
++ }
++ else if (item->rtti() == 2) {
++ CallMapCallingItem* ci = (CallMapCallingItem*)item;
++ activated(ci->function());
++ }
++ else if (item->rtti() == 3) {
++ CallMapCallerItem* ci = (CallMapCallerItem*)item;
++ activated(ci->function());
++ }
++}
++
++void CallMapView::selectedSlot(TreeMapItem* item, bool kbd)
++{
++ if (!item) return;
++ if (item->text(0).isEmpty()) return;
++
++ if (kbd) {
++ TQString msg = i18n("Call Map: Current is '%1'").arg(item->text(0));
++ if (_topLevel)
++ _topLevel->showMessage(msg, 5000);
++ }
++
++ TraceFunction* f = 0;
++
++ if (item->rtti() == 1) {
++ CallMapBaseItem* bi = (CallMapBaseItem*)item;
++ f = bi->function();
++ }
++ else if (item->rtti() == 2) {
++ CallMapCallingItem* ci = (CallMapCallingItem*)item;
++ f = ci->function();
++ }
++ else if (item->rtti() == 3) {
++ CallMapCallerItem* ci = (CallMapCallerItem*)item;
++ f = ci->function();
++ }
++ if (f) {
++ // this avoids marking
++ _selectedItem = f;
++ selected(f);
++ }
++}
++
++TraceItem* CallMapView::canShow(TraceItem* i)
++{
++ TraceItem::CostType t = i ? i->type() : TraceItem::NoCostType;
++
++ switch(t) {
++ case TraceItem::Function:
++ case TraceItem::FunctionCycle:
++ return i;
++ default:
++ break;
++ }
++ return 0;
++}
++
++void CallMapView::doUpdate(int changeType)
++{
++ if (changeType == costType2Changed) return;
++
++ // if there is a selected item, always draw marking...
++ if (changeType & selectedItemChanged) {
++ TraceFunction* f = 0;
++
++ if (_selectedItem) {
++ switch(_selectedItem->type()) {
++ case TraceItem::Function:
++ case TraceItem::FunctionCycle:
++ f = (TraceFunction*)_selectedItem;
++ break;
++ default:
++ break;
++ }
++ }
++ // if this is the only change...
++ if (changeType == selectedItemChanged) {
++ setMarked(f ? 1:0, true);
++ return;
++ }
++ setMarked(f ? 1:0, false);
++ }
++
++
++ if (changeType & activeItemChanged) {
++ TraceFunction* f = 0;
++
++ if (_activeItem) {
++ switch(_activeItem->type()) {
++ case TraceItem::Function:
++ case TraceItem::FunctionCycle:
++ f = (TraceFunction*)_activeItem;
++ break;
++ default:
++ break;
++ }
++ }
++ ((CallMapBaseItem*)base())->setFunction(f);
++ }
++ else if ( ((changeType & partsChanged) && Configuration::showCycles()) ||
++ (changeType & dataChanged) ||
++ (changeType & configChanged)) {
++ /* regenerates the treemap because traceitems were added/removed */
++ base()->refresh();
++ }
++ else if ((changeType & partsChanged) ||
++ (changeType & costTypeChanged)) {
++ /* we need to do the draw order sorting again as the values change */
++ resort();
++ redraw();
++ }
++ else
++ redraw();
++}
++
++
++
++TQColor CallMapView::groupColor(TraceFunction* f) const
++{
++ if (!f)
++ return colorGroup().button();
++
++ return Configuration::functionColor(_groupType, f);
++}
++
++
++TQString CallMapView::tipString(TreeMapItem* i) const
++{
++ TQString tip, itemTip;
++ int count = 0;
++
++ //qDebug("CallMapView::tipString for '%s'", i->text(0).ascii());
++
++ // first, SubPartItem's
++ while (i && count<Configuration::maxSymbolCount()) {
++ itemTip = i->text(0);
++ if ((int)itemTip.length()>Configuration::maxSymbolLength())
++ itemTip = itemTip.left(Configuration::maxSymbolLength()) + "...";
++
++ if (!i->text(1).isEmpty())
++ itemTip += " (" + i->text(1) + ")";
++
++ if (!tip.isEmpty()) tip += "\n";
++
++ tip += itemTip;
++ i = i->parent();
++ count++;
++ }
++ if (count == Configuration::maxSymbolCount()) tip += "\n...";
++
++ return tip;
++}
++
++
++TraceCost* CallMapView::totalCost()
++{
++ TraceFunction* f = ((CallMapBaseItem*)base())->function();
++ if (!f) return 0;
++
++ return Configuration::showExpanded() ? f->inclusive() : f->data();
++}
++
++
++
++
++// CallMapBaseItem
++
++CallMapBaseItem::CallMapBaseItem()
++{
++ _f = 0;
++}
++
++void CallMapBaseItem::setFunction(TraceFunction* f)
++{
++ if (f == _f) return;
++
++ _f = f;
++ refresh();
++}
++
++
++TQString CallMapBaseItem::text(int textNo) const
++{
++ if (textNo == 0) {
++ if (!_f)
++ return i18n("(no function)");
++
++ return _f->prettyName();
++ }
++
++ if (!_f) return TQString();
++
++ if (textNo == 2) return _f->prettyLocation();
++ if (textNo == 3) return _f->calledCount().pretty();
++ if (textNo != 1) return TQString();
++
++ TraceCostType* ct = ((CallMapView*)widget())->costType();
++ TraceCost* t = ((CallMapView*)widget())->totalCost();
++
++ if (Configuration::showPercentage()) {
++ double sum, total = t->subCost(ct);
++ if (total == 0.0)
++ sum = 100.0;
++ else
++ sum = 100.0 * _f->inclusive()->subCost(ct) / total;
++
++ return TQString("%1 %")
++ .arg(sum, 0, 'f', Configuration::percentPrecision());
++ }
++ return _f->inclusive()->prettySubCost(ct);
++}
++
++TQPixmap CallMapBaseItem::pixmap(int i) const
++{
++ if ((i != 1) || !_f) return TQPixmap();
++
++ TraceCostType* ct = ((CallMapView*)widget())->costType();
++ TraceCost* t = ((CallMapView*)widget())->totalCost();
++
++ // colored level meter with frame
++ return costPixmap( ct, _f->inclusive(), (double) (t->subCost(ct)), true);
++}
++
++
++double CallMapBaseItem::value() const
++{
++ if (!_f) return 0.0;
++
++ TraceCostType* ct;
++ ct = ((CallMapView*)widget())->costType();
++ return (double) _f->inclusive()->subCost(ct);
++}
++
++
++double CallMapBaseItem::sum() const
++{
++ if (!_f) return 0.0;
++
++ CallMapView* w = (CallMapView*)widget();
++
++ if (w->showCallers())
++ return 0.0;
++ else
++ return (double) _f->inclusive()->subCost(w->costType());
++}
++
++
++bool CallMapBaseItem::isMarked(int) const
++{
++ return ((CallMapView*)widget())->selectedItem() == _f;
++}
++
++TreeMapItemList* CallMapBaseItem::children()
++{
++ if (_f && !initialized()) {
++ CallMapView* w = (CallMapView*)widget();
++
++ if (0) qDebug("Create Function %s (%s)",
++ w->showCallers() ? "Callers":"Callees",
++ text(0).ascii());
++
++ TraceCall* call;
++
++ setSorting(-1);
++ if (w->showCallers()) {
++ TraceCallList l = _f->callers();
++ for (call=l.first();call;call=l.next()) {
++
++ // don't show calls inside of a cycle
++ if (call->inCycle()>0) continue;
++ if (call->isRecursion()) continue;
++
++ addItem(new CallMapCallerItem(1.0, call));
++ }
++
++ setSum(0);
++ }
++ else {
++ TraceCallList l = _f->callings();
++ for (call=l.first();call;call=l.next()) {
++
++ // don't show calls inside of a cycle
++ if (call->inCycle()>0) continue;
++ if (call->isRecursion()) continue;
++
++ CallMapCallingItem* i = new CallMapCallingItem(1.0, call);
++ i->init();
++ addItem(i);
++ }
++
++ setSum(_f->inclusive()->subCost(w->costType()));
++ }
++ setSorting(-2, false);
++ }
++
++ return _children;
++}
++
++TQColor CallMapBaseItem::backColor() const
++{
++ return ((CallMapView*)widget())->groupColor(_f);
++}
++
++
++
++// CallMapCallingItems
++
++CallMapCallingItem::CallMapCallingItem(double factor, TraceCall* c)
++{
++ _factor = factor;
++ _c = c;
++}
++
++void CallMapCallingItem::init()
++{
++#if 0
++ // create assoziation: if not possible, i.e. an ass. already exists
++ // for the function, we need to draw the recursive version
++ _recursive = !setFunction(_c->called());
++ _valid = true;
++#endif
++}
++
++TQString CallMapCallingItem::text(int textNo) const
++{
++ if (textNo == 0) {
++ if (!_c)
++ return i18n("(no call)");
++
++ return _c->calledName();
++ }
++
++ if (textNo == 2) return _c->called()->prettyLocation();
++ if (textNo == 3) return SubCost(_factor * _c->callCount()).pretty();
++ if (textNo != 1) return TQString();
++
++ TraceCostType* ct;
++ ct = ((CallMapView*)widget())->costType();
++
++ SubCost val = SubCost(_factor * _c->subCost(ct));
++ if (Configuration::showPercentage()) {
++ // percentage relative to function cost
++ TraceCost* t = ((CallMapView*)widget())->totalCost();
++ double p = 100.0 * _factor * _c->subCost(ct) / t->subCost(ct);
++ return TQString("%1 %")
++ .arg(p, 0, 'f', Configuration::percentPrecision());
++ }
++ return val.pretty();
++}
++
++TQPixmap CallMapCallingItem::pixmap(int i) const
++{
++ if (i != 1) return TQPixmap();
++
++ // Cost pixmap
++ TraceCostType* ct = ((CallMapView*)widget())->costType();
++ TraceCost* t = ((CallMapView*)widget())->totalCost();
++
++ // colored level meter with frame
++ return costPixmap( ct, _c, t->subCost(ct) / _factor, true);
++}
++
++
++double CallMapCallingItem::value() const
++{
++ TraceCostType* ct;
++ ct = ((CallMapView*)widget())->costType();
++ return _factor * _c->subCost(ct);
++}
++
++double CallMapCallingItem::sum() const
++{
++ return value();
++}
++
++bool CallMapCallingItem::isMarked(int) const
++{
++ return ((CallMapView*)widget())->selectedItem() == _c->called();
++}
++
++
++TreeMapItemList* CallMapCallingItem::children()
++{
++ if (!initialized()) {
++ if (0) qDebug("Create Calling subitems (%s)", path(0).join("/").ascii());
++
++ TraceCostType* ct;
++ ct = ((CallMapView*)widget())->costType();
++
++ // same as sum()
++ SubCost s = _c->called()->inclusive()->subCost(ct);
++ SubCost v = _c->subCost(ct);
++ if (v>s) {
++ qDebug("Warning: CallingItem subVal %u > Sum %u (%s)",
++ (unsigned)v, (unsigned)s, _c->called()->prettyName().ascii());
++ v = s;
++ }
++ double newFactor = _factor * v / s;
++
++#if 0
++ qDebug("CallingItem: Subitems of %s => %s, factor %f * %d/%d => %f",
++ _c->caller()->prettyName().ascii(),
++ _c->called()->prettyName().ascii(),
++ _factor, v, s, newFactor);
++#endif
++ setSorting(-1);
++ TraceCall* call;
++ TraceCallList l = _c->called()->callings();
++ for (call=l.first();call;call=l.next()) {
++
++ // don't show calls inside of a cycle
++ if (call->inCycle()>0) continue;
++ if (call->isRecursion()) continue;
++
++ CallMapCallingItem* i = new CallMapCallingItem(newFactor, call);
++ i->init();
++ addItem(i);
++ }
++ setSorting(-2, false);
++ }
++
++ return _children;
++}
++
++
++TQColor CallMapCallingItem::backColor() const
++{
++ CallMapView* w = (CallMapView*)widget();
++ return w->groupColor(_c->called());
++}
++
++
++// CallMapCallerItem
++
++CallMapCallerItem::CallMapCallerItem(double factor, TraceCall* c)
++{
++ _factor = factor;
++ _c = c;
++}
++
++TQString CallMapCallerItem::text(int textNo) const
++{
++ if (textNo == 0) {
++ if (!_c)
++ return i18n("(no call)");
++
++ return _c->callerName();
++ }
++
++ if (textNo == 2) return _c->caller()->prettyLocation();
++ if (textNo == 3) return SubCost(_factor * _c->callCount()).pretty();
++ if (textNo != 1) return TQString();
++
++ TraceCostType* ct;
++ ct = ((CallMapView*)widget())->costType();
++
++ SubCost val = SubCost(_factor * _c->subCost(ct));
++ if (Configuration::showPercentage()) {
++ TraceCost* t = ((CallMapView*)widget())->totalCost();
++ double p = 100.0 * _factor * _c->subCost(ct) / t->subCost(ct);
++ return TQString("%1 %")
++ .arg(p, 0, 'f', Configuration::percentPrecision());
++ }
++ return val.pretty();
++}
++
++
++TQPixmap CallMapCallerItem::pixmap(int i) const
++{
++ if (i != 1) return TQPixmap();
++
++ // Cost pixmap
++ TraceCostType* ct = ((CallMapView*)widget())->costType();
++ TraceCost* t = ((CallMapView*)widget())->totalCost();
++
++ // colored level meter with frame
++ return costPixmap( ct, _c, t->subCost(ct) / _factor, true );
++}
++
++
++double CallMapCallerItem::value() const
++{
++ TraceCostType* ct;
++ ct = ((CallMapView*)widget())->costType();
++ return (double) _c->subCost(ct);
++}
++
++bool CallMapCallerItem::isMarked(int) const
++{
++ return ((CallMapView*)widget())->selectedItem() == _c->caller();
++}
++
++
++TreeMapItemList* CallMapCallerItem::children()
++{
++ if (!initialized()) {
++ //qDebug("Create Caller subitems (%s)", name().ascii());
++
++ TraceCostType* ct;
++ ct = ((CallMapView*)widget())->costType();
++
++ SubCost s = _c->caller()->inclusive()->subCost(ct);
++ SubCost v = _c->subCost(ct);
++ double newFactor = _factor * v / s;
++
++
++#if 0
++ qDebug("CallerItem: Subitems of %s => %s, factor %f * %d/%d => %f",
++ _c->caller()->prettyName().ascii(),
++ _c->called()->prettyName().ascii(),
++ _factor, v, s, newFactor);
++#endif
++ setSorting(-1);
++
++ TraceCall* call;
++ TraceCallList l = _c->caller()->callers();
++ for (call=l.first();call;call=l.next()) {
++
++ // don't show calls inside of a cycle
++ if (call->inCycle()>0) continue;
++ if (call->isRecursion()) continue;
++
++ TreeMapItem* i = new CallMapCallerItem(newFactor, call);
++ addItem(i);
++ }
++ setSorting(-2, false);
++ }
++
++ return _children;
++}
++
++TQColor CallMapCallerItem::backColor() const
++{
++ CallMapView* w = (CallMapView*)widget();
++ return w->groupColor(_c->caller());
++}
++
++void CallMapView::readViewConfig(KConfig* c,
++ TQString prefix, TQString postfix, bool)
++{
++ KConfigGroup* g = configGroup(c, prefix, postfix);
++
++ setSplitMode(g->readEntry("SplitMode", DEFAULT_SPLITMODE));
++
++ setFieldVisible(0, g->readBoolEntry("DrawName", DEFAULT_DRAWNAME));
++ setFieldVisible(1, g->readBoolEntry("DrawCost", DEFAULT_DRAWCOST));
++ setFieldVisible(2, g->readBoolEntry("DrawLocation", DEFAULT_DRAWLOCATION));
++ setFieldVisible(3, g->readBoolEntry("DrawCalls", DEFAULT_DRAWCALLS));
++
++ bool enable = g->readBoolEntry("ForceStrings", DEFAULT_FORCESTRINGS);
++ setFieldForced(0, enable);
++ setFieldForced(1, enable);
++ setFieldForced(2, enable);
++ setFieldForced(3, enable);
++
++ setAllowRotation(g->readBoolEntry("AllowRotation", DEFAULT_ROTATION));
++ setShadingEnabled(g->readBoolEntry("Shading", DEFAULT_SHADING));
++ setFieldStop(0, g->readEntry("StopName"));
++ setMaxDrawingDepth(g->readNumEntry("MaxDepth", -1));
++ setMinimalArea(g->readNumEntry("MaxArea", DEFAULT_MAXAREA));
++
++ delete g;
++}
++
++void CallMapView::saveViewConfig(KConfig* c,
++ TQString prefix, TQString postfix, bool)
++{
++ KConfigGroup g(c, (prefix+postfix).ascii());
++
++ writeConfigEntry(&g, "SplitMode", splitModeString(), DEFAULT_SPLITMODE);
++ writeConfigEntry(&g, "DrawName", fieldVisible(0), DEFAULT_DRAWNAME);
++ writeConfigEntry(&g, "DrawCost", fieldVisible(1), DEFAULT_DRAWCOST);
++ writeConfigEntry(&g, "DrawLocation", fieldVisible(2), DEFAULT_DRAWLOCATION);
++ writeConfigEntry(&g, "DrawCalls", fieldVisible(3), DEFAULT_DRAWCALLS);
++ // when option for all text (0-3)
++ writeConfigEntry(&g, "ForceStrings", fieldForced(0), DEFAULT_FORCESTRINGS);
++
++ writeConfigEntry(&g, "AllowRotation", allowRotation(), DEFAULT_ROTATION);
++ writeConfigEntry(&g, "Shading", isShadingEnabled(), DEFAULT_SHADING);
++
++ writeConfigEntry(&g, "StopName", fieldStop(0), "");
++ writeConfigEntry(&g, "MaxDepth", maxDrawingDepth(), -1);
++ writeConfigEntry(&g, "MaxArea", minimalArea(), DEFAULT_MAXAREA);
++}
++
++#include "callmapview.moc"
+diff --git a/kdecachegrind/kdecachegrind/callmapview.h b/kdecachegrind/kdecachegrind/callmapview.h
+new file mode 100644
+index 0000000..860743f
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/callmapview.h
+@@ -0,0 +1,130 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Call Map View
++ */
++
++#ifndef CALLMAPVIEW_H
++#define CALLMAPVIEW_H
++
++#include "treemap.h"
++#include "tracedata.h"
++#include "traceitemview.h"
++
++class CallMapView: public TreeMapWidget, public TraceItemView
++{
++ Q_OBJECT
++ TQ_OBJECT
++
++public:
++
++ CallMapView(bool showCallers, TraceItemView* parentView,
++ TQWidget* parent=0, const char* name=0);
++
++ TQWidget* widget() { return this; }
++ TQString whatsThis() const;
++ void setData(TraceData*);
++
++ void readViewConfig(KConfig*, TQString prefix, TQString postfix, bool);
++ void saveViewConfig(KConfig*, TQString prefix, TQString postfix, bool);
++
++ bool showCallers() const { return _showCallers; }
++ TraceCost* totalCost();
++ TQString tipString(TreeMapItem*) const;
++ TQColor groupColor(TraceFunction*) const;
++
++private slots:
++ void context(TreeMapItem*,const TQPoint &);
++ void selectedSlot(TreeMapItem*, bool);
++ void activatedSlot(TreeMapItem*);
++
++private:
++ TraceItem* canShow(TraceItem*);
++ void doUpdate(int);
++
++ bool _showCallers;
++};
++
++
++
++// Subitems of CallMap
++
++class CallMapBaseItem: public TreeMapItem
++{
++public:
++ CallMapBaseItem();
++
++ void setFunction(TraceFunction* f);
++ TraceFunction* function() { return _f; }
++ int rtti() const { return 1; }
++ double sum() const;
++ double value() const ;
++ bool isMarked(int) const;
++ TQString text(int) const;
++ TQPixmap pixmap(int) const;
++ TreeMapItemList* children();
++ TQColor backColor() const;
++
++private:
++ TraceFunction* _f;
++};
++
++
++class CallMapCallingItem: public TreeMapItem
++{
++public:
++ CallMapCallingItem(double factor, TraceCall* c);
++ void init();
++ int rtti() const { return 2; }
++ int borderWidth() const { return widget()->borderWidth(); }
++ TraceFunction* function() { return _c->called(); }
++ double value() const;
++ double sum() const;
++ bool isMarked(int) const;
++ TQString text(int) const;
++ TQPixmap pixmap(int) const;
++ TreeMapItemList* children();
++ TQColor backColor() const;
++
++private:
++ TraceCall* _c;
++ double _factor;
++};
++
++class CallMapCallerItem: public TreeMapItem
++{
++public:
++ CallMapCallerItem(double factor, TraceCall* c);
++ int rtti() const { return 3; }
++ int borderWidth() const { return widget()->borderWidth(); }
++ TraceFunction* function() { return _c->caller(); }
++ double value() const;
++ bool isMarked(int) const;
++ TQString text(int) const;
++ TQPixmap pixmap(int) const;
++ TreeMapItemList* children();
++ TQColor backColor() const;
++
++private:
++ TraceCall* _c;
++ double _factor;
++};
++
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/callview.cpp b/kdecachegrind/kdecachegrind/callview.cpp
+new file mode 100644
+index 0000000..317d137
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/callview.cpp
+@@ -0,0 +1,256 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Call Views
++ */
++
++#include <tqwhatsthis.h>
++#include <tqpopupmenu.h>
++#include <klocale.h>
++
++#include "configuration.h"
++#include "callitem.h"
++#include "callview.h"
++
++
++
++//
++// CallView
++//
++
++
++CallView::CallView(bool showCallers, TraceItemView* parentView,
++ TQWidget* parent, const char* name)
++ : TQListView(parent, name), TraceItemView(parentView)
++{
++ _showCallers = showCallers;
++
++ addColumn( i18n( "Cost" ) );
++ addColumn( i18n( "Cost 2" ) );
++ if (_showCallers) {
++ addColumn( i18n( "Count" ) );
++ addColumn( i18n( "Caller" ) );
++ }
++ else {
++ addColumn( i18n( "Count" ) );
++ addColumn( i18n( "Callee" ) );
++ }
++
++ setSorting(0,false);
++ setColumnAlignment(0, TQt::AlignRight);
++ setColumnAlignment(1, TQt::AlignRight);
++ setColumnAlignment(2, TQt::AlignRight);
++ setAllColumnsShowFocus(true);
++ setResizeMode(TQListView::LastColumn);
++ setMinimumHeight(50);
++
++ connect( this,
++ TQT_SIGNAL( selectionChanged(TQListViewItem*) ),
++ TQT_SLOT( selectedSlot(TQListViewItem*) ) );
++
++ connect( this,
++ TQT_SIGNAL(contextMenuRequested(TQListViewItem*, const TQPoint &, int)),
++ TQT_SLOT(context(TQListViewItem*, const TQPoint &, int)));
++
++ connect(this,
++ TQT_SIGNAL(doubleClicked(TQListViewItem*)),
++ TQT_SLOT(activatedSlot(TQListViewItem*)));
++
++ connect(this,
++ TQT_SIGNAL(returnPressed(TQListViewItem*)),
++ TQT_SLOT(activatedSlot(TQListViewItem*)));
++
++ TQWhatsThis::add( this, whatsThis() );
++}
++
++TQString CallView::whatsThis() const
++{
++ return _showCallers ?
++ i18n( "<b>List of direct Callers</b>"
++ "<p>This list shows all functions calling the "
++ "current selected one directly, together with "
++ "a call count and the cost spent in the current "
++ "selected function while being called from the "
++ "function from the list.</p>"
++ "<p>An icon instead of an inclusive cost specifies "
++ "that this is a call inside of a recursive cycle. "
++ "An inclusive cost makes no sense here.</p>"
++ "<p>Selecting a function makes it the current selected "
++ "one of this information panel. "
++ "If there are two panels (Split mode), the "
++ "function of the other panel is changed instead.</p>") :
++ i18n( "<b>List of direct Callees</b>"
++ "<p>This list shows all functions called by the "
++ "current selected one directly, together with "
++ "a call count and the cost spent in this function "
++ "while being called from the selected function.</p>"
++ "<p>Selecting a function makes it the current selected "
++ "one of this information panel. "
++ "If there are two panels (Split mode), the "
++ "function of the other panel is changed instead.</p>");
++}
++
++
++void CallView::context(TQListViewItem* i, const TQPoint & p, int col)
++{
++ TQPopupMenu popup;
++
++ // Menu entry:
++ TraceCall* c = i ? ((CallItem*) i)->call() : 0;
++ TraceFunction *f = 0, *cycle = 0;
++
++ if (c) {
++ TQString name = _showCallers ? c->callerName(true) : c->calledName(true);
++ f = _showCallers ? c->caller(true) : c->called(true);
++ cycle = f->cycle();
++
++ popup.insertItem(i18n("Go to '%1'")
++ .arg(Configuration::shortenSymbol(name)), 93);
++
++ if (cycle) {
++ name = Configuration::shortenSymbol(cycle->prettyName());
++ popup.insertItem(i18n("Go to '%1'").arg(name), 94);
++ }
++
++ popup.insertSeparator();
++ }
++
++ if ((col == 0) || (col == 1)) {
++ addCostMenu(&popup);
++ popup.insertSeparator();
++ }
++ addGoMenu(&popup);
++
++ int r = popup.exec(p);
++ if (r == 93) activated(f);
++ else if (r == 94) activated(cycle);
++}
++
++void CallView::selectedSlot(TQListViewItem * i)
++{
++ if (!i) return;
++ TraceCall* c = ((CallItem*) i)->call();
++ // Should we skip cycles here?
++ TraceItem* f = _showCallers ? c->caller(false) : c->called(false);
++
++ _selectedItem = f;
++ selected(f);
++}
++
++void CallView::activatedSlot(TQListViewItem * i)
++{
++ if (!i) return;
++ TraceCall* c = ((CallItem*) i)->call();
++ // skip cycles: use the context menu to get to the cycle...
++ TraceItem* f = _showCallers ? c->caller(true) : c->called(true);
++
++ activated(f);
++}
++
++TraceItem* CallView::canShow(TraceItem* i)
++{
++ TraceItem::CostType t = i ? i->type() : TraceItem::NoCostType;
++
++ switch(t) {
++ case TraceItem::Function:
++ case TraceItem::FunctionCycle:
++ return i;
++ default:
++ break;
++ }
++ return 0;
++}
++
++void CallView::doUpdate(int changeType)
++{
++ // Special case ?
++ if (changeType == selectedItemChanged) {
++
++ if (!_selectedItem) {
++ clearSelection();
++ return;
++ }
++
++ CallItem* ci = (CallItem*) TQListView::selectedItem();
++ TraceCall* c;
++ TraceItem* ti;
++ if (ci) {
++ c = ci->call();
++ ti = _showCallers ? c->caller() : c->called();
++ if (ti == _selectedItem) return;
++ }
++
++ TQListViewItem *item;
++ for (item = firstChild();item;item = item->nextSibling()) {
++ c = ((CallItem*) item)->call();
++ ti = _showCallers ? c->caller() : c->called();
++ if (ti == _selectedItem) {
++ ensureItemVisible(item);
++ setSelected(item, true);
++ break;
++ }
++ }
++ if (!item && ci) clearSelection();
++ return;
++ }
++
++ if (changeType == groupTypeChanged) {
++ TQListViewItem *item;
++ for (item = firstChild();item;item = item->nextSibling())
++ ((CallItem*)item)->updateGroup();
++ return;
++ }
++
++ refresh();
++}
++
++void CallView::refresh()
++{
++ clear();
++ setColumnWidth(0, 50);
++ setColumnWidth(1, _costType2 ? 50:0);
++ setColumnWidth(2, 50);
++ if (_costType)
++ setColumnText(0, _costType->name());
++ if (_costType2)
++ setColumnText(1, _costType2->name());
++
++ if (!_data || !_activeItem) return;
++
++ TraceFunction* f = activeFunction();
++ if (!f) return;
++
++ TraceCall* call;
++ // In the call lists, we skip cycles to show the real call relations
++ TraceCallList l = _showCallers ? f->callers(true) : f->callings(true);
++
++ // Allow resizing of column 1
++ setColumnWidthMode(1, TQListView::Maximum);
++
++ for (call=l.first();call;call=l.next())
++ if (call->subCost(_costType)>0)
++ new CallItem(this, this, call);
++
++ if (!_costType2) {
++ setColumnWidthMode(1, TQListView::Manual);
++ setColumnWidth(1, 0);
++ }
++}
++
++#include "callview.moc"
+diff --git a/kdecachegrind/kdecachegrind/callview.h b/kdecachegrind/kdecachegrind/callview.h
+new file mode 100644
+index 0000000..be644f9
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/callview.h
+@@ -0,0 +1,56 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Call Views
++ */
++
++#ifndef CALLVIEW_H
++#define CALLVIEW_H
++
++#include <tqlistview.h>
++#include "tracedata.h"
++#include "traceitemview.h"
++
++class CallView: public TQListView, public TraceItemView
++{
++ Q_OBJECT
++ TQ_OBJECT
++
++public:
++ CallView(bool showCallers, TraceItemView* parentView,
++ TQWidget* parent=0, const char* name=0);
++
++ virtual TQWidget* widget() { return this; }
++ TQString whatsThis() const;
++ bool showCallers() const { return _showCallers; }
++
++private slots:
++ void context(TQListViewItem*,const TQPoint &, int);
++ void selectedSlot(TQListViewItem*);
++ void activatedSlot(TQListViewItem*);
++
++private:
++ TraceItem* canShow(TraceItem*);
++ void doUpdate(int);
++ void refresh();
++
++ bool _showCallers;
++};
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/configdlg.cpp b/kdecachegrind/kdecachegrind/configdlg.cpp
+new file mode 100644
+index 0000000..e0b4547
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/configdlg.cpp
+@@ -0,0 +1,398 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Configuration Dialog for KCachegrind
++ */
++
++#include <tqcombobox.h>
++#include <tqcheckbox.h>
++#include <tqlineedit.h>
++#include <tqlistview.h>
++#include <tqdict.h>
++#include <tqmessagebox.h>
++
++#include <kcolorbutton.h>
++#include <kfiledialog.h>
++#include <klocale.h>
++#include <knumvalidator.h>
++
++#include "configdlg.h"
++#include "tracedata.h"
++#include "configuration.h"
++
++
++ConfigDlg::ConfigDlg(Configuration* c, TraceData* data,
++ TQWidget* parent, const char* name)
++ :ConfigDlgBase(parent, name)
++{
++ _config = c;
++ _data = data;
++ _objectCS = 0;
++ _classCS = 0;
++ _fileCS = 0;
++ KIntValidator * numValidator = new KIntValidator( this );
++ maxListEdit->setValidator(numValidator );
++ symbolCount->setValidator(numValidator );
++ symbolLength->setValidator(numValidator );
++ precisionEdit->setValidator(numValidator );
++ contextEdit->setValidator(numValidator );
++
++#if 0
++ TQListViewItem *oItem, *fItem, *cItem, *fnItem;
++ oItem = new(colorList, i18n("ELF Objects"));
++
++ fItem = new(colorList, i18n("Source Files"));
++ cItem = new(colorList, i18n("C++ Classes"));
++ fnItem = new(colorList, i18n("Function (no Grouping)"));
++#endif
++
++ connect(objectCombo, TQT_SIGNAL(activated(const TQString &)),
++ this, TQT_SLOT(objectActivated(const TQString &)));
++ connect(objectCombo, TQT_SIGNAL(textChanged(const TQString &)),
++ this, TQT_SLOT(objectActivated(const TQString &)));
++ connect(objectCheck, TQT_SIGNAL(toggled(bool)),
++ this, TQT_SLOT(objectCheckChanged(bool)));
++ connect(objectColor, TQT_SIGNAL(changed(const TQColor &)),
++ this, TQT_SLOT(objectColorChanged(const TQColor &)));
++
++ connect(classCombo, TQT_SIGNAL(activated(const TQString &)),
++ this, TQT_SLOT(classActivated(const TQString &)));
++ connect(classCombo, TQT_SIGNAL(textChanged(const TQString &)),
++ this, TQT_SLOT(classActivated(const TQString &)));
++ connect(classCheck, TQT_SIGNAL(toggled(bool)),
++ this, TQT_SLOT(classCheckChanged(bool)));
++ connect(classColor, TQT_SIGNAL(changed(const TQColor &)),
++ this, TQT_SLOT(classColorChanged(const TQColor &)));
++
++ connect(fileCombo, TQT_SIGNAL(activated(const TQString &)),
++ this, TQT_SLOT(fileActivated(const TQString &)));
++ connect(fileCombo, TQT_SIGNAL(textChanged(const TQString &)),
++ this, TQT_SLOT(fileActivated(const TQString &)));
++ connect(fileCheck, TQT_SIGNAL(toggled(bool)),
++ this, TQT_SLOT(fileCheckChanged(bool)));
++ connect(fileColor, TQT_SIGNAL(changed(const TQColor &)),
++ this, TQT_SLOT(fileColorChanged(const TQColor &)));
++
++ TQString objectPrefix = TraceCost::typeName(TraceCost::Object);
++ TQString classPrefix = TraceCost::typeName(TraceCost::Class);
++ TQString filePrefix = TraceCost::typeName(TraceCost::File);
++
++ objectCombo->setDuplicatesEnabled(false);
++ classCombo->setDuplicatesEnabled(false);
++ fileCombo->setDuplicatesEnabled(false);
++ objectCombo->setAutoCompletion(true);
++ classCombo->setAutoCompletion(true);
++ fileCombo->setAutoCompletion(true);
++
++ // first unspecified cost items from data
++ TraceObjectMap::Iterator oit;
++ TQStringList oList;
++ for ( oit = data->objectMap().begin();
++ oit != data->objectMap().end(); ++oit )
++ oList.append((*oit).prettyName());
++
++ TraceClassMap::Iterator cit;
++ TQStringList cList;
++ for ( cit = data->classMap().begin();
++ cit != data->classMap().end(); ++cit )
++ cList.append((*cit).prettyName());
++
++ TraceFileMap::Iterator fit;
++ TQStringList fList;
++ for ( fit = data->fileMap().begin();
++ fit != data->fileMap().end(); ++fit )
++ fList.append((*fit).prettyName());
++
++ // then already defined colors (have to check for duplicates!)
++ TQDictIterator<Configuration::ColorSetting> it( c->_colors );
++ for( ; it.current(); ++it ) {
++ if ((*it)->automatic) continue;
++
++ TQString n = it.currentKey();
++ if (n.startsWith(objectPrefix)) {
++ n = n.remove(0, objectPrefix.length()+1);
++ if (oList.findIndex(n) == -1) oList.append(n);
++ }
++ else if (n.startsWith(classPrefix)) {
++ n = n.remove(0, classPrefix.length()+1);
++ if (cList.findIndex(n) == -1) cList.append(n);
++ }
++ else if (n.startsWith(filePrefix)) {
++ n = n.remove(0, filePrefix.length()+1);
++ if (fList.findIndex(n) == -1) fList.append(n);
++ }
++ }
++
++ oList.sort();
++ cList.sort();
++ fList.sort();
++ objectCombo->insertStringList(oList);
++ classCombo->insertStringList(cList);
++ fileCombo->insertStringList(fList);
++
++ objectActivated(objectCombo->currentText());
++ classActivated(classCombo->currentText());
++ fileActivated(fileCombo->currentText());
++
++ maxListEdit->setText(TQString::number(c->_maxListCount));
++
++ _dirItem = 0;
++
++ TQListViewItem* i = new TQListViewItem(dirList, i18n("(always)"));
++ i->setOpen(true);
++ TQStringList::Iterator sit = c->_generalSourceDirs.begin();
++ for(; sit != c->_generalSourceDirs.end(); ++sit ) {
++ TQString d = (*sit);
++ if (d.isEmpty()) d = "/";
++ new TQListViewItem(i, d);
++ }
++ for ( oit = data->objectMap().begin();
++ oit != data->objectMap().end(); ++oit ) {
++ TQString n = (*oit).name();
++ i = new TQListViewItem(dirList, n);
++ i->setOpen(true);
++ TQStringList* dirs = c->_objectSourceDirs[n];
++ if (!dirs) continue;
++
++ sit = dirs->begin();
++ for(; sit != dirs->end(); ++sit ) {
++ TQString d = (*sit);
++ if (d.isEmpty()) d = "/";
++ new TQListViewItem(i, d);
++ }
++ }
++
++ connect(dirList, TQT_SIGNAL(selectionChanged(TQListViewItem*)),
++ this, TQT_SLOT(dirsItemChanged(TQListViewItem*)));
++ connect(addDirButton, TQT_SIGNAL(clicked()),
++ this, TQT_SLOT(dirsAddPressed()));
++ connect(deleteDirButton, TQT_SIGNAL(clicked()),
++ this, TQT_SLOT(dirsDeletePressed()));
++ dirList->setSelected(dirList->firstChild(), true);
++
++ symbolCount->setText(TQString::number(c->_maxSymbolCount));
++ symbolLength->setText(TQString::number(c->_maxSymbolLength));
++ precisionEdit->setText(TQString::number(c->_percentPrecision));
++ contextEdit->setText(TQString::number(c->_context));
++}
++
++ConfigDlg::~ConfigDlg()
++{
++}
++
++bool ConfigDlg::configure(Configuration* c, TraceData* d, TQWidget* p)
++{
++ ConfigDlg dlg(c, d, p);
++
++ if (dlg.exec()) {
++
++ bool ok;
++ int newValue = dlg.maxListEdit->text().toUInt(&ok);
++ if (ok && newValue < 500)
++ c->_maxListCount = newValue;
++ else
++ TQMessageBox::warning(p, i18n("KCachegrind Configuration"),
++ i18n("The Maximum Number of List Items should be below 500."
++ "The previous set value (%1) will still be used.")
++ .arg(TQString::number(c->_maxListCount)),
++ TQMessageBox::Ok, 0);
++
++ c->_maxSymbolCount = dlg.symbolCount->text().toInt();
++ c->_maxSymbolLength = dlg.symbolLength->text().toInt();
++ c->_percentPrecision = dlg.precisionEdit->text().toInt();
++ c->_context = dlg.contextEdit->text().toInt();
++ return true;
++ }
++ return false;
++}
++
++void ConfigDlg::objectActivated(const TQString & s)
++{
++// qDebug("objectActivated: %s", s.ascii());
++
++ if (s.isEmpty()) { _objectCS=0; return; }
++
++ TQString n = TraceCost::typeName(TraceCost::Object) + "-" + s;
++
++ Configuration* c = Configuration::config();
++ Configuration::ColorSetting* cs = c->_colors[n];
++ if (!cs)
++ cs = Configuration::color(n);
++// else
++// qDebug("found color %s", n.ascii());
++
++ _objectCS = cs;
++
++ objectCheck->setChecked(cs->automatic);
++ objectColor->setColor(cs->color);
++
++ /*
++ qDebug("Found Color %s, automatic to %s",
++ _objectCS->name.ascii(),
++ _objectCS->automatic ? "true":"false");
++ */
++}
++
++
++void ConfigDlg::objectCheckChanged(bool b)
++{
++ if (_objectCS) {
++ _objectCS->automatic = b;
++ /*
++ qDebug("Set Color %s automatic to %s",
++ _objectCS->name.ascii(),
++ _objectCS->automatic ? "true":"false");
++ */
++ }
++}
++
++void ConfigDlg::objectColorChanged(const TQColor & c)
++{
++ if (_objectCS) _objectCS->color = c;
++}
++
++void ConfigDlg::classActivated(const TQString & s)
++{
++// qDebug("classActivated: %s", s.ascii());
++
++ if (s.isEmpty()) { _classCS=0; return; }
++
++ TQString n = TraceCost::typeName(TraceCost::Class) + "-" + s;
++
++ Configuration* c = Configuration::config();
++ Configuration::ColorSetting* cs = c->_colors[n];
++ if (!cs)
++ cs = Configuration::color(n);
++
++ _classCS = cs;
++
++ classCheck->setChecked(cs->automatic);
++ classColor->setColor(cs->color);
++
++}
++
++
++void ConfigDlg::classCheckChanged(bool b)
++{
++ if (_classCS) _classCS->automatic = b;
++}
++
++void ConfigDlg::classColorChanged(const TQColor & c)
++{
++ if (_classCS) _classCS->color = c;
++}
++
++
++void ConfigDlg::fileActivated(const TQString & s)
++{
++// qDebug("fileActivated: %s", s.ascii());
++
++ if (s.isEmpty()) { _fileCS=0; return; }
++
++ TQString n = TraceCost::typeName(TraceCost::File) + "-" + s;
++
++ Configuration* c = Configuration::config();
++ Configuration::ColorSetting* cs = c->_colors[n];
++ if (!cs)
++ cs = Configuration::color(n);
++
++ _fileCS = cs;
++
++ fileCheck->setChecked(cs->automatic);
++ fileColor->setColor(cs->color);
++}
++
++
++void ConfigDlg::fileCheckChanged(bool b)
++{
++ if (_fileCS) _fileCS->automatic = b;
++}
++
++void ConfigDlg::fileColorChanged(const TQColor & c)
++{
++ if (_fileCS) _fileCS->color = c;
++}
++
++
++void ConfigDlg::dirsItemChanged(TQListViewItem* i)
++{
++ _dirItem = i;
++ deleteDirButton->setEnabled(i->depth() == 1);
++ addDirButton->setEnabled(i->depth() == 0);
++}
++
++void ConfigDlg::dirsDeletePressed()
++{
++ if (!_dirItem || (_dirItem->depth() == 0)) return;
++ TQListViewItem* p = _dirItem->parent();
++ if (!p) return;
++
++ Configuration* c = Configuration::config();
++ TQString objName = p->text(0);
++
++ TQStringList* dirs;
++ if (objName == i18n("(always)"))
++ dirs = &(c->_generalSourceDirs);
++ else
++ dirs = c->_objectSourceDirs[objName];
++ if (!dirs) return;
++
++ dirs->remove(_dirItem->text(0));
++ delete _dirItem;
++ _dirItem = 0;
++
++ deleteDirButton->setEnabled(false);
++}
++
++void ConfigDlg::dirsAddPressed()
++{
++ if (!_dirItem || (_dirItem->depth() >0)) return;
++
++ Configuration* c = Configuration::config();
++ TQString objName = _dirItem->text(0);
++
++ TQStringList* dirs;
++ if (objName == i18n("(always)"))
++ dirs = &(c->_generalSourceDirs);
++ else {
++ dirs = c->_objectSourceDirs[objName];
++ if (!dirs) {
++ dirs = new TQStringList;
++ c->_objectSourceDirs.insert(objName, dirs);
++ }
++ }
++
++ TQString newDir;
++ newDir = KFileDialog::getExistingDirectory(TQString(),
++ this,
++ i18n("Choose Source Folder"));
++ if (newDir.isEmpty()) return;
++
++ // even for "/", we strip the tailing slash
++ if (newDir.endsWith("/"))
++ newDir = newDir.left(newDir.length()-1);
++
++ if (dirs->findIndex(newDir)>=0) return;
++
++ dirs->append(newDir);
++ if (newDir.isEmpty()) newDir = TQString("/");
++ new TQListViewItem(_dirItem, newDir);
++}
++
++#include "configdlg.moc"
+diff --git a/kdecachegrind/kdecachegrind/configdlg.h b/kdecachegrind/kdecachegrind/configdlg.h
+new file mode 100644
+index 0000000..5ef6bab
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/configdlg.h
+@@ -0,0 +1,65 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Configuration Dialog for KCachegrind
++ */
++
++#ifndef CONFIGDLG_H
++#define CONFIGDLG_H
++
++#include "configdlgbase.h"
++#include "configuration.h"
++
++class TraceData;
++
++class ConfigDlg : public ConfigDlgBase
++{
++ Q_OBJECT
++ TQ_OBJECT
++
++public:
++ ConfigDlg(Configuration*, TraceData*,
++ TQWidget* parent = 0, const char* name = 0);
++ ~ConfigDlg();
++
++ static bool configure(Configuration*, TraceData*, TQWidget*);
++
++protected slots:
++ void objectActivated(const TQString &);
++ void objectCheckChanged(bool);
++ void objectColorChanged(const TQColor &);
++ void classActivated(const TQString &);
++ void classCheckChanged(bool);
++ void classColorChanged(const TQColor &);
++ void fileActivated(const TQString &);
++ void fileCheckChanged(bool);
++ void fileColorChanged(const TQColor &);
++ void dirsItemChanged(TQListViewItem*);
++ void dirsDeletePressed();
++ void dirsAddPressed();
++
++private:
++ Configuration* _config;
++ TraceData* _data;
++
++ Configuration::ColorSetting *_objectCS, *_classCS, *_fileCS;
++ TQListViewItem* _dirItem;
++};
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/configdlgbase.ui b/kdecachegrind/kdecachegrind/configdlgbase.ui
+new file mode 100644
+index 0000000..dc0ee9e
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/configdlgbase.ui
+@@ -0,0 +1,653 @@
++<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
++<class>ConfigDlgBase</class>
++<widget class="TQDialog">
++ <property name="name">
++ <cstring>configDlgBase</cstring>
++ </property>
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>447</width>
++ <height>378</height>
++ </rect>
++ </property>
++ <property name="caption">
++ <string>Configuration</string>
++ </property>
++ <vbox>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <property name="margin">
++ <number>11</number>
++ </property>
++ <property name="spacing">
++ <number>6</number>
++ </property>
++ <widget class="TQTabWidget">
++ <property name="name">
++ <cstring>tabWidget2</cstring>
++ </property>
++ <widget class="TQWidget">
++ <property name="name">
++ <cstring>tab</cstring>
++ </property>
++ <attribute name="title">
++ <string>General</string>
++ </attribute>
++ <vbox>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <widget class="TQLayoutWidget">
++ <property name="name">
++ <cstring>layout10</cstring>
++ </property>
++ <grid>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <widget class="TQLineEdit" row="3" column="2" rowspan="1" colspan="2">
++ <property name="name">
++ <cstring>precisionEdit</cstring>
++ </property>
++ <property name="sizePolicy">
++ <sizepolicy>
++ <hsizetype>7</hsizetype>
++ <vsizetype>0</vsizetype>
++ <horstretch>2</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ </widget>
++ <widget class="TQLabel" row="2" column="1">
++ <property name="name">
++ <cstring>TextLabel2</cstring>
++ </property>
++ <property name="text">
++ <string>Truncated when more/longer than:</string>
++ </property>
++ </widget>
++ <widget class="TQLabel" row="3" column="0" rowspan="1" colspan="2">
++ <property name="name">
++ <cstring>TextLabel4_3</cstring>
++ </property>
++ <property name="text">
++ <string>Precision of percentage values:</string>
++ </property>
++ </widget>
++ <widget class="TQLabel" row="1" column="0" rowspan="1" colspan="3">
++ <property name="name">
++ <cstring>TextLabel3</cstring>
++ </property>
++ <property name="text">
++ <string>Symbols in tooltips and context menus</string>
++ </property>
++ </widget>
++ <widget class="TQLineEdit" row="2" column="3">
++ <property name="name">
++ <cstring>symbolLength</cstring>
++ </property>
++ <property name="sizePolicy">
++ <sizepolicy>
++ <hsizetype>4</hsizetype>
++ <vsizetype>0</vsizetype>
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ </widget>
++ <spacer row="2" column="0">
++ <property name="name">
++ <cstring>Spacer6_2_2_2</cstring>
++ </property>
++ <property name="orientation">
++ <enum>Horizontal</enum>
++ </property>
++ <property name="sizeType">
++ <enum>Fixed</enum>
++ </property>
++ <property name="sizeHint">
++ <size>
++ <width>16</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ <widget class="TQLineEdit" row="0" column="2" rowspan="1" colspan="2">
++ <property name="name">
++ <cstring>maxListEdit</cstring>
++ </property>
++ </widget>
++ <widget class="TQLineEdit" row="2" column="2">
++ <property name="name">
++ <cstring>symbolCount</cstring>
++ </property>
++ <property name="sizePolicy">
++ <sizepolicy>
++ <hsizetype>4</hsizetype>
++ <vsizetype>0</vsizetype>
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ </widget>
++ <widget class="TQLabel" row="0" column="0" rowspan="1" colspan="2">
++ <property name="name">
++ <cstring>TextLabel5</cstring>
++ </property>
++ <property name="text">
++ <string>Maximum number of items in lists:</string>
++ </property>
++ </widget>
++ </grid>
++ </widget>
++ <widget class="TQLabel">
++ <property name="name">
++ <cstring>TextLabel1</cstring>
++ </property>
++ <property name="font">
++ <font>
++ <bold>1</bold>
++ </font>
++ </property>
++ <property name="frameShape">
++ <enum>NoFrame</enum>
++ </property>
++ <property name="frameShadow">
++ <enum>Plain</enum>
++ </property>
++ <property name="text">
++ <string>Cost Item Colors</string>
++ </property>
++ </widget>
++ <widget class="TQLayoutWidget">
++ <property name="name">
++ <cstring>Layout9</cstring>
++ </property>
++ <grid>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <property name="margin">
++ <number>0</number>
++ </property>
++ <property name="spacing">
++ <number>6</number>
++ </property>
++ <spacer row="1" column="1">
++ <property name="name">
++ <cstring>Spacer9</cstring>
++ </property>
++ <property name="orientation">
++ <enum>Vertical</enum>
++ </property>
++ <property name="sizeType">
++ <enum>Fixed</enum>
++ </property>
++ <property name="sizeHint">
++ <size>
++ <width>20</width>
++ <height>16</height>
++ </size>
++ </property>
++ </spacer>
++ <spacer row="0" column="0">
++ <property name="name">
++ <cstring>Spacer6</cstring>
++ </property>
++ <property name="orientation">
++ <enum>Horizontal</enum>
++ </property>
++ <property name="sizeType">
++ <enum>Fixed</enum>
++ </property>
++ <property name="sizeHint">
++ <size>
++ <width>16</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ <widget class="TQLayoutWidget" row="0" column="1">
++ <property name="name">
++ <cstring>Layout9</cstring>
++ </property>
++ <grid>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <property name="margin">
++ <number>0</number>
++ </property>
++ <property name="spacing">
++ <number>6</number>
++ </property>
++ <widget class="TQComboBox" row="1" column="1">
++ <property name="name">
++ <cstring>classCombo</cstring>
++ </property>
++ <property name="maximumSize">
++ <size>
++ <width>300</width>
++ <height>32767</height>
++ </size>
++ </property>
++ <property name="editable">
++ <bool>true</bool>
++ </property>
++ </widget>
++ <widget class="TQCheckBox" row="2" column="2">
++ <property name="name">
++ <cstring>fileCheck</cstring>
++ </property>
++ <property name="text">
++ <string>Automatic</string>
++ </property>
++ </widget>
++ <widget class="TQLabel" row="0" column="0">
++ <property name="name">
++ <cstring>TextLabel4</cstring>
++ </property>
++ <property name="text">
++ <string>Object:</string>
++ </property>
++ </widget>
++ <widget class="TQLabel" row="1" column="0">
++ <property name="name">
++ <cstring>TextLabel4_2_2</cstring>
++ </property>
++ <property name="text">
++ <string>Class:</string>
++ </property>
++ </widget>
++ <widget class="KColorButton" row="2" column="3">
++ <property name="name">
++ <cstring>fileColor</cstring>
++ </property>
++ <property name="sizePolicy">
++ <sizepolicy>
++ <hsizetype>0</hsizetype>
++ <vsizetype>0</vsizetype>
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ </widget>
++ <widget class="TQCheckBox" row="1" column="2">
++ <property name="name">
++ <cstring>classCheck</cstring>
++ </property>
++ <property name="text">
++ <string>Automatic</string>
++ </property>
++ </widget>
++ <widget class="KColorButton" row="0" column="3">
++ <property name="name">
++ <cstring>objectColor</cstring>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ </widget>
++ <widget class="TQCheckBox" row="0" column="2">
++ <property name="name">
++ <cstring>objectCheck</cstring>
++ </property>
++ <property name="text">
++ <string>Automatic</string>
++ </property>
++ </widget>
++ <widget class="TQLabel" row="2" column="0">
++ <property name="name">
++ <cstring>TextLabel4_2</cstring>
++ </property>
++ <property name="text">
++ <string>File:</string>
++ </property>
++ </widget>
++ <widget class="KColorButton" row="1" column="3">
++ <property name="name">
++ <cstring>classColor</cstring>
++ </property>
++ <property name="sizePolicy">
++ <sizepolicy>
++ <hsizetype>0</hsizetype>
++ <vsizetype>0</vsizetype>
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ </widget>
++ <widget class="TQComboBox" row="2" column="1">
++ <property name="name">
++ <cstring>fileCombo</cstring>
++ </property>
++ <property name="maximumSize">
++ <size>
++ <width>300</width>
++ <height>32767</height>
++ </size>
++ </property>
++ <property name="editable">
++ <bool>true</bool>
++ </property>
++ </widget>
++ <widget class="TQComboBox" row="0" column="1">
++ <property name="name">
++ <cstring>objectCombo</cstring>
++ </property>
++ <property name="sizePolicy">
++ <sizepolicy>
++ <hsizetype>3</hsizetype>
++ <vsizetype>0</vsizetype>
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="maximumSize">
++ <size>
++ <width>300</width>
++ <height>32767</height>
++ </size>
++ </property>
++ <property name="editable">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </grid>
++ </widget>
++ </grid>
++ </widget>
++ </vbox>
++ </widget>
++ <widget class="TQWidget">
++ <property name="name">
++ <cstring>tab</cstring>
++ </property>
++ <attribute name="title">
++ <string>Annotations</string>
++ </attribute>
++ <vbox>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <widget class="TQLayoutWidget">
++ <property name="name">
++ <cstring>layout8</cstring>
++ </property>
++ <hbox>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <widget class="TQLabel">
++ <property name="name">
++ <cstring>TextLabel4_3_2</cstring>
++ </property>
++ <property name="text">
++ <string>Context lines in annotations:</string>
++ </property>
++ </widget>
++ <widget class="TQLineEdit">
++ <property name="name">
++ <cstring>contextEdit</cstring>
++ </property>
++ <property name="sizePolicy">
++ <sizepolicy>
++ <hsizetype>7</hsizetype>
++ <vsizetype>0</vsizetype>
++ <horstretch>2</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ </widget>
++ </hbox>
++ </widget>
++ <widget class="TQLabel">
++ <property name="name">
++ <cstring>TextLabel1_2</cstring>
++ </property>
++ <property name="font">
++ <font>
++ <bold>1</bold>
++ </font>
++ </property>
++ <property name="text">
++ <string>Source Folders</string>
++ </property>
++ </widget>
++ <widget class="TQLayoutWidget">
++ <property name="name">
++ <cstring>layout11</cstring>
++ </property>
++ <grid>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <spacer row="0" column="0">
++ <property name="name">
++ <cstring>Spacer6_2</cstring>
++ </property>
++ <property name="orientation">
++ <enum>Horizontal</enum>
++ </property>
++ <property name="sizeType">
++ <enum>Fixed</enum>
++ </property>
++ <property name="sizeHint">
++ <size>
++ <width>16</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ <widget class="TQListView" row="0" column="1">
++ <column>
++ <property name="text">
++ <string>Object / Related Source Base</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <property name="name">
++ <cstring>dirList</cstring>
++ </property>
++ <property name="rootIsDecorated">
++ <bool>true</bool>
++ </property>
++ </widget>
++ <widget class="TQLayoutWidget" row="0" column="2">
++ <property name="name">
++ <cstring>layout10</cstring>
++ </property>
++ <vbox>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <widget class="TQPushButton">
++ <property name="name">
++ <cstring>addDirButton</cstring>
++ </property>
++ <property name="text">
++ <string>Add...</string>
++ </property>
++ </widget>
++ <spacer>
++ <property name="name">
++ <cstring>Spacer5</cstring>
++ </property>
++ <property name="orientation">
++ <enum>Vertical</enum>
++ </property>
++ <property name="sizeType">
++ <enum>Expanding</enum>
++ </property>
++ <property name="sizeHint">
++ <size>
++ <width>16</width>
++ <height>49</height>
++ </size>
++ </property>
++ </spacer>
++ <widget class="TQPushButton">
++ <property name="name">
++ <cstring>deleteDirButton</cstring>
++ </property>
++ <property name="text">
++ <string>Delete</string>
++ </property>
++ </widget>
++ </vbox>
++ </widget>
++ <spacer row="1" column="1">
++ <property name="name">
++ <cstring>Spacer9_2</cstring>
++ </property>
++ <property name="orientation">
++ <enum>Vertical</enum>
++ </property>
++ <property name="sizeType">
++ <enum>Fixed</enum>
++ </property>
++ <property name="sizeHint">
++ <size>
++ <width>20</width>
++ <height>16</height>
++ </size>
++ </property>
++ </spacer>
++ </grid>
++ </widget>
++ </vbox>
++ </widget>
++ </widget>
++ <widget class="Line">
++ <property name="name">
++ <cstring>Line1</cstring>
++ </property>
++ <property name="frameShape">
++ <enum>HLine</enum>
++ </property>
++ <property name="frameShadow">
++ <enum>Sunken</enum>
++ </property>
++ <property name="orientation">
++ <enum>Horizontal</enum>
++ </property>
++ </widget>
++ <widget class="TQLayoutWidget">
++ <property name="name">
++ <cstring>Layout4</cstring>
++ </property>
++ <hbox>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <property name="margin">
++ <number>0</number>
++ </property>
++ <property name="spacing">
++ <number>6</number>
++ </property>
++ <spacer>
++ <property name="name">
++ <cstring>Spacer2</cstring>
++ </property>
++ <property name="orientation">
++ <enum>Horizontal</enum>
++ </property>
++ <property name="sizeType">
++ <enum>Expanding</enum>
++ </property>
++ <property name="sizeHint">
++ <size>
++ <width>210</width>
++ <height>0</height>
++ </size>
++ </property>
++ </spacer>
++ <widget class="TQPushButton">
++ <property name="name">
++ <cstring>PushButton2</cstring>
++ </property>
++ <property name="text">
++ <string>&amp;OK</string>
++ </property>
++ <property name="default">
++ <bool>true</bool>
++ </property>
++ </widget>
++ <widget class="TQPushButton">
++ <property name="name">
++ <cstring>PushButton1</cstring>
++ </property>
++ <property name="text">
++ <string>&amp;Cancel</string>
++ </property>
++ </widget>
++ </hbox>
++ </widget>
++ </vbox>
++</widget>
++<connections>
++ <connection>
++ <sender>PushButton2</sender>
++ <signal>clicked()</signal>
++ <receiver>configDlgBase</receiver>
++ <slot>accept()</slot>
++ </connection>
++ <connection>
++ <sender>PushButton1</sender>
++ <signal>clicked()</signal>
++ <receiver>configDlgBase</receiver>
++ <slot>reject()</slot>
++ </connection>
++ <connection>
++ <sender>classCheck</sender>
++ <signal>toggled(bool)</signal>
++ <receiver>classColor</receiver>
++ <slot>setDisabled(bool)</slot>
++ </connection>
++ <connection>
++ <sender>fileCheck</sender>
++ <signal>toggled(bool)</signal>
++ <receiver>fileColor</receiver>
++ <slot>setDisabled(bool)</slot>
++ </connection>
++ <connection>
++ <sender>objectCheck</sender>
++ <signal>toggled(bool)</signal>
++ <receiver>objectColor</receiver>
++ <slot>setDisabled(bool)</slot>
++ </connection>
++</connections>
++<tabstops>
++ <tabstop>objectCombo</tabstop>
++ <tabstop>objectCheck</tabstop>
++ <tabstop>classCombo</tabstop>
++ <tabstop>classCheck</tabstop>
++ <tabstop>classColor</tabstop>
++ <tabstop>fileCombo</tabstop>
++ <tabstop>fileCheck</tabstop>
++ <tabstop>fileColor</tabstop>
++ <tabstop>maxListEdit</tabstop>
++ <tabstop>PushButton1</tabstop>
++ <tabstop>PushButton2</tabstop>
++</tabstops>
++<includes>
++ <include location="global" impldecl="in implementation">kcolorbutton.h</include>
++</includes>
++<pixmapinproject/>
++<layoutdefaults spacing="6" margin="11"/>
++</UI>
+diff --git a/kdecachegrind/kdecachegrind/configuration.cpp b/kdecachegrind/kdecachegrind/configuration.cpp
+new file mode 100644
+index 0000000..02d5c09
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/configuration.cpp
+@@ -0,0 +1,490 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Configuration for KCachegrind
++ */
++
++#include <kconfig.h>
++#include <klocale.h>
++#include <kdebug.h>
++
++#include "configuration.h"
++#include "tracedata.h"
++#include "configdlgbase.h"
++
++#include "traceitemview.h"
++
++//
++// Some predefined cost types...
++//
++
++static TQStringList knownTypes()
++{
++ TQStringList l;
++
++ l << "Ir" << "Dr" << "Dw"
++ << "I1mr" << "D1mr" << "D1mw"
++ << "I2mr" << "D2mr" << "D2mw"
++
++ << "Smp" << "Sys" << "User"
++ << "L1m" << "L2m" << "CEst";
++
++ return l;
++}
++
++
++static TQString knownFormula(TQString name)
++{
++ if (name =="L1m") return TQString("I1mr + D1mr + D1mw");
++ if (name =="L2m") return TQString("I2mr + D2mr + D2mw");
++ if (name =="CEst") return TQString("Ir + 10 L1m + 100 L2m");
++
++ return TQString();
++}
++
++static TQString knownLongName(TQString name)
++{
++ if (name == "Ir") return i18n("Instruction Fetch");
++ if (name =="Dr") return i18n("Data Read Access");
++ if (name =="Dw") return i18n("Data Write Access");
++ if (name =="I1mr") return i18n("L1 Instr. Fetch Miss");
++ if (name =="D1mr") return i18n("L1 Data Read Miss");
++ if (name =="D1mw") return i18n("L1 Data Write Miss");
++ if (name =="I2mr") return i18n("L2 Instr. Fetch Miss");
++ if (name =="D2mr") return i18n("L2 Data Read Miss");
++ if (name =="D2mw") return i18n("L2 Data Write Miss");
++ if (name =="Smp") return i18n("Samples");
++ if (name =="Sys") return i18n("System Time");
++ if (name =="User") return i18n("User Time");
++ if (name =="L1m") return i18n("L1 Miss Sum");
++ if (name =="L2m") return i18n("L2 Miss Sum");
++ if (name =="CEst") return i18n("Cycle Estimation");
++
++ return TQString();
++}
++
++
++
++
++//
++// Configuration
++//
++
++Configuration* Configuration::_config = 0;
++
++Configuration::Configuration()
++ :_colors(517)
++{
++ _config = 0;
++
++ _colors.setAutoDelete(true);
++ _objectSourceDirs.setAutoDelete(true);
++
++ // defaults
++ _showPercentage = true;
++ _showExpanded = false;
++ _showCycles = true;
++ _cycleCut = 0.0;
++ _percentPrecision = 2;
++
++ // max symbol count/length in tooltip/popup
++ _maxSymbolLength = 30;
++ _maxSymbolCount = 10;
++ _maxListCount = 100;
++
++ // annotation behaviour
++ _context = 3;
++ _noCostInside = 20;
++}
++
++Configuration* Configuration::config()
++{
++ if (!_config)
++ _config = new Configuration();
++
++ return _config;
++}
++
++
++void Configuration::saveOptions(KConfig* kconfig)
++{
++ Configuration* c = config();
++
++ // color options
++ KConfigGroup colorConfig(kconfig, TQCString("CostColors"));
++ TQDictIterator<ColorSetting> it( c->_colors );
++ int count = 1;
++ for( ; it.current(); ++it ) {
++ if ( !(*it)->automatic ) {
++ colorConfig.writeEntry( TQString("Name%1").arg(count),
++ it.currentKey());
++ colorConfig.writeEntry( TQString("Color%1").arg(count),
++ (*it)->color);
++ //qDebug("Written Color %s (%d)", it.currentKey().ascii(), count);
++
++ count++;
++ }
++ }
++ colorConfig.writeEntry( "Count", count-1);
++
++ // source options
++ KConfigGroup sourceConfig(kconfig, TQCString("Source"));
++ sourceConfig.writeEntry("Dirs", c->_generalSourceDirs, ':');
++ TQDictIterator<TQStringList> it2( c->_objectSourceDirs );
++ count = 1;
++ for( ; it2.current(); ++it2 ) {
++ sourceConfig.writeEntry( TQString("Object%1").arg(count),
++ it2.currentKey());
++ sourceConfig.writeEntry( TQString("Dirs%1").arg(count),
++ *(*it2), ':');
++ count++;
++ }
++ sourceConfig.writeEntry( "Count", count-1);
++
++ // general options
++ KConfigGroup generalConfig(kconfig, TQCString("General"));
++ generalConfig.writeEntry("ShowPercentage", c->_showPercentage);
++ generalConfig.writeEntry("ShowExpanded", c->_showExpanded);
++ generalConfig.writeEntry("ShowCycles", c->_showCycles);
++ generalConfig.writeEntry("CycleCut", c->_cycleCut);
++ generalConfig.writeEntry("MaxSymbolCount", c->_maxSymbolCount);
++ generalConfig.writeEntry("MaxListCount", c->_maxListCount);
++ generalConfig.writeEntry("MaxSymbolLength", c->_maxSymbolLength);
++ generalConfig.writeEntry("PercentPrecision", c->_percentPrecision);
++
++ generalConfig.writeEntry("Context", c->_context);
++ generalConfig.writeEntry("NoCostInside", c->_noCostInside);
++
++ KConfigGroup ctConfig(kconfig, TQCString("CostTypes"));
++ int ctCount = TraceCostType::knownTypeCount();
++ ctConfig.writeEntry( "Count", ctCount);
++ for (int i=0; i<ctCount; i++) {
++ TraceCostType* t = TraceCostType::knownType(i);
++ ctConfig.writeEntry( TQString("Name%1").arg(i+1), t->name());
++
++ // Use localized key
++ TraceItemView::writeConfigEntry(&ctConfig,
++ TQString("Longname%1").arg(i+1).ascii(),
++ t->longName(),
++ knownLongName(t->name()).utf8().data() /*, true */ );
++ TraceItemView::writeConfigEntry(&ctConfig,
++ TQString("Formula%1").arg(i+1).ascii(),
++ t->formula(), knownFormula(t->name()).utf8().data());
++ }
++}
++
++
++
++
++void Configuration::readOptions(KConfig* kconfig)
++{
++ int i, count;
++ Configuration* c = config();
++
++ // color options
++ c->_colors.clear();
++
++ // colors for default cost types:
++ // red for L2 misses, green for L1 misses, blue for normal accesses
++ c->color("CostType-I2mr")->color = TQColor(240, 0, 0);
++ c->color("CostType-D2mr")->color = TQColor(180,40,40);
++ c->color("CostType-D2mw")->color = TQColor(120,80,80);
++
++ c->color("CostType-I1mr")->color = TQColor(0, 240, 0);
++ c->color("CostType-D1mr")->color = TQColor(40,180,40);
++ c->color("CostType-D1mw")->color = TQColor(80,120,80);
++
++ c->color("CostType-Ir")->color = TQColor(0, 0, 240);
++ c->color("CostType-Dr")->color = TQColor(40,40,180);
++ c->color("CostType-Dw")->color = TQColor(80,80,120);
++
++ KConfigGroup colorConfig(kconfig, TQCString("CostColors"));
++ count = colorConfig.readNumEntry("Count", 0);
++ for (i=1;i<=count;i++) {
++ TQString n = colorConfig.readEntry(TQString("Name%1").arg(i));
++ TQColor color = colorConfig.readColorEntry(TQString("Color%1").arg(i));
++
++ if (n.isEmpty()) continue;
++
++ ColorSetting* cs = new ColorSetting;
++ cs->name = n;
++ cs->automatic = false;
++ cs->color = color;
++
++ c->_colors.insert(n, cs);
++
++ //qDebug("Read Color %s", n.ascii());
++ }
++
++ // source options
++ KConfigGroup sourceConfig(kconfig, TQCString("Source"));
++ TQStringList dirs;
++ dirs = sourceConfig.readListEntry("Dirs", ':');
++ if (dirs.count()>0) c->_generalSourceDirs = dirs;
++ count = sourceConfig.readNumEntry("Count", 0);
++ c->_objectSourceDirs.clear();
++ if (count>17) c->_objectSourceDirs.resize(count);
++ for (i=1;i<=count;i++) {
++ TQString n = sourceConfig.readEntry(TQString("Object%1").arg(i));
++ dirs = sourceConfig.readListEntry(TQString("Dirs%1").arg(i), ':');
++
++ if (n.isEmpty() || (dirs.count()==0)) continue;
++
++ c->_objectSourceDirs.insert(n, new TQStringList(dirs));
++ }
++
++
++ // general options
++ KConfigGroup generalConfig(kconfig, TQCString("General"));
++ c->_showPercentage = generalConfig.readBoolEntry("ShowPercentage", true);
++ c->_showExpanded = generalConfig.readBoolEntry("ShowExpanded", false);
++ c->_showCycles = generalConfig.readBoolEntry("ShowCycles", true);
++ c->_cycleCut = generalConfig.readDoubleNumEntry("CycleCut", 0.0);
++ c->_maxSymbolCount = generalConfig.readNumEntry("MaxSymbolCount", 10);
++ c->_maxListCount = generalConfig.readNumEntry("MaxListCount", 100);
++ c->_maxSymbolLength = generalConfig.readNumEntry("MaxSymbolLength", 30);
++ c->_percentPrecision = generalConfig.readNumEntry("PercentPrecision", 2);
++
++ c->_context = generalConfig.readNumEntry("Context", 3);
++ c->_noCostInside = generalConfig.readNumEntry("NoCostInside", 20);
++
++ // known cost types
++ if (TraceCostType::knownTypeCount()==0) {
++
++ KConfigGroup ctConfig(kconfig, TQCString("CostTypes"));
++ int ctCount = ctConfig.readNumEntry("Count", 0);
++ if (ctCount>0) {
++ for (int i=1;i<=ctCount;i++) {
++ TQString n = ctConfig.readEntry(TQString("Name%1").arg(i));
++ TQString l = ctConfig.readEntry(TQString("Longname%1").arg(i));
++ if (l.isEmpty()) l = knownLongName(n);
++ TQString f = ctConfig.readEntry(TQString("Formula%1").arg(i));
++ if (f.isEmpty()) f = knownFormula(n);
++
++ TraceCostType::add(new TraceCostType(n, l, f));
++ }
++ }
++ else {
++ // add default types
++
++ TQString longName, formula;
++ TraceCostType* ct;
++ TQStringList l = knownTypes();
++ for ( TQStringList::Iterator it = l.begin();
++ it != l.end(); ++it ) {
++ longName = knownLongName(*it);
++ formula = knownFormula(*it);
++ ct = new TraceCostType(*it, longName, formula);
++ TraceCostType::add(ct);
++ }
++ }
++ }
++}
++
++TQColor Configuration::groupColor(TraceItem* cost)
++{
++ TQString n;
++
++ if (!cost)
++ n = TQString("default");
++ else
++ n = TraceCost::typeName(cost->type()) + "-" + cost->prettyName();
++
++ return color(n)->color;
++}
++
++TQColor Configuration::costTypeColor(TraceCostType* t)
++{
++ TQString n;
++
++ if (!t)
++ n = TQString("CostType-default");
++ else
++ n = TQString("CostType-%1").arg(t->name());
++
++ return color(n)->color;
++}
++
++TQColor Configuration::functionColor(TraceCost::CostType gt,
++ TraceFunction* f)
++{
++ TraceCost* group = f;
++ TQString n;
++
++ switch(gt) {
++ case TraceCost::Object: group = f->object(); break;
++ case TraceCost::Class: group = f->cls(); break;
++ case TraceCost::File: group = f->file(); break;
++ default:
++ break;
++ }
++
++ if (group != f) {
++ // first look for manual color of a function in a group
++ n = TraceCost::typeName(group->type()) +
++ "-" + group->prettyName() +
++ "-" + f->prettyName();
++
++ ColorSetting* cs = color(n, false);
++ if (cs) return cs->color;
++ }
++ return groupColor(group);
++}
++
++Configuration::ColorSetting* Configuration::color(TQString n, bool createNew)
++{
++// qDebug("Color for %s", n.latin1());
++
++ // predefined ?
++ Configuration* c = config();
++ ColorSetting* cs = c->_colors[n];
++ if (cs || !createNew) return cs;
++
++ // automatic colors...
++ int h = 0, s = 100;
++ const char* str = n.ascii();
++ while (*str) {
++ h = (h * 37 + s* (unsigned)*str) % 256;
++ s = (s * 17 + h* (unsigned)*str) % 192;
++ str++;
++ }
++
++ //qDebug("New color for %s: H %d, S %d", n.ascii(), h, 64+s);
++ TQColor color = TQColor(h, 64+s, 192, TQColor::Hsv);
++
++ cs = new ColorSetting;
++ cs->name = n;
++ cs->automatic = true;
++ cs->color = color;
++ c->_colors.insert(n, cs);
++
++ //qDebug("new Color %s", n.ascii());
++
++ return cs;
++}
++
++/* Gives back a list of all Source Base Directories of Objects in
++ * current trace. If a special object is given in 2nd argument,
++ * put its Source Base in front.
++ */
++TQStringList Configuration::sourceDirs(TraceData* data, TraceObject* o)
++{
++ TQStringList l = config()->_generalSourceDirs, *ol, *ol2 = 0;
++ TraceObjectMap::Iterator oit;
++ for ( oit = data->objectMap().begin();
++ oit != data->objectMap().end(); ++oit ) {
++ ol = config()->_objectSourceDirs[(*oit).name()];
++ if (&(*oit) == o) {
++ ol2 = ol;
++ continue;
++ }
++ if (!ol) continue;
++
++ for(unsigned int i=0;i<ol->count();i++)
++ l.prepend( (*ol)[i] );
++ }
++ if (ol2) {
++ for(unsigned int i=0;i<ol2->count();i++)
++ l.prepend( (*ol2)[i] );
++ }
++ if (0) kdDebug() << "Configuration::sourceDirs: " << l.join(":") << endl;
++
++ return l;
++}
++
++bool Configuration::showPercentage()
++{
++ return config()->_showPercentage;
++}
++
++bool Configuration::showExpanded()
++{
++ return config()->_showExpanded;
++}
++
++bool Configuration::showCycles()
++{
++ return config()->_showCycles;
++}
++
++void Configuration::setShowPercentage(bool s)
++{
++ Configuration* c = config();
++ if (c->_showPercentage == s) return;
++
++ c->_showPercentage = s;
++}
++
++void Configuration::setShowExpanded(bool s)
++{
++ Configuration* c = config();
++ if (c->_showExpanded == s) return;
++
++ c->_showExpanded = s;
++}
++
++void Configuration::setShowCycles(bool s)
++{
++ Configuration* c = config();
++ if (c->_showCycles == s) return;
++
++ c->_showCycles = s;
++}
++
++double Configuration::cycleCut()
++{
++ return config()->_cycleCut;
++}
++
++int Configuration::percentPrecision()
++{
++ return config()->_percentPrecision;
++}
++
++int Configuration::maxSymbolLength()
++{
++ return config()->_maxSymbolLength;
++}
++
++TQString Configuration::shortenSymbol(TQString s)
++{
++ if ((int)s.length() > maxSymbolLength())
++ s = s.left(maxSymbolLength()) + "...";
++ return s;
++}
++
++int Configuration::maxListCount()
++{
++ return config()->_maxListCount;
++}
++
++int Configuration::maxSymbolCount()
++{
++ return config()->_maxSymbolCount;
++}
++
++int Configuration::context()
++{
++ return config()->_context;
++}
++
++int Configuration::noCostInside()
++{
++ return config()->_noCostInside;
++}
+diff --git a/kdecachegrind/kdecachegrind/configuration.h b/kdecachegrind/kdecachegrind/configuration.h
+new file mode 100644
+index 0000000..478f617
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/configuration.h
+@@ -0,0 +1,101 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Configuration for KCachegrind
++ */
++
++#ifndef CONFIGURATION_H
++#define CONFIGURATION_H
++
++#include <tqcolor.h>
++#include <tqstringlist.h>
++#include <tqdict.h>
++
++#include "tracedata.h"
++
++class KConfig;
++
++class Configuration
++{
++ friend class ConfigDlg;
++
++public:
++ Configuration();
++
++ static Configuration* config();
++
++ static void saveOptions(KConfig*);
++ static void readOptions(KConfig*);
++
++ // color for visualisation of an object
++ static TQColor functionColor(TraceItem::CostType gt, TraceFunction*);
++ static TQColor groupColor(TraceItem*);
++ static TQColor costTypeColor(TraceCostType*);
++ static TQStringList sourceDirs(TraceData*, TraceObject* o = 0);
++ static bool showPercentage();
++ static bool showExpanded();
++ static bool showCycles();
++
++ // lower percentage limit of cost items filled into lists
++ static int percentPrecision();
++ // max symbol lengths/count in tooltip/popup
++ static int maxSymbolLength();
++ // strip a symbol name according to <maxSymbolLength>
++ static TQString shortenSymbol(TQString);
++ static int maxSymbolCount();
++ // max. number of items in lists
++ static int maxListCount();
++
++ // how many lines of context to show before/after annotated source/assembler
++ static int context();
++ // how many lines without cost are still regarded as inside a function
++ static int noCostInside();
++
++ static void setShowPercentage(bool);
++ static void setShowExpanded(bool);
++
++ static void setShowCycles(bool);
++ // upper limit for cutting of a call in cycle detection
++ static double cycleCut();
++
++private:
++ struct ColorSetting {
++ TQString name;
++ TQColor color;
++ bool automatic;
++ };
++
++ static ColorSetting* color(TQString, bool createNew = true);
++
++ TQDict<ColorSetting> _colors;
++
++ TQStringList _generalSourceDirs;
++ TQDict<TQStringList> _objectSourceDirs;
++
++ bool _showPercentage, _showExpanded, _showCycles;
++ double _cycleCut;
++ int _percentPrecision;
++ int _maxSymbolLength, _maxSymbolCount, _maxListCount;
++ int _context, _noCostInside;
++
++ static Configuration* _config;
++};
++
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/costlistitem.cpp b/kdecachegrind/kdecachegrind/costlistitem.cpp
+new file mode 100644
+index 0000000..1e777b0
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/costlistitem.cpp
+@@ -0,0 +1,136 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++#include <math.h>
++
++#include <tqpainter.h>
++#include <tqregexp.h>
++
++#include <klocale.h>
++#include <kiconloader.h>
++#include <kapplication.h>
++
++#include "listutils.h"
++#include "costlistitem.h"
++#include "coverage.h"
++#include "configuration.h"
++
++// CostListItem
++
++
++CostListItem::CostListItem(TQListView* parent, TraceCostItem* costItem,
++ TraceCostType* ct, int size)
++ :TQListViewItem(parent)
++{
++ _groupSize = size;
++ _skipped = 0;
++ _costItem = costItem;
++ setCostType(ct);
++
++ if (costItem) {
++ updateName();
++ setPixmap(1, colorPixmap(10, 10,
++ Configuration::groupColor(_costItem)));
++ }
++}
++
++CostListItem::CostListItem(TQListView* parent, int skipped,
++ TraceCostItem* costItem, TraceCostType* ct)
++ :TQListViewItem(parent)
++{
++ _skipped = skipped;
++ _costItem = costItem;
++ setCostType(ct);
++
++ setText(1, i18n("(%n item skipped)", "(%n items skipped)", _skipped));
++}
++
++void CostListItem::setCostType(TraceCostType* ct)
++{
++ _costType = ct;
++ update();
++}
++
++void CostListItem::updateName()
++{
++ if (!_costItem) return;
++
++ TQString n = _costItem->prettyName();
++ if (_groupSize>=0) n += TQString(" (%1)").arg(_groupSize);
++
++ setText(1, n);
++}
++
++void CostListItem::setSize(int s)
++{
++ _groupSize = s;
++ updateName();
++}
++
++void CostListItem::update()
++{
++ if (!_costItem) return;
++ TraceData* d = _costItem->data();
++
++ double total = d->subCost(_costType);
++ if (total == 0.0) {
++ setText(0, TQString("---"));
++ setPixmap(0, TQPixmap());
++ return;
++ }
++
++ _pure = _costItem->subCost(_costType);
++ double pure = 100.0 * _pure / total;
++ TQString str;
++ if (Configuration::showPercentage())
++ str = TQString("%1").arg(pure, 0, 'f', Configuration::percentPrecision());
++ else
++ str = _costItem->prettySubCost(_costType);
++
++ if (_skipped) {
++ // special handling for skip entries...
++ setText(0, TQString("< %1").arg(str));
++ return;
++ }
++
++ setText(0, str);
++ setPixmap(0, costPixmap(_costType, _costItem, total, false));
++}
++
++int CostListItem::compare(TQListViewItem * i, int col, bool ascending ) const
++{
++ const CostListItem* fi1 = this;
++ const CostListItem* fi2 = (CostListItem*) i;
++
++ // we always want descending order
++ if (ascending) {
++ fi1 = fi2;
++ fi2 = this;
++ }
++
++ // a skip entry is always sorted last
++ if (fi1->_skipped) return -1;
++ if (fi2->_skipped) return 1;
++
++ if (col==0) {
++ if (fi1->_pure < fi2->_pure) return -1;
++ if (fi1->_pure > fi2->_pure) return 1;
++ return 0;
++ }
++ return TQListViewItem::compare(i, col, ascending);
++}
+diff --git a/kdecachegrind/kdecachegrind/costlistitem.h b/kdecachegrind/kdecachegrind/costlistitem.h
+new file mode 100644
+index 0000000..99f654e
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/costlistitem.h
+@@ -0,0 +1,52 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++#ifndef COSTLISTITEM_H
++#define COSTLISTITEM_H
++
++#include <tqlistview.h>
++#include "tracedata.h"
++
++class CostListItem: public TQListViewItem
++{
++public:
++ CostListItem(TQListView* parent, TraceCostItem* cost,
++ TraceCostType* ct, int size = -1);
++ // entry with multiple skipped items
++ CostListItem(TQListView* parent, int skipped, TraceCostItem* cost,
++ TraceCostType* ct);
++
++ int compare(TQListViewItem * i, int col, bool ascending ) const;
++ TraceCostItem* costItem() { return (_skipped) ? 0 : _costItem; }
++ void setCostType(TraceCostType* ct);
++ void update();
++ void setSize(int s);
++
++private:
++ void updateName();
++
++ SubCost _pure;
++ TraceCostType* _costType;
++ TraceCostItem* _costItem;
++ // >0 only for last item in list, if items are skipped
++ int _skipped;
++ // number of items in group, is put in parenthesis after name
++ int _groupSize;
++};
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/costtypeitem.cpp b/kdecachegrind/kdecachegrind/costtypeitem.cpp
+new file mode 100644
+index 0000000..dc35cb2
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/costtypeitem.cpp
+@@ -0,0 +1,149 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Items of cost type view.
++ */
++
++#include <tqpixmap.h>
++#include <klocale.h>
++
++#include "configuration.h"
++#include "listutils.h"
++#include "costtypeitem.h"
++
++
++// CostTypeItem
++
++
++CostTypeItem::CostTypeItem(TQListView* parent, TraceCostItem* costItem,
++ TraceCostType* ct, TraceCost::CostType gt)
++ :TQListViewItem(parent)
++{
++ _costItem = costItem;
++ _costType = ct;
++ _groupType = gt;
++
++ if (ct) {
++ setText(0, ct->longName());
++ setText(3, ct->name());
++ TQString formula = ct->formula();
++ setText(5, formula);
++ if (!formula.isEmpty()) {
++ setText(4, "=");
++ // we have a virtual type: allow editing
++ setRenameEnabled(0, true);
++ setRenameEnabled(3, true);
++ setRenameEnabled(5, true);
++ }
++ }
++ else {
++ setText(0, i18n("Unknown Type"));
++ }
++ update();
++}
++
++void CostTypeItem::setGroupType(TraceCost::CostType gt)
++{
++ if (_groupType == gt) return;
++
++ _groupType = gt;
++ update();
++}
++
++void CostTypeItem::update()
++{
++ TraceData* d = _costItem ? _costItem->data() : 0;
++ double total = d ? ((double)d->subCost(_costType)) : 0.0;
++
++ if (total == 0.0) {
++ setText(1, "-");
++ setPixmap(1, TQPixmap());
++ setText(2, "-");
++ setPixmap(2, TQPixmap());
++ return;
++ }
++
++ TraceFunction* f = (_costItem->type()==TraceCost::Function) ?
++ (TraceFunction*)_costItem : 0;
++
++ TraceCost* selfTotalCost = f ? f->data() : d;
++ if (f && Configuration::showExpanded()) {
++ switch(_groupType) {
++ case TraceCost::Object: selfTotalCost = f->object(); break;
++ case TraceCost::Class: selfTotalCost = f->cls(); break;
++ case TraceCost::File: selfTotalCost = f->file(); break;
++ case TraceCost::FunctionCycle: selfTotalCost = f->cycle(); break;
++ default: break;
++ }
++ }
++ if (_costItem->type()==TraceCost::FunctionCycle) {
++ f = (TraceFunction*)_costItem;
++ selfTotalCost = f->data();
++ }
++
++ double selfTotal = selfTotalCost->subCost(_costType);
++
++ // for all cost items there's a self cost
++ _pure = _costItem ? _costItem->subCost(_costType) : SubCost(0);
++ double pure = 100.0 * _pure / selfTotal;
++ if (Configuration::showPercentage()) {
++ setText(2, TQString("%1")
++ .arg(pure, 0, 'f', Configuration::percentPrecision()));
++ }
++ else
++ setText(2, _costItem->prettySubCost(_costType));
++
++ setPixmap(2, costPixmap(_costType, _costItem, selfTotal, false));
++
++ if (!f) {
++ setText(1, "-");
++ setPixmap(1, TQPixmap());
++ return;
++ }
++
++ _sum = f->inclusive()->subCost(_costType);
++ double sum = 100.0 * _sum / total;
++ if (Configuration::showPercentage()) {
++ setText(1, TQString("%1")
++ .arg(sum, 0, 'f', Configuration::percentPrecision()));
++ }
++ else
++ setText(1, _sum.pretty());
++
++ setPixmap(1, costPixmap(_costType, f->inclusive(), total, false));
++}
++
++
++int CostTypeItem::compare(TQListViewItem * i, int col, bool ascending ) const
++{
++ CostTypeItem* fi = (CostTypeItem*) i;
++ if (col==0) {
++ if (_sum < fi->_sum) return -1;
++ if (_sum > fi->_sum) return 1;
++ return 0;
++ }
++ if (col==1) {
++ if (_pure < fi->_pure) return -1;
++ if (_pure > fi->_pure) return 1;
++ return 0;
++ }
++ return TQListViewItem::compare(i, col, ascending);
++}
++
++
+diff --git a/kdecachegrind/kdecachegrind/costtypeitem.h b/kdecachegrind/kdecachegrind/costtypeitem.h
+new file mode 100644
+index 0000000..d34973d
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/costtypeitem.h
+@@ -0,0 +1,50 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Items of cost type view.
++ */
++
++#ifndef COSTTYEPITEM_H
++#define COSTTYEPITEM_H
++
++#include <tqlistview.h>
++#include "tracedata.h"
++
++
++class CostTypeItem: public TQListViewItem
++{
++public:
++ CostTypeItem(TQListView* parent, TraceCostItem* costItem,
++ TraceCostType* ct, TraceCost::CostType gt);
++
++ int compare(TQListViewItem * i, int col, bool ascending ) const;
++ void setGroupType(TraceCost::CostType);
++ TraceCostItem* costItem() { return _costItem; }
++ TraceCostType* costType() { return _costType; }
++ void update();
++
++private:
++ SubCost _sum, _pure;
++ TraceCostType* _costType;
++ TraceCostItem* _costItem;
++ TraceCost::CostType _groupType;
++};
++
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/costtypeview.cpp b/kdecachegrind/kdecachegrind/costtypeview.cpp
+new file mode 100644
+index 0000000..3f5417e
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/costtypeview.cpp
+@@ -0,0 +1,310 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Cost Type View
++ */
++
++#include <tqwhatsthis.h>
++#include <tqpopupmenu.h>
++#include <klocale.h>
++
++#include "configuration.h"
++#include "costtypeitem.h"
++#include "costtypeview.h"
++#include "toplevel.h"
++
++
++//
++// CostTypeView
++//
++
++
++CostTypeView::CostTypeView(TraceItemView* parentView,
++ TQWidget* parent, const char* name)
++ : TQListView(parent, name), TraceItemView(parentView)
++{
++ addColumn( i18n( "Event Type" ) );
++ addColumn( i18n( "Incl." ) );
++ addColumn( i18n( "Self" ) );
++ addColumn( i18n( "Short" ) );
++ addColumn( TQString() );
++ addColumn( i18n( "Formula" ) );
++
++ setSorting(-1);
++ setAllColumnsShowFocus(true);
++ setColumnAlignment(1, TQt::AlignRight);
++ setColumnAlignment(2, TQt::AlignRight);
++ setColumnAlignment(3, TQt::AlignRight);
++ setMinimumHeight(50);
++
++ connect( this,
++ TQT_SIGNAL( selectionChanged(TQListViewItem*) ),
++ TQT_SLOT( selectedSlot(TQListViewItem*) ) );
++
++ connect( this,
++ TQT_SIGNAL(contextMenuRequested(TQListViewItem*, const TQPoint &, int)),
++ TQT_SLOT(context(TQListViewItem*, const TQPoint &, int)));
++
++ connect(this,
++ TQT_SIGNAL(doubleClicked(TQListViewItem*)),
++ TQT_SLOT(activatedSlot(TQListViewItem*)));
++
++ connect(this,
++ TQT_SIGNAL(returnPressed(TQListViewItem*)),
++ TQT_SLOT(activatedSlot(TQListViewItem*)));
++
++ connect(this,
++ TQT_SIGNAL(itemRenamed(TQListViewItem*,int,const TQString&)),
++ TQT_SLOT(renamedSlot(TQListViewItem*,int,const TQString&)));
++
++ TQWhatsThis::add( this, whatsThis() );
++}
++
++TQString CostTypeView::whatsThis() const
++{
++ return i18n( "<b>Cost Types List</b>"
++ "<p>This list shows all cost types available "
++ "and what the self/inclusive cost of the "
++ "current selected function is for that cost type.</p>"
++ "<p>By choosing a cost type from the list, "
++ "you change the cost type of costs shown "
++ "all over KCachegrind to be the selected one.</p>");
++}
++
++
++void CostTypeView::context(TQListViewItem* i, const TQPoint & p, int)
++{
++ TQPopupMenu popup;
++
++ TraceCostType* ct = i ? ((CostTypeItem*) i)->costType() : 0;
++
++ if (ct)
++ popup.insertItem(i18n("Set Secondary Event Type"), 99);
++ if (_costType2)
++ popup.insertItem(i18n("Remove Secondary Event Type"), 98);
++ if (popup.count()>0)
++ popup.insertSeparator();
++
++ if (ct && !ct->isReal()) {
++ popup.insertItem(i18n("Edit Long Name"), 93);
++ popup.insertItem(i18n("Edit Short Name"), 94);
++ popup.insertItem(i18n("Edit Formula"), 95);
++ popup.insertItem(i18n("Remove"), 96);
++ popup.insertSeparator();
++ }
++
++ addGoMenu(&popup);
++
++ popup.insertSeparator();
++ popup.insertItem(i18n("New Cost Type ..."), 97);
++
++ int r = popup.exec(p);
++ if (r == 98) selectedCostType2(0);
++ else if (r == 99) selectedCostType2(ct);
++ else if (r == 93) i->startRename(0);
++ else if (r == 94) i->startRename(3);
++ else if (r == 95) i->startRename(5);
++ else if (r == 96) {
++
++ // search for a previous type
++ TraceCostType* prev = 0, *ct = 0;
++ TraceCostMapping* m = _data->mapping();
++ for (int i=0;i<m->realCount();i++) {
++ ct = m->realType(i);
++ if (ct) prev = ct;
++ }
++ for (int i=0;i<m->virtualCount();i++) {
++ ct = m->virtualType(i);
++ if (ct == _costType) break;
++ if (ct) prev = ct;
++ }
++
++ if (_data->mapping()->remove(ct)) {
++ // select previous cost type
++ selectedCostType(prev);
++ if (_costType2 == ct)
++ selectedCostType2(prev);
++ refresh();
++ }
++ }
++ else if (r == 97) {
++ int i = 1;
++ while(1) {
++ if (!TraceCostType::knownVirtualType(i18n("New%1").arg(i)))
++ break;
++ i++;
++ }
++ // add same new cost type to this mapping and to known types
++ TQString shortName = i18n("New%1").arg(i);
++ TQString longName = i18n("New Cost Type %1").arg(i);
++ TraceCostType::add(new TraceCostType(shortName, longName, "0"));
++ _data->mapping()->add(new TraceCostType(shortName, longName, "0"));
++ refresh();
++ }
++}
++
++void CostTypeView::selectedSlot(TQListViewItem * i)
++{
++ TraceCostType* ct = i ? ((CostTypeItem*) i)->costType() : 0;
++ if (ct)
++ selectedCostType(ct);
++}
++
++void CostTypeView::activatedSlot(TQListViewItem * i)
++{
++ TraceCostType* ct = i ? ((CostTypeItem*) i)->costType() : 0;
++ if (ct)
++ selectedCostType2(ct);
++}
++
++TraceItem* CostTypeView::canShow(TraceItem* i)
++{
++ if (!i) return 0;
++
++ switch(i->type()) {
++ case TraceCost::Object:
++ case TraceCost::Class:
++ case TraceCost::File:
++ case TraceCost::Call:
++ case TraceCost::FunctionCycle:
++ case TraceCost::Function:
++ break;
++ default:
++ return 0;
++ }
++ return i;
++}
++
++void CostTypeView::doUpdate(int changeType)
++{
++ // Special case ?
++ if (changeType == selectedItemChanged) return;
++
++ if (changeType == costType2Changed) return;
++
++ if (changeType == groupTypeChanged) {
++ TQListViewItem *item;
++ for (item = firstChild();item;item = item->nextSibling())
++ ((CostTypeItem*)item)->setGroupType(_groupType);
++
++ return;
++ }
++
++ if (changeType == costTypeChanged) {
++ TQListViewItem *item;
++ for (item = firstChild();item;item = item->nextSibling())
++ if ( ((CostTypeItem*)item)->costType() == _costType) {
++ setSelected(item, true);
++ ensureItemVisible(item);
++ break;
++ }
++
++ return;
++ }
++
++ if (changeType == partsChanged) {
++ TQListViewItem *item;
++ for (item = firstChild();item;item = item->nextSibling())
++ ((CostTypeItem*)item)->update();
++
++ return;
++ }
++
++
++ refresh();
++}
++
++void CostTypeView::refresh()
++{
++ clear();
++ setColumnWidth(1, 50);
++ setColumnWidth(2, 50);
++
++ if (!_data || !_activeItem) return;
++ switch(_activeItem->type()) {
++ case TraceCost::Object:
++ case TraceCost::Class:
++ case TraceCost::File:
++ case TraceCost::FunctionCycle:
++ case TraceCost::Function:
++ break;
++ default:
++ return;
++ }
++ TraceCostItem* c = (TraceCostItem*) _activeItem;
++
++ TraceCostType* ct =0 ;
++ TQListViewItem* item = 0;
++ TQString sumStr, pureStr;
++ TQListViewItem* costItem=0;
++
++ TraceCostMapping* m = _data->mapping();
++ for (int i=m->virtualCount()-1;i>=0;i--) {
++ ct = m->virtualType(i);
++ if (!ct) continue;
++ item = new CostTypeItem(this, c, ct, _groupType);
++ if (ct == _costType) costItem = item;
++ }
++ for (int i=m->realCount()-1;i>=0;i--) {
++ ct = m->realType(i);
++ item = new CostTypeItem(this, c, ct, _groupType);
++ if (ct == _costType) costItem = item;
++ }
++
++ if (costItem) {
++ setSelected(costItem, true);
++ ensureItemVisible(costItem);
++ }
++
++ if (item) setMinimumHeight(3*item->height());
++}
++
++
++void CostTypeView::renamedSlot(TQListViewItem* item,int c,const TQString& t)
++{
++ TraceCostType* ct = item ? ((CostTypeItem*) item)->costType() : 0;
++ if (!ct || ct->isReal()) return;
++
++ // search for matching known Type
++ int knownCount = TraceCostType::knownTypeCount();
++ TraceCostType* known = 0;
++ for (int i=0; i<knownCount; i++) {
++ known = TraceCostType::knownType(i);
++ if (known->name() == ct->name()) break;
++ }
++
++ if (c == 0) {
++ ct->setLongName(t);
++ if (known) known->setLongName(t);
++ }
++ else if (c == 3) {
++ ct->setName(t);
++ if (known) known->setName(t);
++ }
++ else if (c == 5) {
++ ct->setFormula(t);
++ if (known) known->setFormula(t);
++ }
++ else return;
++
++ if (_topLevel) _topLevel->configChanged();
++ refresh();
++}
++
++#include "costtypeview.moc"
+diff --git a/kdecachegrind/kdecachegrind/costtypeview.h b/kdecachegrind/kdecachegrind/costtypeview.h
+new file mode 100644
+index 0000000..ee9963e
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/costtypeview.h
+@@ -0,0 +1,54 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Cost Type View
++ */
++
++#ifndef COSTTYPEVIEW_H
++#define COSTTYPEVIEW_H
++
++#include <tqlistview.h>
++#include "tracedata.h"
++#include "traceitemview.h"
++
++class CostTypeView: public TQListView, public TraceItemView
++{
++ Q_OBJECT
++ TQ_OBJECT
++
++public:
++ CostTypeView(TraceItemView* parentView,
++ TQWidget* parent=0, const char* name=0);
++
++ virtual TQWidget* widget() { return this; }
++ TQString whatsThis() const;
++
++private slots:
++ void context(TQListViewItem*,const TQPoint &, int);
++ void selectedSlot(TQListViewItem*);
++ void activatedSlot(TQListViewItem*);
++ void renamedSlot(TQListViewItem*,int,const TQString&);
++
++private:
++ TraceItem* canShow(TraceItem*);
++ void doUpdate(int);
++ void refresh();
++};
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/coverage.cpp b/kdecachegrind/kdecachegrind/coverage.cpp
+new file mode 100644
+index 0000000..86e6f7f
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/coverage.cpp
+@@ -0,0 +1,329 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2002 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Function Coverage Analysis
++ */
++
++#include "coverage.h"
++
++//#define DEBUG_COVERAGE 1
++
++TraceCostType* Coverage::_costType;
++
++const int Coverage::maxHistogramDepth = maxHistogramDepthValue;
++const int Coverage::Rtti = 1;
++
++Coverage::Coverage()
++{
++}
++
++void Coverage::init()
++{
++ _self = 0.0;
++ _incl = 0.0;
++ _callCount = 0.0;
++ // should always be overwritten before usage
++ _firstPercentage = 1.0;
++ _minDistance = 9999;
++ _maxDistance = 0;
++ _active = false;
++ _inRecursion = false;
++ for (int i = 0;i<maxHistogramDepth;i++) {
++ _selfHisto[i] = 0.0;
++ _inclHisto[i] = 0.0;
++ }
++
++ _valid = true;
++}
++
++int Coverage::inclusiveMedian()
++{
++ double maxP = _inclHisto[0];
++ int medD = 0;
++ for (int i = 1;i<maxHistogramDepth;i++)
++ if (_inclHisto[i]>maxP) {
++ maxP = _inclHisto[i];
++ medD = i;
++ }
++
++ return medD;
++}
++
++int Coverage::selfMedian()
++{
++ double maxP = _selfHisto[0];
++ int medD = 0;
++ for (int i = 1;i<maxHistogramDepth;i++)
++ if (_selfHisto[i]>maxP) {
++ maxP = _selfHisto[i];
++ medD = i;
++ }
++
++ return medD;
++}
++
++TraceFunctionList Coverage::coverage(TraceFunction* f, CoverageMode m,
++ TraceCostType* ct)
++{
++ invalidate(f->data(), Coverage::Rtti);
++
++ _costType = ct;
++
++ // function f takes ownership over c!
++ Coverage* c = new Coverage();
++ c->setFunction(f);
++ c->init();
++
++ TraceFunctionList l;
++
++ if (m == Caller)
++ c->addCallerCoverage(l, 1.0, 0);
++ else
++ c->addCallingCoverage(l, 1.0, 1.0, 0);
++
++ return l;
++}
++
++void Coverage::addCallerCoverage(TraceFunctionList& fList,
++ double pBack, int d)
++{
++ TraceCallList cList;
++ TraceCall* call;
++ Coverage* c;
++
++ if (_inRecursion) return;
++
++ double incl;
++ incl = (double) (_function->inclusive()->subCost(_costType));
++
++ if (_active) {
++#ifdef DEBUG_COVERAGE
++ qDebug("CallerCov: D %d, %s (was active, incl %f, self %f): newP %f", d,
++ _function->prettyName().ascii(), _incl, _self, pBack);
++#endif
++ _inRecursion = true;
++ }
++ else {
++ _active = true;
++
++ // only add cost if this is no recursion
++
++ _incl += pBack;
++ _firstPercentage = pBack;
++
++ if (_minDistance > d) _minDistance = d;
++ if (_maxDistance < d) _maxDistance = d;
++ if (d<maxHistogramDepth) {
++ _inclHisto[d] += pBack;
++ }
++ else {
++ _inclHisto[maxHistogramDepth-1] += pBack;
++ }
++
++#ifdef DEBUG_COVERAGE
++ qDebug("CallerCov: D %d, %s (now active, new incl %f): newP %f",
++ d, _function->prettyName().ascii(), _incl, pBack);
++#endif
++ }
++
++ double callVal, pBackNew;
++
++ cList = _function->callers();
++ for (call=cList.first();call;call=cList.next()) {
++ if (call->inCycle()>0) continue;
++ if (call->isRecursion()) continue;
++
++ if (call->subCost(_costType)>0) {
++ TraceFunction* caller = call->caller();
++
++ c = (Coverage*) caller->assoziation(rtti());
++ if (!c) {
++ c = new Coverage();
++ c->setFunction(caller);
++ }
++ if (!c->isValid()) {
++ c->init();
++ fList.append(caller);
++ }
++
++ if (c->isActive()) continue;
++ if (c->inRecursion()) continue;
++
++ callVal = (double) call->subCost(_costType);
++ pBackNew = pBack * (callVal / incl);
++
++ // FIXME ?!?
++
++ if (!c->isActive()) {
++ if (d>=0)
++ c->callCount() += (double)call->callCount();
++ else
++ c->callCount() += _callCount;
++ }
++ else {
++ // adjust pNew by sum of geometric series of recursion factor.
++ // Thus we can avoid endless recursion here
++ pBackNew *= 1.0 / (1.0 - pBackNew / c->firstPercentage());
++ }
++
++ // Limit depth
++ if (pBackNew > 0.0001)
++ c->addCallerCoverage(fList, pBackNew, d+1);
++ }
++ }
++
++ if (_inRecursion)
++ _inRecursion = false;
++ else if (_active)
++ _active = false;
++}
++
++/**
++ * pForward is time on percent used,
++ * pBack is given to allow for calculation of call counts
++ */
++void Coverage::addCallingCoverage(TraceFunctionList& fList,
++ double pForward, double pBack, int d)
++{
++ TraceCallList cList;
++ TraceCall* call;
++ Coverage* c;
++
++ if (_inRecursion) return;
++
++#ifdef DEBUG_COVERAGE
++ static const char* spaces = " ";
++#endif
++
++ double self, incl;
++ incl = (double) (_function->inclusive()->subCost(_costType));
++
++#ifdef DEBUG_COVERAGE
++ qDebug("CngCov:%s - %s (incl %f, self %f): forward %f, back %f",
++ spaces+strlen(spaces)-d,
++ _function->prettyName().ascii(), _incl, _self, pForward, pBack);
++#endif
++
++
++ if (_active) {
++ _inRecursion = true;
++
++#ifdef DEBUG_COVERAGE
++ qDebug("CngCov:%s < %s: STOP (is active)",
++ spaces+strlen(spaces)-d,
++ _function->prettyName().ascii());
++#endif
++
++ }
++ else {
++ _active = true;
++
++ // only add cost if this is no recursion
++ self = pForward * (_function->subCost(_costType)) / incl;
++ _incl += pForward;
++ _self += self;
++ _firstPercentage = pForward;
++
++ if (_minDistance > d) _minDistance = d;
++ if (_maxDistance < d) _maxDistance = d;
++ if (d<maxHistogramDepth) {
++ _inclHisto[d] += pForward;
++ _selfHisto[d] += self;
++ }
++ else {
++ _inclHisto[maxHistogramDepth-1] += pForward;
++ _selfHisto[maxHistogramDepth-1] += self;
++ }
++
++#ifdef DEBUG_COVERAGE
++ qDebug("CngCov:%s < %s (incl %f, self %f)",
++ spaces+strlen(spaces)-d,
++ _function->prettyName().ascii(), _incl, _self);
++#endif
++ }
++
++ double callVal, pForwardNew, pBackNew;
++
++ cList = _function->callings();
++ for (call=cList.first();call;call=cList.next()) {
++ if (call->inCycle()>0) continue;
++ if (call->isRecursion()) continue;
++
++ if (call->subCost(_costType)>0) {
++ TraceFunction* calling = call->called();
++
++ c = (Coverage*) calling->assoziation(rtti());
++ if (!c) {
++ c = new Coverage();
++ c->setFunction(calling);
++ }
++ if (!c->isValid()) {
++ c->init();
++ fList.append(calling);
++ }
++
++ if (c->isActive()) continue;
++ if (c->inRecursion()) continue;
++
++ callVal = (double) call->subCost(_costType);
++ pForwardNew = pForward * (callVal / incl);
++ pBackNew = pBack * (callVal /
++ calling->inclusive()->subCost(_costType));
++
++ if (!c->isActive()) {
++ c->callCount() += pBack * call->callCount();
++
++#ifdef DEBUG_COVERAGE
++ qDebug("CngCov:%s > %s: forward %f, back %f, calls %f -> %f, now %f",
++ spaces+strlen(spaces)-d,
++ calling->prettyName().ascii(),
++ pForwardNew, pBackNew,
++ (double)call->callCount(),
++ pBack * call->callCount(),
++ c->callCount());
++#endif
++ }
++ else {
++ // adjust pNew by sum of geometric series of recursion factor.
++ // Thus we can avoid endless recursion here
++ double fFactor = 1.0 / (1.0 - pForwardNew / c->firstPercentage());
++ double bFactor = 1.0 / (1.0 - pBackNew);
++#ifdef DEBUG_COVERAGE
++ qDebug("CngCov:%s Recursion - origP %f, actP %f => factor %f, newP %f",
++ spaces+strlen(spaces)-d,
++ c->firstPercentage(), pForwardNew,
++ fFactor, pForwardNew * fFactor);
++#endif
++ pForwardNew *= fFactor;
++ pBackNew *= bFactor;
++
++ }
++
++ // Limit depth
++ if (pForwardNew > 0.0001)
++ c->addCallingCoverage(fList, pForwardNew, pBackNew, d+1);
++ }
++ }
++
++ if (_inRecursion)
++ _inRecursion = false;
++ else if (_active)
++ _active = false;
++}
++
+diff --git a/kdecachegrind/kdecachegrind/coverage.h b/kdecachegrind/kdecachegrind/coverage.h
+new file mode 100644
+index 0000000..50c5936
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/coverage.h
+@@ -0,0 +1,102 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2002 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Function Coverage Analysis
++ */
++
++#ifndef COVERAGE_H
++#define COVERAGE_H
++
++#include "tracedata.h"
++
++/**
++ * Coverage of a function.
++ * When analysis is done, every function involved will have a
++ * pointer to an object of this class.
++ *
++ * This function also holds the main routine for coverage analysis,
++ * Coverage::coverage(), as static method.
++ */
++class Coverage : public TraceAssoziation
++{
++public:
++ /* Direction of coverage analysis */
++ enum CoverageMode { Caller, Called };
++
++ // max depth for distance histogram
++#define maxHistogramDepthValue 40
++ static const int maxHistogramDepth;
++
++ static const int Rtti;
++
++ Coverage();
++
++ virtual int rtti() { return Rtti; }
++ void init();
++
++ TraceFunction* function() { return _function; }
++ double self() { return _self; }
++ double inclusive() { return _incl; }
++ double firstPercentage() { return _firstPercentage; }
++ double& callCount() { return _callCount; }
++ int minDistance() { return _minDistance; }
++ int maxDistance() { return _maxDistance; }
++ int inclusiveMedian();
++ int selfMedian();
++ double* selfHistogram() { return _selfHisto; }
++ double* inclusiveHistogram() { return _inclHisto; }
++ bool isActive() { return _active; }
++ bool inRecursion() { return _inRecursion; }
++
++ void setSelf(float p) { _self = p; }
++ void setInclusive(float p) { _incl = p; }
++ void setCallCount(float cc) { _callCount = cc; }
++ void setActive(bool a) { _active = a; }
++ void setInRecursion(bool r) { _inRecursion = r; }
++
++ /**
++ * Calculate coverage of all functions based on function f.
++ * If mode is Called, the coverage of functions called by
++ * f is calculated, otherwise that of functions calling f.
++ * SubCost type ct is used for the analysis.
++ * Self values are undefined for Caller mode.
++ *
++ * Returns list of functions covered.
++ * Coverage degree of returned functions can be get
++ * with function->coverage()->percentage()
++ */
++ static TraceFunctionList coverage(TraceFunction* f, CoverageMode m,
++ TraceCostType* ct);
++
++private:
++ void addCallerCoverage(TraceFunctionList& l, double, int d);
++ void addCallingCoverage(TraceFunctionList& l, double, double, int d);
++
++ double _self, _incl, _firstPercentage, _callCount;
++ int _minDistance, _maxDistance;
++ bool _active, _inRecursion;
++ double _selfHisto[maxHistogramDepthValue];
++ double _inclHisto[maxHistogramDepthValue];
++
++ // temporary set for one coverage analysis
++ static TraceCostType* _costType;
++};
++
++#endif
++
+diff --git a/kdecachegrind/kdecachegrind/coverageitem.cpp b/kdecachegrind/kdecachegrind/coverageitem.cpp
+new file mode 100644
+index 0000000..26e5b36
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/coverageitem.cpp
+@@ -0,0 +1,343 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Items of coverage view.
++ */
++
++#include <tqpixmap.h>
++#include <klocale.h>
++
++#include "configuration.h"
++#include "listutils.h"
++#include "coverage.h"
++#include "coverageitem.h"
++
++
++// CallerCoverageItem
++
++
++CallerCoverageItem::CallerCoverageItem(TQListView* parent, Coverage* c,
++ TraceFunction* base,
++ TraceCostType* ct,
++ TraceCost::CostType gt)
++ : TQListViewItem(parent)
++{
++ _skipped = 0;
++ _coverage = c;
++ _function = c ? c->function() : 0;
++ _base = base;
++ _groupType = TraceCost::NoCostType;
++
++ setText(3, _function->prettyNameWithLocation());
++
++ setCostType(ct);
++ setGroupType(gt);
++}
++
++CallerCoverageItem::CallerCoverageItem(TQListView* parent, int skipped, Coverage* c,
++ TraceFunction* base,
++ TraceCostType* ct,
++ TraceCost::CostType gt)
++ : TQListViewItem(parent)
++{
++ _skipped = skipped;
++ _coverage = c;
++ _function = c ? c->function() : 0;
++ _base = base;
++ _groupType = TraceCost::NoCostType;
++
++ setText(3, i18n("(%n function skipped)", "(%n functions skipped)", _skipped));
++
++ setCostType(ct);
++ setGroupType(gt);
++}
++
++void CallerCoverageItem::setGroupType(TraceCost::CostType gt)
++{
++ if (_skipped) return;
++ if (_groupType == gt) return;
++ _groupType = gt;
++
++ TQColor c = Configuration::functionColor(_groupType, _function);
++ setPixmap(3, colorPixmap(10, 10, c));
++}
++
++void CallerCoverageItem::setCostType(TraceCostType* ct)
++{
++ _costType = ct;
++ update();
++}
++
++void CallerCoverageItem::update()
++{
++ if (!_coverage) {
++ setText(0, TQString());
++ setText(1, TQString());
++ return;
++ }
++
++ _pSum = 100.0 * _coverage->inclusive();
++ SubCost realSum = _base->inclusive()->subCost(_costType);
++ _sum = SubCost(realSum * _coverage->inclusive());
++ TQString str;
++ if (Configuration::showPercentage())
++ str = TQString("%1").arg(_pSum, 0, 'f', Configuration::percentPrecision());
++ else
++ str = _sum.pretty();
++
++ if (_skipped) {
++ setText(0, TQString("< %1").arg(str));
++ return;
++ }
++
++ setText(0, str);
++ setPixmap(0, partitionPixmap(25, 10, _coverage->inclusiveHistogram(), 0,
++ Coverage::maxHistogramDepth, false));
++
++ // call count
++ _cc = SubCost(_coverage->callCount());
++ setText(2, _cc ? _cc.pretty() : TQString("(0)"));
++
++ // distance (min/max/median)
++ _distance = _coverage->inclusiveMedian();
++ TQString distString;
++ if (_coverage->minDistance() == _coverage->maxDistance())
++ distString = TQString::number(_distance);
++ else
++ distString = TQString("%1-%2 (%3)")
++ .arg(_coverage->minDistance())
++ .arg(_coverage->maxDistance())
++ .arg(_distance);
++ setText(1, distString);
++}
++
++
++int CallerCoverageItem::compare(TQListViewItem * i,
++ int col, bool ascending ) const
++{
++ const CallerCoverageItem* ci1 = this;
++ const CallerCoverageItem* ci2 = (CallerCoverageItem*) i;
++
++ // we always want descending order
++ if (ascending) {
++ ci1 = ci2;
++ ci2 = this;
++ }
++
++ // a skip entry is always sorted last
++ if (ci1->_skipped) return -1;
++ if (ci2->_skipped) return 1;
++
++ if (col==0) {
++ if (ci1->_pSum < ci2->_pSum) return -1;
++ if (ci1->_pSum > ci2->_pSum) return 1;
++
++ // for same percentage (e.g. all 100%), use distance info
++ if (ci1->_distance < ci2->_distance) return -1;
++ if (ci1->_distance > ci2->_distance) return 1;
++ return 0;
++ }
++
++ if (col==1) {
++ if (ci1->_distance < ci2->_distance) return -1;
++ if (ci1->_distance > ci2->_distance) return 1;
++ return 0;
++ }
++
++ if (col==2) {
++ if (ci1->_cc < ci2->_cc) return -1;
++ if (ci1->_cc > ci2->_cc) return 1;
++ return 0;
++ }
++ return TQListViewItem::compare(i, col, ascending);
++}
++
++
++// CalleeCoverageItem
++
++
++CalleeCoverageItem::CalleeCoverageItem(TQListView* parent, Coverage* c,
++ TraceFunction* base,
++ TraceCostType* ct,
++ TraceCost::CostType gt)
++ : TQListViewItem(parent)
++{
++ _skipped = 0;
++ _coverage = c;
++ _function = c ? c->function() : 0;
++ _base = base;
++ _groupType = TraceCost::NoCostType;
++
++ setText(4, _function->prettyNameWithLocation());
++
++ setCostType(ct);
++ setGroupType(gt);
++}
++
++CalleeCoverageItem::CalleeCoverageItem(TQListView* parent, int skipped, Coverage* c,
++ TraceFunction* base,
++ TraceCostType* ct,
++ TraceCost::CostType gt)
++ : TQListViewItem(parent)
++{
++ _skipped = skipped;
++ _coverage = c;
++ _function = c ? c->function() : 0;
++ _base = base;
++ _groupType = TraceCost::NoCostType;
++
++ setText(4, i18n("(%n function skipped)", "(%n functions skipped)", _skipped));
++
++ setCostType(ct);
++ setGroupType(gt);
++}
++
++void CalleeCoverageItem::setGroupType(TraceCost::CostType gt)
++{
++ if (_skipped) return;
++ if (_groupType == gt) return;
++ _groupType = gt;
++
++ TQColor c = Configuration::functionColor(_groupType, _function);
++ setPixmap(4, colorPixmap(10, 10, c));
++}
++
++void CalleeCoverageItem::setCostType(TraceCostType* ct)
++{
++ _costType = ct;
++ update();
++}
++
++void CalleeCoverageItem::update()
++{
++ if (!_coverage) {
++ setText(0, TQString());
++ setText(1, TQString());
++ setText(2, TQString());
++ return;
++ }
++
++ _pSum = 100.0 * _coverage->inclusive();
++
++ // pSum/pSelf are percentages of inclusive cost of base
++ SubCost realSum = _base->inclusive()->subCost(_costType);
++ _sum = SubCost(realSum * _coverage->inclusive());
++
++
++ TQString str;
++ if (Configuration::showPercentage())
++ str = TQString("%1").arg(_pSum, 0, 'f', Configuration::percentPrecision());
++ else
++ str = _sum.pretty();
++
++ if (_skipped) {
++ str = TQString("< %1").arg(str);
++ setText(0, str);
++ setText(1, str);
++ return;
++ }
++ setText(0, str);
++
++ _pSelf = 100.0 * _coverage->self();
++ _self = SubCost(realSum * _coverage->self());
++
++ if (Configuration::showPercentage()) {
++ setText(1, TQString("%1")
++ .arg(_pSelf, 0, 'f', Configuration::percentPrecision()));
++ }
++ else {
++ setText(1, _self.pretty());
++ }
++
++ setPixmap(0, partitionPixmap(25, 10, _coverage->inclusiveHistogram(), 0,
++ Coverage::maxHistogramDepth, false));
++ setPixmap(1, partitionPixmap(25, 10, _coverage->selfHistogram(), 0,
++ Coverage::maxHistogramDepth, false));
++
++
++ _cc = SubCost(_coverage->callCount());
++ setText(3, _cc ? _cc.pretty() : TQString("(0)"));
++
++ // for comparations
++ _distance = _coverage->inclusiveMedian();
++ TQString distString;
++ if (_coverage->minDistance() == _coverage->maxDistance())
++ distString = TQString::number(_distance);
++ else {
++ int sMed = _coverage->selfMedian();
++ TQString med;
++ if (_distance == sMed)
++ med = TQString::number(_distance);
++ else
++ med = TQString("%1/%2").arg(_distance).arg(sMed);
++
++ distString = TQString("%1-%2 (%3)")
++ .arg(_coverage->minDistance())
++ .arg(_coverage->maxDistance())
++ .arg(med);
++ }
++ setText(2, distString);
++}
++
++
++int CalleeCoverageItem::compare(TQListViewItem * i,
++ int col, bool ascending ) const
++{
++ CalleeCoverageItem* ci = (CalleeCoverageItem*) i;
++
++ // a skip entry is always sorted last
++ if (_skipped) return -1;
++ if (ci->_skipped) return 1;
++
++ if (col==0) {
++ if (_pSum < ci->_pSum) return -1;
++ if (_pSum > ci->_pSum) return 1;
++
++ // for same percentage (e.g. all 100%), use distance info
++ if (_distance < ci->_distance) return -1;
++ if (_distance > ci->_distance) return 1;
++ return 0;
++ }
++
++ if (col==1) {
++ if (_pSelf < ci->_pSelf) return -1;
++ if (_pSelf > ci->_pSelf) return 1;
++
++ // for same percentage (e.g. all 100%), use distance info
++ if (_distance < ci->_distance) return -1;
++ if (_distance > ci->_distance) return 1;
++ return 0;
++ }
++
++ if (col==2) {
++ // we want to sort the distance in contra direction to costs
++ if (_distance < ci->_distance) return 1;
++ if (_distance > ci->_distance) return -1;
++ return 0;
++ }
++
++ if (col==3) {
++ if (_cc < ci->_cc) return -1;
++ if (_cc > ci->_cc) return 1;
++ return 0;
++ }
++ return TQListViewItem::compare(i, col, ascending);
++}
++
++
+diff --git a/kdecachegrind/kdecachegrind/coverageitem.h b/kdecachegrind/kdecachegrind/coverageitem.h
+new file mode 100644
+index 0000000..ba442aa
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/coverageitem.h
+@@ -0,0 +1,82 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Items of coverage view.
++ */
++
++#ifndef COVERAGEITEM_H
++#define COVERAGEITEM_H
++
++#include <tqlistview.h>
++#include "tracedata.h"
++
++class Coverage;
++
++class CallerCoverageItem: public TQListViewItem
++{
++public:
++ CallerCoverageItem(TQListView* parent, Coverage* c, TraceFunction* base,
++ TraceCostType* ct, TraceCost::CostType gt);
++ CallerCoverageItem(TQListView* parent, int skipped, Coverage* c, TraceFunction* base,
++ TraceCostType* ct, TraceCost::CostType gt);
++
++ int compare(TQListViewItem * i, int col, bool ascending ) const;
++ TraceFunction* function() { return (_skipped) ? 0 : _function; }
++ void setCostType(TraceCostType* ct);
++ void setGroupType(TraceCost::CostType);
++ void update();
++
++private:
++ float _pSum;
++ SubCost _sum;
++ TraceCostType* _costType;
++ TraceCost::CostType _groupType;
++ SubCost _cc;
++ int _distance, _skipped;
++ TraceFunction *_function, *_base;
++ Coverage* _coverage;
++};
++
++
++class CalleeCoverageItem: public TQListViewItem
++{
++public:
++ CalleeCoverageItem(TQListView* parent, Coverage* c, TraceFunction* base,
++ TraceCostType* ct, TraceCost::CostType gt);
++ CalleeCoverageItem(TQListView* parent, int skipped, Coverage* c, TraceFunction* base,
++ TraceCostType* ct, TraceCost::CostType gt);
++
++ int compare(TQListViewItem * i, int col, bool ascending ) const;
++ TraceFunction* function() { return (_skipped) ? 0 : _function; }
++ void setCostType(TraceCostType* ct);
++ void setGroupType(TraceCost::CostType);
++ void update();
++
++private:
++ float _pSum, _pSelf;
++ SubCost _sum, _self;
++ TraceCostType* _costType;
++ TraceCost::CostType _groupType;
++ SubCost _cc;
++ int _distance, _skipped;
++ TraceFunction *_function, *_base;
++ Coverage* _coverage;
++};
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/coverageview.cpp b/kdecachegrind/kdecachegrind/coverageview.cpp
+new file mode 100644
+index 0000000..6657e92
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/coverageview.cpp
+@@ -0,0 +1,321 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Coverage Views
++ */
++
++#include <tqwhatsthis.h>
++#include <tqpopupmenu.h>
++#include <klocale.h>
++
++#include "configuration.h"
++#include "coverageitem.h"
++#include "coverage.h"
++#include "coverageview.h"
++
++
++
++//
++// CoverageView
++//
++
++
++CoverageView::CoverageView(bool showCallers, TraceItemView* parentView,
++ TQWidget* parent, const char* name)
++ : TQListView(parent, name), TraceItemView(parentView)
++{
++ _showCallers = showCallers;
++
++
++ addColumn( i18n( "Incl." ) );
++ if (_showCallers) {
++ addColumn( i18n( "Distance" ) );
++ addColumn( i18n( "Called" ) );
++ addColumn( i18n( "Caller" ) );
++ }
++ else {
++ addColumn( i18n( "Self" ) );
++ addColumn( i18n( "Distance" ) );
++ addColumn( i18n( "Calling" ) );
++ addColumn( i18n( "Callee" ) );
++ setColumnAlignment(3, TQt::AlignRight);
++ }
++
++ setSorting(0,false);
++ setColumnAlignment(0, TQt::AlignRight);
++ setColumnAlignment(1, TQt::AlignRight);
++ setColumnAlignment(2, TQt::AlignRight);
++ setAllColumnsShowFocus(true);
++ setResizeMode(TQListView::LastColumn);
++ setMinimumHeight(50);
++
++ connect( this,
++ TQT_SIGNAL( selectionChanged(TQListViewItem*) ),
++ TQT_SLOT( selectedSlot(TQListViewItem*) ) );
++
++ connect( this,
++ TQT_SIGNAL(contextMenuRequested(TQListViewItem*, const TQPoint &, int)),
++ TQT_SLOT(context(TQListViewItem*, const TQPoint &, int)));
++
++ connect(this,
++ TQT_SIGNAL(doubleClicked(TQListViewItem*)),
++ TQT_SLOT(activatedSlot(TQListViewItem*)));
++
++ connect(this,
++ TQT_SIGNAL(returnPressed(TQListViewItem*)),
++ TQT_SLOT(activatedSlot(TQListViewItem*)));
++
++ TQWhatsThis::add( this, whatsThis() );
++}
++
++TQString CoverageView::whatsThis() const
++{
++ return _showCallers ?
++ i18n( "<b>List of all Callers</b>"
++ "<p>This list shows all functions calling the "
++ "current selected one, either directly or with "
++ "several functions in-between on the stack; the "
++ "number of functions in-between plus one "
++ "is called the <em>Distance</em> (e.g. "
++ "for function A,B,C there exists a call from "
++ "A to C when A calls B and B calls C, i.e. "
++ "A => B => C. The distance here is 2).</p>"
++
++ "<p>Absolute cost shown is the cost spent in the "
++ "selected function while a listed function is active; "
++ "relative cost is the percentage of all cost spent in "
++ "the selected function while the listed one is "
++ "active. The cost graphic shows logarithmic "
++ "percentage with a different color for each "
++ "distance.</p>"
++
++ "<p>As there can be many calls from the same function, "
++ "the distance column sometimes shows "
++ "the range of distances for all "
++ "calls happening; then, in parentheses, there is the "
++ "medium distance, i.e. the distance where most of the "
++ "call costs happened.</p>"
++
++ "<p>Selecting a function makes it the current selected "
++ "one of this information panel. "
++ "If there are two panels (Split mode), the "
++ "function of the other panel is changed instead.</p>") :
++
++ i18n( "<b>List of all Callees</b>"
++ "<p>This list shows all functions called by the "
++ "current selected one, either directly or with "
++ "several function in-between on the stack; the "
++ "number of function in-between plus one "
++ "is called the <em>Distance</em> (e.g. "
++ "for function A,B,C there exists a call from "
++ "A to C when A calls B and B calls C, i.e. "
++ "A => B => C. The distance here is 2).</p>"
++
++ "<p>Absolute cost shown is the cost spent in the "
++ "listed function while the selected is active; "
++ "relative cost is the percentage of all cost spent in "
++ "the listed function while the selected one is active. "
++ "The cost graphic always shows logarithmic "
++ "percentage with a different color for each "
++ "distance.</p>"
++
++ "<p>As there can be many calls to the same function, "
++ "the distance column sometimes shows "
++ "the range of distances for all "
++ "calls happening; then, in parentheses, there is the "
++ "medium distance, i.e. the distance where most of the "
++ "call costs happened.</p>"
++
++ "<p>Selecting a function makes it the current selected "
++ "one of this information panel. "
++ "If there are two panels (Split mode), the "
++ "function of the other panel is changed instead.</p>");
++}
++
++void CoverageView::context(TQListViewItem* i, const TQPoint & p, int c)
++{
++ TQPopupMenu popup;
++
++ TraceFunction* f = 0;
++ if (i) {
++ f = _showCallers ?
++ ((CallerCoverageItem*)i)->function() :
++ ((CalleeCoverageItem*)i)->function();
++ }
++
++ if (f) {
++ TQString name = f->name();
++ if ((int)name.length()>Configuration::maxSymbolLength())
++ name = name.left(Configuration::maxSymbolLength()) + "...";
++ popup.insertItem(i18n("Go to '%1'").arg(name), 93);
++ popup.insertSeparator();
++ }
++
++ if ((c == 0) || (!_showCallers && c == 1)) {
++ addCostMenu(&popup, false);
++ popup.insertSeparator();
++ }
++ addGoMenu(&popup);
++
++ int r = popup.exec(p);
++ if (r == 93) activated(f);
++}
++
++void CoverageView::selectedSlot(TQListViewItem * i)
++{
++ TraceFunction* f = 0;
++ if (i) {
++ f = _showCallers ?
++ ((CallerCoverageItem*)i)->function() :
++ ((CalleeCoverageItem*)i)->function();
++ }
++
++ if (f) {
++ _selectedItem = f;
++ selected(f);
++ }
++}
++
++void CoverageView::activatedSlot(TQListViewItem * i)
++{
++ TraceFunction* f = 0;
++ if (i) {
++ f = _showCallers ?
++ ((CallerCoverageItem*)i)->function() :
++ ((CalleeCoverageItem*)i)->function();
++ }
++
++ if (f) activated(f);
++}
++
++TraceItem* CoverageView::canShow(TraceItem* i)
++{
++ TraceItem::CostType t = i ? i->type() : TraceItem::NoCostType;
++
++ switch(t) {
++ case TraceItem::Function:
++ case TraceItem::FunctionCycle:
++ return i;
++ default:
++ break;
++ }
++ return 0;
++}
++
++void CoverageView::doUpdate(int changeType)
++{
++ // Special case ?
++ if (changeType == selectedItemChanged) {
++
++ if (!_selectedItem) {
++ clearSelection();
++ return;
++ }
++
++ TraceFunction* f = 0;
++ TQListViewItem* i = TQListView::selectedItem();
++ if (i) {
++ f = _showCallers ?
++ ((CallerCoverageItem*)i)->function() :
++ ((CalleeCoverageItem*)i)->function();
++ }
++ if (f == _selectedItem) return;
++
++ TQListViewItem *item;
++ for (item = firstChild();item;item = item->nextSibling()) {
++ f = _showCallers ?
++ ((CallerCoverageItem*)item)->function() :
++ ((CalleeCoverageItem*)item)->function();
++ if (f == _selectedItem) {
++ ensureItemVisible(item);
++ setCurrentItem(item);
++ break;
++ }
++ }
++ return;
++ }
++
++ if (changeType == groupTypeChanged) {
++ TQListViewItem *item;
++ for (item = firstChild();item;item = item->nextSibling()) {
++ if (_showCallers)
++ ((CallerCoverageItem*)item)->setGroupType(_groupType);
++ else
++ ((CalleeCoverageItem*)item)->setGroupType(_groupType);
++ }
++ return;
++ }
++
++ refresh();
++}
++
++void CoverageView::refresh()
++{
++ clear();
++ setColumnWidth(0, 50);
++ if (!_showCallers)
++ setColumnWidth(1, 50);
++
++ if (!_data || !_activeItem) return;
++
++ TraceItem::CostType t = _activeItem->type();
++ TraceFunction* f = 0;
++ if (t == TraceItem::Function) f = (TraceFunction*) _activeItem;
++ if (t == TraceItem::FunctionCycle) f = (TraceFunction*) _activeItem;
++ if (!f) return;
++
++ TraceFunction* ff;
++ TraceFunctionList l;
++
++ _hc.clear(Configuration::maxListCount());
++ SubCost realSum = f->inclusive()->subCost(_costType);
++
++ if (_showCallers)
++ l = Coverage::coverage(f, Coverage::Caller, _costType);
++ else
++ l = Coverage::coverage(f, Coverage::Called, _costType);
++
++ for (ff=l.first();ff;ff=l.next()) {
++ Coverage* c = (Coverage*) ff->assoziation(Coverage::Rtti);
++ if (c && (c->inclusive()>0.0))
++ _hc.addCost(ff, SubCost(realSum * c->inclusive()));
++ }
++
++ for(int i=0;i<_hc.realCount();i++) {
++ ff = (TraceFunction*) _hc[i];
++ Coverage* c = (Coverage*) ff->assoziation(Coverage::Rtti);
++ if (_showCallers)
++ new CallerCoverageItem(this, c, f, _costType, _groupType);
++ else
++ new CalleeCoverageItem(this, c, f, _costType, _groupType);
++ }
++ if (_hc.hasMore()) {
++ // a placeholder for all the functions skipped ...
++ ff = (TraceFunction*) _hc[_hc.maxSize()-1];
++ Coverage* c = (Coverage*) ff->assoziation(Coverage::Rtti);
++ if (_showCallers)
++ new CallerCoverageItem(this, _hc.count() - _hc.maxSize(),
++ c, f, _costType, _groupType);
++ else
++ new CalleeCoverageItem(this, _hc.count() - _hc.maxSize(),
++ c, f, _costType, _groupType);
++ }
++}
++
++#include "coverageview.moc"
+diff --git a/kdecachegrind/kdecachegrind/coverageview.h b/kdecachegrind/kdecachegrind/coverageview.h
+new file mode 100644
+index 0000000..09c5de0
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/coverageview.h
+@@ -0,0 +1,57 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Coverage Views
++ */
++
++#ifndef COVERAGEVIEW_H
++#define COVERAGEVIEW_H
++
++#include <tqlistview.h>
++#include "tracedata.h"
++#include "traceitemview.h"
++#include "listutils.h"
++
++class CoverageView: public TQListView, public TraceItemView
++{
++ Q_OBJECT
++ TQ_OBJECT
++
++public:
++ CoverageView(bool showCallers, TraceItemView* parentView,
++ TQWidget* parent=0, const char* name=0);
++
++ virtual TQWidget* widget() { return this; }
++ TQString whatsThis() const;
++
++private slots:
++ void context(TQListViewItem*,const TQPoint &, int);
++ void selectedSlot(TQListViewItem*);
++ void activatedSlot(TQListViewItem*);
++
++private:
++ TraceItem* canShow(TraceItem*);
++ void doUpdate(int);
++ void refresh();
++
++ HighestCostList _hc;
++ bool _showCallers;
++};
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/dumpmanager.cpp b/kdecachegrind/kdecachegrind/dumpmanager.cpp
+new file mode 100644
+index 0000000..2f0891a
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/dumpmanager.cpp
+@@ -0,0 +1,50 @@
++/**
++ * DumpManager
++ * Part of KCachegrind
++ * 2003, Josef Weidendorfer (GPL V2)
++ */
++
++#include "dumpmanager.h"
++
++
++//
++// Dump
++//
++
++Dump::Dump(TQString file)
++{
++ _filename = file;
++}
++
++
++//
++// DumpManager
++//
++
++DumpManager* DumpManager::_self = 0;
++
++
++DumpManager::DumpManager()
++{
++}
++
++DumpManager* DumpManager::self()
++{
++ if (!_self)
++ _self = new DumpManager();
++
++ return _self;
++}
++
++
++DumpList DumpManager::loadableDumps()
++{
++ DumpList res;
++
++ return res;
++}
++
++TraceData* DumpManager::load(Dump*)
++{
++ return 0;
++}
+diff --git a/kdecachegrind/kdecachegrind/dumpmanager.h b/kdecachegrind/kdecachegrind/dumpmanager.h
+new file mode 100644
+index 0000000..4925819
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/dumpmanager.h
+@@ -0,0 +1,59 @@
++/**
++ * DumpManager
++ * Part of KCachegrind
++ * 2003, Josef Weidendorfer (GPL V2)
++ *
++ * DumpManager is a Singleton.
++ * - Has List of current loaded dumps / loadable dumps
++ * - Does "communication" with current running profiles
++ * for dump selection dockable
++ */
++
++#ifndef DUMPMANAGER_H
++#define DUMPMANAGER_H
++
++#include <tqstring.h>
++#include <tqptrlist.h>
++
++class Dump;
++class TraceData;
++
++typedef TQPtrList<Dump> DumpList;
++
++
++/**
++ * A loadable profile Dump
++ */
++class Dump
++{
++public:
++ Dump(TQString);
++
++ TQString filename() { return _filename; }
++
++private:
++ TQString _filename;
++};
++
++
++/*
++ * TODO:
++ * - Everything
++ *
++ */
++
++class DumpManager
++{
++public:
++ DumpManager();
++
++ DumpManager* self();
++
++ DumpList loadableDumps();
++ TraceData* load(Dump*);
++
++private:
++ static DumpManager* _self;
++};
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/dumpselection.cpp b/kdecachegrind/kdecachegrind/dumpselection.cpp
+new file mode 100644
+index 0000000..4d812ef
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/dumpselection.cpp
+@@ -0,0 +1,33 @@
++/**
++ * DumpSelection Dockable
++ * Part of KCachegrind
++ * 2003, Josef Weidendorfer (GPL V2)
++ *
++ * - Fast Selection of dumps to load/activate/use for comparing
++ * - Start a profile run from GUI (current supported: Callgrind)
++ * - View state of running profile runs.
++ *
++ */
++
++#include "dumpselection.h"
++
++/*
++ * TODO:
++ * - Everything !!
++ * - Request State info on current function..
++ *
++ */
++
++
++DumpSelection::DumpSelection( TopLevel* top,
++ TQWidget* parent, const char* name)
++ : DumpSelectionBase(parent, name), TraceItemView(0, top)
++{
++}
++
++DumpSelection::~DumpSelection()
++{}
++
++
++#include "dumpselection.moc"
++
+diff --git a/kdecachegrind/kdecachegrind/dumpselection.h b/kdecachegrind/kdecachegrind/dumpselection.h
+new file mode 100644
+index 0000000..49ca532
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/dumpselection.h
+@@ -0,0 +1,30 @@
++/**
++ * DumpSelection Dockable
++ * Part of KCachegrind
++ * 2003, Josef Weidendorfer (GPL V2)
++ *
++ * - Fast Selection of dumps to load/activate/use for comparing
++ * - Start a profile run from GUI (current supported: Callgrind)
++ * - View state of running profile runs.
++ *
++ */
++
++#ifndef DUMPSELECTION_H
++#define DUMPSELECTION_H
++
++#include "dumpselectionbase.h"
++#include "traceitemview.h"
++
++class DumpSelection : public DumpSelectionBase, public TraceItemView
++{
++ Q_OBJECT
++ TQ_OBJECT
++
++public:
++ DumpSelection( TopLevel*, TQWidget* parent = 0, const char* name = 0);
++ virtual ~DumpSelection();
++
++ TQWidget* widget() { return this; }
++};
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/dumpselectionbase.ui b/kdecachegrind/kdecachegrind/dumpselectionbase.ui
+new file mode 100644
+index 0000000..b8ad1b0
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/dumpselectionbase.ui
+@@ -0,0 +1,1082 @@
++<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
++<class>DumpSelectionBase</class>
++<widget class="TQWidget">
++ <property name="name">
++ <cstring>DumpSelectionBase</cstring>
++ </property>
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>349</width>
++ <height>832</height>
++ </rect>
++ </property>
++ <property name="caption">
++ <string>Profile Dumps</string>
++ </property>
++ <vbox>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <widget class="TQSplitter">
++ <property name="name">
++ <cstring>splitter1</cstring>
++ </property>
++ <property name="orientation">
++ <enum>Vertical</enum>
++ </property>
++ <widget class="TQListView">
++ <column>
++ <property name="text">
++ <string>Target</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <column>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <column>
++ <property name="text">
++ <string>Time</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <column>
++ <property name="text">
++ <string>Path</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <property name="name">
++ <cstring>listView1</cstring>
++ </property>
++ </widget>
++ <widget class="TQTabWidget">
++ <property name="name">
++ <cstring>tabWidget2</cstring>
++ </property>
++ <widget class="TQWidget">
++ <property name="name">
++ <cstring>tab</cstring>
++ </property>
++ <attribute name="title">
++ <string>Options</string>
++ </attribute>
++ <vbox>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <widget class="TQLabel">
++ <property name="name">
++ <cstring>textLabel1</cstring>
++ </property>
++ <property name="sizePolicy">
++ <sizepolicy>
++ <hsizetype>5</hsizetype>
++ <vsizetype>5</vsizetype>
++ <horstretch>1</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string>Target command:</string>
++ </property>
++ </widget>
++ <widget class="TQLineEdit">
++ <property name="name">
++ <cstring>lineEdit1</cstring>
++ </property>
++ </widget>
++ <widget class="TQLabel">
++ <property name="name">
++ <cstring>textLabel2</cstring>
++ </property>
++ <property name="text">
++ <string>Profiler options:</string>
++ </property>
++ </widget>
++ <widget class="TQListView">
++ <column>
++ <property name="text">
++ <string>Option</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <column>
++ <property name="text">
++ <string>Value</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <item>
++ <property name="text">
++ <string>Trace</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <item>
++ <property name="text">
++ <string>Jumps</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ <item>
++ <property name="text">
++ <string>Instructions</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ </item>
++ <item>
++ <property name="text">
++ <string>Events</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <item>
++ <property name="text">
++ <string>Full Cache</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ <item>
++ <property name="text">
++ <string>Custom</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ </item>
++ <item>
++ <property name="text">
++ <string>Collect</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <item>
++ <property name="text">
++ <string>At Startup</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ <item>
++ <property name="text">
++ <string>While In</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ </item>
++ <item>
++ <property name="text">
++ <string>Skip</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <item>
++ <property name="text">
++ <string>PLT</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ <item>
++ <property name="text">
++ <string>Function</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ </item>
++ <item>
++ <property name="text">
++ <string>Dump Profile</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <item>
++ <property name="text">
++ <string>Every BBs</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ <item>
++ <property name="text">
++ <string>On Entering</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ <item>
++ <property name="text">
++ <string>On Leaving</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ </item>
++ <item>
++ <property name="text">
++ <string>Zero Events</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <item>
++ <property name="text">
++ <string>On Entering</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ </item>
++ <item>
++ <property name="text">
++ <string>Separate</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <item>
++ <property name="text">
++ <string>Threads</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ <item>
++ <property name="text">
++ <string>Recursions</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ <item>
++ <property name="text">
++ <string>Call Chain</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ </item>
++ <property name="name">
++ <cstring>listView3</cstring>
++ </property>
++ </widget>
++ <widget class="TQLabel">
++ <property name="name">
++ <cstring>textLabel1_2</cstring>
++ </property>
++ <property name="sizePolicy">
++ <sizepolicy>
++ <hsizetype>5</hsizetype>
++ <vsizetype>5</vsizetype>
++ <horstretch>1</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string>Custom profiler options:</string>
++ </property>
++ </widget>
++ <widget class="TQLineEdit">
++ <property name="name">
++ <cstring>lineEdit1_2</cstring>
++ </property>
++ </widget>
++ <widget class="TQLayoutWidget">
++ <property name="name">
++ <cstring>layout3</cstring>
++ </property>
++ <hbox>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <spacer>
++ <property name="name">
++ <cstring>spacer1</cstring>
++ </property>
++ <property name="orientation">
++ <enum>Horizontal</enum>
++ </property>
++ <property name="sizeType">
++ <enum>Expanding</enum>
++ </property>
++ <property name="sizeHint">
++ <size>
++ <width>21</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ <widget class="TQPushButton">
++ <property name="name">
++ <cstring>pushButton2</cstring>
++ </property>
++ <property name="text">
++ <string>Run New Profile</string>
++ </property>
++ </widget>
++ </hbox>
++ </widget>
++ </vbox>
++ </widget>
++ <widget class="TQWidget">
++ <property name="name">
++ <cstring>tab</cstring>
++ </property>
++ <attribute name="title">
++ <string>Info</string>
++ </attribute>
++ <vbox>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <widget class="TQLabel">
++ <property name="name">
++ <cstring>textLabel8</cstring>
++ </property>
++ <property name="text">
++ <string>Dump reason:</string>
++ </property>
++ </widget>
++ <widget class="TQLineEdit">
++ <property name="name">
++ <cstring>lineEdit3</cstring>
++ </property>
++ </widget>
++ <widget class="TQLabel">
++ <property name="name">
++ <cstring>textLabel6</cstring>
++ </property>
++ <property name="text">
++ <string>Event summary:</string>
++ </property>
++ </widget>
++ <widget class="TQListView">
++ <column>
++ <property name="text">
++ <string>Name</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <column>
++ <property name="text">
++ <string>Sum</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <property name="name">
++ <cstring>listView4</cstring>
++ </property>
++ </widget>
++ <widget class="TQLabel">
++ <property name="name">
++ <cstring>textLabel7</cstring>
++ </property>
++ <property name="text">
++ <string>Miscellaneous:</string>
++ </property>
++ </widget>
++ <widget class="TQTextEdit">
++ <property name="name">
++ <cstring>textEdit2</cstring>
++ </property>
++ </widget>
++ <widget class="TQLayoutWidget">
++ <property name="name">
++ <cstring>layout7</cstring>
++ </property>
++ <hbox>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <spacer>
++ <property name="name">
++ <cstring>spacer3</cstring>
++ </property>
++ <property name="orientation">
++ <enum>Horizontal</enum>
++ </property>
++ <property name="sizeType">
++ <enum>Expanding</enum>
++ </property>
++ <property name="sizeHint">
++ <size>
++ <width>50</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ <widget class="TQPushButton">
++ <property name="name">
++ <cstring>pushButton6</cstring>
++ </property>
++ <property name="text">
++ <string>Show</string>
++ </property>
++ </widget>
++ <widget class="TQPushButton">
++ <property name="name">
++ <cstring>pushButton5</cstring>
++ </property>
++ <property name="text">
++ <string>Compare</string>
++ </property>
++ </widget>
++ </hbox>
++ </widget>
++ </vbox>
++ </widget>
++ <widget class="TQWidget">
++ <property name="name">
++ <cstring>tab</cstring>
++ </property>
++ <attribute name="title">
++ <string>State</string>
++ </attribute>
++ <vbox>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <widget class="TQLayoutWidget">
++ <property name="name">
++ <cstring>layout2</cstring>
++ </property>
++ <hbox>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <widget class="TQPushButton">
++ <property name="name">
++ <cstring>pushButton1</cstring>
++ </property>
++ <property name="text">
++ <string>Update</string>
++ </property>
++ </widget>
++ <widget class="TQCheckBox">
++ <property name="name">
++ <cstring>checkBox1</cstring>
++ </property>
++ <property name="text">
++ <string>Every [s]:</string>
++ </property>
++ </widget>
++ <widget class="TQLineEdit">
++ <property name="name">
++ <cstring>lineEdit3_2</cstring>
++ </property>
++ </widget>
++ </hbox>
++ </widget>
++ <widget class="TQListView">
++ <column>
++ <property name="text">
++ <string>Counter</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <column>
++ <property name="text">
++ <string>Value</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <item>
++ <property name="text">
++ <string>Dumps Done</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ <item>
++ <property name="text">
++ <string>Is Collecting</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ <item>
++ <property name="text">
++ <string>Executed</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <item>
++ <property name="text">
++ <string>Basic Blocks</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ <item>
++ <property name="text">
++ <string>Calls</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ <item>
++ <property name="text">
++ <string>Jumps</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ </item>
++ <item>
++ <property name="text">
++ <string>Events</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <item>
++ <property name="text">
++ <string>Ir</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ </item>
++ <item>
++ <property name="text">
++ <string>Distinct</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <item>
++ <property name="text">
++ <string>ELF Objects</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ <item>
++ <property name="text">
++ <string>Functions</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ <item>
++ <property name="text">
++ <string>Contexts</string>
++ </property>
++ <property name="text">
++ <string></string>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ <property name="pixmap">
++ <pixmap></pixmap>
++ </property>
++ </item>
++ </item>
++ <property name="name">
++ <cstring>listView4_3</cstring>
++ </property>
++ </widget>
++ <widget class="TQLayoutWidget">
++ <property name="name">
++ <cstring>layout4</cstring>
++ </property>
++ <hbox>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <widget class="TQLabel">
++ <property name="name">
++ <cstring>textLabel4</cstring>
++ </property>
++ <property name="sizePolicy">
++ <sizepolicy>
++ <hsizetype>5</hsizetype>
++ <vsizetype>5</vsizetype>
++ <horstretch>1</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string>Stack trace:</string>
++ </property>
++ </widget>
++ <widget class="TQCheckBox">
++ <property name="name">
++ <cstring>checkBox2</cstring>
++ </property>
++ <property name="text">
++ <string>Sync.</string>
++ </property>
++ </widget>
++ </hbox>
++ </widget>
++ <widget class="TQListView">
++ <column>
++ <property name="text">
++ <string>#</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <column>
++ <property name="text">
++ <string>Incl.</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <column>
++ <property name="text">
++ <string>Called</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <column>
++ <property name="text">
++ <string>Function</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <column>
++ <property name="text">
++ <string>Location</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <property name="name">
++ <cstring>listView7</cstring>
++ </property>
++ </widget>
++ <widget class="TQLayoutWidget">
++ <property name="name">
++ <cstring>layout6</cstring>
++ </property>
++ <hbox>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <widget class="TQPushButton">
++ <property name="name">
++ <cstring>pushButton7</cstring>
++ </property>
++ <property name="text">
++ <string>Start</string>
++ </property>
++ </widget>
++ <spacer>
++ <property name="name">
++ <cstring>spacer2</cstring>
++ </property>
++ <property name="orientation">
++ <enum>Horizontal</enum>
++ </property>
++ <property name="sizeType">
++ <enum>Expanding</enum>
++ </property>
++ <property name="sizeHint">
++ <size>
++ <width>20</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ <widget class="TQPushButton">
++ <property name="name">
++ <cstring>pushButton6_2</cstring>
++ </property>
++ <property name="text">
++ <string>Zero</string>
++ </property>
++ </widget>
++ <widget class="TQPushButton">
++ <property name="name">
++ <cstring>pushButton4</cstring>
++ </property>
++ <property name="text">
++ <string>Dump</string>
++ </property>
++ </widget>
++ </hbox>
++ </widget>
++ </vbox>
++ </widget>
++ <widget class="TQWidget">
++ <property name="name">
++ <cstring>tab</cstring>
++ </property>
++ <attribute name="title">
++ <string>Messages</string>
++ </attribute>
++ <vbox>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <widget class="TQTextEdit">
++ <property name="name">
++ <cstring>textEdit2_2</cstring>
++ </property>
++ </widget>
++ <widget class="TQLayoutWidget">
++ <property name="name">
++ <cstring>layout6</cstring>
++ </property>
++ <hbox>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <widget class="TQPushButton">
++ <property name="name">
++ <cstring>pushButton9</cstring>
++ </property>
++ <property name="text">
++ <string>Kill Run</string>
++ </property>
++ </widget>
++ <spacer>
++ <property name="name">
++ <cstring>spacer4</cstring>
++ </property>
++ <property name="orientation">
++ <enum>Horizontal</enum>
++ </property>
++ <property name="sizeType">
++ <enum>Expanding</enum>
++ </property>
++ <property name="sizeHint">
++ <size>
++ <width>21</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ <widget class="TQPushButton">
++ <property name="name">
++ <cstring>pushButton8</cstring>
++ </property>
++ <property name="text">
++ <string>Clear</string>
++ </property>
++ </widget>
++ </hbox>
++ </widget>
++ </vbox>
++ </widget>
++ </widget>
++ </widget>
++ </vbox>
++</widget>
++<layoutdefaults spacing="6" margin="11"/>
++</UI>
+diff --git a/kdecachegrind/kdecachegrind/fixcost.cpp b/kdecachegrind/kdecachegrind/fixcost.cpp
+new file mode 100644
+index 0000000..4102926
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/fixcost.cpp
+@@ -0,0 +1,174 @@
++/*
++ * Part of KCacheGrind
++ *
++ * 2003, Josef Weidendorfer
++ */
++
++#include "fixcost.h"
++#include "utils.h"
++
++
++// FixCost
++
++FixCost::FixCost(TracePart* part, FixPool* pool,
++ TraceFunctionSource* functionSource,
++ PositionSpec& pos,
++ TracePartFunction* partFunction,
++ FixString& s)
++{
++ int maxCount = part->fixSubMapping()->count();
++
++ _part = part;
++ _functionSource = functionSource;
++ _pos = pos;
++
++ _cost = (SubCost*) pool->reserve(sizeof(SubCost) * maxCount);
++ s.stripSpaces();
++ int i = 0;
++ while(i<maxCount) {
++ if (!s.stripUInt64(_cost[i])) break;
++ i++;
++ }
++ _count = i;
++
++ if (!pool->allocateReserved(sizeof(SubCost) * _count))
++ _count = 0;
++
++ _nextCostOfPartFunction = partFunction ?
++ partFunction->setFirstFixCost(this) : 0;
++}
++
++void* FixCost::operator new(size_t size, FixPool* pool)
++{
++ return pool->allocate(size);
++}
++
++void FixCost::addTo(TraceCost* c)
++{
++ TraceSubMapping* sm = _part->fixSubMapping();
++
++ int i, realIndex;
++
++ for(i=0; i<_count; i++) {
++ realIndex = sm->realIndex(i);
++ c->addCost(realIndex, _cost[i]);
++ }
++}
++
++
++
++// FixCallCost
++
++FixCallCost::FixCallCost(TracePart* part, FixPool* pool,
++ TraceFunctionSource* functionSource,
++ unsigned int line, Addr addr,
++ TracePartCall* partCall,
++ SubCost callCount, FixString& s)
++{
++ if (0) qDebug("Got FixCallCost (addr 0x%s, line %d): calls %s",
++ addr.toString().ascii(), line,
++ callCount.pretty().ascii());
++
++ int maxCount = part->fixSubMapping()->count();
++
++ _part = part;
++ _functionSource = functionSource;
++ _line = line;
++ _addr = addr;
++
++ _cost = (SubCost*) pool->reserve(sizeof(SubCost) * (maxCount+1));
++ s.stripSpaces();
++ int i = 0;
++ while(i<maxCount) {
++ if (!s.stripUInt64(_cost[i])) break;
++ i++;
++ }
++ _count = i;
++
++ if (!pool->allocateReserved(sizeof(SubCost) * (_count+1) ))
++ _count = 0;
++ else
++ _cost[_count] = callCount;
++
++ _nextCostOfPartCall = partCall ? partCall->setFirstFixCallCost(this) : 0;
++}
++
++void* FixCallCost::operator new(size_t size, FixPool* pool)
++{
++ return pool->allocate(size);
++}
++
++void FixCallCost::addTo(TraceCallCost* c)
++{
++ TraceSubMapping* sm = _part->fixSubMapping();
++
++ int i, realIndex;
++
++ for(i=0; i<_count; i++) {
++ realIndex = sm->realIndex(i);
++ c->addCost(realIndex, _cost[i]);
++ }
++ c->addCallCount(_cost[_count]);
++
++ if (0) qDebug("Adding from (addr 0x%s, ln %d): calls %s",
++ _addr.toString().ascii(), _line,
++ _cost[_count].pretty().ascii());
++}
++
++void FixCallCost::setMax(TraceCost* c)
++{
++ TraceSubMapping* sm = _part->fixSubMapping();
++
++ int i, realIndex;
++
++ for(i=0; i<_count; i++) {
++ realIndex = sm->realIndex(i);
++ c->maxCost(realIndex, _cost[i]);
++ }
++}
++
++
++// FixJump
++
++FixJump::FixJump(TracePart* part, FixPool* pool,
++ unsigned int line, Addr addr,
++ TracePartFunction* partFunction,
++ TraceFunctionSource* source,
++ unsigned int targetLine, Addr targetAddr,
++ TraceFunction* targetFunction,
++ TraceFunctionSource* targetSource,
++ bool isCondJump,
++ SubCost executed, SubCost followed)
++{
++ _part = part;
++ _source = source;
++ _line = line;
++ _addr = addr;
++
++ _targetFunction = targetFunction;
++ _targetSource = targetSource;
++ _targetLine = targetLine;
++ _targetAddr = targetAddr;
++
++ _isCondJump = isCondJump;
++
++ int size = (isCondJump ? 2 : 1) * sizeof(SubCost);
++ _cost = (SubCost*) pool->allocate(size);
++ _cost[0] = executed;
++ if (isCondJump) _cost[1] = followed;
++
++ _nextJumpOfPartFunction = partFunction ?
++ partFunction->setFirstFixJump(this) : 0;
++}
++
++void* FixJump::operator new(size_t size, FixPool* pool)
++{
++ return pool->allocate(size);
++}
++
++void FixJump::addTo(TraceJumpCost* jc)
++{
++ jc->addExecutedCount(_cost[0]);
++ if (_isCondJump)
++ jc->addFollowedCount(_cost[1]);
++}
+diff --git a/kdecachegrind/kdecachegrind/fixcost.h b/kdecachegrind/kdecachegrind/fixcost.h
+new file mode 100644
+index 0000000..7e90fb4
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/fixcost.h
+@@ -0,0 +1,171 @@
++/*
++ * Part of KCacheGrind
++ *
++ * 2003, Josef Weidendorfer
++ */
++
++#ifndef FIXCOST_H
++#define FIXCOST_H
++
++/**
++ * Setting USE_FIXCOST to 1 enables a memory space hack:
++ * For some data, build up internal data model lazy by using
++ * the Fix*Cost classes, which are simple copies from input data.
++ */
++#define USE_FIXCOST 1
++
++#include "tracedata.h"
++#include "pool.h"
++
++class PositionSpec
++{
++ public:
++ PositionSpec()
++ { fromLine = 0, toLine = 0, fromAddr = 0, toAddr = 0; }
++ PositionSpec(uint l1, uint l2, Addr a1, Addr a2)
++ { fromLine = l1, toLine = l2, fromAddr = a1, toAddr = a2; }
++
++ bool isLineRegion() const { return (fromLine != toLine); }
++ bool isAddrRegion() const { return (fromAddr != toAddr); }
++
++ uint fromLine, toLine;
++ Addr fromAddr, toAddr;
++};
++
++/**
++ * A class holding an unchangable cost item of an input file.
++ *
++ * As there can be a lot of such cost items, we use our own
++ * allocator which uses FixPool
++ */
++class FixCost
++{
++
++ public:
++ FixCost(TracePart*, FixPool*,
++ TraceFunctionSource*,
++ PositionSpec&,
++ TracePartFunction*,
++ FixString&);
++
++ void *operator new(size_t size, FixPool*);
++
++ void addTo(TraceCost*);
++
++ TracePart* part() const { return _part; }
++ bool isLineRegion() const { return _pos.isLineRegion(); }
++ bool isAddrRegion() const { return _pos.isAddrRegion(); }
++ uint fromLine() const { return _pos.fromLine; }
++ uint line() const { return _pos.fromLine; }
++ uint toLine() const { return _pos.toLine; }
++ Addr fromAddr() const { return _pos.fromAddr; }
++ Addr addr() const { return _pos.fromAddr; }
++ Addr toAddr() const { return _pos.toAddr; }
++ TraceFunctionSource* functionSource() const { return _functionSource; }
++
++ FixCost* nextCostOfPartFunction() const
++ { return _nextCostOfPartFunction; }
++
++ private:
++ int _count;
++ SubCost* _cost;
++ PositionSpec _pos;
++
++ TracePart* _part;
++ TraceFunctionSource* _functionSource;
++ FixCost *_nextCostOfPartFunction;
++};
++
++/**
++ * A FixCallCost will be inserted into a
++ * - TracePartCall to keep source/target function info
++ * - TraceFunctionSourceFile to keep file info of call source
++ */
++class FixCallCost
++{
++
++ public:
++ FixCallCost(TracePart*, FixPool*,
++ TraceFunctionSource*,
++ unsigned int line,
++ Addr addr,
++ TracePartCall*,
++ SubCost, FixString&);
++
++ void *operator new(size_t size, FixPool*);
++
++ void addTo(TraceCallCost*);
++ void setMax(TraceCost*);
++
++ TracePart* part() const { return _part; }
++ unsigned int line() const { return _line; }
++ Addr addr() const { return _addr; }
++ SubCost callCount() const { return _cost[_count]; }
++ TraceFunctionSource* functionSource() const { return _functionSource; }
++ FixCallCost* nextCostOfPartCall() const
++ { return _nextCostOfPartCall; }
++
++ private:
++ // we use 1 SubCost more than _count: _cost[_count] is the call count
++ int _count;
++ SubCost* _cost;
++ unsigned int _line;
++ Addr _addr;
++
++ TracePart* _part;
++ TraceFunctionSource* _functionSource;
++ FixCallCost* _nextCostOfPartCall;
++};
++
++/**
++ * A class holding a jump (mostly) inside of a function
++ */
++class FixJump
++{
++
++ public:
++ FixJump(TracePart*, FixPool*,
++ /* source position */
++ unsigned int line, Addr addr,
++ TracePartFunction*, TraceFunctionSource*,
++ /* target position */
++ unsigned int targetLine, Addr targetAddr,
++ TraceFunction*, TraceFunctionSource*,
++ bool isCondJump,
++ SubCost, SubCost);
++
++ void *operator new(size_t size, FixPool*);
++
++ void addTo(TraceJumpCost*);
++
++ TracePart* part() const { return _part; }
++ unsigned int line() const { return _line; }
++ Addr addr() const { return _addr; }
++ TraceFunctionSource* source() const { return _source; }
++ TraceFunction* targetFunction() const { return _targetFunction; }
++ unsigned int targetLine() const { return _targetLine; }
++ Addr targetAddr() const { return _targetAddr; }
++ TraceFunctionSource* targetSource() const { return _targetSource; }
++ bool isCondJump() { return _isCondJump; }
++ SubCost executedCount() const { return _cost[0]; }
++ SubCost followedCount() const
++ { return _isCondJump ? _cost[1] : SubCost(0); }
++
++ FixJump* nextJumpOfPartFunction() const
++ { return _nextJumpOfPartFunction; }
++
++ private:
++ bool _isCondJump;
++ SubCost* _cost;
++ unsigned int _line, _targetLine;
++ Addr _addr, _targetAddr;
++
++ TracePart* _part;
++ TraceFunctionSource *_source, *_targetSource;
++ TraceFunction* _targetFunction;
++ FixJump *_nextJumpOfPartFunction;
++};
++
++#endif
++
++
+diff --git a/kdecachegrind/kdecachegrind/functionitem.cpp b/kdecachegrind/kdecachegrind/functionitem.cpp
+new file mode 100644
+index 0000000..3b694dd
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/functionitem.cpp
+@@ -0,0 +1,236 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * List Item for the FunctionSelection list
++ */
++
++
++//#include <math.h>
++
++//#include <tqpainter.h>
++//#include <tqregexp.h>
++
++#include <klocale.h>
++#include <kiconloader.h>
++#include <kapplication.h>
++
++#include "listutils.h"
++#include "functionitem.h"
++#include "configuration.h"
++
++
++// FunctionItem
++
++FunctionItem::FunctionItem(TQListView* parent, TraceFunction* f,
++ TraceCostType* ct, TraceCost::CostType gt)
++ :TQListViewItem(parent)
++{
++#if 0
++ _costPixValid = false;
++ _groupPixValid = false;
++#endif
++
++ _function = f;
++ _skipped = 0;
++ _groupType = TraceCost::NoCostType;
++ setGroupType(gt);
++ setCostType(ct);
++
++ setText(3, f->prettyName());
++ setText(4, f->prettyLocation());
++}
++
++FunctionItem::FunctionItem(TQListView* parent, int skipped,
++ TraceFunction* f, TraceCostType* ct)
++ :TQListViewItem(parent)
++{
++#if 0
++ _costPixValid = false;
++ _groupPixValid = false;
++#endif
++ _skipped = skipped;
++ _function = f;
++ _groupType = TraceCost::NoCostType;
++ setCostType(ct);
++
++ setText(3, i18n("(%n function skipped)", "(%n functions skipped)", skipped));
++}
++
++#if 0
++const TQPixmap* FunctionItem::pixmap(int column) const
++{
++ if (column == 3) {
++ if (!_groupPixValid) {
++ TQColor c = Configuration::functionColor(_groupType, _function);
++ _groupPix = colorPixmap(10, 10, c);
++ _groupPixValid = true;
++ }
++ return &_groupPix;
++ }
++ if (column == 1) {
++ if (!_costPixValid) {
++ _costPix = colorPixmap(10, 10, c);
++ _costPixValid = true;
++ }
++ return &_costPix;
++ }
++ return 0;
++}
++#endif
++
++void FunctionItem::setGroupType(TraceCost::CostType gt)
++{
++ if (_skipped) return;
++ if (_groupType == gt) return;
++ _groupType = gt;
++
++
++#if 0
++ _groupPixValid = false;
++ viewList()->repaint();
++#else
++ TQColor c = Configuration::functionColor(_groupType, _function);
++ setPixmap(3, colorPixmap(10, 10, c));
++#endif
++}
++
++void FunctionItem::setCostType(TraceCostType* c)
++{
++ _costType = c;
++ update();
++}
++
++void FunctionItem::update()
++{
++ double inclTotal = _function->data()->subCost(_costType);
++ TQString str;
++
++ TraceCost* selfCost = _function->data();
++ if (Configuration::showExpanded()) {
++ switch(_groupType) {
++ case TraceCost::Object: selfCost = _function->object(); break;
++ case TraceCost::Class: selfCost = _function->cls(); break;
++ case TraceCost::File: selfCost = _function->file(); break;
++ default: break;
++ }
++ }
++ double selfTotal = selfCost->subCost(_costType);
++
++ if (_skipped) {
++ // special handling for skip entries...
++
++ // only text updates of incl./self
++
++ // for all skipped functions, cost is below the given function
++ _sum = _function->inclusive()->subCost(_costType);
++ double incl = 100.0 * _sum / inclTotal;
++ if (Configuration::showPercentage())
++ str = TQString("%1").arg(incl, 0, 'f', Configuration::percentPrecision());
++ else
++ str = _function->inclusive()->prettySubCost(_costType);
++ str = "< " + str;
++ setText(0, str);
++ setText(1, str);
++ return;
++ }
++
++ // Call count...
++ if (_function->calledCount() >0)
++ str = _function->prettyCalledCount();
++ else {
++ if (_function == _function->cycle())
++ str = TQString("-");
++ else
++ str = TQString("(0)");
++ }
++ setText(2, str);
++
++ // Incl. cost
++ _sum = _function->inclusive()->subCost(_costType);
++ if (inclTotal == 0.0) {
++ setPixmap(0, TQPixmap());
++ setText(0, "-");
++ }
++ else {
++ double incl = 100.0 * _sum / inclTotal;
++ if (Configuration::showPercentage())
++ setText(0, TQString("%1")
++ .arg(incl, 0, 'f', Configuration::percentPrecision()));
++ else
++ setText(0, _function->inclusive()->prettySubCost(_costType));
++
++ setPixmap(0, costPixmap(_costType, _function->inclusive(), inclTotal, false));
++ }
++
++ // self
++ _pure = _function->subCost(_costType);
++ if (selfTotal == 0.0) {
++ setPixmap(1, TQPixmap());
++ setText(1, "-");
++ }
++ else {
++ double self = 100.0 * _pure / selfTotal;
++
++ if (Configuration::showPercentage())
++ setText(1, TQString("%1")
++ .arg(self, 0, 'f', Configuration::percentPrecision()));
++ else
++ setText(1, _function->prettySubCost(_costType));
++
++ setPixmap(1, costPixmap(_costType, _function, selfTotal, false));
++ }
++}
++
++
++int FunctionItem::compare(TQListViewItem * i, int col, bool ascending ) const
++{
++ const FunctionItem* fi1 = this;
++ const FunctionItem* fi2 = (FunctionItem*) i;
++
++ // we always want descending order
++ if (ascending) {
++ fi1 = fi2;
++ fi2 = this;
++ }
++
++ // a skip entry is always sorted last
++ if (fi1->_skipped) return -1;
++ if (fi2->_skipped) return 1;
++
++ if (col==0) {
++ if (fi1->_sum < fi2->_sum) return -1;
++ if (fi1->_sum > fi2->_sum) return 1;
++ return 0;
++ }
++ if (col==1) {
++ if (fi1->_pure < fi2->_pure) return -1;
++ if (fi1->_pure > fi2->_pure) return 1;
++ return 0;
++ }
++ if (col==2) {
++ if (fi1->_function->calledCount() <
++ fi2->_function->calledCount()) return -1;
++ if (fi1->_function->calledCount() >
++ fi2->_function->calledCount()) return 1;
++ return 0;
++ }
++
++ return TQListViewItem::compare(i, col, ascending);
++}
++
+diff --git a/kdecachegrind/kdecachegrind/functionitem.h b/kdecachegrind/kdecachegrind/functionitem.h
+new file mode 100644
+index 0000000..d8f98f4
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/functionitem.h
+@@ -0,0 +1,58 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * List Item for the FunctionSelection list
++ */
++
++#ifndef FUNCTIONITEM_H
++#define FUNCTIONITEM_H
++
++#include <tqlistview.h>
++#include "tracedata.h"
++
++class FunctionItem: public TQListViewItem
++{
++public:
++ FunctionItem(TQListView* parent, TraceFunction* function,
++ TraceCostType* ct, TraceCost::CostType gt);
++ // constructor for a "Skipped ... " entry
++ FunctionItem(TQListView* parent, int skipped,
++ TraceFunction* function, TraceCostType* ct);
++
++ int compare(TQListViewItem * i, int col, bool ascending ) const;
++ TraceFunction* function() { return (_skipped) ? 0 : _function; }
++ void setCostType(TraceCostType* ct);
++ void setGroupType(TraceCost::CostType);
++ void update();
++
++#if 0
++ const TQPixmap* pixmap (int column) const;
++ bool _costPixValid, _groupPixValid;
++ TQPixMap _costPix, _groupPix;
++#endif
++
++private:
++ SubCost _sum, _pure;
++ TraceCostType* _costType;
++ TraceCost::CostType _groupType;
++ TraceFunction* _function;
++ int _skipped;
++};
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/functionselection.cpp b/kdecachegrind/kdecachegrind/functionselection.cpp
+new file mode 100644
+index 0000000..c5646dd
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/functionselection.cpp
+@@ -0,0 +1,871 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * For function selection, to be put into a TQDockWindow
++ */
++
++#include <tqtimer.h>
++#include <tqlistview.h>
++#include <tqlabel.h>
++#include <tqpushbutton.h>
++#include <tqcombobox.h>
++#include <tqlineedit.h>
++#include <tqregexp.h>
++#include <tqpopupmenu.h>
++
++#include <klocale.h>
++
++#include "traceitemview.h"
++#include "stackbrowser.h"
++#include "functionselection.h"
++#include "partgraph.h"
++#include "functionitem.h"
++#include "costlistitem.h"
++#include "configuration.h"
++#include "toplevel.h"
++
++FunctionSelection::FunctionSelection( TopLevel* top,
++ TQWidget* parent, const char* name)
++ : FunctionSelectionBase(parent, name), TraceItemView(0, top)
++{
++ _group = 0;
++ _inSetGroup = false;
++ _inSetFunction = false;
++
++ TQStringList args;
++ args << i18n("(No Grouping)")
++ << TraceCost::i18nTypeName(TraceItem::Object)
++ << TraceCost::i18nTypeName(TraceItem::File)
++ << TraceCost::i18nTypeName(TraceItem::Class)
++ << TraceCost::i18nTypeName(TraceItem::FunctionCycle);
++
++ groupBox->insertStringList(args);
++ // this needs same order of grouptype actionlist!
++ connect(groupBox, TQT_SIGNAL(activated(int)),
++ top, TQT_SLOT(groupTypeSelected(int)));
++
++ // search while typing...
++ connect(searchEdit, TQT_SIGNAL(textChanged(const TQString&)),
++ this, TQT_SLOT(searchChanged(const TQString&)));
++ connect(&_searchTimer, TQT_SIGNAL(timeout()),
++ this, TQT_SLOT(queryDelayed()));
++ // select first matching group/function on return
++ connect(searchEdit, TQT_SIGNAL(returnPressed()),
++ this, TQT_SLOT(searchReturnPressed()));
++ searchEdit->setMinimumWidth(50);
++
++ // we start with desending cost sorting
++ functionList->setSorting(0,false);
++ functionList->setColumnAlignment(0, TQt::AlignRight);
++ functionList->setColumnAlignment(1, TQt::AlignRight);
++ functionList->setColumnAlignment(2, TQt::AlignRight);
++ functionList->setAllColumnsShowFocus(true);
++ // functionList->setShowSortIndicator(true);
++ // we can have very long function and location names
++ functionList->setColumnWidthMode(3, TQListView::Manual);
++ functionList->setColumnWidth(3, 200);
++ functionList->setColumnWidthMode(4, TQListView::Manual);
++ functionList->setColumnWidth(4, 200);
++
++ groupList->setSorting(0,false);
++ groupList->setColumnAlignment(0, TQt::AlignRight);
++ groupList->setAllColumnsShowFocus(true);
++ // groupList->setShowSortIndicator(true);
++ groupList->setResizeMode(TQListView::LastColumn);
++
++#if 0
++ // single click press activation
++ connect(functionList, TQT_SIGNAL(selectionChanged(TQListViewItem*)),
++ this, TQT_SLOT(functionActivated(TQListViewItem*)));
++ connect(functionList,
++ TQT_SIGNAL(contextMenuRequested(TQListViewItem*, const TQPoint &, int)),
++ this, TQT_SLOT(functionContext(TQListViewItem*, const TQPoint &, int)));
++#else
++ // single click release activation
++ connect(functionList, TQT_SIGNAL(selectionChanged(TQListViewItem*)),
++ this, TQT_SLOT(functionSelected(TQListViewItem*)));
++ connect(functionList, TQT_SIGNAL(clicked(TQListViewItem*)),
++ this, TQT_SLOT(functionActivated(TQListViewItem*)));
++ connect(functionList, TQT_SIGNAL(returnPressed(TQListViewItem*)),
++ this, TQT_SLOT(functionActivated(TQListViewItem*)));
++ connect(functionList,
++ TQT_SIGNAL(contextMenuRequested(TQListViewItem*, const TQPoint &, int)),
++ this, TQT_SLOT(functionContext(TQListViewItem*, const TQPoint &, int)));
++#endif
++
++ connect(groupList, TQT_SIGNAL(selectionChanged(TQListViewItem*)),
++ this, TQT_SLOT(groupSelected(TQListViewItem*)));
++ connect(groupList, TQT_SIGNAL(doubleClicked(TQListViewItem*)),
++ this, TQT_SLOT(groupDoubleClicked(TQListViewItem*)));
++ connect(groupList, TQT_SIGNAL(returnPressed(TQListViewItem*)),
++ this, TQT_SLOT(groupDoubleClicked(TQListViewItem*)));
++ connect(groupList,
++ TQT_SIGNAL(contextMenuRequested(TQListViewItem*, const TQPoint &, int)),
++ this, TQT_SLOT(groupContext(TQListViewItem*, const TQPoint &, int)));
++
++ // start hidden
++ groupList->hide();
++}
++
++FunctionSelection::~FunctionSelection()
++{
++}
++
++void FunctionSelection::searchReturnPressed()
++{
++ query(searchEdit->text());
++
++ TQListViewItem* item;
++ if (_groupType != TraceItem::Function) {
++ // if current group not matching, select first matching group
++ item = groupList->currentItem();
++ if (!item || !item->isVisible()) {
++ item = groupList->firstChild();
++ for (;item;item = item->nextSibling())
++ if (item->isVisible()) break;
++ if (!item) return;
++
++ setGroup(((CostListItem*)item)->costItem());
++ return;
++ }
++ }
++
++ functionActivated(functionList->firstChild());
++}
++
++// trigger the query after some delay, dependent on length
++void FunctionSelection::searchChanged(const TQString& q)
++{
++ _searchDelayed = q;
++ int ms = 100;
++ if (q.length()<5) ms = 200;
++ if (q.length()<2) ms = 300;
++ _searchTimer.start(ms,true);
++}
++
++void FunctionSelection::queryDelayed()
++{
++ query(_searchDelayed);
++}
++
++void FunctionSelection::functionContext(TQListViewItem* i,
++ const TQPoint & p, int c)
++{
++ TQPopupMenu popup;
++ TraceFunction* f = 0;
++
++ if (i) {
++ f = ((FunctionItem*) i)->function();
++ if (f) {
++ popup.insertItem(i18n("Go to %1").arg(f->prettyName()), 93);
++ popup.insertSeparator();
++ }
++ }
++
++ if ((c == 0) || (c == 1)) {
++ addCostMenu(&popup,false);
++ popup.insertSeparator();
++ }
++ addGroupMenu(&popup);
++ popup.insertSeparator();
++ addGoMenu(&popup);
++
++ int r = popup.exec(p);
++ if (r == 93) activated(f);
++}
++
++void FunctionSelection::groupContext(TQListViewItem* /*i*/,
++ const TQPoint & p, int c)
++{
++ TQPopupMenu popup;
++
++#if 0
++ TraceCostItem* g = 0;
++ if (i) {
++ g = ((CostListItem*) i)->costItem();
++ if (!g) {
++ popup.insertItem(i18n("Show All Items"), 93);
++ popup.insertSeparator();
++ }
++ }
++#endif
++ if (c == 0) {
++ addCostMenu(&popup,false);
++ popup.insertSeparator();
++ }
++ addGroupMenu(&popup);
++ popup.insertSeparator();
++ addGoMenu(&popup);
++
++ popup.exec(p);
++}
++
++
++void FunctionSelection::addGroupMenu(TQPopupMenu* popup)
++{
++ TQPopupMenu *popup1 = new TQPopupMenu(popup);
++ popup1->setCheckable(true);
++
++ if (_groupType != TraceItem::Function) {
++ popup1->insertItem(i18n("No Grouping"),0);
++ popup1->insertSeparator();
++ }
++ popup1->insertItem(TraceCost::i18nTypeName(TraceItem::Object),1);
++ popup1->insertItem(TraceCost::i18nTypeName(TraceItem::File),2);
++ popup1->insertItem(TraceCost::i18nTypeName(TraceItem::Class),3);
++ popup1->insertItem(TraceCost::i18nTypeName(TraceItem::FunctionCycle),4);
++ switch(_groupType) {
++ case TraceItem::Object: popup1->setItemChecked(1, true); break;
++ case TraceItem::File: popup1->setItemChecked(2, true); break;
++ case TraceItem::Class: popup1->setItemChecked(3, true); break;
++ case TraceItem::FunctionCycle: popup1->setItemChecked(4, true); break;
++ default: break;
++ }
++ connect(popup1,TQT_SIGNAL(activated(int)),
++ _topLevel,TQT_SLOT(groupTypeSelected(int)));
++
++ popup->insertItem(i18n("Grouping"), popup1);
++}
++
++
++TraceItem* FunctionSelection::canShow(TraceItem* i)
++{
++ TraceItem::CostType t = i ? i->type() : TraceItem::NoCostType;
++
++ switch(t) {
++ case TraceItem::Function:
++ case TraceItem::FunctionCycle:
++ case TraceItem::Object:
++ case TraceItem::File:
++ case TraceItem::Class:
++ break;
++
++ case TraceItem::Instr:
++ i = ((TraceInstr*)i)->function();
++ break;
++
++ case TraceItem::Line:
++ i = ((TraceLine*)i)->functionSource()->function();
++ break;
++
++ default:
++ i = 0;
++ break;
++ }
++ return i;
++}
++
++
++void FunctionSelection::doUpdate(int changeType)
++{
++ // Special case ?
++ if (changeType == selectedItemChanged) return;
++
++ // we don't show cost 2 at all...
++ if (changeType == costType2Changed) return;
++
++ if (changeType == activeItemChanged) {
++ if (_activeItem ==0) {
++ functionList->clearSelection();
++ return;
++ }
++ switch(_activeItem->type()) {
++ case TraceItem::Object:
++ case TraceItem::File:
++ case TraceItem::Class:
++ setGroup((TraceCostItem*)_activeItem);
++ return;
++ default: break;
++ }
++
++ // active item is a function
++ TraceFunction* f = (TraceFunction*) _activeItem;
++
++ // if already current, nothing to do
++ TQListViewItem* i = functionList->currentItem();
++ if (i && (((FunctionItem*)i)->function() == f)) {
++ functionList->setSelected(i,true);
++ return;
++ }
++
++ // reset searchEdit (as not activated from this view)
++ _searchString = TQString();
++ query(TQString());
++
++ // select cost item group of function
++ switch(_groupType) {
++ case TraceItem::Object: setGroup(f->object()); break;
++ case TraceItem::Class: setGroup(f->cls()); break;
++ case TraceItem::File: setGroup(f->file()); break;
++ case TraceItem::FunctionCycle: setGroup(f->cycle()); break;
++ default:
++ break;
++ }
++
++ TQListViewItem* item = functionList->firstChild();
++ for (;item;item = item->nextSibling())
++ if (((FunctionItem*)item)->function() == f)
++ break;
++
++ if (!item)
++ item = new FunctionItem(functionList, f, _costType, _groupType);
++
++ functionList->ensureItemVisible(item);
++ // prohibit signalling of a function selection
++ _inSetFunction = true;
++ functionList->setSelected(item, true);
++ _inSetFunction = false;
++
++ return;
++ }
++
++ if (changeType & groupTypeChanged) {
++ if (_activeItem && (_activeItem->type() == TraceItem::Function)) {
++ TraceFunction* f = (TraceFunction*) _activeItem;
++
++ // select cost item group of function
++ switch(_groupType) {
++ case TraceItem::Object: _group = f->object(); break;
++ case TraceItem::Class: _group = f->cls(); break;
++ case TraceItem::File: _group = f->file(); break;
++ case TraceItem::FunctionCycle: _group = f->cycle(); break;
++ default:
++ _group = 0;
++ break;
++ }
++ }
++
++ int id;
++ switch(_groupType) {
++ case TraceItem::Object: id = 1; break;
++ case TraceItem::File: id = 2; break;
++ case TraceItem::Class: id = 3; break;
++ case TraceItem::FunctionCycle: id = 4; break;
++ default: id = 0; break;
++ }
++ groupBox->setCurrentItem(id);
++
++ if (_groupType == TraceItem::Function)
++ groupList->hide();
++ else
++ groupList->show();
++ }
++
++ // reset searchEdit
++ _searchString = TQString();
++ query(TQString());
++
++ refresh();
++}
++
++
++/*
++ * This set/selects a group of the set available within the
++ * current group type
++ */
++void FunctionSelection::setGroup(TraceCostItem* g)
++{
++ if (!g) return;
++ if (g->type() != _groupType) return;
++ if (g == _group) return;
++ _group = g;
++
++ TQListViewItem* item = groupList->firstChild();
++ for (;item;item = item->nextSibling())
++ if (((CostListItem*)item)->costItem() == g)
++ break;
++
++ if (item) {
++ groupList->ensureItemVisible(item);
++ // prohibit signalling of a group selection
++ _inSetGroup = true;
++ groupList->setSelected(item, true);
++ _inSetGroup = false;
++ }
++ else
++ groupList->clearSelection();
++}
++
++
++void FunctionSelection::refresh()
++{
++ groupList->setUpdatesEnabled(false);
++ groupList->clear();
++
++ // make cost columns as small as possible:
++ // the new functions make them as wide as needed
++ groupList->setColumnWidth(0, 50);
++
++ groupList->setColumnText(1, TraceItem::i18nTypeName(_groupType));
++
++ if (!_data || _data->parts().count()==0) {
++ functionList->clear();
++ groupList->setUpdatesEnabled(true);
++ groupList->repaint();
++
++ // this clears all other lists
++ functionList->setSelected(functionList->firstChild(), true);
++ return;
++ }
++
++ /*
++ qDebug("FunctionSelection::fillLists (%s)",
++ _data->command().ascii());
++ */
++
++ TraceObjectMap::Iterator oit;
++ TraceClassMap::Iterator cit;
++ TraceFileMap::Iterator fit;
++ TQListViewItem *i = 0, *item = 0, *fitem = 0;
++
++ // Fill up group list.
++ // Always show group of current function, even if cost below low limit.
++ //
++
++ _hc.clear(Configuration::maxListCount());
++
++ TraceCostItem *group;
++
++ // update group from _activeItem if possible
++ if (_activeItem && (_activeItem->type() == _groupType))
++ _group = (TraceCostItem*) _activeItem;
++
++ switch(_groupType) {
++ case TraceItem::Object:
++
++ for ( oit = _data->objectMap().begin();
++ oit != _data->objectMap().end(); ++oit )
++ _hc.addCost(&(*oit), (*oit).subCost(_costType));
++ break;
++
++ case TraceItem::Class:
++
++ for ( cit = _data->classMap().begin();
++ cit != _data->classMap().end(); ++cit )
++ _hc.addCost(&(*cit), (*cit).subCost(_costType));
++ break;
++
++ case TraceItem::File:
++
++ for ( fit = _data->fileMap().begin();
++ fit != _data->fileMap().end(); ++fit )
++ _hc.addCost(&(*fit), (*fit).subCost(_costType));
++ break;
++
++ case TraceItem::FunctionCycle:
++ {
++ // add all cycles
++ TraceFunctionCycleList l = _data->functionCycles();
++ for (group=l.first();group;group=l.next())
++ _hc.addCost(group, group->subCost(_costType));
++ }
++
++ break;
++
++ default:
++ {
++ TQListViewItem* oldItem = functionList->selectedItem();
++ TraceFunction* oldFunction = 0;
++ int oldPos = 0;
++ if (oldItem) {
++ oldFunction = ((FunctionItem*)oldItem)->function();
++ oldPos = oldItem->itemPos();
++ oldPos -= functionList->contentsY();
++ if (oldPos < 0 || oldPos > functionList->height())
++ oldFunction = 0;
++ }
++
++ // switching off TQListView updates is buggy with some QT versions...
++ //functionList->setUpdatesEnabled(false);
++ functionList->clear();
++ setCostColumnWidths();
++
++ if (0) qDebug("Function %s at %d, Item %p",
++ oldFunction ? oldFunction->name().ascii() : "-",
++ oldPos, (void*)oldItem);
++
++ TraceFunctionMap::Iterator it;
++ TraceFunction *f;
++ i = 0;
++ fitem = 0;
++ for ( it = _data->functionMap().begin();
++ it != _data->functionMap().end(); ++it )
++ _hc.addCost(&(*it), (*it).inclusive()->subCost(_costType));
++
++ TraceFunctionCycleList l = _data->functionCycles();
++ for (f=l.first();f;f=l.next())
++ _hc.addCost(f, f->inclusive()->subCost(_costType));
++
++ if (_activeItem &&
++ ((_activeItem->type() == TraceItem::Function) ||
++ (_activeItem->type() == TraceItem::FunctionCycle)))
++ fitem = new FunctionItem(functionList, (TraceFunction*)_activeItem,
++ _costType, _groupType);
++
++ for(int i=0;i<_hc.realCount();i++) {
++ f = (TraceFunction*)_hc[i];
++ if (f == _activeItem) continue;
++ new FunctionItem(functionList, f, _costType, _groupType);
++ }
++ if (_hc.hasMore()) {
++ // a placeholder for all the cost items skipped ...
++ new FunctionItem(functionList, _hc.count() - _hc.maxSize(),
++ (TraceFunction*)_hc[_hc.maxSize()-1], _costType);
++ }
++ functionList->sort();
++
++ if (fitem && oldFunction) {
++ _inSetFunction = true;
++ functionList->setSelected(fitem, true);
++ _inSetFunction = false;
++ int newPos = functionList->itemPos(fitem) - functionList->contentsY();
++ functionList->scrollBy(0, newPos-oldPos);
++ }
++ else if (fitem) {
++ functionList->ensureItemVisible(fitem);
++ _inSetFunction = true;
++ functionList->setSelected(fitem, true);
++ _inSetFunction = false;
++ }
++ else
++ functionList->clearSelection();
++
++ //functionList->setUpdatesEnabled(true);
++ //functionList->repaint();
++ groupList->setUpdatesEnabled(true);
++ groupList->repaint();
++ return;
++ }
++ }
++
++ // we always put group of active item in list, even if
++ // it would be skipped because of small costs
++ if (_group)
++ item = new CostListItem(groupList, _group, _costType);
++
++ for(int i=0;i<_hc.realCount();i++) {
++ group = (TraceCostItem*)_hc[i];
++ // don't put group of active item twice into list
++ if (group == _group) continue;
++ new CostListItem(groupList, group, _costType);
++ }
++ if (_hc.hasMore()) {
++ // a placeholder for all the cost items skipped ...
++ new CostListItem(groupList, _hc.count() - _hc.maxSize(),
++ (TraceCostItem*)_hc[_hc.maxSize()-1], _costType);
++ }
++ groupList->sort();
++ if (item) {
++ groupList->ensureItemVisible(item);
++ _inSetGroup = true;
++ groupList->setSelected(item, true);
++ _inSetGroup = false;
++ }
++ else
++ groupList->clearSelection();
++
++ groupList->setUpdatesEnabled(true);
++ groupList->repaint();
++}
++
++
++void FunctionSelection::groupSelected(TQListViewItem* i)
++{
++ if (!i) return;
++ if (!_data) return;
++
++ TraceCostItem* g = ((CostListItem*) i)->costItem();
++ if (!g) return;
++
++ _group = g;
++
++ TraceFunctionList list;
++
++ switch(g->type()) {
++ case TraceItem::Object:
++ list = ((TraceObject*)g)->functions();
++ break;
++ case TraceItem::Class:
++ list = ((TraceClass*)g)->functions();
++ break;
++ case TraceItem::File:
++ list = ((TraceFile*)g)->functions();
++ break;
++ case TraceItem::FunctionCycle:
++ list = ((TraceFunctionCycle*)g)->members();
++ break;
++ default:
++ return;
++ }
++
++ // switching off TQListView updates is buggy with some QT versions...
++ //functionList->setUpdatesEnabled(false);
++
++ functionList->clear();
++ setCostColumnWidths();
++
++ double total;
++ if (Configuration::showExpanded())
++ total = (double) g->subCost(_costType);
++ else
++ total = (double) _data->subCost(_costType);
++#if 0
++ if (total == 0.0) {
++ functionList->setUpdatesEnabled(true);
++ functionList->repaint();
++ return;
++ }
++#endif
++
++ TQRegExp re(_searchString, false, true);
++
++ FunctionItem* fitem = 0;
++ TraceFunction *f;
++ _hc.clear(Configuration::maxListCount());
++ for (f=list.first();f;f=list.next()) {
++ if (re.search(f->prettyName())<0) continue;
++
++ _hc.addCost(f, f->inclusive()->subCost(_costType));
++ if (_activeItem == f)
++ fitem = new FunctionItem(functionList, (TraceFunction*)_activeItem,
++ _costType, _groupType);
++ }
++
++ for(int i=0;i<_hc.realCount();i++) {
++ if (_activeItem == (TraceFunction*)_hc[i]) continue;
++ new FunctionItem(functionList, (TraceFunction*)_hc[i],
++ _costType, _groupType);
++ }
++
++ if (_hc.hasMore()) {
++ // a placeholder for all the functions skipped ...
++ new FunctionItem(functionList, _hc.count() - _hc.maxSize(),
++ (TraceFunction*)_hc[_hc.maxSize()-1], _costType);
++ }
++ functionList->sort();
++
++ if (fitem) {
++ functionList->ensureItemVisible(fitem);
++ _inSetFunction = true;
++ functionList->setSelected(fitem, true);
++ _inSetFunction = false;
++ }
++
++ //functionList->setUpdatesEnabled(true);
++ //functionList->repaint();
++
++ // Don't emit signal if cost item was changed programatically
++ if (!_inSetGroup) {
++ _selectedItem = g;
++ selected(g);
++ }
++}
++
++void FunctionSelection::groupDoubleClicked(TQListViewItem* i)
++{
++ if (!i) return;
++ if (!_data) return;
++ TraceCostItem* g = ((CostListItem*) i)->costItem();
++
++ if (!g) return;
++ // group must be selected first
++ if (g != _group) return;
++
++ activated(g);
++}
++
++
++TraceCostItem* FunctionSelection::group(TQString s)
++{
++ TQListViewItem *item;
++ item = groupList->firstChild();
++ for(;item;item = item->nextSibling())
++ if (((CostListItem*)item)->costItem()->name() == s)
++ return ((CostListItem*)item)->costItem();
++
++ return 0;
++}
++
++
++
++void FunctionSelection::functionSelected(TQListViewItem* i)
++{
++ if (!i) return;
++ if (!_data) return;
++
++ TraceFunction* f = ((FunctionItem*) i)->function();
++ if (!f) return;
++
++ //qDebug("FunctionSelection::functionSelected %s", f->name().ascii());
++
++ // Don't emit signal if function was changed programatically
++ if (!_inSetFunction) {
++ _selectedItem = f;
++ selected(f);
++ }
++}
++
++void FunctionSelection::functionActivated(TQListViewItem* i)
++{
++ if (!i) return;
++ if (!_data) return;
++ TraceFunction* f = ((FunctionItem*) i)->function();
++
++ if (!f) return;
++
++ if (!_inSetFunction)
++ activated(f);
++}
++
++void FunctionSelection::updateGroupSizes(bool hideEmpty)
++{
++ TQListViewItem* item = groupList->firstChild();
++ for (;item;item = item->nextSibling()) {
++ CostListItem* i = (CostListItem*)item;
++ int size = (_groupSize.contains(i->costItem())) ?
++ _groupSize[i->costItem()] : -1;
++ i->setSize(size);
++ i->setVisible(!hideEmpty || (size>0));
++ }
++}
++
++void FunctionSelection::query(TQString query)
++{
++ if (searchEdit->text() != query)
++ searchEdit->setText(query);
++ if (_searchString == query) {
++ // when resetting query, get rid of group sizes
++ if (query.isEmpty()) {
++ _groupSize.clear();
++ updateGroupSizes(false);
++ }
++ return;
++ }
++ _searchString = query;
++
++ TQRegExp re(query, false, true);
++ _groupSize.clear();
++
++ TraceFunction* f = 0;
++ TraceFunctionList list2;
++
++ _hc.clear(Configuration::maxListCount());
++
++ TraceFunctionMap::Iterator it;
++ for ( it = _data->functionMap().begin();
++ it != _data->functionMap().end(); ++it ) {
++ f = &(*it);
++ if (re.search(f->prettyName())>=0) {
++ if (_group) {
++ if (_groupType==TraceItem::Object) {
++ if (_groupSize.contains(f->object()))
++ _groupSize[f->object()]++;
++ else
++ _groupSize[f->object()] = 1;
++ if (f->object() != _group) continue;
++ }
++ else if (_groupType==TraceItem::Class) {
++ if (_groupSize.contains(f->cls()))
++ _groupSize[f->cls()]++;
++ else
++ _groupSize[f->cls()] = 1;
++ if (f->cls() != _group) continue;
++ }
++ else if (_groupType==TraceItem::File) {
++ if (_groupSize.contains(f->file()))
++ _groupSize[f->file()]++;
++ else
++ _groupSize[f->file()] = 1;
++ if (f->file() != _group) continue;
++ }
++ else if (_groupType==TraceItem::FunctionCycle) {
++ if (_groupSize.contains(f->cycle()))
++ _groupSize[f->cycle()]++;
++ else
++ _groupSize[f->cycle()] = 1;
++ if (f->cycle() != _group) continue;
++ }
++ }
++ _hc.addCost(f, f->inclusive()->subCost(_costType));
++ }
++ }
++
++ updateGroupSizes(true);
++
++ FunctionItem *fi, *item = 0;
++
++ functionList->clear();
++ setCostColumnWidths();
++
++ for(int i=0;i<_hc.realCount();i++) {
++ fi = new FunctionItem(functionList, (TraceFunction*)_hc[i],
++ _costType, _groupType);
++ if (_activeItem == f) item = fi;
++ }
++ if (_hc.hasMore()) {
++ // a placeholder for all the functions skipped ...
++ new FunctionItem(functionList, _hc.count() - _hc.maxSize(),
++ (TraceFunction*)_hc[_hc.maxSize()-1], _costType);
++ }
++
++ functionList->sort();
++
++
++ if (item) {
++ functionList->ensureItemVisible(item);
++ _inSetFunction = true;
++ functionList->setSelected(item, true);
++ _inSetFunction = false;
++ }
++ else {
++ // this emits a function selection
++ functionList->setSelected(functionList->firstChild(), true);
++ }
++}
++
++bool FunctionSelection::setTopFunction()
++{
++ TQListViewItem* i = functionList->firstChild();
++ // this emits a function selection
++ functionList->setSelected(i, true);
++ functionActivated(i);
++ return i!=0;
++}
++
++void FunctionSelection::setCostColumnWidths()
++{
++ if (_costType && (_costType->subCost(_data->callMax())>0) ) {
++ functionList->setColumnWidthMode(0, TQListView::Maximum);
++ functionList->setColumnWidth(0,50);
++ functionList->setColumnWidthMode(2, TQListView::Maximum);
++ functionList->setColumnWidth(2,50);
++ }
++ else {
++ functionList->setColumnWidthMode(0, TQListView::Manual);
++ functionList->setColumnWidth(0,0);
++ functionList->setColumnWidthMode(2, TQListView::Manual);
++ functionList->setColumnWidth(2,0);
++ }
++
++ functionList->setColumnWidth(1, 50);
++}
++
++
++
++#include "functionselection.moc"
+diff --git a/kdecachegrind/kdecachegrind/functionselection.h b/kdecachegrind/kdecachegrind/functionselection.h
+new file mode 100644
+index 0000000..c5f7810
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/functionselection.h
+@@ -0,0 +1,86 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * For function selection, to be put into a TQDockWindow
++ */
++
++#ifndef FUNCTIONSELECTION_H
++#define FUNCTIONSELECTION_H
++
++#include "functionselectionbase.h"
++#include "traceitemview.h"
++#include "tracedata.h"
++#include "listutils.h"
++
++class TQPopupMenu;
++
++class TraceFunction;
++class TraceData;
++class StackBrowser;
++class NestedAreaItem;
++
++class FunctionSelection : public FunctionSelectionBase, public TraceItemView
++{
++ Q_OBJECT
++ TQ_OBJECT
++
++public:
++ FunctionSelection( TopLevel*, TQWidget* parent = 0, const char* name = 0);
++ ~FunctionSelection();
++
++ TraceCostItem* group(TQString);
++ void setGroup(TraceCostItem*);
++ void query(TQString);
++ bool setTopFunction();
++
++ TQWidget* widget() { return this; }
++
++ void addGroupMenu(TQPopupMenu*);
++
++public slots:
++ void searchReturnPressed();
++ void searchChanged(const TQString&);
++ void queryDelayed();
++ void groupDoubleClicked( TQListViewItem* );
++ void functionActivated( TQListViewItem* );
++ void groupSelected( TQListViewItem* );
++ void functionSelected( TQListViewItem* );
++ void functionContext(TQListViewItem*, const TQPoint &, int);
++ void groupContext(TQListViewItem*, const TQPoint &, int);
++
++private:
++ TraceItem* canShow(TraceItem* i);
++ void doUpdate(int);
++ void selectFunction();
++ void refresh();
++ void setCostColumnWidths();
++ void updateGroupSizes(bool hideEmpty);
++
++ TraceCostItem* _group;
++
++ TQString _searchString, _searchDelayed;
++ TQTimer _searchTimer;
++ TQMap<TraceCostItem*,int> _groupSize;
++
++ HighestCostList _hc;
++ // when setting a
++ bool _inSetGroup, _inSetFunction;
++};
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/functionselectionbase.ui b/kdecachegrind/kdecachegrind/functionselectionbase.ui
+new file mode 100644
+index 0000000..eec019d
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/functionselectionbase.ui
+@@ -0,0 +1,163 @@
++<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
++<class>FunctionSelectionBase</class>
++<widget class="TQWidget">
++ <property name="name">
++ <cstring>FunctionSelectionBase</cstring>
++ </property>
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>223</width>
++ <height>485</height>
++ </rect>
++ </property>
++ <property name="caption">
++ <string>Function Profile</string>
++ </property>
++ <vbox>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <property name="margin">
++ <number>3</number>
++ </property>
++ <property name="spacing">
++ <number>6</number>
++ </property>
++ <widget class="TQLayoutWidget">
++ <property name="name">
++ <cstring>layout1</cstring>
++ </property>
++ <hbox>
++ <property name="name">
++ <cstring>unnamed</cstring>
++ </property>
++ <widget class="TQLabel">
++ <property name="name">
++ <cstring>searchLabel</cstring>
++ </property>
++ <property name="text">
++ <string>&amp;Search:</string>
++ </property>
++ <property name="buddy" stdset="0">
++ <cstring>searchEdit</cstring>
++ </property>
++ </widget>
++ <widget class="TQLineEdit">
++ <property name="name">
++ <cstring>searchEdit</cstring>
++ </property>
++ </widget>
++ <widget class="TQComboBox">
++ <property name="name">
++ <cstring>groupBox</cstring>
++ </property>
++ </widget>
++ </hbox>
++ </widget>
++ <widget class="TQListView">
++ <column>
++ <property name="text">
++ <string>Self</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <column>
++ <property name="text">
++ <string>Group</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <property name="name">
++ <cstring>groupList</cstring>
++ </property>
++ <property name="sizePolicy">
++ <sizepolicy>
++ <hsizetype>7</hsizetype>
++ <vsizetype>5</vsizetype>
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="maximumSize">
++ <size>
++ <width>32767</width>
++ <height>150</height>
++ </size>
++ </property>
++ </widget>
++ <widget class="TQListView">
++ <column>
++ <property name="text">
++ <string>Incl.</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <column>
++ <property name="text">
++ <string>Self</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <column>
++ <property name="text">
++ <string>Called</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <column>
++ <property name="text">
++ <string>Function</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <column>
++ <property name="text">
++ <string>Location</string>
++ </property>
++ <property name="clickable">
++ <bool>true</bool>
++ </property>
++ <property name="resizable">
++ <bool>true</bool>
++ </property>
++ </column>
++ <property name="name">
++ <cstring>functionList</cstring>
++ </property>
++ </widget>
++ </vbox>
++</widget>
++<layoutdefaults spacing="6" margin="11"/>
++</UI>
+diff --git a/kdecachegrind/kdecachegrind/hi32-app-kcachegrind.png b/kdecachegrind/kdecachegrind/hi32-app-kcachegrind.png
+new file mode 100644
+index 0000000..bd41dae
+Binary files /dev/null and b/kdecachegrind/kdecachegrind/hi32-app-kcachegrind.png differ
+diff --git a/kdecachegrind/kdecachegrind/hi48-app-kcachegrind.png b/kdecachegrind/kdecachegrind/hi48-app-kcachegrind.png
+new file mode 100644
+index 0000000..58c2efd
+Binary files /dev/null and b/kdecachegrind/kdecachegrind/hi48-app-kcachegrind.png differ
+diff --git a/kdecachegrind/kdecachegrind/instritem.cpp b/kdecachegrind/kdecachegrind/instritem.cpp
+new file mode 100644
+index 0000000..ce5e81b
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/instritem.cpp
+@@ -0,0 +1,469 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Items of instruction view.
++ */
++
++#include <tqpixmap.h>
++#include <tqpainter.h>
++
++#include <klocale.h>
++#include <kapplication.h>
++#include <kiconloader.h>
++#include <kdebug.h>
++
++#include "configuration.h"
++#include "listutils.h"
++#include "instritem.h"
++#include "instrview.h"
++
++
++// InstrItem
++
++// for messages
++InstrItem::InstrItem(InstrView* iv, TQListView* parent,
++ Addr addr, const TQString& msg)
++ : TQListViewItem(parent)
++{
++ _view = iv;
++ _addr = addr;
++ _instr = 0;
++ _instrCall = 0;
++ _instrJump = 0;
++ _inside = false;
++
++ setText(0, addr.pretty());
++ setText(6, msg);
++
++ updateGroup();
++ updateCost();
++}
++
++// for code lines
++InstrItem::InstrItem(InstrView* iv, TQListView* parent,
++ Addr addr, bool inside,
++ const TQString& code, const TQString& cmd,
++ const TQString& args, TraceInstr* instr)
++ : TQListViewItem(parent)
++{
++ _view = iv;
++ _addr = addr;
++ _instr = instr;
++ _instrCall = 0;
++ _instrJump = 0;
++ _inside = inside;
++
++ if (args == "...")
++ setText(0, args);
++ else
++ setText(0, addr.pretty());
++ setText(4, code);
++ setText(5, cmd);
++ setText(6, args);
++
++ TraceLine* l;
++ if (instr && (l = instr->line()))
++ setText(7, l->name());
++
++ updateGroup();
++ updateCost();
++}
++
++// for call lines
++InstrItem::InstrItem(InstrView* iv, TQListViewItem* parent, Addr addr,
++ TraceInstr* instr, TraceInstrCall* instrCall)
++ : TQListViewItem(parent)
++{
++ _view = iv;
++ _addr = addr;
++ _instr = instr;
++ _instrCall = instrCall;
++ _instrJump = 0;
++ _inside = true;
++
++ //qDebug("InstrItem: (file %d, line %d) Linecall to %s",
++ // fileno, lineno, _lineCall->call()->called()->prettyName().ascii());
++
++ SubCost cc = _instrCall->callCount();
++ TQString templ = " ";
++ if (cc==0)
++ templ += i18n("Active call to '%1'");
++ else
++ templ += i18n("%n call to '%1'", "%n calls to '%1'", cc);
++
++ TQString callStr = templ.arg(_instrCall->call()->calledName());
++ TraceFunction* calledF = _instrCall->call()->called();
++ calledF->addPrettyLocation(callStr);
++
++ setText(6, callStr);
++
++ updateGroup();
++ updateCost();
++}
++
++// for jump lines
++InstrItem::InstrItem(InstrView* iv, TQListViewItem* parent, Addr addr,
++ TraceInstr* instr, TraceInstrJump* instrJump)
++ : TQListViewItem(parent)
++{
++ _view = iv;
++ _addr = addr;
++ _inside = true;
++ _instr = instr;
++ _instrCall = 0;
++ _instrJump = instrJump;
++
++ //qDebug("SourceItem: (file %d, line %d) Linecall to %s",
++ // fileno, lineno, _lineCall->call()->called()->prettyName().ascii());
++
++ TQString jStr;
++ if (_instrJump->isCondJump())
++ jStr = i18n("Jump %1 of %2 times to 0x%3")
++ .arg(_instrJump->followedCount().pretty())
++ .arg(_instrJump->executedCount().pretty())
++ .arg(_instrJump->instrTo()->addr().toString());
++ else
++ jStr = i18n("Jump %1 times to 0x%2")
++ .arg(_instrJump->executedCount().pretty())
++ .arg(_instrJump->instrTo()->addr().toString());
++
++ setText(6, jStr);
++
++ updateGroup();
++ updateCost();
++}
++
++
++void InstrItem::updateGroup()
++{
++ if (!_instrCall) return;
++
++ TraceFunction* f = _instrCall->call()->called();
++ TQColor c = Configuration::functionColor(_view->groupType(), f);
++ setPixmap(6, colorPixmap(10, 10, c));
++}
++
++void InstrItem::updateCost()
++{
++ _pure = SubCost(0);
++ _pure2 = SubCost(0);
++
++ if (!_instr) return;
++ if (_instrJump) return;
++
++ TraceCost* instrCost = _instrCall ?
++ (TraceCost*)_instrCall : (TraceCost*)_instr;
++
++ // don't show any cost inside of cycles
++ if (_instrCall &&
++ ((_instrCall->call()->inCycle()>0) ||
++ (_instrCall->call()->isRecursion()>0))) {
++ TQString str;
++ TQPixmap p;
++
++ TQString icon = "undo";
++ KIconLoader* loader = KApplication::kApplication()->iconLoader();
++ p= loader->loadIcon(icon, KIcon::Small, 0,
++ KIcon::DefaultState, 0, true);
++ if (p.isNull())
++ str = i18n("(cycle)");
++
++ setText(1, str);
++ setPixmap(1, p);
++ setText(2, str);
++ setPixmap(2, p);
++ return;
++ }
++
++ TraceCost* totalCost;
++ if (Configuration::showExpanded())
++ totalCost = _instr->function()->inclusive();
++ else
++ totalCost = _instr->function()->data();
++
++ TraceCostType *ct = _view->costType();
++ _pure = ct ? instrCost->subCost(ct) : SubCost(0);
++ if (_pure == 0) {
++ setText(1, TQString());
++ setPixmap(1, TQPixmap());
++ }
++ else {
++ double total = totalCost->subCost(ct);
++ double pure = 100.0 * _pure / total;
++
++ if (Configuration::showPercentage())
++ setText(1, TQString("%1")
++ .arg(pure, 0, 'f', Configuration::percentPrecision()));
++ else
++ setText(1, _pure.pretty());
++
++ setPixmap(1, costPixmap(ct, instrCost, total, false));
++ }
++
++ TraceCostType *ct2 = _view->costType2();
++ _pure2 = ct2 ? instrCost->subCost(ct2) : SubCost(0);
++ if (_pure2 == 0) {
++ setText(2, TQString());
++ setPixmap(2, TQPixmap());
++ }
++ else {
++ double total = totalCost->subCost(ct2);
++ double pure = 100.0 * _pure2 / total;
++
++ if (Configuration::showPercentage())
++ setText(2, TQString("%1")
++ .arg(pure, 0, 'f', Configuration::percentPrecision()));
++ else
++ setText(2, _pure2.pretty());
++
++ setPixmap(2, costPixmap(ct2, instrCost, total, false));
++ }
++}
++
++
++int InstrItem::compare(TQListViewItem * i, int col, bool ascending ) const
++{
++ const InstrItem* ii1 = this;
++ const InstrItem* ii2 = (InstrItem*) i;
++
++ // we always want descending order
++ if (((col>0) && ascending) ||
++ ((col==0) && !ascending) ) {
++ ii1 = ii2;
++ ii2 = this;
++ }
++
++ if (col==1) {
++ if (ii1->_pure < ii2->_pure) return -1;
++ if (ii1->_pure > ii2->_pure) return 1;
++ return 0;
++ }
++ if (col==2) {
++ if (ii1->_pure2 < ii2->_pure2) return -1;
++ if (ii1->_pure2 > ii2->_pure2) return 1;
++ return 0;
++ }
++ if (col==0) {
++ if (ii1->_addr < ii2->_addr) return -1;
++ if (ii1->_addr > ii2->_addr) return 1;
++
++ // Same address: code gets above calls/jumps
++ if (!ii1->_instrCall && !ii1->_instrJump) return -1;
++ if (!ii2->_instrCall && !ii2->_instrJump) return 1;
++
++ // calls above jumps
++ if (ii1->_instrCall && !ii2->_instrCall) return -1;
++ if (ii2->_instrCall && !ii1->_instrCall) return 1;
++
++ if (ii1->_instrCall && ii2->_instrCall) {
++ // Two calls: desending sort according costs
++ if (ii1->_pure < ii2->_pure) return 1;
++ if (ii1->_pure > ii2->_pure) return -1;
++
++ // Two calls: sort according function names
++ TraceFunction* f1 = ii1->_instrCall->call()->called();
++ TraceFunction* f2 = ii2->_instrCall->call()->called();
++ if (f1->prettyName() > f2->prettyName()) return 1;
++ return -1;
++ }
++
++ // Two jumps: descending sort according target address
++ if (ii1->_instrJump->instrTo()->addr() <
++ ii2->_instrJump->instrTo()->addr())
++ return -1;
++ if (ii1->_instrJump->instrTo()->addr() >
++ ii2->_instrJump->instrTo()->addr())
++ return 1;
++ return 0;
++
++ }
++ return TQListViewItem::compare(i, col, ascending);
++}
++
++void InstrItem::paintCell( TQPainter *p, const TQColorGroup &cg,
++ int column, int width, int alignment )
++{
++ TQColorGroup _cg( cg );
++
++ if ( !_inside || ((column==1) || column==2))
++ _cg.setColor( TQColorGroup::Base, cg.button() );
++ else if ((_instrCall || _instrJump) && column>2)
++ _cg.setColor( TQColorGroup::Base, cg.midlight() );
++
++ if (column == 3)
++ paintArrows(p, _cg, width);
++ else
++ TQListViewItem::paintCell( p, _cg, column, width, alignment );
++}
++
++void InstrItem::setJumpArray(const TQMemArray<TraceInstrJump*>& a)
++{
++ _jump.duplicate(a);
++}
++
++void InstrItem::paintArrows(TQPainter *p, const TQColorGroup &cg, int width)
++{
++ TQListView *lv = listView();
++ if ( !lv ) return;
++ InstrView* iv = (InstrView*) lv;
++
++ const BackgroundMode bgmode = lv->viewport()->backgroundMode();
++ const TQColorGroup::ColorRole crole
++ = TQPalette::backgroundRoleFromMode( bgmode );
++ if ( cg.brush( crole ) != lv->colorGroup().brush( crole ) )
++ p->fillRect( 0, 0, width, height(), cg.brush( crole ) );
++ else
++ iv->paintEmptyArea( p, TQRect( 0, 0, width, height() ) );
++
++ if ( isSelected() && lv->allColumnsShowFocus() )
++ p->fillRect( 0, 0, width, height(), cg.brush( TQColorGroup::Highlight ) );
++
++ int marg = lv->itemMargin();
++ int yy = height()/2, y1, y2;
++ TQColor c;
++
++ int start = -1, end = -1;
++
++ // draw line borders, detect start/stop of a line
++ for(int i=0;i< (int)_jump.size();i++) {
++ if (_jump[i] == 0) continue;
++
++ y1 = 0;
++ y2 = height();
++ if ((_instrJump == _jump[i]) &&
++ (_jump[i]->instrFrom()->addr() == _addr)) {
++
++ //kdDebug() << "InstrItem " << _addr.toString() << ": start " << i << endl;
++ if (start<0) start = i;
++ if (_jump[i]->instrTo()->addr() <= _addr)
++ y2 = yy;
++ else
++ y1 = yy;
++ }
++ else if (!_instrJump && !_instrCall &&
++ (_jump[i]->instrTo()->addr() == _addr)) {
++
++ //kdDebug() << "InstrItem " << _addr.toString() << ": end " << i << endl;
++ if (end<0) end = i;
++ if (_jump[i]->instrFrom()->addr() < _addr)
++ y2 = yy;
++ else
++ y1 = yy;
++ }
++
++ c = _jump[i]->isCondJump() ? red : blue;
++#if 0
++ if (_jump[i] == ((TraceItemView*)_view)->selectedItem()) {
++ p->fillRect( marg + 6*i-2, (y1==0) ? y1: y1-2,
++ 8, (y2-y1==height())? y2:y2+2,
++ cg.brush( TQColorGroup::Highlight ) );
++ c = lv->colorGroup().highlightedText();
++ }
++#endif
++ p->fillRect( marg + 6*i, y1, 4, y2, c);
++ p->setPen(c.light());
++ p->drawLine( marg + 6*i, y1, marg + 6*i, y2);
++ p->setPen(c.dark());
++ p->drawLine( marg + 6*i +3, y1, marg + 6*i +3, y2);
++ }
++
++ // draw start/stop horizontal line
++ int x, y = yy-2, w, h = 4;
++ if (start >= 0) {
++#if 0
++ if (_jump[start] == ((TraceItemView*)_view)->selectedItem()) {
++ c = lv->colorGroup().highlightedText();
++ }
++#endif
++ c = _jump[start]->isCondJump() ? red : blue;
++ x = marg + 6*start;
++ w = 6*(iv->arrowLevels() - start) + 10;
++ p->fillRect( x, y, w, h, c);
++ p->setPen(c.light());
++ p->drawLine(x, y, x+w-1, y);
++ p->drawLine(x, y, x, y+h-1);
++ p->setPen(c.dark());
++ p->drawLine(x+w-1, y, x+w-1, y+h-1);
++ p->drawLine(x+1, y+h-1, x+w-1, y+h-1);
++ }
++ if (end >= 0) {
++ c = _jump[end]->isCondJump() ? red : blue;
++ x = marg + 6*end;
++ w = 6*(iv->arrowLevels() - end) + 10;
++
++ TQPointArray a;
++ a.putPoints(0, 7, x, y+h,
++ x,y, x+w-8, y, x+w-8, y-2,
++ x+w, yy,
++ x+w-8, y+h+2, x+w-8, y+h);
++ p->setBrush(c);
++ p->drawConvexPolygon(a);
++
++ p->setPen(c.light());
++ p->drawPolyline(a, 0, 5);
++ p->setPen(c.dark());
++ p->drawPolyline(a, 4, 2);
++ p->setPen(c.light());
++ p->drawPolyline(a, 5, 2);
++ p->setPen(c.dark());
++ p->drawPolyline(a, 6, 2);
++ }
++
++ // draw inner vertical line for start/stop
++ // this overwrites borders of horizontal line
++ for(int i=0;i< (int)_jump.size();i++) {
++ if (_jump[i] == 0) continue;
++
++ c = _jump[i]->isCondJump() ? red : blue;
++
++ if (_jump[i]->instrFrom()->addr() == _addr) {
++ bool drawUp = true;
++ if (_jump[i]->instrTo()->addr() == _addr)
++ if (start<0) drawUp=false;
++ if (_jump[i]->instrTo()->addr() > _addr) drawUp=false;
++ if (drawUp)
++ p->fillRect( marg + 6*i +1, 0, 2, yy, c);
++ else
++ p->fillRect( marg + 6*i +1, yy, 2, height()-yy, c);
++ }
++ else if (_jump[i]->instrTo()->addr() == _addr) {
++ if (end<0) end = i;
++ if (_jump[i]->instrFrom()->addr() < _addr)
++ p->fillRect( marg + 6*i +1, 0, 2, yy, c);
++ else
++ p->fillRect( marg + 6*i +1, yy, 2, height()-yy, c);
++ }
++ }
++
++}
++
++int InstrItem::width( const TQFontMetrics& fm,
++ const TQListView* lv, int c ) const
++{
++ if (c != 3) return TQListViewItem::width(fm, lv, c);
++
++ InstrView* iv = (InstrView*) lv;
++ int levels = iv->arrowLevels();
++
++ if (levels == 0) return 0;
++
++ // 10 pixels for the arrow
++ return 10 + 6*levels + lv->itemMargin() * 2;
++}
++
+diff --git a/kdecachegrind/kdecachegrind/instritem.h b/kdecachegrind/kdecachegrind/instritem.h
+new file mode 100644
+index 0000000..2bbce71
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/instritem.h
+@@ -0,0 +1,86 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Items of instruction view.
++ */
++
++#ifndef INSTRITEM_H
++#define INSTRITEM_H
++
++#include <tqlistview.h>
++#include "tracedata.h"
++
++class InstrView;
++
++class InstrItem: public TQListViewItem
++{
++
++public:
++ // for messages
++ InstrItem(InstrView* iv, TQListView* parent,
++ Addr addr, const TQString&);
++
++ // for instruction lines
++ InstrItem(InstrView* iv, TQListView* parent,
++ Addr addr, bool inside,
++ const TQString&, const TQString&, const TQString&,
++ TraceInstr* instr);
++
++ // for call instr
++ InstrItem(InstrView* iv, TQListViewItem* parent, Addr addr,
++ TraceInstr* instr, TraceInstrCall* instrCall);
++
++ // for jump lines
++ InstrItem(InstrView* iv, TQListViewItem* parent, Addr addr,
++ TraceInstr* instr, TraceInstrJump* instrJump);
++
++ Addr addr() const { return _addr; }
++ TraceInstr* instr() const { return _instr; }
++ TraceInstrCall* instrCall() const { return _instrCall; }
++ TraceInstrJump* instrJump() const { return _instrJump; }
++
++ int compare(TQListViewItem * i, int col, bool ascending ) const;
++
++ void paintCell(TQPainter *p, const TQColorGroup &cg,
++ int column, int width, int alignment );
++ int width( const TQFontMetrics& fm,
++ const TQListView* lv, int c ) const;
++
++ void updateGroup();
++ void updateCost();
++
++ // arrow lines
++ void setJumpArray(const TQMemArray<TraceInstrJump*>& a);
++
++protected:
++ void paintArrows(TQPainter *p, const TQColorGroup &cg, int width);
++ TQMemArray<TraceInstrJump*> _jump;
++
++private:
++ InstrView* _view;
++ SubCost _pure, _pure2;
++ Addr _addr;
++ TraceInstr* _instr;
++ TraceInstrJump* _instrJump;
++ TraceInstrCall* _instrCall;
++ bool _inside;
++};
++
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/instrview.cpp b/kdecachegrind/kdecachegrind/instrview.cpp
+new file mode 100644
+index 0000000..3df1679
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/instrview.cpp
+@@ -0,0 +1,949 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Instruction View
++ */
++
++#include <tqfile.h>
++#include <tqregexp.h>
++#include <tqwhatsthis.h>
++#include <tqpopupmenu.h>
++#include <klocale.h>
++#include <kconfig.h>
++#include <kdebug.h>
++
++#include "configuration.h"
++#include "instritem.h"
++#include "instrview.h"
++
++// InstrView defaults
++
++#define DEFAULT_SHOWHEXCODE true
++
++
++// Helpers for parsing output of 'objdump'
++
++static Addr parseAddr(char* buf)
++{
++ Addr addr;
++ uint pos = 0;
++
++ // check for instruction line: <space>* <hex address> ":" <space>*
++ while(buf[pos]==' ' || buf[pos]=='\t') pos++;
++
++ int digits = addr.set(buf + pos);
++ if ((digits==0) || (buf[pos+digits] != ':')) return Addr(0);
++
++ return addr;
++}
++
++
++static bool parseLine(char* buf, Addr& addr,
++ uint& pos1, uint& pos2, uint& pos3)
++{
++ // check for instruction line: <space>* <hex address> ":" <space>*
++
++ pos1 = 0;
++ while(buf[pos1]==' ' || buf[pos1]=='\t') pos1++;
++
++ int digits = addr.set(buf + pos1);
++ pos1 += digits;
++ if ((digits==0) || (buf[pos1] != ':')) return false;
++
++ // further parsing of objdump output...
++ pos1++;
++ while(buf[pos1]==' ' || buf[pos1]=='\t') pos1++;
++
++ // skip code, pattern "xx "*
++ pos2 = pos1;
++ while(1) {
++ if (! ((buf[pos2]>='0' && buf[pos2]<='9') ||
++ (buf[pos2]>='a' && buf[pos2]<='f')) ) break;
++ if (! ((buf[pos2+1]>='0' && buf[pos2+1]<='9') ||
++ (buf[pos2+1]>='a' && buf[pos2+1]<='f')) ) break;
++ if (buf[pos2+2] != ' ') break;
++ pos2 += 3;
++ }
++ buf[pos2-1]=0;
++ while(buf[pos2]==' '|| buf[pos2]=='\t') pos2++;
++
++ // skip mnemonic
++ pos3 = pos2;
++ while(buf[pos3] && buf[pos3]!=' ' && buf[pos3]!='\t') pos3++;
++ if (buf[pos3] != 0) {
++ buf[pos3] = 0;
++ pos3++;
++ while(buf[pos3]==' '|| buf[pos3]=='\t') pos3++;
++ }
++
++ // maximal 50 chars
++ if (strlen(buf+pos2) > 50)
++ strcpy(buf+pos2+47, "...");
++
++ if (0) qDebug("For 0x%s: Code '%s', Mnc '%s', Args '%s'",
++ addr.toString().ascii(), buf+pos1, buf+pos2, buf+pos3);
++
++ return true;
++}
++
++
++
++
++//
++// InstrView
++//
++
++
++InstrView::InstrView(TraceItemView* parentView,
++ TQWidget* parent, const char* name)
++ : TQListView(parent, name), TraceItemView(parentView)
++{
++ _showHexCode = DEFAULT_SHOWHEXCODE;
++ _lastHexCodeWidth = 50;
++
++ _inSelectionUpdate = false;
++ _arrowLevels = 0;
++ _lowList.setSortLow(true);
++ _highList.setSortLow(false);
++
++ addColumn( i18n( "#" ) );
++ addColumn( i18n( "Cost" ) );
++ addColumn( i18n( "Cost 2" ) );
++ addColumn( "" );
++ addColumn( i18n( "Hex" ) );
++ addColumn( "" ); // Instruction
++ addColumn( i18n( "Assembler" ) );
++ addColumn( i18n( "Source Position" ) );
++
++ setAllColumnsShowFocus(true);
++ setColumnAlignment(1, TQt::AlignRight);
++ setColumnAlignment(2, TQt::AlignRight);
++
++ connect(this,
++ TQT_SIGNAL(contextMenuRequested(TQListViewItem*, const TQPoint &, int)),
++ TQT_SLOT(context(TQListViewItem*, const TQPoint &, int)));
++
++ connect(this, TQT_SIGNAL(selectionChanged(TQListViewItem*)),
++ TQT_SLOT(selectedSlot(TQListViewItem*)));
++
++ connect(this,
++ TQT_SIGNAL(doubleClicked(TQListViewItem*)),
++ TQT_SLOT(activatedSlot(TQListViewItem*)));
++
++ connect(this,
++ TQT_SIGNAL(returnPressed(TQListViewItem*)),
++ TQT_SLOT(activatedSlot(TQListViewItem*)));
++
++ TQWhatsThis::add( this, whatsThis());
++}
++
++void InstrView::paintEmptyArea( TQPainter * p, const TQRect & r)
++{
++ TQListView::paintEmptyArea(p, r);
++}
++
++TQString InstrView::whatsThis() const
++{
++ return i18n( "<b>Annotated Assembler</b>"
++ "<p>The annotated assembler list shows the "
++ "machine code instructions of the current selected "
++ "function together with (self) cost spent while "
++ "executing an instruction. If this is a call "
++ "instruction, lines with details on the "
++ "call happening are inserted into the source: "
++ "the cost spent inside of the call, the "
++ "number of calls happening, and the call destination.</p>"
++ "<p>The disassembler output shown is generated with "
++ "the 'objdump' utility from the 'binutils' package.</p>"
++ "<p>Select a line with call information to "
++ "make the destination function of this call current.</p>");
++}
++
++void InstrView::context(TQListViewItem* i, const TQPoint & p, int c)
++{
++ TQPopupMenu popup;
++
++ TraceInstrCall* ic = i ? ((InstrItem*) i)->instrCall() : 0;
++ TraceInstrJump* ij = i ? ((InstrItem*) i)->instrJump() : 0;
++ TraceFunction* f = ic ? ic->call()->called() : 0;
++ TraceInstr* instr = ij ? ij->instrTo() : 0;
++
++ if (f) {
++ TQString name = f->name();
++ if ((int)name.length()>Configuration::maxSymbolLength())
++ name = name.left(Configuration::maxSymbolLength()) + "...";
++ popup.insertItem(i18n("Go to '%1'").arg(name), 93);
++ popup.insertSeparator();
++ }
++ else if (instr) {
++ popup.insertItem(i18n("Go to Address %1").arg(instr->name()), 93);
++ popup.insertSeparator();
++ }
++
++ if ((c == 1) || (c == 2)) {
++ addCostMenu(&popup);
++ popup.insertSeparator();
++ }
++ addGoMenu(&popup);
++
++ popup.insertSeparator();
++ popup.setCheckable(true);
++ popup.insertItem(i18n("Hex Code"), 94);
++ if (_showHexCode) popup.setItemChecked(94,true);
++
++ int r = popup.exec(p);
++ if (r == 93) {
++ if (f) activated(f);
++ if (instr) activated(instr);
++ }
++ else if (r == 94) {
++ _showHexCode = !_showHexCode;
++ // remember width when hiding
++ if (!_showHexCode)
++ _lastHexCodeWidth = columnWidth(4);
++ setColumnWidths();
++ }
++}
++
++
++void InstrView::selectedSlot(TQListViewItem * i)
++{
++ if (!i) return;
++ // programatically selected items are not signalled
++ if (_inSelectionUpdate) return;
++
++ TraceInstrCall* ic = ((InstrItem*) i)->instrCall();
++ TraceInstrJump* ij = ((InstrItem*) i)->instrJump();
++
++ if (!ic && !ij) {
++ TraceInstr* instr = ((InstrItem*) i)->instr();
++ if (instr) {
++ _selectedItem = instr;
++ selected(instr);
++ }
++ return;
++ }
++
++ if (ic) {
++ _selectedItem = ic;
++ selected(ic);
++ }
++ else if (ij) {
++ _selectedItem = ij;
++ selected(ij);
++ }
++}
++
++void InstrView::activatedSlot(TQListViewItem * i)
++{
++ if (!i) return;
++ TraceInstrCall* ic = ((InstrItem*) i)->instrCall();
++ TraceInstrJump* ij = ((InstrItem*) i)->instrJump();
++
++ if (!ic && !ij) {
++ TraceInstr* instr = ((InstrItem*) i)->instr();
++ if (instr) activated(instr);
++ return;
++ }
++
++ if (ic) {
++ TraceFunction* f = ic->call()->called();
++ if (f) activated(f);
++ }
++ else if (ij) {
++ TraceInstr* instr = ij->instrTo();
++ if (instr) activated(instr);
++ }
++}
++
++
++TraceItem* InstrView::canShow(TraceItem* i)
++{
++ TraceItem::CostType t = i ? i->type() : TraceItem::NoCostType;
++ TraceFunction* f = 0;
++
++ switch(t) {
++ case TraceItem::Function:
++ f = (TraceFunction*) i;
++ break;
++
++ case TraceItem::Instr:
++ f = ((TraceInstr*)i)->function();
++ select(i);
++ break;
++
++ case TraceItem::Line:
++ f = ((TraceLine*)i)->functionSource()->function();
++ select(i);
++ break;
++
++ default:
++ break;
++ }
++
++ return f;
++}
++
++
++void InstrView::doUpdate(int changeType)
++{
++ // Special case ?
++ if (changeType == selectedItemChanged) {
++
++ if (!_selectedItem) {
++ clearSelection();
++ return;
++ }
++
++ InstrItem *ii = (InstrItem*)TQListView::selectedItem();
++ if (ii) {
++ if ((ii->instr() == _selectedItem) ||
++ (ii->instr() && (ii->instr()->line() == _selectedItem))) return;
++ }
++
++ TQListViewItem *item, *item2;
++ for (item = firstChild();item;item = item->nextSibling()) {
++ ii = (InstrItem*)item;
++ if ((ii->instr() == _selectedItem) ||
++ (ii->instr() && (ii->instr()->line() == _selectedItem))) {
++ ensureItemVisible(item);
++ _inSelectionUpdate = true;
++ setCurrentItem(item);
++ _inSelectionUpdate = false;
++ break;
++ }
++ item2 = item->firstChild();
++ for (;item2;item2 = item2->nextSibling()) {
++ ii = (InstrItem*)item2;
++ if (!ii->instrCall()) continue;
++ if (ii->instrCall()->call()->called() == _selectedItem) {
++ ensureItemVisible(item2);
++ _inSelectionUpdate = true;
++ setCurrentItem(item2);
++ _inSelectionUpdate = false;
++ break;
++ }
++ }
++ if (item2) break;
++ }
++ return;
++ }
++
++ if (changeType == groupTypeChanged) {
++ TQListViewItem *item, *item2;
++ for (item = firstChild();item;item = item->nextSibling())
++ for (item2 = item->firstChild();item2;item2 = item2->nextSibling())
++ ((InstrItem*)item2)->updateGroup();
++ return;
++ }
++
++ refresh();
++}
++
++void InstrView::setColumnWidths()
++{
++ if (_showHexCode) {
++ setColumnWidthMode(4, TQListView::Maximum);
++ setColumnWidth(4, _lastHexCodeWidth);
++ }
++ else {
++ setColumnWidthMode(4, TQListView::Manual);
++ setColumnWidth(4, 0);
++ }
++}
++
++void InstrView::refresh()
++{
++ _arrowLevels = 0;
++
++ // reset to automatic sizing to get column width
++ setColumnWidthMode(4, TQListView::Maximum);
++
++ clear();
++ setColumnWidth(0, 20);
++ setColumnWidth(1, 50);
++ setColumnWidth(2, _costType2 ? 50:0);
++ setColumnWidth(3, 0); // arrows, defaults to invisible
++ setColumnWidth(4, 0); // hex code column
++ setColumnWidth(5, 20); // command column
++ setColumnWidth(6, 200); // arg column
++ setSorting(0); // always reset to address number sort
++ if (_costType)
++ setColumnText(1, _costType->name());
++ if (_costType2)
++ setColumnText(2, _costType2->name());
++
++ if (!_data || !_activeItem) return;
++
++ TraceItem::CostType t = _activeItem->type();
++ TraceFunction* f = 0;
++ if (t == TraceItem::Function) f = (TraceFunction*) _activeItem;
++ if (t == TraceItem::Instr) {
++ f = ((TraceInstr*)_activeItem)->function();
++ if (!_selectedItem) _selectedItem = _activeItem;
++ }
++ if (t == TraceItem::Line) {
++ f = ((TraceLine*)_activeItem)->functionSource()->function();
++ if (!_selectedItem) _selectedItem = _activeItem;
++ }
++
++ if (!f) return;
++
++ // Allow resizing of column 2
++ setColumnWidthMode(2, TQListView::Maximum);
++
++ // check for instruction map
++ TraceInstrMap::Iterator itStart, it, tmpIt, itEnd;
++ TraceInstrMap* instrMap = f->instrMap();
++ if (instrMap) {
++ it = instrMap->begin();
++ itEnd = instrMap->end();
++ // get first instruction with cost of selected type
++ while(it != itEnd) {
++ if ((*it).hasCost(_costType)) break;
++ if (_costType2 && (*it).hasCost(_costType2)) break;
++ ++it;
++ }
++ }
++ if (!instrMap || (it == itEnd)) {
++ new InstrItem(this, this, 1,
++ i18n("There is no instruction info in the profile data file."));
++ new InstrItem(this, this, 2,
++ i18n("For the Valgrind Calltree Skin, rerun with option"));
++ new InstrItem(this, this, 3, i18n(" --dump-instr=yes"));
++ new InstrItem(this, this, 4, i18n("To see (conditional) jumps, additionally specify"));
++ new InstrItem(this, this, 5, i18n(" --trace-jump=yes"));
++ return;
++ }
++
++ // initialisation for arrow drawing
++ // create sorted list of jumps (for jump arrows)
++ _lowList.clear();
++ _highList.clear();
++ itStart = it;
++ while(1) {
++ TraceInstrJumpList jlist = (*it).instrJumps();
++ TraceInstrJump* ij;
++ for (ij=jlist.first();ij;ij=jlist.next()) {
++ if (ij->executedCount()==0) continue;
++ _lowList.append(ij);
++ _highList.append(ij);
++ }
++ ++it;
++ while(it != itEnd) {
++ if ((*it).hasCost(_costType)) break;
++ if (_costType2 && (*it).hasCost(_costType2)) break;
++ ++it;
++ }
++ if (it == itEnd) break;
++ }
++ _lowList.sort();
++ _highList.sort();
++ _lowList.first(); // iterators to list start
++ _highList.first();
++ _arrowLevels = 0;
++ _jump.resize(0);
++
++
++ // do multiple calls to 'objdump' if there are large gaps in addresses
++ it = itStart;
++ while(1) {
++ itStart = it;
++ while(1) {
++ tmpIt = it;
++ ++it;
++ while(it != itEnd) {
++ if ((*it).hasCost(_costType)) break;
++ if (_costType2 && (*it).hasCost(_costType2)) break;
++ ++it;
++ }
++ if (it == itEnd) break;
++ if (!(*it).addr().isInRange( (*tmpIt).addr(),10000) ) break;
++ }
++
++ // tmpIt is always last instruction with cost
++ if (!fillInstrRange(f, itStart, ++tmpIt)) break;
++ if (it == itEnd) break;
++ }
++
++ _lastHexCodeWidth = columnWidth(4);
++ setColumnWidths();
++
++ if (!_costType2) {
++ setColumnWidthMode(2, TQListView::Manual);
++ setColumnWidth(2, 0);
++ }
++}
++
++/* This is called after adding instrItems, for each of them in
++ * address order. _jump is the global array of valid jumps
++ * for a line while we iterate downwards.
++ * The existing jumps, sorted in lowList according lower address,
++ * is iterated in the same way.
++ */
++void InstrView::updateJumpArray(Addr addr, InstrItem* ii,
++ bool ignoreFrom, bool ignoreTo)
++{
++ TraceInstrJump* ij;
++ Addr lowAddr, highAddr;
++ int iEnd = -1, iStart = -1;
++
++ if (0) qDebug("updateJumpArray(addr 0x%s, jump to %s)",
++ addr.toString().ascii(),
++ ii->instrJump()
++ ? ii->instrJump()->instrTo()->name().ascii() : "?" );
++
++ // check for new arrows starting from here downwards
++ ij=_lowList.current();
++ while(ij) {
++ lowAddr = ij->instrFrom()->addr();
++ if (ij->instrTo()->addr() < lowAddr)
++ lowAddr = ij->instrTo()->addr();
++
++ if (lowAddr > addr) break;
++
++ // if target is downwards but we draw no source, break
++ if (ignoreFrom && (lowAddr < ij->instrTo()->addr())) break;
++ // if source is downward but we draw no target, break
++ if (ignoreTo && (lowAddr < ij->instrFrom()->addr())) break;
++ // if this is another jump start, break
++ if (ii->instrJump() && (ij != ii->instrJump())) break;
++
++#if 0
++ for(iStart=0;iStart<_arrowLevels;iStart++)
++ if (_jump[iStart] &&
++ (_jump[iStart]->instrTo() == ij->instrTo())) break;
++#else
++ iStart = _arrowLevels;
++#endif
++
++ if (iStart==_arrowLevels) {
++ for(iStart=0;iStart<_arrowLevels;iStart++)
++ if (_jump[iStart] == 0) break;
++ if (iStart==_arrowLevels) {
++ _arrowLevels++;
++ _jump.resize(_arrowLevels);
++ }
++ if (0) qDebug(" new start at %d for %s", iStart, ij->name().ascii());
++ _jump[iStart] = ij;
++ }
++ ij=_lowList.next();
++ }
++
++ ii->setJumpArray(_jump);
++
++ // check for active arrows ending here
++ ij=_highList.current();
++ while(ij) {
++ highAddr = ij->instrFrom()->addr();
++ if (ij->instrTo()->addr() > highAddr) {
++ highAddr = ij->instrTo()->addr();
++ if (ignoreTo) break;
++ }
++ else if (ignoreFrom) break;
++
++ if (highAddr > addr) break;
++
++ for(iEnd=0;iEnd<_arrowLevels;iEnd++)
++ if (_jump[iEnd] == ij) break;
++ if (iEnd==_arrowLevels) {
++ kdDebug() << "InstrView: no jump start for end at 0x"
++ << highAddr.toString() << " ?" << endl;
++ iEnd = -1;
++ }
++
++ if (0 && (iEnd>=0))
++ qDebug(" end %d (%s to %s)",
++ iEnd,
++ _jump[iEnd]->instrFrom()->name().ascii(),
++ _jump[iEnd]->instrTo()->name().ascii());
++
++ if (0 && ij) qDebug("next end: %s to %s",
++ ij->instrFrom()->name().ascii(),
++ ij->instrTo()->name().ascii());
++
++ ij=_highList.next();
++ if (highAddr > addr)
++ break;
++ else {
++ if (iEnd>=0) _jump[iEnd] = 0;
++ iEnd = -1;
++ }
++ }
++ if (iEnd>=0) _jump[iEnd] = 0;
++}
++
++
++
++/**
++ * Fill up with instructions from cost range [it;itEnd[
++ */
++bool InstrView::fillInstrRange(TraceFunction* function,
++ TraceInstrMap::Iterator it,
++ TraceInstrMap::Iterator itEnd)
++{
++ Addr costAddr, nextCostAddr, objAddr, addr;
++ Addr dumpStartAddr, dumpEndAddr;
++ TraceInstrMap::Iterator costIt;
++
++ // shouldn't happen
++ if (it == itEnd) return false;
++
++ // calculate address range for call to objdump
++ TraceInstrMap::Iterator tmpIt = itEnd;
++ --tmpIt;
++ nextCostAddr = (*it).addr();
++ dumpStartAddr = (nextCostAddr<20) ? Addr(0) : nextCostAddr -20;
++ dumpEndAddr = (*tmpIt).addr() +20;
++
++ // generate command
++ TQString popencmd, objfile;
++ objfile = function->object()->name();
++ objfile = objfile.replace(TQRegExp("[\"']"), ""); // security...
++ popencmd = TQString("objdump -C -d "
++ "--start-address=0x%1 --stop-address=0x%2 \"%3\"")
++ .arg(dumpStartAddr.toString()).arg(dumpEndAddr.toString())
++ .arg(objfile);
++ if (1) qDebug("Running '%s'...", popencmd.ascii());
++
++ // and run...
++ FILE* iFILE = popen(TQFile::encodeName( popencmd ), "r");
++ if (iFILE == 0) {
++ new InstrItem(this, this, 1,
++ i18n("There is an error trying to execute the command"));
++ new InstrItem(this, this, 2, "");
++ new InstrItem(this, this, 3, popencmd);
++ new InstrItem(this, this, 4, "");
++ new InstrItem(this, this, 5,
++ i18n("Check that you have installed 'objdump'."));
++ new InstrItem(this, this, 6,
++ i18n("This utility can be found in the 'binutils' package."));
++ return false;
++ }
++ TQFile file;
++ file.open(IO_ReadOnly, iFILE);
++
++#define BUF_SIZE 256
++
++ char buf[BUF_SIZE];
++ bool inside = false, skipLineWritten = true;
++ int readBytes = -1;
++ int objdumpLineno = 0, dumpedLines = 0, noAssLines = 0;
++ SubCost most = 0;
++ TraceInstr* currInstr;
++ InstrItem *ii, *ii2, *item = 0, *first = 0, *selected = 0;
++ TQString code, cmd, args;
++ bool needObjAddr = true, needCostAddr = true;
++
++ costAddr = 0;
++ objAddr = 0;
++
++ while (1) {
++
++ if (needObjAddr) {
++ needObjAddr = false;
++
++ // read next objdump line
++ while (1) {
++ readBytes=file.readLine(buf, BUF_SIZE);
++ if (readBytes<=0) {
++ objAddr = 0;
++ break;
++ }
++
++ objdumpLineno++;
++ if (readBytes == BUF_SIZE) {
++ qDebug("ERROR: Line %d of '%s' too long\n",
++ objdumpLineno, popencmd.ascii());
++ }
++ else if ((readBytes>0) && (buf[readBytes-1] == '\n'))
++ buf[readBytes-1] = 0;
++
++ objAddr = parseAddr(buf);
++ if ((objAddr<dumpStartAddr) || (objAddr>dumpEndAddr))
++ objAddr = 0;
++ if (objAddr != 0) break;
++ }
++
++ if (0) kdDebug() << "Got ObjAddr: 0x" << objAddr.toString() << endl;
++ }
++
++ // try to keep objAddr in [costAddr;nextCostAddr]
++ if (needCostAddr &&
++ (nextCostAddr > 0) &&
++ ((objAddr == Addr(0)) || (objAddr >= nextCostAddr)) ) {
++ needCostAddr = false;
++
++ costIt = it;
++ ++it;
++ while(it != itEnd) {
++ if ((*it).hasCost(_costType)) break;
++ if (_costType2 && (*it).hasCost(_costType2)) break;
++ ++it;
++ }
++ costAddr = nextCostAddr;
++ nextCostAddr = (it == itEnd) ? Addr(0) : (*it).addr();
++
++ if (0) kdDebug() << "Got nextCostAddr: 0x" << nextCostAddr.toString()
++ << ", costAddr 0x" << costAddr.toString() << endl;
++ }
++
++ // if we have no more address from objdump, stop
++ if (objAddr == 0) break;
++
++ if ((nextCostAddr==0) || (costAddr == 0) ||
++ (objAddr < nextCostAddr)) {
++ // next line is objAddr
++
++ uint pos1, pos2, pos3;
++
++ // this sets addr
++ parseLine(buf, addr, pos1, pos2, pos3);
++ code = TQString(buf + pos1);
++ cmd = TQString(buf + pos2);
++ args = TQString(buf + pos3);
++
++ if (costAddr == objAddr) {
++ currInstr = &(*costIt);
++ needCostAddr = true;
++ }
++ else
++ currInstr = 0;
++
++ needObjAddr = true;
++
++ if (0) kdDebug() << "Dump Obj Addr: 0x" << addr.toString()
++ << " [" << cmd << " " << args << "], cost (0x"
++ << costAddr.toString() << ", next 0x"
++ << nextCostAddr.toString() << ")" << endl;
++ }
++ else {
++ addr = costAddr;
++ code = cmd = TQString();
++ args = i18n("(No Assembler)");
++
++ currInstr = &(*costIt);
++ needCostAddr = true;
++
++ noAssLines++;
++ if (0) kdDebug() << "Dump Cost Addr: 0x" << addr.toString()
++ << " (no ass), objAddr 0x" << objAddr.toString() << endl;
++ }
++
++ // update inside
++ if (!inside) {
++ if (currInstr) inside = true;
++ }
++ else {
++ if (0) kdDebug() << "Check if 0x" << addr.toString() << " is in ]0x"
++ << costAddr.toString() << ",0x"
++ << (nextCostAddr - 3*Configuration::noCostInside()).toString()
++ << "[" << endl;
++
++ // Suppose a average instruction len of 3 bytes
++ if ( (addr > costAddr) &&
++ ((nextCostAddr==0) ||
++ (addr < nextCostAddr - 3*Configuration::noCostInside()) ))
++ inside = false;
++ }
++
++ int context = Configuration::context();
++
++ if ( ((costAddr==0) || (addr > costAddr + 3*context)) &&
++ ((nextCostAddr==0) || (addr < nextCostAddr - 3*context)) ) {
++
++ // the very last skipLine can be ommitted
++ if ((it == itEnd) &&
++ (itEnd == function->instrMap()->end())) skipLineWritten=true;
++
++ if (!skipLineWritten) {
++ skipLineWritten = true;
++ // a "skipping" line: print "..." instead of a line number
++ code = cmd = TQString();
++ args = TQString("...");
++ }
++ else
++ continue;
++ }
++ else
++ skipLineWritten = false;
++
++
++ ii = new InstrItem(this, this, addr, inside,
++ code, cmd, args, currInstr);
++ dumpedLines++;
++ if (0) kdDebug() << "Dumped 0x" << addr.toString() << " "
++ << (inside ? "Inside " : "Outside")
++ << (currInstr ? "Cost" : "") << endl;
++
++ // no calls/jumps if we have no cost for this line
++ if (!currInstr) continue;
++
++ if (!selected &&
++ (currInstr == _selectedItem) ||
++ (currInstr->line() == _selectedItem)) selected = ii;
++
++ if (!first) first = ii;
++
++ if (currInstr->subCost(_costType) > most) {
++ item = ii;
++ most = currInstr->subCost(_costType);
++ }
++
++ ii->setOpen(true);
++ TraceInstrCallList list = currInstr->instrCalls();
++ TraceInstrCall* ic;
++ for (ic=list.first();ic;ic=list.next()) {
++ if ((ic->subCost(_costType)==0) &&
++ (ic->subCost(_costType2)==0)) continue;
++
++ if (ic->subCost(_costType) > most) {
++ item = ii;
++ most = ic->subCost(_costType);
++ }
++
++ ii2 = new InstrItem(this, ii, addr, currInstr, ic);
++
++ if (!selected && (ic->call()->called() == _selectedItem))
++ selected = ii2;
++ }
++
++ TraceInstrJumpList jlist = currInstr->instrJumps();
++ TraceInstrJump* ij;
++ for (ij=jlist.first();ij;ij=jlist.next()) {
++ if (ij->executedCount()==0) continue;
++
++ new InstrItem(this, ii, addr, currInstr, ij);
++ }
++ }
++
++ if (selected) item = selected;
++ if (item) first = item;
++ if (first) {
++ ensureItemVisible(first);
++ _inSelectionUpdate = true;
++ setCurrentItem(first);
++ _inSelectionUpdate = false;
++ }
++
++ file.close();
++ pclose(iFILE);
++
++ // for arrows: go down the list according to list sorting
++ sort();
++ TQListViewItem *item1, *item2;
++ for (item1=firstChild();item1;item1 = item1->nextSibling()) {
++ ii = (InstrItem*)item1;
++ updateJumpArray(ii->addr(), ii, true, false);
++
++ for (item2=item1->firstChild();item2;item2 = item2->nextSibling()) {
++ ii2 = (InstrItem*)item2;
++ if (ii2->instrJump())
++ updateJumpArray(ii->addr(), ii2, false, true);
++ else
++ ii2->setJumpArray(_jump);
++ }
++ }
++
++ if (arrowLevels())
++ setColumnWidth(3, 10 + 6*arrowLevels() + itemMargin() * 2);
++ else
++ setColumnWidth(3, 0);
++
++
++ if (noAssLines > 1) {
++ // trace cost not machting code
++
++ new InstrItem(this, this, 1,
++ i18n("There is %n cost line without assembler code.",
++ "There are %n cost lines without assembler code.", noAssLines));
++ new InstrItem(this, this, 2,
++ i18n("This happens because the code of"));
++ new InstrItem(this, this, 3, TQString(" %1").arg(objfile));
++ new InstrItem(this, this, 4,
++ i18n("does not seem to match the profile data file."));
++ new InstrItem(this, this, 5, "");
++ new InstrItem(this, this, 6,
++ i18n("Are you using an old profile data file or is the above mentioned"));
++ new InstrItem(this, this, 7,
++ i18n("ELF object from an updated installation/another machine?"));
++ new InstrItem(this, this, 8, "");
++ return false;
++ }
++
++ if (dumpedLines == 0) {
++ // no matching line read from popen
++ new InstrItem(this, this, 1,
++ i18n("There seems to be an error trying to execute the command"));
++ new InstrItem(this, this, 2, "");
++ new InstrItem(this, this, 3, popencmd);
++ new InstrItem(this, this, 4, "");
++ new InstrItem(this, this, 5,
++ i18n("Check that the ELF object used in the command exists."));
++ new InstrItem(this, this, 6,
++ i18n("Check that you have installed 'objdump'."));
++ new InstrItem(this, this, 7,
++ i18n("This utility can be found in the 'binutils' package."));
++ return false;
++ }
++
++ return true;
++}
++
++
++void InstrView::updateInstrItems()
++{
++ InstrItem* ii;
++ TQListViewItem* item = firstChild();
++ for (;item;item = item->nextSibling()) {
++ ii = (InstrItem*)item;
++ TraceInstr* instr = ii->instr();
++ if (!instr) continue;
++
++ ii->updateCost();
++
++ TQListViewItem *next, *i = ii->firstChild();
++ for (;i;i = next) {
++ next = i->nextSibling();
++ ((InstrItem*)i)->updateCost();
++ }
++ }
++}
++
++void InstrView::readViewConfig(KConfig* c,
++ TQString prefix, TQString postfix, bool)
++{
++ KConfigGroup* g = configGroup(c, prefix, postfix);
++
++ if (0) qDebug("InstrView::readViewConfig");
++
++ _showHexCode = g->readBoolEntry("ShowHexCode", DEFAULT_SHOWHEXCODE);
++
++ delete g;
++}
++
++void InstrView::saveViewConfig(KConfig* c,
++ TQString prefix, TQString postfix, bool)
++{
++ KConfigGroup g(c, (prefix+postfix).ascii());
++
++ writeConfigEntry(&g, "ShowHexCode", _showHexCode, DEFAULT_SHOWHEXCODE);
++}
++
++#include "instrview.moc"
+diff --git a/kdecachegrind/kdecachegrind/instrview.h b/kdecachegrind/kdecachegrind/instrview.h
+new file mode 100644
+index 0000000..79d3d76
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/instrview.h
+@@ -0,0 +1,83 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Instruction View
++ */
++
++#ifndef INSTRVIEW_H
++#define INSTRVIEW_H
++
++#include <tqlistview.h>
++#include "traceitemview.h"
++
++class InstrItem;
++
++class InstrView : public TQListView, public TraceItemView
++{
++ friend class InstrItem;
++
++ Q_OBJECT
++ TQ_OBJECT
++
++public:
++ InstrView(TraceItemView* parentView,
++ TQWidget* parent = 0, const char* name = 0);
++
++ virtual TQWidget* widget() { return this; }
++ TQString whatsThis() const;
++
++ void readViewConfig(KConfig*, TQString prefix, TQString postfix, bool);
++ void saveViewConfig(KConfig*, TQString prefix, TQString postfix, bool);
++
++protected:
++ int arrowLevels() { return _arrowLevels; }
++ void paintEmptyArea( TQPainter *, const TQRect & );
++
++private slots:
++ void context(TQListViewItem*, const TQPoint &, int);
++ void selectedSlot(TQListViewItem *);
++ void activatedSlot(TQListViewItem *);
++
++private:
++ TraceItem* canShow(TraceItem*);
++ void doUpdate(int);
++ void refresh();
++ void setColumnWidths();
++ void fillInstr();
++ void updateJumpArray(Addr,InstrItem*,bool,bool);
++ bool fillInstrRange(TraceFunction*,
++ TraceInstrMap::Iterator,TraceInstrMap::Iterator);
++ void updateInstrItems();
++
++ bool _inSelectionUpdate;
++
++ // arrows
++ int _arrowLevels;
++ // temporary needed on creation...
++ TQMemArray<TraceInstrJump*> _jump;
++ TraceInstrJumpList _lowList, _highList;
++
++ // remember width of hex code column if hidden
++ int _lastHexCodeWidth;
++
++ // widget options
++ bool _showHexCode;
++};
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/listutils.cpp b/kdecachegrind/kdecachegrind/listutils.cpp
+new file mode 100644
+index 0000000..0053646
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/listutils.cpp
+@@ -0,0 +1,266 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Some helper functions for TQListViewItem derivates
++ */
++
++#include <tqpainter.h>
++#include "listutils.h"
++
++#define COSTPIX_WIDTH 25
++
++TQPixmap colorPixmap(int w, int h, TQColor c)
++{
++ static TQPixmap* pixs[37];
++ static TQColor cols[37];
++ static bool inited = false;
++
++ if (!inited) {
++ for (int i=0;i<37;i++) pixs[i]=0;
++ inited = true;
++ }
++ int hash = (w+h+c.red()+c.green()+c.blue()) % 37;
++ if (pixs[hash]) {
++ if ((pixs[hash]->width() == w) &&
++ (pixs[hash]->height() == h) &&
++ (cols[hash] == c))
++ return *pixs[hash];
++
++ delete pixs[hash];
++ }
++
++
++ TQPixmap* pix = new TQPixmap(w, h);
++ pix->fill(c);
++ TQPainter p(pix);
++ p.setPen(c.light());
++ p.drawLine(0, 0, w-1, 0);
++ p.drawLine(0, 0, 0, h-1);
++ p.setPen(c.dark());
++ p.drawLine(w-1, 0, w-1, h-1);
++ p.drawLine(0, h-1, w-1, h-1);
++
++ pixs[hash] = pix;
++ cols[hash] = c;
++ return *pix;
++}
++
++/**
++ * Create a percentage pixmap with a filling rate of p percent (0-100).
++ * When withFrame==false, the pixmap is truncated to only the filled portion.
++ */
++TQPixmap percentagePixmap(int w, int h, int percent, TQColor c, bool framed)
++{
++ int iw, ix1, ix2, ih, iy1, iy2;
++
++ // inner rectangle to fill with bar
++ if (framed) {
++ iw = w-2, ix1 = 1, ix2 = w-2;
++ ih = h-2, iy1 = 1, iy2 = h-2;
++ }
++ else {
++ iw = w; ix1 = 0; ix2 = w-1;
++ ih = h; iy1 = 0; iy2 = h-1;
++ }
++
++ /* Limit bar to 100% */
++ int filled = (percent>100) ? iw+1 : iw*percent/100+1;
++ if (!framed) w=filled-1;
++ if (w<3) return TQPixmap();
++
++ TQPixmap pix(w, h);
++ pix.fill(TQt::white);
++ TQPainter p(&pix);
++ p.setPen(TQt::black);
++ if (framed)
++ p.drawRect(0, 0, w, h);
++
++ // inside
++ p.setPen(TQt::NoPen);
++ p.setBrush(c);
++ p.drawRect(ix1, iy1, filled-1,ih);
++
++ // frame
++ ix2 = ix1+filled-2;
++ p.setPen(c.light());
++ p.drawLine(ix1, iy1, ix2, iy1);
++ p.drawLine(ix1, iy1, ix1, iy2);
++ p.setPen(c.dark());
++ p.drawLine(ix1+1, iy2, ix2, iy2);
++ p.drawLine(ix2, iy1, ix2, iy2);
++
++ return pix;
++}
++
++inline TQColor partitionColor(int d, int max)
++{
++ return TQColor( (720*d/max) % 360,
++ 255-(128*d/max), 192, TQColor::Hsv);
++}
++
++
++TQPixmap partitionPixmap(int w, int h,
++ double* hist, TQColor* cArray, int maxIndex, bool framed)
++{
++ int lastPos = 0, nextPos;
++ double val=0.0, sum=0.0;
++ int d, dmin=maxIndex, dmax=0;
++ for (d = 0;d<maxIndex;d++)
++ if (hist[d]>0.0) {
++ sum += hist[d];
++ if (dmin>d) dmin = d;
++ if (dmax<d) dmax = d;
++ }
++
++ // inner rectangle to fill with bar
++ int iw, ix1, ix2, ih, iy1, iy2;
++ if (framed) {
++ iw = w-2, ix1 = 1, ix2 = w-2;
++ ih = h-2, iy1 = 1, iy2 = h-2;
++ }
++ else {
++ iw = w; ix1 = 0; ix2 = w-1;
++ ih = h; iy1 = 0; iy2 = h-1;
++ }
++
++ int filled = (int)(iw*sum+1);
++ if (!framed && (filled < w)) w=filled;
++ if (w<3) return TQPixmap();
++
++ TQPixmap pix(w, h);
++ pix.fill(TQt::white);
++ TQPainter p(&pix);
++ p.setPen(TQt::black);
++ if (framed)
++ p.drawRect(0, 0, w, h);
++
++ //qDebug("Sum %f, dw %d", sum,dw);
++
++ TQColor c, cLast;
++ bool leftDrawn = false;
++ int x1, x2=0;
++ int lastDiff=0, diff;
++ d=dmin;
++ while (d<dmax+1) {
++ val += hist[d];
++ nextPos = (int)(filled * val/sum);
++
++ //qDebug(" hist[%d] %f, val %f, nextPos %d", d, hist[d], val, nextPos);
++
++ diff = nextPos-lastPos;
++ if (diff==0) { d++; continue; }
++
++ c = cArray ? cArray[d] : partitionColor(d,maxIndex);
++
++ x1 = ix1+lastPos;
++ x2 = ix1+nextPos;
++ if (x2>=iw) x2=iw-1;
++
++ // inside
++ p.setPen(TQt::NoPen);
++ p.setBrush(c);
++ p.drawRect(x1, iy1, x2-x1+1, ih);
++
++ // lighter top border
++ p.setPen(c.light());
++ p.drawLine(x1, iy1, x2-1, iy1);
++
++ // when width for last and current distance >2, draw full 3D effect...
++ if (!leftDrawn) {
++ p.drawLine(x1, iy1+1, x1, iy2);
++ leftDrawn = true;
++ }
++
++ // darker bottom border
++ p.setPen(c.dark());
++ p.drawLine(x1, iy2, x2-1, iy2);
++
++ lastPos = nextPos;
++ lastDiff = diff;
++ cLast = c;
++ d++;
++ }
++
++ // right border (in last color)
++ if (x2>0)
++ p.drawLine(x2, iy1, x2, iy2);
++
++ return pix;
++}
++
++
++TQPixmap costPixmap(TraceCostType* ct, TraceCost* cost, double total, bool framed)
++{
++ if (ct->isReal()) {
++ TQColor color = ct->color();
++ double p = 100.0 * cost->subCost(ct) / total;
++ return percentagePixmap(COSTPIX_WIDTH, 10, (int)(p+.5), color, framed);
++ }
++
++ int maxIndex;
++ double h[MaxRealIndexValue];
++ TQColor* cs = ct->mapping()->realColors();
++ maxIndex = ct->histCost(cost, total, h);
++
++ if (maxIndex ==0) return TQPixmap();
++ return partitionPixmap(COSTPIX_WIDTH, 10, h, cs, maxIndex, framed);
++}
++
++
++
++// HighestCostList
++
++HighestCostList::HighestCostList()
++{
++ _maxSize = 0;
++ _count = 0;
++ _costType = 0;
++}
++
++void HighestCostList::clear(int maxSize)
++{
++ _maxSize = maxSize;
++ _count = 0;
++ _item.resize(maxSize);
++ _cost.resize(maxSize);
++}
++
++void HighestCostList::addCost(TraceCost* c, SubCost cost)
++{
++ int i;
++
++ _count++;
++ if (_count > _maxSize) {
++ if (_cost[_maxSize-1] >= cost) return;
++ i = _maxSize-1;
++ }
++ else i = _count-1;
++
++ for(; i>0; i--) {
++ if (_cost[i-1] >= cost) break;
++ else {
++ _cost[i] = _cost[i-1];
++ _item[i] = _item[i-1];
++ }
++ }
++ _cost[i] = cost;
++ _item[i] = c;
++}
++
++
+diff --git a/kdecachegrind/kdecachegrind/listutils.h b/kdecachegrind/kdecachegrind/listutils.h
+new file mode 100644
+index 0000000..e3e13fb
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/listutils.h
+@@ -0,0 +1,65 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Some helper functions for TQListViewItem derivates
++ */
++
++#ifndef LISTUTILS_H
++#define LISTUTILS_H
++
++#include <tqpixmap.h>
++#include <tqstring.h>
++#include <tqcolor.h>
++#include "tracedata.h"
++
++TQString bigNum(SubCost);
++TQPixmap colorPixmap(int w, int h, TQColor c);
++TQPixmap percentagePixmap(int w, int h, int percent, TQColor c, bool framed);
++TQPixmap partitionPixmap(int w, int h, double* hist, TQColor*,
++ int maxIndex, bool framed);
++TQPixmap costPixmap(TraceCostType* ct, TraceCost* cost, double total, bool framed);
++
++/**
++ * A class to calculate the <maxSize> TraceCost items
++ * with highest cost.
++ */
++
++class HighestCostList
++{
++ public:
++ HighestCostList();
++
++ void clear(int maxSize);
++ void addCost(TraceCost*, SubCost);
++ int count() { return _count; }
++ int realCount() { return (_count > _maxSize) ? _maxSize:_count; }
++ int maxSize() { return _maxSize; }
++ bool hasMore() { return _count > _maxSize; }
++ TraceCost* operator[] (int i)
++ { return (i>=0 && i<_count && i<_maxSize) ? _item[i] : 0; }
++
++ private:
++ TraceCostList _list;
++ int _maxSize, _count;
++ TraceCostType* _costType;
++ TQMemArray<TraceCost*> _item;
++ TQMemArray<SubCost> _cost;
++};
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/lo16-app-kcachegrind.png b/kdecachegrind/kdecachegrind/lo16-app-kcachegrind.png
+new file mode 100644
+index 0000000..0985586
+Binary files /dev/null and b/kdecachegrind/kdecachegrind/lo16-app-kcachegrind.png differ
+diff --git a/kdecachegrind/kdecachegrind/lo32-app-kcachegrind.png b/kdecachegrind/kdecachegrind/lo32-app-kcachegrind.png
+new file mode 100644
+index 0000000..12542c8
+Binary files /dev/null and b/kdecachegrind/kdecachegrind/lo32-app-kcachegrind.png differ
+diff --git a/kdecachegrind/kdecachegrind/loader.cpp b/kdecachegrind/kdecachegrind/loader.cpp
+new file mode 100644
+index 0000000..a4aecf5
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/loader.cpp
+@@ -0,0 +1,85 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2002 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Base class for loaders of profiling data.
++ */
++
++#include "loader.h"
++
++
++/// Loader
++
++LoaderList Loader::_loaderList;
++
++Loader::Loader(TQString name, TQString desc)
++{
++ _name = name;
++ _description = desc;
++}
++
++Loader::~Loader()
++{}
++
++bool Loader::canLoadTrace(TQFile*)
++{
++ return false;
++}
++
++bool Loader::loadTrace(TracePart*)
++{
++ return false;
++}
++
++Loader* Loader::matchingLoader(TQFile* file)
++{
++ Loader* l;
++ for (l=_loaderList.first(); l; l = _loaderList.next())
++ if (l->canLoadTrace(file))
++ return l;
++
++ return 0;
++}
++
++Loader* Loader::loader(TQString name)
++{
++ Loader* l;
++ for (l=_loaderList.first(); l; l = _loaderList.next())
++ if (l->name() == name)
++ return l;
++
++ return 0;
++}
++
++// factories of available loaders
++Loader* createCachegrindLoader();
++
++void Loader::initLoaders()
++{
++ _loaderList.append(createCachegrindLoader());
++ //_loaderList.append(GProfLoader::createLoader());
++}
++
++void Loader::deleteLoaders()
++{
++ _loaderList.setAutoDelete(true);
++ _loaderList.clear();
++}
++
++
++#include "loader.moc"
+diff --git a/kdecachegrind/kdecachegrind/loader.h b/kdecachegrind/kdecachegrind/loader.h
+new file mode 100644
+index 0000000..f79f13d
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/loader.h
+@@ -0,0 +1,80 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2002 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * Base class for loaders of profiling data.
++ */
++
++#ifndef LOADER_H
++#define LOADER_H
++
++#include <tqobject.h>
++#include <tqptrlist.h>
++#include <tqstring.h>
++
++class TQFile;
++class TraceData;
++class TracePart;
++class Loader;
++
++
++typedef TQPtrList<Loader> LoaderList;
++
++/**
++ * To implement a new loader, inherit from the Loader class
++ * and implement canLoadTrace(), loadTrace() and if a trace in
++ * this format can consist out of multiple parts, implement
++ * isPartOfTrace(), too.
++ * For registration, put into the static initLoaders() function
++ * of this base class a _loaderList.append(new MyLoader()).
++ *
++ * KCachegrind will use the first matching loader.
++ */
++
++class Loader: public TQObject
++{
++ Q_OBJECT
++ TQ_OBJECT
++
++public:
++ Loader(TQString name, TQString desc);
++ virtual ~Loader();
++
++ virtual bool canLoadTrace(TQFile* file);
++ virtual bool loadTrace(TracePart*);
++
++ static Loader* matchingLoader(TQFile* file);
++ static Loader* loader(TQString name);
++ static void initLoaders();
++ static void deleteLoaders();
++
++ TQString name() const { return _name; }
++ TQString description() const { return _description; }
++
++signals:
++ void updateStatus(TQString, int);
++
++private:
++ TQString _name, _description;
++
++ static LoaderList _loaderList;
++};
++
++
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/main.cpp b/kdecachegrind/kdecachegrind/main.cpp
+new file mode 100644
+index 0000000..fd9df1b
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/main.cpp
+@@ -0,0 +1,95 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * KCachegrind startup
++ */
++
++// for KCACHEGRIND_VERSION
++#include "../version.h"
++
++#include <tqfile.h>
++#include <kapplication.h>
++#include <kcmdlineargs.h>
++#include <kaboutdata.h>
++#include <klocale.h>
++
++#include "toplevel.h"
++#include "tracedata.h"
++#include "loader.h"
++
++static KCmdLineOptions options[] =
++{
++ { "r <exec>", I18N_NOOP("Run <exec> under cachegrind"), 0 },
++ { "+[trace]", I18N_NOOP("Show information of this trace"), 0 },
++ KCmdLineLastOption // End of options.
++};
++
++int main( int argc, char ** argv )
++{
++ KAboutData aboutData("kdecachegrind",
++ I18N_NOOP("KCachegrind"),
++ KCACHEGRIND_VERSION,
++ I18N_NOOP("KDE Frontend for Cachegrind"),
++ KAboutData::License_GPL,
++ I18N_NOOP("(C) 2002, 2003, 2004"), 0,
++ "http://kdecachegrind.sf.net");
++ aboutData.addAuthor("Josef Weidendorfer",
++ I18N_NOOP("Author/Maintainer"),
++ "Josef.Weidendorfer@gmx.de");
++
++ KCmdLineArgs::init(argc, argv, &aboutData);
++ KCmdLineArgs::addCmdLineOptions( options );
++
++ KApplication a;
++ TopLevel* t;
++ Loader::initLoaders();
++
++ if (a.isRestored()){
++ int n = 1;
++ while (KMainWindow::canBeRestored(n)){
++ (new TopLevel())->restore(n);
++ n++;
++ }
++ }
++ else {
++ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
++ if (args->count()>0) {
++ for(int i = 0; i < args->count(); i++) {
++ t = new TopLevel();
++ t->show();
++ t->loadDelayed(TQFile::decodeName(args->arg(i)));
++ }
++ }
++ else {
++ // load trace in current dir
++ t = new TopLevel();
++ t->show();
++ t->loadDelayed(".");
++ }
++ }
++
++ a.connect( &a, TQT_SIGNAL( lastWindowClosed() ), &a, TQT_SLOT( quit() ) );
++ int res = a.exec();
++
++ // to make leak checking in valgrind happy...
++ Loader::deleteLoaders();
++ TraceItem::cleanup();
++
++ return res;
++}
+diff --git a/kdecachegrind/kdecachegrind/multiview.cpp b/kdecachegrind/kdecachegrind/multiview.cpp
+new file mode 100644
+index 0000000..4288e2d
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/multiview.cpp
+@@ -0,0 +1,224 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * MultiView, enclosing multiple TabView's with a user choosable
++ * active view (i.e. focus), separated by a splitter.
++ * Selection of the active view is shown in the next to the right view
++ * (with wrap around).
++ */
++
++#include <tqobjectlist.h>
++#include <kconfig.h>
++#include <kdebug.h>
++
++#include "multiview.h"
++#include "tabview.h"
++
++//
++// MultiView
++//
++
++MultiView::MultiView(TopLevel* top, TQWidget* parent, const char* name)
++ : TQSplitter(parent, name), TraceItemView(0, top)
++{
++ // default
++ setOrientation(Qt::Horizontal);
++
++ appendView();
++ _active = _views.first();
++ _active->setActive(true);
++}
++
++void MultiView::setData(TraceData* d)
++{
++ TraceItemView::setData(d);
++
++ TabView* tv;
++ for(tv=_views.first(); tv; tv=_views.next())
++ tv->setData(d);
++}
++
++void MultiView::setChildCount(int n)
++{
++ while(n< (int)_views.count()) removeView();
++ while(n> (int)_views.count()) appendView();
++}
++
++void MultiView::appendView()
++{
++ int n = _views.count()+1;
++
++ TabView* tv = new TabView(this, this,
++ TQString("TabView-%1").arg(n).ascii());
++ connect(tv, TQT_SIGNAL(activated(TabView*)),
++ this, TQT_SLOT(tabActivated(TabView*)) );
++ _views.append(tv);
++ tv->show();
++
++ // set same attributes as in active view
++ tv->set(0, _data, _costType, _costType2,
++ _groupType, _partList, _activeItem, 0);
++ tv->updateView();
++
++ if (0) kdDebug() << "MultiView::appendView, now "
++ << _views.count() << endl;
++}
++
++void MultiView::removeView()
++{
++ if (_views.count()<=1) return;
++
++ TabView* last = _views.last();
++
++ // if last tab is active, make first active
++ if (last == _active) {
++ TabView* newActive = _views.first();
++ newActive->setActive(true);
++ tabActivated(newActive);
++ }
++
++ _views.removeRef(last);
++ delete last;
++
++ if (0) kdDebug() << "MultiView::removeView, now "
++ << _views.count() << endl;
++}
++
++
++void MultiView::tabActivated(TabView* newActiveTab)
++{
++ if (_active == newActiveTab) return;
++
++ if (0) kdDebug() << "MultiView::tabActivated "
++ << newActiveTab->name() << endl;
++
++ TraceItem* oldActiveItem = 0;
++ if (_active) {
++ oldActiveItem = _active->activeItem();
++ _active->setActive(false);
++ }
++ _active = newActiveTab;
++
++ // make the active item of the new TabView active
++ if (_active && (oldActiveItem != _active->activeItem()))
++ TraceItemView::activated(_active->activeItem());
++}
++
++void MultiView::selected(TraceItemView* sender, TraceItem* i)
++{
++ if (0) kdDebug() << "MultiView::selected " << i->name()
++ << ", sender " << sender->widget()->name() << endl;
++
++ // we react only on selection changes of the active TabView
++ if (sender != (TraceItemView*)_active) return;
++
++ _views.findRef(_active);
++ TabView* next = _views.next();
++ if (!next) next = _views.first();
++
++ // don't change item of active tab
++ if (next == _active) return;
++
++ next->activate(i);
++ next->updateView();
++}
++
++void MultiView::activated(TraceItemView* sender, TraceItem* i)
++{
++ if (0) kdDebug() << "MultiView::activated " << i->name()
++ << ", sender " << sender->widget()->name() << endl;
++
++ // we react only on selection changes of the active TabView
++ if (sender != (TraceItemView*)_active) return;
++
++ TraceItemView::activated(sender,i);
++}
++
++void MultiView::doUpdate(int changeType)
++{
++ TabView* tv;
++ for(tv=_views.first(); tv; tv=_views.next()) {
++ tv->set(changeType, _data, _costType, _costType2,
++ _groupType, _partList,
++ (tv == _active) ? _activeItem : tv->activeItem(),
++ tv->selectedItem());
++ tv->notifyChange(changeType);
++ if (tv->isViewVisible())
++ tv->updateView();
++ }
++}
++
++
++void MultiView::readViewConfig(KConfig* c,
++ TQString prefix, TQString postfix,
++ bool withOptions)
++{
++ if (0) qDebug("%s::readConfig(%s%s)", name(),
++ prefix.ascii(), postfix.ascii());
++
++ TQString active;
++ KConfigGroup* g = configGroup(c, prefix, postfix);
++ int n = g->readNumEntry("Panels", 1);
++ setChildCount(n);
++ setOrientation( (g->readEntry("Orientation") == TQString("Horizontal")) ?
++ Qt::Horizontal : Qt::Vertical );
++
++ setSizes(g->readIntListEntry("PanelSizes"));
++
++ active = g->readEntry("ActivePanel", "");
++ delete g;
++
++ TabView* tv, *activeTV = 0;
++ for(tv=_views.first();tv;tv=_views.next()) {
++ if (tv->name() == active) activeTV=tv;
++ tv->readViewConfig(c, TQString("%1-%2").arg(prefix).arg(tv->name()),
++ postfix, withOptions);
++ }
++
++ // activate panel after restoring
++ if (!activeTV) activeTV = _views.first();
++
++ if (_active == activeTV)
++ TraceItemView::activated(_active->activeItem());
++ else
++ activeTV->setActive(true);
++}
++
++void MultiView::saveViewConfig(KConfig* c,
++ TQString prefix, TQString postfix,
++ bool withOptions)
++{
++ KConfigGroup g(c, (prefix+postfix).ascii());
++
++ g.writeEntry("Panels", childCount());
++ g.writeEntry("Orientation",
++ (orientation() == Qt::Horizontal) ?
++ "Horizontal" : "Vertical");
++
++ g.writeEntry("PanelSizes", sizes());
++ g.writeEntry("ActivePanel", _active ? _active->name() : "none");
++
++ TabView* tv;
++ for(tv=_views.first();tv;tv=_views.next())
++ tv->saveViewConfig(c, TQString("%1-%2").arg(prefix).arg(tv->name()),
++ postfix, withOptions);
++}
++
++
++#include "multiview.moc"
+diff --git a/kdecachegrind/kdecachegrind/multiview.h b/kdecachegrind/kdecachegrind/multiview.h
+new file mode 100644
+index 0000000..9d77101
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/multiview.h
+@@ -0,0 +1,67 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * MultiView, enclosing multiple (default: 2) TabView's with a user
++ * choosable active view (i.e. focus). This is a splitter itself.
++ * Selection of the active view is shown in the next to the right view
++ * (with wrap around).
++ */
++
++#ifndef MULTIVIEW_H
++#define MULTIVIEW_H
++
++#include <tqsplitter.h>
++#include <tqptrlist.h>
++#include "traceitemview.h"
++#include "tabview.h" // because of TQPtrList<TabView>
++
++class MultiView : public TQSplitter, public TraceItemView
++{
++ Q_OBJECT
++ TQ_OBJECT
++
++public:
++ MultiView(TopLevel* top, TQWidget* parent = 0, const char* name = 0);
++
++ TQWidget* widget() { return this; }
++ TabView* activeTabView() const { return _active; }
++ void setData(TraceData*);
++
++ void appendView();
++ void removeView();
++ void setChildCount(int);
++ int childCount() { return _views.count(); }
++
++ void selected(TraceItemView*, TraceItem*);
++ void activated(TraceItemView*, TraceItem*);
++
++ void readViewConfig(KConfig*, TQString prefix, TQString postfix, bool);
++ void saveViewConfig(KConfig*, TQString prefix, TQString postfix, bool);
++
++public slots:
++ void tabActivated(TabView*);
++
++ private:
++ void doUpdate(int);
++
++ TabView* _active;
++ TQPtrList<TabView> _views;
++};
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/partgraph.cpp b/kdecachegrind/kdecachegrind/partgraph.cpp
+new file mode 100644
+index 0000000..a20f53d
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/partgraph.cpp
+@@ -0,0 +1,534 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * TracePart as Nested Area
++ */
++
++#include <klocale.h>
++
++#include "partgraph.h"
++#include "configuration.h"
++#include "listutils.h"
++
++
++// PartAreaWidget
++
++PartAreaWidget::PartAreaWidget(TQWidget* parent, const char* name)
++ : TreeMapWidget(new BasePartItem(), parent, name)
++{
++ _data = 0;
++ _function = 0;
++
++ _costType = 0;
++ _groupType = TraceCost::NoCostType;
++ _visualisation = NoVisualisation;
++ _zoomFunction = false;
++ _callLevels = 1;
++}
++
++void PartAreaWidget::setData(TraceData* data)
++{
++ if (data == _data) return;
++
++ _data = data;
++ _function = 0;
++ _hiddenParts.clear();
++
++ ((BasePartItem*)base())->setData(data);
++}
++
++void PartAreaWidget::changeHidden(const TracePartList& list)
++{
++ _hiddenParts = list;
++ base()->refresh();
++}
++
++
++void PartAreaWidget::setCostType(TraceCostType* ct)
++{
++ _costType = ct;
++
++ // this resizes items
++ base()->redraw();
++}
++
++void PartAreaWidget::setVisualisation(VisualisationMode m)
++{
++ _visualisation = m;
++ refreshParts();
++}
++
++void PartAreaWidget::setZoomFunction(bool zoomFunction)
++{
++ _zoomFunction = zoomFunction;
++ refreshParts();
++}
++
++void PartAreaWidget::setCallLevels(int callLevels)
++{
++ _callLevels = callLevels;
++ refreshParts();
++}
++
++void PartAreaWidget::refreshParts()
++{
++ // rebuild only subparts to keep part selection state
++ TreeMapItem* i;
++ TreeMapItemList* l = base()->children();
++ if (l)
++ for (i=l->first();i;i=l->next())
++ i->refresh();
++
++ // but resize part areas
++ base()->redraw();
++}
++
++
++void PartAreaWidget::setFunction(TraceFunction* f)
++{
++ _function = f;
++
++ if (_visualisation == PartAreaWidget::Inclusive)
++ refreshParts();
++}
++
++void PartAreaWidget::setGroupType(TraceCost::CostType gt)
++{
++ _groupType = gt;
++
++ // rebuild hierarchy below parts.
++ // thus, selected parts stay selected
++ TreeMapItem* i;
++ TreeMapItemList* l = base()->children();
++ if (l)
++ for (i=l->first();i;i=l->next())
++ i->refresh();
++
++ base()->redraw();
++}
++
++bool PartAreaWidget::isHidden(TracePart* part) const
++{
++ return (_hiddenParts.containsRef(part)>0);
++}
++
++TQColor PartAreaWidget::groupColor(TraceFunction* f) const
++{
++ if (!f)
++ return colorGroup().button();
++
++ return Configuration::functionColor(_groupType, f);
++}
++
++TQString PartAreaWidget::tipString(TreeMapItem* i) const
++{
++ TQString tip, itemTip;
++ int count = 0;
++
++ //qDebug("PartAreaWidget::tipString for '%s'", i->name().ascii());
++
++ // first, SubPartItem's
++ while (i && count<Configuration::maxSymbolCount() && i->rtti() == 3) {
++ itemTip = i->text(0);
++ if ((int)itemTip.length()>Configuration::maxSymbolLength())
++ itemTip = itemTip.left(Configuration::maxSymbolLength()) + "...";
++
++ if (!i->text(1).isEmpty())
++ itemTip += " (" + i->text(1) + ")";
++
++ if (!tip.isEmpty())
++ itemTip += "\n";
++
++ tip = itemTip + tip;
++ i = i->parent();
++ count++;
++ }
++
++ // skip to part
++ while (i && i->rtti()==3) i = i->parent();
++
++ if (i && i->rtti()==2) {
++ itemTip = i18n("Profile Part %1").arg(i->text(0));
++ if (!i->text(1).isEmpty())
++ itemTip += " (" + i->text(1) + ")";
++
++ if (!tip.isEmpty())
++ itemTip += "\n";
++
++ tip = itemTip + tip;
++ }
++
++// qDebug("PartAreaWidget:: tip %s, itemTip %s",
++// tip.ascii(), itemTip.ascii());
++
++ return tip;
++}
++
++
++
++
++
++// BasePartItem
++
++BasePartItem::BasePartItem()
++ : TreeMapItem()
++{
++ _data = 0;
++ setSorting(-1);
++}
++
++void BasePartItem::setData(TraceData* data)
++{
++ if (data == _data) return;
++
++ _data = data;
++ refresh();
++}
++
++TreeMapItemList* BasePartItem::children()
++{
++ if (!_data) return _children;
++
++ if (!initialized()) {
++// qDebug("Create Parts (%s)", name().ascii());
++
++ PartAreaWidget* w = (PartAreaWidget*) widget();
++ TracePart* part;
++ TracePartList l = _data->parts();
++ for (part=l.first();part;part=l.next())
++ if (!w->isHidden(part))
++ addItem(new PartItem(part));
++ }
++
++ return _children;
++}
++
++TQString BasePartItem::text(int textNo) const
++{
++ if (textNo == 0) {
++ if (!_data)
++ return i18n("(no trace)");
++
++ if (_data->parts().count() == 0)
++ return i18n("(no part)");
++ }
++ return TQString();
++}
++
++
++TQColor BasePartItem::backColor() const
++{
++ return widget()->colorGroup().base();
++}
++
++double BasePartItem::value() const
++{
++ if (!_data) return 0;
++
++ PartAreaWidget* w = (PartAreaWidget*) widget();
++ return (double)_data->subCost(w->costType());
++}
++
++
++
++
++
++// PartItem
++
++PartItem::PartItem(TracePart* p)
++{
++ _p = p;
++ _factor=1;
++}
++
++TQString PartItem::text(int textNo) const
++{
++ if (textNo == 0)
++ return _p->prettyName();
++
++ if (textNo != 1)
++ return TQString();
++
++ TraceCostType* ct;
++ PartAreaWidget* w = (PartAreaWidget*)widget();
++ SubCost v;
++
++ ct = w->costType();
++ v = _p->subCost(ct);
++
++ if (Configuration::showPercentage()) {
++ TraceCost* t = _p->data()->totals();
++ double p = 100.0 * v / t->subCost(ct);
++ return TQString("%1 %")
++ .arg(p, 0, 'f', Configuration::percentPrecision());
++ }
++ return v.pretty();
++}
++
++
++TQPixmap PartItem::pixmap(int i) const
++{
++ if (i != 1) return TQPixmap();
++
++ // Cost pixmap
++
++ TraceCostType* ct = ((PartAreaWidget*)widget())->costType();
++ return costPixmap( ct, _p, (double) (_p->data()->totals()->subCost(ct)), false );
++}
++
++
++double PartItem::value() const
++{
++ PartAreaWidget* w = (PartAreaWidget*)widget();
++ TraceCostType* ct = w->costType();
++ if ((w->visualisation() == PartAreaWidget::Inclusive) &&
++ w->zoomFunction()) {
++
++ // use value of zoomed function
++ TraceFunction* f = w->function();
++ if (f) {
++ TracePartFunction* pf = (TracePartFunction*) f->findDepFromPart(_p);
++ if (pf)
++ return (double) pf->inclusive()->subCost(ct);
++ // when function is not available in part, hide part
++ return 0.0;
++ }
++ }
++ return (double) _p->subCost(ct);
++}
++
++double PartItem::sum() const
++{
++ PartAreaWidget* w = (PartAreaWidget*)widget();
++ if (w->visualisation() == PartAreaWidget::Inclusive) {
++ double s = value();
++ //qDebug("PartItem::sum [part %s]: %d", _p->name().ascii(), s);
++ return s;
++ }
++ return 0.0;
++}
++
++TreeMapItemList* PartItem::children()
++{
++ if (initialized()) return _children;
++
++ TraceCost* c;
++// qDebug("Create Part subitems (%s)", name().ascii());
++
++ PartAreaWidget* w = (PartAreaWidget*)widget();
++ if (w->visualisation() == PartAreaWidget::Inclusive) {
++ TraceFunction* f = w->function();
++ if (f) {
++ c = f->findDepFromPart(_p);
++ if (c) addItem(new SubPartItem(c));
++ }
++
++ return _children;
++ }
++
++
++ switch( ((PartAreaWidget*)widget())->groupType() ) {
++
++ case TraceCost::Object:
++ {
++ TraceObjectMap::Iterator it;
++ for ( it = _p->data()->objectMap().begin();
++ it != _p->data()->objectMap().end(); ++it ) {
++ c = (*it).findDepFromPart(_p);
++ if (c)
++ addItem(new SubPartItem(c));
++ }
++ }
++ break;
++
++ case TraceCost::Class:
++ {
++ TraceClassMap::Iterator it;
++ for ( it = _p->data()->classMap().begin();
++ it != _p->data()->classMap().end(); ++it ) {
++ c = (*it).findDepFromPart(_p);
++ if (c)
++ addItem(new SubPartItem(c));
++ }
++ }
++ break;
++
++ case TraceCost::File:
++ {
++ TraceFileMap::Iterator it;
++ for ( it = _p->data()->fileMap().begin();
++ it != _p->data()->fileMap().end(); ++it ) {
++ c = (*it).findDepFromPart(_p);
++ if (c)
++ addItem(new SubPartItem(c));
++ }
++ }
++ break;
++
++ case TraceCost::Function:
++ {
++ TraceFunctionMap::Iterator it;
++ for ( it = _p->data()->functionMap().begin();
++ it != _p->data()->functionMap().end(); ++it ) {
++ c = (*it).findDepFromPart(_p);
++ if (c)
++ addItem(new SubPartItem(c));
++ }
++ }
++ break;
++
++ default:
++ break;
++ }
++
++ return _children;
++}
++
++
++TQColor PartItem::backColor() const
++{
++ PartAreaWidget* w = (PartAreaWidget*)widget();
++ return w->groupColor(0);
++}
++
++
++// SubPartItem
++
++SubPartItem::SubPartItem(TraceCost* c)
++{
++ _partCostItem = c;
++ _factor=1;
++}
++
++TQString SubPartItem::text(int textNo) const
++{
++ if (textNo == 0) {
++ if (!_partCostItem)
++ return i18n("(unknown)");
++
++ return _partCostItem->dependant()->prettyName();
++ }
++
++ if (textNo != 1)
++ return TQString();
++
++ TraceCostType* ct;
++ PartAreaWidget* w = (PartAreaWidget*)widget();
++ SubCost v;
++
++ ct = w->costType();
++ if (w->visualisation() == PartAreaWidget::Inclusive)
++ v = ((TracePartFunction*)_partCostItem)->inclusive()->subCost(ct);
++ else
++ v = _partCostItem->subCost(ct);
++
++ if (Configuration::showPercentage()) {
++ TraceCost* t = Configuration::showExpanded() ?
++ _partCostItem->part() : _partCostItem->part()->data()->totals();
++ double p = 100.0 * v / t->subCost(ct);
++ return TQString("%1 %")
++ .arg(p, 0, 'f', Configuration::percentPrecision());
++ }
++ return v.pretty();
++}
++
++TQPixmap SubPartItem::pixmap(int i) const
++{
++ if (i != 1) return TQPixmap();
++
++ // Cost pixmap
++
++ PartAreaWidget* w = (PartAreaWidget*)widget();
++ TraceCostType* ct = w->costType();
++ TraceCost* t = Configuration::showExpanded() ?
++ _partCostItem->part() : _partCostItem->part()->data()->totals();
++ TraceCost* c;
++ if (w->visualisation() == PartAreaWidget::Inclusive)
++ c = ((TracePartFunction*)_partCostItem)->inclusive();
++ else
++ c = _partCostItem;
++
++ return costPixmap( ct, c, (double) (t->subCost(ct)), false );
++}
++
++double SubPartItem::value() const
++{
++ TraceCostType* ct;
++ PartAreaWidget* w = (PartAreaWidget*)widget();
++
++ ct = w->costType();
++ if (w->visualisation() == PartAreaWidget::Inclusive)
++ return (double)
++ ((TracePartFunction*)_partCostItem)->inclusive()->subCost(ct);
++
++ return (double) _partCostItem->subCost(ct);
++}
++
++double SubPartItem::sum() const
++{
++ PartAreaWidget* w = (PartAreaWidget*)widget();
++ if (w->visualisation() == PartAreaWidget::Inclusive) {
++ double s = value();
++ //qDebug("SubPartItem::sum [Cost %s]: %d", _cost->name().ascii(), s);
++ return s;
++ }
++ return 0.0;
++}
++
++TreeMapItemList* SubPartItem::children()
++{
++ if (!initialized()) {
++// qDebug("Create Part sub-subitems (%s)", name().ascii());
++
++ PartAreaWidget* w = (PartAreaWidget*)widget();
++
++ if (depth()-2 > w->callLevels())
++ return _children;
++
++ if (w->visualisation() == PartAreaWidget::Inclusive) {
++ TracePartCall* call;
++ TracePartCallList l;
++
++ setSum(value());
++
++ l = ((TracePartFunction*)_partCostItem)->partCallings();
++ for (call=l.first();call;call=l.next()) {
++ TraceFunction* called = call->call()->called();
++ TraceCost* partCalled = called->findDepFromPart(call->part());
++ if (partCalled)
++ addItem(new SubPartItem(partCalled));
++ }
++ }
++ }
++
++ return _children;
++}
++
++
++TQColor SubPartItem::backColor() const
++{
++ PartAreaWidget* w = (PartAreaWidget*)widget();
++ if (w->visualisation() == PartAreaWidget::Inclusive)
++ return w->groupColor((TraceFunction*)(_partCostItem->dependant()));
++
++ return Configuration::groupColor(_partCostItem->dependant());
++}
++
++
++#include "partgraph.moc"
+diff --git a/kdecachegrind/kdecachegrind/partgraph.h b/kdecachegrind/kdecachegrind/partgraph.h
+new file mode 100644
+index 0000000..f28f12e
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/partgraph.h
+@@ -0,0 +1,132 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++/*
++ * TracePart Graph
++ */
++
++#ifndef PARTGRAPH_H
++#define PARTGRAPH_H
++
++#include "treemap.h"
++#include "tracedata.h"
++
++class PartAreaWidget: public TreeMapWidget
++{
++ Q_OBJECT
++ TQ_OBJECT
++
++public:
++ // Visualisation inside of trace parts
++ enum VisualisationMode { NoVisualisation, Partitioning, Inclusive };
++
++ PartAreaWidget(TQWidget* parent=0, const char* name=0);
++
++ void setData(TraceData* d);
++ void setCostType(TraceCostType* ct);
++ void setGroupType(TraceCost::CostType gt);
++ void setVisualisation(VisualisationMode);
++ void setZoomFunction(bool zoomFunction);
++ void setCallLevels(int callLevels);
++ void setFunction(TraceFunction* f);
++
++ TraceCostType* costType() const { return _costType; }
++ TraceCost::CostType groupType() const { return _groupType; }
++ TraceFunction* function() const { return _function; }
++ VisualisationMode visualisation() const { return _visualisation; }
++ bool zoomFunction() const { return _zoomFunction; }
++ int callLevels() const { return _callLevels; }
++
++ TQColor groupColor(TraceFunction*) const;
++ TQString tipString(TreeMapItem*) const;
++
++ void changeHidden(const TracePartList& list);
++ bool isHidden(TracePart*) const;
++
++private:
++ void refreshParts();
++
++ TraceData* _data;
++ TraceCostType* _costType;
++ TraceCost::CostType _groupType;
++ TraceFunction* _function;
++ VisualisationMode _visualisation;
++ bool _zoomFunction;
++ int _callLevels;
++
++ TracePartList _hiddenParts;
++};
++
++class BasePartItem: public TreeMapItem
++{
++public:
++ BasePartItem();
++
++ void setData(TraceData* d);
++
++ int rtti() const { return 1; }
++ double value() const;
++ TQString text(int) const;
++ int borderWidth() const { return 0; }
++ TreeMapItemList* children();
++ TQColor backColor() const;
++
++private:
++ TraceData* _data;
++};
++
++class PartItem: public TreeMapItem
++{
++public:
++ PartItem(TracePart* p);
++ int rtti() const { return 2; }
++ TracePart* part() { return _p; }
++ double value() const;
++ double sum() const;
++ int borderWidth() const { return 0; }
++ TQString text(int) const;
++ TQPixmap pixmap(int) const;
++ TreeMapItemList* children();
++ TQColor backColor() const;
++
++private:
++ TracePart* _p;
++ unsigned int _factor;
++};
++
++class SubPartItem: public TreeMapItem
++{
++public:
++ SubPartItem(TraceCost*);
++ int rtti() const { return 3; }
++ TraceCost* partCostItem() { return _partCostItem; }
++ double value() const;
++ double sum() const;
++ SplitMode splitMode() const { return Vertical; }
++ TQString text(int) const;
++ TQPixmap pixmap(int) const;
++ TreeMapItemList* children();
++ TQColor backColor() const;
++
++private:
++ TraceCost* _partCostItem;
++ unsigned int _factor;
++};
++
++
++#endif
+diff --git a/kdecachegrind/kdecachegrind/partlistitem.cpp b/kdecachegrind/kdecachegrind/partlistitem.cpp
+new file mode 100644
+index 0000000..40c2db3
+--- /dev/null
++++ b/kdecachegrind/kdecachegrind/partlistitem.cpp
+@@ -0,0 +1,189 @@
++/* This file is part of KCachegrind.
++ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
++
++ KCachegrind is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public
++ License as published by the Free Software Foundation, version 2.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; see the file COPYING. If not, write to
++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ Boston, MA 02110-1301, USA.
++*/
++
++#include <math.h>
++
++#include <tqpainter.h>
++#include <tqregexp.h>
++
++#include <klocale.h>
++#include <kiconloader.h>
++#include <kapplication.h>
++
++#include "listutils.h"
++#include "partlistitem.h"
++#include "coverage.h"
++#include "configuration.h"
++
++
++// PartListItem
++
++PartListItem::PartListItem(TQListView* parent, TraceCostItem* costItem,
++ TraceCostType* ct, TraceCost::CostType gt,
++ TracePart* part)
++ :TQListViewItem(parent)
++{
++ _partCostItem = costItem->findDepFromPart(part);
++ _part = part;
++ _groupType = gt;
++ _costType = ct;
++
++#if 0
++ TQString partName = TQString::number(part->partNumber());
++ if (part->data()->maxThreadID() >1)
++ partName += i18n(" (Thread %1)").arg(part->threadID());
++ setText(0, partName);
++#else
++ setText(0, _part->prettyName());
++#endif
++
++ if (_part->trigger().isEmpty())
++ setText(4,i18n("(none)"));
++ else
++ setText(4, _part->trigger());
++
++ update();
++}
++
++void PartListItem::setCostType(TraceCostType* ct)
++{
++ if (_costType == ct) return;
++
++ _costType = ct;