You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tde-packaging/redhat/tdesdk/kdesdk-3.5.13.1-fix_kdecach...

39684 lines
1.1 MiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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<65>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;
+ update();
+}
+
+void PartListItem::setGroupType(TraceCost::CostType gt)
+{
+ if (_groupType == gt) return;
+
+ _groupType = gt;
+ update();
+}
+
+void PartListItem::update()
+{
+ TracePartFunction* pf;
+ pf = !_partCostItem ? 0 :
+ (_partCostItem->type()==TraceCost::PartFunction) ?
+ ((TracePartFunction*)_partCostItem) : 0;
+
+ double total = _part->subCost(_costType);
+
+ TraceCost* selfTotalCost = _part;
+ if (pf && Configuration::showExpanded()) {
+ switch(_groupType) {
+ case TraceCost::Object: selfTotalCost = pf->partObject(); break;
+ case TraceCost::Class: selfTotalCost = pf->partClass(); break;
+ case TraceCost::File: selfTotalCost = pf->partFile(); break;
+ default: break;
+ }
+ }
+ double selfTotal = selfTotalCost->subCost(_costType);
+
+ _pure = _partCostItem ? _partCostItem->subCost(_costType) : SubCost(0);
+ _sum = pf ? pf->inclusive()->subCost(_costType) : SubCost(0);
+
+ if (selfTotal == 0 || !_partCostItem) {
+ setText(2, TQString("-"));
+ setPixmap(2, TQPixmap());
+ }
+ else {
+ double pure = 100.0 * _pure / selfTotal;
+ if (Configuration::showPercentage()) {
+ setText(2, TQString("%1")
+ .arg(pure, 0, 'f', Configuration::percentPrecision()));
+ }
+ else
+ setText(2, _partCostItem->prettySubCost(_costType));
+
+ setPixmap(2, costPixmap(_costType, _partCostItem, selfTotal, false));
+ }
+
+ if (total == 0 || !pf) {
+ setText(1, TQString("-"));
+ setPixmap(1, TQPixmap());
+ }
+ else {
+ 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, pf->inclusive(), total, false));
+ }
+
+ if (!pf) {
+ setText(3, TQString("-"));
+ _callers = 0;
+ return;
+ }
+
+ TracePartCall* pc;
+ TracePartCallList pl;
+ SubCost callers, callees;
+ TQString str;
+
+ callers = 0;
+ pl = pf->partCallers();
+ for (pc=pl.first();pc;pc=pl.next()) {
+ callers += pc->callCount();
+ }
+
+ if ((callers == 0) && (pf->calledContexts()>0))
+ str = i18n("(active)");
+ else
+ str = callers.pretty();
+
+ _callers = callers;
+ setText(3, str);
+}
+
+
+int PartListItem::compare(TQListViewItem * i, int col, bool ascending ) const
+{
+ PartListItem* fi = (PartListItem*) i;
+ if (col==0) {
+ int mTID = _part->data()->maxThreadID()+1;
+ int mNum = _part->data()->maxPartNumber()+1;
+
+ return
+ (_part->processID() - fi->_part->processID()) * mTID * mNum +
+ (_part->partNumber() - fi->_part->partNumber()) * mTID +
+ (_part->threadID() - fi->_part->threadID());
+ }
+ if (col==1) {
+ if (_sum < fi->_sum) return -1;
+ if (_sum > fi->_sum) return 1;
+ return 0;
+ }
+ if (col==2) {
+ if (_pure < fi->_pure) return -1;
+ if (_pure > fi->_pure) return 1;
+ return 0;
+ }
+ if (col==3) {
+ if (_callers < fi->_callers) return -1;
+ if (_callers > fi->_callers) return 1;
+ return 0;
+ }
+ return TQListViewItem::compare(i, col, ascending);
+}
diff --git a/kdecachegrind/kdecachegrind/partlistitem.h b/kdecachegrind/kdecachegrind/partlistitem.h
new file mode 100644
index 0000000..0ab99a9
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/partlistitem.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.
+*/
+
+#ifndef PARTLISTITEM_H
+#define PARTLISTITEM_H
+
+#include <tqlistview.h>
+#include "tracedata.h"
+
+/**
+ * For info tab, trace part list.
+ * Needs update on
+ * - cost type change
+ *
+ * Note: on a cost item / percentage change, the list is rebuild
+ */
+class PartListItem: public TQListViewItem
+{
+public:
+ PartListItem(TQListView* parent, TraceCostItem* costItem,
+ TraceCostType* ct, TraceCost::CostType gt, TracePart* part);
+
+ int compare(TQListViewItem * i, int col, bool ascending ) const;
+ TraceCost* partCostItem() { return _partCostItem; }
+ void setCostType(TraceCostType* ct);
+ void setGroupType(TraceCost::CostType);
+ TracePart* part() { return _part; }
+ void update();
+
+private:
+ SubCost _sum, _pure;
+ SubCost _callers;
+ TraceCostType* _costType;
+ TraceCost* _partCostItem;
+ TracePart* _part;
+ TraceCost::CostType _groupType;
+};
+
+#endif
diff --git a/kdecachegrind/kdecachegrind/partselection.cpp b/kdecachegrind/kdecachegrind/partselection.cpp
new file mode 100644
index 0000000..703dd75
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/partselection.cpp
@@ -0,0 +1,567 @@
+/* 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.
+*/
+
+/*
+ * For part file 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 <tqpopupmenu.h>
+#include <tqlayout.h>
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <kdebug.h>
+
+#include "partselection.h"
+#include "partgraph.h"
+
+PartSelection::PartSelection( TQWidget* parent, const char* name)
+ : PartSelectionBase(parent, name)
+{
+ _data = 0;
+ _costType = 0;
+ _costType2 = 0;
+ _groupType = TraceItem::NoCostType;
+ _group = 0;
+ _function = 0;
+ _inSelectionUpdate = false;
+
+ _diagramMode = false;
+ _drawFrames = true;
+
+ partAreaWidget->setAllowRotation(false);
+ partAreaWidget->setMaxSelectDepth(2);
+ partAreaWidget->setSelectionMode(TreeMapWidget::Extended);
+ partAreaWidget->setSplitMode(TreeMapItem::HAlternate);
+ partAreaWidget->setVisibleWidth(2, true);
+ partAreaWidget->setFieldType(0, i18n( "Name" ));
+ partAreaWidget->setFieldType(1, i18n( "Cost" ));
+
+ connect(partAreaWidget, TQT_SIGNAL(selectionChanged()),
+ this, TQT_SLOT(selectionChanged()));
+ connect(partAreaWidget, TQT_SIGNAL(currentChanged(TreeMapItem*, bool)),
+ this, TQT_SLOT(currentChangedSlot(TreeMapItem*, bool)));
+ connect(partAreaWidget, TQT_SIGNAL(doubleClicked(TreeMapItem*)),
+ this, TQT_SLOT(doubleClicked(TreeMapItem*)));
+ connect(partAreaWidget,
+ TQT_SIGNAL(contextMenuRequested(TreeMapItem*,const TQPoint &)),
+ this,
+ TQT_SLOT(contextMenuRequested(TreeMapItem*,const TQPoint &)));
+
+ _showInfo = true;
+ showInfo(false);
+}
+
+PartSelection::~PartSelection()
+{
+}
+
+void PartSelection::setData(TraceData* data)
+{
+ if (_data == data) return;
+
+ _data = data;
+ partAreaWidget->setData(data);
+ fillInfo();
+}
+
+
+void PartSelection::refresh()
+{
+ partAreaWidget->redraw();
+ fillInfo();
+}
+
+void PartSelection::setCostType(TraceCostType* ct)
+{
+ if (ct == _costType) return;
+ _costType = ct;
+
+ partAreaWidget->setCostType(ct);
+}
+
+void PartSelection::setCostType2(TraceCostType* ct)
+{
+ if (ct == _costType2) return;
+ _costType2 = ct;
+ if (!_diagramMode) return;
+
+ //TODO: get max cost(type1)/cost(type2) of shown parts
+ //partAreaWidget->setCostType(ct);
+}
+
+void PartSelection::setGroupType(TraceItem::CostType gt)
+{
+ if (gt == _groupType) return;
+ _groupType = gt;
+
+ partAreaWidget->setGroupType(gt);
+}
+
+void PartSelection::setGroup(TraceCostItem*)
+{
+}
+
+void PartSelection::setFunction(TraceFunction* f)
+{
+ if (_function == f) return;
+ _function = f;
+
+ //kdDebug() << "PartSelection::setFunction " << f->name() << endl;
+
+ // FIXME: The TreeMap shouldn't produce spurious selectionChanged events
+ _inSelectionUpdate = true;
+ partAreaWidget->setFunction(_function);
+ _inSelectionUpdate = false;
+}
+
+void PartSelection::setPart(TracePart*)
+{}
+
+void PartSelection::currentChangedSlot(TreeMapItem* i, bool kbd)
+{
+ if (!i) return;
+ if (!kbd) return;
+ if (i->text(0).isEmpty()) return;
+
+ TQString str = i->text(0);
+ if (!i->text(1).isEmpty())
+ str += " (" + i->text(1) + ")";
+ TQString msg = i18n("Profile Part Overview: Current is '%1'").arg(str);
+ emit showMessage(msg, 5000);
+
+ if (_showInfo) fillInfo();
+}
+
+
+void PartSelection::doubleClicked(TreeMapItem* i)
+{
+ if (!i || i->rtti() != 3) return;
+
+ TraceCost* c = ((SubPartItem*) i)->partCostItem();
+ TraceCostItem* ci = 0;
+
+ switch(c->type()) {
+ case TraceItem::PartFunction:
+ {
+ TraceFunction* f = ((TracePartFunction*)c)->function();
+ if (f)
+ emit functionChanged(f);
+ }
+ return;
+
+ case TraceItem::PartObject:
+ ci = ((TracePartObject*)c)->object();
+ break;
+ case TraceItem::PartClass:
+ ci = ((TracePartClass*)c)->cls();
+ break;
+ case TraceItem::PartFile:
+ ci = ((TracePartFile*)c)->file();
+ break;
+ default:
+ break;
+ }
+
+ if (ci)
+ emit groupChanged(ci);
+}
+
+
+void PartSelection::selectionChanged()
+{
+ if (_inSelectionUpdate) return;
+
+ kdDebug() << "PartSelection::selectionChanged" << endl;
+
+ bool something_changed = false;
+ bool nothingSelected = true;
+
+ TracePartList pList;
+ TreeMapItem* i;
+ TracePart* part;
+
+ // if nothing is selected, activate all parts
+ TreeMapItemList* list = partAreaWidget->base()->children();
+ if (!list) return;
+
+ for (i=list->first();i;i=list->next())
+ if (partAreaWidget->isSelected(i)) {
+ nothingSelected = false;
+ break;
+ }
+
+ for (i=list->first();i;i=list->next()) {
+ part = ((PartItem*)i)->part();
+ bool active = nothingSelected || partAreaWidget->isSelected(i);
+ if (active) {
+ pList.append(part);
+ something_changed = true;
+ }
+ }
+
+ if (something_changed) {
+ //qDebug("PartSelection: Something changed.");
+ emit activePartsChanged(pList);
+ }
+}
+
+/* this makes the graph selection the same to the parts in the list */
+void PartSelection::activePartsChangedSlot(const TracePartList& list)
+{
+ _inSelectionUpdate = true;
+
+ kdDebug() << "Entering PartSelection::activePartsChangedSlot" << endl;
+
+ TreeMapItem* i;
+ TreeMapItemList l = *partAreaWidget->base()->children();
+ // first deselect inactive, then select active (makes current active)
+ for (i=l.first();i;i=l.next()) {
+ TracePart* part = ((PartItem*)i)->part();
+ bool active = (list.containsRef(part)>0);
+ if (!active && partAreaWidget->isSelected(i)) {
+#if 0
+ qDebug("PartSelection::partsChangedSlot: Part %s changed to unselected.",
+ ((PartItem*)i)->part()->shortName().ascii());
+#endif
+
+ partAreaWidget->setSelected(i, false);
+ }
+ }
+ for (i=l.first();i;i=l.next()) {
+ TracePart* part = ((PartItem*)i)->part();
+ bool active = (list.containsRef(part)>0);
+ if (active && !partAreaWidget->isSelected(i)) {
+#if 0
+ qDebug("PartSelection::partsChangedSlot: Part %s changed to selected.",
+ ((PartItem*)i)->part()->shortName().ascii());
+#endif
+ partAreaWidget->setSelected(i, true);
+ }
+ }
+
+ _inSelectionUpdate = false;
+
+ kdDebug() << "Leaving PartSelection::activePartsChangedSlot" << endl;
+
+ fillInfo();
+}
+
+void PartSelection::contextMenuRequested(TreeMapItem* i,
+ const TQPoint & p)
+{
+ if (!i) return;
+
+ TQPopupMenu popup;
+ TQPopupMenu ppopup;
+ TQPopupMenu vpopup;
+
+ TQString str;
+ TreeMapItem* s = 0;
+
+ if (_data && (_data->parts().count()>1)) {
+ s = partAreaWidget->possibleSelection(i);
+ if (!s->text(0).isEmpty()) {
+ str = (partAreaWidget->isSelected(s)) ?
+ i18n("Deselect") : i18n("Select");
+ str += " '" + s->text(0) + "'";
+ popup.insertItem(str, 1);
+ }
+
+ popup.insertItem(i18n("Select All Parts"), 2);
+
+ popup.insertItem(i18n("Visible Parts"), &ppopup, 10);
+
+ ppopup.insertItem(i18n("Hide Selected Parts"), 3);
+ ppopup.insertItem(i18n("Unhide Hidden Parts"), 4);
+
+ popup.insertSeparator();
+ }
+
+ popup.insertItem(i18n("Go Back"), 99);
+ if (i->rtti() == 3) {
+ TreeMapItem* ni = i;
+ int id = 100;
+ while (ni && ni->rtti() == 3) {
+ TraceCost* c = ((SubPartItem*)ni)->partCostItem();
+ if (c->type() == TraceItem::PartFunction)
+ if ( ((TracePartFunction*)c)->function() == _function) break;
+
+ str = i18n("Select") + " '" + ni->text(0) + "'";
+ popup.insertItem(str, id);
+ ni = ni->parent();
+ id++;
+ }
+ }
+ popup.insertSeparator();
+
+ vpopup.setCheckable(true);
+ popup.insertItem(i18n("Visualization"), &vpopup, 10);
+
+ vpopup.insertItem(i18n("Partitioning Mode"), 30);
+ vpopup.insertItem(i18n("Diagram Mode"), 34);
+ vpopup.insertItem(i18n("Zoom Function"), 31);
+ vpopup.insertItem(i18n("Show Direct Calls"), 32);
+ vpopup.insertItem(i18n("Increment Shown Call Levels"), 33);
+ if (partAreaWidget->visualisation() == PartAreaWidget::Partitioning) {
+ vpopup.setItemChecked(30, true);
+ vpopup.setItemEnabled(31, false);
+ vpopup.setItemEnabled(32, false);
+ vpopup.setItemEnabled(33, false);
+ }
+ else {
+ vpopup.setItemChecked(31, partAreaWidget->zoomFunction());
+ }
+ vpopup.setItemChecked(34, _diagramMode);
+
+ vpopup.insertSeparator();
+
+ vpopup.insertItem(i18n("Draw Names"), 20);
+ vpopup.insertItem(i18n("Draw Costs"), 21);
+ vpopup.insertItem(i18n("Ignore Proportions"), 22);
+ vpopup.insertItem(i18n("Draw Frames"), 24);
+ vpopup.insertItem(i18n("Allow Rotation"), 23);
+ if (!partAreaWidget->fieldVisible(0) &&
+ !partAreaWidget->fieldVisible(1)) {
+ vpopup.setItemEnabled(22, false);
+ vpopup.setItemEnabled(23, false);
+ }
+ else {
+ vpopup.setItemChecked(20,partAreaWidget->fieldVisible(0));
+ vpopup.setItemChecked(21,partAreaWidget->fieldVisible(1));
+ vpopup.setItemChecked(22,partAreaWidget->fieldForced(0));
+ vpopup.setItemChecked(23,partAreaWidget->allowRotation());
+ vpopup.setItemChecked(24,_drawFrames);
+ }
+
+ if (_showInfo)
+ popup.insertItem(i18n("Hide Info"), 40);
+ else
+ popup.insertItem(i18n("Show Info"), 41);
+
+ int r = popup.exec(partAreaWidget->mapToGlobal(p));
+
+ if (r>=100) {
+ TreeMapItem* ci = i;
+ while (ci && r>100) {
+ ci = ci->parent();
+ r--;
+ }
+ doubleClicked(ci);
+ return;
+ }
+
+ switch(r) {
+ case 1:
+ // select/deselect part under mouse
+ partAreaWidget->setSelected(s, !partAreaWidget->isSelected(s));
+ break;
+
+ case 2:
+ // select all parts
+ {
+ TreeMapItemList list = *partAreaWidget->base()->children();
+ partAreaWidget->setRangeSelection(list.first(), list.last(), true);
+ }
+ break;
+
+ case 3:
+ emit partsHideSelected();
+ break;
+
+ case 4:
+ emit partsUnhideAll();
+ break;
+
+ case 99:
+ // last selected function
+ emit goBack();
+ break;
+
+ case 20:
+ partAreaWidget->setFieldVisible(0, !vpopup.isItemChecked(20));
+ break;
+
+ case 21:
+ partAreaWidget->setFieldVisible(1, !vpopup.isItemChecked(21));
+ break;
+
+ case 22:
+ partAreaWidget->setFieldForced(0, !vpopup.isItemChecked(22));
+ partAreaWidget->setFieldForced(1, !vpopup.isItemChecked(22));
+ break;
+
+ case 23: partAreaWidget->setAllowRotation(!vpopup.isItemChecked(23)); break;
+
+ case 24:
+ _drawFrames = !_drawFrames;
+ partAreaWidget->drawFrame(2,_drawFrames);
+ partAreaWidget->drawFrame(3,_drawFrames);
+ break;
+
+ case 30:
+ partAreaWidget->setVisualisation(!vpopup.isItemChecked(30) ?
+ PartAreaWidget::Partitioning :
+ PartAreaWidget::Inclusive);
+ break;
+
+ case 31:
+ // zoom/unzoom function
+ partAreaWidget->setZoomFunction(!vpopup.isItemChecked(31));
+ break;
+
+ case 32:
+ case 33:
+ // change call Levels
+ {
+ int l = (r==32) ? 1 : partAreaWidget->callLevels()+1;
+ partAreaWidget->setCallLevels(l);
+ }
+ break;
+
+ case 34:
+ _diagramMode = !_diagramMode;
+ partAreaWidget->setTransparent(2,_diagramMode);
+ break;
+
+
+ case 40:
+ case 41:
+ showInfo(r==41);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void PartSelection::hiddenPartsChangedSlot(const TracePartList& list)
+{
+ partAreaWidget->changeHidden(list);
+}
+
+void PartSelection::readVisualisationConfig(KConfigGroup* config)
+{
+ bool enable;
+
+ TQString mode = config->readEntry("PartitionMode", "Inclusive");
+ if (mode == "Inclusive")
+ partAreaWidget->setVisualisation(PartAreaWidget::Inclusive);
+ else
+ partAreaWidget->setVisualisation(PartAreaWidget::Partitioning);
+
+ _diagramMode = config->readBoolEntry("DiagramMode", false);
+ partAreaWidget->setTransparent(2,_diagramMode);
+
+ _drawFrames = config->readBoolEntry("DrawFrames", true);
+ partAreaWidget->drawFrame(2,_drawFrames);
+ partAreaWidget->drawFrame(3,_drawFrames);
+
+ enable = config->readBoolEntry("GraphZoom", false);
+ partAreaWidget->setZoomFunction(enable);
+
+ int levels = config->readNumEntry("GraphLevels", 1);
+ partAreaWidget->setCallLevels(levels);
+
+ enable = config->readBoolEntry("GraphDrawName", true);
+ partAreaWidget->setFieldVisible(0, enable);
+
+ enable = config->readBoolEntry("GraphDrawCost", true);
+ partAreaWidget->setFieldVisible(1, enable);
+
+ enable = config->readBoolEntry("GraphForceStrings", false);
+ partAreaWidget->setFieldForced(0, enable);
+ partAreaWidget->setFieldForced(1, enable);
+
+ enable = config->readBoolEntry("GraphAllowRotation", true);
+ partAreaWidget->setAllowRotation(enable);
+
+ showInfo(config->readBoolEntry("ShowInfo", false));
+}
+
+void PartSelection::saveVisualisationConfig(KConfigGroup* config)
+{
+ TQString mode;
+ if (partAreaWidget->visualisation() == PartAreaWidget::Inclusive)
+ mode = "Inclusive";
+ else
+ mode = "Partitioning";
+ config->writeEntry("PartitionMode", mode);
+
+ config->writeEntry("DiagramMode", _diagramMode);
+ config->writeEntry("DrawFrames", _drawFrames);
+
+ config->writeEntry("GraphZoom", partAreaWidget->zoomFunction());
+ config->writeEntry("GraphLevels", partAreaWidget->callLevels());
+ config->writeEntry("GraphDrawName", partAreaWidget->fieldVisible(0));
+ config->writeEntry("GraphDrawCosts", partAreaWidget->fieldVisible(1));
+ config->writeEntry("GraphForceStrings", partAreaWidget->fieldForced(0));
+ config->writeEntry("GraphAllowRotation", partAreaWidget->allowRotation());
+
+ config->writeEntry("ShowInfo", _showInfo);
+}
+
+void PartSelection::showInfo(bool enable)
+{
+ if (_showInfo == enable) return;
+
+ _showInfo = enable;
+ if (enable) {
+ rangeLabel->show();
+ fillInfo();
+ }
+ else
+ rangeLabel->hide();
+}
+
+void PartSelection::fillInfo()
+{
+ if (!_data) {
+ rangeLabel->setText(i18n("(no trace loaded)"));
+ return;
+ }
+
+ TQString info = _data->activePartRange();
+
+ TreeMapItem* i = partAreaWidget->current();
+ while (i && i->rtti()!=2) i = i->parent();
+ if (i) {
+ TracePart* part = ((PartItem*)i)->part();
+
+ //if (!part->trigger().isEmpty()) info += ", " + part->trigger();
+ if (!part->timeframe().isEmpty())
+ info += ", Time " + part->timeframe() + " BBs";
+ }
+ else {
+ TracePart* part = _data->parts().first();
+
+ if (part && !part->version().isEmpty())
+ info += ", Cachegrind " + part->version();
+ }
+
+
+ rangeLabel->setText(info);
+}
+
+#include "partselection.moc"
diff --git a/kdecachegrind/kdecachegrind/partselection.h b/kdecachegrind/kdecachegrind/partselection.h
new file mode 100644
index 0000000..b8a195f
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/partselection.h
@@ -0,0 +1,96 @@
+/* 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.
+*/
+
+/*
+ * PartSelection for KCachegrind
+ * For part file selection, to be put into a TQDockWindow
+ */
+
+#ifndef PARTSELECTION_H
+#define PARTSELECTION_H
+
+#include <tqobject.h>
+
+#include "partselectionbase.h"
+#include "partgraph.h"
+#include "tracedata.h"
+
+class KConfigGroup;
+class TraceFunction;
+class TraceData;
+class TreeMapItem;
+
+class PartSelection: public PartSelectionBase
+{
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+ PartSelection( TQWidget* parent = 0, const char* name = 0);
+ ~PartSelection();
+
+ TraceData* data() { return _data; }
+ void setData(TraceData*);
+
+ PartAreaWidget* graph() { return partAreaWidget; }
+
+ void readVisualisationConfig(KConfigGroup*);
+ void saveVisualisationConfig(KConfigGroup*);
+
+signals:
+ void activePartsChanged(const TracePartList& list);
+ void partsHideSelected();
+ void partsUnhideAll();
+ void groupChanged(TraceCostItem*);
+ void functionChanged(TraceItem*);
+ void showMessage(const TQString&, int);
+ void goBack();
+
+public slots:
+ void selectionChanged();
+ void doubleClicked(TreeMapItem*);
+ void contextMenuRequested(TreeMapItem*, const TQPoint &);
+ void currentChangedSlot(TreeMapItem*, bool);
+
+ void setPart(TracePart*);
+ void setCostType(TraceCostType*);
+ void setCostType2(TraceCostType*);
+ void setGroupType(TraceItem::CostType);
+ void setGroup(TraceCostItem*);
+ void setFunction(TraceFunction*);
+ void activePartsChangedSlot(const TracePartList& list);
+ void hiddenPartsChangedSlot(const TracePartList& list);
+ void refresh();
+ void showInfo(bool);
+
+private:
+ void fillInfo();
+
+ TraceData* _data;
+ TraceCostType *_costType, *_costType2;
+ TraceItem::CostType _groupType;
+ TraceCostItem* _group;
+ TraceFunction* _function;
+ bool _showInfo;
+ bool _diagramMode;
+ bool _drawFrames;
+
+ bool _inSelectionUpdate;
+};
+
+#endif
diff --git a/kdecachegrind/kdecachegrind/partselectionbase.ui b/kdecachegrind/kdecachegrind/partselectionbase.ui
new file mode 100644
index 0000000..53320d5
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/partselectionbase.ui
@@ -0,0 +1,89 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>PartSelectionBase</class>
+<widget class="TQWidget">
+ <property name="name">
+ <cstring>PartSelectionBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>460</width>
+ <height>402</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Parts Overview</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>6</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="PartAreaWidget">
+ <property name="name">
+ <cstring>partAreaWidget</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>50</height>
+ </size>
+ </property>
+ </widget>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>rangeLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>(no trace parts)</string>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>PartAreaWidget</class>
+ <header location="local">partgraph.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>7</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="XPM.GZ" length="5230">789c9597db4e1d4b0e86eff31428be8b46b5fb54dd551acd051020211c4320c0682eecaa5e9ccf90005bf3ee53cbbfe9d9c9c548a38ea27c2977b5cbfe6dd7fae3c3c2e1cee6c2873fde3d3cf2e3595a48a77cbff0213f5d5dbdfcf35ffff8f3ddfba65998fff161a179ffb777ef771f17d2c2d6cdf53807c705a889cdac6ee72c47736eebd637b5f2b672d70ecd30e744ca7d9b9a4ad7579587363433e527e5d072abefbb03636978ceb4a31c5bc13a91716ad41f89e0aec2fe74abcc6d6ad5f9e4945357375ef75f997357751dd61d19c71afb61bdef421b951f274ebaffb6716cb3f2b2f230f18d3183dd95b1b441d7d59f2e94757ccf1b27eceff69563618d0f5dcfd9d7beeb7a5dd7f3fac6fb4ee32b87c619f1168d976f7d6ff6df26d6ef4b301e1bac7f54f63e747a5e87f5c173276aff605c22a8fefc540e5e3af5972f956359577bf2c6d978cb78d6697edc9eb2f8b143fed7945359d778b0e6c3e7be81bf7465dce23cf4ac3c16567f19fecefaae53bd081b7baccbb131b7d05f679ca03f27c6b9d1f388c6bbaffab7f80dca4d1fed7bfafdbeedb9533d490f1e2ae8d5693ccacb83d77cd027e3d4416faa97beefa3d7f8f086f168f9d9020f43a3f5c5aa877e28eb88f74fe319becfaa873e0c15de775f95639f3dec37c143d361bf2be3cef4b76bdcb7d84ff5d2cbd0227facf1ecd360fa67d54b9f078ffcd10f636e11ff53e3847853ad3c1b668837e9fe43358c2df45a81430b3db2e6676842d368fd48abdc068b87e0fd2e788bf792b21f861e7afd0e0e5ce37dcdd7d0872218e5d789f57b3218a71ae7bb501eca3af67b510e21c05fd27a1b6218ac3ef17d0ed68fe8cb1be3fc6e5159863ca0bfed824340fe687d62c4838c23f677f0370de380fcdd2be7e03dfab1d6cf300bcd80fa80bfb358dbf9547fa18abe413d68fe421d63ade7737aded094cf63fdcc38f4d0bfee17dac2d08380a3a0dff24cb90bdc23ffaa87e0636c912fed87612e38d4df1e982bc4dbdd29872001f14aca319413eb793e83cbfbe8af27606e4c0f5f8d3bcb7763ec6b8da73b57e69083d61f9d82b9b5fada31f635fcaf8d7b7b5ffb41f16e34ff34fe214dfc0c8e1ef1a22330bfcdc345e31e4c33e3c1e6e181b1609e3ac43f8759803e8cd9f2e7e0ff18ab80ef5d8239e2fc0ef129f90ff0bf0773347fee8d13ce279bc6b34af5c61abf58157bf4b765b05435f4abfec726968c2b67e536fa80fe388279067f680d2c750dff75fe9766da07e44bc02521ba4e1d584c1fb261dcc23fd97f63f8c3af136bfc687362c4e76962ed8fac7a2ecdb7853f7c63ec6bf467bd3fc421c680780c60b6f9275fc045aea84fadaf18a2e0fc04ff0237bd9e8fefc0d236e8ef3f8d83c57fdd38daf94edeb886be74fec618b3ed7f3731e66b0fe67a403e76c0454ef8de9231dbfe9f8dc5fc47be38a6887ad2f950964d2fdc1a27d3c7b6710693f6ef9864b4fdb4ffc6cc5540fea0972c339c87afc1c9f4443a5fe2c84d40bd2f82cb3ae6c7b1716dbc37b1e68bf5be118b7e3dead78125d87d0bfa99bd7d8fb78c1bdb4fcfcfd51bcb9d716bebda3fb8966cf7cf57709103f2e327c6fe5a2fdc4ab4fb01deef5283fa65d50ffb54c13fd67ec37d61e845fb070f8571df7c341eec7e7a691c6ae453fb771937d1fa999ebfa43358bf573d3327c6fdd0a9de59b87414e59f60911ef3ff07380d16bf0b63b6fbb8ce0f4e523a80ee8ff8a5f21fe83f384f2e8cf9d419db7d4bb4bff32cb1dd871ae38c79417962dd9f8f2786bfaa3fa992ddbf68d5d8d6797d62dc27b4bf4a9bdeee5be7c619efbb169c2b9bb7aa67e972857a67d59bf8943cf4a6f5237dae3b9c3f4f8cef5713637e6a3c6548e546a7eb87e0b28e7cf7c68ddd2fb15f28acf166bd2f484c19f921f8cbc57de84ff52c397b8f7e178d7bbb7f7e9f18f743d593ccd210d12f9e8c05fd8417c1e5e704e2afefa7aa5cf850ff4fc6a1473debfc4d7561c4ebd3c48897f69fd4e4d8eb7e4efb736a0b23fe9adfd465bb3f388d6ff22933fa1df6f7597ad483c62371f6e6ff8671b6f89e198fb8cfb0ea3f49619c6f6562cc27d5474a7906e6b589d1df549f29e78479450fe0b1c2fc67d5731a0ba33ffc97a167fd7d92ebb1b1f9a87acdcdd8a23ff2e3c4a81fed0fb91bbb88f8e9f772f9b9c6b8bfac187bd41febbcc8c35831f4bb6edc227eeec8b847bc58ef0f398d91a1179d6f391746bdebfd60ac4716b0180bd8a97e473f8ea2dfdb7d9c3f8e1cff8f8760057b27e57f92cb6e743377e24efff29cb97377e12edd55b190c99eddb5bb71b7eeceddbb07f7e89edc0ff7d33dbb17f7ea16dd925b761fdd8a63d8174f52b15e756bee93fbecd6dd17b7e136dd96db763b6ed77d2dd67bee9bdb77078ed49e8b27b7c5fabb3b7447eed855ae768d6bcbd339ef7a37b8e022392a2734fbd1dd119350a24c23cde8844ee98ccee9c2f9c2977445d77443b793fd8ceee89e1ee8919ee807fdb4e7995ee8b5d82fd252b15ffe8bfd097da4155aa535fa34597fa6f5f2f717da28f69bb445dbb433d99fd22e7da53dfa3659efd3017da7c3f2af233aa68aeadfec1b6aa9236fd63d0d14ca15c0719913737b965fedcbf0c83cc29a677cc2a77cc6e77cc1977cc5d7c5fee637fbdbb2db9d5adff343b17ee427fec1737ee69762fffa9bfd222ff17259fdc82bbcca6bfc893ff33a7fe10ddee42ddee69ddfec77f92beff137dee703fece877cc4c7aee58a6b6ee8b8fc10ed7eb13f635f9a4bc5e54719477152ba671977a505c84845c57222a7bfd89fcb999ccb855cca955cbfc5546ee456ee68b14cf67b799047799aec2fdc92fc28999cef567224cff222afb2c85b32e36d599265f9282bb23ad95fba6559934f2593f3e798b74acc8fd5f6b3accb17d9904dd9926db3a7520d1fdd37d9915df95a72599e1291566df7e49beccb817c974339829eb55e56dc7e51ec0d2dcbb1545297a791563af1c5eff2d3beb4faf8562f568f0744745b9e9d5f1f7992d5e412a186ffef7afff7dfdffd077c99ae99</data>
+ </image>
+</images>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kdecachegrind/kdecachegrind/partview.cpp b/kdecachegrind/kdecachegrind/partview.cpp
new file mode 100644
index 0000000..3f344bb
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/partview.cpp
@@ -0,0 +1,235 @@
+/* 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.
+*/
+
+/*
+ * Part View
+ */
+
+#include <tqwhatsthis.h>
+#include <tqpopupmenu.h>
+#include <tqheader.h>
+#include <klocale.h>
+
+#include "configuration.h"
+#include "partlistitem.h"
+#include "toplevel.h"
+#include "partview.h"
+
+
+
+//
+// PartView
+//
+
+
+PartView::PartView(TraceItemView* parentView,
+ TQWidget* parent, const char* name)
+ : TQListView(parent, name), TraceItemView(parentView)
+{
+ _inSelectionUpdate = false;
+
+ addColumn( i18n( "Profile Part" ) );
+ addColumn( i18n( "Incl." ) );
+ addColumn( i18n( "Self" ) );
+ addColumn( i18n( "Called" ) );
+ //addColumn( i18n( "Fixed" ) );
+ addColumn( i18n( "Comment" ) );
+
+ setAllColumnsShowFocus(true);
+ setColumnAlignment(1, TQt::AlignRight);
+ setColumnAlignment(2, TQt::AlignRight);
+ setColumnAlignment(3, TQt::AlignRight);
+ setMinimumHeight(50);
+ setSelectionMode(Extended);
+
+ connect( this,
+ TQT_SIGNAL( selectionChanged() ),
+ TQT_SLOT( selectionChangedSlot() ) );
+
+ connect( this,
+ TQT_SIGNAL(contextMenuRequested(TQListViewItem*, const TQPoint &, int)),
+ TQT_SLOT(context(TQListViewItem*, const TQPoint &, int)));
+
+ TQWhatsThis::add( this, whatsThis() );
+}
+
+TQString PartView::whatsThis() const
+{
+ return i18n( "<b>Trace Part List</b>"
+ "<p>This list shows all trace parts of the loaded "
+ "trace. For each part, the "
+ "self/inclusive cost of the current selected "
+ "function, spent in the part, is shown; "
+ "percentage costs are always relative to the "
+ "total cost <em>of the part</em> (not to the whole "
+ "trace as in the Trace Part Overview). "
+ "Also shown are the calls happening to/from the "
+ "current function inside of the trace part.</p>"
+ "<p>By choosing one or more trace parts from the "
+ "list, the costs shown all over KCachegrind will "
+ "only be the ones spent in the selected part(s). "
+ "If no list selection is shown, in fact all trace "
+ "parts are selected implicitly.</p>"
+ "<p>This is a multi-selection list. You can select "
+ "ranges by dragging the mouse or use SHIFT/CTRL "
+ "modifiers. "
+ "Selection/Deselection of trace parts can also be "
+ "done by using the Trace Part Overview Dockable. "
+ "This one also supports multiple selection.</p>"
+ "<p>Note that the list is hidden if only one trace "
+ "part is loaded.</p>");
+}
+
+
+void PartView::context(TQListViewItem* i, const TQPoint & pos, int)
+{
+ TQPopupMenu popup;
+
+ TracePart* p = i ? ((PartListItem*) i)->part() : 0;
+
+ if (p) {
+ popup.insertItem(i18n("Select '%1'").arg(p->name()), 93);
+ popup.insertItem(i18n("Hide '%1'").arg(p->name()), 94);
+ popup.insertSeparator();
+ }
+
+ popup.insertItem(i18n("Hide Selected"), 95);
+ popup.insertItem(i18n("Show All"), 96);
+ popup.insertSeparator();
+
+ addGoMenu(&popup);
+
+ int r = popup.exec(pos);
+ if (r == 95) {
+ ;
+ }
+
+ // TODO: ...
+}
+
+void PartView::selectionChangedSlot()
+{
+ if (_inSelectionUpdate) return;
+
+ TracePartList l;
+ TQListViewItem* item = firstChild();
+ for(;item;item = item->nextSibling())
+ if (item->isSelected())
+ l.append( ((PartListItem*)item)->part() );
+
+ selected(l);
+}
+
+
+TraceItem* PartView::canShow(TraceItem* i)
+{
+ if (!TraceItemView::data()) return 0;
+ if (TraceItemView::data()->parts().count()>1) return i;
+ return 0;
+}
+
+void PartView::doUpdate(int changeType)
+{
+ // Special case ?
+ if (changeType == costType2Changed) return;
+ if (changeType == selectedItemChanged) return;
+
+ if (changeType == groupTypeChanged) {
+ TQListViewItem *item;
+ for (item = firstChild();item;item = item->nextSibling())
+ ((PartListItem*)item)->setGroupType(_groupType);
+
+ return;
+ }
+
+ if (changeType == costTypeChanged) {
+ TQListViewItem *item;
+ for (item = firstChild();item;item = item->nextSibling())
+ ((PartListItem*)item)->setCostType(_costType);
+
+ return;
+ }
+
+ if (changeType == partsChanged) {
+
+ TracePart* part;
+
+ TQListViewItem* item;
+ _inSelectionUpdate = true;
+ item = firstChild();
+ for(;item;item = item->nextSibling()) {
+ part = ((PartListItem*)item)->part();
+
+ if (_partList.containsRef(part)>0) {
+ setSelected(item, true);
+ ensureItemVisible(item);
+ }
+ else
+ setSelected(item, false);
+ }
+ _inSelectionUpdate = false;
+
+ return;
+ }
+
+ refresh();
+}
+
+void PartView::refresh()
+{
+ clear();
+ setColumnWidth(1, 50);
+ setColumnWidth(2, 50);
+
+ if (!_data || !_activeItem) return;
+
+ TraceItem::CostType t = _activeItem->type();
+ TraceFunction* f = 0;
+ if (t == TraceItem::Function) f = (TraceFunction*) _activeItem;
+ if (!f) return;
+
+ TracePart* part;
+ TracePartList hidden;
+ if (_topLevel)
+ hidden = _topLevel->hiddenParts();
+
+ TracePartList allParts = _data->parts();
+
+ _inSelectionUpdate = true;
+
+ TQListViewItem* item = 0;
+ for (part = allParts.first(); part; part = allParts.next()) {
+ if (hidden.findRef(part)>=0) continue;
+ item = new PartListItem(this, f, _costType, _groupType, part);
+
+ if (part->isActive()) {
+ setSelected(item, true);
+ ensureItemVisible(item);
+ }
+ }
+
+ _inSelectionUpdate = false;
+
+ if (item) {
+ int headerHeight = header()->height();
+ int itemHeight = item->height();
+ setMinimumHeight(headerHeight + 2*itemHeight + 2);
+ }
+}
+
+#include "partview.moc"
diff --git a/kdecachegrind/kdecachegrind/partview.h b/kdecachegrind/kdecachegrind/partview.h
new file mode 100644
index 0000000..92761cc
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/partview.h
@@ -0,0 +1,55 @@
+/* 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.
+*/
+
+/*
+ * Part View
+ */
+
+#ifndef PARTVIEW_H
+#define PARTVIEW_H
+
+#include <tqlistview.h>
+#include "tracedata.h"
+#include "traceitemview.h"
+
+class PartView: public TQListView, public TraceItemView
+{
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+ PartView(TraceItemView* parentView,
+ TQWidget* parent=0, const char* name=0);
+
+ virtual TQWidget* widget() { return this; }
+ TQString whatsThis() const;
+
+ void refresh();
+
+private slots:
+ void context(TQListViewItem*,const TQPoint &, int);
+ void selectionChangedSlot();
+
+private:
+ TraceItem* canShow(TraceItem*);
+ void doUpdate(int);
+
+ bool _inSelectionUpdate;
+};
+
+#endif
diff --git a/kdecachegrind/kdecachegrind/pool.cpp b/kdecachegrind/kdecachegrind/pool.cpp
new file mode 100644
index 0000000..d4a89a7
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/pool.cpp
@@ -0,0 +1,258 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002-2004 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 <string.h>
+#include <stdlib.h>
+#include <tqglobal.h>
+#include "pool.h"
+
+// FixPool
+
+#define CHUNK_SIZE 100000
+
+struct SpaceChunk
+{
+ struct SpaceChunk* next;
+ unsigned int used;
+ char space[1];
+};
+
+FixPool::FixPool()
+{
+ _first = _last = 0;
+ _reservation = 0;
+ _count = 0;
+ _size = 0;
+}
+
+FixPool::~FixPool()
+{
+ struct SpaceChunk* chunk = _first, *next;
+
+ while(chunk) {
+ next = chunk->next;
+ free(chunk);
+ chunk = next;
+ }
+
+ if (0) qDebug("~FixPool: Had %d objects with total size %d\n",
+ _count, _size);
+}
+
+void* FixPool::allocate(unsigned int size)
+{
+ if (!ensureSpace(size)) return 0;
+
+ _reservation = 0;
+ void* result = _last->space + _last->used;
+ _last->used += size;
+
+ _count++;
+ _size += size;
+
+ return result;
+}
+
+void* FixPool::reserve(unsigned int size)
+{
+ if (!ensureSpace(size)) return 0;
+ _reservation = size;
+
+ return _last->space + _last->used;
+}
+
+
+bool FixPool::allocateReserved(unsigned int size)
+{
+ if (_reservation < size) return false;
+
+ _reservation = 0;
+ _last->used += size;
+
+ _count++;
+ _size += size;
+
+ return true;
+}
+
+bool FixPool::ensureSpace(unsigned int size)
+{
+ if (_last && _last->used + size <= CHUNK_SIZE) return true;
+
+ struct SpaceChunk* newChunk;
+
+ // we don't allow allocation sizes > CHUNK_SIZE
+ if (size > CHUNK_SIZE) return false;
+
+ newChunk = (struct SpaceChunk*) malloc(sizeof(struct SpaceChunk) +
+ CHUNK_SIZE);
+ newChunk->next = 0;
+ newChunk->used = 0;
+
+ if (!_last) {
+ _last = _first = newChunk;
+ }
+ else {
+ _last->next = newChunk;
+ _last = newChunk;
+ }
+ return true;
+}
+
+
+// DynPool
+
+DynPool::DynPool()
+{
+ _data = (char*) malloc(CHUNK_SIZE);
+ _used = 0;
+ _size = CHUNK_SIZE;
+
+ // end marker
+ *(int*)_data = 0;
+}
+
+DynPool::~DynPool()
+{
+ // we could check for correctness by iteration over all objects
+
+ ::free(_data);
+}
+
+bool DynPool::allocate(char** ptr, unsigned int size)
+{
+ // round up to multiple of 4
+ size = (size+3) & ~3;
+
+ /* need 12 bytes more:
+ * - 4 bytes for forward chain
+ * - 4 bytes for pointer to ptr
+ * - 4 bytes as end marker (not used for new object)
+ */
+ if (!ensureSpace(size + 12)) return false;
+
+ char** obj = (char**) (_data+_used);
+ obj[0] = (char*)(_data + _used + size + 8);
+ obj[1] = (char*)ptr;
+ *(int*)(_data+_used+size+8) = 0;
+ *ptr = _data+_used+8;
+
+ _used += size + 8;
+
+ return true;
+}
+
+void DynPool::free(char** ptr)
+{
+ if (!ptr ||
+ !*ptr ||
+ (*(char**)(*ptr - 4)) != (char*)ptr )
+ qFatal("Chaining error in DynPool::free");
+
+ (*(char**)(*ptr - 4)) = 0;
+ *ptr = 0;
+}
+
+bool DynPool::ensureSpace(unsigned int size)
+{
+ if (_used + size <= _size) return true;
+
+ unsigned int newsize = _size *3/2 + CHUNK_SIZE;
+ char* newdata = (char*) malloc(newsize);
+
+ unsigned int freed = 0, len;
+ char **p, **pnext, **pnew;
+
+ qDebug("DynPool::ensureSpace size: %d => %d, used %d. %p => %p",
+ _size, newsize, _used, _data, newdata);
+
+ pnew = (char**) newdata;
+ p = (char**) _data;
+ while(*p) {
+ pnext = (char**) *p;
+ len = (char*)pnext - (char*)p;
+
+ if (0) qDebug(" [%8p] Len %d (ptr %p), freed %d (=> %p)",
+ p, len, p[1], freed, pnew);
+
+ /* skip freed space ? */
+ if (p[1] == 0) {
+ freed += len;
+ p = pnext;
+ continue;
+ }
+
+ // new and old still at same address ?
+ if (pnew == p) {
+ pnew = p = pnext;
+ continue;
+ }
+
+ // copy object
+ pnew[0] = (char*)pnew + len;
+ pnew[1] = p[1];
+ memcpy((char*)pnew + 8, (char*)p + 8, len-8);
+
+ // update pointer to object
+ char** ptr = (char**) p[1];
+ if (*ptr != ((char*)p)+8)
+ qFatal("Chaining error in DynPool::ensureSpace");
+ *ptr = ((char*)pnew)+8;
+
+ pnew = (char**) pnew[0];
+ p = pnext;
+ }
+ pnew[0] = 0;
+
+ unsigned int newused = (char*)pnew - (char*)newdata;
+ qDebug("DynPool::ensureSpace size: %d => %d, used %d => %d (%d freed)",
+ _size, newsize, _used, newused, freed);
+
+ ::free(_data);
+ _data = newdata;
+ _size = newsize;
+ _used = newused;
+
+ return true;
+}
+
+/* Testing the DynPool
+int main()
+{
+ char* bufs[CHUNK_SIZE];
+ int i;
+
+ DynPool p;
+
+ for(i=0;i<CHUNK_SIZE;i++) {
+ p.allocate(bufs+i, 10+i%10);
+ if (((i%3)==0) && (i>20))
+ p.free(bufs+i-20);
+ }
+
+ for(i=0;i<CHUNK_SIZE;i++) {
+ if ((bufs[i]==0) || ((i%7)==0)) continue;
+ p.free(bufs+i);
+ }
+
+ for(i=0;i<CHUNK_SIZE;i++) {
+ if (bufs[i]) continue;
+ p.allocate(bufs+i, 10+i%10);
+ }
+}
+*/
diff --git a/kdecachegrind/kdecachegrind/pool.h b/kdecachegrind/kdecachegrind/pool.h
new file mode 100644
index 0000000..c9d70c1
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/pool.h
@@ -0,0 +1,107 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002-2004 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 POOL_H
+#define POOL_H
+
+/**
+ * Pool objects: containers for many small objects.
+ */
+
+struct SpaceChunk;
+
+/**
+ * FixPool
+ *
+ * For objects with fixed size and life time
+ * ending with that of the pool.
+ */
+class FixPool
+{
+ public:
+ FixPool();
+ ~FixPool();
+
+ /**
+ * Take <size> bytes from the pool
+ */
+ void* allocate(unsigned int size);
+
+ /**
+ * Reserve space. If you call allocateReservedSpace(realsize)
+ * with realSize < reserved size directly after, you
+ * will get the same memory area.
+ */
+ void* reserve(unsigned int size);
+
+ /**
+ * Before calling this, you have to reserve at least <size> bytes
+ * with reserveSpace().
+ */
+ bool allocateReserved(unsigned int size);
+
+ private:
+ /* Checks that there is enough space in the last chunk.
+ * Returns false if this is not possible.
+ */
+ bool ensureSpace(unsigned int);
+
+ struct SpaceChunk *_first, *_last;
+ unsigned int _reservation;
+ int _count, _size;
+};
+
+/**
+ * DynPool
+ *
+ * For objects which probably need to be resized
+ * in the future. Objects also can be deleted to free up space.
+ * As objects can also be moved in a defragmentation step,
+ * access has to be done via the given pointer object.
+ */
+class DynPool
+{
+ public:
+ DynPool();
+ ~DynPool();
+
+ /**
+ * Take <size> bytes from the pool, changing <*ptr>
+ * to point to this allocated space.
+ * <*ptr> will be changed if the object is moved.
+ * Returns false if no space available.
+ */
+ bool allocate(char** ptr, unsigned int size);
+
+ /**
+ * To resize, first allocate new space, and free old
+ * afterwards.
+ */
+ void free(char** ptr);
+
+ private:
+ /* Checks that there is enough space. If not,
+ * it compactifies, possibly moving objects.
+ */
+ bool ensureSpace(unsigned int);
+
+ char* _data;
+ unsigned int _used, _size;
+};
+
+#endif // POOL_H
diff --git a/kdecachegrind/kdecachegrind/sourceitem.cpp b/kdecachegrind/kdecachegrind/sourceitem.cpp
new file mode 100644
index 0000000..305b824
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/sourceitem.cpp
@@ -0,0 +1,444 @@
+/* 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 source view.
+ */
+
+#include <tqpixmap.h>
+#include <tqregexp.h>
+#include <tqpainter.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kapplication.h>
+
+#include "configuration.h"
+#include "listutils.h"
+#include "sourceview.h"
+#include "sourceitem.h"
+
+
+// SourceItem
+
+// for source lines
+SourceItem::SourceItem(SourceView* sv, TQListView* parent,
+ int fileno, unsigned int lineno,
+ bool inside, const TQString& src,
+ TraceLine* line)
+ : TQListViewItem(parent)
+{
+ _view = sv;
+ _lineno = lineno;
+ _fileno = fileno;
+ _inside = inside;
+ _line = line;
+ _lineCall = 0;
+ _lineJump = 0;
+
+ if (src == "...")
+ setText(0, src);
+ else
+ setText(0, TQString::number(lineno));
+
+ TQString s = src;
+ setText(4, s.replace( TQRegExp("\t"), " " ));
+
+ updateGroup();
+ updateCost();
+}
+
+// for call lines
+SourceItem::SourceItem(SourceView* sv, TQListViewItem* parent,
+ int fileno, unsigned int lineno,
+ TraceLine* line, TraceLineCall* lineCall)
+ : TQListViewItem(parent)
+{
+ _view = sv;
+ _lineno = lineno;
+ _fileno = fileno;
+ _inside = true;
+ _line = line;
+ _lineCall = lineCall;
+ _lineJump = 0;
+
+ //qDebug("SourceItem: (file %d, line %d) Linecall to %s",
+ // fileno, lineno, _lineCall->call()->called()->prettyName().ascii());
+
+ SubCost cc = _lineCall->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(_lineCall->call()->calledName());
+ TraceFunction* calledF = _lineCall->call()->called();
+ calledF->addPrettyLocation(callStr);
+
+ setText(4, callStr);
+
+ updateGroup();
+ updateCost();
+}
+
+// for jump lines
+SourceItem::SourceItem(SourceView* sv, TQListViewItem* parent,
+ int fileno, unsigned int lineno,
+ TraceLine* line, TraceLineJump* lineJump)
+ : TQListViewItem(parent)
+{
+ _view = sv;
+ _lineno = lineno;
+ _fileno = fileno;
+ _inside = true;
+ _line = line;
+ _lineCall = 0;
+ _lineJump = lineJump;
+
+ //qDebug("SourceItem: (file %d, line %d) Linecall to %s",
+ // fileno, lineno, _lineCall->call()->called()->prettyName().ascii());
+
+ TQString to;
+ if (_lineJump->lineTo()->functionSource() == _line->functionSource())
+ to = _lineJump->lineTo()->name();
+ else
+ to = _lineJump->lineTo()->prettyName();
+
+ TQString jStr;
+ if (_lineJump->isCondJump())
+ jStr = i18n("Jump %1 of %2 times to %3")
+ .arg(_lineJump->followedCount().pretty())
+ .arg(_lineJump->executedCount().pretty())
+ .arg(to);
+ else
+ jStr = i18n("Jump %1 times to %2")
+ .arg(_lineJump->executedCount().pretty())
+ .arg(to);
+
+ setText(4, jStr);
+}
+
+
+void SourceItem::updateGroup()
+{
+ if (!_lineCall) return;
+
+ TraceFunction* f = _lineCall->call()->called();
+ TQColor c = Configuration::functionColor(_view->groupType(), f);
+ setPixmap(4, colorPixmap(10, 10, c));
+}
+
+void SourceItem::updateCost()
+{
+ _pure = SubCost(0);
+ _pure2 = SubCost(0);
+
+ if (!_line) return;
+ if (_lineJump) return;
+
+ TraceCost* lineCost = _lineCall ? (TraceCost*)_lineCall : (TraceCost*)_line;
+
+ // don't show any cost inside of cycles
+ if (_lineCall &&
+ ((_lineCall->call()->inCycle()>0) ||
+ (_lineCall->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 = _line->functionSource()->function()->inclusive();
+ else
+ totalCost = _line->functionSource()->function()->data();
+
+ TraceCostType* ct = _view->costType();
+ _pure = ct ? lineCost->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, lineCost, total, false));
+ }
+
+ TraceCostType* ct2 = _view->costType2();
+ _pure2 = ct2 ? lineCost->subCost(ct2) : SubCost(0);
+ if (_pure2 == 0) {
+ setText(2, TQString());
+ setPixmap(2, TQPixmap());
+ }
+ else {
+ double total = totalCost->subCost(ct2);
+ double pure2 = 100.0 * _pure2 / total;
+
+ if (Configuration::showPercentage())
+ setText(2, TQString("%1")
+ .arg(pure2, 0, 'f', Configuration::percentPrecision()));
+ else
+ setText(2, _pure2.pretty());
+
+ setPixmap(2, costPixmap(ct2, lineCost, total, false));
+ }
+}
+
+
+int SourceItem::compare(TQListViewItem * i, int col, bool ascending ) const
+{
+ const SourceItem* si1 = this;
+ const SourceItem* si2 = (SourceItem*) i;
+
+ // we always want descending order
+ if (((col>0) && ascending) ||
+ ((col==0) && !ascending) ) {
+ si1 = si2;
+ si2 = this;
+ }
+
+ if (col==1) {
+ if (si1->_pure < si2->_pure) return -1;
+ if (si1->_pure > si2->_pure) return 1;
+ return 0;
+ }
+ if (col==2) {
+ if (si1->_pure2 < si2->_pure2) return -1;
+ if (si1->_pure2 > si2->_pure2) return 1;
+ return 0;
+ }
+ if (col==0) {
+ // Sort file numbers
+ if (si1->_fileno < si2->_fileno) return -1;
+ if (si1->_fileno > si2->_fileno) return 1;
+
+ // Sort line numbers
+ if (si1->_lineno < si2->_lineno) return -1;
+ if (si1->_lineno > si2->_lineno) return 1;
+
+ // Same line: code gets above calls/jumps
+ if (!si1->_lineCall && !si1->_lineJump) return -1;
+ if (!si2->_lineCall && !si2->_lineJump) return 1;
+
+ // calls above jumps
+ if (si1->_lineCall && !si2->_lineCall) return -1;
+ if (si2->_lineCall && !si1->_lineCall) return 1;
+
+ if (si1->_lineCall && si2->_lineCall) {
+ // Two calls: desending sort according costs
+ if (si1->_pure < si2->_pure) return 1;
+ if (si1->_pure > si2->_pure) return -1;
+
+ // Two calls: sort according function names
+ TraceFunction* f1 = si1->_lineCall->call()->called();
+ TraceFunction* f2 = si2->_lineCall->call()->called();
+ if (f1->prettyName() > f2->prettyName()) return 1;
+ return -1;
+ }
+
+ // Two jumps: descending sort according target line
+ if (si1->_lineJump->lineTo()->lineno() <
+ si2->_lineJump->lineTo()->lineno())
+ return -1;
+ if (si1->_lineJump->lineTo()->lineno() >
+ si2->_lineJump->lineTo()->lineno())
+ return 1;
+ return 0;
+ }
+ return TQListViewItem::compare(i, col, ascending);
+}
+
+void SourceItem::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 ((_lineCall || _lineJump) && column>2)
+ _cg.setColor( TQColorGroup::Base, cg.midlight() );
+
+ if (column == 3)
+ paintArrows(p, _cg, width);
+ else
+ TQListViewItem::paintCell( p, _cg, column, width, alignment );
+}
+
+void SourceItem::setJumpArray(const TQMemArray<TraceLineJump*>& a)
+{
+ _jump.duplicate(a);
+}
+
+void SourceItem::paintArrows(TQPainter *p, const TQColorGroup &cg, int width)
+{
+ TQListView *lv = listView();
+ if ( !lv ) return;
+ SourceView* sv = (SourceView*) 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
+ sv->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 (_lineJump &&
+ (_lineJump->lineTo() == _jump[i]->lineTo()) &&
+ (_jump[i]->lineFrom()->lineno() == _lineno)) {
+
+ if (start<0) start = i;
+ if (_lineJump == _jump[i]) {
+ if (_jump[i]->lineTo()->lineno() <= _lineno)
+ y2 = yy;
+ else
+ y1 = yy;
+ }
+ }
+ else if (!_lineJump && !_lineCall &&
+ (_jump[i]->lineTo()->lineno() == _lineno)) {
+ if (end<0) end = i;
+ if (_jump[i]->lineFrom()->lineno() < _lineno)
+ y2 = yy;
+ else
+ y1 = yy;
+ }
+
+ c = _jump[i]->isCondJump() ? red : blue;
+ 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) {
+ c = _jump[start]->isCondJump() ? red : blue;
+ x = marg + 6*start;
+ w = 6*(sv->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*(sv->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]->lineFrom()->lineno() == _lineno) {
+ bool drawUp = true;
+ if (_jump[i]->lineTo()->lineno() == _lineno)
+ if (start<0) drawUp = false;
+ if (_jump[i]->lineTo()->lineno() > _lineno) 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]->lineTo()->lineno() == _lineno) {
+ if (end<0) end = i;
+ if (_jump[i]->lineFrom()->lineno() < _lineno)
+ p->fillRect( marg + 6*i +1, 0, 2, yy, c);
+ else
+ p->fillRect( marg + 6*i +1, yy, 2, height()-yy, c);
+ }
+ }
+
+}
+
+int SourceItem::width( const TQFontMetrics& fm,
+ const TQListView* lv, int c ) const
+{
+ if (c != 3) return TQListViewItem::width(fm, lv, c);
+
+ SourceView* sv = (SourceView*) lv;
+ int levels = sv->arrowLevels();
+
+ if (levels == 0) return 0;
+
+ // 10 pixels for the arrow
+ return 10 + 6*levels + lv->itemMargin() * 2;
+}
+
diff --git a/kdecachegrind/kdecachegrind/sourceitem.h b/kdecachegrind/kdecachegrind/sourceitem.h
new file mode 100644
index 0000000..925e575
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/sourceitem.h
@@ -0,0 +1,84 @@
+/* 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 source view.
+ */
+
+#ifndef SOURCEITEM_H
+#define SOURCEITEM_H
+
+#include <tqlistview.h>
+#include "tracedata.h"
+
+class SourceView;
+
+class SourceItem: public TQListViewItem
+{
+public:
+ // for source lines
+ SourceItem(SourceView* sv, TQListView* parent,
+ int fileno, unsigned int lineno,
+ bool inside, const TQString& src,
+ TraceLine* line = 0);
+
+ // for call lines
+ SourceItem(SourceView* sv, TQListViewItem* parent,
+ int fileno, unsigned int lineno,
+ TraceLine* line, TraceLineCall* lineCall);
+
+ // for jump lines
+ SourceItem(SourceView* sv, TQListViewItem* parent,
+ int fileno, unsigned int lineno,
+ TraceLine* line, TraceLineJump* lineJump);
+
+ uint lineno() const { return _lineno; }
+ int fileNumber() const { return _fileno; }
+ bool inside() const { return _inside; }
+ TraceLine* line() const { return _line; }
+ TraceLineCall* lineCall() const { return _lineCall; }
+ TraceLineJump* lineJump() const { return _lineJump; }
+
+ 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<TraceLineJump*>& a);
+
+protected:
+ void paintArrows(TQPainter *p, const TQColorGroup &cg, int width);
+ TQMemArray<TraceLineJump*> _jump;
+
+private:
+ SourceView* _view;
+ SubCost _pure, _pure2;
+ uint _lineno;
+ int _fileno; // for line sorting (even with multiple files)
+ bool _inside;
+ TraceLine* _line;
+ TraceLineJump* _lineJump;
+ TraceLineCall* _lineCall;
+};
+
+#endif
diff --git a/kdecachegrind/kdecachegrind/sourceview.cpp b/kdecachegrind/kdecachegrind/sourceview.cpp
new file mode 100644
index 0000000..dde291e
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/sourceview.cpp
@@ -0,0 +1,813 @@
+/* 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.
+*/
+
+/*
+ * Source View
+ */
+
+#include <tqdir.h>
+#include <tqfile.h>
+#include <tqwhatsthis.h>
+#include <tqpopupmenu.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "configuration.h"
+#include "sourceitem.h"
+#include "sourceview.h"
+
+
+//
+// SourceView
+//
+
+
+SourceView::SourceView(TraceItemView* parentView,
+ TQWidget* parent, const char* name)
+ : TQListView(parent, name), TraceItemView(parentView)
+{
+ _inSelectionUpdate = false;
+
+ _arrowLevels = 0;
+ _lowList.setSortLow(true);
+ _highList.setSortLow(false);
+
+ addColumn( i18n( "#" ) );
+ addColumn( i18n( "Cost" ) );
+ addColumn( i18n( "Cost 2" ) );
+ addColumn( "" );
+ addColumn( i18n( "Source (unknown)" ) );
+
+ setAllColumnsShowFocus(true);
+ setColumnAlignment(0, TQt::AlignRight);
+ setColumnAlignment(1, TQt::AlignRight);
+ setColumnAlignment(2, TQt::AlignRight);
+ setResizeMode(TQListView::LastColumn);
+
+ 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 SourceView::paintEmptyArea( TQPainter * p, const TQRect & r)
+{
+ TQListView::paintEmptyArea(p, r);
+}
+
+
+TQString SourceView::whatsThis() const
+{
+ return i18n( "<b>Annotated Source</b>"
+ "<p>The annotated source list shows the "
+ "source lines of the current selected function "
+ "together with (self) cost spent while executing the "
+ "code of this source line. If there was a call "
+ "in a source line, 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>Select a inserted call information line to "
+ "make the destination function current.</p>");
+}
+
+void SourceView::context(TQListViewItem* i, const TQPoint & p, int c)
+{
+ TQPopupMenu popup;
+
+ // Menu entry:
+ TraceLineCall* lc = i ? ((SourceItem*) i)->lineCall() : 0;
+ TraceLineJump* lj = i ? ((SourceItem*) i)->lineJump() : 0;
+ TraceFunction* f = lc ? lc->call()->called() : 0;
+ TraceLine* line = lj ? lj->lineTo() : 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 (line) {
+ popup.insertItem(i18n("Go to Line %1").arg(line->name()), 93);
+ popup.insertSeparator();
+ }
+
+ if ((c == 1) || (c == 2)) {
+ addCostMenu(&popup);
+ popup.insertSeparator();
+ }
+ addGoMenu(&popup);
+
+ int r = popup.exec(p);
+ if (r == 93) {
+ if (f) activated(f);
+ if (line) activated(line);
+ }
+}
+
+
+void SourceView::selectedSlot(TQListViewItem * i)
+{
+ if (!i) return;
+ // programatically selected items are not signalled
+ if (_inSelectionUpdate) return;
+
+ TraceLineCall* lc = ((SourceItem*) i)->lineCall();
+ TraceLineJump* lj = ((SourceItem*) i)->lineJump();
+
+ if (!lc && !lj) {
+ TraceLine* l = ((SourceItem*) i)->line();
+ if (l) {
+ _selectedItem = l;
+ selected(l);
+ }
+ return;
+ }
+
+ TraceFunction* f = lc ? lc->call()->called() : 0;
+ if (f) {
+ _selectedItem = f;
+ selected(f);
+ }
+ else {
+ TraceLine* line = lj ? lj->lineTo() : 0;
+ if (line) {
+ _selectedItem = line;
+ selected(line);
+ }
+ }
+}
+
+void SourceView::activatedSlot(TQListViewItem * i)
+{
+ if (!i) return;
+ TraceLineCall* lc = ((SourceItem*) i)->lineCall();
+ TraceLineJump* lj = ((SourceItem*) i)->lineJump();
+
+ if (!lc && !lj) {
+ TraceLine* l = ((SourceItem*) i)->line();
+ if (l) activated(l);
+ return;
+ }
+
+ TraceFunction* f = lc ? lc->call()->called() : 0;
+ if (f) activated(f);
+ else {
+ TraceLine* line = lj ? lj->lineTo() : 0;
+ if (line) activated(line);
+ }
+}
+
+TraceItem* SourceView::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 SourceView::doUpdate(int changeType)
+{
+ // Special case ?
+ if (changeType == selectedItemChanged) {
+
+ if (!_selectedItem) {
+ clearSelection();
+ return;
+ }
+
+ TraceLine* sLine = 0;
+ if (_selectedItem->type() == TraceItem::Line)
+ sLine = (TraceLine*) _selectedItem;
+ if (_selectedItem->type() == TraceItem::Instr)
+ sLine = ((TraceInstr*)_selectedItem)->line();
+
+ SourceItem* si = (SourceItem*)TQListView::selectedItem();
+ if (si) {
+ if (si->line() == sLine) return;
+ if (si->lineCall() &&
+ (si->lineCall()->call()->called() == _selectedItem)) return;
+ }
+
+ TQListViewItem *item, *item2;
+ for (item = firstChild();item;item = item->nextSibling()) {
+ si = (SourceItem*)item;
+ if (si->line() == sLine) {
+ ensureItemVisible(item);
+ _inSelectionUpdate = true;
+ setCurrentItem(item);
+ _inSelectionUpdate = false;
+ break;
+ }
+ item2 = item->firstChild();
+ for (;item2;item2 = item2->nextSibling()) {
+ si = (SourceItem*)item2;
+ if (!si->lineCall()) continue;
+ if (si->lineCall()->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())
+ ((SourceItem*)item2)->updateGroup();
+ }
+
+ refresh();
+}
+
+void SourceView::refresh()
+{
+ clear();
+ setColumnWidth(0, 20);
+ setColumnWidth(1, 50);
+ setColumnWidth(2, _costType2 ? 50:0);
+ setColumnWidth(3, 0); // arrows, defaults to invisible
+ setSorting(0); // always reset to line number sort
+ if (_costType)
+ setColumnText(1, _costType->name());
+ if (_costType2)
+ setColumnText(2, _costType2->name());
+
+ _arrowLevels = 0;
+
+ if (!_data || !_activeItem) {
+ setColumnText(4, i18n("(No Source)"));
+ 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);
+
+ TraceFunctionSource* mainSF = f->sourceFile();
+
+ // skip first source if there's no debug info and there are more sources
+ // (this is for a bug in GCC 2.95.x giving unknown source for prologs)
+ if (mainSF &&
+ (mainSF->firstLineno() == 0) &&
+ (mainSF->lastLineno() == 0) &&
+ (f->sourceFiles().count()>1) ) {
+ // skip
+ }
+ else
+ fillSourceFile(mainSF, 0);
+
+ TraceFunctionSource* sf;
+ int fileno = 1;
+ TraceFunctionSourceList l = f->sourceFiles();
+ for (sf=l.first();sf;sf=l.next(), fileno++)
+ if (sf != mainSF)
+ fillSourceFile(sf, fileno);
+
+ if (!_costType2) {
+ setColumnWidthMode(2, TQListView::Manual);
+ setColumnWidth(2, 0);
+ }
+}
+
+
+// helper for fillSourceList:
+// search recursive for a file, starting from a base dir
+static bool checkFileExistance(TQString& dir, const TQString& name)
+{
+ // we leave this in...
+ qDebug("Checking %s/%s", dir.ascii(), name.ascii());
+
+ if (TQFile::exists(dir + "/" + name)) return true;
+
+ // check in subdirectories
+ TQDir d(dir);
+ d.setFilter( TQDir::Dirs | TQDir::NoSymLinks );
+ d.setSorting( TQDir::Unsorted );
+ TQStringList subdirs = d.entryList();
+ TQStringList::Iterator it =subdirs.begin();
+ for(; it != subdirs.end(); ++it ) {
+ if (*it == "." || *it == ".." || *it == "CVS") continue;
+
+ dir = d.filePath(*it);
+ if (checkFileExistance(dir, name)) return true;
+ }
+ return false;
+}
+
+
+void SourceView::updateJumpArray(uint lineno, SourceItem* si,
+ bool ignoreFrom, bool ignoreTo)
+{
+ TraceLineJump* lj;
+ uint lowLineno, highLineno;
+ int iEnd = -1, iStart = -1;
+
+ if (0) qDebug("updateJumpArray(line %d, jump to %s)",
+ lineno,
+ si->lineJump()
+ ? si->lineJump()->lineTo()->name().ascii() : "?" );
+
+
+ lj=_lowList.current();
+ while(lj) {
+ lowLineno = lj->lineFrom()->lineno();
+ if (lj->lineTo()->lineno() < lowLineno)
+ lowLineno = lj->lineTo()->lineno();
+
+ if (lowLineno > lineno) break;
+
+ if (ignoreFrom && (lowLineno < lj->lineTo()->lineno())) break;
+ if (ignoreTo && (lowLineno < lj->lineFrom()->lineno())) break;
+
+ if (si->lineJump() && (lj != si->lineJump())) break;
+
+ int asize = (int)_jump.size();
+#if 0
+ for(iStart=0;iStart<asize;iStart++)
+ if (_jump[iStart] &&
+ (_jump[iStart]->lineTo() == lj->lineTo())) break;
+#else
+ iStart = asize;
+#endif
+
+ if (iStart == asize) {
+ for(iStart=0;iStart<asize;iStart++)
+ if (_jump[iStart] == 0) break;
+
+ if (iStart== asize) {
+ asize++;
+ _jump.resize(asize);
+ if (asize > _arrowLevels) _arrowLevels = asize;
+ }
+
+ if (0) qDebug(" start %d (%s to %s)",
+ iStart,
+ lj->lineFrom()->name().ascii(),
+ lj->lineTo()->name().ascii());
+
+ _jump[iStart] = lj;
+ }
+ lj=_lowList.next();
+ }
+
+ si->setJumpArray(_jump);
+
+ lj=_highList.current();
+ while(lj) {
+ highLineno = lj->lineFrom()->lineno();
+ if (lj->lineTo()->lineno() > highLineno) {
+ highLineno = lj->lineTo()->lineno();
+ if (ignoreTo) break;
+ }
+ else if (ignoreFrom) break;
+
+ if (highLineno > lineno) break;
+
+ for(iEnd=0;iEnd< (int)_jump.size();iEnd++)
+ if (_jump[iEnd] == lj) break;
+ if (iEnd == (int)_jump.size()) {
+ qDebug("LineView: no jump start for end at %x ?", highLineno);
+ iEnd = -1;
+ }
+ lj=_highList.next();
+
+ if (0 && (iEnd>=0))
+ qDebug(" end %d (%s to %s)",
+ iEnd,
+ _jump[iEnd]->lineFrom()->name().ascii(),
+ _jump[iEnd]->lineTo()->name().ascii());
+
+ if (0 && lj) qDebug("next end: %s to %s",
+ lj->lineFrom()->name().ascii(),
+ lj->lineTo()->name().ascii());
+
+ if (highLineno > lineno)
+ break;
+ else {
+ if (iEnd>=0) _jump[iEnd] = 0;
+ iEnd = -1;
+ }
+ }
+ if (iEnd>=0) _jump[iEnd] = 0;
+}
+
+
+/* If sourceList is empty we set the source file name into the header,
+ * else this code is of a inlined function, and we add "inlined from..."
+ */
+void SourceView::fillSourceFile(TraceFunctionSource* sf, int fileno)
+{
+ if (!sf) return;
+
+ if (0) qDebug("Selected Item %s",
+ _selectedItem ? _selectedItem->name().ascii() : "(none)");
+
+ TraceLineMap::Iterator lineIt, lineItEnd;
+ int nextCostLineno = 0, lastCostLineno = 0;
+
+ bool validSourceFile = (!sf->file()->name().isEmpty());
+
+ TraceLine* sLine = 0;
+ if (_selectedItem) {
+ if (_selectedItem->type() == TraceItem::Line)
+ sLine = (TraceLine*) _selectedItem;
+ if (_selectedItem->type() == TraceItem::Instr)
+ sLine = ((TraceInstr*)_selectedItem)->line();
+ }
+
+ if (validSourceFile) {
+ TraceLineMap* lineMap = sf->lineMap();
+ if (lineMap) {
+ lineIt = lineMap->begin();
+ lineItEnd = lineMap->end();
+ // get first line with cost of selected type
+ while(lineIt != lineItEnd) {
+ if (&(*lineIt) == sLine) break;
+ if ((*lineIt).hasCost(_costType)) break;
+ if (_costType2 && (*lineIt).hasCost(_costType2)) break;
+ ++lineIt;
+ }
+
+ nextCostLineno = (lineIt == lineItEnd) ? 0 : (*lineIt).lineno();
+ if (nextCostLineno<0) {
+ kdError() << "SourceView::fillSourceFile: Negative line number "
+ << nextCostLineno << endl
+ << " Function '" << sf->function()->name() << "'" << endl
+ << " File '" << sf->file()->name() << "'" << endl;
+ nextCostLineno = 0;
+ }
+
+ }
+
+ if (nextCostLineno == 0) {
+ new SourceItem(this, this, fileno, 0, false,
+ i18n("There is no cost of current selected type associated"));
+ new SourceItem(this, this, fileno, 1, false,
+ i18n("with any source line of this function in file"));
+ new SourceItem(this, this, fileno, 2, false,
+ TQString(" '%1'").arg(sf->function()->prettyName()));
+ new SourceItem(this, this, fileno, 3, false,
+ i18n("Thus, no annotated source can be shown."));
+ return;
+ }
+ }
+
+ TQString filename = sf->file()->shortName();
+ TQString dir = sf->file()->directory();
+ if (!dir.isEmpty())
+ filename = dir + "/" + filename;
+
+ if (nextCostLineno>0) {
+ // we have debug info... search for source file
+ if (!TQFile::exists(filename)) {
+ TQStringList list = Configuration::sourceDirs(_data,
+ sf->function()->object());
+ TQStringList::Iterator it;
+
+ for ( it = list.begin(); it != list.end(); ++it ) {
+ dir = *it;
+ if (checkFileExistance(dir, sf->file()->shortName())) break;
+ }
+
+ if (it == list.end())
+ nextCostLineno = 0;
+ else {
+ filename = dir + "/" + sf->file()->shortName();
+ // no need to search again
+ sf->file()->setDirectory(dir);
+ }
+ }
+ }
+
+ // do it here, because the source directory could have been set before
+ if (childCount()==0) {
+ setColumnText(4, validSourceFile ?
+ i18n("Source ('%1')").arg(filename) :
+ i18n("Source (unknown)"));
+ }
+ else {
+ new SourceItem(this, this, fileno, 0, true,
+ validSourceFile ?
+ i18n("--- Inlined from '%1' ---").arg(filename) :
+ i18n("--- Inlined from unknown source ---"));
+ }
+
+ if (nextCostLineno == 0) {
+ new SourceItem(this, this, fileno, 0, false,
+ i18n("There is no source available for the following function:"));
+ new SourceItem(this, this, fileno, 1, false,
+ TQString(" '%1'").arg(sf->function()->prettyName()));
+ if (sf->file()->name().isEmpty()) {
+ new SourceItem(this, this, fileno, 2, false,
+ i18n("This is because no debug information is present."));
+ new SourceItem(this, this, fileno, 3, false,
+ i18n("Recompile source and redo the profile run."));
+ if (sf->function()->object()) {
+ new SourceItem(this, this, fileno, 4, false,
+ i18n("The function is located in this ELF object:"));
+ new SourceItem(this, this, fileno, 5, false,
+ TQString(" '%1'")
+ .arg(sf->function()->object()->prettyName()));
+ }
+ }
+ else {
+ new SourceItem(this, this, fileno, 2, false,
+ i18n("This is because its source file cannot be found:"));
+ new SourceItem(this, this, fileno, 3, false,
+ TQString(" '%1'").arg(sf->file()->name()));
+ new SourceItem(this, this, fileno, 4, false,
+ i18n("Add the folder of this file to the source folder list."));
+ new SourceItem(this, this, fileno, 5, false,
+ i18n("The list can be found in the configuration dialog."));
+ }
+ return;
+ }
+
+
+ // initialisation for arrow drawing
+ // create sorted list of jumps (for jump arrows)
+ TraceLineMap::Iterator it = lineIt, nextIt;
+ _lowList.clear();
+ _highList.clear();
+ while(1) {
+
+ nextIt = it;
+ ++nextIt;
+ while(nextIt != lineItEnd) {
+ if (&(*nextIt) == sLine) break;
+ if ((*nextIt).hasCost(_costType)) break;
+ if (_costType2 && (*nextIt).hasCost(_costType2)) break;
+ ++nextIt;
+ }
+
+ TraceLineJumpList jlist = (*it).lineJumps();
+ TraceLineJump* lj;
+ for (lj=jlist.first();lj;lj=jlist.next()) {
+ if (lj->executedCount()==0) continue;
+ // skip jumps to next source line with cost
+ //if (lj->lineTo() == &(*nextIt)) continue;
+
+ _lowList.append(lj);
+ _highList.append(lj);
+ }
+ it = nextIt;
+ if (it == lineItEnd) break;
+ }
+ _lowList.sort();
+ _highList.sort();
+ _lowList.first(); // iterators to list start
+ _highList.first();
+ _jump.resize(0);
+
+
+ char buf[256];
+ bool inside = false, skipLineWritten = true;
+ int readBytes;
+ int fileLineno = 0;
+ SubCost most = 0;
+
+ TraceLine* currLine;
+ SourceItem *si, *si2, *item = 0, *first = 0, *selected = 0;
+ TQFile file(filename);
+ if (!file.open(IO_ReadOnly)) return;
+ while (1) {
+ readBytes=file.readLine(buf, sizeof( buf ));
+ if (readBytes<=0) {
+ // for nice empty 4 lines after function with EOF
+ buf[0] = 0;
+ }
+
+ if (readBytes >= (int) sizeof( buf )) {
+ qDebug("%s:%d Line too long\n",
+ sf->file()->name().ascii(), fileLineno);
+ }
+ else if ((readBytes>0) && (buf[readBytes-1] == '\n'))
+ buf[readBytes-1] = 0;
+
+
+ // keep fileLineno inside [lastCostLineno;nextCostLineno]
+ fileLineno++;
+ if (fileLineno == nextCostLineno) {
+ currLine = &(*lineIt);
+
+ // get next line with cost of selected type
+ ++lineIt;
+ while(lineIt != lineItEnd) {
+ if (&(*lineIt) == sLine) break;
+ if ((*lineIt).hasCost(_costType)) break;
+ if (_costType2 && (*lineIt).hasCost(_costType2)) break;
+ ++lineIt;
+ }
+
+ lastCostLineno = nextCostLineno;
+ nextCostLineno = (lineIt == lineItEnd) ? 0 : (*lineIt).lineno();
+ }
+ else
+ currLine = 0;
+
+ // update inside
+ if (!inside) {
+ if (currLine) inside = true;
+ }
+ else {
+ if ( (fileLineno > lastCostLineno) &&
+ ((nextCostLineno == 0) ||
+ (fileLineno < nextCostLineno - Configuration::noCostInside()) ))
+ inside = false;
+ }
+
+ int context = Configuration::context();
+
+ if ( ((lastCostLineno==0) || (fileLineno > lastCostLineno + context)) &&
+ ((nextCostLineno==0) || (fileLineno < nextCostLineno - context))) {
+ if (lineIt == lineItEnd) break;
+
+ if (!skipLineWritten) {
+ skipLineWritten = true;
+ // a "skipping" line: print "..." instead of a line number
+ strcpy(buf,"...");
+ }
+ else
+ continue;
+ }
+ else
+ skipLineWritten = false;
+
+ si = new SourceItem(this, this,
+ fileno, fileLineno, inside, TQString(buf),
+ currLine);
+
+ if (!currLine) continue;
+
+ if (!selected && (currLine == sLine)) selected = si;
+ if (!first) first = si;
+
+ if (currLine->subCost(_costType) > most) {
+ item = si;
+ most = currLine->subCost(_costType);
+ }
+
+ si->setOpen(true);
+ TraceLineCallList list = currLine->lineCalls();
+ TraceLineCall* lc;
+ for (lc=list.first();lc;lc=list.next()) {
+ if ((lc->subCost(_costType)==0) &&
+ (lc->subCost(_costType2)==0)) continue;
+
+ if (lc->subCost(_costType) > most) {
+ item = si;
+ most = lc->subCost(_costType);
+ }
+
+ si2 = new SourceItem(this, si, fileno, fileLineno, currLine, lc);
+
+ if (!selected && (lc->call()->called() == _selectedItem))
+ selected = si2;
+ }
+
+ TraceLineJumpList jlist = currLine->lineJumps();
+ TraceLineJump* lj;
+ for (lj=jlist.first();lj;lj=jlist.next()) {
+ if (lj->executedCount()==0) continue;
+
+ new SourceItem(this, si, fileno, fileLineno, currLine, lj);
+ }
+ }
+
+ if (selected) item = selected;
+ if (item) first = item;
+ if (first) {
+ ensureItemVisible(first);
+ _inSelectionUpdate = true;
+ setCurrentItem(first);
+ _inSelectionUpdate = false;
+ }
+
+ file.close();
+
+ // for arrows: go down the list according to list sorting
+ sort();
+ TQListViewItem *item1, *item2;
+ for (item1=firstChild();item1;item1 = item1->nextSibling()) {
+ si = (SourceItem*)item1;
+ updateJumpArray(si->lineno(), si, true, false);
+
+ for (item2=item1->firstChild();item2;item2 = item2->nextSibling()) {
+ si2 = (SourceItem*)item2;
+ if (si2->lineJump())
+ updateJumpArray(si->lineno(), si2, false, true);
+ else
+ si2->setJumpArray(_jump);
+ }
+ }
+
+ if (arrowLevels())
+ setColumnWidth(3, 10 + 6*arrowLevels() + itemMargin() * 2);
+ else
+ setColumnWidth(3, 0);
+}
+
+
+void SourceView::updateSourceItems()
+{
+ setColumnWidth(1, 50);
+ setColumnWidth(2, _costType2 ? 50:0);
+ // Allow resizing of column 2
+ setColumnWidthMode(2, TQListView::Maximum);
+
+ if (_costType)
+ setColumnText(1, _costType->name());
+ if (_costType2)
+ setColumnText(2, _costType2->name());
+
+ SourceItem* si;
+ TQListViewItem* item = firstChild();
+ for (;item;item = item->nextSibling()) {
+ si = (SourceItem*)item;
+ TraceLine* l = si->line();
+ if (!l) continue;
+
+ si->updateCost();
+
+ TQListViewItem *next, *i = si->firstChild();
+ for (;i;i = next) {
+ next = i->nextSibling();
+ ((SourceItem*)i)->updateCost();
+ }
+ }
+
+ if (!_costType2) {
+ setColumnWidthMode(2, TQListView::Manual);
+ setColumnWidth(2, 0);
+ }
+}
+
+#include "sourceview.moc"
diff --git a/kdecachegrind/kdecachegrind/sourceview.h b/kdecachegrind/kdecachegrind/sourceview.h
new file mode 100644
index 0000000..b72fc7a
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/sourceview.h
@@ -0,0 +1,71 @@
+/* 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.
+*/
+
+/*
+ * Source View
+ */
+
+#ifndef SOURCEVIEW_H
+#define SOURCEVIEW_H
+
+#include <tqlistview.h>
+#include "traceitemview.h"
+
+class SourceItem;
+
+class SourceView : public TQListView, public TraceItemView
+{
+ friend class SourceItem;
+
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+ SourceView(TraceItemView* parentView,
+ TQWidget* parent = 0, const char* name = 0);
+
+ TQWidget* widget() { return this; }
+ TQString whatsThis() const;
+
+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 updateJumpArray(uint,SourceItem*,bool,bool);
+ void fillSourceFile(TraceFunctionSource*, int);
+ void updateSourceItems();
+
+ bool _inSelectionUpdate;
+
+ // arrows
+ int _arrowLevels;
+ // temporary needed on creation...
+ TQMemArray<TraceLineJump*> _jump;
+ TraceLineJumpList _lowList, _highList;
+};
+
+#endif
diff --git a/kdecachegrind/kdecachegrind/stackbrowser.cpp b/kdecachegrind/kdecachegrind/stackbrowser.cpp
new file mode 100644
index 0000000..78095eb
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/stackbrowser.cpp
@@ -0,0 +1,417 @@
+/* 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 <tqlistview.h>
+
+#include "stackbrowser.h"
+
+// Stack
+
+Stack::Stack(TraceFunction* top, TraceCallList calls)
+{
+ _refCount = 0;
+ _top = top;
+ _calls = calls;
+
+ extendBottom();
+}
+
+Stack::Stack(TraceFunction* f)
+{
+ _refCount = 0;
+ _top = f;
+
+ extendBottom();
+ extendTop();
+}
+
+void Stack::extendBottom()
+{
+ TraceCallList l;
+ TraceCall *c, *call;
+ SubCost most;
+ TraceFunction* f;
+
+ if (_calls.last())
+ f = _calls.last()->called();
+ else
+ f = _top;
+
+ if (!f) return;
+ // don't follow calls from cycles
+ if (f->cycle() == f) return;
+
+
+ int max = 30;
+
+ // try to extend to lower stack frames
+ while (f && (max-- >0)) {
+ l = f->callings();
+ call = 0;
+ most = 0;
+ for (c=l.first();c;c=l.next()) {
+ // no cycle calls in stack: could be deleted without notice
+ if (c->called()->cycle() == c->called()) continue;
+ // no simple recursions
+ if (c->called() == _top) continue;
+
+ if (c->called()->name().isEmpty()) continue;
+ SubCost sc = c->subCost(0); // FIXME
+ if (sc == 0) continue;
+
+ if (sc > most) {
+ most = sc;
+ call = c;
+ }
+ }
+ if (!call)
+ break;
+
+ _calls.append(call);
+ f = call->called();
+ }
+}
+
+
+void Stack::extendTop()
+{
+ TraceCallList l;
+ TraceCall *c, *call;
+ SubCost most;
+
+ int max = 10;
+
+ // don't follow calls from cycles
+ if (_top->cycle() == _top) return;
+
+ // try to extend to upper stack frames
+ while (_top && (max-- >0)) {
+ l = _top->callers();
+ call = 0;
+ most = 0;
+ for (c=l.first();c;c=l.next()) {
+ // no cycle calls in stack: could be deleted without notice
+ if (c->caller()->cycle() == c->caller()) continue;
+ // no simple recursions
+ if (c->caller() == _top) continue;
+
+ if (c->caller()->name().isEmpty()) continue;
+ SubCost sc = c->subCost(0); // FIXME
+ if (sc == 0) continue;
+
+ if (sc > most) {
+ most = sc;
+ call = c;
+ }
+ }
+ if (!call)
+ break;
+
+ _calls.prepend(call);
+ _top = call->caller();
+ }
+}
+
+TraceFunction* Stack::caller(TraceFunction* fn, bool extend)
+{
+ TraceFunction* f;
+ TraceCall* c;
+
+ if (extend && (_top == fn)) {
+ // extend at top
+ extendTop();
+ f = _top;
+ }
+
+ for (c=_calls.first();c;c=_calls.next()) {
+ f = c->called();
+ if (f == fn)
+ return c->caller();
+ }
+ return 0;
+}
+
+TraceFunction* Stack::called(TraceFunction* fn, bool extend)
+{
+ TraceFunction* f;
+ TraceCall* c;
+
+ for (c=_calls.first();c;c=_calls.next()) {
+ f = c->caller();
+ if (f == fn)
+ return c->called();
+ }
+
+ if (extend && (c->called() == fn)) {
+ // extend at bottom
+ extendBottom();
+
+ // and search again
+ for (c=_calls.first();c;c=_calls.next()) {
+ f = c->caller();
+ if (f == fn)
+ return c->called();
+ }
+ }
+
+ return 0;
+}
+
+bool Stack::contains(TraceFunction* fn)
+{
+ // cycles are listed on there own
+ if (fn->cycle() == fn) return false;
+ if (_top->cycle() == _top) return false;
+
+ if (fn == _top)
+ return true;
+
+ TraceFunction* f = _top;
+ TraceCall* c;
+
+ for (c=_calls.first();c;c=_calls.next()) {
+ f = c->called();
+ if (f == fn)
+ return true;
+ }
+
+ TraceCallList l;
+
+ // try to extend at bottom (even if callCount 0)
+ l = f->callings();
+ for (c=l.first();c;c=l.next()) {
+ f = c->called();
+ if (f == fn)
+ break;
+ }
+
+ if (c) {
+ _calls.append(c);
+
+ // extend at bottom after found one
+ extendBottom();
+ return true;
+ }
+
+ // try to extend at top (even if callCount 0)
+ l = _top->callers();
+ for (c=l.first();c;c=l.next()) {
+ f = c->caller();
+ if (f == fn)
+ break;
+ }
+
+ if (c) {
+ _calls.prepend(c);
+
+ // extend at top after found one
+ extendTop();
+ return true;
+ }
+
+ return false;
+}
+
+Stack* Stack::split(TraceFunction* f)
+{
+ TraceCallList calls = _calls;
+ TraceCall *c, *c2;
+
+ // cycles are listed on there own
+ if (f->cycle() == f) return 0;
+ if (_top->cycle() == _top) return false;
+
+ for (c=calls.first();c;c=calls.next()) {
+ TraceCallList l = c->called()->callings();
+ for (c2=l.first();c2;c2=l.next()) {
+ if (c2 == c) continue;
+ if (c2->called() == f)
+ break;
+ }
+ if (c2)
+ break;
+ }
+
+ if (!c)
+ return 0;
+
+ // remove bottom part
+ calls.last();
+ while (calls.current() && calls.current()!=c)
+ calls.removeLast();
+
+ calls.append(c2);
+ return new Stack(_top, calls );
+}
+
+TQString Stack::toString()
+{
+ TQString res = _top->name();
+ TraceCall *c;
+ for (c=_calls.first();c;c=_calls.next())
+ res += "\n > " + c->called()->name();
+
+ return res;
+}
+
+
+// HistoryItem
+
+HistoryItem::HistoryItem(Stack* stack, TraceFunction* function)
+{
+ _stack = stack;
+ _function = function;
+ if (_stack)
+ _stack->ref();
+
+ _last = 0;
+ _next = 0;
+
+/*
+ qDebug("New Stack History Item (sRef %d): %s\n %s",
+ _stack->refCount(), _function->name().ascii(),
+ _stack->toString().ascii());
+*/
+}
+
+HistoryItem::~HistoryItem()
+{
+ if (0) qDebug("Deleting Stack History Item (sRef %d): %s",
+ _stack->refCount(),
+ _function->name().ascii());
+
+ if (_last)
+ _last->_next = _next;
+ if (_stack) {
+ if (_stack->deref() == 0)
+ delete _stack;
+ }
+}
+
+
+// StackBrowser
+
+StackBrowser::StackBrowser()
+{
+ _current = 0;
+}
+
+StackBrowser::~StackBrowser()
+{
+ delete _current;
+}
+
+HistoryItem* StackBrowser::select(TraceFunction* f)
+{
+ if (!_current) {
+ Stack* s = new Stack(f);
+ _current = new HistoryItem(s, f);
+ }
+ else if (_current->function() != f) {
+ // make current item the last one
+ HistoryItem* item = _current;
+ if (item->next()) {
+ item = item->next();
+ item->last()->setNext(0);
+
+ while (item->next()) {
+ item = item->next();
+ delete item->last();
+ }
+ delete item;
+ }
+
+ Stack* s = _current->stack();
+ if (!s->contains(f)) {
+ s = s->split(f);
+ if (!s)
+ s = new Stack(f);
+ }
+
+ item = _current;
+ _current = new HistoryItem(s, f);
+ item->setNext(_current);
+ _current->setLast(item);
+ }
+
+ // qDebug("Selected %s in StackBrowser", f->name().ascii());
+
+ return _current;
+}
+
+HistoryItem* StackBrowser::goBack()
+{
+ if (_current && _current->last())
+ _current = _current->last();
+
+ return _current;
+}
+
+HistoryItem* StackBrowser::goForward()
+{
+ if (_current && _current->next())
+ _current = _current->next();
+
+ return _current;
+}
+
+HistoryItem* StackBrowser::goUp()
+{
+ if (_current) {
+ TraceFunction* f = _current->stack()->caller(_current->function(), true);
+ if (f)
+ _current = select(f);
+ }
+
+ return _current;
+}
+
+HistoryItem* StackBrowser::goDown()
+{
+ if (_current) {
+ TraceFunction* f = _current->stack()->called(_current->function(), true);
+ if (f)
+ _current = select(f);
+ }
+
+ return _current;
+}
+
+bool StackBrowser::canGoBack()
+{
+ return _current && _current->last();
+}
+
+bool StackBrowser::canGoForward()
+{
+ return _current && _current->next();
+}
+
+bool StackBrowser::canGoUp()
+{
+ if (!_current) return false;
+
+ return _current->stack()->caller(_current->function(), false);
+}
+
+bool StackBrowser::canGoDown()
+ {
+ if (!_current) return false;
+
+ return _current->stack()->called(_current->function(), false);
+}
diff --git a/kdecachegrind/kdecachegrind/stackbrowser.h b/kdecachegrind/kdecachegrind/stackbrowser.h
new file mode 100644
index 0000000..e7d6b80
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/stackbrowser.h
@@ -0,0 +1,109 @@
+/* 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 STACKBROWSER_H
+#define STACKBROWSER_H
+
+#include "tracedata.h"
+
+// A history of selected functions within stacks
+
+class Stack
+{
+public:
+ Stack(TraceFunction*);
+
+ // extend the stack at top/bottom if possible
+ bool contains(TraceFunction*);
+
+ void extendBottom();
+ void extendTop();
+
+ // search for a function on stack calling specified function.
+ // if found, return upper part with new function call
+ Stack* split(TraceFunction*);
+
+ // increment reference count
+ void ref() { _refCount++; }
+ // decrement reference count
+ bool deref() { return --_refCount; }
+ int refCount() { return _refCount; }
+
+ TraceFunction* top() { return _top; }
+ TraceCallList calls() { return _calls; }
+ TraceFunction* caller(TraceFunction*, bool extend);
+ TraceFunction* called(TraceFunction*, bool extend);
+
+ TQString toString();
+
+private:
+ Stack(TraceFunction* top, TraceCallList list);
+
+ // at the top of the stack we have a function...
+ TraceFunction* _top;
+ // list ordered from top to bottom
+ TraceCallList _calls;
+ int _refCount;
+};
+
+class HistoryItem
+{
+public:
+ HistoryItem(Stack*, TraceFunction*);
+ ~HistoryItem();
+
+ Stack* stack() { return _stack; }
+ TraceFunction* function() { return _function; }
+ HistoryItem* last() { return _last; }
+ HistoryItem* next() { return _next; }
+ void setLast(HistoryItem* h) { _last = h; }
+ void setNext(HistoryItem* h) { _next = h; }
+
+private:
+
+ HistoryItem *_last, *_next;
+ Stack* _stack;
+ TraceFunction* _function;
+};
+
+
+class StackBrowser
+{
+public:
+ StackBrowser();
+ ~StackBrowser();
+
+ // A function was selected. This creates a new history entry
+ HistoryItem* select(TraceFunction*);
+
+ HistoryItem* current() { return _current; }
+ bool canGoBack();
+ bool canGoForward();
+ bool canGoUp();
+ bool canGoDown();
+ HistoryItem* goBack();
+ HistoryItem* goForward();
+ HistoryItem* goUp();
+ HistoryItem* goDown();
+
+private:
+ HistoryItem* _current;
+};
+
+
+#endif
diff --git a/kdecachegrind/kdecachegrind/stackitem.cpp b/kdecachegrind/kdecachegrind/stackitem.cpp
new file mode 100644
index 0000000..e3763ab
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/stackitem.cpp
@@ -0,0 +1,116 @@
+/* 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 stack dockable.
+ */
+
+#include <tqpixmap.h>
+#include <klocale.h>
+
+#include "configuration.h"
+#include "listutils.h"
+#include "stackitem.h"
+#include "stackselection.h"
+
+// StackItem
+
+StackItem::StackItem(StackSelection* ss,
+ TQListView* parent, TraceFunction* f)
+ :TQListViewItem(parent)
+{
+ _view = ss;
+ _function = f;
+ _call = 0;
+
+ updateGroup();
+ updateCost();
+
+ setText(2, TQString("-- "));
+ setText(3, f->prettyName());
+}
+
+StackItem::StackItem(StackSelection* ss,
+ TQListView* parent, TraceCall* call)
+ :TQListViewItem(parent)
+{
+ _view = ss;
+ _call = call;
+ _function = call->called();
+
+ updateGroup();
+ updateCost();
+
+ setText(3, _function->prettyName());
+}
+
+
+void StackItem::updateGroup()
+{
+ TQColor c = Configuration::functionColor(_view->groupType(),
+ _function);
+ setPixmap(3, colorPixmap(10, 10, c));
+}
+
+void StackItem::updateCost()
+{
+ if (!_call) return;
+
+ setText(2, _call->prettyCallCount());
+
+ TraceCostType* ct = _view->costType();
+ _sum = _call->subCost(ct);
+ double total = _call->called()->data()->subCost(ct);
+ if (total == 0.0) {
+ setText(0, "-");
+ setPixmap(0, TQPixmap());
+ }
+ else {
+ double sum = 100.0 * _sum / total;
+
+ if (Configuration::showPercentage())
+ setText(0, TQString("%1")
+ .arg(sum, 0, 'f', Configuration::percentPrecision()));
+ else
+ setText(0, _call->prettySubCost(ct));
+
+ setPixmap(0, costPixmap(ct, _call, total, false));
+ }
+
+ // if _costType2 is 0, column1 is hidden, no change needed
+ TraceCostType* ct2 = _view->costType2();
+ if (!ct2) return;
+
+ _sum = _call->subCost(ct2);
+ total = _call->called()->data()->subCost(ct2);
+ if (total == 0.0) {
+ setText(1, "-");
+ setPixmap(1, TQPixmap());
+ }
+ else {
+ double sum = 100.0 * _sum / total;
+
+ if (Configuration::showPercentage())
+ setText(1, TQString("%1")
+ .arg(sum, 0, 'f', Configuration::percentPrecision()));
+ else
+ setText(1, _call->prettySubCost(ct2));
+
+ setPixmap(1, costPixmap(ct2, _call, total, false));
+ }
+}
diff --git a/kdecachegrind/kdecachegrind/stackitem.h b/kdecachegrind/kdecachegrind/stackitem.h
new file mode 100644
index 0000000..250e9f6
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/stackitem.h
@@ -0,0 +1,56 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003, 2004
+ 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 stack dockable.
+ */
+
+#ifndef STACKITEM_H
+#define STACKITEM_H
+
+#include <tqlistview.h>
+#include "tracedata.h"
+
+class StackSelection;
+
+
+// for the stack browser
+
+class StackItem: public TQListViewItem
+{
+public:
+ // for top
+ StackItem(StackSelection* ss, TQListView* parent, TraceFunction* f);
+ StackItem(StackSelection* ss, TQListView* parent, TraceCall* c);
+
+ TraceFunction* function() { return _function; }
+ TraceCall* call() { return _call; }
+ void updateGroup();
+ void updateCost();
+
+private:
+ StackSelection* _view;
+ SubCost _sum;
+ TraceFunction* _function;
+ TraceCall* _call;
+};
+
+
+
+#endif
diff --git a/kdecachegrind/kdecachegrind/stackselection.cpp b/kdecachegrind/kdecachegrind/stackselection.cpp
new file mode 100644
index 0000000..5909475
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/stackselection.cpp
@@ -0,0 +1,230 @@
+/* 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.
+*/
+
+/*
+ * StackSelection for KCachegrind
+ * For function selection of a most expected stack,
+ * 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 <kdebug.h>
+
+#include "stackbrowser.h"
+#include "stackselection.h"
+#include "stackitem.h"
+
+StackSelection::StackSelection( TQWidget* parent, const char* name)
+ : StackSelectionBase(parent, name)
+{
+ _data = 0;
+ _browser = new StackBrowser();
+ _item = 0;
+ _function = 0;
+ _costType = 0;
+ _costType2 = 0;
+ _groupType = TraceItem::Function;
+
+ stackList->setSorting(-1);
+ stackList->setAllColumnsShowFocus(true);
+ stackList->setResizeMode(TQListView::LastColumn);
+ stackList->setColumnAlignment(0, TQt::AlignRight);
+ stackList->setColumnAlignment(1, TQt::AlignRight);
+ stackList->setColumnAlignment(2, TQt::AlignRight);
+ stackList->setColumnWidth(0, 50);
+ // 2nd cost column hidden at first (_costType2 == 0)
+ stackList->setColumnWidth(1, 0);
+ stackList->setColumnWidth(2, 50);
+
+ connect(stackList, TQT_SIGNAL(selectionChanged(TQListViewItem*)),
+ this, TQT_SLOT(stackSelected(TQListViewItem*)));
+}
+
+StackSelection::~StackSelection()
+{
+ delete _browser;
+}
+
+void StackSelection::setData(TraceData* data)
+{
+ if (_data == data) return;
+
+ _data = data;
+
+ stackList->clear();
+ delete _browser;
+ _browser = new StackBrowser();
+ _function = 0;
+}
+
+
+void StackSelection::setFunction(TraceFunction* f)
+{
+ if (_function == f) return;
+ _function = f;
+
+ if (!_data || !_function) return;
+
+ //kdDebug() << "StackSelection::setFunction " << f->name() << endl;
+
+ HistoryItem* item = _browser->current();
+ if (!item || item->function() != f) {
+ _browser->select(f);
+ rebuildStackList();
+ }
+}
+
+
+void StackSelection::rebuildStackList()
+{
+ HistoryItem* item = _browser->current();
+ stackList->clear();
+ stackList->setColumnWidth(0, 50);
+ stackList->setColumnWidth(1, _costType2 ? 50:0);
+ stackList->setColumnWidth(2, 50);
+ if (!item || !item->stack()) return;
+
+ TraceFunction* top = item->stack()->top();
+ if (!top) return;
+
+ stackList->setColumnWidthMode(1, TQListView::Maximum);
+
+ TraceCallList l = item->stack()->calls();
+ TraceCall* call;
+ for (call=l.last();call;call=l.prev())
+ new StackItem(this, stackList, call);
+
+ new StackItem(this, stackList, top);
+
+ // select current function
+ TQListViewItem* i = stackList->firstChild();
+ for (;i;i=i->nextSibling())
+ if (((StackItem*)i)->function() == item->function())
+ break;
+
+ if (i) {
+ // this calls stackFunctionSelected()
+ stackList->setCurrentItem(i);
+ stackList->ensureItemVisible(i);
+ }
+
+ if (!_costType2) {
+ stackList->setColumnWidthMode(1, TQListView::Manual);
+ stackList->setColumnWidth(1, 0);
+ }
+}
+
+void StackSelection::stackSelected(TQListViewItem* i)
+{
+ if (!i) return;
+
+ TraceFunction* f = ((StackItem*)i)->function();
+ emit functionSelected(f);
+}
+
+
+void StackSelection::browserBack()
+{
+ if (_browser && _browser->canGoBack()) {
+ _browser->goBack();
+ rebuildStackList();
+ }
+}
+
+void StackSelection::browserForward()
+{
+ if (_browser && _browser->canGoForward()) {
+ _browser->goForward();
+ rebuildStackList();
+ }
+}
+
+void StackSelection::browserUp()
+{
+ if (_browser) {
+ _browser->goUp();
+ rebuildStackList();
+ }
+}
+
+void StackSelection::browserDown()
+{
+ if (_browser) {
+ _browser->goDown();
+ rebuildStackList();
+ }
+}
+
+void StackSelection::refresh()
+{
+ TQListViewItem* item = stackList->firstChild();
+ for(;item;item = item->nextSibling())
+ ((StackItem*)item)->updateCost();
+}
+
+void StackSelection::setCostType(TraceCostType* ct)
+{
+ if (ct == _costType) return;
+ _costType = ct;
+
+ stackList->setColumnWidth(0, 50);
+ if (_costType)
+ stackList->setColumnText(0, _costType->name());
+
+ TQListViewItem* item = stackList->firstChild();
+ for(;item;item = item->nextSibling())
+ ((StackItem*)item)->updateCost();
+}
+
+void StackSelection::setCostType2(TraceCostType* ct)
+{
+ if (ct == _costType2) return;
+ _costType2 = ct;
+
+ stackList->setColumnWidth(1, 50);
+ stackList->setColumnWidthMode(1, TQListView::Maximum);
+ if (_costType2)
+ stackList->setColumnText(1, _costType2->name());
+
+ TQListViewItem* item = stackList->firstChild();
+ for(;item;item = item->nextSibling())
+ ((StackItem*)item)->updateCost();
+
+ if (!_costType2) {
+ stackList->setColumnWidthMode(1, TQListView::Manual);
+ stackList->setColumnWidth(1, 0);
+ }
+}
+
+void StackSelection::setGroupType(TraceItem::CostType gt)
+{
+ if (_groupType == gt) return;
+ _groupType = gt;
+
+ TQListViewItem* item = stackList->firstChild();
+ for(;item;item = item->nextSibling())
+ ((StackItem*)item)->updateGroup();
+}
+
+#include "stackselection.moc"
diff --git a/kdecachegrind/kdecachegrind/stackselection.h b/kdecachegrind/kdecachegrind/stackselection.h
new file mode 100644
index 0000000..2bb3a75
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/stackselection.h
@@ -0,0 +1,81 @@
+/* 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.
+*/
+
+/*
+ * StackSelection for KCachegrind
+ * For function selection of a most expected stack,
+ * to be put into a TQDockWindow
+ */
+
+#ifndef STACKSELECTION_H
+#define STACKSELECTION_H
+
+#include "stackselectionbase.h"
+#include "tracedata.h"
+
+class TraceFunction;
+class TraceData;
+class StackBrowser;
+class NestedAreaItem;
+
+class StackSelection : public StackSelectionBase
+{
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+ StackSelection( TQWidget* parent = 0, const char* name = 0);
+ ~StackSelection();
+
+ TraceData* data() const { return _data; }
+ void setData(TraceData*);
+ StackBrowser* browser() const { return _browser; }
+ TraceCostType* costType() { return _costType; }
+ TraceCostType* costType2() { return _costType2; }
+ TraceItem::CostType groupType() { return _groupType; }
+
+signals:
+ void functionSelected(TraceItem*);
+
+public slots:
+ void setFunction(TraceFunction*);
+ void setCostType(TraceCostType*);
+ void setCostType2(TraceCostType*);
+ void setGroupType(TraceItem::CostType);
+
+ void stackSelected( TQListViewItem* );
+ void browserBack();
+ void browserForward();
+ void browserUp();
+ void browserDown();
+ void refresh();
+ void rebuildStackList();
+
+private:
+ void selectFunction();
+
+ TraceData* _data;
+ StackBrowser* _browser;
+ TQListViewItem* _item;
+ TraceFunction* _function;
+ TraceCostType* _costType;
+ TraceCostType* _costType2;
+ TraceItem::CostType _groupType;
+};
+
+#endif
diff --git a/kdecachegrind/kdecachegrind/stackselectionbase.ui b/kdecachegrind/kdecachegrind/stackselectionbase.ui
new file mode 100644
index 0000000..c61010f
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/stackselectionbase.ui
@@ -0,0 +1,80 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>StackSelectionBase</class>
+<widget class="TQWidget">
+ <property name="name">
+ <cstring>StackSelectionBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>168</width>
+ <height>108</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Stack Selection</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="TQListView">
+ <column>
+ <property name="text">
+ <string>Cost</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizeable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Cost2</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizeable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Calls</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizeable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Function</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizeable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>stackList</cstring>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kdecachegrind/kdecachegrind/subcost.cpp b/kdecachegrind/kdecachegrind/subcost.cpp
new file mode 100644
index 0000000..7b5034e
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/subcost.cpp
@@ -0,0 +1,62 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2004 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 <tqstring.h>
+
+#include "subcost.h"
+
+//---------------------------------------------------
+// SubCost
+
+bool SubCost::set(const char** ps)
+{
+ const char* s = *ps;
+ if (!s || (*s < '0') || (*s > '9')) return false;
+
+ v = *s - '0';
+ s++;
+ while(*s >= '0' && *s <= '9') {
+ v = 10* v + (*s-'0');
+ s++;
+ }
+ while(*s == ' ') s++;
+ *ps = s;
+
+ return true;
+}
+
+TQString SubCost::pretty()
+{
+ unsigned long long n = v;
+
+ if (n==0) return TQString(" 0");
+
+ int i = 0;
+ TQString res = "";
+
+ while (n) {
+ if ((i>0) && !(i%3)) res = " " + res;
+ i++;
+ res = TQChar('0'+int(n%10)) + res;
+ n /= 10;
+ }
+ res = " " + res;
+ return res;
+}
+
+
diff --git a/kdecachegrind/kdecachegrind/subcost.h b/kdecachegrind/kdecachegrind/subcost.h
new file mode 100644
index 0000000..8169280
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/subcost.h
@@ -0,0 +1,66 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002-2004 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 SUBCOST_H
+#define SUBCOST_H
+
+#include "utils.h"
+
+typedef unsigned long long uint64;
+
+/**
+ * Cost event counter, simple wrapper around a 64bit entity
+ */
+class SubCost
+{
+ public:
+ SubCost() {}
+ SubCost(uint64 i) { v=i; }
+ SubCost(unsigned i) { v=i; }
+ SubCost(int i) { v=(unsigned)i; }
+ SubCost(double d) { v= (uint64)(d + .5); }
+
+ SubCost& operator=(uint64 i) { v = i; return *this; }
+ SubCost& operator=(unsigned i) { v = i; return *this; }
+ SubCost& operator=(int i) { v = i; return *this; }
+ SubCost& operator=(double d) { v = (uint64)(d + .5); return *this; }
+
+ bool set(const char** s);
+ bool set(FixString& s) { return s.stripUInt64(v); }
+
+ operator uint64&() { return v; }
+
+ bool operator==(unsigned i) const { return v == i; }
+ bool operator==(int i) const { return v == (unsigned)i; }
+ bool operator<(unsigned i) const { return v < i; }
+ bool operator<(int i) const { return v < (unsigned)i; }
+ bool operator<(const SubCost& s) const { return v < s.v; }
+ bool operator>(unsigned i) const { return v > i; }
+ bool operator>(int i) const { return v > (unsigned)i; }
+ bool operator>(const SubCost& s) const { return v > s.v; }
+
+ /**
+ * Convert SubCost value into a TQString,
+ * spaced every 3 digits.
+ */
+ TQString pretty();
+
+ uint64 v;
+};
+
+#endif
diff --git a/kdecachegrind/kdecachegrind/tabview.cpp b/kdecachegrind/kdecachegrind/tabview.cpp
new file mode 100644
index 0000000..0049d1e
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/tabview.cpp
@@ -0,0 +1,890 @@
+/* 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.
+*/
+
+/*
+ * Tab View, enclosing detailed views for one trace item in
+ * two tab widgets, separated by a splitter
+ */
+
+#include <tqobjectlist.h>
+#include <tqsplitter.h>
+#include <tqtabwidget.h>
+#include <tqlayout.h>
+#include <tqwhatsthis.h>
+#include <tqpopupmenu.h>
+
+#include <klocale.h>
+#include <kconfig.h>
+
+#include "tabview.h"
+#include "costtypeview.h"
+#include "partview.h"
+#include "callview.h"
+#include "coverageview.h"
+#include "callmapview.h"
+#include "instrview.h"
+#include "sourceview.h"
+#include "callgraphview.h"
+
+// TabBar
+
+TabBar::TabBar(TabView* v, TQTabWidget* parent, const char *name)
+ : TQTabBar(parent, name)
+{
+ _tabWidget = parent;
+ _tabView = v;
+}
+
+void TabBar::mousePressEvent(TQMouseEvent *e)
+{
+ if (e->button() == Qt::RightButton) {
+ TQTab *tab = selectTab( e->pos() );
+ TQWidget* page;
+ page = tab ? _tabWidget->page( indexOf( tab->identifier() ) ) :0;
+
+ TQPopupMenu popup, popup1, popup2, popup3;
+ if (page) {
+ TraceItemView::Position p = _tabView->tabPosition(page);
+ if (p != TraceItemView::Top) {
+ popup.insertItem(i18n("Move to Top"), 81);
+ popup2.insertItem(i18n("Top"), 91);
+ }
+ if (p != TraceItemView::Right) {
+ popup.insertItem(i18n("Move to Right"), 82);
+ popup2.insertItem(i18n("Right"), 92);
+ }
+ if (p != TraceItemView::Bottom) {
+ popup.insertItem(i18n("Move to Bottom"), 83);
+ popup2.insertItem(i18n("Bottom"), 93);
+ }
+ if (p != TraceItemView::Left) {
+ popup.insertItem(i18n("Move to Bottom Left"), 84);
+ popup2.insertItem(i18n("Bottom Left"), 94);
+ }
+ popup.insertItem(i18n("Move Area To"), &popup2, 2);
+ popup.insertSeparator();
+ popup.insertItem(i18n("Hide This Tab"), 80);
+ popup.insertItem(i18n("Hide Area"), 90);
+
+ if (_tabView->visibleTabs() <2) {
+ popup.setItemEnabled(80, false);
+ popup.setItemEnabled(90, false);
+ }
+ else if (_tabView->visibleAreas() <2)
+ popup.setItemEnabled(90, false);
+ }
+ popup3.insertItem(i18n("Top"), 101);
+ popup3.insertItem(i18n("Right"), 102);
+ popup3.insertItem(i18n("Bottom"), 103);
+ popup3.insertItem(i18n("Bottom Left"), 104);
+ popup.insertItem(i18n("Show Hidden On"), &popup3, 3);
+
+ int r = popup.exec( mapToGlobal( e->pos() ) );
+
+ TraceItemView::Position p = TraceItemView::Hidden;
+ if ((r % 10) == 1) p = TraceItemView::Top;
+ if ((r % 10) == 2) p = TraceItemView::Right;
+ if ((r % 10) == 3) p = TraceItemView::Bottom;
+ if ((r % 10) == 4) p = TraceItemView::Left;
+
+ if (r>=80 && r<100) _tabView->moveTab(page, p, r>=90);
+ if (r>=100 && r<110) _tabView->moveTab(0, p, true);
+ }
+
+ TQTabBar::mousePressEvent( e );
+}
+
+
+//
+// Splitter
+//
+
+Splitter::Splitter(Qt::Orientation o, TQWidget* parent, const char* name)
+ : TQSplitter(o, parent, name)
+{}
+
+void Splitter::moveEvent(TQMoveEvent* e)
+{
+ TQSplitter::moveEvent(e);
+
+ if (0) qDebug("Splitter %s: Move", name());
+ checkVisiblity();
+}
+
+void Splitter::checkVisiblity()
+{
+ const TQObjectList l = childrenListObject();
+ TQObjectListIt it( l );
+ TQObject *obj;
+ while ( (obj = it.current()) != 0 ) {
+ ++it;
+ if (obj->isA("Splitter")) ((Splitter*)obj)->checkVisiblity();
+ else if (obj->isA("TabWidget")) ((TabWidget*)obj)->checkVisibility();
+ }
+}
+
+
+
+
+//
+// TabWidget
+//
+
+TabWidget::TabWidget(TabView* v, TQWidget* parent,
+ const char* name, WFlags f)
+ : TQTabWidget(parent, name, f)
+{
+ _hasVisibleRect = false;
+ setTabBar(new TabBar(v, this));
+}
+
+void TabWidget::checkVisibility()
+{
+ bool hasVisibleRect = (visibleRect().width()>1) &&
+ (visibleRect().height()>1);
+
+ if (0) qDebug("TabWidget %s: VR (%dx%d) HasVisibleRect: %s => %s",
+ name(),
+ visibleRect().width(), visibleRect().height(),
+ _hasVisibleRect ? "Yes":"No",
+ hasVisibleRect ? "Yes":"No");
+
+ if (hasVisibleRect != _hasVisibleRect) {
+ _hasVisibleRect = hasVisibleRect;
+ emit visibleRectChanged(this);
+ }
+}
+
+void TabWidget::resizeEvent(TQResizeEvent *e)
+{
+ TQTabWidget::resizeEvent(e);
+ if (0) qDebug("TabWidget %s:\n Resize from (%d/%d) to (%d/%d)",
+ name(),
+ e->oldSize().width(), e->oldSize().height(),
+ e->size().width(), e->size().height());
+ checkVisibility();
+}
+
+void TabWidget::showEvent(TQShowEvent* e)
+{
+ TQTabWidget::showEvent(e);
+
+ if (0) qDebug("TabWidget %s: Show", name());
+ checkVisibility();
+}
+
+void TabWidget::hideEvent(TQHideEvent* e)
+{
+ TQTabWidget::hideEvent(e);
+
+ if (0) qDebug("TabWidget %s: Hide", name());
+ checkVisibility();
+}
+
+void TabWidget::moveEvent(TQMoveEvent* e)
+{
+ TQTabWidget::moveEvent(e);
+
+ if (0) qDebug("TabWidget %s: Move", name());
+ checkVisibility();
+}
+
+
+
+//
+// TabView
+//
+
+/*
+ * Areas for child views
+ *
+ * leftSplitter
+ * |
+ * | ----- -----
+ * | _/ \_______________/ \____
+ * | | Top | TopRight |
+ * | | | |
+ * -> |---------------------| |
+ * | BottomLeft | Bottom | |
+ * | | | |
+ * -\_____/------\____/--------------
+ *
+ * ^ ^
+ * bottomSplitter mainSplitter
+ */
+
+TabView::TabView(TraceItemView* parentView,
+ TQWidget* parent, const char* name)
+ : TQWidget(parent, name), TraceItemView(parentView)
+{
+ setFocusPolicy(TQ_StrongFocus);
+
+ _isCollapsed = true;
+
+ TQVBoxLayout* vbox = new TQVBoxLayout( this, 6, 6);
+
+ _nameLabel = new KSqueezedTextLabel( this, "nameLabel" );
+ _nameLabel->setText(i18n("(No profile data file loaded)"));
+ vbox->addWidget( _nameLabel );
+
+ _mainSplitter = new TQSplitter(Qt::Horizontal, this);
+ _leftSplitter = new Splitter(Qt::Vertical, _mainSplitter, "Left");
+ vbox->addWidget( _mainSplitter );
+
+ _rightTW = new TabWidget(this, _mainSplitter, "Right");
+ connect(_rightTW, TQT_SIGNAL(currentChanged(TQWidget*)),
+ this, TQT_SLOT(tabChanged(TQWidget*)));
+ connect(_rightTW, TQT_SIGNAL(visibleRectChanged(TabWidget*)),
+ this, TQT_SLOT(visibleRectChangedSlot(TabWidget*)));
+
+ _topTW = new TabWidget(this, _leftSplitter, "Top");
+ connect(_topTW, TQT_SIGNAL(currentChanged(TQWidget*)),
+ this, TQT_SLOT(tabChanged(TQWidget*)));
+ connect(_topTW, TQT_SIGNAL(visibleRectChanged(TabWidget*)),
+ this, TQT_SLOT(visibleRectChangedSlot(TabWidget*)));
+
+ _bottomSplitter = new Splitter(Qt::Horizontal,
+ _leftSplitter, "Bottom");
+
+ _leftTW = new TabWidget(this, _bottomSplitter, "Left");
+ _leftTW->setTabPosition(TQTabWidget::Bottom);
+ connect(_leftTW, TQT_SIGNAL(currentChanged(TQWidget*)),
+ this, TQT_SLOT(tabChanged(TQWidget*)));
+ connect(_leftTW, TQT_SIGNAL(visibleRectChanged(TabWidget*)),
+ this, TQT_SLOT(visibleRectChangedSlot(TabWidget*)));
+
+ _bottomTW = new TabWidget(this, _bottomSplitter, "Bottom");
+ _bottomTW->setTabPosition(TQTabWidget::Bottom);
+ connect(_bottomTW, TQT_SIGNAL(currentChanged(TQWidget*)),
+ this, TQT_SLOT(tabChanged(TQWidget*)));
+ connect(_bottomTW, TQT_SIGNAL(visibleRectChanged(TabWidget*)),
+ this, TQT_SLOT(visibleRectChangedSlot(TabWidget*)));
+
+
+ // default positions...
+
+ addTop( addTab( i18n("Types"),
+ new CostTypeView(this, _topTW,
+ "CostTypeView")));
+ addTop( addTab( i18n("Callers"),
+ new CallView(true, this, _topTW,
+ "CallerView")));
+ addTop( addTab( i18n("All Callers"),
+ new CoverageView(true, this, _topTW,
+ "AllCallerView")));
+ addTop( addTab( i18n("Caller Map"),
+ new CallMapView(true, this, _bottomTW,
+ "CallerMapView")));
+ addTop( addTab( i18n("Source"),
+ new SourceView(this, _topTW,
+ "SourceView")));
+
+ addBottom( addTab( i18n("Parts"),
+ new PartView(this, _bottomTW,
+ "PartView")));
+ addBottom( addTab( i18n("Call Graph"),
+ new CallGraphView(this, _bottomTW,
+ "CallGraphView")));
+ addBottom( addTab( i18n("Callees"),
+ new CallView(false, this, _bottomTW,
+ "CalleeView")));
+ addBottom( addTab( i18n("All Callees"),
+ new CoverageView(false, this, _bottomTW,
+ "AllCalleeView")));
+
+ addBottom( addTab( i18n("Callee Map"),
+ new CallMapView(false, this, _topTW,
+ "CalleeMapView")));
+ addBottom( addTab( i18n("Assembler"),
+ new InstrView(this, _bottomTW,
+ "InstrView")));
+
+ // after all child widgets are created...
+ _lastFocus = 0;
+ _active = false;
+ installFocusFilters();
+
+ updateVisibility();
+
+ TQWhatsThis::add( this, whatsThis() );
+}
+
+void TabView::setData(TraceData* d)
+{
+ TraceItemView::setData(d);
+
+ TraceItemView* v;
+ for (v=_tabs.first();v;v=_tabs.next())
+ v->setData(d);
+}
+
+TraceItemView* TabView::addTab(TQString label, TraceItemView* view)
+{
+ view->setTitle(label);
+ _tabs.append(view);
+ return view;
+}
+
+void TabView::addTop(TraceItemView* view)
+{
+ view->setPosition(TraceItemView::Top);
+ _topTW->insertTab(view->widget(), view->title());
+}
+
+void TabView::addBottom(TraceItemView* view)
+{
+ view->setPosition(TraceItemView::Bottom);
+ _bottomTW->insertTab(view->widget(), view->title());
+}
+
+TraceItemView::Position TabView::tabPosition(TQWidget* w)
+{
+ TraceItemView* v;
+ for (v=_tabs.first();v;v=_tabs.next())
+ if (v->widget() == w) return v->position();
+
+ return Hidden;
+}
+
+int TabView::visibleTabs()
+{
+ int c = 0;
+ TraceItemView* v;
+ for (v=_tabs.first();v;v=_tabs.next()) {
+ if (v->position() == Hidden) continue;
+ c++;
+ }
+ return c;
+}
+
+
+int TabView::visibleAreas()
+{
+ int c = 0, t = 0, b = 0, r = 0, l = 0;
+ TraceItemView* v;
+ for (v=_tabs.first();v;v=_tabs.next()) {
+ switch(v->position()) {
+ case TraceItemView::Top: t++; break;
+ case TraceItemView::Bottom: b++; break;
+ case TraceItemView::Left: l++; break;
+ case TraceItemView::Right: r++; break;
+ default: break;
+ }
+ }
+ if (t>0) c++;
+ if (b>0) c++;
+ if (l>0) c++;
+ if (r>0) c++;
+
+ return c;
+}
+
+
+
+// This hides/shows splitters and tabwidgets according to tab childs
+void TabView::updateVisibility()
+{
+ // calculate count of tabs in areas
+ int t = 0, b = 0, r = 0, l = 0;
+ TraceItemView* v;
+ for (v=_tabs.first();v;v=_tabs.next()) {
+ switch(v->position()) {
+ case TraceItemView::Top: t++; break;
+ case TraceItemView::Bottom: b++; break;
+ case TraceItemView::Left: l++; break;
+ case TraceItemView::Right: r++; break;
+ default: break;
+ }
+ }
+
+ if (0) qDebug("TabView::updateVisiblity t %d, b %d, l %d, r %d",
+ t, b, l, r);
+
+ TQValueList<int> s;
+ s.append(100);
+
+
+ // children of mainSplitter
+ if (_rightTW->isHidden() != (r == 0)) {
+ if (r == 0) {
+ _rightTW->hide();
+
+ if (!_topTW->hasVisibleRect() &&
+ !_bottomTW->hasVisibleRect() &&
+ !_leftTW->hasVisibleRect()) _mainSplitter->setSizes(s);
+ }
+ else
+ _rightTW->show();
+ }
+ if (_leftSplitter->isHidden() != (t+b+l == 0)) {
+ if (t+b+l == 0) {
+ _leftSplitter->hide();
+
+ if (!_rightTW->hasVisibleRect()) _mainSplitter->setSizes(s);
+ }
+ else
+ _leftSplitter->show();
+ }
+
+ // children of leftSplitter
+ if (_topTW->isHidden() != (t == 0)) {
+ if (t == 0) {
+ _topTW->hide();
+
+ if (!_bottomTW->hasVisibleRect() &&
+ !_leftTW->hasVisibleRect()) _leftSplitter->setSizes(s);
+ }
+ else
+ _topTW->show();
+ }
+
+ if (_bottomSplitter->isHidden() != (b+l == 0)) {
+ if (b+l == 0) {
+ _bottomSplitter->hide();
+
+ if (!_topTW->hasVisibleRect()) _leftSplitter->setSizes(s);
+ }
+ else
+ _bottomSplitter->show();
+ }
+
+ // children of bottomSplitter
+ if (_bottomTW->isHidden() != (b == 0)) {
+ if (b == 0) {
+ _bottomTW->hide();
+
+ if (!_leftTW->hasVisibleRect()) _bottomSplitter->setSizes(s);
+ }
+ else
+ _bottomTW->show();
+ }
+ if (_leftTW->isHidden() != (l == 0)) {
+ if (l == 0) {
+ _leftTW->hide();
+
+ if (!_bottomTW->hasVisibleRect()) _bottomSplitter->setSizes(s);
+ }
+ else
+ _leftTW->show();
+ }
+}
+
+TabWidget* TabView::tabWidget(Position p)
+{
+ switch(p) {
+ case TraceItemView::Top: return _topTW;
+ case TraceItemView::Bottom: return _bottomTW;
+ case TraceItemView::Left: return _leftTW;
+ case TraceItemView::Right: return _rightTW;
+ default: break;
+ }
+ return 0;
+}
+
+void TabView::moveTab(TQWidget* w, Position p, bool wholeArea)
+{
+ TraceItemView *v;
+ Position origPos = Hidden;
+ if (w) {
+ for (v=_tabs.first();v;v=_tabs.next())
+ if (v->widget() == w) break;
+
+ if (!v) return;
+ origPos = v->position();
+ }
+ if (origPos == p) return;
+
+ TabWidget *from, *to;
+ from = tabWidget(origPos);
+ to = tabWidget(p);
+
+ TQPtrList<TraceItemView> tabs;
+ for (v=_tabs.first();v;v=_tabs.next())
+ if ((v->position() == origPos) &&
+ (wholeArea || (v->widget() == w))) tabs.append(v);
+
+ bool isEnabled;
+ for (v=tabs.first();v;v=tabs.next()) {
+ v->setPosition(p);
+ w = v->widget();
+
+ if (from) {
+ isEnabled = from->isTabEnabled(w);
+ from->removePage(w);
+ }
+ else isEnabled = (v->canShow(_activeItem)!=0);
+
+ if (to) {
+ TraceItemView *vv;
+ int idx = -1, i;
+ for(vv = _tabs.first(); vv && (vv!=v); vv = _tabs.next()) {
+ i = to->indexOf(vv->widget());
+ if (i>=0) idx = i;
+ }
+ to->insertTab(w, v->title(), idx+1);
+ to->setTabEnabled(w, isEnabled);
+ if (isEnabled) {
+ to->showPage(w);
+ v->updateView();
+ }
+ }
+ }
+ updateVisibility();
+}
+
+
+TQString TabView::whatsThis() const
+{
+ return i18n( "<b>Information Tabs</b>"
+ "<p>This widget shows information for the "
+ "current selected function in different tabs: "
+ "<ul>"
+ "<li>The Costs tab shows a list of available event types "
+ "and the inclusive and self costs regarding to these types.</li>"
+ "<li>The Parts tab shows a list of trace parts "
+ "if the trace consists of more than one part (otherwise, "
+ "this tab is hided). "
+ "The cost of the selected function spent in the different "
+ "parts together with the calls happening is shown.</li>"
+ "<li>The Call Lists tab shows direct callers and "
+ "callees of the function in more detail.</li>"
+ "<li>The Coverage tab shows the same is the Call "
+ "Lists tab, but not only direct callers and callees "
+ "but also indirect ones.</li>"
+ "<li>The Call Graph tab shows a graphical "
+ "visualization of the calls done by this function.</li>"
+ "<li>The Source tab presents annotated source code "
+ "if debugging information and the source file "
+ "is available.</li>"
+ "<li>The Assembler tab presents annotated assembler code "
+ "if trace information on instruction level "
+ "is available.</li></ul>"
+ "For more information, see the <em>What's This?</em> "
+ "help of the corresponding tab widget</p>");
+}
+
+void TabView::installFocusFilters()
+{
+ TQObjectList *l = queryList(TQWIDGET_OBJECT_NAME_STRING);
+ TQObjectListIt it( *l );
+ TQObject *obj;
+
+ while ( (obj = it.current()) != 0 ) {
+ ++it;
+ if ( ((TQWidget*)obj)->isFocusEnabled() )
+ obj->installEventFilter(this);
+ }
+ delete l;
+}
+
+
+bool TabView::eventFilter(TQObject* o, TQEvent* e)
+{
+ if (e->type() == TQEvent::FocusIn) {
+ _lastFocus = o->isWidgetType() ? (TQWidget*) o : 0;
+ setActive(_lastFocus != 0);
+ }
+ return TQWidget::eventFilter(o,e);
+}
+
+void TabView::mousePressEvent(TQMouseEvent*)
+{
+ if (_lastFocus)
+ _lastFocus->setFocus();
+ setActive(true);
+}
+
+void TabView::setActive(bool a)
+{
+ if (a == _active) return;
+ _active = a;
+
+ TQFont nameLabel_font( _nameLabel->font() );
+ nameLabel_font.setBold(a);
+ _nameLabel->setFont( nameLabel_font );
+
+ if (0) qDebug("%s::setActive(%s)", name(), a ? "true":"false");
+
+ if (a) emit activated(this);
+}
+
+void TabView::doUpdate(int changeType)
+{
+ if (changeType & (activeItemChanged | configChanged | dataChanged))
+
+ _nameLabel->setText( !_data ? i18n("(No Data loaded)") :
+ !_activeItem ? i18n("(No function selected)") :
+ _activeItem->prettyName());
+
+
+ // we use our own list iterators because setTabEnabled can
+ // invoke tabChanged, which mangles with the lists, too
+ bool canShow;
+ TraceItemView *v;
+ TQPtrListIterator<TraceItemView> it( _tabs );
+ while ( (v=it.current()) != 0) {
+ ++it;
+
+ TabWidget *tw = 0;
+ switch(v->position()) {
+ case TraceItemView::Top: tw = _topTW; break;
+ case TraceItemView::Bottom: tw = _bottomTW; break;
+ case TraceItemView::Left: tw = _leftTW; break;
+ case TraceItemView::Right: tw = _rightTW; break;
+ default: break;
+ }
+
+ // update even if hidden
+ if (tw) {
+ if (!tw->hasVisibleRect()) continue;
+ }
+ canShow = v->set(changeType, _data, _costType, _costType2,
+ _groupType, _partList,
+ _activeItem, _selectedItem);
+ v->notifyChange(changeType);
+
+ if (!tw) continue;
+ if (tw->isTabEnabled(v->widget()) != canShow)
+ tw->setTabEnabled(v->widget(), canShow);
+
+ if (v->widget() == tw->currentPage())
+ v->updateView();
+ }
+}
+
+
+void TabView::tabChanged(TQWidget* w)
+{
+ TraceItemView *v;
+ for (v=_tabs.first();v;v=_tabs.next())
+ if (v->widget() == w) v->updateView();
+}
+
+void TabView::visibleRectChangedSlot(TabWidget* tw)
+{
+ if (0) qDebug("%s: %svisible !",
+ tw->name(), tw->hasVisibleRect() ? "":"un");
+
+ if (tw->hasVisibleRect()) doUpdate(0);
+}
+
+void TabView::resizeEvent(TQResizeEvent* e)
+{
+ TQWidget::resizeEvent(e);
+
+ bool collapsed = (e->size().width()<=1) || (e->size().height()<=1);
+ if (_isCollapsed != collapsed) {
+ _isCollapsed = collapsed;
+ updateView();
+ }
+
+ if (0) qDebug("TabView::Resize from (%d/%d) to (%d/%d)",
+ e->oldSize().width(), e->oldSize().height(),
+ e->size().width(), e->size().height());
+}
+
+void TabView::selected(TraceItemView*, TraceItem* s)
+{
+ // we set selected item for our own children
+ select(s);
+ updateView();
+
+ // still forward to parent
+ if (_parentView) _parentView->selected(this, s);
+}
+
+
+void TabView::readViewConfig(KConfig* c,
+ TQString prefix, TQString postfix,
+ bool withOptions)
+{
+ if (0) qDebug("%s::readConfig(%s%s)", name(),
+ prefix.ascii(), postfix.ascii());
+
+ KConfigGroup* g = configGroup(c, prefix, postfix);
+
+ _mainSplitter->setSizes(g->readIntListEntry("MainSizes"));
+ _leftSplitter->setSizes(g->readIntListEntry("LeftSizes"));
+ _bottomSplitter->setSizes(g->readIntListEntry("BottomSizes"));
+
+ TQString activeT = g->readEntry("ActiveTop", "CallerView");
+ TQString activeB = g->readEntry("ActiveBottom", "CalleeView");
+ TQString activeL = g->readEntry("ActiveLeft", "");
+ TQString activeR = g->readEntry("ActiveRight", "");
+
+ TQStringList topTabs = g->readListEntry("TopTabs");
+ TQStringList bottomTabs = g->readListEntry("BottomTabs");
+ TQStringList leftTabs = g->readListEntry("LeftTabs");
+ TQStringList rightTabs = g->readListEntry("RightTabs");
+
+ if (topTabs.isEmpty() && bottomTabs.isEmpty() &&
+ rightTabs.isEmpty() && leftTabs.isEmpty()) {
+ // no tabs visible ?! Reset to default
+ topTabs << "CostTypeView" << "CallerView" << "AllCallerView"
+ << "CalleeMapView" << "SourceView";
+ bottomTabs << "PartView" << "CalleeView" << "CallGraphView"
+ << "AllCalleeView" << "CallerMapView" << "InstrView";
+ }
+
+ TraceItemView *activeTop = 0, *activeBottom = 0;
+ TraceItemView *activeLeft = 0, *activeRight = 0;
+
+ moveTab(0, TraceItemView::Top, true);
+ TraceItemView *v;
+ TQPtrListIterator<TraceItemView> it( _tabs );
+ while ( (v=it.current()) != 0) {
+ ++it;
+
+ TQString n = TQString(v->widget()->name());
+ if (topTabs.contains(n)) {
+ moveTab(v->widget(), TraceItemView::Top);
+ if (n == activeT) activeTop = v;
+ }
+ else if (bottomTabs.contains(n)) {
+ moveTab(v->widget(), TraceItemView::Bottom);
+ if (n == activeB) activeBottom = v;
+ }
+ else if (leftTabs.contains(n)) {
+ moveTab(v->widget(), TraceItemView::Left);
+ if (n == activeL) activeLeft = v;
+ }
+ else if (rightTabs.contains(n)) {
+ moveTab(v->widget(), TraceItemView::Right);
+ if (n == activeR) activeRight = v;
+ }
+ else moveTab(v->widget(), Hidden);
+
+ if (withOptions)
+ v->readViewConfig(c, TQString("%1-%2")
+ .arg(prefix).arg(v->widget()->name()),
+ postfix, true);
+ }
+ if (activeTop) _topTW->showPage(activeTop->widget());
+ if (activeBottom)_bottomTW->showPage(activeBottom->widget());
+ if (activeLeft) _leftTW->showPage(activeLeft->widget());
+ if (activeRight) _rightTW->showPage(activeRight->widget());
+
+ TQString activeType = g->readEntry("ActiveItemType", "");
+ TQString activeName = g->readEntry("ActiveItemName", "");
+ TQString selectedType = g->readEntry("SelectedItemType", "");
+ TQString selectedName = g->readEntry("SelectedItemName", "");
+ delete g;
+
+ if (!_data) return;
+
+ if (withOptions) {
+ // restore active item
+ TraceItem::CostType t = TraceItem::costType(activeType);
+ if (t==TraceItem::NoCostType) t = TraceItem::Function;
+ TraceCost* activeItem = _data->search(t, activeName, _costType);
+ if (!activeItem) return;
+ activate(activeItem);
+
+ // restore selected item
+ t = TraceItem::costType(selectedType);
+ if (t==TraceItem::NoCostType) t = TraceItem::Function;
+ TraceCost* selectedItem = _data->search(t, selectedName,
+ _costType, activeItem);
+ if (selectedItem) select(selectedItem);
+ }
+
+ updateView();
+}
+
+void TabView::saveViewConfig(KConfig* c,
+ TQString prefix, TQString postfix,
+ bool withOptions)
+{
+ KConfigGroup g(c, (prefix+postfix).ascii());
+
+ g.writeEntry("MainSizes", _mainSplitter->sizes());
+ g.writeEntry("LeftSizes", _leftSplitter->sizes());
+ g.writeEntry("BottomSizes", _bottomSplitter->sizes());
+
+ TQString a;
+ if ((_topTW->count()>0) &&
+ (_topTW->isTabEnabled(_topTW->currentPage())))
+ a = TQString(_topTW->currentPage()->name());
+ g.writeEntry("ActiveTop", a);
+
+ a.setLength(0);
+ if ((_bottomTW->count()>0) &&
+ (_bottomTW->isTabEnabled(_bottomTW->currentPage())))
+ a = TQString(_bottomTW->currentPage()->name());
+ g.writeEntry("ActiveBottom", a);
+
+ a.setLength(0);
+ if ((_leftTW->count()>0) &&
+ (_leftTW->isTabEnabled(_leftTW->currentPage())))
+ a = TQString(_leftTW->currentPage()->name());
+ g.writeEntry("ActiveLeft", a);
+
+ a.setLength(0);
+ if ((_rightTW->count()>0) &&
+ (_rightTW->isTabEnabled(_rightTW->currentPage())))
+ a = TQString(_rightTW->currentPage()->name());
+ g.writeEntry("ActiveRight", a);
+
+ if (withOptions)
+ if (_activeItem) {
+ g.writeEntry("ActiveItemType",
+ TraceItem::typeName(_activeItem->type()));
+ g.writeEntry("ActiveItemName", _activeItem->name());
+ if (_selectedItem) {
+ g.writeEntry("SelectedItemType",
+ TraceItem::typeName(_selectedItem->type()));
+ g.writeEntry("SelectedItemName", _selectedItem->name());
+ }
+ }
+
+ TQStringList topList, bottomList, leftList, rightList;
+ TraceItemView *v;
+ for (v=_tabs.first();v;v=_tabs.next()) {
+ switch(v->position()) {
+ case TraceItemView::Top:
+ topList << TQString(v->widget()->name());
+ break;
+
+ case TraceItemView::Bottom:
+ bottomList << TQString(v->widget()->name());
+ break;
+
+ case TraceItemView::Left:
+ leftList << TQString(v->widget()->name());
+ break;
+
+ case TraceItemView::Right:
+ rightList << TQString(v->widget()->name());
+ break;
+
+ default: break;
+ }
+ }
+
+ g.writeEntry("TopTabs", topList);
+ g.writeEntry("BottomTabs", bottomList);
+ g.writeEntry("LeftTabs", leftList);
+ g.writeEntry("RightTabs", rightList);
+
+ if (withOptions)
+ for (v=_tabs.first();v;v=_tabs.next())
+ v->saveViewConfig(c, TQString("%1-%2").arg(prefix)
+ .arg(v->widget()->name()), postfix, true);
+}
+
+#include "tabview.moc"
diff --git a/kdecachegrind/kdecachegrind/tabview.h b/kdecachegrind/kdecachegrind/tabview.h
new file mode 100644
index 0000000..b9b4026
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/tabview.h
@@ -0,0 +1,174 @@
+/* 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.
+*/
+
+/*
+ * Tab View, enclosing detailed views for one trace item in
+ * two tab widgets, separated by a splitter
+ */
+
+#ifndef TABVIEW_H
+#define TABVIEW_H
+
+#include <tqptrlist.h>
+#include <tqwidget.h>
+#include <tqtabwidget.h>
+#include <tqtabbar.h>
+#include <ksqueezedtextlabel.h>
+#include "traceitemview.h"
+
+class TQSplitter;
+class TabView;
+
+/**
+ * Subclass of TQTabBar to enable context menu on tabs
+ */
+class TabBar : public TQTabBar
+{
+ Q_OBJECT
+ TQ_OBJECT
+
+ public:
+ TabBar(TabView*, TQTabWidget* parent, const char *name = 0);
+ protected:
+ void mousePressEvent(TQMouseEvent *e);
+
+ private:
+ TQTabWidget* _tabWidget;
+ TabView* _tabView;
+};
+
+
+/**
+ * Own Splitter:
+ * Call checkVisiblity for all TabWidget children of the splitter
+ * on a MoveEvent. This typically is produced when collapsing the widget
+ * inside of another splitter.
+ */
+class Splitter: public TQSplitter
+{
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+ Splitter(Qt::Orientation o, TQWidget* parent = 0, const char* name = 0);
+ void checkVisiblity();
+
+protected:
+ void moveEvent(TQMoveEvent *);
+};
+
+
+/**
+ * Own TabView:
+ * - A TQTabWidget able to track its visible rect via resizeEvents.
+ * This is needed to track if this widget is collapsed in a TQSplitter.
+ * - Use own TabBar for context menu
+ */
+class TabWidget: public TQTabWidget
+{
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+
+ TabWidget(TabView*, TQWidget* parent = 0,
+ const char* name = 0, WFlags f = 0);
+
+ bool hasVisibleRect() { return _hasVisibleRect; }
+ void checkVisibility();
+
+signals:
+ void visibleRectChanged(TabWidget*);
+
+protected:
+ void resizeEvent(TQResizeEvent *);
+ void showEvent(TQShowEvent *);
+ void hideEvent(TQHideEvent *);
+ void moveEvent(TQMoveEvent *);
+
+private:
+ bool _hasVisibleRect;
+};
+
+
+
+class TabView : public TQWidget, public TraceItemView
+{
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+
+ TabView(TraceItemView* parentView,
+ TQWidget* parent = 0, const char* name = 0);
+
+ virtual TQWidget* widget() { return this; }
+ TQString whatsThis() const ;
+ void setData(TraceData*);
+ bool isViewVisible() const { return !_isCollapsed; }
+ void selected(TraceItemView*, TraceItem*);
+ bool active() const { return _active; }
+ void setActive(bool);
+
+ /**
+ * Rearrange tabs
+ * if <w> == 0, move hidden tabs
+ */
+ void moveTab(TQWidget* w, Position, bool wholeArea = false);
+
+ Position tabPosition(TQWidget*);
+ int visibleTabs();
+ int visibleAreas();
+
+ void readViewConfig(KConfig*, TQString prefix, TQString postfix, bool);
+ void saveViewConfig(KConfig*, TQString prefix, TQString postfix, bool);
+
+public slots:
+ void tabChanged(TQWidget*);
+ void visibleRectChangedSlot(TabWidget*);
+
+signals:
+ void activated(TabView*);
+
+protected:
+ void resizeEvent(TQResizeEvent *);
+ bool eventFilter(TQObject*, TQEvent*);
+ void mousePressEvent(TQMouseEvent*);
+
+private:
+ TraceItemView* addTab(TQString, TraceItemView*);
+ void addTop(TraceItemView*);
+ void addBottom(TraceItemView*);
+ TabWidget* tabWidget(Position);
+ void updateVisibility();
+ void doUpdate(int);
+ void installFocusFilters();
+
+ // this is true if width or height <= 1, and no child updates are done
+ bool _isCollapsed;
+
+ KSqueezedTextLabel* _nameLabel;
+ TQSplitter *_mainSplitter, *_leftSplitter, *_bottomSplitter;
+ TabWidget *_topTW, *_leftTW, *_bottomTW, *_rightTW;
+ TQPtrList<TraceItemView> _tabs;
+
+ TQWidget* _lastFocus;
+ bool _active;
+};
+
+#endif
diff --git a/kdecachegrind/kdecachegrind/kdecachegrind.desktop b/kdecachegrind/kdecachegrind/kdecachegrind.desktop
new file mode 100644
index 0000000..7089370
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/kdecachegrind.desktop
@@ -0,0 +1,103 @@
+# KDE Config File
+[Desktop Entry]
+Type=Application
+Exec=kdecachegrind -caption "%c" %i %m %u
+MimeType=application/x-kcachegrind;
+Icon=kdecachegrind
+DocPath=kdecachegrind/index.html
+Terminal=false
+Name=KCachegrind
+Name[hi]=के-केश-ग्रिंड
+Name[sv]=Kcachegrind
+Name[ta]= இடைமாற்றகட்டம்
+GenericName=Profiler Frontend
+GenericName[bs]=Profiler frontend
+GenericName[ca]=Interfície de Profiler
+GenericName[cs]=Rozhraní pro profilaci
+GenericName[cy]=Blaen-wyneb Proffilydd
+GenericName[da]=Grænseflade til profilering
+GenericName[de]=Profiler Oberfläche
+GenericName[el]=Πρόγραμμα προφίλ
+GenericName[eo]=Fasado de Profililo
+GenericName[es]=Interfaz para Profiler
+GenericName[et]=Profileerimisrakendus
+GenericName[eu]=Profilatzailearen interfazea
+GenericName[fa]=پایانۀ گزارش‌گیر
+GenericName[fi]=Profiloijan käyttöliittymä
+GenericName[fr]=Interface de profilage
+GenericName[ga]=Comhéadan ar Phróifíleoir
+GenericName[gl]=Interface para o profiler
+GenericName[hi]=प्रोफ़ाइलर फ्रन्टएण्ड
+GenericName[hu]=Profilozó
+GenericName[is]=Myndrænt viðmót á afkastakönnuð
+GenericName[it]=Interfaccia a profiler
+GenericName[ja]=プロファイラフロントエンド
+GenericName[ka]=პროფილერის Frontend
+GenericName[kk]=Профильдеткіштің интерфейсі
+GenericName[lt]=Profiliuoklio naudotojo sąsaja
+GenericName[nb]=Grensesnitt for profilvisning
+GenericName[nds]=Profiler-Böversiet
+GenericName[ne]=प्रोफाइलर फ्रन्टइन्ड
+GenericName[nl]=Profiler-hulpprogramma
+GenericName[nn]=Grensesnitt for profilvising
+GenericName[pa]=ਪਰੋਫਾਇਲਰ ਮੁੱਖ ਭੂਮੀ
+GenericName[pl]=Interfejs do profilera
+GenericName[pt]=Interface de Profiler
+GenericName[pt_BR]=Interface para o Profiler
+GenericName[ru]=Профилировщик
+GenericName[sk]=Rozhranie pre profiler
+GenericName[sl]=Vmesnik profilnika
+GenericName[sr]=Графички интерфејс за профајлер
+GenericName[sr@Latn]=Grafički interfejs za profajler
+GenericName[sv]=Profileringsgränssnitt
+GenericName[ta]= விவரக்குறிப்பு முன்பகுதி
+GenericName[tg]=Интерфейс ба профилкунанда
+GenericName[tr]=Profil Önyüzü
+GenericName[uk]=Інтерфейс до Profiler
+GenericName[zh_CN]=个性数据前端
+GenericName[zh_TW]=分析器前端
+Comment=Visualization of Performance Profiling Data
+Comment[bg]=Визуализация на данните за производителност
+Comment[bs]=Vizualizacija podataka za profiliranje performansi
+Comment[ca]=Visualizació de dades de perfilat de rendiment
+Comment[cs]=Vizualizace profilovacích dat výkonu
+Comment[da]=Visualisering af profileringsdata
+Comment[de]=Visualisierung von Daten des Laufzeitverhaltens eines Programmes
+Comment[el]=Αναπαράσταση δεδομένων ταχύτητας προφίλ
+Comment[en_GB]=Visualisation of Performance Profiling Data
+Comment[es]=Visualización de datos de análisis de rendimiento
+Comment[et]=Jõudluse profileerimise andmete visualiseerimise vahend
+Comment[eu]=Errendimendu profil datuen bistaratzea
+Comment[fa]=تجسم کارایی گزارش داده‌ها
+Comment[fi]=Visualisointi tehokkuusprofiloinnin tiedoista
+Comment[fr]=Visualisation des données de performance de profilage
+Comment[gl]=Visualización dos datos da análise de rendimento
+Comment[hi]=परफार्मेस प्रोफाइलिंग डाटा का विजुअलाइज़ेशन
+Comment[hu]=Teljesítményprofil-adatok megjelenítése
+Comment[is]=Sjónræn framsetning gagna úr afkastakönnun
+Comment[it]=Visualizzazione dei dati di profiling delle prestazioni
+Comment[ja]=パフォーマンスプロファイルデータを視覚化
+Comment[ka]=წარმადობის მაპროფფილებელი მონაცემების ვიზუალიზაცია
+Comment[kk]=Деректерді профильдеудің визуализациясы
+Comment[lt]=Veikimo profiliavimo duomenų vizualizacija
+Comment[nb]=Vis informasjon om ytelse.
+Comment[nds]=Visualiseren vun Programmleisten-Looptietdaten
+Comment[ne]=सम्पादन प्रोफाइलिङ डाटाको दृष्टिकरण
+Comment[nl]=Visualisatie van Performance Profiling Data
+Comment[nn]=Vis informasjon om yting
+Comment[pl]=Wizualizacja danych profilowania wydajności
+Comment[pt]=Visualização dos Dados de Análise de Performance
+Comment[pt_BR]=Visualização de Dados de Perfil de Desempenho
+Comment[ru]=Утилита для визуального профилирования приложений
+Comment[sk]=Vizualizácia dát o výkone
+Comment[sl]=Vizualizacija podatkov profilnih zmogljivosti
+Comment[sr]=Визуелизација података о профилисању перформанси
+Comment[sr@Latn]=Vizuelizacija podataka o profilisanju performansi
+Comment[sv]=Åskådliggörande av profileringsdata för prestanda
+Comment[ta]= விவர தகவலை செயல்பாட்டு காட்சியாளிப்பு
+Comment[tg]=Утилита барои гузориши профили визуалӣ
+Comment[uk]=Візуалізація даних профілювання швидкодії
+Comment[zh_CN]=性能个性数据的可视化表现
+Comment[zh_TW]=效能分析資料視覺化
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;Development;
diff --git a/kdecachegrind/kdecachegrind/kdecachegrindui.rc b/kdecachegrind/kdecachegrind/kdecachegrindui.rc
new file mode 100644
index 0000000..9531829
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/kdecachegrindui.rc
@@ -0,0 +1,57 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="kdecachegrind" version="4">
+ <MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="file_add" append="open_merge"/>
+ <Action name="reload" append="revert_merge"/>
+ <Action name="dump" append="revert_merge"/>
+ <Action name="export"/>
+ </Menu>
+ <Menu name="view"><text>&amp;View</text>
+ <Action name="view_cost_type"/>
+ <Action name="view_cost_type2"/>
+ <Action name="view_group_type"/>
+ <Separator/>
+ <Menu name="layouts"><text>&amp;Layout</text>
+ <Action name="layout_next"/>
+ <Action name="layout_previous"/>
+ <Action name="layout_duplicate"/>
+ <Action name="layout_remove"/>
+ <Separator/>
+ <Action name="layout_restore"/>
+ <Action name="layout_save"/>
+ </Menu>
+ <Action name="view_split"/>
+ <Action name="view_split_dir"/>
+ <Separator/>
+ <Action name="view_percentage"/>
+ <Action name="view_expanded"/>
+ <Action name="view_cycles"/>
+ </Menu>
+ <Menu name="settings">
+ <Menu append="show_toolbar_merge"><text>Sidebars</text>
+ <Action name="settings_show_dumpdock"/>
+ <Action name="settings_show_partdock"/>
+ <Action name="settings_show_stackdock"/>
+ <Action name="settings_show_profiledock"/>
+ </Menu>
+ </Menu>
+ </MenuBar>
+
+ <ToolBar name="mainToolBar" noMerge="1"><text>Main Toolbar</text>
+ <Action name="file_open"/>
+ <Action name="reload"/>
+ <Action name="dump"/>
+ <Separator/>
+ <Action name="go_up"/>
+ <Action name="go_back"/>
+ <Action name="go_forward"/>
+ <Separator/>
+ <Action name="view_percentage"/>
+ <Action name="view_expanded"/>
+ <Action name="view_cycles"/>
+ </ToolBar>
+ <ToolBar name="stateToolBar" noMerge="1"><text>State Toolbar</text>
+ <Action name="view_cost_type"/>
+ </ToolBar>
+</kpartgui>
diff --git a/kdecachegrind/kdecachegrind/tips b/kdecachegrind/kdecachegrind/tips
new file mode 100644
index 0000000..1f555c0
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/tips
@@ -0,0 +1,141 @@
+<tip category="KCachegrind|Help">
+<html>
+<p>...that the <em>What's This?</em> help for every GUI widget
+in KCachegrind contains detailed usage information for this widget?
+It is highly recommended to read at least these help texts on first
+use. Request <em>What's This?</em> help by pressing
+Shift+F1 and clicking on the widget.</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Explanation">
+<html>
+<p>...that you can get profile information at instruction level
+with Calltree when you provide the option <em>--dump-instr=yes</em>?
+Use the Assembler View for the instruction annotations.
+</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Keyboard">
+<html>
+<p>...that you can use Alt-Left/Right keys of your keyboard to go
+back/forward in the active object history ?</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Keyboard">
+<html>
+<p>...that you can navigate in the Callee/Caller Map View using
+arrow keys? Use Left/Right to change to siblings of the current
+item; use Up/Down to go one nesting level up/down. To select
+the current item, press Space, and to activate it, press Return.
+</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Keyboard">
+<html>
+<p>...that you can navigate in the Call Graph View using
+arrow keys? Use Up/Down to go one calling level up/down, alternating
+between calls and functions. Use Left/Right to change to siblings of a current
+selected call. To activate the current item, press Return.
+</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Filters">
+<html>
+<p>...that you can rapidly locate a function by entering part of its
+name (case-insensitive) into the edit line of the toolbar
+and hit return?</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Appearance">
+<html>
+<p>...that you can assign custom colors to
+ELF objects/C++ Classes/Source Files for graph coloring
+in <em>Settings->Configure KCachegrind...</em>?</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Configuration">
+<html>
+<p>...that you can see if debug info is available for a selected
+function by looking at the location label in the Info tab or
+the source listing header in the source tab?</p>
+<p>There must be the name of the source file (with extension).
+If KCachegrind still doesn't show the source, make sure that you
+have added the directory of the source file to the
+<em>Source Directories</em> list in the configuration.
+</html>
+</tip>
+
+<tip category="KCachegrind|Appearance">
+<html>
+<p>...that you can configure whether KCachgrind should
+show absolute event counts or relative ones (percentage display)?</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Appearance">
+<html>
+<p>...that you can configure the maximum number of items
+for all function lists in KCachegrind? Limiting the number
+of items is done to get a fast reacting GUI. The last item in
+the list will show you the number of skipped functions, together
+with a cost condition for these skipped functions.</p>
+<p>To activate a function with small costs, search for it and select
+it in the flat profile. Selecting functions with small cost will
+temporarily add them to the flat profile list.</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Explanation">
+<html>
+<p>...that the Coverage tab - in contrast to the Call Lists tab -
+shows <em>all</em> functions that are calling the selected function
+(upper part) / are called by the selected function (bottom part),
+no matter how many function are between them on the stack?</p>
+<p>Examples:</p>
+<p>An entry in the upper list for function foo1() with a value of 50%
+with function bar() selected means that 50% of all the cost of function
+bar() happened while called from function foo1().</p>
+<p>An entry in the bottom list for function foo2() with a value of 50%
+with function bar() selected means that 50% of all the cost of function
+bar() happened while calling foo2() from bar().</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Explanation">
+<html>
+<p>...that waiting for the tool tip inside of a tree map
+shows the list of names of the nested rectangles the mouse
+pointer is over?</p>
+<p>Items from this list can be selected by pressing the right
+mouse button.</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Explanation">
+<html>
+<p>...that you can constrain the cost counts shown to only a
+few parts of the whole trace by selecting these parts in the
+"Trace Selection" Dockable?</p>
+<p>To generate multiple parts in a profiling run with
+cachegrind, use e.g. option --cachedumps=xxx for parts
+of a length of xxx basic blocks (A basic block is a run
+of not-branching assembler statements inside of your program
+code).</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Explanation">
+<p>...that by splitting the view to show information of
+two functions simultaniously, selecting a function in
+one panel shows the information for that function
+in the other panel?</p>
+</html>
+</tip>
+
diff --git a/kdecachegrind/kdecachegrind/toplevel.cpp b/kdecachegrind/kdecachegrind/toplevel.cpp
new file mode 100644
index 0000000..5a2e1de
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/toplevel.cpp
@@ -0,0 +1,2389 @@
+/* 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.
+*/
+
+/*
+ * KCachegrind top level window
+ */
+
+#define TRACE_UPDATES 0
+#define ENABLE_DUMPDOCK 0
+
+#include <stdlib.h> // for system()
+
+#include <tqvbox.h>
+#include <tqtimer.h>
+#include <tqwhatsthis.h>
+#include <tqlineedit.h>
+#include <tqtextstream.h>
+#include <tqsizepolicy.h>
+#include <tqprogressbar.h>
+#include <tqfile.h>
+#include <tqeventloop.h>
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kstatusbar.h>
+#include <kstdaccel.h>
+#include <kstdaction.h>
+#include <kaction.h>
+#include <kurl.h>
+#include <kfiledialog.h>
+#include <kio/netaccess.h>
+#include <kedittoolbar.h>
+#include <kkeydialog.h>
+#include <ktip.h>
+#include <kpopupmenu.h>
+#include <kdebug.h>
+
+#if ENABLE_DUMPDOCK
+#include "dumpselection.h"
+#endif
+
+#include "toplevel.h"
+#include "partselection.h"
+#include "functionselection.h"
+#include "stackselection.h"
+#include "stackbrowser.h"
+#include "tracedata.h"
+#include "configuration.h"
+#include "configdlg.h"
+#include "multiview.h"
+#include "callgraphview.h"
+
+
+TopLevel::TopLevel(const char *name)
+ : KMainWindow(0, name), DCOPObject("KCachegrindIface")
+{
+ init();
+
+ createDocks();
+
+ _multiView = new MultiView(this, this, "MultiView");
+ setCentralWidget(_multiView);
+
+ createActions();
+
+ _partDockShown->setChecked(!_partDock->isHidden());
+ _stackDockShown->setChecked(!_stackDock->isHidden());
+ _functionDockShown->setChecked(!_functionDock->isHidden());
+
+ connect(_partDock, TQT_SIGNAL(visibilityChanged(bool)),
+ TQT_TQOBJECT(this), TQT_SLOT(partVisibilityChanged(bool)));
+ connect(_stackDock, TQT_SIGNAL(visibilityChanged(bool)),
+ TQT_TQOBJECT(this), TQT_SLOT(stackVisibilityChanged(bool)));
+ connect(_functionDock, TQT_SIGNAL(visibilityChanged(bool)),
+ TQT_TQOBJECT(this), TQT_SLOT(functionVisibilityChanged(bool)));
+
+#if ENABLE_DUMPDOCK
+ _dumpDockShown->setChecked(!_dumpDock->isHidden());
+ connect(_dumpDock, TQT_SIGNAL(visibilityChanged(bool)),
+ TQT_TQOBJECT(this), TQT_SLOT(dumpVisibilityChanged(bool)));
+#endif
+
+ _statusbar = statusBar();
+ _statusLabel = new TQLabel(_statusbar);
+#if 0
+ // how to do avoid main window resizing on large statusbar label?
+ TQSizePolicy p(TQSizePolicy::Fixed, TQSizePolicy::Expanding);
+ _statusLabel->setSizePolicy(p);
+ _statusbar->setSizePolicy(p);
+#endif
+ _statusbar->addWidget(_statusLabel, 1);
+
+ KConfig* kconfig = KGlobal::config();
+ Configuration::readOptions( kconfig );
+ _openRecent->loadEntries( kconfig );
+
+ // set toggle after reading configuration
+ _showPercentage = Configuration::showPercentage();
+ _showExpanded = Configuration::showExpanded();
+ _showCycles = Configuration::showCycles();
+ _taPercentage->setChecked(_showPercentage);
+ _taExpanded->setChecked(_showExpanded);
+ _taCycles->setChecked(_showCycles);
+
+ setupPartSelection(_partSelection);
+
+ // KCachegrind for KDE 3.0.x does not allow to hide toolbars...
+#if KDE_VERSION >= 308 // KDE 3.1
+ setStandardToolBarMenuEnabled(true);
+#endif
+
+ // QT dock windows are created before (using QT position restoring)
+ createGUI();
+
+ setAutoSaveSettings();
+
+ // restore current state settings (not configuration options)
+ restoreCurrentState(TQString());
+
+ // if this is the first toplevel, show tip of day
+ if (memberList->count() == 1)
+ TQTimer::singleShot( 200, TQT_TQOBJECT(this), TQT_SLOT(slotShowTipOnStart()) );
+}
+
+void TopLevel::init()
+{
+ _activeParts.clear();
+ _hiddenParts.clear();
+
+ _progressBar = 0;
+
+ _data = 0;
+ _function = 0;
+ _costType = 0;
+ _costType2 = 0;
+ _groupType = TraceCost::NoCostType;
+ _group = 0;
+
+ _layoutCurrent = 0;
+ _layoutCount = 1;
+
+ // for delayed slots
+ _traceItemDelayed = 0;
+ _costTypeDelayed = 0;
+ _costType2Delayed = 0;
+ _groupTypeDelayed = TraceCost::NoCostType;
+ _groupDelayed = 0;
+ _directionDelayed = TraceItemView::None;
+ _lastSender = 0;
+}
+
+
+/**
+ * Setup the part selection widget.
+ * Statusbar has to be created before.
+ */
+void TopLevel::setupPartSelection(PartSelection* ps)
+{
+ // setup connections from the part selection widget
+
+ connect(ps, TQT_SIGNAL(activePartsChanged(const TracePartList&)),
+ TQT_TQOBJECT(this), TQT_SLOT(activePartsChangedSlot(const TracePartList&)));
+ connect(ps, TQT_SIGNAL(groupChanged(TraceCostItem*)),
+ TQT_TQOBJECT(this), TQT_SLOT(setGroupDelayed(TraceCostItem*)));
+ connect(ps, TQT_SIGNAL(functionChanged(TraceItem*)),
+ TQT_TQOBJECT(this), TQT_SLOT(setTraceItemDelayed(TraceItem*)));
+
+ connect(ps, TQT_SIGNAL(goBack()),
+ _stackSelection, TQT_SLOT(browserBack()));
+
+ connect(ps, TQT_SIGNAL(partsHideSelected()),
+ TQT_TQOBJECT(this), TQT_SLOT(partsHideSelectedSlotDelayed()));
+ connect(ps, TQT_SIGNAL(partsUnhideAll()),
+ TQT_TQOBJECT(this), TQT_SLOT(partsUnhideAllSlotDelayed()));
+
+ connect(ps, TQT_SIGNAL(showMessage(const TQString&, int)),
+ _statusbar, TQT_SLOT(message(const TQString&, int)));
+}
+
+/**
+ * This saves the current state of the main window and
+ * sub widgets.
+ *
+ * No positions are saved. These is done automatically for
+ * KToolbar, and manually in queryExit() for QT docks.
+ */
+void TopLevel::saveCurrentState(TQString postfix)
+{
+ KConfig* kconfig = KGlobal::config();
+ TQCString pf = postfix.ascii();
+
+ KConfigGroup psConfig(kconfig, TQCString("PartOverview")+pf);
+ _partSelection->saveVisualisationConfig(&psConfig);
+
+ KConfigGroup stateConfig(kconfig, TQCString("CurrentState")+pf);
+ stateConfig.writeEntry("CostType",
+ _costType ? _costType->name() : TQString("?"));
+ stateConfig.writeEntry("CostType2",
+ _costType2 ? _costType2->name() : TQString("?"));
+ stateConfig.writeEntry("GroupType", TraceItem::typeName(_groupType));
+
+ _multiView->saveViewConfig(kconfig, TQString("MainView"), postfix, true);
+}
+
+/**
+ * This function is called when a trace is closed.
+ * Save browsing position for later restoring
+ */
+void TopLevel::saveTraceSettings()
+{
+ TQString key = traceKey();
+
+ KConfigGroup pConfig(KGlobal::config(), TQCString("TracePositions"));
+ pConfig.writeEntry(TQString("CostType%1").arg(key),
+ _costType ? _costType->name() : TQString("?"));
+ pConfig.writeEntry(TQString("CostType2%1").arg(key),
+ _costType2 ? _costType2->name() : TQString("?"));
+ pConfig.writeEntry(TQString("GroupType%1").arg(key),
+ TraceItem::typeName(_groupType));
+
+ if (!_data) return;
+
+ KConfigGroup aConfig(KGlobal::config(), TQCString("Layouts"));
+ aConfig.writeEntry(TQString("Count%1").arg(key), _layoutCount);
+ aConfig.writeEntry(TQString("Current%1").arg(key), _layoutCurrent);
+
+ saveCurrentState(key);
+ pConfig.writeEntry(TQString("Group%1").arg(key),
+ _group ? _group->name() : TQString());
+}
+
+/**
+ * This restores the current state of the main window and
+ * sub widgets.
+ *
+ * This does NOT restore any positions. This is done automatically for
+ * KToolbar, and manually in the createDocks() for QT docks..
+ */
+void TopLevel::restoreCurrentState(TQString postfix)
+{
+ KConfig* kconfig = KGlobal::config();
+ TQStringList gList = kconfig->groupList();
+ TQCString pf = postfix.ascii();
+
+ // dock properties (not position, this should be have done before)
+ TQCString group = TQCString("PartOverview");
+ if (gList.contains(group+pf)) group += pf;
+ KConfigGroup psConfig(kconfig, group);
+ _partSelection->readVisualisationConfig(&psConfig);
+
+ _multiView->readViewConfig(kconfig, TQString("MainView"), postfix, true);
+ _taSplit->setChecked(_multiView->childCount()>1);
+ _taSplitDir->setEnabled(_multiView->childCount()>1);
+ _taSplitDir->setChecked(_multiView->orientation() == Qt::Horizontal);
+}
+
+
+void TopLevel::createDocks()
+{
+ _partDock = new TQDockWindow(TQDockWindow::InDock, this);
+ _partDock->setCaption(i18n("Parts Overview"));
+ _partDock->setCloseMode( TQDockWindow::Always );
+ _partSelection = new PartSelection(_partDock, "partSelection");
+ _partDock->setWidget(_partSelection);
+ _partDock->setResizeEnabled(true);
+ _partDock->setFixedExtentWidth(200);
+ TQWhatsThis::add( _partSelection, i18n(
+ "<b>The Parts Overview</b>"
+ "<p>A trace consists of multiple trace parts when "
+ "there are several profile data files from one profile run. "
+ "The Trace Part Overview dockable shows these, "
+ "horizontally ordered in execution time; "
+ "the rectangle sizes are proportional to the total "
+ "cost spent in the parts. You can select one or several "
+ "parts to constrain all costs shown to these parts only."
+ "</p>"
+ "<p>The parts are further subdivided: there is a "
+ "partitioning and an callee split mode: "
+ "<ul><li>Partitioning: You see the "
+ "partitioning into groups for a trace part, according to "
+ "the group type selected. E.g. if ELF object groups are "
+ "selected, you see colored rectangles for each "
+ "used ELF object (shared library or executable), sized "
+ "according to the cost spent therein.</li>"
+ "<li>Callee: A rectangle showing the inclusive "
+ "cost of the current selected function in the trace part "
+ "is shown. "
+ "This is split up into smaller rectangles to show the costs of its "
+ "callees.</li></ul></p>"));
+
+ _stackDock = new TQDockWindow(TQDockWindow::InDock, this);
+ _stackDock->setResizeEnabled(true);
+ // Why is the caption only correct with a close button?
+ _stackDock->setCloseMode( TQDockWindow::Always );
+ _stackSelection = new StackSelection(_stackDock, "stackSelection");
+ _stackDock->setWidget(_stackSelection);
+ _stackDock->setFixedExtentWidth(200);
+ _stackDock->setCaption(i18n("Top Cost Call Stack"));
+ TQWhatsThis::add( _stackSelection, i18n(
+ "<b>The Top Cost Call Stack</b>"
+ "<p>This is a purely fictional 'most probable' call stack. "
+ "It is built up by starting with the current selected "
+ "function and adds the callers/callees with highest cost "
+ "at the top and to bottom.</p>"
+ "<p>The <b>Cost</b> and <b>Calls</b> columns show the "
+ "cost used for all calls from the function in the line "
+ "above.</p>"));
+
+ connect(_stackSelection, TQT_SIGNAL(functionSelected(TraceItem*)),
+ TQT_TQOBJECT(this), TQT_SLOT(setTraceItemDelayed(TraceItem*)));
+
+ _functionDock = new TQDockWindow(TQDockWindow::InDock, this);
+ _functionDock->setCaption(i18n("Flat Profile"));
+ _functionDock->setCloseMode( TQDockWindow::Always );
+ _functionSelection = new FunctionSelection(this, _functionDock,
+ "functionSelection");
+ _functionSelection->setTopLevel(this);
+
+ _functionDock->setWidget(_functionSelection);
+ _functionDock->setResizeEnabled(true);
+ _functionDock->setFixedExtentWidth(200);
+ TQWhatsThis::add( _functionSelection, i18n(
+ "<b>The Flat Profile</b>"
+ "<p>The flat profile contains a group and a function "
+ "selection list. The group list contains all groups "
+ "where costs "
+ "are spent in, depending on the chosen group type. "
+ "The group list is hidden when group type 'Function' "
+ "is selected.<p>"
+ "<p>The function list contains the functions of the "
+ "selected group (or all for 'Function' group type), "
+ "ordered by the costs spent therein. Functions with "
+ "costs less than 1% are hidden on default.</p>"));
+
+#if ENABLE_DUMPDOCK
+ _dumpDock = new TQDockWindow(TQDockWindow::InDock, this);
+ _dumpDock->setCaption(i18n("Profile Dumps"));
+ _dumpDock->setCloseMode( TQDockWindow::Always );
+ _dumpSelection = new DumpSelection(this, _dumpDock,
+ "dumpSelection");
+ _dumpSelection->setTopLevel(this);
+
+ _dumpDock->setWidget(_dumpSelection);
+ _dumpDock->setResizeEnabled(true);
+ _dumpDock->setFixedExtentWidth(200);
+ TQWhatsThis::add( _dumpSelection, i18n(
+ "<b>Profile Dumps</b>"
+ "<p>This dockable shows in the top part the list of "
+ "loadable profile dumps in all subdirectories of: "
+ "<ul><li>current working directory of KCachegrind, "
+ "i.e. where it was started from, and "
+ "<li>the default profile dump directory given in the "
+ "configuration.</ul> "
+ "The list is sorted according the the target command "
+ "profiled in the corresponding dump.</p>"
+ "<p>On selecting a profile dump, information for it "
+ "is shown in the bottom area of the dockable: "
+ "<ul><li><b>Options</b> allows you to view the profiled "
+ "command and profile options of this dump. By changing "
+ "any item, a new (yet unexisting) profile template "
+ "is created. Press <b>Run Profile</b> to start a"
+ "profile run with these options in the background. "
+ "<li><b>Info</b> gives detailed info on the selected "
+ "dump like event cost summary and properties of the "
+ "simulated cache. "
+ "<li><b>State</b> is only available for current happening "
+ "profiles runs. Press <b>Update</b> to see different "
+ "counters of the run, and a stack trace of the current "
+ "position in the program profiled. Check the <b>Every</b> "
+ "option to let KCachegrind regularly poll these data. "
+ "Check the <b>Sync</b> option to let the dockable activate "
+ "the top function in the current loaded dump.</ul></p>"));
+#endif
+
+ // Restore QT Dock positions...
+ KConfigGroup dockConfig(KGlobal::config(), TQCString("Docks"));
+ TQString str = dockConfig.readEntry("Position", TQString());
+ if (0) qDebug("Docks/Position: '%s'", str.ascii());
+ if (str.isEmpty()) {
+ // default positions
+ addDockWindow(_partDock, DockLeft);
+ addDockWindow(_stackDock, DockLeft);
+ addDockWindow(_functionDock, DockLeft);
+ _stackDock->hide();
+#if ENABLE_DUMPDOCK
+ addDockWindow(_dumpDock, DockLeft);
+ _dumpDock->hide();
+#endif
+ }
+ else {
+ TQTextStream ts( &str, IO_ReadOnly );
+ ts >> *this;
+ }
+ _forcePartDock = dockConfig.readBoolEntry("ForcePartDockVisible", false);
+
+#if 0
+ // dock context menu
+ setAppropriate(_partDock, true);
+ setAppropriate(_stackDock, true);
+ setAppropriate(_dumpDock, true);
+ setAppropriate(_functionDock, true);
+
+ connect( _partDock, TQT_SIGNAL(contextMenuRequested(const TQPoint &)),
+ TQT_TQOBJECT(this), TQT_SLOT(showDockMenu(const TQPoint &)));
+#endif
+}
+
+
+TopLevel::~TopLevel()
+{
+ delete _data;
+}
+
+
+void TopLevel::saveProperties(KConfig* c)
+{
+ c->writeEntry("TraceName", _data->traceName());
+}
+
+void TopLevel::readProperties(KConfig* c)
+{
+ TQString traceName = c->readEntry("TraceName");
+ if (!traceName.isEmpty()) {
+ TraceData* d = new TraceData(this);
+ d->load(traceName);
+ setData(d);
+ }
+}
+
+void TopLevel::createLayoutActions()
+{
+ TQString hint;
+ KAction* action;
+
+ action = new KAction( i18n( "&Duplicate" ),
+ KShortcut(KKey("Ctrl+Plus")),
+ TQT_TQOBJECT(this), TQT_SLOT(layoutDuplicate()),
+ actionCollection(), "layout_duplicate" );
+ hint = i18n("<b>Duplicate Current Layout</b>"
+ "<p>Make a copy of the current layout.</p>");
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n( "&Remove" ), KShortcut(),
+ TQT_TQOBJECT(this), TQT_SLOT(layoutRemove()),
+ actionCollection(), "layout_remove" );
+ hint = i18n("<b>Remove Current Layout</b>"
+ "<p>Delete current layout and make the previous active.</p>");
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n( "&Go to Next" ),
+ KShortcut(KKey("Ctrl+Right")),
+ TQT_TQOBJECT(this), TQT_SLOT(layoutNext()),
+ actionCollection(), "layout_next" );
+ hint = i18n("Go to Next Layout");
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n( "&Go to Previous" ),
+ KShortcut(KKey("Ctrl+Left")),
+ TQT_TQOBJECT(this), TQT_SLOT(layoutPrevious()),
+ actionCollection(), "layout_previous" );
+ hint = i18n("Go to Previous Layout");
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n( "&Restore to Default" ), KShortcut(),
+ TQT_TQOBJECT(this), TQT_SLOT(layoutRestore()),
+ actionCollection(), "layout_restore" );
+ hint = i18n("Restore Layouts to Default");
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n( "&Save as Default" ), KShortcut(),
+ TQT_TQOBJECT(this), TQT_SLOT(layoutSave()),
+ actionCollection(), "layout_save" );
+ hint = i18n("Save Layouts as Default");
+ action->setWhatsThis( hint );
+}
+
+// TODO: split this up...
+void TopLevel::createMiscActions()
+{
+ TQString hint;
+ KAction* action;
+
+ action = KStdAction::openNew(TQT_TQOBJECT(this), TQT_SLOT(newWindow()), actionCollection());
+ hint = i18n("<b>New</b><p>Open new empty KCachegrind window.</p>");
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n( "&Add..." ), KShortcut(),
+ TQT_TQOBJECT(this), TQT_SLOT(addTrace()),
+ actionCollection(), "file_add" );
+ hint = i18n("<b>Add Profile Data</b>"
+ "<p>This opens an additional profile data file in the current window.</p>");
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n( "&Reload" ), "reload",
+#if KDE_VERSION > 0x030190
+ // for KDE 3.2: KStdAccel::key is deprecated
+ KStdAccel::shortcut(KStdAccel::Reload),
+#else
+ KStdAccel::key(KStdAccel::Reload),
+#endif
+ TQT_TQOBJECT(this), TQT_SLOT( reload() ), actionCollection(), "reload" );
+ hint = i18n("<b>Reload Profile Data</b>"
+ "<p>This loads any new created parts, too.</p>");
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n( "&Export Graph" ), KShortcut(),
+ TQT_TQOBJECT(this), TQT_SLOT(exportGraph()),
+ actionCollection(), "export" );
+
+ hint = i18n("<b>Export Call Graph</b>"
+ "<p>Generates a file with extension .dot for the tools "
+ "of the GraphViz package.</p>");
+ action->setWhatsThis( hint );
+
+
+ _taDump = new KToggleAction( i18n( "&Force Dump" ), "redo",
+#if KDE_VERSION > 0x030190
+ // for KDE 3.2: KStdAccel::key is deprecated
+ KStdAccel::shortcut(KStdAccel::Redo),
+#else
+ KStdAccel::key(KStdAccel::Redo),
+#endif
+ TQT_TQOBJECT(this), TQT_SLOT( forceTrace() ),
+ actionCollection(), "dump" );
+ hint = i18n("<b>Force Dump</b>"
+ "<p>This forces a dump for a Callgrind profile run "
+ "in the current directory. This action is checked while "
+ "KCachegrind looks for the dump. If the dump is "
+ "finished, it automatically reloads the current trace. "
+ "If this is the one from the running Callgrind, the new "
+ "created trace part will be loaded, too.</p>"
+ "<p>Force dump creates a file 'callgrind.cmd', and "
+ "checks every second for its existence. A running "
+ "Callgrind will detect this file, dump a trace part, "
+ "and delete 'callgrind.cmd'. "
+ "The deletion is detected by KCachegrind, "
+ "and it does a Reload. If there's <em>no</em> Callgrind "
+ "running, press 'Force Dump' again to cancel the dump "
+ "request. This deletes 'callgrind.cmd' itself and "
+ "stops polling for a new dump.</p>"
+ "<p>Note: A Callgrind run <em>only</em> detects "
+ "existence of 'callgrind.cmd' when actively running "
+ "a few milliseconds, i.e. "
+ "<em>not</em> sleeping. Tip: For a profiled GUI program, "
+ "you can awake Callgrind e.g. by resizing a window "
+ "of the program.</p>");
+ _taDump->setWhatsThis( hint );
+
+ action = KStdAction::open(TQT_TQOBJECT(this), TQT_SLOT(loadTrace()), actionCollection());
+ hint = i18n("<b>Open Profile Data</b>"
+ "<p>This opens a profile data file, with possible multiple parts</p>");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ _openRecent = KStdAction::openRecent(TQT_TQOBJECT(this), TQT_SLOT(loadTrace(const KURL&)),
+ actionCollection());
+
+ KStdAction::showStatusbar(TQT_TQOBJECT(this),
+ TQT_SLOT(toggleStatusBar()), actionCollection());
+
+ _partDockShown = new KToggleAction(i18n("Parts Overview"), KShortcut(),
+ TQT_TQOBJECT(this), TQT_SLOT(togglePartDock()),
+ actionCollection(),
+ "settings_show_partdock");
+
+ hint = i18n("Show/Hide the Parts Overview Dockable");
+ _partDockShown->setToolTip( hint );
+ _partDockShown->setWhatsThis( hint );
+
+ _stackDockShown = new KToggleAction(i18n("Call Stack"), KShortcut(),
+ TQT_TQOBJECT(this), TQT_SLOT(toggleStackDock()),
+ actionCollection(),
+ "settings_show_stackdock");
+
+ hint = i18n("Show/Hide the Call Stack Dockable");
+ _stackDockShown->setToolTip( hint );
+ _stackDockShown->setWhatsThis( hint );
+
+ _functionDockShown = new KToggleAction(i18n("Function Profile"), KShortcut(),
+ TQT_TQOBJECT(this), TQT_SLOT(toggleFunctionDock()),
+ actionCollection(),
+ "settings_show_profiledock");
+
+ hint = i18n("Show/Hide the Function Profile Dockable");
+ _functionDockShown->setToolTip( hint );
+ _functionDockShown->setWhatsThis( hint );
+
+#if ENABLE_DUMPDOCK
+ _dumpDockShown = new KToggleAction(i18n("Profile Dumps"), KShortcut(),
+ TQT_TQOBJECT(this), TQT_SLOT(toggleDumpDock()),
+ actionCollection(),
+ "settings_show_dumpdock");
+
+ hint = i18n("Show/Hide the Profile Dumps Dockable");
+ _dumpDockShown->setToolTip( hint );
+ _dumpDockShown->setWhatsThis( hint );
+#endif
+
+ _taPercentage = new KToggleAction(i18n("Show Relative Costs"), "percent",
+ KShortcut(),
+ TQT_TQOBJECT(this), TQT_SLOT(togglePercentage()),
+ actionCollection(),
+ "view_percentage");
+#if KDE_VERSION >= 0x030290
+ // for KDE 3.3: show another text instead of a checkmark
+ _taPercentage->setCheckedState(i18n("Show Absolute Costs"));
+#endif
+
+ hint = i18n("Show relative instead of absolute costs");
+ _taPercentage->setToolTip( hint );
+ _taPercentage->setWhatsThis( hint );
+
+ _taExpanded = new KToggleAction(i18n("Percentage Relative to Parent"), "move",
+ KShortcut(),
+ TQT_TQOBJECT(this), TQT_SLOT(toggleExpanded()),
+ actionCollection(),
+ "view_expanded");
+
+ hint = i18n("Show percentage costs relative to parent");
+ _taExpanded->setToolTip( hint );
+ _taExpanded->setWhatsThis( hint );
+
+ hint = i18n("<b>Show percentage costs relative to parent</b>"
+ "<p>If this is switched off, percentage costs are always shown "
+ "relative to the total cost of the profile part(s) that are "
+ "currently browsed. By turning on this option, percentage cost "
+ "of shown cost items will be relative to the parent cost item."
+ "<ul><table>"
+ "<tr><td><b>Cost Type</td><td><b>Parent Cost</td></tr>"
+ "<tr><td>Function Cumulative</td><td>Total</td></tr>"
+ "<tr><td>Function Self</td><td>Function Group (*) / Total</td></tr>"
+ "<tr><td>Call</td><td>Function Cumulative</td></tr>"
+ "<tr><td>Source Line</td><td>Function Cumulative</td></tr>"
+ "</table>"
+ "<p>(*) Only if function grouping is switched on (e.g. ELF object grouping).");
+ _taExpanded->setWhatsThis( hint );
+
+ _taCycles = new KToggleAction( i18n( "Do Cycle Detection" ), "undo",
+ KShortcut(),
+ TQT_TQOBJECT(this), TQT_SLOT( toggleCycles() ), actionCollection(),
+ "view_cycles" );
+#if KDE_VERSION >= 0x030290
+ // for KDE 3.3: show another text instead of a checkmark
+ _taCycles->setCheckedState(i18n("Skip Cycle Detection"));
+#endif
+
+ hint = i18n("<b>Detect recursive cycles</b>"
+ "<p>If this is switched off, the treemap drawing will show "
+ "black areas when a recursive call is made instead of drawing the "
+ "recursion ad infinitum. Note that "
+ "the size of black areas often will be wrong, as inside recursive "
+ "cycles the cost of calls cannot be determined; the error is small, "
+ "however, for false cycles (see documentation)."
+ "<p>The correct handling for cycles is to detect them and collapse all "
+ "functions of a cycle into a virtual function, which is done when this "
+ "option is selected. Unfortunately, with GUI applications, this often will "
+ "lead to huge false cycles, making the analysis impossible; therefore, there "
+ "is the option to switch this off.");
+ _taCycles->setWhatsThis( hint );
+
+ KStdAction::quit(TQT_TQOBJECT(this), TQT_SLOT(close()), actionCollection());
+ KStdAction::preferences(TQT_TQOBJECT(this), TQT_SLOT(configure()), actionCollection());
+ KStdAction::keyBindings(TQT_TQOBJECT(this), TQT_SLOT(configureKeys()), actionCollection());
+ KStdAction::configureToolbars(TQT_TQOBJECT(this),TQT_SLOT(configureToolbars()),
+ actionCollection());
+#if 0
+ action = KStdAction::back(_stackSelection, TQT_SLOT(browserBack()),
+ actionCollection());
+ hint = i18n("Go back in function selection history");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = KStdAction::forward(_stackSelection, TQT_SLOT(browserForward()),
+ actionCollection());
+ hint = i18n("Go forward in function selection history");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = KStdAction::up(_stackSelection, TQT_SLOT(browserUp()),
+ actionCollection());
+ hint = i18n("<b>Go Up</b>"
+ "<p>Go to last selected caller of current function. "
+ "If no caller was visited, use that with highest cost.</p>");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+#else
+ _paUp = new KToolBarPopupAction( i18n( "&Up" ), "up",
+ ALT+Key_Up,
+ TQT_TQOBJECT(_stackSelection), TQT_SLOT( browserUp() ),
+ actionCollection(), "go_up" );
+ connect( _paUp->popupMenu(), TQT_SIGNAL( aboutToShow() ),
+ TQT_TQOBJECT(this), TQT_SLOT( upAboutToShow() ) );
+ connect( _paUp->popupMenu(), TQT_SIGNAL( activated( int ) ),
+ TQT_TQOBJECT(this), TQT_SLOT( upActivated( int ) ) );
+ hint = i18n("<b>Go Up</b>"
+ "<p>Go to last selected caller of current function. "
+ "If no caller was visited, use that with highest cost.</p>");
+ _paUp->setToolTip( hint );
+ _paUp->setWhatsThis( hint );
+
+ TQPair< KGuiItem, KGuiItem > backForward = KStdGuiItem::backAndForward();
+ _paBack = new KToolBarPopupAction( backForward.first, ALT+Key_Left,
+ TQT_TQOBJECT(_stackSelection), TQT_SLOT(browserBack()),
+ actionCollection(), "go_back" );
+ connect( _paBack->popupMenu(), TQT_SIGNAL( aboutToShow() ),
+ TQT_TQOBJECT(this), TQT_SLOT( backAboutToShow() ) );
+ connect( _paBack->popupMenu(), TQT_SIGNAL( activated( int ) ),
+ TQT_TQOBJECT(this), TQT_SLOT( backActivated( int ) ) );
+ hint = i18n("Go back in function selection history");
+ _paBack->setToolTip( hint );
+ _paBack->setWhatsThis( hint );
+
+ _paForward = new KToolBarPopupAction( backForward.second, ALT+Key_Right,
+ TQT_TQOBJECT(_stackSelection),
+ TQT_SLOT(browserForward()),
+ actionCollection(), "go_forward" );
+ connect( _paForward->popupMenu(), TQT_SIGNAL( aboutToShow() ),
+ this, TQT_SLOT( forwardAboutToShow() ) );
+ connect( _paForward->popupMenu(), TQT_SIGNAL( activated( int ) ),
+ this, TQT_SLOT( forwardActivated( int ) ) );
+ hint = i18n("Go forward in function selection history");
+ _paForward->setToolTip( hint );
+ _paForward->setWhatsThis( hint );
+#endif
+
+ _saCost = new KSelectAction( i18n("Primary Event Type"), KShortcut(),
+ actionCollection(), "view_cost_type");
+ hint = i18n("Select primary event type of costs");
+ _saCost->setComboWidth(300);
+ _saCost->setToolTip( hint );
+ _saCost->setWhatsThis( hint );
+
+ // cost types are dependent on loaded data, thus KSelectAction
+ // is filled in setData()
+ connect( _saCost, TQT_SIGNAL(activated(const TQString&)),
+ TQT_TQOBJECT(this), TQT_SLOT(costTypeSelected(const TQString&)));
+
+ _saCost2 = new KSelectAction( i18n("Secondary Event Type"), KShortcut(),
+ actionCollection(), "view_cost_type2");
+ hint = i18n("Select secondary event type for cost e.g. shown in annotations");
+ _saCost2->setComboWidth(300);
+ _saCost2->setToolTip( hint );
+ _saCost2->setWhatsThis( hint );
+
+ connect( _saCost2, TQT_SIGNAL(activated(const TQString&)),
+ TQT_TQOBJECT(this), TQT_SLOT(costType2Selected(const TQString&)));
+
+ saGroup = new KSelectAction( i18n("Grouping"), KShortcut(),
+ actionCollection(), "view_group_type");
+
+ hint = i18n("Select how functions are grouped into higher level cost items");
+ saGroup->setToolTip( hint );
+ saGroup->setWhatsThis( hint );
+
+ TQStringList args;
+
+ args << i18n("(No Grouping)")
+ << TraceCost::i18nTypeName(TraceItem::Object)
+ << TraceCost::i18nTypeName(TraceItem::File)
+ << TraceCost::i18nTypeName(TraceItem::Class)
+ << TraceCost::i18nTypeName(TraceItem::FunctionCycle);
+
+ saGroup->setItems(args);
+ connect( saGroup, TQT_SIGNAL(activated(int)),
+ TQT_TQOBJECT(this), TQT_SLOT(groupTypeSelected(int)));
+
+ _taSplit = new KToggleAction(i18n("Split"), "view_left_right", KShortcut(),
+ TQT_TQOBJECT(this), TQT_SLOT(splitSlot()),
+ actionCollection(), "view_split");
+
+ hint = i18n("Show two information panels");
+ _taSplit->setToolTip( hint );
+ _taSplit->setWhatsThis( hint );
+
+ _taSplitDir = new KToggleAction(i18n("SplitQt::Horizontal"),
+ "view_left_right", KShortcut(),
+ TQT_TQOBJECT(this), TQT_SLOT(splitDirSlot()),
+ actionCollection(), "view_split_dir");
+
+ hint = i18n("Change Split Qt::Orientation when main window is split.");
+ _taSplitDir->setToolTip( hint );
+ _taSplitDir->setWhatsThis( hint );
+
+ // copied from KMail...
+#if KDE_VERSION >= 308 // KDE 3.1
+ KStdAction::tipOfDay( TQT_TQOBJECT(this), TQT_SLOT( slotShowTip() ), actionCollection() );
+#else
+ (void) new KAction( KGuiItem( i18n("Tip of the &Day..."), "idea",
+ i18n("Show \"Tip of the Day\"") ),
+ 0, TQT_TQOBJECT(this), TQT_SLOT(slotShowTip()),
+ actionCollection(), "help_show_tip" );
+#endif
+}
+
+void TopLevel::createActions()
+{
+ createMiscActions();
+ createLayoutActions();
+}
+
+void TopLevel::toggleStatusBar()
+{
+ if (statusBar()->isVisible())
+ statusBar()->hide();
+ else
+ statusBar()->show();
+}
+
+void TopLevel::togglePartDock()
+{
+ if (!_partDock->isVisible())
+ _partDock->show();
+ else
+ _partDock->hide();
+}
+
+void TopLevel::toggleStackDock()
+{
+ if (!_stackDock->isVisible())
+ _stackDock->show();
+ else
+ _stackDock->hide();
+}
+
+void TopLevel::toggleDumpDock()
+{
+#if ENABLE_DUMPDOCK
+ if (!_dumpDock->isVisible())
+ _dumpDock->show();
+ else
+ _dumpDock->hide();
+#endif
+}
+
+void TopLevel::toggleFunctionDock()
+{
+ if (!_functionDock->isVisible())
+ _functionDock->show();
+ else
+ _functionDock->hide();
+}
+
+void TopLevel::togglePercentage()
+{
+ setPercentage(_taPercentage->isChecked());
+}
+
+void TopLevel::setAbsoluteCost()
+{
+ setPercentage(false);
+}
+
+void TopLevel::setRelativeCost()
+{
+ setPercentage(true);
+}
+
+void TopLevel::setPercentage(bool show)
+{
+ if (_showPercentage == show) return;
+ _showPercentage = show;
+ if (_taPercentage->isChecked() != show)
+ _taPercentage->setChecked(show);
+
+ // FIXME: Delete when no view gets this config from Configuration
+ Configuration::setShowPercentage(_showPercentage);
+
+ _partSelection->refresh();
+ _stackSelection->refresh();
+
+ _functionSelection->notifyChange(TraceItemView::configChanged);
+ _functionSelection->updateView();
+
+ _multiView->notifyChange(TraceItemView::configChanged);
+ _multiView->updateView();
+}
+
+void TopLevel::toggleExpanded()
+{
+ bool show = _taExpanded->isChecked();
+ if (_showExpanded == show) return;
+ _showExpanded = show;
+
+ // FIXME: Delete when no view gets this config from Configuration
+ Configuration::setShowExpanded(_showExpanded);
+
+ _partSelection->refresh();
+ _stackSelection->refresh();
+
+ _functionSelection->notifyChange(TraceItemView::configChanged);
+ _functionSelection->updateView();
+
+ _multiView->notifyChange(TraceItemView::configChanged);
+ _multiView->updateView();
+}
+
+void TopLevel::toggleCycles()
+{
+ bool show = _taCycles->isChecked();
+ if (_showCycles == show) return;
+ _showCycles = show;
+
+ // FIXME: Delete when no view gets this config from Configuration
+ Configuration::setShowCycles(_showCycles);
+
+ if (!_data) return;
+
+ _data->invalidateDynamicCost();
+ _data->updateFunctionCycles();
+
+ _partSelection->refresh();
+ _stackSelection->rebuildStackList();
+
+ _functionSelection->notifyChange(TraceItemView::configChanged);
+ _functionSelection->updateView();
+
+ _multiView->notifyChange(TraceItemView::configChanged);
+ _multiView->updateView();
+}
+
+void TopLevel::partVisibilityChanged(bool v)
+{
+ _partDockShown->setChecked(v);
+}
+
+void TopLevel::stackVisibilityChanged(bool v)
+{
+ _stackDockShown->setChecked(v);
+}
+
+#if ENABLE_DUMPDOCK
+void TopLevel::dumpVisibilityChanged(bool v)
+#else
+void TopLevel::dumpVisibilityChanged(bool)
+#endif
+{
+#if ENABLE_DUMPDOCK
+ _dumpDockShown->setChecked(v);
+#endif
+}
+
+void TopLevel::functionVisibilityChanged(bool v)
+{
+ _functionDockShown->setChecked(v);
+ if (v)
+ _functionSelection->updateView();
+}
+
+
+void TopLevel::querySlot()
+{
+ _functionSelection->query(queryLineEdit->text());
+}
+
+void TopLevel::configureKeys()
+{
+#if KDE_VERSION > 0x030190
+ // for KDE 3.2: KKeyDialog::configureKeys is deprecated
+ KKeyDialog::configure(actionCollection(), this, true);
+#else
+ KKeyDialog::configureKeys(actionCollection(), xmlFile(), true, this);
+#endif
+}
+
+
+void TopLevel::configureToolbars()
+{
+ KEditToolbar *dlg = new KEditToolbar(guiFactory(),this);
+
+ if (dlg->exec())
+ createGUI();
+
+ delete dlg;
+}
+
+
+void TopLevel::newTrace()
+{
+ // start cachegrind on command...
+}
+
+void TopLevel::newWindow()
+{
+ TopLevel* t = new TopLevel(0);
+ t->show();
+}
+
+
+void TopLevel::loadTrace()
+{
+ KURL url = KFileDialog::getOpenURL(":",
+ i18n("cachegrind.out* callgrind.out*|Callgrind Profile Data\n*|All Files"),
+ this,
+ i18n("Select Callgrind Profile Data"));
+ loadTrace(url);
+}
+
+void TopLevel::loadTrace(const KURL& url)
+{
+ if (url.isEmpty()) return;
+
+ // network transparancy
+ TQString tmpFile;
+#if KDE_VERSION > 0x030190
+ // for KDE 3.2: KIO::NetAccess::download with 2 args is deprecated
+ if(KIO::NetAccess::download( url, tmpFile, this )) {
+#else
+ if(KIO::NetAccess::download( url, tmpFile )) {
+#endif
+ _openRecent->addURL(url);
+ _openRecent->saveEntries( KGlobal::config() );
+
+ loadTrace(tmpFile);
+ KIO::NetAccess::removeTempFile( tmpFile );
+ }
+}
+
+void TopLevel::loadTrace(TQString file)
+{
+ if (file.isEmpty()) return;
+
+ if (_data && _data->parts().count()>0) {
+
+ // In new window
+ TopLevel* t = new TopLevel();
+ t->show();
+ t->loadDelayed(file);
+ return;
+ }
+
+ // this constructor enables progress bar callbacks
+ TraceData* d = new TraceData(this);
+ d->load(file);
+ setData(d);
+}
+
+
+void TopLevel::addTrace()
+{
+ KURL url = KFileDialog::getOpenURL(TQString(),
+ i18n("cachegrind.out* callgrind.out*|Callgrind Profile Data\n*|All Files"),
+ this,
+ i18n("Add Callgrind Profile Data"));
+ addTrace(url);
+}
+
+void TopLevel::addTrace(const KURL& url)
+{
+ if (url.isEmpty()) return;
+
+ // network transparancy
+ TQString tmpFile;
+#if KDE_VERSION > 0x030190
+ // for KDE 3.2: KIO::NetAccess::download with 2 args is deprecated
+ if(KIO::NetAccess::download( url, tmpFile, this )) {
+#else
+ if(KIO::NetAccess::download( url, tmpFile )) {
+#endif
+ _openRecent->addURL(url);
+ _openRecent->saveEntries( KGlobal::config() );
+
+ addTrace(tmpFile);
+ KIO::NetAccess::removeTempFile( tmpFile );
+ }
+}
+
+void TopLevel::addTrace(TQString file)
+{
+ if (file.isEmpty()) return;
+
+ if (_data) {
+ _data->load(file);
+
+ // GUI update for added data
+ configChanged();
+ return;
+ }
+
+ // this constructor enables progress bar callbacks
+ TraceData* d = new TraceData(this);
+ d->load(file);
+ setData(d);
+}
+
+
+
+void TopLevel::loadDelayed(TQString file)
+{
+ _loadTraceDelayed = file;
+ TQTimer::singleShot(0, TQT_TQOBJECT(this), TQT_SLOT(loadTraceDelayed()));
+}
+
+void TopLevel::loadTraceDelayed()
+{
+ if (_loadTraceDelayed.isEmpty()) return;
+
+ loadTrace(_loadTraceDelayed);
+ _loadTraceDelayed = TQString();
+}
+
+
+void TopLevel::reload()
+{
+ TQString trace;
+ if (!_data || _data->parts().count()==0)
+ trace = "."; // open first trace found in dir
+ else
+ trace = _data->traceName();
+
+ // this also keeps sure we have the same browsing position...
+ TraceData* d = new TraceData(this);
+ d->load(trace);
+ setData(d);
+}
+
+void TopLevel::exportGraph()
+{
+ if (!_data || !_function) return;
+
+ TQString n = TQString("callgraph.dot");
+ GraphExporter ge(_data, _function, _costType, _groupType, n);
+ ge.writeDot();
+
+ TQString cmd = TQString("(dot %1 -Tps > %2.ps; kghostview %3.ps)&")
+ .arg(n).arg(n).arg(n);
+ system(TQFile::encodeName( cmd ));
+}
+
+
+bool TopLevel::setCostType(TQString s)
+{
+ TraceCostType* ct;
+
+ ct = (_data) ? _data->mapping()->type(s) : 0;
+
+ // if costtype with given name not found, use first available
+ if (!ct && _data) ct = _data->mapping()->type(0);
+
+ return setCostType(ct);
+}
+
+bool TopLevel::setCostType2(TQString s)
+{
+ TraceCostType* ct;
+
+ // Special type i18n("(Hidden)") gives 0
+ ct = (_data) ? _data->mapping()->type(s) : 0;
+
+ return setCostType2(ct);
+}
+
+void TopLevel::costTypeSelected(const TQString& s)
+{
+ TraceCostType* ct;
+
+ ct = (_data) ? _data->mapping()->typeForLong(s) : 0;
+ setCostType(ct);
+}
+
+void TopLevel::costType2Selected(const TQString& s)
+{
+ TraceCostType* ct;
+
+ ct = (_data) ? _data->mapping()->typeForLong(s) : 0;
+ setCostType2(ct);
+}
+
+bool TopLevel::setCostType(TraceCostType* ct)
+{
+ if (_costType == ct) return false;
+ _costType = ct;
+
+ if (ct) {
+ int idx=0;
+ TQStringList l = _saCost->items();
+ for (TQStringList::Iterator it = l.begin(); it != l.end(); ++it, ++idx ) {
+ if (*it == ct->longName())
+ _saCost->setCurrentItem(idx);
+ }
+ }
+
+ _partSelection->setCostType(_costType);
+ _stackSelection->setCostType(_costType);
+
+ _functionSelection->setCostType(_costType);
+ _functionSelection->updateView();
+
+ _multiView->setCostType(_costType);
+ _multiView->updateView();
+
+ updateStatusBar();
+
+ return true;
+}
+
+bool TopLevel::setCostType2(TraceCostType* ct)
+{
+ if (_costType2 == ct) return false;
+ _costType2 = ct;
+
+ TQString longName = ct ? ct->longName() : i18n("(Hidden)");
+
+ int idx=0;
+ TQStringList l = _saCost2->items();
+ for (TQStringList::Iterator it = l.begin(); it != l.end(); ++it, ++idx ) {
+ if (*it == longName)
+ _saCost2->setCurrentItem(idx);
+ }
+
+ _partSelection->setCostType2(_costType2);
+ _stackSelection->setCostType2(_costType2);
+
+ _functionSelection->setCostType2(_costType2);
+ _functionSelection->updateView();
+
+ _multiView->setCostType2(_costType2);
+ _multiView->updateView();
+
+ updateStatusBar();
+
+ return true;
+}
+
+
+void TopLevel::groupTypeSelected(int cg)
+{
+ switch(cg) {
+ case 0: setGroupType( TraceItem::Function ); break;
+ case 1: setGroupType( TraceItem::Object ); break;
+ case 2: setGroupType( TraceItem::File ); break;
+ case 3: setGroupType( TraceItem::Class ); break;
+ case 4: setGroupType( TraceItem::FunctionCycle ); break;
+ default: break;
+ }
+}
+
+bool TopLevel::setGroupType(TQString s)
+{
+ TraceItem::CostType gt;
+
+ gt = (_data) ? _data->costType(s) : TraceData::costType(s);
+ // only allow Function/Object/File/Class as grouptype
+ switch(gt) {
+ case TraceItem::Object:
+ case TraceItem::File:
+ case TraceItem::Class:
+ case TraceItem::FunctionCycle:
+ break;
+ default:
+ gt = TraceItem::Function;
+ }
+
+ return setGroupType(gt);
+}
+
+bool TopLevel::setGroupType(TraceItem::CostType gt)
+{
+ if (_groupType == gt) return false;
+ _groupType = gt;
+
+ int idx = -1;
+ switch(gt) {
+ case TraceItem::Function: idx = 0; break;
+ case TraceItem::Object: idx = 1; break;
+ case TraceItem::File: idx = 2; break;
+ case TraceItem::Class: idx = 3; break;
+ case TraceItem::FunctionCycle: idx = 4; break;
+ default:
+ break;
+ }
+
+ if (idx==-1) return false;
+
+ if (saGroup->currentItem() != idx)
+ saGroup->setCurrentItem(idx);
+
+ _stackSelection->setGroupType(_groupType);
+ _partSelection->setGroupType(_groupType);
+
+ _functionSelection->set(_groupType);
+ _functionSelection->updateView();
+
+ _multiView->set(_groupType);
+ _multiView->updateView();
+
+ updateStatusBar();
+
+ return true;
+}
+
+bool TopLevel::setGroup(TQString s)
+{
+ return true;
+ TraceCostItem* ci = _functionSelection->group(s);
+ if (!ci)
+ return false;
+
+ return setGroup(ci);
+}
+
+
+bool TopLevel::setGroup(TraceCostItem* g)
+{
+ _multiView->activate(g);
+ _multiView->updateView();
+ _functionSelection->activate(g);
+ _functionSelection->updateView();
+
+ if (_group == g) return false;
+ _group = g;
+
+
+ updateStatusBar();
+
+ return true;
+}
+
+bool TopLevel::setFunction(TQString s)
+{
+ if (!_data) return false;
+
+ TraceCost* f = _data->search(TraceItem::Function, s, _costType);
+ if (!f) return false;
+
+ return setFunction((TraceFunction*)f);
+}
+
+bool TopLevel::setFunction(TraceFunction* f)
+{
+ _multiView->activate(f);
+ _multiView->updateView();
+
+ _functionSelection->activate(f);
+ _functionSelection->updateView();
+
+ if (_function == f) return false;
+ _function = f;
+
+ _partSelection->setFunction(_function);
+ _stackSelection->setFunction(_function);
+
+ StackBrowser* b = _stackSelection->browser();
+ if (b) {
+ // don't disable up: a press forces stack-up extending...
+ _paForward->setEnabled(b->canGoForward());
+ _paBack->setEnabled(b->canGoBack());
+ }
+
+#if TRACE_UPDATES
+ qDebug("TopLevel::setFunction(%s), lastSender %s",
+ f ? f->prettyName().ascii() : "0",
+ _lastSender ? _lastSender->name() :"0" );
+#endif
+
+ return true;
+}
+
+
+/**
+ * Delayed versions.
+ * We always have a pair of slots: One receiver to start the
+ * delay with a singleShot Timer. It stores the parameter into a
+ * temporary variable. And one parameterless slot for
+ * forwarding, using this temporary.
+ */
+void TopLevel::setCostTypeDelayed(TraceCostType* ct)
+{
+ _costTypeDelayed = ct;
+ TQTimer::singleShot (0, TQT_TQOBJECT(this), TQT_SLOT(setCostTypeDelayed()));
+}
+
+void TopLevel::setCostType2Delayed(TraceCostType* ct)
+{
+ _costType2Delayed = ct;
+ TQTimer::singleShot (0, TQT_TQOBJECT(this), TQT_SLOT(setCostType2Delayed()));
+}
+
+void TopLevel::setCostTypeDelayed()
+{
+ setCostType(_costTypeDelayed);
+}
+
+void TopLevel::setCostType2Delayed()
+{
+ setCostType2(_costType2Delayed);
+}
+
+void TopLevel::setGroupTypeDelayed(TraceItem::CostType gt)
+{
+ _groupTypeDelayed = gt;
+ TQTimer::singleShot (0, TQT_TQOBJECT(this), TQT_SLOT(setGroupTypeDelayed()));
+}
+
+void TopLevel::setGroupTypeDelayed()
+{
+ setGroupType(_groupTypeDelayed);
+}
+
+void TopLevel::setGroupDelayed(TraceCostItem* g)
+{
+#if TRACE_UPDATES
+ qDebug("TopLevel::setGroupDelayed(%s), sender %s",
+ g ? g->prettyName().ascii() : "0",
+ _lastSender ? _lastSender->name() :"0" );
+#endif
+
+ _groupDelayed = g;
+ TQTimer::singleShot (0, TQT_TQOBJECT(this), TQT_SLOT(setGroupDelayed()));
+}
+
+void TopLevel::setGroupDelayed()
+{
+ setGroup(_groupDelayed);
+}
+
+void TopLevel::setDirectionDelayed(TraceItemView::Direction d)
+{
+ _directionDelayed = d;
+ TQTimer::singleShot (0, TQT_TQOBJECT(this), TQT_SLOT(setDirectionDelayed()));
+}
+
+void TopLevel::setDirectionDelayed()
+{
+ switch(_directionDelayed) {
+ case TraceItemView::Back:
+ _stackSelection->browserBack();
+ break;
+
+ case TraceItemView::Forward:
+ _stackSelection->browserForward();
+ break;
+
+ case TraceItemView::Up:
+ {
+ StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0;
+ HistoryItem* hi = b ? b->current() : 0;
+ TraceFunction* f = hi ? hi->function() : 0;
+
+ if (!f) break;
+ f = hi->stack()->caller(f, false);
+ if (f) setFunction(f);
+ }
+ break;
+
+ default: break;
+ }
+
+ _directionDelayed = TraceItemView::None;
+}
+
+
+void TopLevel::setTraceItemDelayed(TraceItem* i)
+{
+ // no need to select same item a 2nd time...
+ if (_traceItemDelayed == i) return;
+ _traceItemDelayed = i;
+ _lastSender = TQT_TQOBJECT(const_cast<TQT_BASE_OBJECT_NAME*>(sender()));
+
+ kdDebug() << "Selected " << (i ? i->prettyName() : "(none)") << endl;
+
+#if TRACE_UPDATES
+ qDebug("TopLevel::setTraceItemDelayed(%s), sender %s",
+ i ? i->prettyName().ascii() : "0",
+ _lastSender ? _lastSender->name() :"0" );
+#endif
+
+ TQTimer::singleShot (0, TQT_TQOBJECT(this), TQT_SLOT(setTraceItemDelayed()));
+}
+
+void TopLevel::setTraceItemDelayed()
+{
+ if (!_traceItemDelayed) return;
+
+ switch(_traceItemDelayed->type()) {
+ case TraceItem::Function:
+ case TraceItem::FunctionCycle:
+ setFunction((TraceFunction*)_traceItemDelayed);
+ break;
+
+ case TraceItem::Object:
+ case TraceItem::File:
+ case TraceItem::Class:
+ setGroup((TraceCostItem*)_traceItemDelayed);
+ break;
+
+#if 0
+ // this conflicts with the selection policy of InstrView ?!?
+ case TraceItem::Instr:
+ case TraceItem::Line:
+ // only for multiview
+ _multiView->activate(_traceItemDelayed);
+ _multiView->updateView();
+ break;
+#endif
+
+ default: break;
+ }
+
+ _traceItemDelayed = 0;
+ _lastSender = 0;
+}
+
+/**
+ * A TraceData object cannot be viewed many times in different
+ * toplevel windows. Thus, this toplevel window takes ownership
+ * of the TraceData object: on closing the window or opening
+ * another trace, the object is destroyed.
+ */
+void TopLevel::setData(TraceData* data)
+{
+ if (data == _data) return;
+
+ _lastSender = 0;
+
+ saveTraceSettings();
+
+ if (_data) {
+ _partSelection->setData(0);
+ _stackSelection->setData(0);
+
+ _functionSelection->setData(0);
+ _functionSelection->updateView();
+ _multiView->setData(0);
+ _multiView->updateView();
+
+ // we are the owner...
+ delete _data;
+ }
+
+ // reset members
+ init();
+
+ _data = data;
+
+ // fill cost type list
+ TQStringList types;
+
+ if (_data) {
+ /* add all supported virtual types */
+ TraceCostMapping* m = _data->mapping();
+ m->addKnownVirtualTypes();
+
+ /* first, fill selection list with available cost types */
+ for (int i=0;i<m->realCount();i++)
+ types << m->realType(i)->longName();
+ for (int i=0;i<m->virtualCount();i++)
+ types << m->virtualType(i)->longName();
+ }
+ _saCost->setItems(types);
+ _saCost->setComboWidth(300);
+
+ if (types.count()>0) {
+ // second type list gets an additional "(Hidden)"
+ types.prepend(i18n("(Hidden)"));
+ }
+ _saCost2->setItems(types);
+ _saCost2->setComboWidth(300);
+ // default is hidden
+ if (types.count()>0)
+ _saCost2->setCurrentItem(0);
+
+ _partSelection->setData(_data);
+ _stackSelection->setData(_data);
+ _functionSelection->setData(_data);
+ _functionSelection->updateView();
+ _multiView->setData(_data);
+ _multiView->updateView();
+
+ /* this is needed to let the other widgets know the types */
+ restoreTraceTypes();
+
+ restoreTraceSettings();
+
+ TQString caption;
+ if (_data) {
+ caption = _data->traceName();
+ if (!_data->command().isEmpty())
+ caption += " [" + _data->command() + "]";
+ }
+ setCaption(caption);
+
+ if (!_data || (!_forcePartDock && _data->parts().count()<2)) {
+ _partDock->hide();
+ _partDockShown->setChecked(false);
+ }
+ else {
+ _partDock->show();
+ _partDockShown->setChecked(true);
+ }
+
+ updateStatusBar();
+}
+
+void TopLevel::addCostMenu(TQPopupMenu* popup, bool withCost2)
+{
+ if (_data) {
+ TQPopupMenu *popup1 = new TQPopupMenu(popup);
+ TQPopupMenu *popup2 = 0;
+ popup1->setCheckable(true);
+
+ if (withCost2) {
+ popup2 = new TQPopupMenu(popup);
+ popup2->setCheckable(true);
+
+ if (_costType2) {
+ popup2->insertItem(i18n("Hide"),199);
+ popup2->insertSeparator();
+ }
+ }
+
+ TraceCostMapping* m = _data->mapping();
+ TraceCostType* ct;
+ for (int i=0;i<m->realCount();i++) {
+ ct = m->realType(i);
+ popup1->insertItem(ct->longName(), 100+i);
+ if (_costType == ct) popup1->setItemChecked(100+i,true);
+ if (popup2) {
+ popup2->insertItem(ct->longName(), 100+i);
+ if (_costType2 == ct) popup2->setItemChecked(100+i,true);
+ }
+ }
+ for (int i=0;i<m->virtualCount();i++) {
+ ct = m->virtualType(i);
+ popup1->insertItem(ct->longName(), 200+i);
+ if (_costType == ct) popup1->setItemChecked(200+i,true);
+ if (popup2) {
+ popup2->insertItem(ct->longName(), 200+i);
+ if (_costType2 == ct) popup2->setItemChecked(200+i,true);
+ }
+ }
+ popup->insertItem(i18n("Primary Event Type"), popup1);
+ connect(popup1,TQT_SIGNAL(activated(int)),this,TQT_SLOT(setCostType(int)));
+ if (popup2) {
+ popup->insertItem(i18n("Secondary Event Type"), popup2);
+ connect(popup2,TQT_SIGNAL(activated(int)),this,TQT_SLOT(setCostType2(int)));
+ }
+ }
+ if (_showPercentage)
+ popup->insertItem(i18n("Show Absolute Cost"),
+ TQT_TQOBJECT(this), TQT_SLOT(setAbsoluteCost()));
+ else
+ popup->insertItem(i18n("Show Relative Cost"),
+ TQT_TQOBJECT(this), TQT_SLOT(setRelativeCost()));
+}
+
+bool TopLevel::setCostType(int id)
+{
+ if (!_data) return false;
+
+ TraceCostMapping* m = _data->mapping();
+ TraceCostType* ct=0;
+ if (id >=100 && id<199) ct = m->realType(id-100);
+ if (id >=200 && id<299) ct = m->virtualType(id-200);
+
+ return ct ? setCostType(ct) : false;
+}
+
+bool TopLevel::setCostType2(int id)
+{
+ if (!_data) return false;
+
+ TraceCostMapping* m = _data->mapping();
+ TraceCostType* ct=0;
+ if (id >=100 && id<199) ct = m->realType(id-100);
+ if (id >=200 && id<299) ct = m->virtualType(id-200);
+
+ return setCostType2(ct);
+}
+
+void TopLevel::addGoMenu(TQPopupMenu* popup)
+{
+ popup->insertItem(i18n("Go Back"), TQT_TQOBJECT(this), TQT_SLOT(goBack()));
+ popup->insertItem(i18n("Go Forward"), TQT_TQOBJECT(this), TQT_SLOT(goForward()));
+ popup->insertItem(i18n("Go Up"), TQT_TQOBJECT(this), TQT_SLOT(goUp()));
+}
+
+void TopLevel::goBack()
+{
+ setDirectionDelayed(TraceItemView::Back);
+}
+
+void TopLevel::goForward()
+{
+ setDirectionDelayed(TraceItemView::Forward);
+}
+
+void TopLevel::goUp()
+{
+ setDirectionDelayed(TraceItemView::Up);
+}
+
+TQString TopLevel::traceKey()
+{
+ if (!_data || _data->command().isEmpty()) return TQString();
+
+ TQString name = _data->command();
+ TQString key;
+ for (unsigned int l=0;l<name.length();l++)
+ if (name[l].isLetterOrNumber()) key += name[l];
+
+ return TQString("-") + key;
+}
+
+
+void TopLevel::restoreTraceTypes()
+{
+ TQString key = traceKey();
+
+ KConfigGroup cConfig(KGlobal::config(), TQCString("CurrentState"));
+ KConfigGroup pConfig(KGlobal::config(), TQCString("TracePositions"));
+
+ TQString groupType, costType, costType2;
+ groupType = pConfig.readEntry(TQString("GroupType%1").arg(key));
+ costType = pConfig.readEntry(TQString("CostType%1").arg(key));
+ costType2 = pConfig.readEntry(TQString("CostType2%1").arg(key));
+
+ if (groupType.isEmpty()) groupType = cConfig.readEntry("GroupType");
+ if (costType.isEmpty()) costType = cConfig.readEntry("CostType");
+ if (costType2.isEmpty()) costType2 = cConfig.readEntry("CostType2");
+
+ setGroupType(groupType);
+ setCostType(costType);
+ setCostType2(costType2);
+
+ // if still no cost type set, use first available
+ if (!_costType && !_saCost->items().isEmpty())
+ costTypeSelected(_saCost->items().first());
+
+ KConfigGroup aConfig(KGlobal::config(), TQCString("Layouts"));
+ _layoutCount = aConfig.readNumEntry(TQString("Count%1").arg(key), 0);
+ _layoutCurrent = aConfig.readNumEntry(TQString("Current%1").arg(key), 0);
+ if (_layoutCount == 0) layoutRestore();
+ updateLayoutActions();
+}
+
+
+/**
+ * This must be called after setting group/cost types in the function
+ * selection widget, because the group/function choosing depends on
+ * filled lists in the function selection widget
+ */
+void TopLevel::restoreTraceSettings()
+{
+ if (!_data) return;
+
+ TQString key = traceKey();
+
+ KConfigGroup pConfig(KGlobal::config(), TQCString("TracePositions"));
+ TQString group = pConfig.readEntry(TQString("Group%1").arg(key));
+ if (!group.isEmpty()) setGroup(group);
+
+ restoreCurrentState(key);
+
+ // restoreCurrentState() usually leads to a call to setTraceItemDelayed()
+ // to restore last active item...
+ if (!_traceItemDelayed) {
+ // function not available any more.. try with "main"
+ if (!setFunction("main"))
+ _functionSelection->setTopFunction();
+ }
+}
+
+
+/* Layout */
+
+void TopLevel::layoutDuplicate()
+{
+ // save current and allocate a new slot
+ _multiView->saveViewConfig(KGlobal::config(),
+ TQString("Layout%1-MainView").arg(_layoutCurrent),
+ traceKey(), false);
+ _layoutCurrent = _layoutCount;
+ _layoutCount++;
+
+ updateLayoutActions();
+
+ kdDebug() << "TopLevel::layoutDuplicate: count " << _layoutCount << endl;
+}
+
+void TopLevel::layoutRemove()
+{
+ if (_layoutCount <2) return;
+
+ int from = _layoutCount-1;
+ if (_layoutCurrent == from) { _layoutCurrent--; from--; }
+ // restore from last and decrement count
+ _multiView->readViewConfig(KGlobal::config(),
+ TQString("Layout%1-MainView").arg(from),
+ traceKey(), false);
+ _layoutCount--;
+
+ updateLayoutActions();
+}
+
+void TopLevel::layoutNext()
+{
+ if (_layoutCount <2) return;
+
+ KConfig* config = KGlobal::config();
+ TQString key = traceKey();
+
+ _multiView->saveViewConfig(config,
+ TQString("Layout%1-MainView").arg(_layoutCurrent),
+ key, false);
+ _layoutCurrent++;
+ if (_layoutCurrent == _layoutCount) _layoutCurrent = 0;
+
+ _multiView->readViewConfig(config,
+ TQString("Layout%1-MainView").arg(_layoutCurrent),
+ key, false);
+
+ if (0) kdDebug() << "TopLevel::layoutNext: current "
+ << _layoutCurrent << endl;
+}
+
+void TopLevel::layoutPrevious()
+{
+ if (_layoutCount <2) return;
+
+ KConfig* config = KGlobal::config();
+ TQString key = traceKey();
+
+ _multiView->saveViewConfig(config,
+ TQString("Layout%1-MainView").arg(_layoutCurrent),
+ key, false);
+ _layoutCurrent--;
+ if (_layoutCurrent <0) _layoutCurrent = _layoutCount-1;
+
+ _multiView->readViewConfig(config,
+ TQString("Layout%1-MainView").arg(_layoutCurrent),
+ key, false);
+
+ if (0) kdDebug() << "TopLevel::layoutPrevious: current "
+ << _layoutCurrent << endl;
+}
+
+void TopLevel::layoutSave()
+{
+ KConfig* config = KGlobal::config();
+ TQString key = traceKey();
+
+ _multiView->saveViewConfig(config,
+ TQString("Layout%1-MainView").arg(_layoutCurrent),
+ key, false);
+
+ for(int i=0;i<_layoutCount;i++) {
+ _multiView->readViewConfig(config,
+ TQString("Layout%1-MainView").arg(i),
+ key, false);
+ _multiView->saveViewConfig(config,
+ TQString("Layout%1-MainView").arg(i),
+ TQString(), false);
+ }
+
+ _multiView->readViewConfig(config,
+ TQString("Layout%1-MainView").arg(_layoutCurrent),
+ key, false);
+
+ KConfigGroup aConfig(config, TQCString("Layouts"));
+ aConfig.writeEntry("DefaultCount", _layoutCount);
+ aConfig.writeEntry("DefaultCurrent", _layoutCurrent);
+}
+
+void TopLevel::layoutRestore()
+{
+ KConfig* config = KGlobal::config();
+ KConfigGroup aConfig(config, TQCString("Layouts"));
+ _layoutCount = aConfig.readNumEntry("DefaultCount", 0);
+ _layoutCurrent = aConfig.readNumEntry("DefaultCurrent", 0);
+ if (_layoutCount == 0) {
+ _layoutCount++;
+ return;
+ }
+
+ TQString key = traceKey();
+ for(int i=0;i<_layoutCount;i++) {
+ _multiView->readViewConfig(config,
+ TQString("Layout%1-MainView").arg(i),
+ TQString(), false);
+ _multiView->saveViewConfig(config,
+ TQString("Layout%1-MainView").arg(i),
+ key, false);
+ }
+
+ _multiView->readViewConfig(config,
+ TQString("Layout%1-MainView").arg(_layoutCurrent),
+ key, false);
+
+ updateLayoutActions();
+}
+
+
+void TopLevel::updateLayoutActions()
+{
+ KAction* ka;
+
+ ka = actionCollection()->action("layout_next");
+ if (ka) ka->setEnabled(_layoutCount>1);
+
+ ka = actionCollection()->action("layout_previous");
+ if (ka) ka->setEnabled(_layoutCount>1);
+
+ ka = actionCollection()->action("layout_remove");
+ if (ka) ka->setEnabled(_layoutCount>1);
+
+ _statusbar->message(i18n("Layout Count: %1").arg(_layoutCount), 1000);
+}
+
+
+void TopLevel::updateStatusBar()
+{
+ if (!_data || _data->parts().count()==0) {
+ _statusLabel->setText(i18n("No profile data file loaded."));
+ return;
+ }
+
+ TQString status = TQString("%1 [%2] - ")
+ .arg(_data->shortTraceName())
+ .arg(_data->activePartRange());
+
+ if (_costType) {
+ status += i18n("Total %1 Cost: %2")
+ .arg(_costType->longName())
+ .arg(_data->prettySubCost(_costType));
+
+ /* this gets too long...
+ if (_costType2 && (_costType2 != _costType))
+ status += i18n(", %1 Cost: %2")
+ .arg(_costType2->longName())
+ .arg(_data->prettySubCost(_costType2));
+ */
+ }
+ else
+ status += i18n("No event type selected");
+
+ /* Not working... should give group of selected function
+
+ if (_groupType != TraceItem::Function) {
+ status += TQString(" - %1 '%2'")
+ .arg(TraceItem::i18nTypeName(_groupType))
+ .arg(_group ? _group->prettyName() : i18n("(None)"));
+ }
+ */
+
+ _statusLabel->setText(status);
+}
+
+void TopLevel::configure()
+{
+ if (ConfigDlg::configure(Configuration::config(), _data, this)) {
+ Configuration::saveOptions(KGlobal::config());
+
+ configChanged();
+ }
+ else
+ Configuration::readOptions(KGlobal::config());
+}
+
+bool TopLevel::queryClose()
+{
+ saveTraceSettings();
+
+ return true;
+}
+
+bool TopLevel::queryExit()
+{
+ // save current toplevel options as defaults...
+ Configuration::setShowPercentage(_showPercentage);
+ Configuration::setShowExpanded(_showExpanded);
+ Configuration::setShowCycles(_showCycles);
+ Configuration::saveOptions(KGlobal::config());
+
+ saveCurrentState(TQString());
+
+ // save QT dock positions...
+
+ // We don't want to save the KToolbar position here.
+ // Its already stored.
+ delete toolBar();
+
+ KConfigGroup dockConfig(KGlobal::config(), TQCString("Docks"));
+ TQString str;
+ TQTextStream ts( &str, IO_WriteOnly );
+ ts << *this;
+#if 1
+ dockConfig.writeEntry("Position", str);
+#else
+ /* We store this with a localized key because for dock positions,
+ * QT uses the localized captions of docks.
+ * This way, when changing languages, you don't loose dock position
+ * settings.
+ * For the retrieval to work, we need to store a non-localized.
+ */
+ dockConfig.writeEntry("Position", str, true, false, true);
+#endif
+
+ // if part dock was chosen visible even for only 1 part loaded,
+ // keep this choice...
+ _forcePartDock = false;
+ if (_data && (_data->parts().count()<2) && _partDock->isVisible())
+ _forcePartDock=true;
+ dockConfig.writeEntry("ForcePartDockVisible", _forcePartDock);
+
+ return true;
+}
+
+
+void TopLevel::splitSlot()
+{
+ int count = _multiView->childCount();
+ if (count<1) count = 1;
+ if (count>2) count = 2;
+ count = 3-count;
+ _multiView->setChildCount(count);
+
+ _taSplit->setChecked(count>1);
+ _taSplitDir->setEnabled(count>1);
+ _taSplitDir->setChecked(_multiView->orientation() == Qt::Horizontal);
+}
+
+void TopLevel::splitDirSlot()
+{
+ _multiView->setOrientation( _taSplitDir->isChecked() ?
+ Qt::Horizontal : Qt::Vertical );
+}
+
+
+
+// this is called after a config change in the dialog
+void TopLevel::configChanged()
+{
+ //qDebug("TopLevel::configChanged");
+ //_showPercentage->setChecked(Configuration::showPercentage());
+
+ // invalidate found/cached dirs of source files
+ _data->resetSourceDirs();
+
+ _partSelection->refresh();
+ _stackSelection->refresh();
+
+ _functionSelection->notifyChange(TraceItemView::configChanged);
+ _functionSelection->updateView();
+
+ _multiView->notifyChange(TraceItemView::configChanged);
+ _multiView->updateView();
+}
+
+void TopLevel::slotShowTipOnStart() {
+ KTipDialog::showTip(this);
+}
+
+void TopLevel::slotShowTip() {
+ KTipDialog::showTip( this, TQString(), true );
+}
+
+void TopLevel::dummySlot()
+{
+}
+
+void TopLevel::activePartsChangedSlot(const TracePartList& list)
+{
+ if (!_data) return;
+
+ if (!_data->activateParts(list)) {
+// qDebug("TopLevel::activePartsChangedSlot: No Change!");
+ return;
+ }
+ _activeParts = list;
+
+ _partSelection->activePartsChangedSlot(list);
+
+ _multiView->set(list);
+ _multiView->updateView();
+
+ _functionSelection->set(list);
+ _functionSelection->updateView();
+
+ _stackSelection->refresh();
+
+ updateStatusBar();
+}
+
+void TopLevel::partsHideSelectedSlotDelayed()
+{
+ TQTimer::singleShot( 0, TQT_TQOBJECT(this), TQT_SLOT(partsHideSelectedSlot()) );
+}
+
+// this puts selected parts into hidden list,
+// deselects them and makes the remaining parts selected
+void TopLevel::partsHideSelectedSlot()
+{
+ if (!_data) return;
+
+ TracePart* part;
+ TracePartList newHidden, newActive;
+ TracePartList l = _data->parts();
+ for (part=l.first();part;part=l.next()) {
+ if ((_activeParts.findRef(part)>=0) ||
+ (_hiddenParts.findRef(part)>=0))
+ newHidden.append(part);
+ else
+ newActive.append(part);
+ }
+
+ _hiddenParts = newHidden;
+ _partSelection->hiddenPartsChangedSlot(_hiddenParts);
+
+#if 0
+ _mainWidget1->hiddenPartsChangedSlot(_hiddenParts);
+ _mainWidget2->hiddenPartsChangedSlot(_hiddenParts);
+#endif
+
+ activePartsChangedSlot(newActive);
+}
+
+void TopLevel::partsUnhideAllSlotDelayed()
+{
+ TQTimer::singleShot( 0, TQT_TQOBJECT(this), TQT_SLOT(partsUnhideAllSlot()) );
+}
+
+// this unhides all hidden parts. Does NOT change selection
+void TopLevel::partsUnhideAllSlot()
+{
+ if (!_data) return;
+
+ _hiddenParts.clear();
+ _partSelection->hiddenPartsChangedSlot(_hiddenParts);
+#if 0
+ _mainWidget1->hiddenPartsChangedSlot(_hiddenParts);
+ _mainWidget2->hiddenPartsChangedSlot(_hiddenParts);
+#endif
+}
+
+void TopLevel::forceTrace()
+{
+// qDebug("forceTrace");
+
+ // Needs Callgrind now...
+ TQFile cmd("callgrind.cmd");
+ if (!cmd.exists()) {
+ cmd.open(IO_WriteOnly);
+ cmd.writeBlock("DUMP\n", 5);
+ cmd.close();
+ }
+ if (_taDump->isChecked())
+ TQTimer::singleShot( 1000, TQT_TQOBJECT(this), TQT_SLOT(forceTraceReload()) );
+ else {
+ // cancel request
+ cmd.remove();
+ }
+
+}
+
+void TopLevel::forceTraceReload()
+{
+// qDebug("forceTraceReload");
+
+ TQFile cmd("callgrind.cmd");
+ if (cmd.exists()) {
+ if (_taDump->isChecked())
+ TQTimer::singleShot( 1000, TQT_TQOBJECT(this), TQT_SLOT(forceTraceReload()) );
+ return;
+ }
+ _taDump->setChecked(false);
+ reload();
+}
+
+void TopLevel::forwardAboutToShow()
+{
+ TQPopupMenu *popup = _paForward->popupMenu();
+
+ popup->clear();
+ StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0;
+ HistoryItem* hi = b ? b->current() : 0;
+ TraceFunction* f;
+
+ if (!hi) {
+ popup->insertItem(i18n("(No Stack)"));
+ return;
+ }
+
+ hi = hi->next();
+ if (!hi) {
+ popup->insertItem(i18n("(No next function)"));
+ return;
+ }
+
+ int count = 1;
+ while (count<Configuration::maxSymbolCount() && hi) {
+ f = hi->function();
+ if (!f) break;
+
+ TQString name = f->prettyName();
+ if ((int)name.length()>Configuration::maxSymbolLength())
+ name = name.left(Configuration::maxSymbolLength()) + "...";
+
+ //qDebug("forward: Adding %s", name.ascii());
+ popup->insertItem(name, count);
+ hi = hi->next();
+ count++;
+ }
+}
+
+void TopLevel::backAboutToShow()
+{
+ TQPopupMenu *popup = _paBack->popupMenu();
+
+ popup->clear();
+ StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0;
+ HistoryItem* hi = b ? b->current() : 0;
+ TraceFunction* f;
+
+ if (!hi) {
+ popup->insertItem(i18n("(No Stack)"));
+ return;
+ }
+
+ hi = hi->last();
+ if (!hi) {
+ popup->insertItem(i18n("(No previous function)"));
+ return;
+ }
+
+ int count = 1;
+ while (count<Configuration::maxSymbolCount() && hi) {
+ f = hi->function();
+ if (!f) break;
+
+ TQString name = f->prettyName();
+ if ((int)name.length()>Configuration::maxSymbolLength())
+ name = name.left(Configuration::maxSymbolLength()) + "...";
+
+ //qDebug("back: Adding %s", name.ascii());
+ popup->insertItem(name, count);
+ hi = hi->last();
+ count++;
+ }
+}
+
+void TopLevel::upAboutToShow()
+{
+ TQPopupMenu *popup = _paUp->popupMenu();
+
+ popup->clear();
+ StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0;
+ HistoryItem* hi = b ? b->current() : 0;
+ TraceFunction* f = hi ? hi->function() : 0;
+
+ if (!f) {
+ popup->insertItem(i18n("(No Stack)"));
+ return;
+ }
+ f = hi->stack()->caller(f, false);
+ if (!f) {
+ popup->insertItem(i18n("(No Function Up)"));
+ return;
+ }
+
+ int count = 1;
+ while (count<Configuration::maxSymbolCount() && f) {
+ TQString name = f->prettyName();
+ if ((int)name.length()>Configuration::maxSymbolLength())
+ name = name.left(Configuration::maxSymbolLength()) + "...";
+
+ popup->insertItem(name, count);
+ f = hi->stack()->caller(f, false);
+ count++;
+ }
+
+}
+
+void TopLevel::forwardActivated(int id)
+{
+ //qDebug("forwardActivated: %d", id);
+
+ StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0;
+ if (!b) return;
+
+ while (id>1) {
+ b->goForward();
+ id--;
+ }
+ _stackSelection->browserForward();
+}
+
+void TopLevel::backActivated(int id)
+{
+ //qDebug("backActivated: %d", id);
+
+ StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0;
+ if (!b) return;
+
+ while (id>1) {
+ b->goBack();
+ id--;
+ }
+ _stackSelection->browserBack();
+}
+
+void TopLevel::upActivated(int id)
+{
+ //qDebug("upActivated: %d", id);
+
+ StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0;
+ HistoryItem* hi = b ? b->current() : 0;
+ if (!hi) return;
+
+ TraceFunction* f = hi->function();
+
+ while (id>0 && f) {
+ f = hi->stack()->caller(f, false);
+ id--;
+ }
+
+ //qDebug("upActivated: %s", f ? f->prettyName().ascii() : "??" );
+ if (f)
+ setFunction(f);
+
+}
+
+void TopLevel::showMessage(const TQString& msg, int ms)
+{
+ if (_statusbar)
+ _statusbar->message(msg, ms);
+}
+
+void TopLevel::showStatus(TQString msg, int progress)
+{
+ static bool msgUpdateNeeded = true;
+
+ if (msg.isEmpty()) {
+ if (_progressBar) {
+ _statusbar->removeWidget(_progressBar);
+ delete _progressBar;
+ _progressBar = 0;
+ }
+ _statusbar->clear();
+ _progressMsg = msg;
+ return;
+ }
+
+ if (_progressMsg.isEmpty()) _progressStart.start();
+
+ if (msg != _progressMsg) {
+ _progressMsg = msg;
+ msgUpdateNeeded = true;
+ }
+
+ // do nothing if last change was less than 0.5 seconds ago
+ if (_progressStart.elapsed() < 500) return;
+
+ if (!_progressBar) {
+ _progressBar = new TQProgressBar(_statusbar);
+ _progressBar->setMaximumSize(200, _statusbar->height()-4);
+ _statusbar->addWidget(_progressBar, 1, true);
+ _progressBar->show();
+ msgUpdateNeeded = true;
+ }
+
+ _progressStart.restart();
+
+ if (msgUpdateNeeded) {
+ _statusbar->message(msg);
+ msgUpdateNeeded = false;
+ }
+ _progressBar->setProgress(progress);
+
+ // let the progress bar update itself
+ TQEventLoop* l = tqApp->eventLoop();
+ if (l) l->processEvents(TQEventLoop::ExcludeUserInput);
+}
+
+#include "toplevel.moc"
diff --git a/kdecachegrind/kdecachegrind/toplevel.h b/kdecachegrind/kdecachegrind/toplevel.h
new file mode 100644
index 0000000..10e7cde
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/toplevel.h
@@ -0,0 +1,275 @@
+/* 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.
+*/
+
+/*
+ * KCachegrind top level window
+ */
+
+#ifndef TOPLEVEL_H
+#define TOPLEVEL_H
+
+#include <tqdatetime.h>
+
+#include <dcopobject.h>
+#include <kmainwindow.h>
+
+#include "traceitemview.h"
+#include "tracedata.h"
+
+class MultiView;
+class TQLineEdit;
+class TQDockWidget;
+class TQLabel;
+class TQProgressBar;
+class TQPopupMenu;
+
+class KURL;
+class KSelectAction;
+class KToggleAction;
+class KToolBarPopupAction;
+
+class TraceData;
+class KRecentFilesAction;
+class MainWidget;
+class PartSelection;
+class FunctionSelection;
+class DumpSelection;
+class StackSelection;
+class TraceFunction;
+
+class TopLevel : public KMainWindow, public DCOPObject
+{
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+ TopLevel(const char *name = 0);
+ ~TopLevel();
+
+ TraceData* data() { return _data; }
+ void setData(TraceData*);
+
+ virtual void saveProperties(KConfig*);
+ virtual void readProperties(KConfig*);
+
+ void createActions();
+ void createDocks();
+
+ TraceItem::CostType groupType() { return _groupType; }
+ TraceCostType* costType() { return _costType; }
+ TraceCostType* costType2() { return _costType2; }
+ TracePartList activeParts() { return _activeParts; }
+ TracePartList hiddenParts() { return _hiddenParts; }
+
+ // current config
+ bool showPercentage() const { return _showPercentage; }
+ bool showExpanded() const { return _showExpanded; }
+ bool showCycles() const { return _showCycles; }
+
+ /* convenience functions for often used context menu items */
+ void addCostMenu(TQPopupMenu*,bool);
+ void addGoMenu(TQPopupMenu*);
+
+public slots:
+ void newTrace();
+ void loadTrace();
+ void loadTrace(const KURL&);
+ void loadTrace(TQString);
+ void addTrace();
+ void addTrace(const KURL&);
+ void addTrace(TQString);
+
+ // for quick showing the main window...
+ void loadDelayed(TQString);
+
+ void reload();
+ void exportGraph();
+ void newWindow();
+ void configure();
+ void querySlot();
+ void dummySlot();
+
+ // layouts
+ void layoutDuplicate();
+ void layoutRemove();
+ void layoutNext();
+ void layoutPrevious();
+ void layoutSave();
+ void layoutRestore();
+ void updateLayoutActions();
+
+ void updateStatusBar();
+ void costTypeSelected(const TQString&);
+ void costType2Selected(const TQString&);
+ void groupTypeSelected(int);
+ void splitSlot();
+ void splitDirSlot();
+ void configureToolbars();
+ void configureKeys();
+ bool queryExit();
+ bool queryClose();
+ void togglePartDock();
+ void toggleStackDock();
+ void toggleFunctionDock();
+ void toggleDumpDock();
+ void toggleStatusBar();
+ void partVisibilityChanged(bool);
+ void dumpVisibilityChanged(bool);
+ void stackVisibilityChanged(bool);
+ void functionVisibilityChanged(bool);
+ void togglePercentage();
+ void setPercentage(bool);
+ void setAbsoluteCost();
+ void setRelativeCost();
+ void toggleExpanded();
+ void toggleCycles();
+ void forceTrace();
+ void forceTraceReload();
+ void forwardAboutToShow();
+ void backAboutToShow();
+ void upAboutToShow();
+ void forwardActivated(int);
+ void backActivated(int);
+ void upActivated(int);
+
+ bool setCostType(TraceCostType*);
+ bool setCostType2(TraceCostType*);
+ bool setCostType(TQString);
+ bool setCostType2(TQString);
+ bool setCostType(int);
+ bool setCostType2(int);
+ bool setGroupType(TraceItem::CostType);
+ bool setGroupType(TQString);
+ bool setGroup(TraceCostItem*);
+ bool setGroup(TQString);
+ bool setFunction(TraceFunction*);
+ bool setFunction(TQString);
+ void activePartsChangedSlot(const TracePartList& list);
+ void partsHideSelectedSlot();
+ void partsUnhideAllSlot();
+
+ /* These go back to mainloop first by using a timer.
+ * So they can be called from event handlers that
+ * aren't allowed to delete list entries.
+ */
+ void setCostTypeDelayed(TraceCostType*);
+ void setCostType2Delayed(TraceCostType*);
+ void setGroupTypeDelayed(TraceItem::CostType);
+ void setGroupDelayed(TraceCostItem*);
+ void setTraceItemDelayed(TraceItem*);
+ void partsHideSelectedSlotDelayed();
+ void partsUnhideAllSlotDelayed();
+ void goBack();
+ void goForward();
+ void goUp();
+ void setDirectionDelayed(TraceItemView::Direction);
+
+ /* SingleShot Slots (without parameters) for the delayed versions */
+ void setCostTypeDelayed();
+ void setCostType2Delayed();
+ void setGroupTypeDelayed();
+ void setGroupDelayed();
+ void setTraceItemDelayed();
+ void loadTraceDelayed();
+ void setDirectionDelayed();
+
+ // configuration has changed
+ void configChanged();
+
+ //void refresh();
+ void slotShowTipOnStart();
+ void slotShowTip();
+
+ // progress in status bar, empty message disables progress display
+ void showStatus(TQString msg, int progress);
+ void showMessage(const TQString&, int msec);
+
+private:
+ void init();
+ void createLayoutActions();
+ void createMiscActions();
+ void setupMainWidget(MainWidget*);
+ void setupPartSelection(PartSelection*);
+ void restoreCurrentState(TQString postfix);
+ void saveCurrentState(TQString postfix);
+ void saveTraceSettings();
+ TQString traceKey();
+ void restoreTraceTypes();
+ void restoreTraceSettings();
+
+ KStatusBar* _statusbar;
+ TQLabel* _statusLabel;
+ KRecentFilesAction* _openRecent;
+ bool _twoMainWidgets;
+ Qt::Orientation _spOrientation;
+
+ MultiView* _multiView;
+ FunctionSelection* _functionSelection;
+ DumpSelection* _dumpSelection;
+ PartSelection* _partSelection;
+ StackSelection* _stackSelection;
+ TQLineEdit* queryLineEdit;
+
+ TQDockWindow *_partDock, *_stackDock, *_functionDock, *_dumpDock;
+ bool _forcePartDock;
+
+ KSelectAction *_saCost, *_saCost2, *saGroup;
+ KToggleAction *_partDockShown, *_stackDockShown;
+ KToggleAction *_functionDockShown, *_dumpDockShown;
+ KToggleAction *_taPercentage, *_taExpanded, *_taCycles;
+ KToggleAction *_taDump, *_taSplit, *_taSplitDir;
+ KToolBarPopupAction *_paForward, *_paBack, *_paUp;
+
+ TraceFunction* _function;
+ const TQObject* _lastSender;
+
+ // trace data shown in this window
+ TraceData* _data;
+ // subcost types used for visualisation
+ TraceCostType* _costType;
+ TraceCostType* _costType2;
+ // grouping of function list
+ TraceItem::CostType _groupType;
+ // selected group
+ TraceCostItem* _group;
+ // selected parts
+ TracePartList _activeParts;
+ // hidden parts
+ TracePartList _hiddenParts;
+ // layouts
+ int _layoutCurrent, _layoutCount;
+
+ // for delayed slots
+ TraceCostType* _costTypeDelayed;
+ TraceCostType* _costType2Delayed;
+ TraceItem::CostType _groupTypeDelayed;
+ TraceCostItem* _groupDelayed;
+ TraceItem* _traceItemDelayed;
+ TQString _loadTraceDelayed;
+ TraceItemView::Direction _directionDelayed;
+
+ // for status progress display
+ TQString _progressMsg;
+ TQTime _progressStart;
+ TQProgressBar* _progressBar;
+
+ // toplevel configuration options
+ bool _showPercentage, _showExpanded, _showCycles;
+};
+
+#endif
diff --git a/kdecachegrind/kdecachegrind/tracedata.cpp b/kdecachegrind/kdecachegrind/tracedata.cpp
new file mode 100644
index 0000000..f129c2e
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/tracedata.cpp
@@ -0,0 +1,5068 @@
+/* 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 <stdlib.h>
+
+#include <tqfile.h>
+#include <tqdir.h>
+#include <tqfileinfo.h>
+#include <tqregexp.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "tracedata.h"
+#include "toplevel.h"
+#include "loader.h"
+#include "configuration.h"
+#include "utils.h"
+#include "fixcost.h"
+
+
+#define TRACE_DEBUG 0
+#define TRACE_ASSERTIONS 0
+
+const int TraceCost::MaxRealIndex = MaxRealIndexValue;
+const int TraceCost::InvalidIndex = -1;
+
+//---------------------------------------------------
+// Addr
+
+bool Addr::set(FixString& s)
+{
+ return s.stripUInt64(_v);
+}
+
+int Addr::set(const char *s)
+{
+ int n = 0;
+ _v = 0;
+
+ while((n<16) && *s) {
+ if ((*s>='0') && (*s<='9'))
+ _v = 16*_v + (*s-'0');
+ else if ((*s>='a') && (*s<='f'))
+ _v = 16*_v + 10 + (*s-'a');
+ else if ((*s>='A') && (*s<='F'))
+ _v = 16*_v + 10 + (*s-'A');
+ else break;
+ s++;
+ n++;
+ }
+
+ return n;
+}
+
+
+TQString Addr::toString() const
+{
+ if (_v == 0) return TQString("0");
+
+ uint64 n = _v;
+ TQString hex;
+ hex.reserve(16);
+
+ while(n>0) {
+ int d = (n & 15);
+ hex = TQChar((d<10) ? ('0'+d) : ('A'-10+d)) + hex;
+ n /= 16;
+ }
+
+ return hex;
+}
+
+TQString Addr::pretty() const
+{
+ if (_v == 0) return TQString("0");
+
+ uint64 n = _v;
+ int p = 0;
+ TQString hex;
+ hex.reserve(20);
+
+ while(n>0) {
+ int d = (n & 15);
+ if ((p>0) && ((p%4)==0)) hex = " " + hex;
+ hex = TQChar((d<10) ? ('0'+d) : ('A'-10+d)) + hex;
+ n /= 16;
+ p++;
+ }
+
+ return hex;
+}
+
+bool Addr::isInRange(Addr a, int distance)
+{
+ uint64 diff = (a._v > _v) ? (a._v - _v) : (_v - a._v);
+ uint64 dist = (distance<0) ? distance : -distance;
+ return (diff < dist);
+}
+
+//---------------------------------------------------
+// TraceItem
+
+TQString* TraceItem::_typeName = 0;
+TQString* TraceItem::_i18nTypeName = 0;
+
+TraceItem::TraceItem()
+{
+ _position = 0;
+ _dep = 0;
+ _dirty = true;
+}
+
+TraceItem::~TraceItem()
+{}
+
+void TraceItem::cleanup()
+{
+ if (_typeName) {
+ delete [] _typeName;
+ _typeName = 0;
+ }
+ if (_i18nTypeName) {
+ delete [] _i18nTypeName;
+ _i18nTypeName = 0;
+ }
+}
+
+TQString TraceItem::typeName(CostType t)
+{
+ if (!_typeName) {
+ _typeName = new TQString [MaxCostType+1];
+ TQString* strs = _typeName;
+ for(int i=0;i<=MaxCostType;i++)
+ strs[i] = TQString("?");
+
+ strs[Item] = I18N_NOOP("Abstract Item");
+ strs[Cost] = I18N_NOOP("Cost Item");
+ strs[PartLine] = I18N_NOOP("Part Source Line");
+ strs[Line] = I18N_NOOP("Source Line");
+ strs[PartLineCall] = I18N_NOOP("Part Line Call");
+ strs[LineCall] = I18N_NOOP("Line Call");
+ strs[PartLineJump] = I18N_NOOP("Part Jump");
+ strs[LineJump] = I18N_NOOP("Jump");
+ strs[PartInstr] = I18N_NOOP("Part Instruction");
+ strs[Instr] = I18N_NOOP("Instruction");
+ strs[PartInstrJump] = I18N_NOOP("Part Instruction Jump");
+ strs[InstrJump] = I18N_NOOP("Instruction Jump");
+ strs[PartInstrCall] = I18N_NOOP("Part Instruction Call");
+ strs[InstrCall] = I18N_NOOP("Instruction Call");
+ strs[PartCall] = I18N_NOOP("Part Call");
+ strs[Call] = I18N_NOOP("Call");
+ strs[PartFunction] = I18N_NOOP("Part Function");
+ strs[FunctionSource] = I18N_NOOP("Function Source File");
+ strs[Function] = I18N_NOOP("Function");
+ strs[FunctionCycle] = I18N_NOOP("Function Cycle");
+ strs[PartClass] = I18N_NOOP("Part Class");
+ strs[Class] = I18N_NOOP("Class");
+ strs[PartFile] = I18N_NOOP("Part Source File");
+ strs[File] = I18N_NOOP("Source File");
+ strs[PartObject] = I18N_NOOP("Part ELF Object");
+ strs[Object] = I18N_NOOP("ELF Object");
+ strs[Part] = I18N_NOOP("Profile Part");
+ strs[Data] = I18N_NOOP("Program Trace");
+ }
+ if (t<0 || t> MaxCostType) t = MaxCostType;
+ return _typeName[t];
+}
+
+TraceItem::CostType TraceItem::costType(TQString s)
+{
+ // This is the default cost Type
+ if (s.isEmpty()) return Function;
+
+ CostType type;
+ for (int i=0; i<MaxCostType;i++) {
+ type = (CostType) i;
+ if (typeName(type) == s)
+ return type;
+ }
+ return NoCostType;
+}
+
+// all strings of typeName() are translatable because of I18N_NOOP there
+TQString TraceItem::i18nTypeName(CostType t)
+{
+ if (!_i18nTypeName) {
+ _i18nTypeName = new TQString [MaxCostType+1];
+ for(int i=0;i<=MaxCostType;i++)
+ _i18nTypeName[i] = i18n(typeName((CostType)i).utf8().data());
+ }
+ if (t<0 || t> MaxCostType) t = MaxCostType;
+ return _i18nTypeName[t];
+}
+
+TraceItem::CostType TraceItem::i18nCostType(TQString s)
+{
+ // This is the default cost Type
+ if (s.isEmpty()) return Function;
+
+ CostType type;
+ for (int i=0; i<MaxCostType;i++) {
+ type = (CostType) i;
+ if (i18nTypeName(type) == s)
+ return type;
+ }
+ return NoCostType;
+}
+
+
+void TraceItem::clear()
+{
+ invalidate();
+}
+
+
+TQString TraceItem::costString(TraceCostMapping*)
+{
+ return TQString("(no cost)");
+}
+
+TQString TraceItem::name() const
+{
+ if (part()) {
+ return i18n("%1 from %2")
+ .arg(_dep->name())
+ .arg(part()->name());
+ }
+
+ if (_dep)
+ return _dep->name();
+
+ return i18n("(unknown)");
+}
+
+TQString TraceItem::prettyName() const
+{
+ if (name().isEmpty()) return i18n("(unknown)");
+ return name();
+}
+
+
+TQString TraceItem::fullName() const
+{
+ return TQString("%1 %2")
+ .arg(typeName(type())).arg(prettyName());
+}
+
+TQString TraceItem::toString()
+{
+ return TQString("%1\n [%3]").arg(fullName()).arg(costString(0));
+}
+
+void TraceItem::invalidate()
+{
+ if (_dirty) return;
+ _dirty = true;
+
+ if (_dep)
+ _dep->invalidate();
+}
+
+void TraceItem::update()
+{
+ _dirty = false;
+}
+
+TracePart* TraceItem::part()
+{
+ return _position ? _position->part() : 0;
+}
+
+const TracePart* TraceItem::part() const
+{
+ return _position ? _position->part() : 0;
+}
+
+TraceData* TraceItem::data()
+{
+ return _position ? _position->data() : 0;
+}
+
+const TraceData* TraceItem::data() const
+{
+ return _position ? _position->data() : 0;
+}
+
+
+//---------------------------------------------------
+// TraceCost
+
+TraceCost::TraceCost()
+ : TraceItem()
+{
+ _cachedType = 0; // no virtual value cached
+
+ TraceCost::clear();
+}
+
+TraceCost::~TraceCost()
+{}
+
+
+void TraceCost::clear()
+{
+ // simple set usage count to 0
+ _count = 0;
+
+ TraceItem::clear();
+}
+
+
+
+void TraceCost::set(TraceSubMapping* sm, const char* s)
+{
+ if (!sm) return;
+ if (!s) {
+ if (_count>0) clear();
+ return;
+ }
+
+ while(*s == ' ') s++;
+
+ if (sm->isIdentity()) {
+ int i = 0;
+ while(i<sm->count()) {
+ if (!_cost[i].set(&s)) break;
+ i++;
+ }
+ _count = i;
+ }
+ else {
+ int i = 0, maxIndex = 0, index;
+ while(1) {
+ index = sm->realIndex(i);
+ if (maxIndex<index) maxIndex=index;
+ if (index == TraceCost::InvalidIndex) break;
+ if (!_cost[index].set(&s)) break;
+ i++;
+ }
+ // we have to set all costs of unused indexes till maxIndex to zero
+ for(i=sm->firstUnused(); i<=maxIndex; i=sm->nextUnused(i))
+ _cost[i] = 0;
+ _count = maxIndex;
+ }
+ // a cost change has to be propagated (esp. in subclasses)
+ invalidate();
+}
+
+void TraceCost::set(TraceSubMapping* sm, FixString & s)
+{
+ if (!sm) return;
+
+ s.stripSpaces();
+
+ if (sm->isIdentity()) {
+ int i = 0;
+ while(i<sm->count()) {
+ if (!s.stripUInt64(_cost[i])) break;
+ i++;
+ }
+ _count = i;
+ }
+ else {
+ int i = 0, maxIndex = 0, index;
+ while(1) {
+ index = sm->realIndex(i);
+ if (maxIndex<index) maxIndex=index;
+ if (index == TraceCost::InvalidIndex) break;
+ if (!s.stripUInt64(_cost[index])) break;
+ i++;
+ }
+ // we have to set all costs of unused indexes till maxIndex to zero
+ for(i=sm->firstUnused(); i<=maxIndex; i=sm->nextUnused(i))
+ _cost[i] = 0;
+ _count = maxIndex+1;
+ }
+ invalidate();
+}
+
+
+void TraceCost::addCost(TraceSubMapping* sm, const char* s)
+{
+ if (!sm || !s) return;
+
+ SubCost v;
+
+ if (sm->isIdentity()) {
+ int i = 0;
+ while(i<sm->count()) {
+ if (!v.set(&s)) break;
+ if (i<_count)
+ _cost[i] += v;
+ else
+ _cost[i] = v;
+ i++;
+ }
+ if (i > _count) _count = i;
+ }
+ else {
+ int i = 0, maxIndex = 0, index;
+ while(1) {
+ if (!v.set(&s)) break;
+ index = sm->realIndex(i);
+ if (maxIndex<index) maxIndex=index;
+ if (index == TraceCost::InvalidIndex) break;
+ if (index<_count)
+ _cost[index] += v;
+ else
+ _cost[index] = v;
+ i++;
+ }
+ if (maxIndex >= _count) {
+ /* we have to set all costs of unused indexes in the interval
+ * [_count;maxIndex] to zero */
+ for(i=sm->nextUnused(_count-1); i<=maxIndex; i=sm->nextUnused(i))
+ _cost[i] = 0;
+ _count = maxIndex+1;
+ }
+ }
+
+ // a cost change has to be propagated (esp. in subclasses)
+ invalidate();
+
+#if TRACE_DEBUG
+ _dirty = false; // don't recurse !
+ qDebug("%s\n now %s", fullName().ascii(),
+ TraceCost::costString(0).ascii());
+ _dirty = true; // because of invalidate()
+#endif
+}
+
+void TraceCost::addCost(TraceSubMapping* sm, FixString & s)
+{
+ if (!sm) return;
+
+ s.stripSpaces();
+
+ SubCost v;
+
+ if (sm->isIdentity()) {
+ int i = 0;
+ while(i<sm->count()) {
+ if (!s.stripUInt64(v)) break;
+ if (i<_count)
+ _cost[i] += v;
+ else
+ _cost[i] = v;
+ i++;
+ }
+ if (i > _count) _count = i;
+ }
+ else {
+ int i = 0, maxIndex = 0, index;
+ while(1) {
+ if (!s.stripUInt64(v)) break;
+ index = sm->realIndex(i);
+ if (maxIndex<index) maxIndex=index;
+ if (index == TraceCost::InvalidIndex) break;
+ if (index<_count)
+ _cost[index] += v;
+ else
+ _cost[index] = v;
+ i++;
+ }
+ if (maxIndex >= _count) {
+ /* we have to set all costs of unused indexes in the interval
+ * [_count;maxIndex] to zero */
+ for(i=sm->nextUnused(_count-1); i<=maxIndex; i=sm->nextUnused(i))
+ _cost[i] = 0;
+ _count = maxIndex+1;
+ }
+ }
+
+ invalidate();
+
+#if TRACE_DEBUG
+ _dirty = false; // don't recurse !
+ qDebug("%s\n now %s", fullName().ascii(),
+ TraceCost::costString(0).ascii());
+ _dirty = true; // because of invalidate()
+#endif
+}
+
+
+// update each subcost to be maximum of old and given costs
+void TraceCost::maxCost(TraceSubMapping* sm, FixString & s)
+{
+ if (!sm) return;
+
+ s.stripSpaces();
+
+ SubCost v;
+
+ if (sm->isIdentity()) {
+ int i = 0;
+ while(i<sm->count()) {
+ if (!s.stripUInt64(v)) break;
+ if (i<_count) {
+ if (v>_cost[i]) _cost[i] = v;
+ }
+ else
+ _cost[i] = v;
+ i++;
+ }
+ if (i > _count) _count = i;
+ }
+ else {
+ int i = 0, maxIndex = 0, index;
+ while(1) {
+ if (!s.stripUInt64(v)) break;
+ index = sm->realIndex(i);
+ if (maxIndex<index) maxIndex=index;
+ if (index == TraceCost::InvalidIndex) break;
+ if (index<_count) {
+ if (v>_cost[index]) _cost[index] = v;
+ }
+ else
+ _cost[index] = v;
+ i++;
+ }
+ if (maxIndex >= _count) {
+ /* we have to set all costs of unused indexes in the interval
+ * [_count;maxIndex] to zero */
+ for(i=sm->nextUnused(_count-1); i<=maxIndex; i=sm->nextUnused(i))
+ _cost[i] = 0;
+ _count = maxIndex+1;
+ }
+ }
+
+ invalidate();
+
+#if TRACE_DEBUG
+ _dirty = false; // don't recurse !
+ qDebug("%s\n now %s", fullName().ascii(),
+ TraceCost::costString(0).ascii());
+ _dirty = true; // because of invalidate()
+#endif
+}
+
+
+void TraceCost::addCost(TraceCost* item)
+{
+ int i;
+
+ if (!item) return;
+
+ // we have to update the other item if needed
+ // because we access the item costs directly
+ if (item->_dirty) item->update();
+
+ if (item->_count < _count) {
+ for (i = 0; i<item->_count; i++)
+ _cost[i] += item->_cost[i];
+ }
+ else {
+ for (i = 0; i<_count; i++)
+ _cost[i] += item->_cost[i];
+ for (; i<item->_count; i++)
+ _cost[i] = item->_cost[i];
+ _count = item->_count;
+ }
+
+ // a cost change has to be propagated (esp. in subclasses)
+ invalidate();
+
+#if TRACE_DEBUG
+ _dirty = false; // don't recurse !
+ qDebug("%s added cost item\n %s\n now %s",
+ fullName().ascii(), item->fullName().ascii(),
+ TraceCost::costString(0).ascii());
+ _dirty = true; // because of invalidate()
+#endif
+}
+
+void TraceCost::maxCost(TraceCost* item)
+{
+ int i;
+
+ if (!item) return;
+
+ // we have to update the other item if needed
+ // because we access the item costs directly
+ if (item->_dirty) item->update();
+
+ if (item->_count < _count) {
+ for (i = 0; i<item->_count; i++)
+ if (_cost[i] < item->_cost[i]) _cost[i] = item->_cost[i];
+ }
+ else {
+ for (i = 0; i<_count; i++)
+ if (_cost[i] < item->_cost[i]) _cost[i] = item->_cost[i];
+ for (; i<item->_count; i++)
+ _cost[i] = item->_cost[i];
+ _count = item->_count;
+ }
+
+ // a cost change has to be propagated (esp. in subclasses)
+ invalidate();
+
+#if TRACE_DEBUG
+ _dirty = false; // don't recurse !
+ qDebug("%s added cost item\n %s\n now %s",
+ fullName().ascii(), item->fullName().ascii(),
+ TraceCost::costString(0).ascii());
+ _dirty = true; // because of invalidate()
+#endif
+}
+
+void TraceCost::addCost(int type, SubCost value)
+{
+ if (type<0 || type>=MaxRealIndex) return;
+ if (type<_count)
+ _cost[type] += value;
+ else {
+ for(int i=_count;i<type;i++)
+ _cost[i] = 0;
+ _cost[type] = value;
+ _count = type+1;
+ }
+
+ // a cost change has to be propagated (esp. in subclasses)
+ invalidate();
+}
+
+void TraceCost::maxCost(int type, SubCost value)
+{
+ if (type<0 || type>=MaxRealIndex) return;
+ if (type<_count) {
+ if (value>_cost[type]) _cost[type] = value;
+ }
+ else {
+ for(int i=_count;i<type;i++)
+ _cost[i] = 0;
+ _cost[type] = value;
+ _count = type+1;
+ }
+
+ // a cost change has to be propagated (esp. in subclasses)
+ invalidate();
+}
+
+
+TraceCost TraceCost::diff(TraceCost* item)
+{
+ TraceCost res;
+
+ // we have to update the other item if needed
+ // because we access the item costs directly
+ if (item->_dirty) item->update();
+
+ int maxCount = (item->_count > _count) ? item->_count : _count;
+
+ res._count = maxCount;
+ for (int i=0; i<maxCount;i++)
+ res._cost[i] = item->subCost(i) - subCost(i);
+
+ return res;
+}
+
+TQString TraceCost::costString(TraceCostMapping* m)
+{
+ TQString res;
+
+ if (_dirty) update();
+
+ int maxIndex = m ? m->realCount() : TraceCost::MaxRealIndex;
+ for (int i = 0; i<maxIndex; i++) {
+ if (!res.isEmpty()) res += ", ";
+ if (m) res += m->type(i)->name() + " ";
+
+ res += subCost(i).pretty();
+ }
+ return res;
+}
+
+
+void TraceCost::invalidate()
+{
+ if (_dirty) return;
+ _dirty = true;
+ _cachedType = 0; // cached value is invalid, too
+
+ if (_dep)
+ _dep->invalidate();
+}
+
+void TraceCost::update()
+{
+ _dirty = false;
+}
+
+// this is only for real types
+SubCost TraceCost::subCost(int idx)
+{
+ if (idx<0) return 0;
+
+ /* update if needed as cost could be calculated dynamically in subclasses
+ * this can change _count !! */
+ if (_dirty) update();
+ if (idx>=_count) return 0;
+
+ return _cost[idx];
+}
+
+SubCost TraceCost::subCost(TraceCostType* t)
+{
+ if (!t) return 0;
+ if (_cachedType != t) {
+ _cachedType = t;
+ _cachedCost = t->subCost(this);
+ }
+ return _cachedCost;
+}
+
+TQString TraceCost::prettySubCost(TraceCostType* t)
+{
+ return subCost(t).pretty();
+}
+
+
+
+//---------------------------------------------------
+// TraceJumpCost
+
+TraceJumpCost::TraceJumpCost()
+ :TraceItem()
+{
+ TraceJumpCost::clear();
+}
+
+TraceJumpCost::~TraceJumpCost()
+{}
+
+SubCost TraceJumpCost::executedCount()
+{
+ if (_dirty) update();
+
+ return _executedCount;
+}
+
+SubCost TraceJumpCost::followedCount()
+{
+ if (_dirty) update();
+
+ return _followedCount;
+}
+
+TQString TraceJumpCost::costString(TraceCostMapping*)
+{
+ if (_dirty) update();
+
+ return TQString("%1/%2")
+ .arg(_followedCount.pretty())
+ .arg(_executedCount.pretty());
+}
+
+void TraceJumpCost::clear()
+{
+ _followedCount = 0;
+ _executedCount = 0;
+}
+
+void TraceJumpCost::addCost(TraceJumpCost* item)
+{
+ if (item->_dirty) item->update();
+
+ _followedCount += item->followedCount();
+ _executedCount += item->executedCount();
+}
+
+
+//---------------------------------------------------
+// TraceCostType
+
+TQPtrList<TraceCostType>* TraceCostType::_knownTypes = 0;
+
+TraceCostType::TraceCostType(TQString name, TQString longName, TQString formula)
+{
+ _name = name;
+ _longName = longName;
+ _formula = formula;
+ _mapping = 0;
+ _realIndex = TraceCost::InvalidIndex;
+ _parsed = false;
+ _inParsing = false;
+
+ for (int i=0; i<TraceCost::MaxRealIndex;i++)
+ _coefficient[i] = 0;
+}
+
+void TraceCostType::setFormula(TQString formula)
+{
+ _formula = formula;
+ _realIndex = TraceCost::InvalidIndex;
+ _parsed = false;
+}
+
+void TraceCostType::setMapping(TraceCostMapping* m)
+{
+ _parsed = false;
+ _mapping = m;
+}
+
+// setting the index to TraceCost::MaxRealIndex makes it a
+// real type with unspecified index
+void TraceCostType::setRealIndex(int i)
+{
+ if (i<0 || i>TraceCost::MaxRealIndex)
+ i=TraceCost::InvalidIndex;
+
+ _realIndex = i;
+ _formula = TQString();
+}
+
+// checks for existing types and sets coefficients
+bool TraceCostType::parseFormula()
+{
+ if (_parsed) return true;
+ if (_inParsing) {
+ qDebug("TraceCostType::parseFormula: Recursion detected.");
+ return false;
+ }
+
+ if (!_mapping) {
+ qDebug("TraceCostType::parseFormula: No mapping set!");
+ return false;
+ }
+
+ _inParsing = true;
+
+ for (int i=0; i<TraceCost::MaxRealIndex;i++)
+ _coefficient[i] = 0;
+
+ TQRegExp rx( "((?:\\+|\\-)?)\\s*(\\d*)\\s*\\*?\\s*(\\w+)" );
+
+ int factor, pos;
+ TQString costName;
+ TraceCostType* costType;
+
+ pos = 0;
+ while (1) {
+ pos = rx.search(_formula, pos);
+ if (pos<0) break;
+ pos += rx.matchedLength();
+ if (rx.cap(0).isEmpty()) break;
+
+ //qDebug("parseFormula: matched '%s','%s','%s'",
+ // rx.cap(1).ascii(), rx.cap(2).ascii(), rx.cap(3).ascii());
+
+ costName = rx.cap(3);
+ costType = _mapping->type(costName);
+ if (!costType) {
+ // qDebug("Cost type '%s': In formula cost '%s' unknown.",
+ // _name.ascii(), costName.ascii());
+
+ _inParsing = false;
+ return false;
+ }
+
+ factor = (rx.cap(2).isEmpty()) ? 1 : rx.cap(2).toInt();
+ if (rx.cap(1) == "-") factor = -factor;
+
+ if (costType->isReal())
+ _coefficient[costType->realIndex()] += factor;
+ else {
+ costType->parseFormula();
+ for (int i=0; i<TraceCost::MaxRealIndex;i++)
+ _coefficient[i] += factor * costType->_coefficient[i];
+ }
+ }
+
+ _inParsing = false;
+ _parsed = true;
+
+ return true;
+}
+
+TQString TraceCostType::parsedFormula()
+{
+ TQString res;
+
+ if (!parseFormula()) return res;
+
+ for (int i=0; i<TraceCost::MaxRealIndex;i++) {
+ int c = _coefficient[i];
+ if (c == 0) continue;
+
+ if (!res.isEmpty()) {
+ res += " ";
+ if (c>0) res += "+ ";
+ }
+ if (c<0) { res += "- "; c = -c; }
+ res += TQString::number(c);
+
+ TraceCostType* t = _mapping->type(i);
+ if (!t) continue;
+
+ if (!t->name().isEmpty())
+ res += TQString(" * %1").arg(t->name());
+ }
+
+ return res;
+}
+
+SubCost TraceCostType::subCost(TraceCost* c)
+{
+ if (_realIndex != TraceCost::InvalidIndex)
+ return c->subCost(_realIndex);
+
+ if (!_parsed) {
+ if (!parseFormula()) return 0;
+ }
+ SubCost res = 0;
+
+ int rc = _mapping->realCount();
+ for (int i = 0;i<rc;i++)
+ if (_coefficient[i] != 0)
+ res += _coefficient[i] * c->subCost(i);
+
+ return res;
+}
+
+int TraceCostType::histCost(TraceCost* c, double total, double* hist)
+{
+ if (total == 0.0) return 0;
+
+ if (!_parsed) {
+ if (!parseFormula()) return 0;
+ }
+
+ int rc = _mapping->realCount();
+ for (int i = 0;i<rc;i++) {
+ if (_coefficient[i] != 0)
+ hist[i] = _coefficient[i] * c->subCost(i) / total;
+ else
+ hist[i] = 0.0;
+ }
+
+ return rc;
+}
+
+
+
+
+TraceCostType* TraceCostType::knownRealType(TQString n)
+{
+ if (!_knownTypes) return 0;
+
+ TraceCostType* t;
+ for (t=_knownTypes->first();t;t=_knownTypes->next())
+ if (t->isReal() && (t->name() == n)) {
+ TraceCostType* type = new TraceCostType(*t);
+ return type;
+ }
+
+ return 0;
+}
+
+TraceCostType* TraceCostType::knownVirtualType(TQString n)
+{
+ if (!_knownTypes) return 0;
+
+ TraceCostType* t;
+ for (t=_knownTypes->first();t;t=_knownTypes->next())
+ if (!t->isReal() && (t->name() == n)) {
+ TraceCostType* type = new TraceCostType(*t);
+ return type;
+ }
+
+ return 0;
+}
+
+// we take ownership
+void TraceCostType::add(TraceCostType* t)
+{
+ if (!t) return;
+
+ t->setMapping(0);
+
+ if (!_knownTypes)
+ _knownTypes = new TQPtrList<TraceCostType>;
+
+ /* Already known? */
+ TraceCostType* kt;
+ for (kt=_knownTypes->first();kt;kt=_knownTypes->next())
+ if (kt->name() == t->name()) break;
+
+ if (kt) {
+ // Overwrite old type
+ if (!t->longName().isEmpty() &&
+ (t->longName() != t->name())) kt->setLongName(t->longName());
+ if (!t->formula().isEmpty()) kt->setFormula(t->formula());
+
+ delete t;
+ }
+ else {
+ if (t->longName().isEmpty()) t->setLongName(t->name());
+ _knownTypes->append(t);
+ }
+}
+
+
+int TraceCostType::knownTypeCount()
+{
+ if (!_knownTypes) return 0;
+
+ return _knownTypes->count();
+}
+
+bool TraceCostType::remove(TQString n)
+{
+ if (!_knownTypes) return false;
+
+ TraceCostType* t;
+ for (t=_knownTypes->first();t;t=_knownTypes->next())
+ if (!t->isReal() && (t->name() == n)) {
+ _knownTypes->removeRef(t);
+ delete t;
+ return true;
+ }
+
+ return false;
+}
+
+TraceCostType* TraceCostType::knownType(int i)
+{
+ if (!_knownTypes) return 0;
+ if (i<0 || i>=(int)_knownTypes->count()) return 0;
+
+ return _knownTypes->at(i);
+}
+
+TQColor TraceCostType::color()
+{
+ if (!_mapping) return TQColor();
+ return _mapping->realColors()[_realIndex];
+}
+
+
+//---------------------------------------------------
+// TraceCostMapping
+
+TraceCostMapping::TraceCostMapping()
+{
+ _realCount = 0;
+ _virtualCount = 0;
+ for (int i=0;i<TraceCost::MaxRealIndex;i++) _real[i] = 0;
+ for (int i=0;i<TraceCost::MaxRealIndex;i++) _virtual[i] = 0;
+}
+
+TraceCostMapping::~TraceCostMapping()
+{
+ for (int i=0;i<TraceCost::MaxRealIndex;i++)
+ if (_real[i]) delete _real[i];
+
+ for (int i=0;i<TraceCost::MaxRealIndex;i++)
+ if (_virtual[i]) delete _virtual[i];
+}
+
+TraceSubMapping* TraceCostMapping::subMapping(TQString types, bool create)
+{
+ // first check if there's enough space in the mapping
+ int newCount = 0;
+ int pos = 0, pos2, len = types.length();
+
+ while (1) {
+ // skip space
+ while((pos<len) && types[pos].isSpace()) pos++;
+
+ pos2 = pos;
+ while((pos2<len) && !types[pos2].isSpace()) pos2++;
+ if (pos2 == pos) break;
+
+ if (realIndex(types.mid(pos,pos2-pos)) == TraceCost::InvalidIndex)
+ newCount++;
+
+ pos = pos2;
+ }
+
+ if (!create && (newCount>0)) return 0;
+
+ if (newCount+_realCount > TraceCost::MaxRealIndex) {
+ kdDebug() << "TraceCostMapping::subMapping: No space for "
+ << newCount << " sub costs." << endl;
+ return 0;
+ }
+
+ TraceSubMapping* sm = new TraceSubMapping(this);
+
+ pos = 0;
+ while (1) {
+ // skip space
+ while((pos<len) && types[pos].isSpace()) pos++;
+
+ pos2 = pos;
+ while((pos2<len) && !types[pos2].isSpace()) pos2++;
+ if (pos2 == pos) break;
+
+ sm->append(addReal(types.mid(pos,pos2-pos)));
+
+ pos = pos2;
+ }
+
+ return sm;
+}
+
+
+int TraceCostMapping::addReal(TQString t)
+{
+ int index = realIndex(t);
+ if (index>=0) return index;
+
+ TraceCostType* ct = TraceCostType::knownRealType(t);
+ if (!ct) ct = new TraceCostType(t, t);
+
+ // make it real
+ ct->setRealIndex();
+
+ return add(ct);
+}
+
+// add a cost type to a mapping
+// this transfers ownership of the type!
+int TraceCostMapping::add(TraceCostType* ct)
+{
+ if (!ct) return TraceCost::InvalidIndex;
+
+ ct->setMapping(this);
+
+ if (ct->isReal()) {
+ if (_realCount >= TraceCost::MaxRealIndex) {
+ qDebug("WARNING: Maximum for real cost types reached (on adding '%s')",
+ ct->name().ascii());
+ return TraceCost::InvalidIndex;
+ }
+ _real[_realCount] = ct;
+ ct->setRealIndex(_realCount);
+ _realColor[_realCount] = Configuration::costTypeColor(ct);
+
+ _realCount++;
+ return _realCount-1;
+ }
+
+ if (_virtualCount >= TraceCost::MaxRealIndex) {
+ qDebug("WARNING: Maximum for virtual cost types reached (on adding '%s')",
+ ct->name().ascii());
+ return TraceCost::InvalidIndex;
+ }
+ _virtual[_virtualCount] = ct;
+ _virtualCount++;
+ return _virtualCount-1;
+}
+
+// we delete the type: t is invalid when returning true!
+bool TraceCostMapping::remove(TraceCostType* t)
+{
+ if (!t) return false;
+ if (t->mapping() != this) return false;
+
+ // don't delete real types
+ if (t->isReal()) return false;
+
+ int i;
+ for(i=0;i<_virtualCount;i++)
+ if (_virtual[i] == t) break;
+
+ // not found?
+ if (i == _virtualCount) return false;
+
+ // delete known type with same name
+ TraceCostType::remove(t->name());
+
+ // delete this type
+ _virtual[i] = 0;
+ delete t;
+ if (i+1 == _virtualCount) {
+ // we can reuse the last index
+ _virtualCount--;
+ }
+ return true;
+}
+
+
+TraceCostType* TraceCostMapping::realType(int t)
+{
+ if (t<0 || t>=_realCount) return 0;
+ return _real[t];
+}
+
+TraceCostType* TraceCostMapping::virtualType(int t)
+{
+ if (t<0 || t>=_virtualCount) return 0;
+ return _virtual[t];
+}
+
+
+TraceCostType* TraceCostMapping::type(int t)
+{
+ if (t<0) return 0;
+ if (t<_realCount) return _real[t];
+
+ t -= TraceCost::MaxRealIndex;
+ if (t<0) return 0;
+ if (t<_virtualCount) return _virtual[t];
+
+ return 0;
+}
+
+TraceCostType* TraceCostMapping::type(TQString name)
+{
+ for (int i=0;i<_realCount;i++)
+ if (_real[i] && (_real[i]->name() == name))
+ return _real[i];
+
+ for (int i=0;i<_virtualCount;i++)
+ if (_virtual[i] && (_virtual[i]->name() == name))
+ return _virtual[i];
+
+ return 0;
+}
+
+TraceCostType* TraceCostMapping::typeForLong(TQString name)
+{
+ for (int i=0;i<_realCount;i++)
+ if (_real[i] && (_real[i]->longName() == name))
+ return _real[i];
+
+ for (int i=0;i<_virtualCount;i++)
+ if (_virtual[i] && (_virtual[i]->longName() == name))
+ return _virtual[i];
+
+ return 0;
+}
+
+
+int TraceCostMapping::realIndex(TQString name)
+{
+ for (int i=0;i<_realCount;i++)
+ if (_real[i] && (_real[i]->name() == name))
+ return i;
+
+ return TraceCost::InvalidIndex;
+}
+
+int TraceCostMapping::index(TQString name)
+{
+ for (int i=0;i<_realCount;i++)
+ if (_real[i] && (_real[i]->name() == name))
+ return i;
+
+ for (int i=0;i<_virtualCount;i++)
+ if (_virtual[i] && (_virtual[i]->name() == name))
+ return TraceCost::MaxRealIndex + 1 + i;
+
+ return TraceCost::InvalidIndex;
+}
+
+int TraceCostMapping::addKnownVirtualTypes()
+{
+ int addCount = 0;
+ int addDiff, i;
+ int knownCount = TraceCostType::knownTypeCount();
+
+ while (1) {
+ addDiff = 0;
+ for (i=0; i<knownCount; i++) {
+ TraceCostType* t = TraceCostType::knownType(i);
+ if (t->isReal()) continue;
+ if (index(t->name()) != TraceCost::InvalidIndex) continue;
+ t->setMapping(this);
+ if (t->parseFormula()) {
+ addDiff++;
+ add(new TraceCostType(t->name(), t->longName(), t->formula()));
+ }
+ t->setMapping(0);
+ }
+ if (addDiff == 0) break;
+ addCount += addDiff;
+ }
+ return addCount;
+}
+
+
+//---------------------------------------------------
+// TraceSubMapping
+
+TraceSubMapping::TraceSubMapping(TraceCostMapping* mapping)
+{
+ _mapping = mapping;
+ clear();
+}
+
+void TraceSubMapping::clear()
+{
+ _count = 0;
+ _isIdentity = true;
+ _firstUnused = 0;
+ for(int i=0;i<TraceCost::MaxRealIndex;i++) {
+ _realIndex[i] = TraceCost::InvalidIndex;
+ _nextUnused[i] = i+1;
+ }
+}
+
+bool TraceSubMapping::append(TQString type, bool create)
+{
+ if (!_mapping) return false;
+ int index = create ? _mapping->addReal(type) : _mapping->realIndex(type);
+
+ return append(index);
+}
+
+bool TraceSubMapping::append(int type)
+{
+ if (!_mapping) return false;
+ if ((type<0) || (type >= _mapping->realCount())) return false;
+
+ if ( _count >= TraceCost::MaxRealIndex) return false;
+
+ _realIndex[_count] = type;
+
+ if (_isIdentity && (_count != type)) _isIdentity = false;
+ if (type == _firstUnused)
+ _firstUnused = _nextUnused[type];
+ for(int i=0;i<type;i++)
+ if (_nextUnused[i] == type)
+ _nextUnused[i]=_nextUnused[type];
+
+ _count++;
+ return true;
+}
+
+
+//---------------------------------------------------
+// TraceCallCost
+
+TraceCallCost::TraceCallCost()
+{
+ _callCount = 0;
+}
+
+TraceCallCost::~TraceCallCost()
+{}
+
+
+TQString TraceCallCost::costString(TraceCostMapping* m)
+{
+ return TQString("%1, Calls %2")
+ .arg(TraceCost::costString(m))
+ .arg(_callCount.pretty());
+}
+
+TQString TraceCallCost::prettyCallCount()
+{
+ return _callCount.pretty();
+}
+
+void TraceCallCost::clear()
+{
+ _callCount = 0;
+ TraceCost::clear();
+}
+
+SubCost TraceCallCost::callCount()
+{
+ if (_dirty) update();
+
+ return _callCount;
+}
+
+void TraceCallCost::addCallCount(SubCost c)
+{
+ _callCount += c;
+
+ invalidate();
+}
+
+
+//---------------------------------------------------
+// TraceInclusiveCost
+
+TraceInclusiveCost::TraceInclusiveCost()
+{}
+
+TraceInclusiveCost::~TraceInclusiveCost()
+{}
+
+TQString TraceInclusiveCost::costString(TraceCostMapping* m)
+{
+ return TQString("%1, Inclusive %2")
+ .arg(TraceCost::costString(m))
+ .arg(_inclusive.costString(m));
+}
+
+void TraceInclusiveCost::clear()
+{
+ _inclusive.clear();
+ TraceCost::clear();
+}
+
+TraceCost* TraceInclusiveCost::inclusive()
+{
+ if (_dirty) update();
+
+ return &_inclusive;
+}
+
+void TraceInclusiveCost::addInclusive(TraceCost* c)
+{
+ _inclusive.addCost(c);
+
+ invalidate();
+}
+
+
+//---------------------------------------------------
+// TraceListCost
+
+TraceListCost::TraceListCost()
+{
+ _lastDep = 0;
+}
+
+TraceListCost::~TraceListCost()
+{}
+
+void TraceListCost::addDep(TraceCost* dep)
+{
+#if TRACE_ASSERTIONS
+ if (_deps.findRef(dep)>=0) {
+ qDebug("addDep: %s already in list!",
+ dep->fullName().ascii());
+ return;
+ }
+#endif
+
+ _deps.append(dep);
+ _lastDep = dep;
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(), dep->fullName().ascii(),
+ _deps.count());
+#endif
+}
+
+TraceCost* TraceListCost::findDepFromPart(TracePart* part)
+{
+ if (_lastDep && _lastDep->part() == part)
+ return _lastDep;
+
+ TraceCost* dep;
+ for (dep = _deps.first(); dep; dep = _deps.next())
+ if (dep->part() == part) {
+ _lastDep = dep;
+ return dep;
+ }
+ return 0;
+}
+
+
+void TraceListCost::update()
+{
+ if (!_dirty) return;
+
+#if TRACE_DEBUG
+ qDebug("update %s (count %d)",
+ fullName().ascii(), _deps.count());
+#endif
+
+ clear();
+ TraceCost* item;
+ for (item = _deps.first(); item; item = _deps.next()) {
+ if (onlyActiveParts())
+ if (!item->part() || !item->part()->isActive()) continue;
+
+ addCost(item);
+ }
+
+ _dirty = false;
+
+#if TRACE_DEBUG
+ qDebug(" > %s", costString(0).ascii());
+#endif
+}
+
+
+
+//---------------------------------------------------
+// TraceJumpListCost
+
+TraceJumpListCost::TraceJumpListCost()
+{
+ _lastDep = 0;
+}
+
+TraceJumpListCost::~TraceJumpListCost()
+{}
+
+void TraceJumpListCost::addDep(TraceJumpCost* dep)
+{
+#if TRACE_ASSERTIONS
+ if (_deps.findRef(dep)>=0) {
+ qDebug("addDep: %s already in list!",
+ dep->fullName().ascii());
+ return;
+ }
+#endif
+
+ _deps.append(dep);
+ _lastDep = dep;
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(), dep->fullName().ascii(),
+ _deps.count());
+#endif
+}
+
+TraceJumpCost* TraceJumpListCost::findDepFromPart(TracePart* part)
+{
+ if (_lastDep && _lastDep->part() == part)
+ return _lastDep;
+
+ TraceJumpCost* dep;
+ for (dep = _deps.first(); dep; dep = _deps.next())
+ if (dep->part() == part) {
+ _lastDep = dep;
+ return dep;
+ }
+ return 0;
+}
+
+
+void TraceJumpListCost::update()
+{
+ if (!_dirty) return;
+
+#if TRACE_DEBUG
+ qDebug("update %s (count %d)",
+ fullName().ascii(), _deps.count());
+#endif
+
+ clear();
+ TraceJumpCost* item;
+ for (item = _deps.first(); item; item = _deps.next()) {
+ if (onlyActiveParts())
+ if (!item->part() || !item->part()->isActive()) continue;
+
+ addCost(item);
+ }
+
+ _dirty = false;
+
+#if TRACE_DEBUG
+ qDebug(" > %s", costString(0).ascii());
+#endif
+}
+
+
+
+//---------------------------------------------------
+// TraceCallListCost
+
+TraceCallListCost::TraceCallListCost()
+{
+ _lastDep = 0;
+}
+
+TraceCallListCost::~TraceCallListCost()
+{}
+
+void TraceCallListCost::addDep(TraceCallCost* dep)
+{
+#if TRACE_ASSERTIONS
+ if (_deps.findRef(dep)>=0) {
+ qDebug("addDep: %s already in list!",
+ dep->fullName().ascii());
+ return;
+ }
+#endif
+
+ _deps.append(dep);
+ _lastDep = dep;
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(), dep->fullName().ascii(),
+ _deps.count());
+#endif
+}
+
+TraceCallCost* TraceCallListCost::findDepFromPart(TracePart* part)
+{
+ if (_lastDep && _lastDep->part() == part)
+ return _lastDep;
+
+ TraceCallCost* dep;
+ for (dep = _deps.first(); dep; dep = _deps.next())
+ if (dep->part() == part) {
+ _lastDep = dep;
+ return dep;
+ }
+ return 0;
+}
+
+
+void TraceCallListCost::update()
+{
+ if (!_dirty) return;
+
+#if TRACE_DEBUG
+ qDebug("update %s (count %d)",
+ fullName().ascii(), _deps.count());
+#endif
+
+ /* Without dependent cost items, assume fixed costs,
+ * i.e. don't change cost */
+ if (_deps.count()>0) {
+ clear();
+ TraceCallCost* item;
+ for (item = _deps.first(); item; item = _deps.next()) {
+ if (onlyActiveParts())
+ if (!item->part() || !item->part()->isActive()) continue;
+
+ addCost(item);
+ addCallCount(item->callCount());
+ }
+ }
+
+ _dirty = false;
+
+#if TRACE_DEBUG
+ qDebug(" > %s", costString(0).ascii());
+#endif
+}
+
+
+//---------------------------------------------------
+// TraceInclusiveListCost
+
+TraceInclusiveListCost::TraceInclusiveListCost()
+{
+ _lastDep = 0;
+}
+
+TraceInclusiveListCost::~TraceInclusiveListCost()
+{}
+
+
+void TraceInclusiveListCost::addDep(TraceInclusiveCost* dep)
+{
+#if TRACE_ASSERTIONS
+ if (_deps.findRef(dep)>=0) {
+ qDebug("addDep: %s already in list!",
+ dep->fullName().ascii());
+ return;
+ }
+#endif
+
+ _deps.append(dep);
+ _lastDep = dep;
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(), dep->fullName().ascii(),
+ _deps.count());
+#endif
+}
+
+TraceInclusiveCost* TraceInclusiveListCost::findDepFromPart(TracePart* part)
+{
+ if (_lastDep && _lastDep->part() == part)
+ return _lastDep;
+
+ TraceInclusiveCost* dep;
+ for (dep = _deps.first(); dep; dep = _deps.next())
+ if (dep->part() == part) {
+ _lastDep = dep;
+ return dep;
+ }
+ return 0;
+}
+
+void TraceInclusiveListCost::update()
+{
+ if (!_dirty) return;
+
+#if TRACE_DEBUG
+ qDebug("update %s (count %d)",
+ fullName().ascii(), _deps.count());
+#endif
+
+ clear();
+ TraceInclusiveCost* item;
+ for (item = _deps.first(); item; item = _deps.next()) {
+ if (onlyActiveParts())
+ if (!item->part() || !item->part()->isActive()) continue;
+
+ addCost(item);
+ addInclusive(item->inclusive());
+ }
+
+ _dirty = false;
+
+#if TRACE_DEBUG
+ qDebug(" > %s", costString(0).ascii());
+#endif
+}
+
+
+
+//---------------------------------------------------
+// TracePartInstrJump
+
+TracePartInstrJump::TracePartInstrJump(TraceInstrJump* instrJump,
+ TracePartInstrJump* next)
+{
+ _dep = instrJump;
+ _next = next;
+}
+
+TracePartInstrJump::~TracePartInstrJump()
+{}
+
+
+//---------------------------------------------------
+// TracePartInstrCall
+
+TracePartInstrCall::TracePartInstrCall(TraceInstrCall* instrCall)
+{
+ _dep = instrCall;
+}
+
+TracePartInstrCall::~TracePartInstrCall()
+{}
+
+
+
+//---------------------------------------------------
+// TracePartInstr
+
+TracePartInstr::TracePartInstr(TraceInstr* instr)
+{
+ _dep = instr;
+}
+
+TracePartInstr::~TracePartInstr()
+{}
+
+
+
+//---------------------------------------------------
+// TracePartLineJump
+
+TracePartLineJump::TracePartLineJump(TraceLineJump* lineJump)
+{
+ _dep = lineJump;
+}
+
+TracePartLineJump::~TracePartLineJump()
+{}
+
+
+//---------------------------------------------------
+// TracePartLineCall
+
+TracePartLineCall::TracePartLineCall(TraceLineCall* lineCall)
+{
+ _dep = lineCall;
+}
+
+TracePartLineCall::~TracePartLineCall()
+{}
+
+
+//---------------------------------------------------
+// TracePartLine
+
+TracePartLine::TracePartLine(TraceLine* line)
+{
+ _dep = line;
+}
+
+TracePartLine::~TracePartLine()
+{}
+
+
+
+
+//---------------------------------------------------
+// TracePartCall
+
+TracePartCall::TracePartCall(TraceCall* call)
+{
+ _dep = call;
+
+ _firstFixCallCost = 0;
+}
+
+TracePartCall::~TracePartCall()
+{}
+
+bool TracePartCall::isRecursion()
+{
+ return call()->isRecursion();
+}
+
+void TracePartCall::update()
+{
+#if !USE_FIXCOST
+ TraceCallListCost::update();
+#else
+
+ if (!_dirty) return;
+
+#if TRACE_DEBUG
+ qDebug("update %s", fullName().ascii());
+#endif
+
+ /* Without dependent cost items, assume fixed costs,
+ * i.e. don't change cost */
+ if (_firstFixCallCost) {
+ clear();
+ FixCallCost* item;
+ for (item = _firstFixCallCost; item; item = item->nextCostOfPartCall())
+ item->addTo(this);
+ }
+
+ _dirty = false;
+
+#if TRACE_DEBUG
+ qDebug(" > %s", costString(0).ascii());
+#endif
+
+#endif // USE_FIXCOST
+}
+
+
+//---------------------------------------------------
+// TracePartFunction
+
+TracePartFunction::TracePartFunction(TraceFunction* function,
+ TracePartObject* partObject,
+ TracePartFile *partFile)
+{
+ _dep = function;
+ _partObject = partObject;
+ _partFile = partFile;
+ _partClass = 0;
+
+ _calledCount = 0;
+ _callingCount = 0;
+ _calledContexts = 0;
+ _callingContexts = 0;
+
+ _firstFixCost = 0;
+ _firstFixJump = 0;
+}
+
+TracePartFunction::~TracePartFunction()
+{}
+
+TQString TracePartFunction::prettyCalledCount()
+{
+ return _calledCount.pretty();
+}
+
+TQString TracePartFunction::prettyCallingCount()
+{
+ return _callingCount.pretty();
+}
+
+TQString TracePartFunction::costString(TraceCostMapping* m)
+{
+ update();
+
+ TQString res = TraceInclusiveCost::costString(m);
+ res += TQString(", called from %1: %2")
+ .arg(_calledContexts).arg(prettyCalledCount());
+ res += TQString(", calling from %1: %2")
+ .arg(_callingContexts).arg(prettyCallingCount());
+
+ return res;
+}
+
+
+void TracePartFunction::addPartInstr(TracePartInstr* ref)
+{
+#if TRACE_ASSERTIONS
+ if (_partInstr.findRef(ref)>=0) {
+ qDebug("TracePartFunction::addPartInstr: %s already in list!",
+ ref->name().ascii());
+ return;
+ }
+#endif
+
+ _partInstr.append(ref);
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(), ref->fullName().ascii(),
+ _partInstr.count());
+#endif
+}
+
+
+void TracePartFunction::addPartLine(TracePartLine* ref)
+{
+#if TRACE_ASSERTIONS
+ if (_partLines.findRef(ref)>=0) {
+ qDebug("TracePartFunction::addPartLine: %s already in list!",
+ ref->name().ascii());
+ return;
+ }
+#endif
+
+ _partLines.append(ref);
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(), ref->fullName().ascii(),
+ _partLines.count());
+#endif
+}
+
+
+void TracePartFunction::addPartCaller(TracePartCall* ref)
+{
+#if TRACE_ASSERTIONS
+ if (_partCallers.findRef(ref)>=0) {
+ qDebug("TracePartFunction::addPartCaller: %s already in list!",
+ ref->name().ascii());
+ return;
+ }
+#endif
+
+ _partCallers.append(ref);
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added Caller\n %s (now %d)",
+ fullName().ascii(), ref->fullName().ascii(),
+ _partCallers.count());
+#endif
+}
+
+
+void TracePartFunction::addPartCalling(TracePartCall* ref)
+{
+#if TRACE_ASSERTIONS
+ if (_partCallings.findRef(ref)>=0) {
+ qDebug("TracePartFunction::addPartCalling: %s already in list!",
+ ref->name().ascii());
+ return;
+ }
+#endif
+
+ _partCallings.append(ref);
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added Calling\n %s (now %d)",
+ fullName().ascii(), ref->fullName().ascii(),
+ _partCallings.count());
+#endif
+}
+
+SubCost TracePartFunction::calledCount()
+{
+ if (_dirty) update();
+
+ return _calledCount;
+}
+
+int TracePartFunction::calledContexts()
+{
+ if (_dirty) update();
+
+ return _calledContexts;
+}
+
+SubCost TracePartFunction::callingCount()
+{
+ if (_dirty) update();
+
+ return _callingCount;
+}
+
+
+int TracePartFunction::callingContexts()
+{
+ if (_dirty) update();
+
+ return _callingContexts;
+}
+
+
+void TracePartFunction::update()
+{
+ if (!_dirty) return;
+
+#if TRACE_DEBUG
+ qDebug("TracePartFunction::update %s (Callers %d, Callings %d, lines %d)",
+ name().ascii(), _partCallers.count(), _partCallings.count(),
+ _partLines.count());
+#endif
+
+ _calledCount = 0;
+ _callingCount = 0;
+ _calledContexts = 0;
+ _callingContexts = 0;
+
+ // calculate additional cost metrics
+ TracePartCall *caller, *calling;
+ for (caller=_partCallers.first();caller;caller=_partCallers.next()) {
+
+ // FIXME
+ if (caller->subCost(0)>0)
+ _calledContexts++;
+
+ SubCost c = caller->callCount();
+ if (c>0) {
+ _calledCount += c;
+ }
+ }
+ for (calling=_partCallings.first();calling;calling=_partCallings.next()) {
+ // FIXME
+ if (calling->subCost(0)>0)
+ _callingContexts++;
+
+ SubCost c = calling->callCount();
+ if (c>0) {
+ _callingCount += c;
+ }
+ }
+
+ // self cost
+#if !USE_FIXCOST
+ if (_partLines.count()>0) {
+ TraceCost::clear();
+
+ TracePartLine* line;
+ for (line = _partLines.first(); line; line = _partLines.next())
+ addCost(line);
+ }
+#else
+ if (_firstFixCost) {
+ TraceCost::clear();
+
+ FixCost* item;
+ for (item = _firstFixCost; item; item = item->nextCostOfPartFunction())
+ item->addTo(this);
+ }
+#endif
+
+
+ /* There are two possibilities to calculate inclusive cost:
+ * 1) sum of call costs to this function
+ * 2) sum of call costs from this function + self cost
+ *
+ * 1) is wrong if a function was called spontaneous, but also by a call.
+ * This eventually can happen with thread/process startup functions,
+ * and signal handlers.
+ *
+ * 2) is wrong with "skipped PLT" and the calltree skin, because
+ * cost of PLT is attributed to called function (?)
+ *
+ * For now, do 1) if there are callers, otherwise 2).
+ * Should this be fixed to take the maximum of 1) and 2) ?
+ */
+ _inclusive.clear();
+ if (_calledCount>0) {
+ // inclusive cost: if possible, use caller sums
+ for (caller=_partCallers.first();caller;caller=_partCallers.next()) {
+ // detect simple recursion (no cycle)
+ if (caller->isRecursion()) continue;
+
+ addInclusive(caller);
+ }
+ }
+ else {
+ // without caller info, use calling sum + line costs
+ for (calling=_partCallings.first();calling;calling=_partCallings.next()) {
+ // detect simple recursion (no cycle)
+ if (calling->isRecursion()) continue;
+
+ addInclusive(calling);
+ }
+ _dirty = false; // don't recurse!
+ addInclusive(this);
+ }
+
+ _dirty = false;
+
+#if TRACE_DEBUG
+ qDebug(" > %s", costString(0).ascii());
+#endif
+}
+
+
+
+//---------------------------------------------------
+// TracePartClass
+
+TracePartClass::TracePartClass(TraceClass* cls)
+{
+ _dep = cls;
+}
+
+TracePartClass::~TracePartClass()
+{}
+
+TQString TracePartClass::prettyName() const
+{
+ return TQString("%1 from %2")
+ .arg( _dep->name().isEmpty() ? TQString("(global)") : _dep->name())
+ .arg(part()->name());
+}
+
+//---------------------------------------------------
+// TracePartFile
+
+TracePartFile::TracePartFile(TraceFile* file)
+{
+ _dep = file;
+}
+
+TracePartFile::~TracePartFile()
+{}
+
+
+//---------------------------------------------------
+// TracePartObject
+
+TracePartObject::TracePartObject(TraceObject* object)
+{
+ _dep = object;
+}
+
+TracePartObject::~TracePartObject()
+{}
+
+
+
+
+//---------------------------------------------------
+// TraceInstrJump
+
+TraceInstrJump::TraceInstrJump(TraceInstr* instrFrom, TraceInstr* instrTo,
+ bool isCondJump)
+{
+ _first = 0;
+
+ _instrFrom = instrFrom;
+ _instrTo = instrTo;
+ _isCondJump = isCondJump;
+}
+
+TraceInstrJump::~TraceInstrJump()
+{
+ // we are the owner of the TracePartInstrJump's generated in our factory
+ TracePartInstrJump* item = _first, *next;
+ while(item) {
+ next = item->next();
+ delete item;
+ item = next;
+ }
+}
+
+TracePartInstrJump* TraceInstrJump::partInstrJump(TracePart* part)
+{
+ static TracePartInstrJump* item = 0;
+
+ // shortcut
+ if (item && (item->instrJump()==this) && (item->part() == part)) return item;
+
+ for(item = _first; item; item = item->next())
+ if (item->part() == part) break;
+
+ if (!item) {
+ item = new TracePartInstrJump(this, _first);
+ item->setPosition(part);
+ _first = item;
+ }
+ return item;
+}
+
+void TraceInstrJump::update()
+{
+ if (!_dirty) return;
+
+ clear();
+ TracePartInstrJump* item;
+ for (item = _first; item; item = item->next()) {
+ if (!item->part() || !item->part()->isActive()) continue;
+
+ addCost(item);
+ }
+ _dirty = false;
+
+#if TRACE_DEBUG
+ qDebug("updated %s", fullName().ascii());
+#endif
+
+#if TRACE_DEBUG
+ qDebug(" > %s", costString(0).ascii());
+#endif
+}
+
+TQString TraceInstrJump::name() const
+{
+ return TQString("jump at 0x%1 to 0x%2")
+ .arg(_instrFrom->addr().toString())
+ .arg(_instrTo->addr().toString());
+}
+
+
+//---------------------------------------------------
+// TraceInstrJumpList
+
+
+int TraceInstrJumpList::compareItems ( Item item1, Item item2 )
+{
+ TraceInstrJump* ij1 = (TraceInstrJump*) item1;
+ TraceInstrJump* ij2 = (TraceInstrJump*) item2;
+
+ Addr addr1Low = ij1->instrFrom()->addr();
+ Addr addr2Low = ij2->instrFrom()->addr();
+ Addr addr1High = ij1->instrTo()->addr();
+ Addr addr2High = ij2->instrTo()->addr();
+ Addr t;
+
+ if (addr1Low > addr1High) {
+ t = addr1Low;
+ addr1Low = addr1High;
+ addr1High = t;
+ }
+
+ if (addr2Low > addr2High) {
+ t = addr2Low;
+ addr2Low = addr2High;
+ addr2High = t;
+ }
+
+ if (_sortLow) {
+ // we sort according to smallest instruction address
+ if (addr1Low != addr2Low) return (addr1Low > addr2Low) ? 1:-1;
+ // jump ends come before jump starts
+ if (addr1Low == ij1->instrTo()->addr()) return -1;
+ if (addr2Low == ij2->instrTo()->addr()) return 1;
+ return (addr1High > addr2High) ? 1:-1;
+ }
+
+ // we sort according to highest instruction address
+ if (addr1High != addr2High) return (addr1High > addr2High) ? 1:-1;
+ // jump ends come before jump starts
+ if (addr1High == ij1->instrTo()->addr()) return -1;
+ if (addr2High == ij2->instrTo()->addr()) return 1;
+ return (addr1Low > addr2Low) ? 1:-1;
+}
+
+
+//---------------------------------------------------
+// TraceLineJump
+
+TraceLineJump::TraceLineJump(TraceLine* lineFrom, TraceLine* lineTo,
+ bool isCondJump)
+{
+ // we are the owner of TracePartLineJump's generated in our factory
+ _deps.setAutoDelete(true);
+
+ _lineFrom = lineFrom;
+ _lineTo = lineTo;
+ _isCondJump = isCondJump;
+}
+
+TraceLineJump::~TraceLineJump()
+{}
+
+
+TracePartLineJump* TraceLineJump::partLineJump(TracePart* part)
+{
+ TracePartLineJump* item = (TracePartLineJump*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartLineJump(this);
+ item->setPosition(part);
+ addDep(item);
+ }
+ return item;
+}
+
+
+TQString TraceLineJump::name() const
+{
+ return TQString("jump at %1 to %2")
+ .arg(_lineFrom->prettyName())
+ .arg(_lineTo->prettyName());
+}
+
+
+//---------------------------------------------------
+// TraceLineJumpList
+
+
+int TraceLineJumpList::compareItems ( Item item1, Item item2 )
+{
+ TraceLineJump* lj1 = (TraceLineJump*) item1;
+ TraceLineJump* lj2 = (TraceLineJump*) item2;
+
+ uint line1Low = lj1->lineFrom()->lineno();
+ uint line2Low = lj2->lineFrom()->lineno();
+ uint line1High = lj1->lineTo()->lineno();
+ uint line2High = lj2->lineTo()->lineno();
+ uint t;
+
+ if (line1Low > line1High) {
+ t = line1Low; line1Low = line1High; line1High = t;
+ }
+ if (line2Low > line2High) {
+ t = line2Low; line2Low = line2High; line2High = t;
+ }
+
+ if (_sortLow) {
+ // we sort according to smallest line number
+ if (line1Low != line2Low) return line1Low - line2Low;
+ // jump ends come before jump starts
+ if (line1Low == lj1->lineTo()->lineno()) return -1;
+ if (line2Low == lj2->lineTo()->lineno()) return 1;
+ return line1High - line2High;
+ }
+
+ // we sort according to highest line number
+ if (line1High != line2High) return line1High - line2High;
+ // jump ends come before jump starts
+ if (line1High == lj1->lineTo()->lineno()) return -1;
+ if (line2High == lj2->lineTo()->lineno()) return 1;
+ return line1Low - line2Low;
+}
+
+
+//---------------------------------------------------
+// TraceInstrCall
+
+TraceInstrCall::TraceInstrCall(TraceCall* call, TraceInstr* instr)
+{
+ // we are the owner of TracePartInstrCall's generated in our factory
+ _deps.setAutoDelete(true);
+
+ _call = call;
+ _instr = instr;
+}
+
+TraceInstrCall::~TraceInstrCall()
+{}
+
+
+TracePartInstrCall* TraceInstrCall::partInstrCall(TracePart* part,
+ TracePartCall*)
+{
+ TracePartInstrCall* item = (TracePartInstrCall*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartInstrCall(this);
+ item->setPosition(part);
+ addDep(item);
+ // instruction calls are not registered in function calls
+ // as together with line calls calls are duplicated
+ //partCall->addDep(item);
+ }
+ return item;
+}
+
+
+TQString TraceInstrCall::name() const
+{
+ return TQString("%1 at %2").arg(_call->name()).arg(_instr->name());
+}
+
+
+//---------------------------------------------------
+// TraceLineCall
+
+TraceLineCall::TraceLineCall(TraceCall* call, TraceLine* line)
+{
+ // we are the owner of TracePartLineCall's generated in our factory
+ _deps.setAutoDelete(true);
+
+ _call = call;
+ _line = line;
+}
+
+TraceLineCall::~TraceLineCall()
+{}
+
+
+TracePartLineCall* TraceLineCall::partLineCall(TracePart* part,
+ TracePartCall* partCall)
+{
+ TracePartLineCall* item = (TracePartLineCall*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartLineCall(this);
+ item->setPosition(part);
+ addDep(item);
+ partCall->addDep(item);
+ }
+ return item;
+}
+
+
+TQString TraceLineCall::name() const
+{
+ return TQString("%1 at %2").arg(_call->name()).arg(_line->name());
+}
+
+
+//---------------------------------------------------
+// TraceCall
+
+TraceCall::TraceCall(TraceFunction* caller, TraceFunction* called)
+{
+ // we are the owner of all items generated in our factory
+ _deps.setAutoDelete(true);
+ _lineCalls.setAutoDelete(true);
+
+ _caller = caller;
+ _called = called;
+}
+
+
+TraceCall::~TraceCall()
+{}
+
+TracePartCall* TraceCall::partCall(TracePart* part,
+ TracePartFunction* partCaller,
+ TracePartFunction* partCalling)
+{
+ TracePartCall* item = (TracePartCall*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartCall(this);
+ item->setPosition(part);
+ addDep(item);
+ partCaller->addPartCalling(item);
+ partCalling->addPartCaller(item);
+ }
+ return item;
+}
+
+TraceInstrCall* TraceCall::instrCall(TraceInstr* i)
+{
+ TraceInstrCall* icall;
+ for (icall=_instrCalls.first();icall;icall=_instrCalls.next())
+ if (icall->instr() == i)
+ break;
+
+ if (!icall) {
+ icall = new TraceInstrCall(this, i);
+
+ _instrCalls.append(icall);
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("Created %s [TraceCall::instrCall]", icall->fullName().ascii());
+#endif
+ i->addInstrCall(icall);
+ }
+ return icall;
+}
+
+
+TraceLineCall* TraceCall::lineCall(TraceLine* l)
+{
+ TraceLineCall* lcall;
+ for (lcall=_lineCalls.first();lcall;lcall=_lineCalls.next())
+ if (lcall->line() == l)
+ break;
+
+ if (!lcall) {
+ lcall = new TraceLineCall(this, l);
+
+ _lineCalls.append(lcall);
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("Created %s [TraceCall::lineCall]", lcall->fullName().ascii());
+#endif
+ l->addLineCall(lcall);
+ }
+ return lcall;
+}
+
+
+void TraceCall::invalidateDynamicCost()
+{
+ TraceLineCall* lc;
+ for (lc=_lineCalls.first();lc;lc=_lineCalls.next())
+ lc->invalidate();
+
+ TraceInstrCall* ic;
+ for (ic=_instrCalls.first();ic;ic=_instrCalls.next())
+ ic->invalidate();
+
+ invalidate();
+}
+
+
+TQString TraceCall::name() const
+{
+ return TQString("%1 => %2")
+ .arg(_caller->name())
+ .arg(_called->name());
+}
+
+int TraceCall::inCycle()
+{
+ if (!_caller || !_called) return 0;
+ if (!_caller->cycle()) return 0;
+ if (_caller == _caller->cycle()) return 0;
+ if (_caller->cycle() != _called->cycle()) return 0;
+
+ return _caller->cycle()->cycleNo();
+}
+
+void TraceCall::update()
+{
+ if (!_dirty) return;
+
+ // special handling for cycles
+ if (_caller && _caller->cycle() && _caller==_caller->cycle()) {
+
+ // we have no part calls: use inclusive cost of called function
+ clear();
+ if (_called)
+ addCost(_called->inclusive());
+ _dirty = false;
+ return;
+ }
+
+ TraceCallListCost::update();
+}
+
+TraceFunction* TraceCall::caller(bool /*skipCycle*/) const
+{
+ return _caller;
+}
+
+TraceFunction* TraceCall::called(bool skipCycle) const
+{
+ if (!skipCycle && _called) {
+ // if this is a call to a cycle member from outside of the cycle,
+ // fake it to be a call to the whole cycle
+ if (_called->cycle() && _caller &&
+ (_caller->cycle() != _called->cycle()))
+ return _called->cycle();
+ }
+
+ return _called;
+}
+
+TQString TraceCall::callerName(bool skipCycle) const
+{
+ if (!_caller) return i18n("(no caller)");
+
+ if (!skipCycle) {
+ // if this call goes into a cycle, add the entry function
+ TraceFunctionCycle* c = _called->cycle();
+ if (c && _caller && (_caller->cycle() != c)) {
+ TQString via = _called->prettyName();
+ return i18n("%1 via %2").arg(_caller->prettyName()).arg(via);
+ }
+ }
+
+ return _caller->prettyName();
+}
+
+TQString TraceCall::calledName(bool skipCycle) const
+{
+ if (!_called) return i18n("(no callee)");
+
+ if (!skipCycle) {
+ // if this call goes into a cycle, add the entry function
+ TraceFunctionCycle* c = _called->cycle();
+ if (c && _caller && (_caller->cycle() != c)) {
+ // HACK to get rid of cycle postfix...
+ _called->setCycle(0);
+ TQString via = _called->prettyName();
+ _called->setCycle(c);
+ return i18n("%1 via %2").arg(c->name()).arg(via);
+ }
+ }
+ return _called->prettyName();
+}
+
+
+//---------------------------------------------------
+// TraceInstr
+
+TraceInstr::TraceInstr()
+{
+ // we are the owner of TracePartInstr's generated in our factory
+ _deps.setAutoDelete(true);
+ _instrJumps.setAutoDelete(true);
+
+ _addr = 0;
+ _line = 0;
+ _function = 0;
+}
+
+TraceInstr::~TraceInstr()
+{}
+
+bool TraceInstr::hasCost(TraceCostType* ct)
+{
+ bool res = subCost(ct) > 0;
+ if (!res) {
+ TraceInstrCall* ic;
+ for(ic=_instrCalls.first();ic;ic=_instrCalls.next())
+ if (ic->subCost(ct) > 0) break;
+ res = (ic != 0);
+ if (!res) {
+ TraceInstrJump* ij;
+ for(ij=_instrJumps.first();ij;ij=_instrJumps.next())
+ if (ij->executedCount() > 0) break;
+ res = (ij != 0);
+ }
+ }
+
+ return res;
+}
+
+TracePartInstr* TraceInstr::partInstr(TracePart* part,
+ TracePartFunction* partFunction)
+{
+ TracePartInstr* item = (TracePartInstr*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartInstr(this);
+ item->setPosition(part);
+ addDep(item);
+ //part->addDep(item);
+ partFunction->addPartInstr(item);
+ }
+ return item;
+}
+
+TraceInstrJump* TraceInstr::instrJump(TraceInstr* to, bool isJmpCond)
+{
+ TraceInstrJump* jump;
+ for (jump=_instrJumps.first();jump;jump=_instrJumps.next())
+ if (jump->instrTo() == to)
+ break;
+
+ if (!jump) {
+ jump = new TraceInstrJump(this, to, isJmpCond);
+
+ _instrJumps.append(jump);
+ }
+ return jump;
+}
+
+
+
+void TraceInstr::addInstrCall(TraceInstrCall* instrCall)
+{
+#if TRACE_ASSERTIONS
+ if (_instrCalls.findRef(instrCall)>=0) return;
+
+ if (instrCall->instr() != this) {
+ qDebug("Can't add instruction call to another instruction!");
+ return;
+ }
+#endif
+
+ _instrCalls.append(instrCall);
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(),
+ instrCall->fullName().ascii(), _instrCalls.count());
+#endif
+}
+
+
+TQString TraceInstr::name() const
+{
+ return TQString("0x%1").arg(_addr.toString());
+}
+
+TQString TraceInstr::prettyName() const
+{
+ return TQString("0x%1").arg(_addr.toString());
+}
+
+
+//---------------------------------------------------
+// TraceLine
+
+TraceLine::TraceLine()
+{
+ // we are the owner of TracePartLine's generated in our factory
+ _deps.setAutoDelete(true);
+ _lineJumps.setAutoDelete(true);
+
+ _lineno = 0;
+ _sourceFile = 0;
+}
+
+TraceLine::~TraceLine()
+{}
+
+bool TraceLine::hasCost(TraceCostType* ct)
+{
+ bool res = subCost(ct) > 0;
+ if (!res) {
+ TraceLineCall* lc;
+ for(lc=_lineCalls.first();lc;lc=_lineCalls.next())
+ if (lc->subCost(ct) > 0) break;
+ res = (lc != 0);
+ if (!res) {
+ TraceLineJump* lj;
+ for(lj=_lineJumps.first();lj;lj=_lineJumps.next())
+ if (lj->executedCount() > 0) break;
+ res = (lj != 0);
+ }
+ }
+
+ return res;
+}
+
+TracePartLine* TraceLine::partLine(TracePart* part,
+ TracePartFunction* partFunction)
+{
+ TracePartLine* item = (TracePartLine*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartLine(this);
+ item->setPosition(part);
+ addDep(item);
+#if !USE_FIXCOST
+ part->addDep(item);
+#endif
+ partFunction->addPartLine(item);
+ }
+ return item;
+}
+
+TraceLineJump* TraceLine::lineJump(TraceLine* to, bool isJmpCond)
+{
+ TraceLineJump* jump;
+ for (jump=_lineJumps.first();jump;jump=_lineJumps.next())
+ if (jump->lineTo() == to)
+ break;
+
+ if (!jump) {
+ jump = new TraceLineJump(this, to, isJmpCond);
+
+ _lineJumps.append(jump);
+ }
+ return jump;
+}
+
+
+void TraceLine::addLineCall(TraceLineCall* lineCall)
+{
+#if TRACE_ASSERTIONS
+ if (_lineCalls.findRef(lineCall)>=0) return;
+
+ if (lineCall->line() != this) {
+ qDebug("Can't add line call to another line!");
+ return;
+ }
+#endif
+
+ TraceFunction* caller = lineCall->call()->caller();
+ TraceFunction* function = _sourceFile->function();
+ if (caller != function) {
+ // We regard 2 functions as the same if they have
+ // same class, name, object
+ if ((caller->cls() != function->cls()) ||
+ (caller->name() != function->name()) ||
+ (caller->object() != function->object())) {
+
+ qDebug("ERROR: Adding line call, line %d\n of %s to\n %s ?!",
+ lineCall->line()->lineno(),
+ caller->info().ascii(), function->info().ascii());
+ }
+ }
+
+ _lineCalls.append(lineCall);
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(),
+ lineCall->fullName().ascii(), _lineCalls.count());
+#endif
+}
+
+
+TQString TraceLine::name() const
+{
+ TQString fileShortName = _sourceFile->file()->shortName();
+ if (fileShortName.isEmpty())
+ return i18n("(unknown)");
+
+ return TQString("%1:%2")
+ .arg(fileShortName).arg(_lineno);
+}
+
+TQString TraceLine::prettyName() const
+{
+ return TQString("%1 [%2]")
+ .arg(name()).arg(_sourceFile->function()->prettyName());
+}
+
+//---------------------------------------------------
+// TraceCostItem
+
+TraceCostItem::TraceCostItem()
+{
+}
+
+TraceCostItem::~TraceCostItem()
+{}
+
+
+//---------------------------------------------------
+// TraceFunctionSource
+
+TraceFunctionSource::TraceFunctionSource(TraceFunction* function,
+ TraceFile* file)
+{
+ _file = file;
+ _function = function;
+
+ // the function is dependent from our cost sum
+ _dep = _function;
+
+ _lineMap = 0;
+ _lineMapFilled = false;
+ _line0 = 0;
+}
+
+TraceFunctionSource::~TraceFunctionSource()
+{
+ if (_lineMap) delete _lineMap;
+ if (_line0) delete _line0;
+}
+
+TQString TraceFunctionSource::name() const
+{
+ return TQString("%1 for %2").arg(_file->name()).arg(_function->name());
+}
+
+uint TraceFunctionSource::firstLineno()
+{
+ // lazy generate the map if not done up to now
+ TraceLineMap* map = lineMap();
+ // ignore line 0 here
+ if (!map || map->count() == 0) return 0;
+ TraceLineMap::Iterator it = map->begin();
+ return (*it).lineno();
+}
+
+uint TraceFunctionSource::lastLineno()
+{
+ // lazy generate the map if not done up to now
+ TraceLineMap* map = lineMap();
+ // ignore line 0 here
+ if (!map || map->count() == 0) return 0;
+ TraceLineMap::Iterator it = map->end();
+ --it;
+ return (*it).lineno();
+}
+
+/* factory */
+TraceLine* TraceFunctionSource::line(uint lineno, bool createNew)
+{
+ if (lineno == 0) {
+ if (!_line0) {
+ if (!createNew) return 0;
+ _line0 = new TraceLine;
+ _line0->setSourceFile(this);
+ _line0->setLineno(0);
+ }
+ return _line0;
+ }
+
+ if (!createNew) {
+ if (!_lineMap) return 0;
+ TraceLineMap::Iterator it = _lineMap->find(lineno);
+ if (it == _lineMap->end()) return 0;
+ return &(it.data());
+ }
+
+ if (!_lineMap) _lineMap = new TraceLineMap;
+
+ TraceLine& l = (*_lineMap)[lineno];
+ if (!l.isValid()) {
+ l.setSourceFile(this);
+ l.setLineno(lineno);
+
+#if TRACE_DEBUG
+ qDebug("Created %s [TraceFunctionSource::line]",
+ l.fullName().ascii());
+#endif
+ }
+ return &l;
+}
+
+void TraceFunctionSource::update()
+{
+ if (!_dirty) return;
+
+ clear();
+
+ // no need to create lineMap if not already created
+ if (_lineMap) {
+ TraceLineMap::Iterator lit;
+ for ( lit = _lineMap->begin();
+ lit != _lineMap->end(); ++lit )
+ addCost( &(*lit) );
+ }
+
+ _dirty = false;
+}
+
+void TraceFunctionSource::invalidateDynamicCost()
+{
+ // no need to create lineMap if not already created
+ if (_lineMap) {
+ TraceLineMap::Iterator lit;
+ for ( lit = _lineMap->begin();
+ lit != _lineMap->end(); ++lit )
+ (*lit).invalidate();
+ }
+
+ invalidate();
+}
+
+TraceLineMap* TraceFunctionSource::lineMap()
+{
+#if USE_FIXCOST
+
+ if (_lineMapFilled) return _lineMap;
+ _lineMapFilled = true;
+ if (!_lineMap)
+ _lineMap = new TraceLineMap;
+
+ TraceLine* l = 0;
+ TracePartLine* pl = 0;
+ TraceLineCall* lc = 0;
+ TracePartLineCall* plc = 0;
+
+ /* go over all part objects for this function, and
+ * - build TraceLines (the line map) using FixCost objects
+ * - build TraceJumpLines using FixJump objects
+ */
+ TraceInclusiveCostList pfList = _function->deps();
+ TracePartFunction* pf = (TracePartFunction*) pfList.first();
+ for(; pf; pf = (TracePartFunction*) pfList.next()) {
+
+ if (0) qDebug("PartFunction %s:%d",
+ pf->function()->name().ascii(), pf->part()->partNumber());
+
+ FixCost* fc = pf->firstFixCost();
+ for(; fc; fc = fc->nextCostOfPartFunction()) {
+ if (fc->line() == 0) continue;
+ if (fc->functionSource() != this) continue;
+
+ if (!l || l->lineno() != fc->line()) {
+ l = &(*_lineMap)[fc->line()];
+ if (!l->isValid()) {
+ l->setSourceFile(this);
+ l->setLineno(fc->line());
+ }
+ pl = 0;
+ }
+ if (!pl || pl->part() != fc->part())
+ pl = l->partLine(fc->part(), pf);
+ fc->addTo(pl);
+ }
+
+ TraceLine* to = 0;
+ TraceLineJump* lj;
+ TracePartLineJump* plj;
+ FixJump* fj = pf->firstFixJump();
+ for(; fj; fj = fj->nextJumpOfPartFunction()) {
+ if (fj->line() == 0) continue;
+ if (fj->source() != this) continue;
+ if (!fj->targetSource()) {
+ // be robust against buggy loaders
+ continue;
+ }
+
+ // don't display jumps to same or following line
+ if ((fj->line() == fj->targetLine()) ||
+ (fj->line()+1 == fj->targetLine())) continue;
+
+ if (!l || l->lineno() != fj->line()) {
+ l = &(*_lineMap)[fj->line()];
+ if (!l->isValid()) {
+ l->setSourceFile(this);
+ l->setLineno(fj->line());
+ }
+ }
+
+ to = fj->targetSource()->line(fj->targetLine(), true);
+
+ lj = l->lineJump(to, fj->isCondJump());
+ plj = lj->partLineJump(fj->part());
+
+ fj->addTo(plj);
+ }
+
+
+ TracePartCallList pcList = pf->partCallings();
+ TracePartCall* pc = pcList.first();
+ for(; pc; pc = pcList.next()) {
+
+ if (0) qDebug("PartCall %s:%d",
+ pc->call()->name().ascii(),
+ pf->part()->partNumber());
+
+ FixCallCost* fcc = pc->firstFixCallCost();
+ for(; fcc; fcc = fcc->nextCostOfPartCall()) {
+ if (fcc->line() == 0) continue;
+ if (fcc->functionSource() != this) continue;
+
+ if (!l || l->lineno() != fcc->line()) {
+ l = &(*_lineMap)[fcc->line()];
+ if (!l->isValid()) {
+ l->setSourceFile(this);
+ l->setLineno(fcc->line());
+ }
+ }
+ if (!lc || lc->call() != pc->call() || lc->line() != l) {
+ lc = pc->call()->lineCall(l);
+ plc = 0;
+ }
+ if (!plc || plc->part() != fcc->part())
+ plc = lc->partLineCall(fcc->part(), pc);
+
+ fcc->addTo(plc);
+ if (0) qDebug("Add FixCallCost %s:%d/0x%s, CallCount %s",
+ fcc->functionSource()->file()->shortName().ascii(),
+ fcc->line(), fcc->addr().toString().ascii(),
+ fcc->callCount().pretty().ascii());
+ }
+ }
+ }
+
+#endif
+
+ return _lineMap;
+}
+
+
+
+//---------------------------------------------------
+// TraceAssoziation
+
+TraceAssoziation::TraceAssoziation()
+{
+ _function = 0;
+ _valid = false;
+}
+
+TraceAssoziation::~TraceAssoziation()
+{
+ // don't delete from TraceFunction
+ if (_function) _function->removeAssoziation(this);
+}
+
+bool TraceAssoziation::isAssoziated()
+{
+ if (!_function) return false;
+
+ return _function->assoziation(rtti())==this;
+}
+
+bool TraceAssoziation::setFunction(TraceFunction* f)
+{
+ if (_function == f)
+ return isAssoziated();
+
+ if (_function) {
+ // don't delete ourself
+ _function->removeAssoziation(this);
+ }
+
+ _function = f;
+ if (f && f->assoziation(rtti()) == 0) {
+ f->addAssoziation(this);
+ return true;
+ }
+ return false;
+}
+
+void TraceAssoziation::clear(TraceData* d, int rtti)
+{
+ TraceFunctionMap::Iterator it;
+ for ( it = d->functionMap().begin();
+ it != d->functionMap().end(); ++it )
+ (*it).removeAssoziation(rtti);
+}
+
+void TraceAssoziation::invalidate(TraceData* d, int rtti)
+{
+ TraceFunctionMap::Iterator it;
+ for ( it = d->functionMap().begin();
+ it != d->functionMap().end(); ++it )
+ (*it).invalidateAssoziation(rtti);
+}
+
+
+//---------------------------------------------------
+// TraceFunction
+
+TraceFunction::TraceFunction()
+{
+ _object = 0;
+ _file = 0;
+ _cls = 0;
+ _cycle = 0;
+
+ // we are the owner of items generated in our factory
+ _deps.setAutoDelete(true);
+ _callings.setAutoDelete(true);
+ _sourceFiles.setAutoDelete(true);
+
+ _calledCount = 0;
+ _callingCount = 0;
+ _calledContexts = 0;
+ _callingContexts = 0;
+
+ _instrMap = 0;
+ _instrMapFilled = false;
+}
+
+
+TraceFunction::~TraceFunction()
+{
+ _assoziations.setAutoDelete(true);
+ _assoziations.clear();
+
+ if (_instrMap) delete _instrMap;
+}
+
+// no unique check is done!
+void TraceFunction::addAssoziation(TraceAssoziation* a)
+{
+ if (!a) return;
+ _assoziations.append(a);
+}
+
+void TraceFunction::removeAssoziation(TraceAssoziation* a)
+{
+ _assoziations.removeRef(a);
+}
+
+void TraceFunction::removeAssoziation(int rtti, bool reallyDelete)
+{
+ if (rtti==0) {
+ if (reallyDelete)
+ _assoziations.setAutoDelete(true);
+ _assoziations.clear();
+ _assoziations.setAutoDelete(false);
+ return;
+ }
+
+ TraceAssoziation* a;
+ for (a=_assoziations.first();a;a=_assoziations.next())
+ if (a->rtti() == rtti) {
+ if (reallyDelete) delete a;
+ _assoziations.remove();
+ return;
+ }
+}
+
+void TraceFunction::invalidateAssoziation(int rtti)
+{
+ TraceAssoziation* a;
+ for (a=_assoziations.first();a;a=_assoziations.next())
+ if ((rtti==0) || (a->rtti() == rtti))
+ a->invalidate();
+}
+
+TraceAssoziation* TraceFunction::assoziation(int rtti)
+{
+ TraceAssoziation* a;
+ for (a=_assoziations.first();a;a=_assoziations.next())
+ if (a->rtti() == rtti)
+ return a;
+ return 0;
+}
+
+
+// helper for prettyName
+bool TraceFunction::isUniquePrefix(TQString prefix) const
+{
+ TraceFunctionMap::ConstIterator it, it2;
+ it = it2 = _myMapIterator;
+ if (it != data()->functionBeginIterator()) {
+ it2--;
+ if ((*it2).name().startsWith(prefix)) return false;
+ }
+ if (it != data()->functionEndIterator()) {
+ it++;
+ if ((*it).name().startsWith(prefix)) return false;
+ }
+ return true;
+}
+
+
+TQString TraceFunction::prettyName() const
+{
+ TQString res = _name;
+
+ if (_name.isEmpty())
+ return i18n("(unknown)");
+
+ int p = _name.find('(');
+ if (p>0) {
+ // handle C++ "operator()" correct
+ if ((_name[p+1] == ')') && (_name[p+2] == '(')) p+=2;
+
+ // we have a C++ symbol with argument types:
+ // check for unique function name (inclusive '(' !)
+ if (isUniquePrefix(_name.left(p+1)))
+ res = _name.left(p);
+ }
+
+ // cycle members
+ if (_cycle) {
+ if (_cycle != this)
+ res = TQString("%1 <cycle %2>").arg(res).arg(_cycle->cycleNo());
+ else
+ res = TQString("<cycle %2>").arg(_cycle->cycleNo());
+ }
+
+
+ return res;
+}
+
+/*
+ * Returns location string: ELF object and source file(s).
+ */
+TQString TraceFunction::location(int maxFiles) const
+{
+ TQString loc;
+
+ // add object file with address range
+ if (_object) {
+ loc = _object->shortName();
+
+#if 0
+ uint from = firstAddress();
+ uint to = lastAddress();
+ if (from != 0 && to != 0) {
+ if (from == to)
+ loc += TQString(" (0x%1)").arg(to, 0, 16);
+ else
+ loc += TQString(" (0x%1-0x%2)").arg(from, 0, 16).arg(to, 0, 16);
+ }
+#endif
+ }
+
+ // add all source files
+ int filesAdded = 0;
+ TraceFunctionSourceList list = _sourceFiles;
+ TraceFunctionSource* sourceFile = list.first();
+ for (;sourceFile;sourceFile=list.next()) {
+ if (!sourceFile->file() ||
+ (sourceFile->file()->name().isEmpty()) )
+ continue;
+
+ if (!loc.isEmpty())
+ loc += (filesAdded>0) ? ", " : ": ";
+ filesAdded++;
+
+ if ((maxFiles>0) && (filesAdded>maxFiles)) {
+ loc += "...";
+ break;
+ }
+ loc += sourceFile->file()->shortName();
+
+#if 0
+ from = sourceFile->firstLineno();
+ to = sourceFile->lastLineno();
+ if (from != 0 && to != 0) {
+ if (from == to)
+ loc += TQString(" (%1)").arg(to);
+ else
+ loc += TQString(" (%1-%2)").arg(from).arg(to);
+ }
+#endif
+ }
+
+ return loc;
+}
+
+// pretty version is allowed to mangle the string...
+TQString TraceFunction::prettyLocation(int maxFiles) const
+{
+ TQString l = location(maxFiles);
+ if (l.isEmpty()) return i18n("(unknown)");
+
+ return l;
+}
+
+void TraceFunction::addPrettyLocation(TQString& s, int maxFiles) const
+{
+ TQString l = location(maxFiles);
+ if (l.isEmpty()) return;
+
+ s += TQString(" (%1)").arg(l);
+}
+
+TQString TraceFunction::prettyNameWithLocation(int maxFiles) const
+{
+ TQString l = location(maxFiles);
+ if (l.isEmpty()) return prettyName();
+
+ return TQString("%1 (%2)").arg(prettyName()).arg(l);
+}
+
+TQString TraceFunction::info() const
+{
+ TQString l = location();
+ if (l.isEmpty())
+ return TQString("Function %1").arg(name());
+
+ return TQString("Function %1 (location %2)")
+ .arg(name()).arg(l);
+}
+
+
+Addr TraceFunction::firstAddress() const
+{
+ // ignore address 0 here
+ if (!_instrMap || _instrMap->count() == 0) return 0;
+ TraceInstrMap::ConstIterator it = _instrMap->begin();
+ return (*it).addr();
+}
+
+Addr TraceFunction::lastAddress() const
+{
+ // ignore address 0 here
+ if (!_instrMap || _instrMap->count() == 0) return 0;
+ TraceInstrMap::ConstIterator it = _instrMap->end();
+ --it;
+ return (*it).addr();
+}
+
+/* factory */
+TraceInstr* TraceFunction::instr(Addr addr, bool createNew)
+{
+ // address 0 not allowed
+ if (addr == Addr(0)) return 0;
+
+ if (!createNew) {
+ if (!_instrMap) return 0;
+ TraceInstrMap::Iterator it = _instrMap->find(addr);
+ if (it == _instrMap->end())
+ return 0;
+ return &(it.data());
+ }
+
+ if (!_instrMap) _instrMap = new TraceInstrMap;
+
+ TraceInstr& i = (*_instrMap)[addr];
+ if (!i.isValid()) {
+ i.setAddr(addr);
+ i.setFunction(this);
+
+#if TRACE_DEBUG
+ qDebug("Created %s [TraceFunction::instr]",
+ i.fullName().ascii());
+#endif
+ }
+ return &i;
+}
+
+void TraceFunction::addCaller(TraceCall* caller)
+{
+#if TRACE_ASSERTIONS
+ if (caller->called() != this) {
+ qDebug("Can't add call to another line!\n");
+ return;
+ }
+
+ if (_callers.findRef(caller)>=0) return;
+#endif
+
+ _callers.append(caller);
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added Caller\n %s (now %d)",
+ fullName().ascii(), caller->fullName().ascii(), _callers.count());
+#endif
+}
+
+
+
+TraceCall* TraceFunction::calling(TraceFunction* called)
+{
+ TraceCallMap::Iterator it = _callingMap.find(called);
+ TraceCall* calling = (it == _callingMap.end()) ? 0 : it.data();
+
+ if (!calling) {
+ calling = new TraceCall(this, called);
+
+ _callingMap.insert(called, calling);
+ _callings.append(calling);
+
+ // we have to invalidate ourself so invalidations from item propagate up
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("Created %s [TraceFunction::calling]", calling->fullName().ascii());
+#endif
+ called->addCaller(calling);
+ }
+ return calling;
+}
+
+TraceFunctionSource* TraceFunction::sourceFile(TraceFile* file,
+ bool createNew)
+{
+ if (!file) file = _file;
+
+ TraceFunctionSource* sourceFile = _sourceFiles.first();
+ for (;sourceFile;sourceFile=_sourceFiles.next())
+ if (sourceFile->file() == file) break;
+
+ if (!sourceFile && createNew) {
+ sourceFile = new TraceFunctionSource(this, file);
+
+ _sourceFiles.append(sourceFile);
+
+ // we have to invalidate ourself so invalidations from item propagate up
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("Created SourceFile %s [TraceFunction::line]",
+ file->name().ascii());
+#endif
+ file->addSourceFile(sourceFile);
+ }
+ return sourceFile;
+}
+
+TraceLine* TraceFunction::line(TraceFile* file, uint lineno,
+ bool createNew)
+{
+ Q_ASSERT(file!=0);
+
+ TraceFunctionSource* sf = sourceFile(file, createNew);
+ if (!sf)
+ return 0;
+ else
+ return sf->line(lineno, createNew);
+}
+
+
+TracePartFunction* TraceFunction::partFunction(TracePart* part,
+ TracePartFile* partFile,
+ TracePartObject* partObject)
+{
+ TracePartFunction* item = (TracePartFunction*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartFunction(this, partObject, partFile);
+ item->setPosition(part);
+ addDep(item);
+#if USE_FIXCOST
+ part->addDep(item);
+#endif
+
+ if (_cls) {
+ TracePartClass* partClass = _cls->partClass(part);
+ partClass->addPartFunction(item);
+ item->setPartClass(partClass);
+ }
+
+ partFile->addPartFunction(item);
+ if (partObject)
+ partObject->addPartFunction(item);
+ }
+ else if (item->partObject()==0 && partObject) {
+ item->setPartObject(partObject);
+ partObject->addPartFunction(item);
+ }
+
+ return item;
+}
+
+
+SubCost TraceFunction::calledCount()
+{
+ if (_dirty) update();
+
+ return _calledCount;
+}
+
+int TraceFunction::calledContexts()
+{
+ if (_dirty) update();
+
+ return _calledContexts;
+}
+
+SubCost TraceFunction::callingCount()
+{
+ if (_dirty) update();
+
+ return _callingCount;
+}
+
+int TraceFunction::callingContexts()
+{
+ if (_dirty) update();
+
+ return _callingContexts;
+}
+
+TQString TraceFunction::prettyCalledCount()
+{
+ return _calledCount.pretty();
+}
+
+TQString TraceFunction::prettyCallingCount()
+{
+ return _callingCount.pretty();
+}
+
+
+TraceCallList TraceFunction::callers(bool skipCycle) const
+{
+ if (skipCycle) return _callers;
+
+ // fake the callers for cycle members
+ if (_cycle && (_cycle != this)) {
+ TraceCallList l;
+ TraceCall* c;
+
+ // inner-cycle-callers
+ TraceCallList list=_callers;
+ for (c=list.first();c;c=list.next())
+ if (c->caller()->cycle() == _cycle)
+ l.append(c);
+
+ // call from cycle itself
+ for (c=_cycle->_callings.first();c;c=_cycle->_callings.next())
+ if (c->called() == this) {
+ l.append(c);
+ return l;
+ }
+ }
+
+ return _callers;
+}
+
+const TraceCallList& TraceFunction::callings(bool /* skipCycle */) const
+{
+ return _callings;
+}
+
+void TraceFunction::invalidateDynamicCost()
+{
+ TraceCall* c;
+ for (c=_callings.first();c;c=_callings.next())
+ c->invalidateDynamicCost();
+
+ TraceFunctionSource* sf;
+ for (sf=_sourceFiles.first();sf;sf=_sourceFiles.next())
+ sf->invalidateDynamicCost();
+
+ if (_instrMap) {
+ TraceInstrMap::Iterator iit;
+ for ( iit = _instrMap->begin();
+ iit != _instrMap->end(); ++iit )
+ (*iit).invalidate();
+ }
+
+ invalidate();
+}
+
+void TraceFunction::update()
+{
+ if (!_dirty) return;
+
+#if TRACE_DEBUG
+ qDebug("Update %s (Callers %d, sourceFiles %d, instrs %d)",
+ _name.ascii(), _callers.count(),
+ _sourceFiles.count(), _instrMap ? _instrMap->count():0);
+#endif
+
+ _calledCount = 0;
+ _callingCount = 0;
+ _calledContexts = 0;
+ _callingContexts = 0;
+ clear();
+
+ // context count is NOT the sum of part contexts
+ TraceCall *caller, *calling;
+ for (caller=_callers.first();caller;caller=_callers.next()) {
+ // FIXME
+ if (caller->subCost(0)>0)
+ _calledContexts++;
+ _calledCount += caller->callCount();
+ }
+
+ for (calling=_callings.first();calling;calling=_callings.next()) {
+ // FIXME
+ if (calling->subCost(0)>0) _callingContexts++;
+ _callingCount += calling->callCount();
+ }
+
+ if (data()->inFunctionCycleUpdate() || !_cycle) {
+ // usual case (no cycle member)
+ TraceInclusiveCost* item;
+ for (item=_deps.first();item;item=_deps.next()) {
+ if (!item->part() || !item->part()->isActive()) continue;
+
+ addCost(item);
+ addInclusive(item->inclusive());
+ }
+ }
+ else {
+ // this is a cycle or cycle member
+ for (calling=_callings.first();calling;calling=_callings.next()) {
+
+ // ignore inner-cycle member calls for inclusive cost
+ if ((_cycle != this) &&
+ (calling->inCycle()>0)) continue;
+
+ addInclusive(calling);
+ }
+
+ // self cost
+ if (type() == FunctionCycle) {
+ // cycle: self cost is sum of cycle member self costs, but
+ // doesn't add to inclusive cost
+ TraceFunctionList mList = ((TraceFunctionCycle*)this)->members();
+ TraceFunction* m;
+ for (m=mList.first();m;m=mList.next())
+ addCost(m);
+ }
+ else {
+ // cycle member
+ TraceInclusiveCost* item;
+ for (item=_deps.first();item;item=_deps.next()) {
+ if (!item->part() || !item->part()->isActive()) continue;
+
+ addCost(item);
+ }
+ _dirty = false; // don't recurse
+ addInclusive(this);
+ }
+ }
+ _dirty = false;
+
+#if TRACE_DEBUG
+ qDebug("> %s", costString(0).ascii());
+#endif
+}
+
+bool TraceFunction::isCycle()
+{
+ return _cycle == this;
+}
+
+bool TraceFunction::isCycleMember()
+{
+ return _cycle && (_cycle != this);
+}
+
+void TraceFunction::cycleReset()
+{
+ _cycle = 0;
+ _cycleStackDown = 0;
+ _cycleLow = 0;
+}
+
+// this doesn't mark functions calling themself !
+void TraceFunction::cycleDFS(int d, int& pNo, TraceFunction** pTop)
+{
+ if (_cycleLow != 0) return;
+
+ if (0)
+ qDebug("%s D%02d > %s (%d)",
+ TQString().fill(' ', d).ascii(), d, prettyName().ascii(), pNo+1);
+
+
+
+ // initialize with prefix order
+ pNo++;
+ int prefixNo = pNo;
+ _cycleLow = prefixNo;
+
+ // put myself on stack
+ _cycleStackDown = *pTop;
+ *pTop = this;
+
+ /* cycle cut heuristic:
+ * skip calls for cycle detection if they make less than _cycleCut
+ * percent of the cost of the function.
+ * FIXME: Which cost type to use for this heuristic ?!
+ */
+
+ SubCost base = 0;
+ if (_callers.count()>0) {
+ TraceCallList l = _callers;
+ TraceCall *caller;
+
+ for (caller=l.first();caller;caller=l.next())
+ if (caller->subCost(0) > base)
+ base = caller->subCost(0);
+ }
+ else base = inclusive()->subCost(0);
+
+ SubCost cutLimit = SubCost(base * Configuration::cycleCut());
+
+ if (0)
+ qDebug("%s Cum. %s, Max Caller %s, cut limit %s",
+ TQString().fill(' ', d).ascii(),
+ inclusive()->subCost(0).pretty().ascii(),
+ base.pretty().ascii(),
+ cutLimit.pretty().ascii());
+
+ TraceCall *calling;
+ TraceCallList l = _callings;
+ for (calling=l.first();calling;calling=l.next()) {
+ TraceFunction* called = calling->called();
+
+ // cycle cut heuristic
+ if (calling->subCost(0) < cutLimit) {
+ if (0) qDebug("%s Cut call to %s (cum. %s)",
+ TQString().fill(' ', d).ascii(),
+ called->prettyName().ascii(),
+ calling->subCost(0).pretty().ascii());
+
+ continue;
+ }
+
+ if (called->_cycleLow==0) {
+ // not visited yet
+ called->cycleDFS(d+1, pNo, pTop);
+ if (called->_cycleLow < _cycleLow)
+ _cycleLow = called->_cycleLow;
+ }
+ else if (called->_cycleStackDown) {
+ // backlink to same SCC (still in stack)
+ if (called->_cycleLow < _cycleLow)
+ _cycleLow = called->_cycleLow;
+
+ if (0)
+ qDebug("%s D%02d - %s (%d)",
+ TQString().fill(' ', d+1).ascii(), d+1,
+ called->prettyName().ascii(), called->_cycleLow);
+ }
+ else {
+ if (0)
+ qDebug("%s D%02d - %s (%d) [Not on stack]",
+ TQString().fill(' ', d+1).ascii(), d+1,
+ called->prettyName().ascii(), called->_cycleLow);
+ }
+ }
+
+ if (prefixNo == _cycleLow) {
+ // this is the base of a SCC.
+
+ if (*pTop == this) {
+ *pTop = _cycleStackDown;
+ _cycleStackDown = 0;
+ }
+ else {
+ // a SCC with >1 members
+
+ TraceFunctionCycle* cycle = data()->functionCycle(this);
+ if (0) qDebug("BASE CYC %d %s",
+ cycle->cycleNo(), prettyName().ascii());
+ while(*pTop) {
+ TraceFunction* top = *pTop;
+ cycle->add(top);
+
+ // remove from stack
+ *pTop = top->_cycleStackDown;
+ top->_cycleStackDown = 0;
+
+ if (0) qDebug("CYC %s", top->prettyName().ascii());
+ if (top == this) break;
+ }
+ }
+ }
+ if (0)
+ qDebug("%s D%02d < %s (%d)",
+ TQString().fill(' ', d).ascii(), d,
+ prettyName().ascii(), _cycleLow);
+}
+
+
+TraceInstrMap* TraceFunction::instrMap()
+{
+#if USE_FIXCOST
+
+ if (_instrMapFilled) return _instrMap;
+ _instrMapFilled = true;
+ if (!_instrMap)
+ _instrMap = new TraceInstrMap;
+
+ TraceLine* l = 0;
+ TraceInstr* i = 0;
+ TracePartInstr* pi = 0;
+ TraceInstrCall* ic = 0;
+ TracePartInstrCall* pic = 0;
+
+ TraceInclusiveCostList pfList = deps();
+ TracePartFunction* pf = (TracePartFunction*) pfList.first();
+ for(; pf; pf = (TracePartFunction*) pfList.next()) {
+
+ if (0) qDebug("PartFunction %s:%d",
+ pf->function()->name().ascii(), pf->part()->partNumber());
+
+ FixCost* fc = pf->firstFixCost();
+ for(; fc; fc = fc->nextCostOfPartFunction()) {
+ if (fc->addr() == 0) continue;
+
+ if (!l || (l->lineno() != fc->line()) ||
+ (l->functionSource() != fc->functionSource()))
+ l = fc->functionSource()->line(fc->line(),true);
+
+ if (!i || i->addr() != fc->addr()) {
+ i = &(*_instrMap)[fc->addr()];
+ if (!i->isValid()) {
+ i->setFunction(this);
+ i->setAddr(fc->addr());
+ i->setLine(l);
+ }
+ pi = 0;
+ }
+ if (!pi || pi->part() != fc->part())
+ pi = i->partInstr(fc->part(), pf);
+ fc->addTo(pi);
+ }
+
+ TraceInstr* to = 0;
+ TraceInstrJump* ij;
+ TracePartInstrJump* pij;
+ FixJump* fj = pf->firstFixJump();
+ for(; fj; fj = fj->nextJumpOfPartFunction()) {
+ if (fj->addr() == 0) continue;
+
+ if (!l || (l->lineno() != fj->line()) ||
+ (l->functionSource() != fj->source()))
+ l = fj->source()->line(fj->line(),true);
+
+ if (!i || i->addr() != fj->addr()) {
+ i = &(*_instrMap)[fj->addr()];
+ if (!i->isValid()) {
+ i->setFunction(this);
+ i->setAddr(fj->addr());
+ i->setLine(l);
+ }
+ }
+
+ to = fj->targetFunction()->instr(fj->targetAddr(), true);
+
+ ij = i->instrJump(to, fj->isCondJump());
+ pij = ij->partInstrJump(fj->part());
+
+ fj->addTo(pij);
+ }
+
+ TracePartCallList pcList = pf->partCallings();
+ TracePartCall* pc = pcList.first();
+ for(; pc; pc = pcList.next()) {
+
+ if (0) qDebug("PartCall %s:%d",
+ pc->call()->name().ascii(),
+ pf->part()->partNumber());
+
+ FixCallCost* fcc = pc->firstFixCallCost();
+ for(; fcc; fcc = fcc->nextCostOfPartCall()) {
+ if (fcc->addr() == 0) continue;
+
+ if (!l || (l->lineno() != fcc->line()) ||
+ (l->functionSource() != fcc->functionSource()))
+ l = fcc->functionSource()->line(fcc->line(),true);
+
+ if (!i || i->addr() != fcc->addr()) {
+ i = &(*_instrMap)[fcc->addr()];
+ if (!i->isValid()) {
+ i->setFunction(this);
+ i->setAddr(fcc->addr());
+ i->setLine(l);
+ }
+ }
+ if (!ic || ic->call() != pc->call() || ic->instr() != i) {
+ ic = pc->call()->instrCall(i);
+ pic = 0;
+ }
+ if (!pic || pic->part() != fcc->part())
+ pic = ic->partInstrCall(fcc->part(), pc);
+
+ fcc->addTo(pic);
+ if (0) qDebug("Add FixCallCost %s:%d/0x%s, CallCount %s",
+ fcc->functionSource()->file()->shortName().ascii(),
+ fcc->line(), fcc->addr().toString().ascii(),
+ fcc->callCount().pretty().ascii());
+ }
+ }
+ }
+
+#endif
+
+ return _instrMap;
+}
+
+
+
+//---------------------------------------------------
+// TraceFunctionCycle
+
+TraceFunctionCycle::TraceFunctionCycle(TraceFunction* f, int n)
+{
+ _base = f;
+ _cycleNo = n;
+ _cycle = this;
+
+ setPosition(f->data());
+ setName(TQString("<cycle %1>").arg(n));
+
+ // reset to attributes of base function
+ setFile(_base->file());
+ setClass(_base->cls());
+ setObject(_base->object());
+}
+
+void TraceFunctionCycle::init()
+{
+ _members.clear();
+ _memberSet.clear();
+ _callers.clear();
+ // this deletes all TraceCall's to members
+ _callings.clear();
+
+ invalidate();
+}
+
+void TraceFunctionCycle::add(TraceFunction* f)
+{
+ _members.append(f);
+ _memberSet.insert(f,1);
+}
+
+void TraceFunctionCycle::setup()
+{
+ if (_members.count()==0) return;
+
+ TraceFunction* f;
+ for (f=_members.first();f;f=_members.next()) {
+
+ // the cycle takes all outside callers from its members
+ TraceCall *call;
+ TraceCallList l = f->callers();
+ for (call=l.first();call;call=l.next()) {
+ if ( _memberSet.contains(call->caller()) ) continue;
+ _callers.append(call);
+ }
+
+ // the cycle has a call to each member
+ call = new TraceCall(this, f);
+ call->invalidate();
+ _callings.append(call);
+
+ // now do some faking...
+ f->setCycle(this);
+ }
+ invalidate();
+}
+
+
+//---------------------------------------------------
+// TraceClass
+
+TraceClass::TraceClass()
+{
+ // we are the owner of items generated in our factory
+ _deps.setAutoDelete(true);
+}
+
+TraceClass::~TraceClass()
+{}
+
+TQString TraceClass::prettyName() const
+{
+ if (_name.isEmpty())
+ return TQString("(global)");
+ return _name;
+}
+
+TracePartClass* TraceClass::partClass(TracePart* part)
+{
+ TracePartClass* item = (TracePartClass*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartClass(this);
+ item->setPosition(part);
+ addDep(item);
+ }
+ return item;
+}
+
+void TraceClass::addFunction(TraceFunction* function)
+{
+#if TRACE_ASSERTIONS
+ if (function->cls() != this) {
+ qDebug("Can't add function to a class not enclosing this function\n");
+ return;
+ }
+
+ if (_functions.findRef(function)>=0) return;
+#endif
+
+ _functions.append(function);
+
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(),
+ function->fullName().ascii(), _functions.count());
+#endif
+}
+
+
+
+//---------------------------------------------------
+// TraceFile
+
+TraceFile::TraceFile()
+{
+ // we are the owner of items generated in our factory
+ _deps.setAutoDelete(true);
+}
+
+TraceFile::~TraceFile()
+{}
+
+TracePartFile* TraceFile::partFile(TracePart* part)
+{
+ TracePartFile* item = (TracePartFile*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartFile(this);
+ item->setPosition(part);
+ addDep(item);
+ }
+ return item;
+}
+
+void TraceFile::addFunction(TraceFunction* function)
+{
+#if TRACE_ASSERTIONS
+ if (function->file() != this) {
+ qDebug("Can't add function to a file not enclosing this function\n");
+ return;
+ }
+
+ if (_functions.findRef(function)>=0) return;
+#endif
+
+ _functions.append(function);
+
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(),
+ function->fullName().ascii(), _functions.count());
+#endif
+}
+
+
+void TraceFile::addSourceFile(TraceFunctionSource* sourceFile)
+{
+#if TRACE_ASSERTIONS
+ if (sourceFile->file() != this) {
+ qDebug("Can't add sourceFile to a file not having lines for it\n");
+ return;
+ }
+#endif
+
+ _sourceFiles.append(sourceFile);
+ // not truely needed, as we don't use the sourceFiles for cost update
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s \n added SourceFile %s (now %d)",
+ fullName().ascii(), sourceFile->fullName().ascii(),
+ _sourceFiles.count());
+#endif
+}
+
+
+
+void TraceFile::setDirectory(const TQString& dir)
+{
+ if (dir.endsWith("/"))
+ _dir = dir.left(dir.length()-1);
+ else
+ _dir = dir;
+}
+
+TQString TraceFile::directory()
+{
+ if (!_dir.isEmpty()) return _dir;
+
+ int lastIndex = 0, index;
+ while ( (index=_name.find("/", lastIndex)) >=0)
+ lastIndex = index+1;
+
+ if (lastIndex==0) return TQString();
+
+ // without ending "/"
+ return _name.left(lastIndex-1);
+}
+
+
+TQString TraceFile::shortName() const
+{
+ int lastIndex = 0, index;
+ while ( (index=_name.find("/", lastIndex)) >=0)
+ lastIndex = index+1;
+
+ return _name.mid(lastIndex);
+}
+
+TQString TraceFile::prettyName() const
+{
+ TQString sn = shortName();
+
+ if (sn.isEmpty())
+ return i18n("(unknown)");
+
+ return sn;
+}
+
+TQString TraceFile::prettyLongName() const
+{
+ if (_name.isEmpty())
+ return i18n("(unknown)");
+ return _name;
+}
+
+
+//---------------------------------------------------
+// TraceObject
+
+TraceObject::TraceObject()
+{
+ // we are the owner of items generated in our factory
+ _deps.setAutoDelete(true);
+}
+
+TraceObject::~TraceObject()
+{}
+
+TracePartObject* TraceObject::partObject(TracePart* part)
+{
+ TracePartObject* item = (TracePartObject*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartObject(this);
+ item->setPosition(part);
+ addDep(item);
+ }
+ return item;
+}
+
+void TraceObject::addFunction(TraceFunction* function)
+{
+#if TRACE_ASSERTIONS
+ if (function->object() != this) {
+ qDebug("Can't add function to an object not enclosing this function\n");
+ return;
+ }
+
+ if (_functions.findRef(function)>=0) return;
+#endif
+
+ _functions.append(function);
+
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(),
+ function->fullName().ascii(), _functions.count());
+#endif
+}
+
+// strip path
+void TraceObject::setName(const TQString& name)
+{
+ _name = name;
+
+ int lastIndex = 0, index;
+ while ( (index=_name.find("/", lastIndex)) >=0)
+ lastIndex = index+1;
+
+ _shortName = _name.mid(lastIndex);
+}
+
+TQString TraceObject::prettyName() const
+{
+ if (_shortName.isEmpty())
+ return i18n("(unknown)");
+
+ return _shortName;
+}
+
+//---------------------------------------------------
+// TracePart
+
+TracePart::TracePart(TraceData* data, TQFile* file)
+{
+ setPosition(data);
+
+ _dep = data;
+ _file = file;
+ if (_file)
+ _name = _file->name();
+ _active = true;
+
+ _number = 0;
+ _tid = 0;
+ _pid = 0;
+
+ _fixSubMapping = 0;
+}
+
+TracePart::~TracePart()
+{
+ delete _file;
+
+ delete _fixSubMapping;
+}
+
+void TracePart::setPartNumber(int n)
+{
+ if (data()->maxPartNumber() <n) data()->setMaxPartNumber(n);
+ _number = n;
+}
+
+void TracePart::setThreadID(int tid)
+{
+ if (data()->maxThreadID() <tid) data()->setMaxThreadID(tid);
+ _tid = tid;
+}
+
+void TracePart::setProcessID(int pid)
+{
+ _pid = pid;
+}
+
+
+
+// strip path
+TQString TracePart::shortName() const
+{
+ int lastIndex = 0, index;
+ while ( (index=_name.find("/", lastIndex)) >=0)
+ lastIndex = index+1;
+
+ return _name.mid(lastIndex);
+}
+
+TQString TracePart::prettyName() const
+{
+ TQString name = TQString("%1.%2").arg(_pid).arg(_number);
+ if (data()->maxThreadID()>1)
+ name += TQString("-%3").arg(_tid);
+ return name;
+}
+
+bool TracePart::activate(bool active)
+{
+ if (_active == active) return false;
+ _active = active;
+
+ // to be done by the client of this function
+ // data()->invalidateDynamicCost();
+ // So better use the TraceData functions...
+
+ return true;
+}
+
+
+
+//---------------------------------------------------
+// TracePartList
+
+int TracePartList::compareItems ( Item item1, Item item2 )
+{
+ TracePart* p1 = (TracePart*) item1;
+ TracePart* p2 = (TracePart*) item2;
+ int mTID = p1->data()->maxThreadID()+1;
+ int mNum = p1->data()->maxPartNumber()+1;
+
+ return
+ (p1->processID() - p2->processID()) * mTID * mNum +
+ (p1->partNumber() - p2->partNumber()) * mTID +
+ (p1->threadID() - p2->threadID());
+}
+
+TQString TracePartList::names() const
+{
+ TQString res;
+ TracePart* p;
+ TracePartList l = *this;
+ for (p=l.first();p;p=l.next()) {
+ if (!res.isEmpty()) res += ", ";
+ res += p->shortName();
+ }
+
+ return res;
+}
+
+
+
+//---------------------------------------------------
+// TraceData
+
+
+// create vectors with reasonable default sizes, but not wasting memory
+TraceData::TraceData(TopLevel* top)
+{
+ _topLevel = top;
+ init();
+}
+
+TraceData::TraceData(const TQString& base)
+{
+ _topLevel = 0;
+ init();
+ load(base);
+}
+
+void TraceData::init()
+{
+ _parts.setAutoDelete(true);
+
+ _functionCycleCount = 0;
+ _inFunctionCycleUpdate = false;
+
+ _maxThreadID = 0;
+ _maxPartNumber = 0;
+ _fixPool = 0;
+ _dynPool = 0;
+}
+
+TraceData::~TraceData()
+{
+ if (_fixPool) delete _fixPool;
+ if (_dynPool) delete _dynPool;
+}
+
+TQString TraceData::shortTraceName() const
+{
+ int lastIndex = 0, index;
+ while ( (index=_traceName.find("/", lastIndex)) >=0)
+ lastIndex = index+1;
+
+ return _traceName.mid(lastIndex);
+}
+
+FixPool* TraceData::fixPool()
+{
+ if (!_fixPool)
+ _fixPool = new FixPool();
+
+ return _fixPool;
+}
+
+DynPool* TraceData::dynPool()
+{
+ if (!_dynPool)
+ _dynPool = new DynPool();
+
+ return _dynPool;
+}
+
+
+/**
+ * Two cases:
+ *
+ * - <base> is a directory: Load first profile data file available
+ * - <base> is a file name without part/thread suffixes
+ */
+void TraceData::load(const TQString& base)
+{
+ bool baseExisting = true;
+
+ _traceName = base;
+ TQFileInfo finfo(base);
+ TQString file = finfo.fileName();
+ TQDir dir = finfo.dir();
+
+ if (!finfo.exists()) {
+ baseExisting = false;
+ }
+ else if (finfo.isDir()) {
+ // search for first profile data file in directory
+ dir = TQDir(base);
+
+ TQStringList prefixList;
+ prefixList << "callgrind.out" << "cachegrind.out";
+ for ( TQStringList::Iterator it = prefixList.begin();
+ it != prefixList.end(); ++it ) {
+ file = *it;
+
+ // search for ".pid"
+ TQStringList strList = dir.entryList(file+".*", TQDir::Files);
+ if (strList.count()>0) {
+ int l = file.length();
+ file = strList.first();
+ l++;
+ while(file[l] >= '0' && file[l] <= '9') l++;
+ file = file.left(l);
+ break;
+ }
+ }
+
+ _traceName = dir.path() + "/" + file;
+ }
+
+ TQStringList strList;
+ strList += dir.entryList(file+".*", TQDir::Files);
+ strList += dir.entryList(file+"-*", TQDir::Files);
+
+ baseExisting = TQFile::exists(_traceName);
+ if (baseExisting)
+ strList << file;
+
+ if (strList.count() == 0) {
+ _traceName = base + "/" + file + " " + i18n("(not found)");
+ return;
+ }
+
+
+ // try to guess pid from file name
+ unsigned int pos = file.length();
+ unsigned int pid = 0, f=1;
+ pos--;
+ while(pos>0) {
+ if (file[pos] < '0' || file[pos] > '9') break;
+ pid += f * (file[pos].latin1() - '0');
+ pos--;
+ f *= 10;
+ }
+
+ TQStringList::Iterator it;
+ unsigned int maxNumber = 0;
+ for (it = strList.begin(); it != strList.end(); ++it ) {
+ TracePart* p = addPart( dir.path(), *it );
+
+ if (!p) {
+ kdDebug() << "Error loading " << *it << endl;
+ continue;
+ }
+
+ const TQString& str = *it;
+ unsigned int pos = file.length();
+
+ // try to guess part number from file name
+ unsigned int n = 0;
+ if ((str.length() > pos) && (str[pos] == '.')) {
+ pos++;
+ while(str.length()>pos) {
+ if ((int)str.at(pos) < '0' || (int)str.at(pos) > '9') break;
+ n = 10*n + (str[pos++] - '0');
+ }
+ }
+
+ // try to guess thread number from file name
+ unsigned int t = 0;
+ if ((str.length() > pos) && (str[pos] == '-')) {
+ pos++;
+ while(str.length()>pos) {
+ if ((int)str.at(pos) < '0' || (int)str.at(pos) > '9') break;
+ t = 10*t + (str[pos++] - '0');
+ }
+ }
+
+ //qDebug("File %s: Part %d, Thread %d", (*it).ascii(), n, t);
+
+ if (p->partNumber()>0) n = p->partNumber();
+ if (n>maxNumber) maxNumber = n;
+ if (n==0) n = maxNumber+1;
+ p->setPartNumber(n);
+
+ if (p->threadID()==0) p->setThreadID(t);
+ if (p->processID()==0) p->setProcessID(pid);
+
+ _parts.append(p);
+ }
+ _parts.sort();
+
+ invalidateDynamicCost();
+ updateFunctionCycles();
+
+ // clear loading messages from status bar
+ if (_topLevel) _topLevel->showStatus(TQString(), 0);
+}
+
+TracePart* TraceData::addPart(const TQString& dir, const TQString& name)
+{
+ TQString filename = TQString("%1/%2").arg(dir).arg(name);
+#if TRACE_DEBUG
+ qDebug("TraceData::addPart('%s')", filename.ascii());
+#endif
+
+ TQFile* file = new TQFile(filename);
+
+ Loader* l = Loader::matchingLoader(file);
+ if (!l) return 0;
+
+ if (_topLevel)
+ _topLevel->connect(l, TQT_SIGNAL(updateStatus(TQString, int)),
+ TQT_SLOT(showStatus(TQString, int)));
+
+ TracePart* part = new TracePart(this, file);
+
+ if (! l->loadTrace(part)) {
+ delete part;
+ part = 0;
+ }
+
+ if (_topLevel) l->disconnect(_topLevel);
+
+ return part;
+}
+
+bool TraceData::activateParts(const TracePartList& l)
+{
+ bool changed = false;
+
+ TracePart* part;
+ for (part=_parts.first();part;part=_parts.next())
+ if (part->activate(l.containsRef(part)>0))
+ changed = true;
+
+ if (changed) {
+ // because active parts have changed, throw away calculated
+ // costs...
+ invalidateDynamicCost();
+ updateFunctionCycles();
+ }
+
+ return changed;
+}
+
+
+bool TraceData::activateParts(TracePartList l, bool active)
+{
+ bool changed = false;
+
+ TracePart* part;
+ for (part=l.first();part;part=l.next())
+ if (_parts.findRef(part)>=0)
+ if (part->activate(active))
+ changed = true;
+
+ if (changed) {
+ invalidateDynamicCost();
+ updateFunctionCycles();
+ }
+
+ return changed;
+}
+
+bool TraceData::activatePart(TracePart* p, bool active)
+{
+ return p->activate(active);
+}
+
+bool TraceData::activateAll(bool active)
+{
+ return activateParts(_parts, active);
+}
+
+
+TracePart* TraceData::part(TQString& name)
+{
+ TracePart* part;
+ for (part=_parts.first();part;part=_parts.next())
+ if (part->name() == name)
+ return part;
+ return 0;
+}
+
+TQString TraceData::activePartRange()
+{
+ TQString res;
+ int r1=-1, r2=-1, count=1;
+ TracePart* part;
+ for (part=_parts.first();part;part=_parts.next(), count++)
+ if (part->isActive()) {
+ if (r1<0) { r1 = r2 = count; }
+ else if (r2 == count-1) { r2 = count; }
+ else {
+ if (!res.isEmpty()) res += ";";
+ if (r1==r2) res += TQString::number(r1);
+ else res += TQString("%1-%2").arg(r1).arg(r2);
+ r1 = r2 = count;
+ }
+ }
+ if (r1>=0) {
+ if (!res.isEmpty()) res += ";";
+ if (r1==r2) res += TQString::number(r1);
+ else res += TQString("%1-%2").arg(r1).arg(r2);
+ }
+
+ return res;
+}
+
+void TraceData::invalidateDynamicCost()
+{
+ // invalidate all dynamic costs
+
+ TraceObjectMap::Iterator oit;
+ for ( oit = _objectMap.begin();
+ oit != _objectMap.end(); ++oit )
+ (*oit).invalidate();
+
+ TraceClassMap::Iterator cit;
+ for ( cit = _classMap.begin();
+ cit != _classMap.end(); ++cit )
+ (*cit).invalidate();
+
+ TraceFileMap::Iterator fit;
+ for ( fit = _fileMap.begin();
+ fit != _fileMap.end(); ++fit )
+ (*fit).invalidate();
+
+ TraceFunctionMap::Iterator it;
+ for ( it = _functionMap.begin();
+ it != _functionMap.end(); ++it ) {
+ (*it).invalidateDynamicCost();
+ }
+
+ invalidate();
+
+}
+
+
+TraceObject* TraceData::object(const TQString& name)
+{
+ TraceObject& o = _objectMap[name];
+ if (!o.data()) {
+ // was created
+ o.setPosition(this);
+ o.setName(name);
+
+#if TRACE_DEBUG
+ qDebug("Created %s [TraceData::object]",
+ o.fullName().ascii());
+#endif
+ }
+ return &o;
+}
+
+
+TraceFile* TraceData::file(const TQString& name)
+{
+ TraceFile& f = _fileMap[name];
+ if (!f.data()) {
+ // was created
+ f.setPosition(this);
+ f.setName(name);
+
+#if TRACE_DEBUG
+ qDebug("Created %s [TraceData::file]",
+ f.fullName().ascii());
+#endif
+ }
+ return &f;
+}
+
+
+// usually only called by function()
+TraceClass* TraceData::cls(const TQString& fnName, TQString& shortName)
+{
+ int lastIndex = 0, index, pIndex;
+
+ // we ignore any "::" after a '(' or a space
+ pIndex=fnName.find("(", 0);
+
+#if 0
+ int sIndex=fnName.find(" ", 0);
+ if (sIndex>=0)
+ if ((pIndex == -1) || (sIndex < pIndex))
+ pIndex = sIndex;
+#endif
+
+ while ((index=fnName.find("::", lastIndex)) >=0) {
+ if (pIndex>=0 && pIndex<index) break;
+ lastIndex = index+2;
+ }
+
+ TQString clsName = (lastIndex < 3) ? TQString() :
+ fnName.left(lastIndex-2);
+ shortName = fnName.mid(lastIndex);
+
+ TraceClass& c = _classMap[clsName];
+ if (!c.data()) {
+ // was created
+ c.setPosition(this);
+ c.setName(clsName);
+
+#if TRACE_DEBUG
+ qDebug("Created %s [TraceData::cls]",
+ c.fullName().ascii());
+#endif
+ }
+ return &c;
+}
+
+
+// name is inclusive class/namespace prefix
+TraceFunction* TraceData::function(const TQString& name,
+ TraceFile* file, TraceObject* object)
+{
+ // strip class name
+ TQString shortName;
+ TraceClass* c = cls(name, shortName);
+
+ if (!file || !object || !c) {
+ qDebug("ERROR - no file/object/class for %s ?!", name.ascii());
+ return 0;
+ }
+
+ // Don't use file in key: A function can go over many files
+ // (inlined parts), but still is ONE function.
+ TQString key = name + object->shortName();
+
+ TraceFunctionMap::Iterator it;
+ it = _functionMap.find(key);
+ if (it == _functionMap.end()) {
+ it = _functionMap.insert(key, TraceFunction());
+ TraceFunction& f = it.data();
+
+ f.setPosition(this);
+ f.setName(name);
+ f.setClass(c);
+ f.setObject(object);
+ f.setFile(file);
+ f.setMapIterator(it);
+
+#if TRACE_DEBUG
+ qDebug("Created %s [TraceData::function]\n for %s, %s, %s",
+ f.fullName().ascii(),
+ c->fullName().ascii(), file->fullName().ascii(),
+ object ? object->fullName().ascii() : "(unknown object)");
+#endif
+
+ c->addFunction(&f);
+ object->addFunction(&f);
+ file->addFunction(&f);
+ }
+
+ return &(it.data());
+}
+
+TraceFunctionMap::Iterator TraceData::functionIterator(TraceFunction* f)
+{
+
+ // IMPORTANT: build as SAME key as used in function() above !!
+ TQString key;
+
+ if (f->cls()) key = f->cls()->name() + "::";
+ key += f->name();
+ key += f->object()->shortName();
+
+ return _functionMap.find(key);
+}
+
+TraceFunctionMap::ConstIterator TraceData::functionBeginIterator() const
+{
+ return _functionMap.begin();
+}
+
+TraceFunctionMap::ConstIterator TraceData::functionEndIterator() const
+{
+ return _functionMap.end();
+}
+
+
+void TraceData::resetSourceDirs()
+{
+ TraceFileMap::Iterator fit;
+ for ( fit = _fileMap.begin();
+ fit != _fileMap.end(); ++fit )
+ (*fit).resetDirectory();
+}
+
+void TraceData::update()
+{
+ if (!_dirty) return;
+
+ clear();
+ _totals.clear();
+
+ TracePart* part;
+ for (part=_parts.first();part;part=_parts.next()) {
+ _totals.addCost(part->totals());
+ if (part->isActive())
+ addCost(part->totals());
+ }
+
+ _dirty = false;
+}
+
+TraceCost* TraceData::search(TraceItem::CostType t, TQString name,
+ TraceCostType* ct, TraceCost* parent)
+{
+ TraceCost* result = 0;
+ TraceItem::CostType pt = parent ? parent->type() : NoCostType;
+ SubCost sc, scTop = 0;
+
+ switch(t) {
+ case Function:
+ {
+ TraceFunction *f;
+ TraceFunctionMap::Iterator it;
+ for ( it = _functionMap.begin();
+ it != _functionMap.end(); ++it ) {
+ f = &(*it);
+
+ if (f->name() != name) continue;
+
+ if ((pt == Class) && (parent != f->cls())) continue;
+ if ((pt == File) && (parent != f->file())) continue;
+ if ((pt == Object) && (parent != f->object())) continue;
+
+ if (ct) {
+ sc = f->inclusive()->subCost(ct);
+ if (sc <= scTop) continue;
+ scTop = sc;
+ }
+
+ result = f;
+ }
+ }
+ break;
+
+ case File:
+ {
+ TraceFile *f;
+ TraceFileMap::Iterator it;
+ for ( it = _fileMap.begin();
+ it != _fileMap.end(); ++it ) {
+ f = &(*it);
+ if (f->name() != name) continue;
+ if (ct) {
+ sc = f->subCost(ct);
+ if (sc <= scTop) continue;
+ scTop = sc;
+ }
+ result = f;
+ }
+ }
+ break;
+
+ case Class:
+ {
+ TraceClass *c;
+ TraceClassMap::Iterator it;
+ for ( it = _classMap.begin();
+ it != _classMap.end(); ++it ) {
+ c = &(*it);
+ if (c->name() != name) continue;
+ if (ct) {
+ sc = c->subCost(ct);
+ if (sc <= scTop) continue;
+ scTop = sc;
+ }
+ result = c;
+ }
+ }
+ break;
+
+ case Object:
+ {
+ TraceObject *o;
+ TraceObjectMap::Iterator it;
+ for ( it = _objectMap.begin();
+ it != _objectMap.end(); ++it ) {
+ o = &(*it);
+ if (o->name() != name) continue;
+ if (ct) {
+ sc = o->subCost(ct);
+ if (sc <= scTop) continue;
+ scTop = sc;
+ }
+ result = o;
+ }
+ }
+ break;
+
+ case Instr:
+ if (pt == Function) {
+ TraceInstrMap* instrMap = ((TraceFunction*)parent)->instrMap();
+ if (!instrMap) break;
+
+ TraceInstr *instr;
+ TraceInstrMap::Iterator it;
+ for ( it = instrMap->begin();
+ it != instrMap->end(); ++it ) {
+ instr = &(*it);
+ if (instr->name() != name) continue;
+ result = instr;
+ }
+ }
+ break;
+
+ case Line:
+ {
+ TraceFunctionSourceList sList;
+ if (pt == Function)
+ sList = ((TraceFunction*)parent)->sourceFiles();
+ else if (pt == FunctionSource)
+ sList.append((TraceFunctionSource*) parent);
+ else break;
+
+ TraceLineMap* lineMap;
+ TraceLine* line;
+ TraceLineMap::Iterator it;
+ TraceFunctionSource* fs;
+ for(fs = sList.first(); fs; fs = sList.next()) {
+ lineMap = fs->lineMap();
+ if (!lineMap) continue;
+
+ for ( it = lineMap->begin();
+ it != lineMap->end(); ++it ) {
+ line = &(*it);
+ if (line->name() != name) continue;
+ result = line;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return result;
+}
+
+
+TraceFunctionCycle* TraceData::functionCycle(TraceFunction* f)
+{
+ TraceFunctionCycle* cycle;
+ for (cycle=_functionCycles.first();cycle;cycle=_functionCycles.next())
+ if (cycle->base() == f) return cycle;
+
+ _functionCycleCount++;
+ cycle = new TraceFunctionCycle(f, _functionCycleCount);
+
+ _functionCycles.append(cycle);
+ return cycle;
+}
+
+
+void TraceData::updateFunctionCycles()
+{
+ //qDebug("Updating cycles...");
+
+ // init cycle info
+ TraceFunctionCycle* cycle;
+ for (cycle=_functionCycles.first();cycle;cycle=_functionCycles.next())
+ cycle->init();
+
+ TraceFunctionMap::Iterator it;
+ for ( it = _functionMap.begin(); it != _functionMap.end(); ++it )
+ (*it).cycleReset();
+
+ if (!Configuration::showCycles()) return;
+
+ _inFunctionCycleUpdate = true;
+
+
+#if 0
+ int fCount = _functionMap.size(), fNo = 0, progress=0, p;
+ TQString msg = i18n("Recalculating Function Cycles...");
+ if (_topLevel) _topLevel->showStatus(msg,0);
+#endif
+
+ // DFS and collapse strong connected components (Tarjan)
+ int pNo = 0;
+ TraceFunction* stackTop;
+ for ( it = _functionMap.begin(); it != _functionMap.end(); ++it ) {
+
+#if 0
+ if (_topLevel) {
+ fNo++;
+ p = 100*fNo/fCount;
+ if (p> progress) {
+ progress = p;
+ _topLevel->showStatus(msg, p);
+ }
+ }
+#endif
+
+ stackTop = 0;
+ (*it).cycleDFS(1, pNo, &stackTop);
+ }
+
+ // postprocess cycles
+ for (cycle=_functionCycles.first();cycle;cycle=_functionCycles.next())
+ cycle->setup();
+
+ _inFunctionCycleUpdate = false;
+ // we have to invalidate costs because cycles are now taken into account
+ invalidateDynamicCost();
+
+#if 0
+ if (0) if (_topLevel) _topLevel->showStatus(TQString(),0);
+#endif
+}
+
+void TraceData::updateObjectCycles()
+{
+}
+
+
+void TraceData::updateClassCycles()
+{
+}
+
+
+void TraceData::updateFileCycles()
+{
+}
+
+
diff --git a/kdecachegrind/kdecachegrind/tracedata.h b/kdecachegrind/kdecachegrind/tracedata.h
new file mode 100644
index 0000000..8fab2b6
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/tracedata.h
@@ -0,0 +1,1967 @@
+/* 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.
+*/
+
+/*
+ * Classes holding profiling data for
+ * multiple tracefiles for one command.
+ * See class TraceData first.
+ */
+
+#ifndef TRACEDATA_H
+#define TRACEDATA_H
+
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqptrlist.h>
+#include <tqmap.h>
+#include <tqptrvector.h>
+#include <tqcolor.h>
+
+#include "subcost.h"
+#include "utils.h"
+
+class TQFile;
+
+/**
+ * All cost items are classes prefixed with "Trace".
+ * "TraceCost" holds basic cost metrics for the simplest, smallest
+ * trace entity: These are events counted for an instruction at
+ * a specific memory address of the traced program.
+ * All other cost items are derived from TraceCost, and add needed
+ * cost metrics, e.g. for a call the number of calls that happened.
+ *
+ * Abstract, i.e. never instantiated cost items are
+ * - TraceCost: Basic cost metrics (instr/read/write access + cache events)
+ * - TraceCallCost: Additional call count cost metric.
+ * - TraceInclusiveCost: Additional TraceCost aggregated.
+ * - TraceListCost: Adds dependency to a list of TraceCost's
+ * - TraceCallListCost: same for list of TraceCallCost's
+ * - TraceInclusiveListCost: same for list of TraceInclusiveCost's
+ * - TraceCostItem: Base for cost items for "interesting" costs:
+ * TraceFunction, TraceClass, TraceFile, TraceObject
+ *
+ * The smallest Cachegrind output is trace data indexed by a source
+ * line number, a TracePartLine. Another one is a call from one
+ * source line of a function to another function, a TracePartLineCall.
+ * All other cost items derive the value by summation of cost metrics
+ * from TraceLineItem and TracePartLineCall costs; their cost is
+ * calculated lazy on demand and cached afterwards.
+ *
+ * For cost items, which are sums over all trace files read in, the
+ * summed cost metrics change when e.g. a new trace file is read.
+ * Thus, their cached costs are invalidated, and again recalculated
+ * only on demand. In the following list, theses cost items are called
+ * "dynamic", the other "fixed" (but neverless calculated lazy).
+ *
+ * Cost Item Type Summation of ...
+ *
+ * TracePartLineCall fixed Read from trace file
+ * TracePartLine fixed Read from trace file
+ * TracePartCall fixed TracePartLineCall's
+ * TraceLineCall dynamic TracePartLineCall's
+ * TraceCall dynamic TraceLineCall's
+ * TraceLine dynamic TracePartLine's and TraceLineCall's
+ * TracePartFunction fixed TracePartLine's / TracePartCall's
+ * TraceFunction dynamic TraceLine's / TraceCall's (called from)
+ * TracePartClass fixed TracePartFunction's
+ * TraceClass dynamic TraceFunction's
+ * TracePartFile fixed TracePartFunction's
+ * TraceFile dynamic TraceFunction's
+ * TracePartObject fixed TracePartFunction's
+ * TraceObject dynamic TraceFunction's
+ * TracePart fixed TracePartLine's
+ * TraceData dynamic TracePart's
+ *
+ * As there exists only one TraceData object for a traced program, its the
+ * owner of some "high level" cost items. The following shows the owner
+ * relationship of the cost item classes, together with references.
+ *
+ * Cost Item Owner (& back ref) Other References to
+ *
+ * TracePartLineCall TraceLineCall
+ * TracePartCall TraceCall TracePartLineCall's
+ * TracePartLine TraceLine TracePartLineCall's
+ * TracePartFunction TraceFunction
+ * TracePartClass TraceClass TracePart
+ * TracePartFile TraceFile TracePart
+ * TracePartObject TraceObject TracePart
+ * TraceLineCall TraceCall TracePartLineCall's
+ * TraceCall TraceFunction TracePartCall's
+ * TraceLine TraceData TraceLineCall's
+ * TraceFunction TraceData TraceCall's (calling)
+ * TraceClass TraceData
+ * TraceFile TraceData
+ * TraceObject TraceData
+ * TracePart TraceData
+ * TraceData Main Application
+ *
+ * Convention:
+ * - The owner has a factory method for owned objects,
+ * and calls addXXX() to install references in other objects
+ * - The owner is first arg in a constructor.
+ */
+
+
+class FixString;
+class FixCost;
+class FixCallCost;
+class FixJump;
+class FixPool;
+class DynPool;
+class TopLevel;
+
+class TraceCost;
+class TraceCostType;
+class TraceCostMapping;
+class TraceSubMapping;
+class TraceJumpCost;
+class TraceCallCost;
+class TraceInclusiveCost;
+
+class TracePartInstr;
+class TracePartInstrCall;
+class TracePartLine;
+class TracePartLineCall;
+class TracePartCall;
+class TracePartLineRegion;
+class TracePartFunction;
+class TracePartClass;
+class TracePartObject;
+class TracePartFile;
+
+class TraceInstr;
+class TraceInstrJump;
+class TraceInstrCall;
+class TraceLine;
+class TraceLineJump;
+class TraceLineCall;
+class TraceCall;
+class TraceLineRegion;
+class TraceFunctionSource;
+class TraceFunction;
+class TraceFunctionCycle;
+class TraceClass;
+class TraceObject;
+class TraceFile;
+class TracePart;
+class TraceData;
+
+typedef TQPtrList<TraceCost> TraceCostList;
+typedef TQPtrList<TraceJumpCost> TraceJumpCostList;
+typedef TQPtrList<TraceCallCost> TraceCallCostList;
+typedef TQPtrList<TraceInclusiveCost> TraceInclusiveCostList;
+
+typedef TQPtrList<TracePartCall> TracePartCallList;
+typedef TQPtrList<TracePartInstr> TracePartInstrList;
+typedef TQPtrList<TracePartLine> TracePartLineList;
+typedef TQPtrList<TracePartLineRegion> TracePartLineRegionList;
+typedef TQPtrList<TracePartFunction> TracePartFunctionList;
+typedef TQPtrList<TracePartInstrCall> TracePartInstrCallList;
+typedef TQPtrList<TracePartLineCall> TracePartLineCallList;
+
+
+typedef TQPtrList<TraceInstr> TraceInstrList;
+typedef TQPtrList<TraceLine> TraceLineList;
+typedef TQPtrList<TraceInstrCall> TraceInstrCallList;
+typedef TQPtrList<TraceLineCall> TraceLineCallList;
+typedef TQPtrList<TraceCall> TraceCallList;
+typedef TQPtrList<TraceFile> TraceFileList;
+typedef TQPtrList<TraceLineRegion> TraceLineRegionList;
+typedef TQPtrList<TraceFunctionSource> TraceFunctionSourceList;
+typedef TQPtrList<TraceFunction> TraceFunctionList;
+typedef TQPtrList<TraceFunctionCycle> TraceFunctionCycleList;
+typedef TQMap<TQString, TraceObject> TraceObjectMap;
+typedef TQMap<TQString, TraceClass> TraceClassMap;
+typedef TQMap<TQString, TraceFile> TraceFileMap;
+typedef TQMap<TQString, TraceFunction> TraceFunctionMap;
+typedef TQMap<uint, TraceLine> TraceLineMap;
+
+
+/**
+ * Addresses are 64bit values like costs to be able
+ * to always load profile data produced on 64bit
+ * architectures.
+ */
+class Addr
+{
+ public:
+ Addr() { _v=0; }
+ Addr(uint64 v) { _v = v; }
+
+ // Interpretes char data at s as hex (without "0x" prefix)
+ // and return number of interpreted chars.
+ int set(const char *s);
+ bool set(FixString& s);
+ TQString toString() const;
+ // similar to toString(), but adds a space every 4 digits
+ TQString pretty() const;
+
+ // returns true if this address is in [a-distance;a+distance]
+ bool isInRange(Addr a, int distance);
+
+ bool operator==(const Addr& a) const { return (_v == a._v); }
+ bool operator!=(const Addr& a) const { return (_v != a._v); }
+ bool operator>(const Addr& a) const { return _v > a._v; }
+ bool operator>=(const Addr& a) const { return _v >= a._v; }
+ bool operator<(const Addr& a) const { return _v < a._v; }
+ bool operator<=(const Addr& a) const { return _v <= a._v; }
+
+ Addr operator+(int d) const { return Addr(_v + d); }
+ Addr operator-(int d) const { return Addr(_v - d); }
+
+ private:
+ uint64 _v;
+};
+
+typedef TQMap<Addr, TraceInstr> TraceInstrMap;
+
+
+/**
+ * Base class for cost items.
+ */
+class TraceItem
+{
+public:
+
+ // RTTI for trace item classes, using type() method
+ enum CostType { Item, Cost,
+ PartInstr, Instr,
+ PartLine, Line,
+ PartInstrJump, InstrJump,
+ PartLineJump, LineJump,
+ PartInstrCall, InstrCall,
+ PartLineCall, LineCall,
+ PartCall, Call,
+ PartLineRegion, LineRegion,
+ PartFunction, FunctionSource, Function, FunctionCycle,
+ PartClass, Class, ClassCycle,
+ PartFile, File, FileCycle,
+ PartObject, Object, ObjectCycle,
+ Part, Data,
+ MaxCostType, NoCostType };
+
+ TraceItem();
+ virtual ~TraceItem();
+
+ virtual CostType type() const { return Item; }
+
+ // conversion of item type to locale independent string (e.g. for config)
+ static TQString typeName(CostType);
+ static CostType costType(TQString);
+ // the versions below should be used for user visible strings, as
+ // these use localisation settings
+ static TQString i18nTypeName(CostType);
+ static CostType i18nCostType(TQString);
+ // clean up some static data
+ static void cleanup();
+
+ /**
+ * Returns dynamic name info (without type)
+ */
+ virtual TQString name() const;
+
+ /**
+ * Same as name, but sometimes nicer for humans :-)
+ */
+ virtual TQString prettyName() const;
+
+ /**
+ * Returns text of all cost metrics
+ */
+ virtual TQString costString(TraceCostMapping*);
+
+ /**
+ * Returns type name + dynamic name
+ */
+ TQString fullName() const;
+
+ /**
+ * Returns full name + cost text
+ */
+ TQString toString();
+
+ /**
+ * Set all cost counters to zero
+ */
+ virtual void clear();
+
+ /** Invalidate the cost attributes.
+ * An invalidated object needs to be recalculated when a cost
+ * attribute is requested (e.g. by subCost()).
+ * Has to be overwritten by subclasses when the cost influences costs of
+ * other cost items. If only one item depends on the cost of this item,
+ * it can by set with setDependant() without a need for overwriting.
+ */
+ virtual void invalidate();
+
+ /**
+ * Sets a dependant to be invalidated when this cost is invalidated.
+ * Call this function directly after the constructor.
+ */
+ void setDependant(TraceItem* d) { _dep = d; }
+
+ TraceItem* dependant() { return _dep; }
+
+ /**
+ * If this item is from a single profile data file, position
+ * points to a TracePart, otherwise to a TraceData object.
+ */
+ void setPosition(TraceItem* p) { _position = p; }
+
+ // getters for specific positions, to be overwritten
+ virtual TracePart* part();
+ virtual const TracePart* part() const;
+ virtual TraceData* data();
+ virtual const TraceData* data() const;
+
+ protected:
+ /** Updates cost attributes.
+ * This has to be called by subclasses that access cost attributes
+ * directly
+ */
+ virtual void update();
+
+ bool _dirty;
+
+ TraceItem* _position;
+ TraceItem* _dep;
+
+ private:
+ static TQString *_typeName, *_i18nTypeName;
+};
+
+
+
+/**
+ * An array of basic cost metrics for a trace item.
+ *
+ * The semantic of specific indexes is stored in the
+ * TraceCostMapping of the TraceData object holding this TraceCost.
+ */
+class TraceCost: public TraceItem
+{
+public:
+ /**
+ * The maximal number of subcosts a TraceCost can have.
+ */
+ static const int MaxRealIndex;
+#define MaxRealIndexValue 13
+ static const int InvalidIndex;
+
+
+ TraceCost();
+ virtual ~TraceCost();
+
+ virtual CostType type() const { return Cost; }
+ virtual TQString costString(TraceCostMapping*);
+
+ virtual void clear();
+
+ // set the cost according to a submapping and a list of ASCII numbers
+ void set(TraceSubMapping*, const char*);
+ void set(TraceSubMapping*, FixString&);
+ // add a cost according to a submapping and a list of ASCII numbers
+ void addCost(TraceSubMapping*, const char*);
+ void addCost(TraceSubMapping*, FixString&);
+ // add the cost of another item
+ void addCost(TraceCost* item);
+ void addCost(int index, SubCost value);
+
+ // maximal cost
+ void maxCost(TraceSubMapping*, FixString&);
+ void maxCost(TraceCost* item);
+ void maxCost(int index, SubCost value);
+ TraceCost diff(TraceCost* item);
+
+ virtual void invalidate();
+
+ /** Returns a sub cost. This automatically triggers
+ * a call to update() if needed.
+ */
+ SubCost subCost(TraceCostType*);
+
+ /**
+ * Same as above, but only for real types
+ */
+ SubCost subCost(int);
+
+ /** Returns a cost attribute converted to a string
+ * (with space after every 3 digits)
+ */
+ TQString prettySubCost(TraceCostType*);
+
+ protected:
+ virtual void update();
+
+ SubCost _cost[MaxRealIndexValue];
+ int _count; // only _count first indexes of _cost are used
+
+ // cache last virtual subcost for faster access
+ SubCost _cachedCost;
+ TraceCostType* _cachedType;
+};
+
+
+
+/**
+ * A cost type, e.g. "L1 Read Miss", short "l1rm".
+ *
+ * We distinguish "real" cost types, where the values come
+ * from the trace file, and "virtual" cost types, which
+ * are calculated from the real ones.
+ *
+ * For a virtual cost type, set a formula to calculate it:
+ * e.g. for "Read Misses" : "l1rm + l2rm".
+ * To allow for parsing, you must specify a TraceCostMapping
+ * with according cost types (e.g. "l1rm" and "l2rm" for above formula).
+ *
+ * The cost type with empty name is the "const" cost type.
+ */
+class TraceCostType
+{
+public:
+
+ /**
+ * <name> is a short (non-localized) identifier for the cost type,
+ * e.g. "l1rm".
+ * <longName> is a long localized string, e.g. "L1 Read Miss"
+ * <formula> uses short names to reference other types
+ */
+ TraceCostType(TQString name,
+ TQString longName = TQString(),
+ TQString formula = TQString());
+
+ void setName(TQString n) { _name = n; }
+ void setLongName(TQString n) { _longName = n; }
+ void setMapping(TraceCostMapping* m);
+ void setFormula(TQString);
+ // default arg is for specifying a real type, but index unknown
+ void setRealIndex(int r = TraceCost::MaxRealIndex);
+
+ const TQString& name() { return _name; }
+ const TQString& longName() { return _longName; }
+ const TQString& formula() { return _formula; }
+ TraceCostMapping* mapping() { return _mapping; }
+ int realIndex() { return _realIndex; }
+ bool isReal() { return _formula.isEmpty(); }
+ TQColor color();
+
+ /*
+ * returns true if all cost type names can be resolved in formula
+ */
+ bool parseFormula();
+ TQString parsedFormula();
+
+ SubCost subCost(TraceCost*);
+
+ /*
+ * For virtual costs, returns a histogram for use with
+ * partitionPixmap().
+ * Returns maximal real index.
+ */
+ int histCost(TraceCost* c, double total, double* hist);
+
+ // application wide known types, referenced by short name
+ // next 2 functions return a new type object instance
+ static TraceCostType* knownRealType(TQString);
+ static TraceCostType* knownVirtualType(TQString);
+ static void add(TraceCostType*);
+ static bool remove(TQString);
+ static int knownTypeCount();
+ static TraceCostType* knownType(int);
+
+private:
+
+ TQString _name, _longName, _formula;
+ TraceCostMapping* _mapping;
+ bool _parsed, _inParsing;
+ // index MaxRealIndex is for constant addition
+ int _coefficient[MaxRealIndexValue];
+ int _realIndex;
+
+ static TQPtrList<TraceCostType>* _knownTypes;
+};
+
+
+/**
+ * A class for managing a set of cost types.
+ *
+ * Each cost type has an index:
+ * - Real costs are in range [0 .. TraceCost:MaxRealIndex[
+ * - Virtual costs are in range [MaxRealIndex, ...]
+ */
+class TraceCostMapping
+{
+public:
+ TraceCostMapping();
+ ~TraceCostMapping();
+
+ /**
+ * Defines a sub mapping with a list of real types
+ * If <create> is false, checks if this is a existing sub mapping.
+ */
+ TraceSubMapping* subMapping(TQString types, bool create = true);
+
+ // "knows" about some real types
+ int addReal(TQString);
+ int add(TraceCostType*);
+ bool remove(TraceCostType*);
+ int realCount() { return _realCount; }
+ int virtualCount() { return _virtualCount; }
+ int minVirtualIndex() { return TraceCost::MaxRealIndex; }
+ TraceCostType* type(int);
+ TraceCostType* realType(int);
+ TraceCostType* virtualType(int);
+ TraceCostType* type(TQString);
+ TraceCostType* typeForLong(TQString);
+ int realIndex(TQString);
+ int index(TQString);
+ TQColor* realColors() { return _realColor; }
+
+ /**
+ * Adds all known virtual types that can be parsed
+ */
+ int addKnownVirtualTypes();
+
+private:
+ // we support only a fixed number of real and virtual types
+ TraceCostType* _real[MaxRealIndexValue];
+ TQColor _realColor[MaxRealIndexValue];
+ TraceCostType* _virtual[MaxRealIndexValue];
+ int _realCount, _virtualCount;
+};
+
+/**
+ * A submapping of a TraceCostMapping
+ *
+ * This is a fixed ordered list of indexes for real cost types
+ * in a mapping.
+ *
+ * You can define a mapping by requesting submappings. Undefined cost
+ * types will get a new real type index.
+ * TraceCostMapping m;
+ * sm1 = m.subMapping("Event1 Cost1 Cost2"); // returns submap [0,1,2]
+ * sm2 = m.subMapping("Event2 Cost3 Event1"); // returns submap [3,4,0]
+ * Real types of m will be:
+ * (0:Event1, 1:Cost1, 2:Cost2, 3:Event2, 4:Cost3)
+ */
+class TraceSubMapping
+{
+public:
+ TraceSubMapping(TraceCostMapping*);
+
+ bool append(TQString, bool create=true);
+ bool append(int);
+ void clear();
+
+ /**
+ * Get number of used indexes
+ */
+ int count() { return _count; }
+
+ /**
+ * Is this submapping the identity( i.e. realIndex(i)=i ) ?
+ * This often allows for optimizations.
+ */
+ bool isIdentity() { return _isIdentity; }
+ int realIndex(int i)
+ { return (i<0 || i>=_count) ? TraceCost::InvalidIndex : _realIndex[i]; }
+
+ /*
+ * Allows an iteration over the sorted list of all real indexes not used in
+ * this submapping, up to topIndex (use TraceCost::MaxRealIndex for all).
+ * Usage: for(i = firstUnused(); i < topIndex; i = nextUnused(i)) { LOOP }
+ */
+ int firstUnused() { return _firstUnused; }
+ int nextUnused(int i) {
+ if (i<0 || i>=TraceCost::MaxRealIndex) return TraceCost::InvalidIndex;
+ return _nextUnused[i]; }
+
+private:
+ TraceCostMapping* _mapping;
+ int _count, _firstUnused;
+ bool _isIdentity;
+ int _realIndex[MaxRealIndexValue];
+ int _nextUnused[MaxRealIndexValue];
+};
+
+
+/**
+ * Cost of a (conditional) jump.
+ */
+class TraceJumpCost: public TraceItem
+{
+ public:
+ TraceJumpCost();
+ virtual ~TraceJumpCost();
+
+ // reimplementations for cost addition
+ virtual TQString costString(TraceCostMapping* m);
+ virtual void clear();
+
+ void addCost(TraceJumpCost*);
+
+ // additional cost metrics
+ SubCost followedCount();
+ SubCost executedCount();
+ void addFollowedCount(SubCost c) { _followedCount += c; }
+ void addExecutedCount(SubCost c) { _executedCount += c; }
+
+ protected:
+ SubCost _executedCount, _followedCount;
+};
+
+
+
+/**
+ * Cost item with additional call count metric.
+ */
+class TraceCallCost: public TraceCost
+{
+ public:
+ TraceCallCost();
+ virtual ~TraceCallCost();
+
+ // reimplementations for cost addition
+ virtual TQString costString(TraceCostMapping* m);
+ virtual void clear();
+
+ // additional cost metric
+ SubCost callCount();
+ TQString prettyCallCount();
+ void addCallCount(SubCost c);
+
+ protected:
+ SubCost _callCount;
+};
+
+
+/**
+ * Cost item with additional inclusive metric
+ */
+class TraceInclusiveCost: public TraceCost
+{
+ public:
+ TraceInclusiveCost();
+ virtual ~TraceInclusiveCost();
+
+ // reimplementations for cost addition
+ virtual TQString costString(TraceCostMapping* m);
+ virtual void clear();
+
+ // additional cost metric
+ TraceCost* inclusive();
+ void addInclusive(TraceCost*);
+
+ protected:
+ TraceCost _inclusive;
+};
+
+
+/**
+ * Cost Item
+ * dependend on a list of cost items.
+ */
+class TraceListCost: public TraceCost
+{
+ public:
+ TraceListCost();
+ virtual ~TraceListCost();
+
+ // reimplementation for dependency list
+ virtual void update();
+
+ TraceCostList& deps() { return _deps; }
+ void addDep(TraceCost*);
+ TraceCost* findDepFromPart(TracePart*);
+
+ protected:
+ // overwrite in subclass to change update behaviour
+ virtual bool onlyActiveParts() { return false; }
+
+ TraceCostList _deps;
+
+ private:
+ // very temporary: cached
+ TraceCost* _lastDep;
+};
+
+
+/**
+ * Jump Cost Item
+ * dependend on a list of Jump cost items.
+ */
+class TraceJumpListCost: public TraceJumpCost
+{
+ public:
+ TraceJumpListCost();
+ virtual ~TraceJumpListCost();
+
+ // reimplementation for dependency list
+ virtual void update();
+
+ TraceJumpCostList deps() { return _deps; }
+ void addDep(TraceJumpCost*);
+ TraceJumpCost* findDepFromPart(TracePart*);
+
+ protected:
+ // overwrite in subclass to change update behaviour
+ virtual bool onlyActiveParts() { return false; }
+
+ TraceJumpCostList _deps;
+
+ private:
+ // very temporary: cached
+ TraceJumpCost* _lastDep;
+};
+
+
+
+
+/**
+ * Call Cost Item
+ * dependend on a list of Call cost items.
+ */
+class TraceCallListCost: public TraceCallCost
+{
+ public:
+ TraceCallListCost();
+ virtual ~TraceCallListCost();
+
+ // reimplementation for dependency list
+ virtual void update();
+
+ TraceCallCostList deps() { return _deps; }
+ void addDep(TraceCallCost*);
+ TraceCallCost* findDepFromPart(TracePart*);
+
+ protected:
+ // overwrite in subclass to change update behaviour
+ virtual bool onlyActiveParts() { return false; }
+
+ TraceCallCostList _deps;
+
+ private:
+ // very temporary: cached
+ TraceCallCost* _lastDep;
+};
+
+
+/**
+ * Inclusive Cost Item dependend on a list of inclusive cost items.
+ */
+class TraceInclusiveListCost: public TraceInclusiveCost
+{
+ public:
+ TraceInclusiveListCost();
+ virtual ~TraceInclusiveListCost();
+
+ // reimplementation for dependency
+ virtual void update();
+
+ TraceInclusiveCostList deps() { return _deps; }
+ void addDep(TraceInclusiveCost*);
+ TraceInclusiveCost* findDepFromPart(TracePart*);
+
+ protected:
+ // overwrite in subclass to change update behaviour
+ virtual bool onlyActiveParts() { return false; }
+
+ TraceInclusiveCostList _deps;
+
+ private:
+ // very temporary: cached
+ TraceInclusiveCost* _lastDep;
+};
+
+
+
+
+
+/*-----------------------------------------------------------------
+ * Classes for cost items of one trace file, i.e. a "trace part"
+ *-----------------------------------------------------------------
+ */
+
+/**
+ * Cost of jump at a instruction code address from a trace file.
+ */
+class TracePartInstrJump: public TraceJumpCost
+{
+ public:
+ TracePartInstrJump(TraceInstrJump*, TracePartInstrJump*);
+ virtual ~TracePartInstrJump();
+
+ virtual CostType type() const { return PartInstrJump; }
+ // fix cost item
+ virtual void update() {}
+ TraceInstrJump* instrJump() const { return (TraceInstrJump*) _dep; }
+ TracePartInstrJump* next() const { return _next; }
+
+ private:
+ // chaining all parts for InstrJump
+ TracePartInstrJump* _next;
+};
+
+
+/**
+ * Cost of a call at a instruction code address from a trace file.
+ * Cost is always up to date, no lazy update needed.
+ */
+class TracePartInstrCall: public TraceCallCost
+{
+public:
+ TracePartInstrCall(TraceInstrCall*);
+ virtual ~TracePartInstrCall();
+
+ virtual CostType type() const { return PartInstrCall; }
+ // fix cost item
+ virtual void update() {}
+ TraceInstrCall* instrCall() const { return (TraceInstrCall*) _dep; }
+};
+
+
+/**
+ * Cost of a code instruction address from a trace file.
+ * Cost is always up to date, no lazy update needed.
+ */
+class TracePartInstr: public TraceCost
+{
+public:
+ TracePartInstr(TraceInstr*);
+ virtual ~TracePartInstr();
+
+ virtual CostType type() const { return PartInstr; }
+ // fix cost item
+ virtual void update() {}
+
+ TraceInstr* instr() const { return (TraceInstr*)_dep; }
+};
+
+
+/**
+ * Cost of jump at a source line from a trace file.
+ */
+class TracePartLineJump: public TraceJumpCost
+{
+ public:
+ TracePartLineJump(TraceLineJump*);
+ virtual ~TracePartLineJump();
+
+ virtual CostType type() const { return PartLineJump; }
+ // fix cost item
+ virtual void update() {}
+ TraceLineJump* lineJump() const { return (TraceLineJump*) _dep; }
+};
+
+
+/**
+ * Cost of a call at a line from a trace file.
+ * Cost is always up to date, no lazy update needed.
+ */
+class TracePartLineCall: public TraceCallCost
+{
+public:
+ TracePartLineCall(TraceLineCall*);
+ virtual ~TracePartLineCall();
+
+ virtual CostType type() const { return PartLineCall; }
+ // fix cost item
+ virtual void update() {}
+ TraceLineCall* lineCall() const { return (TraceLineCall*) _dep; }
+};
+
+
+
+/**
+ * Cost of a line from a trace file.
+ * Cost is always up to date, no lazy update needed.
+ */
+class TracePartLine: public TraceCost
+{
+public:
+ TracePartLine(TraceLine*);
+ virtual ~TracePartLine();
+
+ virtual CostType type() const { return PartLine; }
+ // fix cost item
+ virtual void update() {}
+
+ TraceLine* line() const { return (TraceLine*)_dep; }
+};
+
+
+/**
+ * Cost of a source region.
+ */
+class TracePartLineRegion: public TraceInclusiveCost
+{
+public:
+ TracePartLineRegion(TraceLineRegion*);
+ virtual ~TracePartLineRegion();
+
+ virtual CostType type() const { return PartLineRegion; }
+ virtual void update();
+
+ TraceLineRegion* region() const { return (TraceLineRegion*)_dep; }
+};
+
+
+/**
+ * Cost of a call at a function to another function,
+ * from a single trace file.
+ */
+class TracePartCall: public TraceCallListCost
+{
+public:
+ TracePartCall(TraceCall* call);
+ virtual ~TracePartCall();
+
+ virtual CostType type() const { return PartCall; }
+ // calls a function itself?
+ bool isRecursion();
+
+ // reimplementation for dependency list
+ virtual void update();
+
+ TraceCall* call() const { return (TraceCall*)_dep; }
+
+ FixCallCost* setFirstFixCallCost(FixCallCost* fc)
+ { FixCallCost* t = _firstFixCallCost; _firstFixCallCost = fc; return t; }
+ FixCallCost* firstFixCallCost() const { return _firstFixCallCost; }
+
+private:
+ FixCallCost* _firstFixCallCost;
+};
+
+
+/**
+ * Cost of a function,
+ * from a single trace file.
+ */
+class TracePartFunction: public TraceInclusiveCost
+{
+public:
+ TracePartFunction(TraceFunction*,
+ TracePartObject*, TracePartFile*);
+ virtual ~TracePartFunction();
+
+ virtual CostType type() const { return PartFunction; }
+ virtual void update();
+ virtual TQString costString(TraceCostMapping* m);
+
+ void addPartInstr(TracePartInstr*);
+ void addPartLine(TracePartLine*);
+ void addPartCaller(TracePartCall*);
+ void addPartCalling(TracePartCall*);
+
+ TraceFunction* function() { return (TraceFunction*) _dep; }
+ TracePartObject* partObject() { return _partObject; }
+ TracePartClass* partClass() { return _partClass; }
+ TracePartFile* partFile() { return _partFile; }
+ const TracePartCallList& partCallers() { return _partCallers; }
+ const TracePartCallList& partCallings() { return _partCallings; }
+ void setPartObject(TracePartObject* o) { _partObject = o; }
+ void setPartClass(TracePartClass* c) { _partClass = c; }
+ void setPartFile(TracePartFile* f) { _partFile = f; }
+
+ /* for linked list of FixXXX objects */
+ FixCost* setFirstFixCost(FixCost* fc)
+ { FixCost* t = _firstFixCost; _firstFixCost = fc; return t; }
+ FixCost* firstFixCost() const { return _firstFixCost; }
+ FixJump* setFirstFixJump(FixJump* fj)
+ { FixJump* t = _firstFixJump; _firstFixJump = fj; return t; }
+ FixJump* firstFixJump() const { return _firstFixJump; }
+
+ // additional cost metrics
+ SubCost calledCount();
+ SubCost callingCount();
+ TQString prettyCalledCount();
+ TQString prettyCallingCount();
+ int calledContexts();
+ int callingContexts();
+
+private:
+ TracePartObject* _partObject;
+ TracePartClass* _partClass;
+ TracePartFile* _partFile;
+
+ TracePartCallList _partCallings;
+ TracePartCallList _partCallers;
+ TracePartInstrList _partInstr;
+ TracePartLineList _partLines;
+
+ // cached
+ SubCost _calledCount, _callingCount;
+ int _calledContexts, _callingContexts;
+
+ FixCost* _firstFixCost;
+ FixJump* _firstFixJump;
+};
+
+
+/**
+ * Cost of a class,
+ * from a single trace file.
+ */
+class TracePartClass: public TraceInclusiveListCost
+{
+public:
+ TracePartClass(TraceClass*);
+ virtual ~TracePartClass();
+
+ virtual CostType type() const { return PartClass; }
+ TQString prettyName() const;
+
+ TraceClass* cls() { return (TraceClass*)_dep; }
+ void addPartFunction(TracePartFunction* f) { addDep(f); }
+};
+
+
+/**
+ * Cost of a source file,
+ * from a single trace file.
+ */
+class TracePartFile: public TraceInclusiveListCost
+{
+public:
+ TracePartFile(TraceFile*);
+ virtual ~TracePartFile();
+
+ virtual CostType type() const { return PartFile; }
+ TraceFile* file() { return (TraceFile*)_dep; }
+ void addPartFunction(TracePartFunction* f) { addDep(f); }
+};
+
+
+/**
+ * Cost of a object,
+ * from a single trace file.
+ */
+class TracePartObject: public TraceInclusiveListCost
+{
+public:
+ TracePartObject(TraceObject*);
+ virtual ~TracePartObject();
+
+ virtual CostType type() const { return PartObject; }
+ TraceObject* object() const { return (TraceObject*)_dep; }
+ void addPartFunction(TracePartFunction* f) { addDep(f); }
+};
+
+
+
+/**
+ * A Trace Part: All data read from a trace file, containing all costs
+ * that happened in a specified time interval of the executed command.
+ */
+class TracePart: public TraceListCost
+{
+public:
+ TracePart(TraceData*, TQFile* file);
+ virtual ~TracePart();
+
+ virtual CostType type() const { return Part; }
+ virtual TracePart* part() { return this; }
+ virtual const TracePart* part() const { return this; }
+
+ TQString shortName() const;
+ TQString prettyName() const;
+ TQFile* file() const { return _file; }
+ TQString name() const { return _name; }
+ TQString description() const { return _descr; }
+ TQString trigger() const { return _trigger; }
+ TQString timeframe() const { return _timeframe; }
+ TQString version() const { return _version; }
+ int partNumber() { return _number; }
+ int threadID() { return _tid; }
+ int processID() { return _pid; }
+ void setDescription(const TQString& d) { _descr = d; }
+ void setTrigger(const TQString& t) { _trigger = t; }
+ void setTimeframe(const TQString& t) { _timeframe = t; }
+ void setVersion(const TQString& v) { _version = v; }
+ void setPartNumber(int n);
+ void setThreadID(int t);
+ void setProcessID(int p);
+ TraceCost* totals() { return &_totals; }
+ /* we get owner of the submapping */
+ void setFixSubMapping(TraceSubMapping* sm) { _fixSubMapping = sm; }
+ TraceSubMapping* fixSubMapping() { return _fixSubMapping; }
+
+ // returns true if something changed
+ bool activate(bool);
+ bool isActive() { return _active; }
+
+private:
+ TQFile* _file;
+ TQString _name;
+ TQString _descr;
+ TQString _trigger;
+ TQString _timeframe;
+ TQString _version;
+
+ int _number, _tid, _pid;
+
+ bool _active;
+
+ // the totals line
+ TraceCost _totals;
+
+ // submapping for all fix costs of this part
+ TraceSubMapping* _fixSubMapping;
+};
+
+
+class TracePartList: public TQPtrList<TracePart>
+{
+ public:
+ TQString names() const;
+ protected:
+ int compareItems ( Item item1, Item item2 );
+};
+
+
+/*-----------------------------------------------------------------
+ * Classes for cost items summed up from multiple trace parts
+ *-----------------------------------------------------------------
+ */
+
+
+/**
+ * A jump from an instruction to another inside of a function
+ */
+class TraceInstrJump: public TraceJumpCost
+{
+public:
+ TraceInstrJump(TraceInstr* instrFrom, TraceInstr* instrTo,
+ bool isCondJump);
+ virtual ~TraceInstrJump();
+
+ virtual CostType type() const { return InstrJump; }
+ virtual TQString name() const;
+
+ virtual void update();
+
+ TraceInstr* instrFrom() const { return _instrFrom; }
+ TraceInstr* instrTo() const { return _instrTo; }
+ bool isCondJump() const { return _isCondJump; }
+
+ // part factory
+ TracePartInstrJump* partInstrJump(TracePart*);
+
+ private:
+ TraceInstr *_instrFrom, *_instrTo;
+ bool _isCondJump;
+ // list of parts for this InstrJump
+ TracePartInstrJump* _first;
+};
+
+class TraceInstrJumpList: public TQPtrList<TraceInstrJump>
+{
+ public:
+ TraceInstrJumpList() { _sortLow = true; }
+ void setSortLow(bool s) { _sortLow = s; }
+
+ protected:
+ int compareItems ( Item item1, Item item2 );
+
+ private:
+ bool _sortLow;
+};
+
+
+/**
+ * A jump from one line to another inside of a function.
+ */
+class TraceLineJump: public TraceJumpListCost
+{
+ public:
+ TraceLineJump(TraceLine* lineFrom, TraceLine* lineTo,
+ bool isCondJump);
+ virtual ~TraceLineJump();
+
+ virtual CostType type() const { return LineJump; }
+ virtual TQString name() const;
+
+ TraceLine* lineFrom() const { return _lineFrom; }
+ TraceLine* lineTo() const { return _lineTo; }
+ bool isCondJump() { return _isCondJump; }
+
+ // part factory
+ TracePartLineJump* partLineJump(TracePart*);
+
+ protected:
+ bool onlyActiveParts() { return true; }
+
+ private:
+ TraceLine *_lineFrom, *_lineTo;
+ bool _isCondJump;
+};
+
+
+class TraceLineJumpList: public TQPtrList<TraceLineJump>
+{
+ public:
+ TraceLineJumpList() { _sortLow = true; }
+ void setSortLow(bool s) { _sortLow = s; }
+
+ protected:
+ int compareItems ( Item item1, Item item2 );
+
+ private:
+ bool _sortLow;
+};
+
+
+/**
+ * A call from an instruction of one function to another function
+ */
+class TraceInstrCall: public TraceCallListCost
+{
+ public:
+ TraceInstrCall(TraceCall* call, TraceInstr* instr);
+ virtual ~TraceInstrCall();
+
+ virtual CostType type() const { return InstrCall; }
+ virtual TQString name() const;
+
+ TraceInstr* instr() const { return _instr; }
+ TraceCall* call() const { return _call; }
+
+ // part factory
+ TracePartInstrCall* partInstrCall(TracePart*, TracePartCall*);
+
+ protected:
+ bool onlyActiveParts() { return true; }
+
+ private:
+ TraceInstr* _instr;
+ TraceCall* _call;
+};
+
+
+/**
+ * A call from a line of one function to another function.
+ */
+class TraceLineCall: public TraceCallListCost
+{
+ public:
+ TraceLineCall(TraceCall* call, TraceLine* line);
+ virtual ~TraceLineCall();
+
+ virtual CostType type() const { return LineCall; }
+ virtual TQString name() const;
+
+ TraceLine* line() const { return _line; }
+ TraceCall* call() const { return _call; }
+
+ // part factory
+ TracePartLineCall* partLineCall(TracePart*, TracePartCall*);
+
+ protected:
+ bool onlyActiveParts() { return true; }
+
+ private:
+ TraceLine* _line;
+ TraceCall* _call;
+};
+
+
+/**
+ * A call from one to another function.
+ * Consists of a list a TraceLineCalls
+ */
+class TraceCall: public TraceCallListCost
+{
+ public:
+ TraceCall(TraceFunction* caller, TraceFunction* called);
+ virtual ~TraceCall();
+
+ virtual CostType type() const { return Call; }
+ virtual TQString name() const;
+
+ // calls a function itself?
+ bool isRecursion() { return _caller == _called; }
+
+ // return cycle number >0 if call is inside of a cycle
+ int inCycle();
+ // we need some special handling for cycle calls
+ void update();
+
+ void invalidateDynamicCost();
+
+ // factories
+ TracePartCall* partCall(TracePart*,
+ TracePartFunction*, TracePartFunction*);
+ TraceLineCall* lineCall(TraceLine*);
+ TraceInstrCall* instrCall(TraceInstr*);
+
+ TraceFunction* caller(bool skipCycle=false) const;
+ TraceFunction* called(bool skipCycle=false) const;
+ TQString callerName(bool skipCycle=false) const;
+ TQString calledName(bool skipCycle=false) const;
+ const TraceLineCallList& lineCalls() const { return _lineCalls; }
+ const TraceInstrCallList& instrCalls() const { return _instrCalls; }
+
+ FixCallCost* setFirstFixCost(FixCallCost* fc)
+ { FixCallCost* t = _firstFixCost; _firstFixCost = fc; return t; }
+
+ protected:
+ bool onlyActiveParts() { return true; }
+
+ private:
+ TraceInstrCallList _instrCalls;
+ TraceLineCallList _lineCalls;
+ TraceFunction* _caller;
+ TraceFunction* _called;
+
+ FixCallCost* _firstFixCost;
+};
+
+
+/**
+ * A code instruction address of the program.
+ * Consists of a list a TracePartInstr from different trace files
+ * and a list of TraceInstrCalls if there are calls from this address.
+ */
+class TraceInstr: public TraceListCost
+{
+ public:
+ TraceInstr();
+ virtual ~TraceInstr();
+
+ virtual CostType type() const { return Instr; }
+ virtual TQString name() const;
+ TQString prettyName() const;
+
+ bool isValid() { return _addr != Addr(0); }
+
+ // factories
+ TracePartInstr* partInstr(TracePart* part,
+ TracePartFunction* partFunction);
+ TraceInstrJump* instrJump(TraceInstr* to, bool isCondJump);
+
+ void addInstrCall(TraceInstrCall*);
+
+ Addr addr() const { return _addr; }
+ TraceFunction* function() const { return _function; }
+ TraceLine* line() const { return _line; }
+ const TraceInstrJumpList& instrJumps() const { return _instrJumps; }
+ const TraceInstrCallList& instrCalls() const { return _instrCalls; }
+ bool hasCost(TraceCostType*);
+
+ // only to be called after default constructor
+ void setAddr(const Addr addr) { _addr = addr; }
+ void setFunction(TraceFunction* f) { _function = f; }
+ void setLine(TraceLine* l) { _line = l; }
+
+ protected:
+ bool onlyActiveParts() { return true; }
+
+ private:
+ Addr _addr;
+ TraceFunction* _function;
+ TraceLine* _line;
+
+ TraceInstrJumpList _instrJumps;
+ TraceInstrCallList _instrCalls;
+};
+
+
+/**
+ * A source line of the program.
+ * Consists of a list a TracePartLines from different trace files
+ * and a list of TraceLineCalls if there are calls from this line.
+ */
+class TraceLine: public TraceListCost
+{
+public:
+ TraceLine();
+ virtual ~TraceLine();
+
+ virtual CostType type() const { return Line; }
+ virtual TQString name() const;
+ TQString prettyName() const;
+
+ // factories
+ TracePartLine* partLine(TracePart* part,
+ TracePartFunction* partFunction);
+ TraceLineJump* lineJump(TraceLine* to, bool isCondJump);
+
+ void addLineCall(TraceLineCall*);
+
+
+ bool isValid() { return _sourceFile != 0; }
+ bool hasCost(TraceCostType*);
+ TraceFunctionSource* functionSource() const { return _sourceFile; }
+ uint lineno() const { return _lineno; }
+ const TraceLineCallList& lineCalls() const { return _lineCalls; }
+ const TraceLineJumpList& lineJumps() const { return _lineJumps; }
+
+ // only to be called after default constructor
+ void setSourceFile(TraceFunctionSource* sf) { _sourceFile = sf; }
+ void setLineno(uint lineno) { _lineno = lineno; }
+
+ protected:
+ bool onlyActiveParts() { return true; }
+
+ private:
+ TraceFunctionSource* _sourceFile;
+ uint _lineno;
+
+ TraceLineJumpList _lineJumps;
+ TraceLineCallList _lineCalls;
+};
+
+
+/*
+ * Base class for all costs which
+ * represent "interesting" items or group of items
+ * with settable name and inclusive cost
+ */
+class TraceCostItem: public TraceInclusiveListCost
+{
+ public:
+ TraceCostItem();
+ virtual ~TraceCostItem();
+
+ virtual TQString name() const { return _name; }
+ virtual void setName(const TQString& name) { _name = name; }
+
+ protected:
+ bool onlyActiveParts() { return true; }
+
+ protected:
+ TQString _name;
+};
+
+
+/**
+ * Cost of a source region.
+ */
+class TraceLineRegion: public TraceInclusiveListCost
+{
+public:
+ TraceLineRegion(uint from, uint to, TQString name);
+ virtual ~TraceLineRegion();
+
+ virtual CostType type() const { return LineRegion; }
+ virtual void update();
+
+ uint from() const { return _from; }
+ uint to() const { return _to; }
+ TQString name() const { return _name; }
+
+ // factories
+ TracePartLine* partLineRegion(TracePart* part,
+ TracePartFunction* partFunction);
+ private:
+ uint _from, _to;
+ TQString _name;
+};
+
+
+/**
+ * A container helper class for TraceFunction for source lines
+ * where a function is implemented in.
+ * With inlining, lines of the same function can come from
+ * different source files.
+ * An instance of this class holds all lines of one source file
+ * for a function in a map
+ */
+class TraceFunctionSource: public TraceCost
+{
+public:
+ TraceFunctionSource(TraceFunction*, TraceFile*);
+ virtual ~TraceFunctionSource();
+
+ virtual CostType type() const { return FunctionSource; }
+ virtual TQString name() const;
+
+ // reimplementation for dependency map
+ virtual void update();
+
+ TraceFile* file() const { return _file; }
+ TraceFunction* function() const { return _function; }
+ uint firstLineno();
+ uint lastLineno();
+ TraceLineMap* lineMap();
+
+ void invalidateDynamicCost();
+
+ /* factories */
+ TraceLine* line(uint lineno, bool createNew = true);
+ TraceLineRegion* region(uint from, uint to, TQString name,
+ bool createNew = true);
+
+ private:
+ TraceFile* _file;
+ TraceFunction* _function;
+ TraceLineMap* _lineMap;
+ TraceLine* _line0;
+ TraceLineRegionList* _regions;
+
+ bool _lineMapFilled;
+};
+
+
+/**
+ * For temporary assoziation of objects with TraceFunctions.
+ * Used in coverage analysis and TreeMap drawing.
+ */
+class TraceAssoziation
+{
+ public:
+ /**
+ * Creates an invalid assoziation.
+ */
+ TraceAssoziation();
+ virtual ~TraceAssoziation();
+
+ // for runtime detection
+ virtual int rtti() { return 0; }
+
+ /**
+ * Could we set the function assoziation to ourself?
+ * This only can return false if this is a unique assoziation.
+ */
+ bool isAssoziated();
+
+ /**
+ * reset function to assoziate this object to.
+ * returns true if assoziation could be established
+ */
+ bool setFunction(TraceFunction*);
+ TraceFunction* function() { return _function; }
+
+ void invalidate() { _valid = false; }
+ bool isValid() { return _valid; }
+
+ /**
+ * Delete all assoziations in TraceFunctions of data with
+ * rtti runtime info. rtti = 0: delete ALL assoziations.
+ */
+ static void clear(TraceData* data, int rtti);
+
+ /**
+ * Invalidate all assoziations in TraceFunctions of data with
+ * rtti runtime info. rtti = 0: Invalidate ALL assoziations.
+ */
+ static void invalidate(TraceData* data, int rtti);
+
+ protected:
+ TraceFunction* _function;
+ bool _valid;
+};
+
+typedef TQPtrList<TraceAssoziation> TraceAssoziationList;
+typedef TQMap<TraceFunction*, TraceCall*> TraceCallMap;
+
+/**
+ * A traced function
+ *
+ * References to functions are stored in
+ * (1) a function map in TraceData (by value)
+ * (2) a TraceClass
+ */
+class TraceFunction: public TraceCostItem
+{
+ public:
+ TraceFunction();
+ TraceFunction(TraceData* data, const TQString& name,
+ TraceClass* cls, TraceFile* file, TraceObject* object);
+ virtual ~TraceFunction();
+
+ virtual CostType type() const { return Function; }
+ virtual void update();
+
+ // this invalidate all subcosts of function depending on
+ // active status of parts
+ void invalidateDynamicCost();
+
+ void addCaller(TraceCall*);
+
+ // factories
+ TraceCall* calling(TraceFunction* called);
+ TraceLine* line(TraceFile*, uint lineno, bool createNew = true);
+ TraceInstr* instr(Addr addr, bool createNew = true);
+ TracePartFunction* partFunction(TracePart*,
+ TracePartFile*, TracePartObject*);
+
+ /**
+ * Returns empty string if location is fully unknown.
+ * Use prettyLocation for single user-visible string.
+ * A function can have a lot of code from different sources (inlined);
+ * maxItems limits this list. Default is full list
+ */
+ TQString location(int maxFiles = 0) const;
+
+ TQString prettyName() const;
+ TQString prettyLocation(int maxFiles = 0) const;
+ TQString prettyNameWithLocation(int maxFiles = 1) const;
+ void addPrettyLocation(TQString&, int maxFiles = 1) const;
+ // type + name + location
+ TQString info() const;
+
+ TraceClass* cls() const { return _cls; }
+ TraceFile* file() const { return _file; }
+ TraceObject* object() const { return _object; }
+ // get the source file with lines from function declaration (not inlined)
+ TraceFunctionSource* sourceFile(TraceFile* file = 0,
+ bool createNew = false);
+ const TraceFunctionSourceList& sourceFiles() const
+ { return _sourceFiles; }
+ TraceCallList callers(bool skipCycle=false) const;
+ const TraceCallList& callings(bool skipCycle=false) const;
+
+ Addr firstAddress() const;
+ Addr lastAddress() const;
+ TraceInstrMap* instrMap();
+
+ // cost metrics
+ SubCost calledCount();
+ SubCost callingCount();
+ TQString prettyCalledCount();
+ TQString prettyCallingCount();
+ int calledContexts();
+ int callingContexts();
+
+ // only to be called after default constructor
+ void setFile(TraceFile* file) { _file = file; }
+ void setObject(TraceObject* object) { _object = object; }
+ void setClass(TraceClass* cls) { _cls = cls; }
+ void setMapIterator(TraceFunctionMap::Iterator it) { _myMapIterator = it; }
+
+ // see TraceFunctionAssoziation
+ void addAssoziation(TraceAssoziation* a);
+ void removeAssoziation(TraceAssoziation* a);
+ void removeAssoziation(int rtti, bool reallyDelete = true);
+ void invalidateAssoziation(int rtti);
+ TraceAssoziation* assoziation(int rtti);
+
+ // cycles
+ void setCycle(TraceFunctionCycle* c) { _cycle = c; }
+ TraceFunctionCycle* cycle() { return _cycle; }
+ bool isCycle();
+ bool isCycleMember();
+ void cycleReset();
+ void cycleDFS(int d, int& pNo, TraceFunction** pTop);
+
+ protected:
+ TraceCallList _callers; // list of calls we are called from
+ TraceCallList _callings; // list of calls we are calling (we are owner)
+ TraceCallMap _callingMap; // contains the same as _callings in a map
+ TraceFunctionCycle* _cycle;
+
+ private:
+ bool isUniquePrefix(TQString) const;
+ TraceFunctionMap::Iterator _myMapIterator;
+
+ TraceClass* _cls;
+ TraceObject* _object;
+ TraceFile* _file;
+
+ TraceFunctionSourceList _sourceFiles; // we are owner
+ TraceInstrMap* _instrMap; // we are owner
+ bool _instrMapFilled;
+
+ // see TraceAssoziation
+ TraceAssoziationList _assoziations;
+
+ // for cycle detection
+ int _cycleLow;
+ TraceFunction* _cycleStackDown;
+
+ // cached
+ SubCost _calledCount, _callingCount;
+ int _calledContexts, _callingContexts;
+};
+
+typedef TQMap<TraceFunction*,int> TraceFunctionSet;
+
+/**
+ * A cycle of recursive calling functions.
+ *
+ * This is itself shown as a function
+ */
+class TraceFunctionCycle: public TraceFunction
+{
+ public:
+ TraceFunctionCycle(TraceFunction*, int n);
+
+ virtual CostType type() const { return FunctionCycle; }
+
+ // this removes all members from this cycle
+ void init();
+ void add(TraceFunction*);
+ // this sets up the cycle once members are added
+ void setup();
+
+ TraceFunction* base() const { return _base; }
+ int cycleNo() const { return _cycleNo; }
+ const TraceFunctionList& members() const { return _members; }
+
+ private:
+ TraceFunction* _base;
+ int _cycleNo;
+
+ TraceFunctionList _members;
+ TraceFunctionSet _memberSet;
+};
+
+
+/**
+ * A C++ Class / Namespace
+ *
+ * If a function symbol has a prefix ending in "::",
+ * the prefix is supposed to be a class/namespace specifier.
+ * Without such a prefix, we put a symbol in the "(global)" namespace.
+ */
+class TraceClass: public TraceCostItem
+{
+ public:
+ TraceClass();
+ virtual ~TraceClass();
+
+ virtual CostType type() const { return Class; }
+ virtual TQString prettyName() const;
+
+ void addFunction(TraceFunction*);
+ const TraceFunctionList& functions() const { return _functions; }
+
+ // part factory
+ TracePartClass* partClass(TracePart*);
+
+ private:
+ TraceFunctionList _functions;
+};
+
+
+
+/**
+ * A source file containing function definitions
+ */
+class TraceFile: public TraceCostItem
+{
+ public:
+ TraceFile();
+ virtual ~TraceFile();
+
+ virtual CostType type() const { return File; }
+ void setDirectory(const TQString& dir);
+ void resetDirectory() { _dir = TQString(); }
+ TQString directory();
+
+ void addFunction(TraceFunction*);
+ void addSourceFile(TraceFunctionSource*);
+
+ // without path
+ TQString shortName() const;
+ TQString prettyName() const;
+ TQString prettyLongName() const;
+ const TraceFunctionList& functions() const { return _functions; }
+ const TraceFunctionSourceList& sourceFiles() const
+ { return _sourceFiles; }
+
+ // part factory
+ TracePartFile* partFile(TracePart*);
+
+ private:
+ TraceFunctionList _functions;
+ TraceFunctionSourceList _sourceFiles;
+ TQString _dir;
+};
+
+
+/**
+ * A object containing a text segment (shared lib/executable)
+ * with defined functions
+ */
+class TraceObject: public TraceCostItem
+{
+ public:
+ TraceObject();
+ virtual ~TraceObject();
+
+ virtual CostType type() const { return Object; }
+
+ void addFunction(TraceFunction*);
+
+ virtual void setName(const TQString& name);
+ TQString shortName() const { return _shortName; }
+ TQString prettyName() const;
+ const TraceFunctionList& functions() const { return _functions; }
+
+ // part factory
+ TracePartObject* partObject(TracePart*);
+
+ private:
+ TraceFunctionList _functions;
+ TQString _shortName;
+};
+
+
+
+/**
+ * This class holds profiling data of multiple tracefiles
+ * generated with cachegrind on one command.
+ *
+ */
+class TraceData: public TraceCost
+{
+ public:
+ TraceData(TopLevel* top = 0);
+ TraceData(const TQString& base);
+ virtual ~TraceData();
+
+ virtual CostType type() const { return Data; }
+ virtual TraceData* data() { return this; }
+ virtual const TraceData* data() const { return this; }
+
+ /**
+ * Loads a trace file.
+ *
+ * This adjusts the TraceCostMapping according to given cost types
+ */
+ void load(const TQString&);
+
+ /** returns true if something changed. These do NOT
+ * invalidate the dynamic costs on a activation change,
+ * i.e. all cost items dependend on active parts.
+ * This has to be done by the caller when true is returned by
+ * calling invalidateDynamicCost().
+ */
+ bool activateParts(const TracePartList&);
+ bool activateParts(TracePartList, bool active);
+ bool activatePart(TracePart*, bool active);
+ bool activateAll(bool active=true);
+
+ TracePartList parts() const { return _parts; }
+ TracePart* part(TQString& name);
+
+ // with path
+ TQString traceName() const { return _traceName; }
+
+ // without path
+ TQString shortTraceName() const;
+ TQString activePartRange();
+
+ TraceCostMapping* mapping() { return &_mapping; }
+
+ // memory pools
+ FixPool* fixPool();
+ DynPool* dynPool();
+
+ // factories for object/file/class/function/line instances
+ TraceObject* object(const TQString& name);
+ TraceFile* file(const TQString& name);
+ TraceClass* cls(const TQString& fnName, TQString& shortName);
+ // function creation involves class creation if needed
+ TraceFunction* function(const TQString& name, TraceFile*, TraceObject*);
+ // factory for function cycles
+ TraceFunctionCycle* functionCycle(TraceFunction*);
+
+ /**
+ * Search for item with given name and highest subcost of given cost type.
+ *
+ * For some items, they will only be found if the parent cost is given:
+ * Instr, Line, Call => need parent of type Function
+ * For Function, a parent of type Obj/File/Class can be given, but
+ * isn't needed.
+ */
+ TraceCost* search(TraceItem::CostType, TQString,
+ TraceCostType* ct = 0, TraceCost* parent = 0);
+
+ // for pretty function names without signature if unique...
+ TraceFunctionMap::Iterator functionIterator(TraceFunction*);
+ TraceFunctionMap::ConstIterator functionBeginIterator() const;
+ TraceFunctionMap::ConstIterator functionEndIterator() const;
+
+ TraceObjectMap& objectMap() { return _objectMap; }
+ TraceFileMap& fileMap() { return _fileMap; }
+ TraceClassMap& classMap() { return _classMap; }
+ TraceFunctionMap& functionMap() { return _functionMap; }
+
+ const TraceFunctionCycleList& functionCycles() { return _functionCycles; }
+
+ TraceCost* callMax() { return &_callMax; }
+
+ void setCommand(const TQString& command) { _command = command; }
+ TQString command() const { return _command; }
+ TraceCost* totals() { return &_totals; }
+ void setMaxThreadID(int tid) { _maxThreadID = tid; }
+ int maxThreadID() const { return _maxThreadID; }
+ void setMaxPartNumber(int n) { _maxPartNumber = n; }
+ int maxPartNumber() const { return _maxPartNumber; }
+
+ // reset all manually set directories for source files
+ void resetSourceDirs();
+
+ virtual void update();
+
+ // invalidates all cost items dependant on active state of parts
+ void invalidateDynamicCost();
+
+ // cycle detection
+ void updateFunctionCycles();
+ void updateObjectCycles();
+ void updateClassCycles();
+ void updateFileCycles();
+ bool inFunctionCycleUpdate() { return _inFunctionCycleUpdate; }
+
+ private:
+ void init();
+ // add trace part: events from one trace file
+ TracePart* addPart(const TQString& dir, const TQString& file);
+
+ // for progress bar callbacks
+ TopLevel* _topLevel;
+
+ TracePartList _parts;
+
+ // The mapping for all costs
+ TraceCostMapping _mapping;
+
+ FixPool* _fixPool;
+ DynPool* _dynPool;
+
+ // always the trace totals (not dependent on active parts)
+ TraceCost _totals;
+ int _maxThreadID;
+ int _maxPartNumber;
+
+ TraceObjectMap _objectMap;
+ TraceClassMap _classMap;
+ TraceFileMap _fileMap;
+ TraceFunctionMap _functionMap;
+ TQString _command;
+ TQString _traceName;
+
+ // Max of all costs of calls: This allows to see if the incl. cost can
+ // be hidden for a cost type, as it's always the same as self cost
+ TraceCost _callMax;
+
+ // cycles
+ TraceFunctionCycleList _functionCycles;
+ int _functionCycleCount;
+ bool _inFunctionCycleUpdate;
+};
+
+
+
+#endif
diff --git a/kdecachegrind/kdecachegrind/traceitemview.cpp b/kdecachegrind/kdecachegrind/traceitemview.cpp
new file mode 100644
index 0000000..d11f02b
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/traceitemview.cpp
@@ -0,0 +1,443 @@
+/* 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.
+*/
+
+/*
+ * Trace Item View
+ */
+
+#include <tqwidget.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "traceitemview.h"
+#include "toplevel.h"
+
+#define TRACE_UPDATES 0
+
+TraceItemView::TraceItemView(TraceItemView* parentView, TopLevel* top)
+{
+ _parentView = parentView;
+ _topLevel = top ? top : parentView->topLevel();
+
+ _data = _newData = 0;
+ // _partList and _newPartList is empty
+ _activeItem = _newActiveItem = 0;
+ _selectedItem = _newSelectedItem = 0;
+ _costType = _newCostType = 0;
+ _costType2 = _newCostType2 = 0;
+ _groupType = _newGroupType = TraceItem::NoCostType;
+
+ _status = nothingChanged;
+ _inUpdate = false;
+ _pos = Hidden;
+}
+
+TQString TraceItemView::whatsThis() const
+{
+ return i18n("No description available");
+}
+
+void TraceItemView::select(TraceItem* i)
+{
+ _newSelectedItem = i;
+}
+
+KConfigGroup* TraceItemView::configGroup(KConfig* c,
+ TQString group, TQString post)
+{
+ TQStringList gList = c->groupList();
+ if (gList.contains((group+post).ascii()) ) group += post;
+ return new KConfigGroup(c, group);
+}
+
+void TraceItemView::writeConfigEntry(KConfigBase* c, const char* pKey,
+ TQString value, const char* def, bool bNLS)
+{
+ if (!c) return;
+ if ((value.isEmpty() && ((def == 0) || (*def == 0))) ||
+ (value == TQString(def)))
+ c->deleteEntry(pKey);
+ else
+ c->writeEntry(pKey, value, true, false, bNLS);
+}
+
+void TraceItemView::writeConfigEntry(KConfigBase* c, const char* pKey,
+ int value, int def)
+{
+ if (!c) return;
+ if (value == def)
+ c->deleteEntry(pKey);
+ else
+ c->writeEntry(pKey, value);
+}
+
+void TraceItemView::writeConfigEntry(KConfigBase* c, const char* pKey,
+ double value, double def)
+{
+ if (!c) return;
+ if (value == def)
+ c->deleteEntry(pKey);
+ else
+ c->writeEntry(pKey, value);
+}
+
+void TraceItemView::writeConfigEntry(KConfigBase* c, const char* pKey,
+ bool value, bool def)
+{
+ if (!c) return;
+ if (value == def)
+ c->deleteEntry(pKey);
+ else
+ c->writeEntry(pKey, value);
+}
+
+void TraceItemView::readViewConfig(KConfig*, TQString, TQString, bool)
+{}
+
+#if 1
+void TraceItemView::saveViewConfig(KConfig*, TQString, TQString, bool)
+{}
+#else
+void TraceItemView::saveViewConfig(KConfig* c,
+ TQString prefix, TQString postfix, bool)
+{
+ // write a dummy config entry to see missing virtual functions
+ KConfigGroup g(c, (prefix+postfix).ascii());
+ g.writeEntry("SaveNotImplemented", true);
+}
+#endif
+
+bool TraceItemView::activate(TraceItem* i)
+{
+ i = canShow(i);
+ _newActiveItem = i;
+
+ return (i != 0);
+}
+
+TraceFunction* TraceItemView::activeFunction()
+{
+ TraceItem::CostType t = _activeItem->type();
+ switch(t) {
+ case TraceItem::Function:
+ case TraceItem::FunctionCycle:
+ return (TraceFunction*) _activeItem;
+ default:
+ break;
+ }
+ return 0;
+}
+
+bool TraceItemView::set(int changeType, TraceData* d,
+ TraceCostType* t1, TraceCostType* t2,
+ TraceItem::CostType g, const TracePartList& l,
+ TraceItem* a, TraceItem* s)
+{
+ _status |= changeType;
+ _newData = d;
+ _newGroupType = g;
+ _newCostType = t1;
+ _newCostType2 = t2;
+ _newPartList = l;
+ _newSelectedItem = s;
+ _newActiveItem = canShow(a);
+ if (!_newActiveItem) {
+ _newSelectedItem = 0;
+ return false;
+ }
+
+ return true;
+}
+
+
+bool TraceItemView::isViewVisible()
+{
+ TQWidget* w = widget();
+ if (w)
+ return w->isVisible();
+ return false;
+}
+
+void TraceItemView::setData(TraceData* d)
+{
+ _newData = d;
+
+ // invalidate all pointers to old data
+ _activeItem = _newActiveItem = 0;
+ _selectedItem = _newSelectedItem = 0;
+ _costType = _newCostType = 0;
+ _costType2 = _newCostType2 = 0;
+ _groupType = _newGroupType = TraceItem::NoCostType;
+ _partList.clear();
+ _newPartList.clear();
+
+ // updateView will change this to dataChanged
+ _status = nothingChanged;
+}
+
+void TraceItemView::updateView(bool force)
+{
+ if (!force && !isViewVisible()) return;
+
+ if (_newData != _data) {
+ _status |= dataChanged;
+ _data = _newData;
+ }
+ else {
+ _status &= ~dataChanged;
+
+ // if there's no data change and data is 0, no update needed
+ if (!_data) return;
+ }
+
+ if (!(_newPartList == _partList)) {
+ _status |= partsChanged;
+ _partList = _newPartList;
+ }
+ else
+ _status &= ~partsChanged;
+
+ if (_newActiveItem != _activeItem) {
+
+ // when setting a new active item, there's no selection
+ _selectedItem = 0;
+
+ _status |= activeItemChanged;
+ _activeItem = _newActiveItem;
+ }
+ else
+ _status &= ~activeItemChanged;
+
+ if (_newCostType != _costType) {
+ _status |= costTypeChanged;
+ _costType = _newCostType;
+ }
+ else
+ _status &= ~costTypeChanged;
+
+ if (_newCostType2 != _costType2) {
+ _status |= costType2Changed;
+ _costType2 = _newCostType2;
+ }
+ else
+ _status &= ~costType2Changed;
+
+ if (_newGroupType != _groupType) {
+ _status |= groupTypeChanged;
+ _groupType = _newGroupType;
+ }
+ else
+ _status &= ~groupTypeChanged;
+
+
+ if (_newSelectedItem != _selectedItem) {
+ _status |= selectedItemChanged;
+ _selectedItem = _newSelectedItem;
+ }
+ else
+ _status &= ~selectedItemChanged;
+
+
+ if (!force && (_status == nothingChanged)) return;
+
+#if TRACE_UPDATES
+ kdDebug() << (widget() ? widget()->name() : "TraceItemView")
+ << "::doUpdate ( "
+ << ((_status & dataChanged) ? "data ":"")
+ << ((_status & configChanged) ? "config ":"")
+ << ")" << endl;
+
+ if (_status & partsChanged)
+ kdDebug() << " Part List "
+ << _partList.names()
+ << endl;
+
+ if (_status & costTypeChanged)
+ kdDebug() << " Cost type "
+ << (_costType ? _costType->name().ascii() : "?")
+ << endl;
+
+ if (_status & costType2Changed)
+ kdDebug() << " Cost type 2 "
+ << (_costType2 ? _costType2->name().ascii() : "?")
+ << endl;
+
+ if (_status & groupTypeChanged)
+ kdDebug() << " Group type "
+ << TraceItem::typeName(_groupType)
+ << endl;
+
+ if (_status & activeItemChanged)
+ kdDebug() << " Active: "
+ << (_activeItem ? _activeItem->fullName().ascii() : "?")
+ << endl;
+
+ if (_status & selectedItemChanged)
+ kdDebug() << " Selected: "
+ << (_selectedItem ? _selectedItem->fullName().ascii() : "?")
+ << endl;
+#endif
+
+ int st = _status;
+ _status = nothingChanged;
+ doUpdate(st);
+ return;
+
+ if (_inUpdate) return;
+ _inUpdate = true;
+ doUpdate(_status);
+ _inUpdate = false;
+}
+
+
+void TraceItemView::selected(TraceItemView* /*sender*/, TraceItem* i)
+{
+#if TRACE_UPDATES
+ kdDebug() << (widget() ? widget()->name() : "TraceItemView")
+ << "::selected "
+ << (i ? i->name().ascii(): "(nil)")
+ << ", sender "
+ << sender->widget()->name() << endl;
+#endif
+
+ if (_parentView) _parentView->selected(this, i);
+}
+
+void TraceItemView::selected(TraceItemView* /*sender*/, const TracePartList& l)
+{
+#if TRACE_UPDATES
+ kdDebug() << (widget() ? widget()->name() : "TraceItemView")
+ << "::selected "
+ << l.names()
+ << ", sender "
+ << sender->widget()->name() << endl;
+#endif
+
+ if (_parentView)
+ _parentView->selected(this, l);
+ else
+ if (_topLevel) _topLevel->activePartsChangedSlot(l);
+}
+
+void TraceItemView::activated(TraceItemView* /*sender*/, TraceItem* i)
+{
+#if TRACE_UPDATES
+ kdDebug() << (widget() ? widget()->name() : "TraceItemView")
+ << "::activated "
+ << (i ? i->name().ascii(): "(nil)")
+ << ", sender "
+ << sender->widget()->name() << endl;
+#endif
+
+ if (_parentView)
+ _parentView->activated(this, i);
+ else
+ if (_topLevel) _topLevel->setTraceItemDelayed(i);
+}
+
+void TraceItemView::selectedCostType(TraceItemView*, TraceCostType* t)
+{
+ if (_parentView)
+ _parentView->selectedCostType(this, t);
+ else
+ if (_topLevel) _topLevel->setCostTypeDelayed(t);
+}
+
+void TraceItemView::selectedCostType2(TraceItemView*, TraceCostType* t)
+{
+ if (_parentView)
+ _parentView->selectedCostType2(this, t);
+ else
+ if (_topLevel) _topLevel->setCostType2Delayed(t);
+}
+
+void TraceItemView::activated(TraceItemView*, Direction d)
+{
+ if (_parentView)
+ _parentView->activated(this, d);
+ else
+ if (_topLevel) _topLevel->setDirectionDelayed(d);
+}
+
+void TraceItemView::doUpdate(int)
+{
+}
+
+void TraceItemView::selected(TraceItem* i)
+{
+ if (_parentView)
+ _parentView->selected(this, i);
+
+}
+
+void TraceItemView::selected(const TracePartList& l)
+{
+ if (_parentView)
+ _parentView->selected(this, l);
+ else
+ if (_topLevel) _topLevel->activePartsChangedSlot(l);
+}
+
+void TraceItemView::activated(TraceItem* i)
+{
+#if TRACE_UPDATES
+ kdDebug() << (widget() ? widget()->name() : "TraceItemView")
+ << "::activated "
+ << (i ? i->name().ascii(): "(nil)") << endl;
+#endif
+
+ if (_parentView)
+ _parentView->activated(this, i);
+ else
+ if (_topLevel) _topLevel->setTraceItemDelayed(i);
+}
+
+void TraceItemView::selectedCostType(TraceCostType* t)
+{
+ if (_parentView)
+ _parentView->selectedCostType(this, t);
+ else
+ if (_topLevel) _topLevel->setCostTypeDelayed(t);
+}
+
+void TraceItemView::selectedCostType2(TraceCostType* t)
+{
+ if (_parentView)
+ _parentView->selectedCostType2(this, t);
+ else
+ if (_topLevel) _topLevel->setCostType2Delayed(t);
+}
+
+void TraceItemView::activated(Direction d)
+{
+ if (_parentView)
+ _parentView->activated(this, d);
+ else
+ if (_topLevel) _topLevel->setDirectionDelayed(d);
+}
+
+void TraceItemView::addCostMenu(TQPopupMenu* p, bool withCost2)
+{
+ if (_topLevel) _topLevel->addCostMenu(p, withCost2);
+}
+
+void TraceItemView::addGoMenu(TQPopupMenu* p)
+{
+ if (_topLevel) _topLevel->addGoMenu(p);
+}
diff --git a/kdecachegrind/kdecachegrind/traceitemview.h b/kdecachegrind/kdecachegrind/traceitemview.h
new file mode 100644
index 0000000..f83aa89
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/traceitemview.h
@@ -0,0 +1,206 @@
+/* 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.
+*/
+
+/*
+ * Trace Item View
+ */
+
+#ifndef TRACEITEMVIEW_H
+#define TRACEITEMVIEW_H
+
+#include "tracedata.h"
+
+class TQWidget;
+class TQPopupMenu;
+
+class KConfig;
+class KConfigGroup;
+class KConfigBase;
+
+class TopLevel;
+
+/**
+ * Abstract Base Class for KCachegrind Views
+ *
+ * This class delivers the shared functionality of all KCachegrind
+ * Views for one TraceItem (like Function, Object...), the "active"
+ * item. Additional view attributes are current primary cost type,
+ * an optional secondary cost type, group type,
+ * and possibly a selected costitem in this view.
+ * Note that there is a difference in changing the selected item of
+ * a view (this usually changes selection in other views, too), and
+ * activating that item.
+ */
+class TraceItemView
+{
+public:
+
+ /**
+ * Change type for update functions
+ * - <dataChanged> is used if e.g. cycles are recalculated
+ */
+ enum { nothingChanged = 0,
+ costTypeChanged = 1,
+ costType2Changed = 2,
+ groupTypeChanged = 4,
+ partsChanged = 8,
+ activeItemChanged = 16,
+ selectedItemChanged = 32,
+ dataChanged = 64,
+ configChanged = 128 };
+
+ enum Direction { None, Back, Forward, Up };
+
+ // a TraceItemView can have a position in a parent container
+ enum Position { Hidden, Top, Right, Left, Bottom };
+
+ TraceItemView(TraceItemView* parentView, TopLevel* top = 0);
+ virtual ~TraceItemView() {}
+
+ virtual TQString whatsThis() const;
+
+ static KConfigGroup* configGroup(KConfig*, TQString prefix, TQString postfix);
+ static void writeConfigEntry(KConfigBase*, const char* pKey, TQString value,
+ const char* def, bool bNLS = false);
+ static void writeConfigEntry(KConfigBase*, const char* pKey,
+ int value, int def);
+ static void writeConfigEntry(KConfigBase*, const char* pKey,
+ bool value, bool def);
+ static void writeConfigEntry(KConfigBase*, const char* pKey,
+ double value, double def);
+ virtual void readViewConfig(KConfig*, TQString prefix, TQString postfix,
+ bool withOptions);
+ virtual void saveViewConfig(KConfig*, TQString prefix, TQString postfix,
+ bool withOptions);
+
+ // Immediate remove all references to old data, and set the new.
+ // This resets the visualization state.
+ // A GUI update has to be triggered with updateView().
+ // Overwrite in container views to also set new data for all members.
+ virtual void setData(TraceData* d);
+
+ // change from parent, call updateView() to update lazily (only if visible)
+ void setCostType(TraceCostType* t) { _newCostType = t; }
+ void setCostType2(TraceCostType* t) { _newCostType2 = t; }
+ void set(TraceItem::CostType g) { _newGroupType = g; }
+ void set(const TracePartList& l) { _newPartList = l; }
+ // returns false if nothing can be shown for this trace item
+ bool activate(TraceItem* i);
+ void select(TraceItem* i);
+ void notifyChange(int changeType) { _status |= changeType; }
+ // all in one
+ bool set(int, TraceData*, TraceCostType*, TraceCostType*,
+ TraceItem::CostType, const TracePartList&,
+ TraceItem*, TraceItem*);
+
+ // general update request, call if view is/gets visible
+ void updateView(bool force = false);
+
+ /**
+ * Notification from child views.
+ * Default implementation notifies parent
+ */
+ virtual void selected(TraceItemView* sender, TraceItem*);
+ virtual void selected(TraceItemView* sender, const TracePartList&);
+ virtual void activated(TraceItemView* sender, Direction);
+ virtual void selectedCostType(TraceItemView* sender, TraceCostType*);
+ virtual void selectedCostType2(TraceItemView* sender, TraceCostType*);
+ virtual void activated(TraceItemView* sender, TraceItem*);
+
+ // getters...
+ // always get the newest values
+ TraceData* data() const { return _newData; }
+ TraceItem* activeItem() const { return _newActiveItem; }
+ TraceItem* selectedItem() const { return _newSelectedItem; }
+ TraceCostType* costType() const { return _newCostType; }
+ TraceCostType* costType2() const { return _newCostType2; }
+ TraceItem::CostType groupType() const { return _newGroupType; }
+ const TracePartList& partList() const { return _newPartList; }
+
+ TraceFunction* activeFunction();
+ int status() const { return _status; }
+
+ // pointer to top level window to e.g. show status messages
+ void setTopLevel(TopLevel* t) { _topLevel = t; }
+ TopLevel* topLevel() const { return _topLevel; }
+
+ void setPosition(Position p) { _pos = p; }
+ Position position() const { return _pos; }
+
+ void setTitle(TQString t) { _title = t; }
+ TQString title() const { return _title; }
+
+ // We depend on derived class to be a widget.
+ // Force overiding by making this abstract.
+ virtual TQWidget* widget() = 0;
+
+ /**
+ * This function is called when a new item should become active.
+ * Reimplement this in subclasses.
+ *
+ * Returns the real item to become active. You can call select() here.
+ * Return 0 if nothing can be shown.
+ * Use the methods like data() instead of _data here, as
+ * _data possibly will give old/wrong information.
+ */
+ virtual TraceItem* canShow(TraceItem* i) { return i; }
+
+ /* convenience functions for often used context menu items */
+ void addCostMenu(TQPopupMenu*,bool withCost2 = true);
+ void addGoMenu(TQPopupMenu*);
+
+protected:
+ // helpers to call selected()/activated() of parentView
+ void selected(TraceItem*);
+ void selected(const TracePartList&);
+ void activated(TraceItem*);
+ void selectedCostType(TraceCostType*);
+ void selectedCostType2(TraceCostType*);
+ void activated(Direction);
+
+ /* Is this view visible?
+ * if not, doUpdate() won't be called by updateView()
+ */
+ virtual bool isViewVisible();
+
+ // update handler (to be reimplemented)
+ virtual void doUpdate(int changeType);
+
+ TraceItemView* _parentView;
+ TopLevel* _topLevel;
+
+ TraceData* _data;
+ TracePartList _partList;
+ TraceItem *_activeItem, *_selectedItem;
+ TraceCostType *_costType, *_costType2;
+ TraceItem::CostType _groupType;
+
+private:
+ TraceData* _newData;
+ TracePartList _newPartList;
+ TraceItem *_newActiveItem, *_newSelectedItem;
+ TraceCostType *_newCostType, *_newCostType2;
+ TraceItem::CostType _newGroupType;
+
+ TQString _title;
+ int _status;
+ bool _inUpdate;
+ Position _pos;
+};
+
+#endif
diff --git a/kdecachegrind/kdecachegrind/treemap.cpp b/kdecachegrind/kdecachegrind/treemap.cpp
new file mode 100644
index 0000000..0d4b8dc
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/treemap.cpp
@@ -0,0 +1,3214 @@
+/* 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.
+*/
+
+/*
+ * A Widget for visualizing hierarchical metrics as areas.
+ * The API is similar to TQListView.
+ */
+
+#include <math.h>
+
+#include <tqpainter.h>
+#include <tqtooltip.h>
+#include <tqregexp.h>
+#include <tqstyle.h>
+#include <tqpopupmenu.h>
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <kdebug.h>
+
+#include "treemap.h"
+
+
+// set this to 1 to enable debug output
+#define DEBUG_DRAWING 0
+#define MAX_FIELD 12
+
+
+//
+// StoredDrawParams
+//
+StoredDrawParams::StoredDrawParams()
+{
+ _selected = false;
+ _current = false;
+ _shaded = true;
+ _rotated = false;
+
+ _backColor = TQt::white;
+
+ // field array has size 0
+}
+
+StoredDrawParams::StoredDrawParams(TQColor c,
+ bool selected, bool current)
+{
+ _backColor = c;
+
+ _selected = selected;
+ _current = current;
+ _shaded = true;
+ _rotated = false;
+ _drawFrame = true;
+
+ // field array has size 0
+}
+
+TQString StoredDrawParams::text(int f) const
+{
+ if ((f<0) || (f >= (int)_field.size()))
+ return TQString();
+
+ return _field[f].text;
+}
+
+TQPixmap StoredDrawParams::pixmap(int f) const
+{
+ if ((f<0) || (f >= (int)_field.size()))
+ return TQPixmap();
+
+ return _field[f].pix;
+}
+
+DrawParams::Position StoredDrawParams::position(int f) const
+{
+ if ((f<0) || (f >= (int)_field.size()))
+ return Default;
+
+ return _field[f].pos;
+}
+
+int StoredDrawParams::maxLines(int f) const
+{
+ if ((f<0) || (f >= (int)_field.size()))
+ return 0;
+
+ return _field[f].maxLines;
+}
+
+const TQFont& StoredDrawParams::font() const
+{
+ static TQFont* f = 0;
+ if (!f) f = new TQFont(TQApplication::font());
+
+ return *f;
+}
+
+void StoredDrawParams::ensureField(int f)
+{
+ static Field* def = 0;
+ if (!def) {
+ def = new Field();
+ def->pos = Default;
+ def->maxLines = 0;
+ }
+
+ if (f<0 || f>=MAX_FIELD) return;
+
+ if ((int)_field.size() < f+1) _field.resize(f+1, *def);
+}
+
+
+void StoredDrawParams::setField(int f, const TQString& t, TQPixmap pm,
+ Position p, int maxLines)
+{
+ if (f<0 || f>=MAX_FIELD) return;
+ ensureField(f);
+
+ _field[f].text = t;
+ _field[f].pix = pm;
+ _field[f].pos = p;
+ _field[f].maxLines = maxLines;
+}
+
+void StoredDrawParams::setText(int f, const TQString& t)
+{
+ if (f<0 || f>=MAX_FIELD) return;
+ ensureField(f);
+
+ _field[f].text = t;
+}
+
+void StoredDrawParams::setPixmap(int f, const TQPixmap& pm)
+{
+ if (f<0 || f>=MAX_FIELD) return;
+ ensureField(f);
+
+ _field[f].pix = pm;
+}
+
+void StoredDrawParams::setPosition(int f, Position p)
+{
+ if (f<0 || f>=MAX_FIELD) return;
+ ensureField(f);
+
+ _field[f].pos = p;
+}
+
+void StoredDrawParams::setMaxLines(int f, int m)
+{
+ if (f<0 || f>=MAX_FIELD) return;
+ ensureField(f);
+
+ _field[f].maxLines = m;
+}
+
+
+
+//
+// RectDrawing
+//
+
+RectDrawing::RectDrawing(TQRect r)
+{
+ _fm = 0;
+ _dp = 0;
+ setRect(r);
+}
+
+
+RectDrawing::~RectDrawing()
+{
+ delete _fm;
+ delete _dp;
+}
+
+DrawParams* RectDrawing::drawParams()
+{
+ if (!_dp)
+ _dp = new StoredDrawParams();
+
+ return _dp;
+}
+
+
+void RectDrawing::setDrawParams(DrawParams* dp)
+{
+ if (_dp) delete _dp;
+ _dp = dp;
+}
+
+void RectDrawing::setRect(TQRect r)
+{
+ _rect = r;
+
+ _usedTopLeft = 0;
+ _usedTopCenter = 0;
+ _usedTopRight = 0;
+ _usedBottomLeft = 0;
+ _usedBottomCenter = 0;
+ _usedBottomRight = 0;
+
+ _fontHeight = 0;
+}
+
+TQRect RectDrawing::remainingRect(DrawParams* dp)
+{
+ if (!dp) dp = drawParams();
+
+ if ((_usedTopLeft >0) ||
+ (_usedTopCenter >0) ||
+ (_usedTopRight >0)) {
+ if (dp->rotated())
+ _rect.setLeft(_rect.left() + _fontHeight);
+ else
+ _rect.setTop(_rect.top() + _fontHeight);
+ }
+
+ if ((_usedBottomLeft >0) ||
+ (_usedBottomCenter >0) ||
+ (_usedBottomRight >0)) {
+ if (dp->rotated())
+ _rect.setRight(_rect.right() - _fontHeight);
+ else
+ _rect.setBottom(_rect.bottom() - _fontHeight);
+ }
+ return _rect;
+}
+
+
+void RectDrawing::drawBack(TQPainter* p, DrawParams* dp)
+{
+ if (!dp) dp = drawParams();
+ if (_rect.width()<=0 || _rect.height()<=0) return;
+
+ TQRect r = _rect;
+ TQColor normal = dp->backColor();
+ if (dp->selected()) normal = normal.light();
+ bool isCurrent = dp->current();
+
+ if (dp->drawFrame() || isCurrent) {
+ // 3D raised/sunken frame effect...
+ TQColor high = normal.light();
+ TQColor low = normal.dark();
+ p->setPen( isCurrent ? low:high);
+ p->drawLine(r.left(), r.top(), r.right(), r.top());
+ p->drawLine(r.left(), r.top(), r.left(), r.bottom());
+ p->setPen( isCurrent ? high:low);
+ p->drawLine(r.right(), r.top(), r.right(), r.bottom());
+ p->drawLine(r.left(), r.bottom(), r.right(), r.bottom());
+ r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
+ }
+ if (r.width()<=0 || r.height()<=0) return;
+
+ if (dp->shaded()) {
+ // some shading
+ bool goDark = tqGray(normal.rgb())>128;
+ int rBase, gBase, bBase;
+ normal.rgb(&rBase, &gBase, &bBase);
+ p->setBrush(TQBrush::NoBrush);
+
+ // shade parameters:
+ int d = 7;
+ float factor = 0.1, forth=0.7, back1 =0.9, toBack2 = .7, back2 = 0.97;
+
+ // coefficient corrections because of rectangle size
+ int s = r.width();
+ if (s > r.height()) s = r.height();
+ if (s<100) {
+ forth -= .3 * (100-s)/100;
+ back1 -= .2 * (100-s)/100;
+ back2 -= .02 * (100-s)/100;
+ }
+
+
+ // maximal color difference
+ int rDiff = goDark ? -rBase/d : (255-rBase)/d;
+ int gDiff = goDark ? -gBase/d : (255-gBase)/d;
+ int bDiff = goDark ? -bBase/d : (255-bBase)/d;
+
+ TQColor shadeColor;
+ while (factor<.95) {
+ shadeColor.setRgb((int)(rBase+factor*rDiff+.5),
+ (int)(gBase+factor*gDiff+.5),
+ (int)(bBase+factor*bDiff+.5));
+ p->setPen(shadeColor);
+ p->drawRect(r);
+ r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
+ if (r.width()<=0 || r.height()<=0) return;
+ factor = 1.0 - ((1.0 - factor) * forth);
+ }
+
+ // and back (1st half)
+ while (factor>toBack2) {
+ shadeColor.setRgb((int)(rBase+factor*rDiff+.5),
+ (int)(gBase+factor*gDiff+.5),
+ (int)(bBase+factor*bDiff+.5));
+ p->setPen(shadeColor);
+ p->drawRect(r);
+ r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
+ if (r.width()<=0 || r.height()<=0) return;
+ factor = 1.0 - ((1.0 - factor) / back1);
+ }
+
+ // and back (2nd half)
+ while ( factor>.01) {
+ shadeColor.setRgb((int)(rBase+factor*rDiff+.5),
+ (int)(gBase+factor*gDiff+.5),
+ (int)(bBase+factor*bDiff+.5));
+ p->setPen(shadeColor);
+ p->drawRect(r);
+ r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
+ if (r.width()<=0 || r.height()<=0) return;
+
+ factor = factor * back2;
+ }
+ }
+
+ // fill inside
+ p->setPen(TQPen::NoPen);
+ p->setBrush(normal);
+ p->drawRect(r);
+}
+
+
+bool RectDrawing::drawField(TQPainter* p, int f, DrawParams* dp)
+{
+ if (!dp) dp = drawParams();
+
+ if (!_fm) {
+ _fm = new TQFontMetrics(dp->font());
+ _fontHeight = _fm->height();
+ }
+
+ TQRect r = _rect;
+
+ if (0) kdDebug(90100) << "DrawField: Rect " << r.x() << "/" << r.y()
+ << " - " << r.width() << "x" << r.height() << endl;
+
+ int h = _fontHeight;
+ bool rotate = dp->rotated();
+ int width = (rotate ? r.height() : r.width()) -4;
+ int height = (rotate ? r.width() : r.height());
+ int lines = height / h;
+
+ // stop if we have no space available
+ if (lines<1) return false;
+
+ // calculate free space in first line (<unused>)
+ int pos = dp->position(f);
+ if (pos == DrawParams::Default) {
+ switch(f%4) {
+ case 0: pos = DrawParams::TopLeft; break;
+ case 1: pos = DrawParams::TopRight; break;
+ case 2: pos = DrawParams::BottomRight; break;
+ case 3: pos = DrawParams::BottomLeft; break;
+ }
+ }
+
+ int unused = 0;
+ bool isBottom = false;
+ bool isCenter = false;
+ bool isRight = false;
+ int* used = 0;
+ switch(pos) {
+ case DrawParams::TopLeft:
+ used = &_usedTopLeft;
+ if (_usedTopLeft == 0) {
+ if (_usedTopCenter)
+ unused = (width - _usedTopCenter)/2;
+ else
+ unused = width - _usedTopRight;
+ }
+ break;
+
+ case DrawParams::TopCenter:
+ isCenter = true;
+ used = &_usedTopCenter;
+ if (_usedTopCenter == 0) {
+ if (_usedTopLeft > _usedTopRight)
+ unused = width - 2 * _usedTopLeft;
+ else
+ unused = width - 2 * _usedTopRight;
+ }
+ break;
+
+ case DrawParams::TopRight:
+ isRight = true;
+ used = &_usedTopRight;
+ if (_usedTopRight == 0) {
+ if (_usedTopCenter)
+ unused = (width - _usedTopCenter)/2;
+ else
+ unused = width - _usedTopLeft;
+ }
+ break;
+
+ case DrawParams::BottomLeft:
+ isBottom = true;
+ used = &_usedBottomLeft;
+ if (_usedBottomLeft == 0) {
+ if (_usedBottomCenter)
+ unused = (width - _usedBottomCenter)/2;
+ else
+ unused = width - _usedBottomRight;
+ }
+ break;
+
+ case DrawParams::BottomCenter:
+ isCenter = true;
+ isBottom = true;
+ used = &_usedBottomCenter;
+ if (_usedBottomCenter == 0) {
+ if (_usedBottomLeft > _usedBottomRight)
+ unused = width - 2 * _usedBottomLeft;
+ else
+ unused = width - 2 * _usedBottomRight;
+ }
+ break;
+
+ case DrawParams::BottomRight:
+ isRight = true;
+ isBottom = true;
+ used = &_usedBottomRight;
+ if (_usedBottomRight == 0) {
+ if (_usedBottomCenter)
+ unused = (width - _usedBottomCenter)/2;
+ else
+ unused = width - _usedBottomLeft;
+ }
+ break;
+ }
+
+ if (isBottom) {
+ if ((_usedTopLeft >0) ||
+ (_usedTopCenter >0) ||
+ (_usedTopRight >0))
+ lines--;
+ }
+ else if (!isBottom) {
+ if ((_usedBottomLeft >0) ||
+ (_usedBottomCenter >0) ||
+ (_usedBottomRight >0))
+ lines--;
+ }
+ if (lines<1) return false;
+
+
+ int y = isBottom ? height - h : 0;
+
+ if (unused < 0) unused = 0;
+ if (unused == 0) {
+ // no space available in last line at this position
+ y = isBottom ? (y-h) : (y+h);
+ lines--;
+
+ if (lines<1) return false;
+
+ // new line: reset used space
+ if (isBottom)
+ _usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0;
+ else
+ _usedTopLeft = _usedTopCenter = _usedTopRight = 0;
+
+ unused = width;
+ }
+
+ // stop as soon as possible when there's no space for "..."
+ static int dotW = 0;
+ if (!dotW) dotW = _fm->width("...");
+ if (width < dotW) return false;
+
+ // get text and pixmap now, only if we need to, because it is possible
+ // that they are calculated on demand (and this can take some time)
+ TQString name = dp->text(f);
+ if (name.isEmpty()) return 0;
+ TQPixmap pix = dp->pixmap(f);
+
+ // check if pixmap can be drawn
+ int pixW = pix.width();
+ int pixH = pix.height();
+ int pixY = 0;
+ bool pixDrawn = true;
+ if (pixW>0) {
+ pixW += 2; // X distance from pix
+ if ((width < pixW + dotW) || (height < pixH)) {
+ // don't draw
+ pixW = 0;
+ }
+ else
+ pixDrawn = false;
+ }
+
+ // width of text and pixmap to be drawn
+ int w = pixW + _fm->width(name);
+
+ if (0) kdDebug(90100) << " For '" << name << "': Unused " << unused
+ << ", StrW " << w << ", Width " << width << endl;
+
+ // if we have limited space at 1st line:
+ // use it only if whole name does fit in last line...
+ if ((unused < width) && (w > unused)) {
+ y = isBottom ? (y-h) : (y+h);
+ lines--;
+
+ if (lines<1) return false;
+
+ // new line: reset used space
+ if (isBottom)
+ _usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0;
+ else
+ _usedTopLeft = _usedTopCenter = _usedTopRight = 0;
+ }
+
+ p->save();
+ p->setPen( (tqGray(dp->backColor().rgb())>100) ? TQt::black : TQt::white);
+ p->setFont(dp->font());
+ if (rotate) {
+ //p->translate(r.x()+2, r.y()+r.height());
+ p->translate(r.x(), r.y()+r.height()-2);
+ p->rotate(270);
+ }
+ else
+ p->translate(r.x()+2, r.y());
+
+
+ // adjust available lines according to maxLines
+ int max = dp->maxLines(f);
+ if ((max > 0) && (lines>max)) lines = max;
+
+ /* loop over name parts to break up string depending on available width.
+ * every char category change is supposed a possible break,
+ * with the exception Uppercase=>Lowercase.
+ * It's good enough for numbers, Symbols...
+ *
+ * If the text is to be written at the bottom, we start with the
+ * end of the string (so everything is reverted)
+ */
+ TQString remaining;
+ int origLines = lines;
+ while (lines>0) {
+
+ if (w>width && lines>1) {
+ int lastBreakPos = name.length(), lastWidth = w;
+ int len = name.length();
+ TQChar::Category caOld, ca;
+
+ if (!isBottom) {
+ // start with comparing categories of last 2 chars
+ caOld = name[len-1].category();
+ while (len>2) {
+ len--;
+ ca = name[len-1].category();
+ if (ca != caOld) {
+ // "Aa" has no break between...
+ if (ca == TQChar::Letter_Uppercase &&
+ caOld == TQChar::Letter_Lowercase) {
+ caOld = ca;
+ continue;
+ }
+ caOld = ca;
+ lastBreakPos = len;
+ w = pixW + _fm->width(name, len);
+ lastWidth = w;
+ if (w <= width) break;
+ }
+ }
+ w = lastWidth;
+ remaining = name.mid(lastBreakPos);
+ // remove space on break point
+ if (name[lastBreakPos-1].category() == TQChar::Separator_Space)
+ name = name.left(lastBreakPos-1);
+ else
+ name = name.left(lastBreakPos);
+ }
+ else { // bottom
+ int l = len;
+ caOld = name[l-len].category();
+ while (len>2) {
+ len--;
+ ca = name[l-len].category();
+
+ if (ca != caOld) {
+ // "Aa" has no break between...
+ if (caOld == TQChar::Letter_Uppercase &&
+ ca == TQChar::Letter_Lowercase) {
+ caOld = ca;
+ continue;
+ }
+ caOld = ca;
+ lastBreakPos = len;
+ w = pixW + _fm->width(name.right(len));
+ lastWidth = w;
+ if (w <= width) break;
+ }
+ }
+ w = lastWidth;
+ remaining = name.left(l-lastBreakPos);
+ // remove space on break point
+ if (name[l-lastBreakPos].category() == TQChar::Separator_Space)
+ name = name.right(lastBreakPos-1);
+ else
+ name = name.right(lastBreakPos);
+ }
+ }
+ else
+ remaining = TQString();
+
+ /* truncate and add ... if needed */
+ if (w>width) {
+ int len = name.length();
+ w += dotW;
+ while (len>2 && (w > width)) {
+ len--;
+ w = pixW + _fm->width(name, len) + dotW;
+ }
+ // stop drawing: we cannot draw 2 chars + "..."
+ if (w>width) break;
+
+ name = name.left(len) + "...";
+ }
+
+ int x = 0;
+ if (isCenter)
+ x = (width - w)/2;
+ else if (isRight)
+ x = width - w;
+
+ if (!pixDrawn) {
+ pixY = y+(h-pixH)/2; // default: center vertically
+ if (pixH > h) pixY = isBottom ? y-(pixH-h) : y;
+
+ p->drawPixmap( x, pixY, pix);
+
+ // for distance to next text
+ pixY = isBottom ? (pixY - h - 2) : (pixY + pixH + 2);
+ pixDrawn = true;
+ }
+
+
+ if (0) kdDebug(90100) << " Drawing '" << name << "' at "
+ << x+pixW << "/" << y << endl;
+
+ p->drawText( x+pixW, y,
+ width - pixW, h,
+ TQt::AlignLeft, name);
+ y = isBottom ? (y-h) : (y+h);
+ lines--;
+
+ if (remaining.isEmpty()) break;
+ name = remaining;
+ w = pixW + _fm->width(name);
+ }
+
+ // make sure the pix stays visible
+ if (pixDrawn && (pixY>0)) {
+ if (isBottom && (pixY<y)) y = pixY;
+ if (!isBottom && (pixY>y)) y = pixY;
+ }
+
+ if (origLines > lines) {
+ // if only 1 line written, don't reset _used* vars
+ if (lines - origLines >1) {
+ if (isBottom)
+ _usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0;
+ else
+ _usedTopLeft = _usedTopCenter = _usedTopRight = 0;
+ }
+
+ // take back one line
+ y = isBottom ? (y+h) : (y-h);
+ if (used) *used = w;
+ }
+
+ // update free space
+ if (!isBottom) {
+ if (rotate)
+ _rect.setRect(r.x()+y, r.y(), r.width()-y, r.height());
+ else
+ _rect.setRect(r.x(), r.y()+y, r.width(), r.height()-y);
+ }
+ else {
+ if (rotate)
+ _rect.setRect(r.x(), r.y(), y+h, r.height());
+ else
+ _rect.setRect(r.x(), r.y(), r.width(), y+h);
+ }
+
+ p->restore();
+
+ return true;
+}
+
+
+
+
+
+
+//
+// TreeMapItemList
+//
+
+int TreeMapItemList::compareItems ( Item item1, Item item2 )
+{
+ bool ascending;
+ int result;
+
+ TreeMapItem* parent = ((TreeMapItem*)item1)->parent();
+ // shouldn't happen
+ if (!parent) return 0;
+
+ int textNo = parent->sorting(&ascending);
+
+ if (textNo < 0) {
+ double diff = ((TreeMapItem*)item1)->value() -
+ ((TreeMapItem*)item2)->value();
+ result = (diff < -.9) ? -1 : (diff > .9) ? 1 : 0;
+ }
+ else
+ result = (((TreeMapItem*)item1)->text(textNo) <
+ ((TreeMapItem*)item2)->text(textNo)) ? -1 : 1;
+
+ return ascending ? result : -result;
+}
+
+
+TreeMapItem* TreeMapItemList::commonParent()
+{
+ TreeMapItem* parent, *item;
+ parent = first();
+ if (parent)
+ while( (item = next()) != 0)
+ parent = parent->commonParent(item);
+
+ return parent;
+}
+
+
+// TreeMapItem
+
+TreeMapItem::TreeMapItem(TreeMapItem* parent, double value)
+{
+ _value = value;
+ _parent = parent;
+
+ _sum = 0;
+ _children = 0;
+ _widget = 0;
+ _index = -1;
+ _depth = -1; // not set
+ _unused_self = 0;
+ _freeRects = 0;
+
+ if (_parent) {
+ // take sorting from parent
+ _sortTextNo = _parent->sorting(&_sortAscending);
+ _parent->addItem(this);
+ }
+ else {
+ _sortAscending = false;
+ _sortTextNo = -1; // default: no sorting
+ }
+}
+
+
+TreeMapItem::TreeMapItem(TreeMapItem* parent, double value,
+ TQString text1, TQString text2,
+ TQString text3, TQString text4)
+{
+ _value = value;
+ _parent = parent;
+
+ // this resizes the text vector only if needed
+ if (!text4.isEmpty()) setText(3, text4);
+ if (!text3.isEmpty()) setText(2, text3);
+ if (!text2.isEmpty()) setText(1, text2);
+ setText(0, text1);
+
+ _sum = 0;
+ _children = 0;
+ _widget = 0;
+ _index = -1;
+ _depth = -1; // not set
+ _unused_self = 0;
+ _freeRects = 0;
+
+ if (_parent) _parent->addItem(this);
+}
+
+TreeMapItem::~TreeMapItem()
+{
+ if (_children) delete _children;
+ if (_freeRects) delete _freeRects;
+
+ // finally, notify widget about deletion
+ if (_widget) _widget->deletingItem(this);
+}
+
+void TreeMapItem::setParent(TreeMapItem* p)
+{
+ _parent = p;
+ if (p) _widget = p->_widget;
+}
+
+bool TreeMapItem::isChildOf(TreeMapItem* item)
+{
+ if (!item) return false;
+
+ TreeMapItem* i = this;
+ while (i) {
+ if (item == i) return true;
+ i = i->_parent;
+ }
+ return false;
+}
+
+TreeMapItem* TreeMapItem::commonParent(TreeMapItem* item)
+{
+ while (item && !isChildOf(item)) {
+ item = item->parent();
+ }
+ return item;
+}
+
+void TreeMapItem::redraw()
+{
+ if (_widget)
+ _widget->redraw(this);
+}
+
+void TreeMapItem::clear()
+{
+ if (_children) {
+ // delete selected items below this item from selection
+ if (_widget) _widget->clearSelection(this);
+
+ delete _children;
+ _children = 0;
+ }
+}
+
+
+// invalidates current children and forces redraw
+// this is only usefull when children are created on demand in items()
+void TreeMapItem::refresh()
+{
+ clear();
+ redraw();
+}
+
+
+TQStringList TreeMapItem::path(int textNo) const
+{
+ TQStringList list(text(textNo));
+
+ TreeMapItem* i = _parent;
+ while (i) {
+ TQString text = i->text(textNo);
+ if (!text.isEmpty())
+ list.prepend(i->text(textNo));
+ i = i->_parent;
+ }
+ return list;
+}
+
+int TreeMapItem::depth() const
+{
+ if (_depth>0) return _depth;
+
+ if (_parent)
+ return _parent->depth() + 1;
+ return 1;
+}
+
+
+bool TreeMapItem::initialized()
+{
+ if (!_children) {
+ _children = new TreeMapItemList;
+ _children->setAutoDelete(true);
+ return false;
+ }
+ return true;
+}
+
+void TreeMapItem::addItem(TreeMapItem* i)
+{
+ if (!i) return;
+
+ if (!_children) {
+ _children = new TreeMapItemList;
+ _children->setAutoDelete(true);
+ }
+ i->setParent(this);
+
+ if (sorting(0) == -1)
+ _children->append(i); // preserve insertion order
+ else
+ _children->inSort(i);
+}
+
+
+// default implementations of virtual functions
+
+double TreeMapItem::value() const
+{
+ return _value;
+}
+
+double TreeMapItem::sum() const
+{
+ return _sum;
+}
+
+DrawParams::Position TreeMapItem::position(int f) const
+{
+ Position p = StoredDrawParams::position(f);
+ if (_widget && (p == Default))
+ p = _widget->fieldPosition(f);
+
+ return p;
+}
+
+// use widget font
+const TQFont& TreeMapItem::font() const
+{
+ return _widget->currentFont();
+}
+
+
+bool TreeMapItem::isMarked(int) const
+{
+ return false;
+}
+
+
+int TreeMapItem::borderWidth() const
+{
+ if (_widget)
+ return _widget->borderWidth();
+
+ return 2;
+}
+
+int TreeMapItem::sorting(bool* ascending) const
+{
+ if (ascending) *ascending = _sortAscending;
+ return _sortTextNo;
+}
+
+// do *not* set sorting recursively
+void TreeMapItem::setSorting(int textNo, bool ascending)
+{
+ if (_sortTextNo == textNo) {
+ if(_sortAscending == ascending) return;
+ if (textNo == -1) {
+ // when no sorting is done, order change doesn't do anything
+ _sortAscending = ascending;
+ return;
+ }
+ }
+ _sortAscending = ascending;
+ _sortTextNo = textNo;
+
+ if (_children && _sortTextNo != -1) _children->sort();
+}
+
+void TreeMapItem::resort(bool recursive)
+{
+ if (!_children) return;
+
+ if (_sortTextNo != -1) _children->sort();
+
+ if (recursive)
+ for (TreeMapItem* i=_children->first(); i; i=_children->next())
+ i->resort(recursive);
+}
+
+
+TreeMapItem::SplitMode TreeMapItem::splitMode() const
+{
+ if (_widget)
+ return _widget->splitMode();
+
+ return Best;
+}
+
+int TreeMapItem::rtti() const
+{
+ return 0;
+}
+
+TreeMapItemList* TreeMapItem::children()
+{
+ if (!_children) {
+ _children = new TreeMapItemList;
+ _children->setAutoDelete(true);
+ }
+ return _children;
+}
+
+void TreeMapItem::clearItemRect()
+{
+ _rect = TQRect();
+ clearFreeRects();
+}
+
+void TreeMapItem::clearFreeRects()
+{
+ if (_freeRects) _freeRects->clear();
+}
+
+void TreeMapItem::addFreeRect(const TQRect& r)
+{
+ // don't add invalid rects
+ if ((r.width() < 1) || (r.height() < 1)) return;
+
+ if (!_freeRects) {
+ _freeRects = new TQPtrList<TQRect>;
+ _freeRects->setAutoDelete(true);
+ }
+
+ if (0) kdDebug(90100) << "addFree(" << path(0).join("/") << ", "
+ << r.x() << "/" << r.y() << "-"
+ << r.width() << "x" << r.height() << ")" << endl;
+
+ TQRect* last = _freeRects->last();
+ if (!last) {
+ _freeRects->append(new TQRect(r));
+ return;
+ }
+
+ // join rect with last rect if possible
+ // this saves memory and doesn't make the tooltip flicker
+
+ bool replaced = false;
+ if ((last->left() == r.left()) && (last->width() == r.width())) {
+ if ((last->bottom()+1 == r.top()) || (r.bottom()+1 == last->top())) {
+ *last |= r;
+ replaced = true;
+ }
+ }
+ else if ((last->top() == r.top()) && (last->height() == r.height())) {
+ if ((last->right()+1 == r.left()) || (r.right()+1 == last->left())) {
+ *last |= r;
+ replaced = true;
+ }
+ }
+
+ if (!replaced) {
+ _freeRects->append(new TQRect(r));
+ return;
+ }
+
+ if (0) kdDebug(90100) << " united with last to ("
+ << last->x() << "/" << last->y() << "-"
+ << last->width() << "x" << last->height() << ")" << endl;
+}
+
+
+// Tooltips for TreeMapWidget
+
+class TreeMapTip: public TQToolTip
+{
+public:
+ TreeMapTip( TQWidget* p ):TQToolTip(p) {}
+
+protected:
+ void maybeTip( const TQPoint & );
+};
+
+void TreeMapTip::maybeTip( const TQPoint& pos )
+{
+ if ( !parentWidget()->inherits( "TreeMapWidget" ) )
+ return;
+
+ TreeMapWidget* p = (TreeMapWidget*)parentWidget();
+ TreeMapItem* i;
+ i = p->item(pos.x(), pos.y());
+ TQPtrList<TQRect>* rList = i ? i->freeRects() : 0;
+ if (rList) {
+ TQRect* r;
+ for(r=rList->first();r;r=rList->next())
+ if (r->contains(pos))
+ tip(*r, p->tipString(i));
+ }
+}
+
+
+
+// TreeMapWidget
+
+TreeMapWidget::TreeMapWidget(TreeMapItem* base,
+ TQWidget* parent, const char* name)
+ : TQWidget(parent, name)
+{
+ _base = base;
+ _base->setWidget(this);
+
+ _font = font();
+ _fontHeight = fontMetrics().height();
+
+
+ // default behaviour
+ _selectionMode = Single;
+ _splitMode = TreeMapItem::AlwaysBest;
+ _visibleWidth = 2;
+ _reuseSpace = false;
+ _skipIncorrectBorder = false;
+ _drawSeparators = false;
+ _allowRotation = true;
+ _borderWidth = 2;
+ _shading = true; // beautiful is default!
+ _maxSelectDepth = -1; // unlimited
+ _maxDrawingDepth = -1; // unlimited
+ _minimalArea = -1; // unlimited
+ _markNo = 0;
+
+ for(int i=0;i<4;i++) {
+ _drawFrame[i] = true;
+ _transparent[i] = false;
+ }
+
+ // _stopAtText will be unset on resizing (per default)
+ // _textVisible will be true on resizing (per default)
+ // _forceText will be false on resizing (per default)
+
+ // start state: _selection is an empty list
+ _current = 0;
+ _oldCurrent = 0;
+ _pressed = 0;
+ _lastOver = 0;
+ _needsRefresh = _base;
+
+ setBackgroundMode(TQt::NoBackground);
+ setFocusPolicy(TQ_StrongFocus);
+ _tip = new TreeMapTip(this);
+}
+
+TreeMapWidget::~TreeMapWidget()
+{
+ delete _base;
+ delete _tip;
+}
+
+const TQFont& TreeMapWidget::currentFont() const
+{
+ return _font;
+}
+
+void TreeMapWidget::setSplitMode(TreeMapItem::SplitMode m)
+{
+ if (_splitMode == m) return;
+
+ _splitMode = m;
+ redraw();
+}
+
+TreeMapItem::SplitMode TreeMapWidget::splitMode() const
+{
+ return _splitMode;
+}
+
+bool TreeMapWidget::setSplitMode(TQString mode)
+{
+ if (mode == "Bisection") setSplitMode(TreeMapItem::Bisection);
+ else if (mode == "Columns") setSplitMode(TreeMapItem::Columns);
+ else if (mode == "Rows") setSplitMode(TreeMapItem::Rows);
+ else if (mode == "AlwaysBest") setSplitMode(TreeMapItem::AlwaysBest);
+ else if (mode == "Best") setSplitMode(TreeMapItem::Best);
+ else if (mode == "HAlternate") setSplitMode(TreeMapItem::HAlternate);
+ else if (mode == "VAlternate") setSplitMode(TreeMapItem::VAlternate);
+ else if (mode == "Horizontal") setSplitMode(TreeMapItem::Horizontal);
+ else if (mode == "Vertical") setSplitMode(TreeMapItem::Vertical);
+ else return false;
+
+ return true;
+}
+
+TQString TreeMapWidget::splitModeString() const
+{
+ TQString mode;
+ switch(splitMode()) {
+ case TreeMapItem::Bisection: mode = "Bisection"; break;
+ case TreeMapItem::Columns: mode = "Columns"; break;
+ case TreeMapItem::Rows: mode = "Rows"; break;
+ case TreeMapItem::AlwaysBest: mode = "AlwaysBest"; break;
+ case TreeMapItem::Best: mode = "Best"; break;
+ case TreeMapItem::HAlternate: mode = "HAlternate"; break;
+ case TreeMapItem::VAlternate: mode = "VAlternate"; break;
+ case TreeMapItem::Horizontal: mode = "Horizontal"; break;
+ case TreeMapItem::Vertical: mode = "Vertical"; break;
+ default: mode = "Unknown"; break;
+ }
+ return mode;
+}
+
+
+void TreeMapWidget::setShadingEnabled(bool s)
+{
+ if (_shading == s) return;
+
+ _shading = s;
+ redraw();
+}
+
+void TreeMapWidget::drawFrame(int d, bool b)
+{
+ if ((d<0) || (d>=4) || (_drawFrame[d]==b)) return;
+
+ _drawFrame[d] = b;
+ redraw();
+}
+
+void TreeMapWidget::setTransparent(int d, bool b)
+{
+ if ((d<0) || (d>=4) || (_transparent[d]==b)) return;
+
+ _transparent[d] = b;
+ redraw();
+}
+
+void TreeMapWidget::setAllowRotation(bool enable)
+{
+ if (_allowRotation == enable) return;
+
+ _allowRotation = enable;
+ redraw();
+}
+
+void TreeMapWidget::setVisibleWidth(int width, bool reuseSpace)
+{
+ if (_visibleWidth == width && _reuseSpace == reuseSpace) return;
+
+ _visibleWidth = width;
+ _reuseSpace = reuseSpace;
+ redraw();
+}
+
+void TreeMapWidget::setSkipIncorrectBorder(bool enable)
+{
+ if (_skipIncorrectBorder == enable) return;
+
+ _skipIncorrectBorder = enable;
+ redraw();
+}
+
+void TreeMapWidget::setBorderWidth(int w)
+{
+ if (_borderWidth == w) return;
+
+ _borderWidth = w;
+ redraw();
+}
+
+void TreeMapWidget::setMaxDrawingDepth(int d)
+{
+ if (_maxDrawingDepth == d) return;
+
+ _maxDrawingDepth = d;
+ redraw();
+}
+
+TQString TreeMapWidget::defaultFieldType(int f) const
+{
+ return i18n("Text %1").arg(f+1);
+}
+
+TQString TreeMapWidget::defaultFieldStop(int) const
+{
+ return TQString();
+}
+
+bool TreeMapWidget::defaultFieldVisible(int f) const
+{
+ return (f<2);
+}
+
+bool TreeMapWidget::defaultFieldForced(int) const
+{
+ return false;
+}
+
+DrawParams::Position TreeMapWidget::defaultFieldPosition(int f) const
+{
+ switch(f%4) {
+ case 0: return DrawParams::TopLeft;
+ case 1: return DrawParams::TopRight;
+ case 2: return DrawParams::BottomRight;
+ case 3: return DrawParams::BottomLeft;
+ default:break;
+ }
+ return DrawParams::TopLeft;
+}
+
+bool TreeMapWidget::resizeAttr(int size)
+{
+ if (size<0 || size>=MAX_FIELD) return false;
+
+ if (size>(int)_attr.size()) {
+ struct FieldAttr a;
+ int oldSize = _attr.size();
+ _attr.resize(size, a);
+ while (oldSize<size) {
+ _attr[oldSize].type = defaultFieldType(oldSize);
+ _attr[oldSize].stop = defaultFieldStop(oldSize);
+ _attr[oldSize].visible = defaultFieldVisible(oldSize);
+ _attr[oldSize].forced = defaultFieldForced(oldSize);
+ _attr[oldSize].pos = defaultFieldPosition(oldSize);
+ oldSize++;
+ }
+ }
+ return true;
+}
+
+void TreeMapWidget::setFieldType(int f, TQString type)
+{
+ if (((int)_attr.size() < f+1) &&
+ (type == defaultFieldType(f))) return;
+ if (resizeAttr(f+1)) _attr[f].type = type;
+
+ // no need to redraw: the type string is not visible in the TreeMap
+}
+
+TQString TreeMapWidget::fieldType(int f) const
+{
+ if (f<0 || (int)_attr.size()<f+1) return defaultFieldType(f);
+ return _attr[f].type;
+}
+
+void TreeMapWidget::setFieldStop(int f, TQString stop)
+{
+ if (((int)_attr.size() < f+1) &&
+ (stop == defaultFieldStop(f))) return;
+ if (resizeAttr(f+1)) {
+ _attr[f].stop = stop;
+ redraw();
+ }
+}
+
+TQString TreeMapWidget::fieldStop(int f) const
+{
+ if (f<0 || (int)_attr.size()<f+1) return defaultFieldStop(f);
+ return _attr[f].stop;
+}
+
+void TreeMapWidget::setFieldVisible(int f, bool enable)
+{
+ if (((int)_attr.size() < f+1) &&
+ (enable == defaultFieldVisible(f))) return;
+
+ if (resizeAttr(f+1)) {
+ _attr[f].visible = enable;
+ redraw();
+ }
+}
+
+bool TreeMapWidget::fieldVisible(int f) const
+{
+ if (f<0 || (int)_attr.size()<f+1)
+ return defaultFieldVisible(f);
+
+ return _attr[f].visible;
+}
+
+void TreeMapWidget::setFieldForced(int f, bool enable)
+{
+ if (((int)_attr.size() < f+1) &&
+ (enable == defaultFieldForced(f))) return;
+
+ if (resizeAttr(f+1)) {
+ _attr[f].forced = enable;
+ if (_attr[f].visible) redraw();
+ }
+}
+
+bool TreeMapWidget::fieldForced(int f) const
+{
+ if (f<0 || (int)_attr.size()<f+1)
+ return defaultFieldForced(f);
+
+ return _attr[f].forced;
+}
+
+void TreeMapWidget::setFieldPosition(int f, TreeMapItem::Position pos)
+{
+ if (((int)_attr.size() < f+1) &&
+ (pos == defaultFieldPosition(f))) return;
+
+ if (resizeAttr(f+1)) {
+ _attr[f].pos = pos;
+ if (_attr[f].visible) redraw();
+ }
+}
+
+DrawParams::Position TreeMapWidget::fieldPosition(int f) const
+{
+ if (f<0 || (int)_attr.size()<f+1)
+ return defaultFieldPosition(f);
+
+ return _attr[f].pos;
+}
+
+void TreeMapWidget::setFieldPosition(int f, TQString pos)
+{
+ if (pos == "TopLeft")
+ setFieldPosition(f, DrawParams::TopLeft);
+ else if (pos == "TopCenter")
+ setFieldPosition(f, DrawParams::TopCenter);
+ else if (pos == "TopRight")
+ setFieldPosition(f, DrawParams::TopRight);
+ else if (pos == "BottomLeft")
+ setFieldPosition(f, DrawParams::BottomLeft);
+ else if (pos == "BottomCenter")
+ setFieldPosition(f, DrawParams::BottomCenter);
+ else if (pos == "BottomRight")
+ setFieldPosition(f, DrawParams::BottomRight);
+ else if (pos == "Default")
+ setFieldPosition(f, DrawParams::Default);
+}
+
+TQString TreeMapWidget::fieldPositionString(int f) const
+{
+ TreeMapItem::Position pos = fieldPosition(f);
+ if (pos == DrawParams::TopLeft) return TQString("TopLeft");
+ if (pos == DrawParams::TopCenter) return TQString("TopCenter");
+ if (pos == DrawParams::TopRight) return TQString("TopRight");
+ if (pos == DrawParams::BottomLeft) return TQString("BottomLeft");
+ if (pos == DrawParams::BottomCenter) return TQString("BottomCenter");
+ if (pos == DrawParams::BottomRight) return TQString("BottomRight");
+ if (pos == DrawParams::Default) return TQString("Default");
+ return TQString("unknown");
+}
+
+void TreeMapWidget::setMinimalArea(int area)
+{
+ if (_minimalArea == area) return;
+
+ _minimalArea = area;
+ redraw();
+}
+
+
+void TreeMapWidget::deletingItem(TreeMapItem* i)
+{
+ // remove any references to the item to be deleted
+ while(_selection.findRef(i) > -1)
+ _selection.remove();
+
+ while(_tmpSelection.findRef(i) > -1)
+ _tmpSelection.remove();
+
+ if (_current == i) _current = 0;
+ if (_oldCurrent == i) _oldCurrent = 0;
+ if (_pressed == i) _pressed = 0;
+ if (_lastOver == i) _lastOver = 0;
+
+ // don't redraw a deleted item
+ if (_needsRefresh == i) {
+ // we can savely redraw the parent, as deleting order is
+ // from child to parent; i.e. i->parent() is existing.
+ _needsRefresh = i->parent();
+ }
+}
+
+
+TQString TreeMapWidget::tipString(TreeMapItem* i) const
+{
+ TQString tip, itemTip;
+
+ while (i) {
+ if (!i->text(0).isEmpty()) {
+ itemTip = i->text(0);
+ if (!i->text(1).isEmpty())
+ itemTip += " (" + i->text(1) + ")";
+
+ if (!tip.isEmpty())
+ tip += "\n";
+
+ tip += itemTip;
+ }
+ i = i->parent();
+ }
+ return tip;
+}
+
+TreeMapItem* TreeMapWidget::item(int x, int y) const
+{
+ TreeMapItem* p = _base;
+ TreeMapItem* i;
+
+ if (!TQT_TQRECT_OBJECT(rect()).contains(x, y)) return 0;
+ if (DEBUG_DRAWING) kdDebug(90100) << "item(" << x << "," << y << "):" << endl;
+
+ while (1) {
+ TreeMapItemList* list = p->children();
+ if (!list)
+ i = 0;
+ else {
+ int idx=0;
+ for (i=list->first();i;i=list->next(),idx++) {
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " Checking " << i->path(0).join("/") << " ("
+ << i->itemRect().x() << "/" << i->itemRect().y()
+ << "-" << i->itemRect().width()
+ << "x" << i->itemRect().height() << ")" << endl;
+
+ if (i->itemRect().contains(x, y)) {
+
+ if (DEBUG_DRAWING) kdDebug(90100) << " .. Got. Index " << idx << endl;
+
+ p->setIndex(idx);
+ break;
+ }
+ }
+ }
+
+ if (!i) {
+ static TreeMapItem* last = 0;
+ if (p != last) {
+ last = p;
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << "item(" << x << "," << y << "): Got "
+ << p->path(0).join("/") << " (Size "
+ << p->itemRect().width() << "x" << p->itemRect().height()
+ << ", Val " << p->value() << ")" << endl;
+ }
+
+ return p;
+ }
+ p = i;
+ }
+ return 0;
+}
+
+TreeMapItem* TreeMapWidget::possibleSelection(TreeMapItem* i) const
+{
+ if (i) {
+ if (_maxSelectDepth>=0) {
+ int depth = i->depth();
+ while(i && depth > _maxSelectDepth) {
+ i = i->parent();
+ depth--;
+ }
+ }
+ }
+ return i;
+}
+
+TreeMapItem* TreeMapWidget::visibleItem(TreeMapItem* i) const
+{
+ if (i) {
+ /* Must have a visible area */
+ while(i && ((i->itemRect().width() <1) ||
+ (i->itemRect().height() <1))) {
+ TreeMapItem* p = i->parent();
+ if (!p) break;
+ int idx = p->children()->findRef(i);
+ idx--;
+ if (idx<0)
+ i = p;
+ else
+ i = p->children()->at(idx);
+ }
+ }
+ return i;
+}
+
+void TreeMapWidget::setSelected(TreeMapItem* item, bool selected)
+{
+ item = possibleSelection(item);
+ setCurrent(item);
+
+ TreeMapItem* changed = setTmpSelected(item, selected);
+ if (!changed) return;
+
+ _selection = _tmpSelection;
+ if (_selectionMode == Single)
+ emit selectionChanged(item);
+ emit selectionChanged();
+ redraw(changed);
+
+ if (0) kdDebug(90100) << (selected ? "S":"Des") << "elected Item "
+ << (item ? item->path(0).join("") : TQString("(null)"))
+ << " (depth " << (item ? item->depth() : -1)
+ << ")" << endl;
+}
+
+void TreeMapWidget::setMarked(int markNo, bool redrawWidget)
+{
+ // if there's no marking, return
+ if ((_markNo == 0) && (markNo == 0)) return;
+
+ _markNo = markNo;
+ if (!clearSelection() && redrawWidget) redraw();
+}
+
+/* Returns all items which appear only in one of the given lists */
+TreeMapItemList TreeMapWidget::diff(TreeMapItemList& l1,
+ TreeMapItemList& l2)
+{
+ TreeMapItemList l;
+ TreeMapItemListIterator it1(l1), it2(l2);
+
+ TreeMapItem* item;
+ while ( (item = it1.current()) != 0 ) {
+ ++it1;
+ if (l2.containsRef(item) > 0) continue;
+ l.append(item);
+ }
+ while ( (item = it2.current()) != 0 ) {
+ ++it2;
+ if (l1.containsRef(item) > 0) continue;
+ l.append(item);
+ }
+
+ return l;
+}
+
+/* Only modifies _tmpSelection.
+ * Returns 0 when no change happened, otherwise the TreeMapItem that has
+ * to be redrawn for all changes.
+ */
+TreeMapItem* TreeMapWidget::setTmpSelected(TreeMapItem* item, bool selected)
+{
+ if (!item) return 0;
+ if (_selectionMode == NoSelection) return 0;
+
+ TreeMapItemList old = _tmpSelection;
+
+ if (_selectionMode == Single) {
+ _tmpSelection.clear();
+ if (selected) _tmpSelection.append(item);
+ }
+ else {
+ if (selected) {
+ TreeMapItem* i=_tmpSelection.first();
+ while (i) {
+ if (i->isChildOf(item) || item->isChildOf(i)) {
+ _tmpSelection.remove();
+ i = _tmpSelection.current();
+ }
+ else
+ i = _tmpSelection.next();
+ }
+ _tmpSelection.append(item);
+ }
+ else
+ _tmpSelection.removeRef(item);
+ }
+
+ return diff(old, _tmpSelection).commonParent();
+}
+
+
+bool TreeMapWidget::clearSelection(TreeMapItem* parent)
+{
+ TreeMapItemList old = _selection;
+
+ TreeMapItem* i=_selection.first();
+ while (i) {
+ if (i->isChildOf(parent)) {
+ _selection.remove();
+ i = _selection.current();
+ }
+ else
+ i = _selection.next();
+ }
+
+ TreeMapItem* changed = diff(old, _selection).commonParent();
+ if (changed) {
+ changed->redraw();
+ emit selectionChanged();
+ }
+ return (changed != 0);
+}
+
+bool TreeMapWidget::isSelected(TreeMapItem* i) const
+{
+ return _selection.containsRef(i)>0;
+}
+
+bool TreeMapWidget::isTmpSelected(TreeMapItem* i)
+{
+ return _tmpSelection.containsRef(i)>0;
+}
+
+
+void TreeMapWidget::setCurrent(TreeMapItem* i, bool kbd)
+{
+ TreeMapItem* old = _current;
+ _current = i;
+
+ if (_markNo >0) {
+ // remove mark
+ _markNo = 0;
+
+ if (1) kdDebug(90100) << "setCurrent(" << i->path(0).join("/")
+ << ") - mark removed" << endl;
+
+ // always complete redraw needed to remove mark
+ redraw();
+
+ if (old == _current) return;
+ }
+ else {
+ if (old == _current) return;
+
+ if (old) old->redraw();
+ if (i) i->redraw();
+ }
+
+ //kdDebug(90100) << "Current Item " << (i ? i->path().ascii() : "(null)") << endl;
+
+ emit currentChanged(i, kbd);
+}
+
+void TreeMapWidget::setRangeSelection(TreeMapItem* i1,
+ TreeMapItem* i2, bool selected)
+{
+ i1 = possibleSelection(i1);
+ i2 = possibleSelection(i2);
+ setCurrent(i2);
+
+ TreeMapItem* changed = setTmpRangeSelection(i1, i2, selected);
+ if (!changed) return;
+
+ _selection = _tmpSelection;
+ if (_selectionMode == Single)
+ emit selectionChanged(i2);
+ emit selectionChanged();
+ redraw(changed);
+}
+
+TreeMapItem* TreeMapWidget::setTmpRangeSelection(TreeMapItem* i1,
+ TreeMapItem* i2,
+ bool selected)
+{
+ if ((i1 == 0) && (i2 == 0)) return 0;
+ if ((i1 == 0) || i1->isChildOf(i2)) return setTmpSelected(i2, selected);
+ if ((i2 == 0) || i2->isChildOf(i1)) return setTmpSelected(i1, selected);
+
+ TreeMapItem* changed = setTmpSelected(i1, selected);
+ TreeMapItem* changed2 = setTmpSelected(i2, selected);
+ if (changed2) changed = changed2->commonParent(changed);
+
+ TreeMapItem* commonParent = i1;
+ while (commonParent && !i2->isChildOf(commonParent)) {
+ i1 = commonParent;
+ commonParent = commonParent->parent();
+ }
+ if (!commonParent) return changed;
+ while (i2 && i2->parent() != commonParent)
+ i2 = i2->parent();
+ if (!i2) return changed;
+
+ TreeMapItemList* list = commonParent->children();
+ if (!list) return changed;
+
+ TreeMapItem* i = list->first();
+ bool between = false;
+ while (i) {
+ if (between) {
+ if (i==i1 || i==i2) break;
+ changed2 = setTmpSelected(i, selected);
+ if (changed2) changed = changed2->commonParent(changed);
+ }
+ else if (i==i1 || i==i2)
+ between = true;
+ i = list->next();
+ }
+
+ return changed;
+}
+
+void TreeMapWidget::contextMenuEvent( TQContextMenuEvent* e )
+{
+ //kdDebug(90100) << "TreeMapWidget::contextMenuEvent" << endl;
+
+ if ( receivers( TQT_SIGNAL(contextMenuRequested(TreeMapItem*, const TQPoint &)) ) )
+ e->accept();
+
+ if ( e->reason() == TQContextMenuEvent::Keyboard ) {
+ TQRect r = (_current) ? _current->itemRect() : _base->itemRect();
+ TQPoint p = TQPoint(r.left() + r.width()/2, r.top() + r.height()/2);
+ emit contextMenuRequested(_current, p);
+ }
+ else {
+ TreeMapItem* i = item(e->x(), e->y());
+ emit contextMenuRequested(i, e->pos());
+ }
+}
+
+
+void TreeMapWidget::mousePressEvent( TQMouseEvent* e )
+{
+ //kdDebug(90100) << "TreeMapWidget::mousePressEvent" << endl;
+
+ _oldCurrent = _current;
+
+ TreeMapItem* i = item(e->x(), e->y());
+
+ _pressed = i;
+
+ _inShiftDrag = e->state() & ShiftButton;
+ _inControlDrag = e->state() & ControlButton;
+ _lastOver = _pressed;
+
+ TreeMapItem* changed = 0;
+ TreeMapItem* item = possibleSelection(_pressed);
+
+ switch(_selectionMode) {
+ case Single:
+ changed = setTmpSelected(item, true);
+ break;
+ case Multi:
+ changed = setTmpSelected(item, !isTmpSelected(item));
+ break;
+ case Extended:
+ if (_inControlDrag)
+ changed = setTmpSelected(item, !isTmpSelected(item));
+ else if (_inShiftDrag) {
+ TreeMapItem* sCurrent = possibleSelection(_current);
+ changed = setTmpRangeSelection(sCurrent, item,
+ !isTmpSelected(item));
+ }
+ else {
+ _selectionMode = Single;
+ changed = setTmpSelected(item, true);
+ _selectionMode = Extended;
+ }
+ break;
+ default:
+ break;
+ }
+
+ // item under mouse always selected on right button press
+ if (e->button() == Qt::RightButton) {
+ TreeMapItem* changed2 = setTmpSelected(item, true);
+ if (changed2) changed = changed2->commonParent(changed);
+ }
+
+ setCurrent(_pressed);
+
+ if (changed)
+ redraw(changed);
+
+ if (e->button() == Qt::RightButton) {
+
+ // emit selection change
+ if (! (_tmpSelection == _selection)) {
+ _selection = _tmpSelection;
+ if (_selectionMode == Single)
+ emit selectionChanged(_lastOver);
+ emit selectionChanged();
+ }
+ _pressed = 0;
+ _lastOver = 0;
+ emit rightButtonPressed(i, e->pos());
+ }
+}
+
+void TreeMapWidget::mouseMoveEvent( TQMouseEvent* e )
+{
+ //kdDebug(90100) << "TreeMapWidget::mouseMoveEvent" << endl;
+
+ if (!_pressed) return;
+ TreeMapItem* over = item(e->x(), e->y());
+ if (_lastOver == over) return;
+
+ setCurrent(over);
+ if (over == 0) {
+ _lastOver = 0;
+ return;
+ }
+
+ TreeMapItem* changed = 0;
+ TreeMapItem* item = possibleSelection(over);
+
+ switch(_selectionMode) {
+ case Single:
+ changed = setTmpSelected(item, true);
+ break;
+ case Multi:
+ changed = setTmpSelected(item, !isTmpSelected(item));
+ break;
+ case Extended:
+ if (_inControlDrag)
+ changed = setTmpSelected(item, !isTmpSelected(item));
+ else {
+ TreeMapItem* sLast = possibleSelection(_lastOver);
+ changed = setTmpRangeSelection(sLast, item, true);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ _lastOver = over;
+
+ if (changed)
+ redraw(changed);
+}
+
+void TreeMapWidget::mouseReleaseEvent( TQMouseEvent* )
+{
+ //kdDebug(90100) << "TreeMapWidget::mouseReleaseEvent" << endl;
+
+ if (!_pressed) return;
+
+ if (!_lastOver) {
+ // take back
+ setCurrent(_oldCurrent);
+ TreeMapItem* changed = diff(_tmpSelection, _selection).commonParent();
+ _tmpSelection = _selection;
+ if (changed)
+ redraw(changed);
+ }
+ else {
+ if (! (_tmpSelection == _selection)) {
+ _selection = _tmpSelection;
+ if (_selectionMode == Single)
+ emit selectionChanged(_lastOver);
+ emit selectionChanged();
+ }
+ if (!_inControlDrag && !_inShiftDrag && (_pressed == _lastOver))
+ emit clicked(_lastOver);
+ }
+
+ _pressed = 0;
+ _lastOver = 0;
+}
+
+
+void TreeMapWidget::mouseDoubleClickEvent( TQMouseEvent* e )
+{
+ TreeMapItem* over = item(e->x(), e->y());
+
+ emit doubleClicked(over);
+}
+
+
+/* returns -1 if nothing visible found */
+int nextVisible(TreeMapItem* i)
+{
+ TreeMapItem* p = i->parent();
+ if (!p || p->itemRect().isEmpty()) return -1;
+
+ int idx = p->children()->findRef(i);
+ if (idx<0) return -1;
+
+ while (idx < (int)p->children()->count()-1) {
+ idx++;
+ TQRect r = p->children()->at(idx)->itemRect();
+ if (r.width()>1 && r.height()>1)
+ return idx;
+ }
+ return -1;
+}
+
+/* returns -1 if nothing visible found */
+int prevVisible(TreeMapItem* i)
+{
+ TreeMapItem* p = i->parent();
+ if (!p || p->itemRect().isEmpty()) return -1;
+
+ int idx = p->children()->findRef(i);
+ if (idx<0) return -1;
+
+ while (idx > 0) {
+ idx--;
+ TQRect r = p->children()->at(idx)->itemRect();
+ if (r.width()>1 && r.height()>1)
+ return idx;
+ }
+ return -1;
+}
+
+
+
+
+void TreeMapWidget::keyPressEvent( TQKeyEvent* e )
+{
+ if (e->key() == Key_Escape && _pressed) {
+
+ // take back
+ if (_oldCurrent != _lastOver)
+ setCurrent(_oldCurrent);
+ if (! (_tmpSelection == _selection)) {
+ TreeMapItem* changed = diff(_tmpSelection, _selection).commonParent();
+ _tmpSelection = _selection;
+ if (changed)
+ redraw(changed);
+ }
+ _pressed = 0;
+ _lastOver = 0;
+ }
+
+ if ((e->key() == Key_Space) ||
+ (e->key() == Key_Return)) {
+
+ switch(_selectionMode) {
+ case NoSelection:
+ break;
+ case Single:
+ setSelected(_current, true);
+ break;
+ case Multi:
+ setSelected(_current, !isSelected(_current));
+ break;
+ case Extended:
+ if ((e->state() & ControlButton) || (e->state() & ShiftButton))
+ setSelected(_current, !isSelected(_current));
+ else {
+ _selectionMode = Single;
+ setSelected(_current, true);
+ _selectionMode = Extended;
+ }
+ }
+
+ if (_current && (e->key() == Key_Return))
+ emit returnPressed(_current);
+
+ return;
+ }
+
+ if (!_current) {
+ if (e->key() == Key_Down) {
+ setCurrent(_base, true);
+ }
+ return;
+ }
+
+ TreeMapItem* old = _current, *newItem;
+ TreeMapItem* p = _current->parent();
+
+ bool goBack;
+ if (_current->sorting(&goBack) == -1) {
+ // noSorting
+ goBack = false;
+ }
+
+
+ if ((e->key() == Key_Backspace) ||
+ (e->key() == Key_Up)) {
+ newItem = visibleItem(p);
+ setCurrent(newItem, true);
+ }
+ else if (e->key() == Key_Left) {
+ int newIdx = goBack ? nextVisible(_current) : prevVisible(_current);
+ if (p && newIdx>=0) {
+ p->setIndex(newIdx);
+ setCurrent(p->children()->at(newIdx), true);
+ }
+ }
+ else if (e->key() == Key_Right) {
+ int newIdx = goBack ? prevVisible(_current) : nextVisible(_current);
+ if (p && newIdx>=0) {
+ p->setIndex(newIdx);
+ setCurrent(p->children()->at(newIdx), true);
+ }
+ }
+ else if (e->key() == Key_Down) {
+ if (_current->children() && _current->children()->count()>0) {
+ int newIdx = _current->index();
+ if (newIdx<0)
+ newIdx = goBack ? (_current->children()->count()-1) : 0;
+ if (newIdx>=(int)_current->children()->count())
+ newIdx = _current->children()->count()-1;
+ newItem = visibleItem(_current->children()->at(newIdx));
+ setCurrent(newItem, true);
+ }
+ }
+
+ if (old == _current) return;
+ if (! (e->state() & ControlButton)) return;
+ if (! (e->state() & ShiftButton)) return;
+
+ switch(_selectionMode) {
+ case NoSelection:
+ break;
+ case Single:
+ setSelected(_current, true);
+ break;
+ case Multi:
+ setSelected(_current, !isSelected(_current));
+ break;
+ case Extended:
+ if (e->state() & ControlButton)
+ setSelected(_current, !isSelected(_current));
+ else
+ setSelected(_current, isSelected(old));
+ }
+}
+
+void TreeMapWidget::fontChange( const TQFont& )
+{
+ redraw();
+}
+
+
+void TreeMapWidget::resizeEvent( TQResizeEvent * )
+{
+ // this automatically redraws (as size is changed)
+ drawTreeMap();
+}
+
+void TreeMapWidget::paintEvent( TQPaintEvent * )
+{
+ drawTreeMap();
+}
+
+void TreeMapWidget::showEvent( TQShowEvent * )
+{
+ // refresh only if needed
+ drawTreeMap();
+}
+
+// Updates screen from shadow buffer,
+// but redraws before if needed
+void TreeMapWidget::drawTreeMap()
+{
+ // no need to draw if hidden
+ if (!isVisible()) return;
+
+ if (_pixmap.size() != size())
+ _needsRefresh = _base;
+
+ if (_needsRefresh) {
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << "Redrawing " << _needsRefresh->path(0).join("/") << endl;
+
+ if (_needsRefresh == _base) {
+ // redraw whole widget
+ _pixmap = TQPixmap(size());
+ _pixmap.fill(backgroundColor());
+ }
+ TQPainter p(&_pixmap);
+ if (_needsRefresh == _base) {
+ p.setPen(black);
+ p.drawRect(TQRect(2, 2, TQWidget::width()-4, TQWidget::height()-4));
+ _base->setItemRect(TQRect(3, 3, TQWidget::width()-6, TQWidget::height()-6));
+ }
+ else {
+ // only subitem
+ if (!_needsRefresh->itemRect().isValid()) return;
+ }
+
+ // reset cached font object; it could have been changed
+ _font = font();
+ _fontHeight = fontMetrics().height();
+
+ drawItems(&p, _needsRefresh);
+ _needsRefresh = 0;
+ }
+
+ bitBlt( TQT_TQPAINTDEVICE(this), 0, 0, TQT_TQPAINTDEVICE(&_pixmap), 0, 0,
+ TQWidget::width(), TQWidget::height(), CopyROP, true);
+
+ if (hasFocus()) {
+ TQPainter p(this);
+ style().tqdrawPrimitive( TQStyle::PE_FocusRect, &p,
+ TQRect(0, 0, TQWidget::width(), TQWidget::height()),
+ colorGroup() );
+ }
+}
+
+
+
+void TreeMapWidget::redraw(TreeMapItem* i)
+{
+ if (!i) return;
+
+ if (!_needsRefresh)
+ _needsRefresh = i;
+ else {
+ if (!i->isChildOf(_needsRefresh))
+ _needsRefresh = _needsRefresh->commonParent(i);
+ }
+
+ if (isVisible()) {
+ // delayed drawing if we have multiple redraw requests
+ update();
+ }
+}
+
+void TreeMapWidget::drawItem(TQPainter* p,
+ TreeMapItem* item)
+{
+ bool isSelected = false;
+ TreeMapItem* i;
+
+ if (_markNo>0) {
+ for(i = item;i;i=i->parent())
+ if (i->isMarked(_markNo)) break;
+
+ isSelected = (i!=0);
+ }
+ else {
+ for (i=_tmpSelection.first();i;i=_tmpSelection.next())
+ if (item->isChildOf(i)) break;
+
+ isSelected = (i!=0);
+ }
+
+ bool isCurrent = _current && item->isChildOf(_current);
+ int dd = item->depth();
+ if (isTransparent(dd)) return;
+
+ RectDrawing d(item->itemRect());
+ item->setSelected(isSelected);
+ item->setCurrent(isCurrent);
+ item->setShaded(_shading);
+ item->drawFrame(drawFrame(dd));
+ d.drawBack(p, item);
+}
+
+
+bool TreeMapWidget::horizontal(TreeMapItem* i, const TQRect& r)
+{
+ switch(i->splitMode()) {
+ case TreeMapItem::HAlternate:
+ return (i->depth()%2)==1;
+ case TreeMapItem::VAlternate:
+ return (i->depth()%2)==0;
+ case TreeMapItem::Horizontal:
+ return true;
+ case TreeMapItem::Vertical:
+ return false;
+ default:
+ return r.width() > r.height();
+ }
+ return false;
+}
+
+
+/**
+ * Draw TreeMapItems recursive, starting from item
+ */
+void TreeMapWidget::drawItems(TQPainter* p,
+ TreeMapItem* item)
+{
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << "+drawItems(" << item->path(0).join("/") << ", "
+ << item->itemRect().x() << "/" << item->itemRect().y()
+ << "-" << item->itemRect().width() << "x"
+ << item->itemRect().height() << "), Val " << item->value()
+ << ", Sum " << item->sum() << endl;
+
+ drawItem(p, item);
+ item->clearFreeRects();
+
+ TQRect origRect = item->itemRect();
+ int bw = item->borderWidth();
+ TQRect r = TQRect(origRect.x()+bw, origRect.y()+bw,
+ origRect.width()-2*bw, origRect.height()-2*bw);
+
+ TreeMapItemList* list = item->children();
+ TreeMapItem* i;
+
+ bool stopDrawing = false;
+
+ // only subdivide if there are children
+ if (!list || list->count()==0)
+ stopDrawing = true;
+
+ // only subdivide if there is enough space
+ if (!stopDrawing && (r.width()<=0 || r.height()<=0))
+ stopDrawing = true;
+
+ // stop drawing if maximum depth is reached
+ if (!stopDrawing &&
+ (_maxDrawingDepth>=0 && item->depth()>=_maxDrawingDepth))
+ stopDrawing = true;
+
+ // stop drawing if stopAtText is reached
+ if (!stopDrawing)
+ for (int no=0;no<(int)_attr.size();no++) {
+ TQString stopAt = fieldStop(no);
+ if (!stopAt.isEmpty() && (item->text(no) == stopAt)) {
+ stopDrawing = true;
+ break;
+ }
+ }
+
+ // area size is checked later...
+#if 0
+ // stop drawing if minimal area size is reached
+ if (!stopDrawing &&
+ (_minimalArea > 0) &&
+ (r.width() * r.height() < _minimalArea)) stopDrawing = true;
+#endif
+
+ if (stopDrawing) {
+ if (list) {
+ // invalidate rects
+ for (i=list->first();i;i=list->next())
+ i->clearItemRect();
+ }
+ // tooltip apears on whole item rect
+ item->addFreeRect(item->itemRect());
+
+ // if we have space for text...
+ if ((r.height() < _fontHeight) || (r.width() < _fontHeight)) return;
+
+ RectDrawing d(r);
+ item->setRotated(_allowRotation && (r.height() > r.width()));
+ for (int no=0;no<(int)_attr.size();no++) {
+ if (!fieldVisible(no)) continue;
+ d.drawField(p, no, item);
+ }
+ r = d.remainingRect(item);
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << "-drawItems(" << item->path(0).join("/") << ")" << endl;
+ return;
+ }
+
+ double user_sum, child_sum, self;
+
+ // user supplied sum
+ user_sum = item->sum();
+
+ // own sum
+ child_sum = 0;
+ for (i=list->first();i;i=list->next()) {
+ child_sum += i->value();
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " child: " << i->text(0) << ", value "
+ << i->value() << endl;
+ }
+
+ TQRect orig = r;
+
+ // if we have space for text...
+ if ((r.height() >= _fontHeight) && (r.width() >= _fontHeight)) {
+
+ RectDrawing d(r);
+ item->setRotated(_allowRotation && (r.height() > r.width()));
+ for (int no=0;no<(int)_attr.size();no++) {
+ if (!fieldVisible(no)) continue;
+ if (!fieldForced(no)) continue;
+ d.drawField(p, no, item);
+ }
+ r = d.remainingRect(item);
+ }
+
+ if (orig.x() == r.x()) {
+ // Strings on top
+ item->addFreeRect(TQRect(orig.x(), orig.y(),
+ orig.width(), orig.height()-r.height()));
+ }
+ else {
+ // Strings on the left
+ item->addFreeRect(TQRect(orig.x(), orig.y(),
+ orig.width()-r.width(), orig.height()));
+ }
+
+ if (user_sum == 0) {
+ // user didn't supply any sum
+ user_sum = child_sum;
+ self = 0;
+ }
+ else {
+ self = user_sum - child_sum;
+
+ if (user_sum < child_sum) {
+ //kdDebug(90100) << "TreeMWidget " <<
+ // item->path() << ": User sum " << user_sum << " < Child Items sum " << child_sum << endl;
+
+ // invalid user supplied sum: ignore and use calculate sum
+ user_sum = child_sum;
+ self = 0.0;
+ }
+ else {
+ // Try to put the border waste in self
+ // percent of wasted space on border...
+ float borderArea = origRect.width() * origRect.height();
+ borderArea = (borderArea - r.width()*r.height())/borderArea;
+ unsigned borderValue = (unsigned)(borderArea * user_sum);
+
+ if (borderValue > self) {
+ if (_skipIncorrectBorder) {
+ r = origRect;
+ // should add my self to nested self and set my self =0
+ }
+ else
+ self = 0.0;
+ }
+ else
+ self -= borderValue;
+
+ user_sum = child_sum + self;
+ }
+ }
+
+ bool rotate = (_allowRotation && (r.height() > r.width()));
+ int self_length = (int)( ((rotate) ? r.width() : r.height()) *
+ self / user_sum + .5);
+ if (self_length > 0) {
+ // take space for self cost
+ TQRect sr = r;
+ if (rotate) {
+ sr.setWidth( self_length );
+ r.setRect(r.x()+sr.width(), r.y(), r.width()-sr.width(), r.height());
+ }
+ else {
+ sr.setHeight( self_length );
+ r.setRect(r.x(), r.y()+sr.height(), r.width(), r.height()-sr.height());
+ }
+
+ // set selfRect (not occupied by children) for tooltip
+ item->addFreeRect(sr);
+
+ if (0) kdDebug(90100) << "Item " << item->path(0).join("/") << ": SelfR "
+ << sr.x() << "/" << sr.y() << "-" << sr.width()
+ << "/" << sr.height() << ", self " << self << "/"
+ << user_sum << endl;
+
+ if ((sr.height() >= _fontHeight) && (sr.width() >= _fontHeight)) {
+
+ RectDrawing d(sr);
+ item->setRotated(_allowRotation && (r.height() > r.width()));
+ for (int no=0;no<(int)_attr.size();no++) {
+ if (!fieldVisible(no)) continue;
+ if (fieldForced(no)) continue;
+ d.drawField(p, no, item);
+ }
+ }
+
+ user_sum -= self;
+ }
+
+ bool goBack;
+ if (item->sorting(&goBack) == -1) {
+ // noSorting
+ goBack = false;
+ }
+
+ TreeMapItemListIterator it(*list);
+ if (goBack) it.toLast();
+
+ if (item->splitMode() == TreeMapItem::Columns) {
+ int len = list->count();
+ bool drawDetails = true;
+
+ while (len>0 && user_sum>0) {
+ TreeMapItemListIterator first = it;
+ double valSum = 0;
+ int lenLeft = len;
+ int columns = (int)(sqrt((double)len * r.width()/r.height())+.5);
+ if (columns==0) columns = 1; //should never be needed
+
+ while (lenLeft>0 && ((double)valSum*(len-lenLeft) <
+ (double)len*user_sum/columns/columns)) {
+ valSum += it.current()->value();
+ if (goBack) --it; else ++it;
+ lenLeft--;
+ }
+
+ // we always split horizontally
+ int nextPos = (int)((double)r.width() * valSum / user_sum);
+ TQRect firstRect = TQRect(r.x(), r.y(), nextPos, r.height());
+
+ if (nextPos < _visibleWidth) {
+ if (item->sorting(0) == -1) {
+ // fill current rect with hash pattern
+ drawFill(item, p, firstRect);
+ }
+ else {
+ // fill rest with hash pattern
+ drawFill(item, p, r, first, len, goBack);
+ break;
+ }
+ }
+ else {
+ drawDetails = drawItemArray(p, item, firstRect,
+ valSum, first, len-lenLeft, goBack);
+ }
+ r.setRect(r.x()+nextPos, r.y(), r.width()-nextPos, r.height());
+ user_sum -= valSum;
+ len = lenLeft;
+
+ if (!drawDetails) {
+ if (item->sorting(0) == -1)
+ drawDetails = true;
+ else {
+ drawFill(item, p, r, it, len, goBack);
+ break;
+ }
+ }
+ }
+ }
+ else if (item->splitMode() == TreeMapItem::Rows) {
+ int len = list->count();
+ bool drawDetails = true;
+
+ while (len>0 && user_sum>0) {
+ TreeMapItemListIterator first = it;
+ double valSum = 0;
+ int lenLeft = len;
+ int rows = (int)(sqrt((double)len * r.height()/r.width())+.5);
+ if (rows==0) rows = 1; //should never be needed
+
+ while (lenLeft>0 && ((double)valSum*(len-lenLeft) <
+ (double)len*user_sum/rows/rows)) {
+ valSum += it.current()->value();
+ if (goBack) --it; else ++it;
+ lenLeft--;
+ }
+
+ // we always split horizontally
+ int nextPos = (int)((double)r.height() * valSum / user_sum);
+ TQRect firstRect = TQRect(r.x(), r.y(), r.width(), nextPos);
+
+ if (nextPos < _visibleWidth) {
+ if (item->sorting(0) == -1) {
+ drawFill(item, p, firstRect);
+ }
+ else {
+ drawFill(item, p, r, first, len, goBack);
+ break;
+ }
+ }
+ else {
+ drawDetails = drawItemArray(p, item, firstRect,
+ valSum, first, len-lenLeft, goBack);
+ }
+ r.setRect(r.x(), r.y()+nextPos, r.width(), r.height()-nextPos);
+ user_sum -= valSum;
+ len = lenLeft;
+
+ if (!drawDetails) {
+ if (item->sorting(0) == -1)
+ drawDetails = true;
+ else {
+ drawFill(item, p, r, it, len, goBack);
+ break;
+ }
+ }
+ }
+ }
+ else
+ drawItemArray(p, item, r, user_sum, it, list->count(), goBack);
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << "-drawItems(" << item->path(0).join("/") << ")" << endl;
+}
+
+// fills area with a pattern if to small to draw children
+void TreeMapWidget::drawFill(TreeMapItem* i, TQPainter* p, TQRect& r)
+{
+ p->setBrush(TQt::Dense4Pattern);
+ p->setPen(TQt::NoPen);
+ p->drawRect(r);
+ i->addFreeRect(r);
+}
+
+// fills area with a pattern if to small to draw children
+void TreeMapWidget::drawFill(TreeMapItem* i, TQPainter* p, TQRect& r,
+ TreeMapItemListIterator it, int len, bool goBack)
+{
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " +drawFill(" << r.x() << "/" << r.y()
+ << "-" << r.width() << "x" << r.height()
+ << ", len " << len << ")" << endl;
+
+ p->setBrush(TQt::Dense4Pattern);
+ p->setPen(TQt::NoPen);
+ p->drawRect(r);
+ i->addFreeRect(r);
+
+ // reset rects
+ while (len>0 && it.current()) {
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " Reset Rect " << (*it)->path(0).join("/") << endl;
+
+ (*it)->clearItemRect();
+ if (goBack) --it; else ++it;
+ len--;
+ }
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " -drawFill(" << r.x() << "/" << r.y()
+ << "-" << r.width() << "x" << r.height()
+ << ", len " << len << ")" << endl;
+}
+
+// returns false if rect gets to small
+bool TreeMapWidget::drawItemArray(TQPainter* p, TreeMapItem* item,
+ TQRect& r, double user_sum,
+ TreeMapItemListIterator it, int len,
+ bool goBack)
+{
+ if (user_sum == 0) return false;
+
+ static bool b2t = true;
+
+ // stop recursive bisection for small rectangles
+ if (((r.height() < _visibleWidth) &&
+ (r.width() < _visibleWidth)) ||
+ ((_minimalArea > 0) &&
+ (r.width() * r.height() < _minimalArea))) {
+
+ drawFill(item, p, r, it, len, goBack);
+ return false;
+ }
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " +drawItemArray(" << item->path(0).join("/")
+ << ", " << r.x() << "/" << r.y() << "-" << r.width()
+ << "x" << r.height() << ")" << endl;
+
+ if (len>2 && (item->splitMode() == TreeMapItem::Bisection)) {
+
+ TreeMapItemListIterator first = it;
+ double valSum = 0;
+ int lenLeft = len;
+ //while (lenLeft>0 && valSum<user_sum/2) {
+ while (lenLeft>len/2) {
+ valSum += it.current()->value();
+ if (goBack) --it; else ++it;
+ lenLeft--;
+ }
+
+ // draw first half...
+ bool drawOn;
+
+ if (r.width() > r.height()) {
+ int halfPos = (int)((double)r.width() * valSum / user_sum);
+ TQRect firstRect = TQRect(r.x(), r.y(), halfPos, r.height());
+ drawOn = drawItemArray(p, item, firstRect,
+ valSum, first, len-lenLeft, goBack);
+ r.setRect(r.x()+halfPos, r.y(), r.width()-halfPos, r.height());
+ }
+ else {
+ int halfPos = (int)((double)r.height() * valSum / user_sum);
+ TQRect firstRect = TQRect(r.x(), r.y(), r.width(), halfPos);
+ drawOn = drawItemArray(p, item, firstRect,
+ valSum, first, len-lenLeft, goBack);
+ r.setRect(r.x(), r.y()+halfPos, r.width(), r.height()-halfPos);
+ }
+
+ // if no sorting, don't stop drawing
+ if (item->sorting(0) == -1) drawOn = true;
+
+ // second half
+ if (drawOn)
+ drawOn = drawItemArray(p, item, r, user_sum - valSum,
+ it, lenLeft, goBack);
+ else {
+ drawFill(item, p, r, it, len, goBack);
+ }
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " -drawItemArray(" << item->path(0).join("/")
+ << ")" << endl;
+
+ return drawOn;
+ }
+
+ bool hor = horizontal(item,r);
+
+ TreeMapItem* i;
+ while (len>0) {
+ i = it.current();
+ if (user_sum <= 0) {
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << "drawItemArray: Reset " << i->path(0).join("/") << endl;
+
+ i->clearItemRect();
+ if (goBack) --it; else ++it;
+ len--;
+ continue;
+ }
+
+ // stop drawing for small rectangles
+ if (((r.height() < _visibleWidth) &&
+ (r.width() < _visibleWidth)) ||
+ ((_minimalArea > 0) &&
+ (r.width() * r.height() < _minimalArea))) {
+
+ drawFill(item, p, r, it, len, goBack);
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " -drawItemArray(" << item->path(0).join("/")
+ << "): Stop" << endl;
+ return false;
+ }
+
+ if (i->splitMode() == TreeMapItem::AlwaysBest)
+ hor = r.width() > r.height();
+
+ int lastPos = hor ? r.width() : r.height();
+ double val = i->value();
+ int nextPos = (user_sum <= 0.0) ? 0: (int)(lastPos * val / user_sum +.5);
+ if (nextPos>lastPos) nextPos = lastPos;
+
+ if ((item->sorting(0) != -1) && (nextPos < _visibleWidth)) {
+ drawFill(item, p, r, it, len, goBack);
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " -drawItemArray(" << item->path(0).join("/")
+ << "): Stop" << endl;
+ return false;
+ }
+
+ TQRect currRect = r;
+
+ if (hor)
+ currRect.setWidth(nextPos);
+ else {
+ if (b2t)
+ currRect.setRect(r.x(), r.bottom()-nextPos+1, r.width(), nextPos);
+ else
+ currRect.setHeight(nextPos);
+ }
+
+ // don't draw very small rectangles:
+ if (nextPos >= _visibleWidth) {
+ i->setItemRect(currRect);
+ drawItems(p, i);
+ }
+ else {
+ i->clearItemRect();
+ drawFill(item, p, currRect);
+ }
+
+ // draw Separator
+ if (_drawSeparators && (nextPos<lastPos)) {
+ p->setPen(black);
+ if (hor) {
+ if (r.top()<=r.bottom())
+ p->drawLine(r.x() + nextPos, r.top(), r.x() + nextPos, r.bottom());
+ }
+ else {
+ if (r.left()<=r.right())
+ p->drawLine(r.left(), r.y() + nextPos, r.right(), r.y() + nextPos);
+ }
+ nextPos++;
+ }
+
+ if (hor)
+ r.setRect(r.x() + nextPos, r.y(), lastPos-nextPos, r.height());
+ else {
+ if (b2t)
+ r.setRect(r.x(), r.y(), r.width(), lastPos-nextPos);
+ else
+ r.setRect(r.x(), r.y() + nextPos, r.width(), lastPos-nextPos);
+ }
+
+ user_sum -= val;
+ if (goBack) --it; else ++it;
+ len--;
+ }
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " -drawItemArray(" << item->path(0).join("/")
+ << "): Continue" << endl;
+
+ return true;
+}
+
+
+/*----------------------------------------------------------------
+ * Popup menus for option setting
+ */
+
+void TreeMapWidget::splitActivated(int id)
+{
+ if (id == _splitID) setSplitMode(TreeMapItem::Bisection);
+ else if (id == _splitID+1) setSplitMode(TreeMapItem::Columns);
+ else if (id == _splitID+2) setSplitMode(TreeMapItem::Rows);
+ else if (id == _splitID+3) setSplitMode(TreeMapItem::AlwaysBest);
+ else if (id == _splitID+4) setSplitMode(TreeMapItem::Best);
+ else if (id == _splitID+5) setSplitMode(TreeMapItem::VAlternate);
+ else if (id == _splitID+6) setSplitMode(TreeMapItem::HAlternate);
+ else if (id == _splitID+7) setSplitMode(TreeMapItem::Horizontal);
+ else if (id == _splitID+8) setSplitMode(TreeMapItem::Vertical);
+}
+
+
+void TreeMapWidget::addSplitDirectionItems(TQPopupMenu* popup, int id)
+{
+ _splitID = id;
+ popup->setCheckable(true);
+
+ connect(popup, TQT_SIGNAL(activated(int)),
+ this, TQT_SLOT(splitActivated(int)));
+
+ popup->insertItem(i18n("Recursive Bisection"), id);
+ popup->insertItem(i18n("Columns"), id+1);
+ popup->insertItem(i18n("Rows"), id+2);
+ popup->insertItem(i18n("Always Best"), id+3);
+ popup->insertItem(i18n("Best"), id+4);
+ popup->insertItem(i18n("Alternate (V)"), id+5);
+ popup->insertItem(i18n("Alternate (H)"), id+6);
+ popup->insertItem(i18n("Horizontal"), id+7);
+ popup->insertItem(i18n("Vertical"), id+8);
+
+ switch(splitMode()) {
+ case TreeMapItem::Bisection: popup->setItemChecked(id,true); break;
+ case TreeMapItem::Columns: popup->setItemChecked(id+1,true); break;
+ case TreeMapItem::Rows: popup->setItemChecked(id+2,true); break;
+ case TreeMapItem::AlwaysBest: popup->setItemChecked(id+3,true); break;
+ case TreeMapItem::Best: popup->setItemChecked(id+4,true); break;
+ case TreeMapItem::VAlternate: popup->setItemChecked(id+5,true); break;
+ case TreeMapItem::HAlternate: popup->setItemChecked(id+6,true); break;
+ case TreeMapItem::Horizontal: popup->setItemChecked(id+7,true); break;
+ case TreeMapItem::Vertical: popup->setItemChecked(id+8,true); break;
+ default: break;
+ }
+}
+
+void TreeMapWidget::visualizationActivated(int id)
+{
+ if (id == _visID+2) setSkipIncorrectBorder(!skipIncorrectBorder());
+ else if (id == _visID+3) setBorderWidth(0);
+ else if (id == _visID+4) setBorderWidth(1);
+ else if (id == _visID+5) setBorderWidth(2);
+ else if (id == _visID+6) setBorderWidth(3);
+ else if (id == _visID+10) setAllowRotation(!allowRotation());
+ else if (id == _visID+11) setShadingEnabled(!isShadingEnabled());
+ else if (id<_visID+19 || id>_visID+100) return;
+
+ id -= 20+_visID;
+ int f = id/10;
+ if ((id%10) == 1) setFieldVisible(f, !fieldVisible(f));
+ else if ((id%10) == 2) setFieldForced(f, !fieldForced(f));
+ else if ((id%10) == 3) setFieldPosition(f, DrawParams::TopLeft);
+ else if ((id%10) == 4) setFieldPosition(f, DrawParams::TopCenter);
+ else if ((id%10) == 5) setFieldPosition(f, DrawParams::TopRight);
+ else if ((id%10) == 6) setFieldPosition(f, DrawParams::BottomLeft);
+ else if ((id%10) == 7) setFieldPosition(f, DrawParams::BottomCenter);
+ else if ((id%10) == 8) setFieldPosition(f, DrawParams::BottomRight);
+}
+
+void TreeMapWidget::addVisualizationItems(TQPopupMenu* popup, int id)
+{
+ _visID = id;
+
+ popup->setCheckable(true);
+
+ TQPopupMenu* bpopup = new TQPopupMenu();
+ bpopup->setCheckable(true);
+
+ connect(popup, TQT_SIGNAL(activated(int)),
+ this, TQT_SLOT(visualizationActivated(int)));
+ connect(bpopup, TQT_SIGNAL(activated(int)),
+ this, TQT_SLOT(visualizationActivated(int)));
+
+ TQPopupMenu* spopup = new TQPopupMenu();
+ addSplitDirectionItems(spopup, id+100);
+ popup->insertItem(i18n("Nesting"), spopup, id);
+
+ popup->insertItem(i18n("Border"), bpopup, id+1);
+ bpopup->insertItem(i18n("Correct Borders Only"), id+2);
+ bpopup->insertSeparator();
+ bpopup->insertItem(i18n("Width %1").arg(0), id+3);
+ bpopup->insertItem(i18n("Width %1").arg(1), id+4);
+ bpopup->insertItem(i18n("Width %1").arg(2), id+5);
+ bpopup->insertItem(i18n("Width %1").arg(3), id+6);
+ bpopup->setItemChecked(id+2, skipIncorrectBorder());
+ bpopup->setItemChecked(id+3, borderWidth()==0);
+ bpopup->setItemChecked(id+4, borderWidth()==1);
+ bpopup->setItemChecked(id+5, borderWidth()==2);
+ bpopup->setItemChecked(id+6, borderWidth()==3);
+
+ popup->insertItem(i18n("Allow Rotation"), id+10);
+ popup->setItemChecked(id+10,allowRotation());
+ popup->insertItem(i18n("Shading"), id+11);
+ popup->setItemChecked(id+11,isShadingEnabled());
+
+ if (_attr.size() ==0) return;
+
+ popup->insertSeparator();
+ int f;
+ TQPopupMenu* tpopup;
+ id += 20;
+ for (f=0;f<(int)_attr.size();f++, id+=10) {
+ tpopup = new TQPopupMenu();
+ tpopup->setCheckable(true);
+ popup->insertItem(_attr[f].type, tpopup, id);
+ tpopup->insertItem(i18n("Visible"), id+1);
+ tpopup->insertItem(i18n("Take Space From Children"), id+2);
+ tpopup->insertSeparator();
+ tpopup->insertItem(i18n("Top Left"), id+3);
+ tpopup->insertItem(i18n("Top Center"), id+4);
+ tpopup->insertItem(i18n("Top Right"), id+5);
+ tpopup->insertItem(i18n("Bottom Left"), id+6);
+ tpopup->insertItem(i18n("Bottom Center"), id+7);
+ tpopup->insertItem(i18n("Bottom Right"), id+8);
+
+ tpopup->setItemChecked(id+1,_attr[f].visible);
+ tpopup->setItemEnabled(id+2,_attr[f].visible);
+ tpopup->setItemEnabled(id+3,_attr[f].visible);
+ tpopup->setItemEnabled(id+4,_attr[f].visible);
+ tpopup->setItemEnabled(id+5,_attr[f].visible);
+ tpopup->setItemEnabled(id+6,_attr[f].visible);
+ tpopup->setItemEnabled(id+7,_attr[f].visible);
+ tpopup->setItemEnabled(id+8,_attr[f].visible);
+ tpopup->setItemChecked(id+2,_attr[f].forced);
+ tpopup->setItemChecked(id+3,_attr[f].pos == DrawParams::TopLeft);
+ tpopup->setItemChecked(id+4,_attr[f].pos == DrawParams::TopCenter);
+ tpopup->setItemChecked(id+5,_attr[f].pos == DrawParams::TopRight);
+ tpopup->setItemChecked(id+6,_attr[f].pos == DrawParams::BottomLeft);
+ tpopup->setItemChecked(id+7,_attr[f].pos == DrawParams::BottomCenter);
+ tpopup->setItemChecked(id+8,_attr[f].pos == DrawParams::BottomRight);
+
+ connect(tpopup, TQT_SIGNAL(activated(int)),
+ this, TQT_SLOT(visualizationActivated(int)));
+ }
+}
+
+void TreeMapWidget::selectionActivated(int id)
+{
+ TreeMapItem* i = _menuItem;
+ id -= _selectionID;
+ while (id>0 && i) {
+ i=i->parent();
+ id--;
+ }
+ if (i)
+ setSelected(i, true);
+}
+
+void TreeMapWidget::addSelectionItems(TQPopupMenu* popup,
+ int id, TreeMapItem* i)
+{
+ if (!i) return;
+
+ _selectionID = id;
+ _menuItem = i;
+
+ connect(popup, TQT_SIGNAL(activated(int)),
+ this, TQT_SLOT(selectionActivated(int)));
+
+ while (i) {
+ TQString name = i->text(0);
+ if (name.isEmpty()) break;
+ popup->insertItem(i->text(0), id++);
+ i = i->parent();
+ }
+}
+
+void TreeMapWidget::fieldStopActivated(int id)
+{
+ if (id == _fieldStopID) setFieldStop(0, TQString());
+ else {
+ TreeMapItem* i = _menuItem;
+ id -= _fieldStopID+1;
+ while (id>0 && i) {
+ i=i->parent();
+ id--;
+ }
+ if (i)
+ setFieldStop(0, i->text(0));
+ }
+}
+
+void TreeMapWidget::addFieldStopItems(TQPopupMenu* popup,
+ int id, TreeMapItem* i)
+{
+ _fieldStopID = id;
+
+ connect(popup, TQT_SIGNAL(activated(int)),
+ this, TQT_SLOT(fieldStopActivated(int)));
+
+ popup->insertItem(i18n("No %1 Limit").arg(fieldType(0)), id);
+ popup->setItemChecked(id, fieldStop(0).isEmpty());
+ _menuItem = i;
+ bool foundFieldStop = false;
+ if (i) {
+ popup->insertSeparator();
+
+ while (i) {
+ id++;
+ TQString name = i->text(0);
+ if (name.isEmpty()) break;
+ popup->insertItem(i->text(0), id);
+ if (fieldStop(0) == i->text(0)) {
+ popup->setItemChecked(id, true);
+ foundFieldStop = true;
+ }
+ i = i->parent();
+ }
+ }
+
+ if (!foundFieldStop && !fieldStop(0).isEmpty()) {
+ popup->insertSeparator();
+ popup->insertItem(fieldStop(0), id+1);
+ popup->setItemChecked(id+1, true);
+ }
+}
+
+void TreeMapWidget::areaStopActivated(int id)
+{
+ if (id == _areaStopID) setMinimalArea(-1);
+ else if (id == _areaStopID+1) {
+ int area = _menuItem ? (_menuItem->width() * _menuItem->height()) : -1;
+ setMinimalArea(area);
+ }
+ else if (id == _areaStopID+2) setMinimalArea(100);
+ else if (id == _areaStopID+3) setMinimalArea(400);
+ else if (id == _areaStopID+4) setMinimalArea(1000);
+ else if (id == _areaStopID+5) setMinimalArea(minimalArea()*2);
+ else if (id == _areaStopID+6) setMinimalArea(minimalArea()/2);
+}
+
+void TreeMapWidget::addAreaStopItems(TQPopupMenu* popup,
+ int id, TreeMapItem* i)
+{
+ _areaStopID = id;
+ _menuItem = i;
+
+ connect(popup, TQT_SIGNAL(activated(int)),
+ this, TQT_SLOT(areaStopActivated(int)));
+
+ bool foundArea = false;
+
+ popup->insertItem(i18n("No Area Limit"), id);
+ popup->setItemChecked(id, minimalArea() == -1);
+
+ if (i) {
+ int area = i->width() * i->height();
+ popup->insertSeparator();
+ popup->insertItem(i18n("Area of '%1' (%2)")
+ .arg(i->text(0)).arg(area), id+1);
+ if (area == minimalArea()) {
+ popup->setItemChecked(id+1, true);
+ foundArea = true;
+ }
+ }
+
+ popup->insertSeparator();
+ int area = 100, count;
+ for (count=0;count<3;count++) {
+ popup->insertItem(i18n("1 Pixel", "%n Pixels", area), id+2+count);
+ if (area == minimalArea()) {
+ popup->setItemChecked(id+2+count, true);
+ foundArea = true;
+ }
+ area = (area==100) ? 400 : (area==400) ? 1000 : 4000;
+ }
+
+ if (minimalArea()>0) {
+ popup->insertSeparator();
+ if (!foundArea) {
+ popup->insertItem(i18n("1 Pixel", "%n Pixels", minimalArea()), id+10);
+ popup->setItemChecked(id+10, true);
+ }
+
+ popup->insertItem(i18n("Double Area Limit (to %1)")
+ .arg(minimalArea()*2), id+5);
+ popup->insertItem(i18n("Halve Area Limit (to %1)")
+ .arg(minimalArea()/2), id+6);
+ }
+}
+
+
+void TreeMapWidget::depthStopActivated(int id)
+{
+ if (id == _depthStopID) setMaxDrawingDepth(-1);
+ else if (id == _depthStopID+1) {
+ int d = _menuItem ? _menuItem->depth() : -1;
+ setMaxDrawingDepth(d);
+ }
+ else if (id == _depthStopID+2) setMaxDrawingDepth(maxDrawingDepth()-1);
+ else if (id == _depthStopID+3) setMaxDrawingDepth(maxDrawingDepth()+1);
+}
+
+void TreeMapWidget::addDepthStopItems(TQPopupMenu* popup,
+ int id, TreeMapItem* i)
+{
+ _depthStopID = id;
+ _menuItem = i;
+
+ connect(popup, TQT_SIGNAL(activated(int)),
+ this, TQT_SLOT(depthStopActivated(int)));
+
+ bool foundDepth = false;
+
+ popup->insertItem(i18n("No Depth Limit"), id);
+ popup->setItemChecked(id, maxDrawingDepth() == -1);
+
+ if (i) {
+ int d = i->depth();
+ popup->insertSeparator();
+ popup->insertItem(i18n("Depth of '%1' (%2)")
+ .arg(i->text(0)).arg(d), id+1);
+ if (d == maxDrawingDepth()) {
+ popup->setItemChecked(id+1, true);
+ foundDepth = true;
+ }
+ }
+
+ if (maxDrawingDepth()>1) {
+ popup->insertSeparator();
+ if (!foundDepth) {
+ popup->insertItem(i18n("Depth %1").arg(maxDrawingDepth()), id+10);
+ popup->setItemChecked(id+10, true);
+ }
+
+ popup->insertItem(i18n("Decrement (to %1)")
+ .arg(maxDrawingDepth()-1), id+2);
+ popup->insertItem(i18n("Increment (to %1)")
+ .arg(maxDrawingDepth()+1), id+3);
+ }
+}
+
+
+
+/*----------------------------------------------------------------
+ * Option saving/restoring
+ */
+
+void TreeMapWidget::saveOptions(KConfigGroup* config, TQString prefix)
+{
+ config->writeEntry(prefix+"Nesting", splitModeString());
+ config->writeEntry(prefix+"AllowRotation", allowRotation());
+ config->writeEntry(prefix+"ShadingEnabled", isShadingEnabled());
+ config->writeEntry(prefix+"OnlyCorrectBorder", skipIncorrectBorder());
+ config->writeEntry(prefix+"BorderWidth", borderWidth());
+ config->writeEntry(prefix+"MaxDepth", maxDrawingDepth());
+ config->writeEntry(prefix+"MinimalArea", minimalArea());
+
+ int f, fCount = _attr.size();
+ config->writeEntry(prefix+"FieldCount", fCount);
+ for (f=0;f<fCount;f++) {
+ config->writeEntry(TQString(prefix+"FieldVisible%1").arg(f),
+ _attr[f].visible);
+ config->writeEntry(TQString(prefix+"FieldForced%1").arg(f),
+ _attr[f].forced);
+ config->writeEntry(TQString(prefix+"FieldStop%1").arg(f),
+ _attr[f].stop);
+ config->writeEntry(TQString(prefix+"FieldPosition%1").arg(f),
+ fieldPositionString(f));
+ }
+}
+
+
+void TreeMapWidget::restoreOptions(KConfigGroup* config, TQString prefix)
+{
+ bool enabled;
+ int num;
+ TQString str;
+
+ str = config->readEntry(prefix+"Nesting");
+ if (!str.isEmpty()) setSplitMode(str);
+
+ if (config->hasKey(prefix+"AllowRotation")) {
+ enabled = config->readBoolEntry(prefix+"AllowRotation", true);
+ setAllowRotation(enabled);
+ }
+
+ if (config->hasKey(prefix+"ShadingEnabled")) {
+ enabled = config->readBoolEntry(prefix+"ShadingEnabled", true);
+ setShadingEnabled(enabled);
+ }
+
+ if (config->hasKey(prefix+"OnlyCorrectBorder")) {
+ enabled = config->readBoolEntry(prefix+"OnlyCorrectBorder", false);
+ setSkipIncorrectBorder(enabled);
+ }
+
+ num = config->readNumEntry(prefix+"BorderWidth", -2);
+ if (num!=-2) setBorderWidth(num);
+
+ num = config->readNumEntry(prefix+"MaxDepth", -2);
+ if (num!=-2) setMaxDrawingDepth(num);
+
+ num = config->readNumEntry(prefix+"MinimalArea", -2);
+ if (num!=-2) setMinimalArea(num);
+
+ num = config->readNumEntry(prefix+"FieldCount", -2);
+ if (num<=0 || num>MAX_FIELD) return;
+
+ int f;
+ for (f=0;f<num;f++) {
+ str = TQString(prefix+"FieldVisible%1").arg(f);
+ if (config->hasKey(str))
+ setFieldVisible(f, config->readBoolEntry(str));
+
+ str = TQString(prefix+"FieldForced%1").arg(f);
+ if (config->hasKey(str))
+ setFieldForced(f, config->readBoolEntry(str));
+
+ str = config->readEntry(TQString(prefix+"FieldStop%1").arg(f));
+ setFieldStop(f, str);
+
+ str = config->readEntry(TQString(prefix+"FieldPosition%1").arg(f));
+ if (!str.isEmpty()) setFieldPosition(f, str);
+ }
+}
+
+#include "treemap.moc"
diff --git a/kdecachegrind/kdecachegrind/treemap.h b/kdecachegrind/kdecachegrind/treemap.h
new file mode 100644
index 0000000..422cd35
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/treemap.h
@@ -0,0 +1,759 @@
+/* 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.
+*/
+
+/**
+ * A Widget for visualizing hierarchical metrics as areas.
+ * The API is similar to TQListView.
+ *
+ * This file defines the following classes:
+ * DrawParams, RectDrawing, TreeMapItem, TreeMapWidget
+ *
+ * DrawParams/RectDrawing allows reusing of TreeMap drawing
+ * functions in other widgets.
+ */
+
+#ifndef TREEMAP_H
+#define TREEMAP_H
+
+#include <tqstring.h>
+#include <tqwidget.h>
+#include <tqpixmap.h>
+#include <tqptrlist.h>
+#include <tqvaluevector.h>
+#include <tqcolor.h>
+#include <tqapplication.h>
+#include <tqstringlist.h>
+
+class TQPopupMenu;
+class TreeMapTip;
+class TreeMapWidget;
+class TreeMapItem;
+class TreeMapItemList;
+class TQString;
+
+class KConfigGroup;
+
+
+/**
+ * Drawing parameters for an object.
+ * A Helper Interface for RectDrawing.
+ */
+class DrawParams
+{
+public:
+ /**
+ * Positions for drawing into a rectangle.
+ *
+ * The specified position assumes no rotation.
+ * If there is more than one text for one position, it is put
+ * nearer to the center of the item.
+ *
+ * Drawing at top positions cuts free space from top,
+ * drawing at bottom positions cuts from bottom.
+ * Default usually gives positions clockwise according to field number.
+ */
+ enum Position { TopLeft, TopCenter, TopRight,
+ BottomLeft, BottomCenter, BottomRight,
+ Default, Unknown};
+
+ // no constructor as this is an abstract class
+ virtual ~DrawParams() {}
+
+ virtual TQString text(int) const = 0;
+ virtual TQPixmap pixmap(int) const = 0;
+ virtual Position position(int) const = 0;
+ // 0: no limit, negative: leave at least -maxLines() free
+ virtual int maxLines(int) const { return 0; }
+ virtual int fieldCount() const { return 0; }
+
+ virtual TQColor backColor() const { return TQt::white; }
+ virtual const TQFont& font() const = 0;
+
+ virtual bool selected() const { return false; }
+ virtual bool current() const { return false; }
+ virtual bool shaded() const { return true; }
+ virtual bool rotated() const { return false; }
+ virtual bool drawFrame() const { return true; }
+};
+
+
+/*
+ * DrawParam with attributes stored
+ */
+class StoredDrawParams: public DrawParams
+{
+public:
+ StoredDrawParams();
+ StoredDrawParams(TQColor c,
+ bool selected = false, bool current = false);
+
+ // getters
+ TQString text(int) const;
+ TQPixmap pixmap(int) const;
+ Position position(int) const;
+ int maxLines(int) const;
+ int fieldCount() const { return _field.size(); }
+
+ TQColor backColor() const { return _backColor; }
+ bool selected() const { return _selected; }
+ bool current() const { return _current; }
+ bool shaded() const { return _shaded; }
+ bool rotated() const { return _rotated; }
+ bool drawFrame() const { return _drawFrame; }
+
+ const TQFont& font() const;
+
+ // attribute setters
+ void setField(int f, const TQString& t, TQPixmap pm = TQPixmap(),
+ Position p = Default, int maxLines = 0);
+ void setText(int f, const TQString&);
+ void setPixmap(int f, const TQPixmap&);
+ void setPosition(int f, Position);
+ void setMaxLines(int f, int);
+ void setBackColor(const TQColor& c) { _backColor = c; }
+ void setSelected(bool b) { _selected = b; }
+ void setCurrent(bool b) { _current = b; }
+ void setShaded(bool b) { _shaded = b; }
+ void setRotated(bool b) { _rotated = b; }
+ void drawFrame(bool b) { _drawFrame = b; }
+
+protected:
+ TQColor _backColor;
+ bool _selected :1;
+ bool _current :1;
+ bool _shaded :1;
+ bool _rotated :1;
+ bool _drawFrame :1;
+
+private:
+ // resize field array if needed to allow to access field <f>
+ void ensureField(int f);
+
+ struct Field {
+ TQString text;
+ TQPixmap pix;
+ Position pos;
+ int maxLines;
+ };
+
+ TQValueVector<Field> _field;
+};
+
+
+/* State for drawing on a rectangle.
+ *
+ * Following drawing functions are provided:
+ * - background drawing with shading and 3D frame
+ * - successive pixmap/text drawing at various positions with wrap-around
+ * optimized for minimal space usage (e.g. if a text is drawn at top right
+ * after text on top left, the same line is used if space allows)
+ *
+ */
+class RectDrawing
+{
+public:
+ RectDrawing(TQRect);
+ ~RectDrawing();
+
+ // The default DrawParams object used.
+ DrawParams* drawParams();
+ // we take control over the given object (i.e. delete at destruction)
+ void setDrawParams(DrawParams*);
+
+ // draw on a given TQPainter, use this class as info provider per default
+ void drawBack(TQPainter*, DrawParams* dp = 0);
+ /* Draw field at position() from pixmap()/text() with maxLines().
+ * Returns true if something was drawn
+ */
+ bool drawField(TQPainter*, int f, DrawParams* dp = 0);
+
+ // resets rectangle for free space
+ void setRect(TQRect);
+
+ // Returns the rectangle area still free of text/pixmaps after
+ // a number of drawText() calls.
+ TQRect remainingRect(DrawParams* dp = 0);
+
+private:
+ int _usedTopLeft, _usedTopCenter, _usedTopRight;
+ int _usedBottomLeft, _usedBottomCenter, _usedBottomRight;
+ TQRect _rect;
+
+ // temporary
+ int _fontHeight;
+ TQFontMetrics* _fm;
+ DrawParams* _dp;
+};
+
+
+class TreeMapItemList: public TQPtrList<TreeMapItem>
+{
+public:
+ TreeMapItem* commonParent();
+protected:
+ int compareItems ( Item item1, Item item2 );
+};
+
+typedef TQPtrListIterator<TreeMapItem> TreeMapItemListIterator;
+
+
+/**
+ * Base class of items in TreeMap.
+ *
+ * This class supports an arbitrary number of text() strings
+ * positioned counterclock-wise starting at TopLeft. Each item
+ * has its own static value(), sum() and sorting(). The
+ * splitMode() and borderWidth() is taken from a TreeMapWidget.
+ *
+ * If you want more flexibility, reimplement TreeMapItem and
+ * override the corresponding methods. For dynamic creation of child
+ * items on demand, reimplement children().
+ */
+class TreeMapItem: public StoredDrawParams
+{
+public:
+
+ /**
+ * Split direction for nested areas:
+ * AlwaysBest: Choose split direction for every subitem according to
+ * longest side of rectangle left for drawing
+ * Best: Choose split direction for all subitems of an area
+ * depending on longest side
+ * HAlternate:Qt::Horizontal at top; alternate direction on depth step
+ * VAlternate:Qt::Vertical at top; alternate direction on depth step
+ * Qt::Horizontal: Always horizontal split direction
+ * Qt::Vertical: Always vertical split direction
+ */
+ enum SplitMode { Bisection, Columns, Rows,
+ AlwaysBest, Best,
+ HAlternate, VAlternate,
+ Horizontal, Vertical };
+
+ TreeMapItem(TreeMapItem* parent = 0, double value = 1.0 );
+ TreeMapItem(TreeMapItem* parent, double value,
+ TQString text1, TQString text2 = TQString(),
+ TQString text3 = TQString(), TQString text4 = TQString());
+ virtual ~TreeMapItem();
+
+ bool isChildOf(TreeMapItem*);
+
+ TreeMapItem* commonParent(TreeMapItem* item);
+
+ // force a redraw of this item
+ void redraw();
+
+ // delete all children
+ void clear();
+
+ // force new child generation & refresh
+ void refresh();
+
+ // call in a reimplemented items() method to check if already called
+ // after a clear(), this will return false
+ bool initialized();
+
+ /**
+ * Adds an item to a parent.
+ * When no sorting is used, the item is appended (drawn at bottom).
+ * This is only needed if the parent was not already specified in the
+ * construction of the item.
+ */
+ void addItem(TreeMapItem*);
+
+ /**
+ * Returns a list of text strings of specified text number,
+ * from root up to this item.
+ */
+ TQStringList path(int) const;
+
+ /**
+ * Depth of this item. This is the distance to root.
+ */
+ int depth() const;
+
+ /**
+ * Parent Item
+ */
+ TreeMapItem* parent() const { return _parent; }
+
+ /**
+ * Temporary rectangle used for drawing this item the last time.
+ * This is internally used to map from a point to an item.
+ */
+ void setItemRect(const TQRect& r) { _rect = r; }
+ void clearItemRect();
+ const TQRect& itemRect() const { return _rect; }
+ int width() const { return _rect.width(); }
+ int height() const { return _rect.height(); }
+
+ /**
+ * Temporary rectangle list of free space of this item.
+ * Used internally to enable tooltip.
+ */
+ void clearFreeRects();
+ TQPtrList<TQRect>* freeRects() const { return _freeRects; }
+ void addFreeRect(const TQRect& r);
+
+ /**
+ * Temporary child item index of the child that was current() recently.
+ */
+ int index() const { return _index; }
+ void setIndex(int i) { _index = i; }
+
+
+ /**
+ * TreeMap widget this item is put in.
+ */
+ TreeMapWidget* widget() const { return _widget; }
+
+ void setParent(TreeMapItem* p);
+ void setWidget(TreeMapWidget* w) { _widget = w; }
+ void setSum(double s) { _sum = s; }
+ void setValue(double s) { _value = s; }
+
+ virtual double sum() const;
+ virtual double value() const;
+ // replace "Default" position with setting from TreeMapWidget
+ virtual Position position(int) const;
+ virtual const TQFont& font() const;
+ virtual bool isMarked(int) const;
+
+ virtual int borderWidth() const;
+
+ /**
+ * Returns the text number after that sorting is done or
+ * -1 for no sorting, -2 for value() sorting (default).
+ * If ascending != 0, a bool value is written at that location
+ * to indicate if sorting should be ascending.
+ */
+ virtual int sorting(bool* ascending) const;
+
+ /**
+ * Set the sorting for child drawing.
+ *
+ * Default is no sorting: <textNo> = -1
+ * For value() sorting, use <textNo> = -2
+ *
+ * For fast sorting, set this to -1 before child insertions and call
+ * again after inserting all children.
+ */
+ void setSorting(int textNo, bool ascending = true);
+
+ /**
+ * Resort according to the already set sorting.
+ *
+ * This has to be done if the sorting base changes (e.g. text or values
+ * change). If this is only true for the children of this item, you can
+ * set the recursive parameter to false.
+ */
+ void resort(bool recursive = true);
+
+ virtual SplitMode splitMode() const;
+ virtual int rtti() const;
+ // not const as this can create children on demand
+ virtual TreeMapItemList* children();
+
+protected:
+ TreeMapItemList* _children;
+ double _sum, _value;
+
+private:
+ TreeMapWidget* _widget;
+ TreeMapItem* _parent;
+
+ int _sortTextNo;
+ bool _sortAscending;
+
+ // temporary layout
+ TQRect _rect;
+ TQPtrList<TQRect>* _freeRects;
+ int _depth;
+
+ // temporary self value (when using level skipping)
+ double _unused_self;
+
+ // index of last active subitem
+ int _index;
+};
+
+
+/**
+ * Class for visualization of a metric of hierarchically
+ * nested items as 2D areas.
+ */
+class TreeMapWidget: public TQWidget
+{
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+
+ /**
+ * Same as in TQListBox/TQListView
+ */
+ enum SelectionMode { Single, Multi, Extended, NoSelection };
+
+ /* The widget becomes owner of the base item */
+ TreeMapWidget(TreeMapItem* base, TQWidget* parent=0, const char* name=0);
+ ~TreeMapWidget();
+
+ /**
+ * Returns the TreeMapItem filling out the widget space
+ */
+ TreeMapItem* base() const { return _base; }
+
+ /**
+ * Returns a reference to the current widget font.
+ */
+ const TQFont& currentFont() const;
+
+ /**
+ * Returns the area item at position x/y, independent from any
+ * maxSelectDepth setting.
+ */
+ TreeMapItem* item(int x, int y) const;
+
+ /**
+ * Returns the nearest item with a visible area; this
+ * can be the given item itself.
+ */
+ TreeMapItem* visibleItem(TreeMapItem*) const;
+
+ /**
+ * Returns the item possible for selection. this returns the
+ * given item itself or a parent thereof,
+ * depending on setting of maxSelectDepth().
+ */
+ TreeMapItem* possibleSelection(TreeMapItem*) const;
+
+ /**
+ * Selects or unselects an item.
+ * In multiselection mode, the constrain that a selected item
+ * has no selected children or parents stays true.
+ */
+ void setSelected(TreeMapItem*, bool selected = true);
+
+ /**
+ * Switches on the marking <markNo>. Marking 0 switches off marking.
+ * This is mutually exclusive to selection, and is automatically
+ * switched off when selection is changed (also by the user).
+ * Marking is visually the same as selection, and is based on
+ * TreeMapItem::isMarked(<markNo>).
+ * This enables to programmatically show multiple selected items
+ * at once even in single selection mode.
+ */
+ void setMarked(int markNo = 1, bool redraw = true);
+
+ /**
+ * Clear selection of all selected items which are children of
+ * parent. When parent == 0, clears whole selection
+ * Returns true if selection changed.
+ */
+ bool clearSelection(TreeMapItem* parent = 0);
+
+ /**
+ * Selects or unselects items in a range.
+ * This is needed internally for Shift-Click in Extented mode.
+ * Range means for a hierarchical widget:
+ * - select/unselect i1 and i2 according selected
+ * - search common parent of i1 and i2, and select/unselect the
+ * range of direct children between but excluding the child
+ * leading to i1 and the child leading to i2.
+ */
+ void setRangeSelection(TreeMapItem* i1,
+ TreeMapItem* i2, bool selected);
+
+ /**
+ * Sets the current item.
+ * The current item is mainly used for keyboard navigation.
+ */
+ void setCurrent(TreeMapItem*, bool kbd=false);
+
+ /**
+ * Set the maximal depth a selected item can have.
+ * If you try to select a item with higher depth, the ancestor holding
+ * this condition is used.
+ *
+ * See also possibleSelection().
+ */
+ void setMaxSelectDepth(int d) { _maxSelectDepth = d; }
+
+
+ void setSelectionMode(SelectionMode m) { _selectionMode = m; }
+
+ /**
+ * for setting/getting global split direction
+ */
+ void setSplitMode(TreeMapItem::SplitMode m);
+ TreeMapItem::SplitMode splitMode() const;
+ // returns true if string was recognized
+ bool setSplitMode(TQString);
+ TQString splitModeString() const;
+
+
+ /*
+ * Shading of rectangles enabled ?
+ */
+ void setShadingEnabled(bool s);
+ bool isShadingEnabled() const { return _shading; }
+
+ /* Setting for a whole depth level: draw 3D frame (default) or solid */
+ void drawFrame(int d, bool b);
+ bool drawFrame(int d) const { return (d<4)?_drawFrame[d]:true; }
+
+ /* Setting for a whole depth level: draw items (default) or transparent */
+ void setTransparent(int d, bool b);
+ bool isTransparent(int d) const { return (d<4)?_transparent[d]:false; }
+
+ /**
+ * Items usually have a size proportional to their value().
+ * With <width>, you can give the minimum width
+ * of the resulting rectangle to still be drawn.
+ * For space not used because of to small items, you can specify
+ * with <reuseSpace> if the background should shine through or
+ * the space will be used to enlarge the next item to be drawn
+ * at this level.
+ */
+ void setVisibleWidth(int width, bool reuseSpace = false);
+
+ /**
+ * If a children value() is almost the parents sum(),
+ * it can happen that the border to be drawn for visibilty of
+ * nesting relations takes to much space, and the
+ * parent/child size relation can not be mapped to a correct
+ * area size relation.
+ *
+ * Either
+ * (1) Ignore the incorrect drawing, or
+ * (2) Skip drawing of the parent level alltogether.
+ */
+ void setSkipIncorrectBorder(bool enable = true);
+ bool skipIncorrectBorder() const { return _skipIncorrectBorder; }
+
+ /**
+ * Maximal nesting depth
+ */
+ void setMaxDrawingDepth(int d);
+ int maxDrawingDepth() const { return _maxDrawingDepth; }
+
+ /**
+ * Minimal area for rectangles to draw
+ */
+ void setMinimalArea(int area);
+ int minimalArea() const { return _minimalArea; }
+
+ /* defaults for text attributes */
+ TQString defaultFieldType(int) const;
+ TQString defaultFieldStop(int) const;
+ bool defaultFieldVisible(int) const;
+ bool defaultFieldForced(int) const;
+ DrawParams::Position defaultFieldPosition(int) const;
+
+ /**
+ * Set the type name of a field.
+ * This is important for the visualization menu generated
+ * with visualizationMenu()
+ */
+ void setFieldType(int, TQString);
+ TQString fieldType(int) const;
+
+ /**
+ * Stop drawing at item with name
+ */
+ void setFieldStop(int, TQString);
+ TQString fieldStop(int) const;
+
+ /**
+ * Should the text with number textNo be visible?
+ * This is only done if remaining space is enough to allow for
+ * proportional size constrains.
+ */
+ void setFieldVisible(int, bool);
+ bool fieldVisible(int) const;
+
+ /**
+ * Should the drawing of the name into the rectangle be forced?
+ * This enables drawing of the name before drawing subitems, and
+ * thus destroys proportional constrains.
+ */
+ void setFieldForced(int, bool);
+ bool fieldForced(int) const;
+
+ /**
+ * Set the field position in the area. See TreeMapItem::Position
+ */
+ void setFieldPosition(int, DrawParams::Position);
+ DrawParams::Position fieldPosition(int) const;
+ void setFieldPosition(int, TQString);
+ TQString fieldPositionString(int) const;
+
+ /**
+ * Do we allow the texts to be rotated by 90 degrees for better fitting?
+ */
+ void setAllowRotation(bool);
+ bool allowRotation() const { return _allowRotation; }
+
+ void setBorderWidth(int w);
+ int borderWidth() const { return _borderWidth; }
+
+ /**
+ * Save/restore options.
+ */
+ void saveOptions(KConfigGroup*, TQString prefix = TQString());
+ void restoreOptions(KConfigGroup*, TQString prefix = TQString());
+
+ /**
+ * These functions populate given popup menus.
+ * The added items are already connected to handlers.
+ *
+ * The int is the menu id where to start for the items (100 IDs reserved).
+ */
+ void addSplitDirectionItems(TQPopupMenu*, int);
+ void addSelectionItems(TQPopupMenu*, int, TreeMapItem*);
+ void addFieldStopItems(TQPopupMenu*, int, TreeMapItem*);
+ void addAreaStopItems(TQPopupMenu*, int, TreeMapItem*);
+ void addDepthStopItems(TQPopupMenu*, int, TreeMapItem*);
+ void addVisualizationItems(TQPopupMenu*, int);
+
+ TreeMapWidget* widget() { return this; }
+ TreeMapItem* current() const { return _current; }
+ TreeMapItemList selection() const { return _selection; }
+ bool isSelected(TreeMapItem* i) const;
+ int maxSelectDepth() const { return _maxSelectDepth; }
+ SelectionMode selectionMode() const { return _selectionMode; }
+
+ /**
+ * Return tooltip string to show for a item (can be rich text)
+ * Default implementation gives lines with "text0 (text1)" going to root.
+ */
+ virtual TQString tipString(TreeMapItem* i) const;
+
+ /**
+ * Redraws an item with all children.
+ * This takes changed values(), sums(), colors() and text() into account.
+ */
+ void redraw(TreeMapItem*);
+ void redraw() { redraw(_base); }
+
+ /**
+ * Resort all TreeMapItems. See TreeMapItem::resort().
+ */
+ void resort() { _base->resort(true); }
+
+ // internal
+ void drawTreeMap();
+
+ // used internally when items are destroyed
+ void deletingItem(TreeMapItem*);
+
+protected slots:
+ void splitActivated(int);
+ void selectionActivated(int);
+ void fieldStopActivated(int);
+ void areaStopActivated(int);
+ void depthStopActivated(int);
+ void visualizationActivated(int);
+
+signals:
+ void selectionChanged();
+ void selectionChanged(TreeMapItem*);
+
+ /**
+ * This signal is emitted if the current item changes.
+ * If the change is done because of keyboard navigation,
+ * the <kbd> is set to true
+ */
+ void currentChanged(TreeMapItem*, bool keyboard);
+ void clicked(TreeMapItem*);
+ void returnPressed(TreeMapItem*);
+ void doubleClicked(TreeMapItem*);
+ void rightButtonPressed(TreeMapItem*, const TQPoint &);
+ void contextMenuRequested(TreeMapItem*, const TQPoint &);
+
+protected:
+ void mousePressEvent( TQMouseEvent * );
+ void contextMenuEvent( TQContextMenuEvent * );
+ void mouseReleaseEvent( TQMouseEvent * );
+ void mouseMoveEvent( TQMouseEvent * );
+ void mouseDoubleClickEvent( TQMouseEvent * );
+ void keyPressEvent( TQKeyEvent* );
+ void paintEvent( TQPaintEvent * );
+ void resizeEvent( TQResizeEvent * );
+ void showEvent( TQShowEvent * );
+ void fontChange( const TQFont& );
+
+private:
+ TreeMapItemList diff(TreeMapItemList&, TreeMapItemList&);
+ // returns true if selection changed
+ TreeMapItem* setTmpSelected(TreeMapItem*, bool selected = true);
+ TreeMapItem* setTmpRangeSelection(TreeMapItem* i1,
+ TreeMapItem* i2, bool selected);
+ bool isTmpSelected(TreeMapItem* i);
+
+ void drawItem(TQPainter* p, TreeMapItem*);
+ void drawItems(TQPainter* p, TreeMapItem*);
+ bool horizontal(TreeMapItem* i, const TQRect& r);
+ void drawFill(TreeMapItem*,TQPainter* p, TQRect& r);
+ void drawFill(TreeMapItem*,TQPainter* p, TQRect& r,
+ TreeMapItemListIterator it, int len, bool goBack);
+ bool drawItemArray(TQPainter* p, TreeMapItem*, TQRect& r, double,
+ TreeMapItemListIterator it, int len, bool);
+ bool resizeAttr(int);
+
+ TreeMapItem* _base;
+ TreeMapItem *_current, *_pressed, *_lastOver, *_oldCurrent;
+ TreeMapTip* _tip;
+ int _maxSelectDepth, _maxDrawingDepth;
+
+ // attributes for field, per textNo
+ struct FieldAttr {
+ TQString type, stop;
+ bool visible, forced;
+ DrawParams::Position pos;
+ };
+ TQValueVector<FieldAttr> _attr;
+
+ SelectionMode _selectionMode;
+ TreeMapItem::SplitMode _splitMode;
+ int _visibleWidth, _stopArea, _minimalArea, _borderWidth;
+ bool _reuseSpace, _skipIncorrectBorder, _drawSeparators, _shading;
+ bool _allowRotation;
+ bool _transparent[4], _drawFrame[4];
+ TreeMapItem * _needsRefresh;
+ TreeMapItemList _selection;
+ int _markNo;
+
+ // for the context menus: start IDs
+ int _splitID, _selectionID, _visID;
+ int _fieldStopID, _areaStopID, _depthStopID;
+ TreeMapItem* _menuItem;
+
+ // temporary selection while dragging, used for drawing
+ // most of the time, _selection == _tmpSelection
+ TreeMapItemList _tmpSelection;
+ bool _inShiftDrag, _inControlDrag;
+
+ // temporary widget font metrics while drawing
+ TQFont _font;
+ int _fontHeight;
+
+ // back buffer pixmap
+ TQPixmap _pixmap;
+};
+
+#endif
diff --git a/kdecachegrind/kdecachegrind/utils.cpp b/kdecachegrind/kdecachegrind/utils.cpp
new file mode 100644
index 0000000..65c7e34
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/utils.cpp
@@ -0,0 +1,483 @@
+/* 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.
+*/
+
+/*
+ * Utility classes for KCachegrind
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_MMAP
+#include <unistd.h>
+#include <sys/mman.h>
+#endif
+
+#include <tqfile.h>
+#include <errno.h>
+
+#include "utils.h"
+
+
+// class FixString
+
+FixString::FixString(const char* str, int len)
+{
+ _str = str;
+ _len = len;
+}
+
+bool FixString::stripFirst(char& c)
+{
+ if (!_len) {
+ c = 0;
+ return false;
+ }
+
+ c = *_str;
+ _str++;
+ _len--;
+ return true;
+ }
+
+bool FixString::stripPrefix(const char* p)
+{
+ if (_len == 0) return false;
+ if (!p || (*p != *_str)) return false;
+
+ const char* s = _str+1;
+ int l = _len-1;
+ p++;
+ while(*p) {
+ if (l==0) return false;
+ if (*s != *p) return false;
+ p++;
+ s++;
+ l--;
+ }
+ _str = s;
+ _len = l;
+ return true;
+}
+
+
+// this parses hexadecimal (with prefix '0x' too)
+bool FixString::stripUInt(unsigned int& v, bool stripSpaces)
+{
+ if (_len==0) {
+ v = 0;
+ return false;
+ }
+
+ char c = *_str;
+ if (c<'0' || c>'9') {
+ v = 0;
+ return false;
+ }
+
+ v = c-'0';
+ const char* s = _str+1;
+ int l = _len-1;
+ c = *s;
+
+ if ((l>0) && (c == 'x') && (v==0)) {
+ // hexadecimal
+ s++;
+ c = *s;
+ l--;
+
+ while(l>0) {
+ if (c>='0' && c<='9')
+ v = 16*v + (c-'0');
+ else if (c>='a' && c<='f')
+ v = 16*v + 10 + (c-'a');
+ else if (c>='A' && c<='F')
+ v = 16*v + 10 + (c-'A');
+ else
+ break;
+ s++;
+ c = *s;
+ l--;
+ }
+ }
+ else {
+ // decimal
+
+ while(l>0) {
+ if (c<'0' || c>'9') break;
+ v = 10*v + (c-'0');
+ s++;
+ c = *s;
+ l--;
+ }
+ }
+
+ if (stripSpaces)
+ while(l>0) {
+ if (c != ' ') break;
+ s++;
+ c = *s;
+ l--;
+ }
+
+ _str = s;
+ _len = l;
+ return true;
+}
+
+
+void FixString::stripSurroundingSpaces()
+{
+ if (_len==0) return;
+
+ // leading spaces
+ while((_len>0) && (*_str==' ')) {
+ _len--;
+ _str++;
+ }
+
+ // trailing spaces
+ while((_len>0) && (_str[_len-1]==' ')) {
+ _len--;
+ }
+}
+
+void FixString::stripSpaces()
+{
+ while((_len>0) && (*_str==' ')) {
+ _len--;
+ _str++;
+ }
+}
+
+bool FixString::stripName(FixString& s)
+{
+ if (_len==0) return false;
+
+ // first char has to be a letter or "_"
+ if (!TQChar(*_str).isLetter() && (*_str != '_')) return false;
+
+ int newLen = 1;
+ const char* newStr = _str;
+
+ _str++;
+ _len--;
+
+ while(_len>0) {
+ if (!TQChar(*_str).isLetterOrNumber()
+ && (*_str != '_')) break;
+
+ newLen++;
+ _str++;
+ _len--;
+ }
+
+ s.set(newStr, newLen);
+ return true;
+}
+
+FixString FixString::stripUntil(char c)
+{
+ if (_len == 0) return FixString();
+
+ const char* newStr = _str;
+ int newLen = 0;
+
+ while(_len>0) {
+ if (*_str == c) {
+ _str++;
+ _len--;
+ break;
+ }
+
+ _str++;
+ _len--;
+ newLen++;
+ }
+ return FixString(newStr, newLen);
+}
+
+bool FixString::stripUInt64(uint64& v, bool stripSpaces)
+{
+ if (_len==0) {
+ v = 0;
+ return false;
+ }
+
+ char c = *_str;
+ if (c<'0' || c>'9') {
+ v = 0;
+ return false;
+ }
+
+ v = c-'0';
+ const char* s = _str+1;
+ int l = _len-1;
+ c = *s;
+
+ if ((l>0) && (c == 'x') && (v==0)) {
+ // hexadecimal
+ s++;
+ c = *s;
+ l--;
+
+ while(l>0) {
+ if (c>='0' && c<='9')
+ v = 16*v + (c-'0');
+ else if (c>='a' && c<='f')
+ v = 16*v + 10 + (c-'a');
+ else if (c>='A' && c<='F')
+ v = 16*v + 10 + (c-'A');
+ else
+ break;
+ s++;
+ c = *s;
+ l--;
+ }
+ }
+ else {
+ // decimal
+ while(l>0) {
+ if (c<'0' || c>'9') break;
+ v = 10*v + (c-'0');
+ s++;
+ c = *s;
+ l--;
+ }
+ }
+
+ if (stripSpaces)
+ while(l>0) {
+ if (c != ' ') break;
+ s++;
+ c = *s;
+ l--;
+ }
+
+ _str = s;
+ _len = l;
+ return true;
+}
+
+
+bool FixString::stripInt64(int64& v, bool stripSpaces)
+{
+ if (_len==0) {
+ v = 0;
+ return false;
+ }
+
+ char c = *_str;
+ if (c<'0' || c>'9') {
+ v = 0;
+ return false;
+ }
+
+ v = c-'0';
+ const char* s = _str+1;
+ int l = _len-1;
+ c = *s;
+
+ if ((l>0) && (c == 'x') && (v==0)) {
+ // hexadecimal
+ s++;
+ c = *s;
+ l--;
+
+ while(l>0) {
+ if (c>='0' && c<='9')
+ v = 16*v + (c-'0');
+ else if (c>='a' && c<='f')
+ v = 16*v + 10 + (c-'a');
+ else if (c>='A' && c<='F')
+ v = 16*v + 10 + (c-'A');
+ else
+ break;
+ s++;
+ c = *s;
+ l--;
+ }
+ }
+ else {
+ // decimal
+
+ while(l>0) {
+ if (c<'0' || c>'9') break;
+ v = 10*v + (c-'0');
+ s++;
+ c = *s;
+ l--;
+ }
+ }
+
+ if (stripSpaces)
+ while(l>0) {
+ if (c != ' ') break;
+ s++;
+ c = *s;
+ l--;
+ }
+
+ _str = s;
+ _len = l;
+ return true;
+}
+
+
+
+// class FixFile
+
+FixFile::FixFile(TQFile* file)
+{
+ if (!file) {
+ _len = 0;
+ _currentLeft = 0;
+ _openError = true;
+ return;
+ }
+
+ _filename = file->name();
+ if (!file->isOpen() && !file->open( IO_ReadOnly ) ) {
+ qWarning( "%s: %s", (const char*) TQFile::encodeName(_filename),
+ strerror( errno ) );
+ _len = 0;
+ _currentLeft = 0;
+ _openError = true;
+ return;
+ }
+
+ _openError = false;
+ _used_mmap = false;
+
+#ifdef HAVE_MMAP
+ char *addr = 0;
+ size_t len = file->size();
+ if (len>0) addr = (char *) mmap( addr, len,
+ PROT_READ, MAP_PRIVATE,
+ file->handle(), 0 );
+ if (addr && (addr != MAP_FAILED)) {
+ // mmap succeeded
+ _base = addr;
+ _len = len;
+ _used_mmap = true;
+
+ if (0) qDebug("Mapped '%s'", _filename.ascii());
+ } else {
+#endif // HAVE_MMAP
+ // try reading the data into memory instead
+ _data = file->readAll();
+ _base = _data.data();
+ _len = _data.size();
+#ifdef HAVE_MMAP
+ }
+#endif // HAVE_MMAP
+
+ _current = _base;
+ _currentLeft = _len;
+}
+
+FixFile::~FixFile()
+{
+ // if the file was read into _data, it will be deleted automatically
+
+#ifdef HAVE_MMAP
+ if (_used_mmap) {
+ if (0) qDebug("Unmapping '%s'", _filename.ascii());
+ if (munmap(_base, _len) != 0)
+ qWarning( "munmap: %s", strerror( errno ) );
+ }
+#endif // HAVE_MMAP
+}
+
+bool FixFile::nextLine(FixString& str)
+{
+ if (_currentLeft == 0) return false;
+
+ unsigned left = _currentLeft;
+ char* current = _current;
+
+ while(left>0) {
+ if (*current == 0 || *current == '\n') break;
+ current++;
+ left--;
+ }
+
+ if (0) {
+ char tmp[200];
+ int l = _currentLeft-left;
+ if (l>199) l = 199;
+ strncpy(tmp, _current, l);
+ tmp[l] = 0;
+ qDebug("[FixFile::nextLine] At %d, len %d: '%s'",
+ _current - _base, _currentLeft-left, tmp);
+ }
+
+ str.set(_current, _currentLeft-left);
+
+ if (*current == '\n') {
+ current++;
+ left--;
+ }
+ _current = current;
+ _currentLeft = left;
+
+ return true;
+}
+
+bool FixFile::setCurrent(unsigned pos)
+{
+ if (pos > _len) return false;
+
+ _current = _base + pos;
+ _currentLeft = _len - pos;
+ return true;
+}
+
+
+#if 0
+
+// class AppendList
+
+
+AppendList::AppendList()
+{
+ _next = 0;
+ _current = 0;
+ _last = 0;
+
+ _count = 0;
+ _currentIndex = 0;
+ _lastIndex = 0;
+ _autoDelete = false;
+}
+
+
+void AppendList::clear()
+{
+ int count = _count;
+ int i;
+
+ if (count <= firstLen) {
+ if (_autoDelete)
+ for (i=0;i<count;i++)
+ delete _first[i];
+ }
+}
+
+#endif
diff --git a/kdecachegrind/kdecachegrind/utils.h b/kdecachegrind/kdecachegrind/utils.h
new file mode 100644
index 0000000..7256f05
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/utils.h
@@ -0,0 +1,164 @@
+/* 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.
+*/
+
+/*
+ * Utility classes for KCachegrind
+ */
+
+#ifndef UTILS_H
+#define UTILS_H
+
+#include <tqstring.h>
+
+class TQFile;
+
+typedef unsigned long long uint64;
+typedef long long int64;
+
+/**
+ * A simple, constant string class
+ *
+ * For use with zero-copy strings from mapped files.
+ */
+class FixString {
+
+ public:
+ // constructor for an invalid string
+ FixString() { _len = 0; _str = 0; }
+
+ /**
+ * FixString never does a deep copy! You have to make sure that
+ * the string starting at the char pointer is valid trough the
+ * lifetime of FixString.
+ */
+ FixString(const char*, int len);
+
+ int len() { return _len; }
+ const char* ascii() { return _str; }
+ bool isEmpty() { return _len == 0; }
+ bool isValid() { return _str != 0; }
+
+ // sets <c> to first character and returns true if length >0
+ bool first(char& c)
+ { if (_len==0) return false; c=_str[0]; return true; }
+
+ void set(const char* s, int l) { _str=s; _len=l; }
+ bool stripFirst(char&);
+ bool stripPrefix(const char*);
+
+ /**
+ * Strip leading and trailing spaces
+ */
+ void stripSurroundingSpaces();
+
+ /**
+ * Strip leading spaces
+ */
+ void stripSpaces();
+
+ /**
+ * Strip name: [A-Za-z_][0-9A_Za-z_]*
+ */
+ bool stripName(FixString&);
+
+ /**
+ * Strip string until char appears or end. Strips char, too.
+ */
+ FixString stripUntil(char);
+
+ bool stripUInt(uint&, bool stripSpaces = true);
+ bool stripUInt64(uint64&, bool stripSpaces = true);
+ bool stripInt64(int64&, bool stripSpaces = true);
+
+ operator TQString() const
+ { return TQString::fromLatin1(_str,_len); }
+
+ private:
+ const char* _str;
+ int _len;
+};
+
+
+/**
+ * A class for fast line by line reading of a read-only ASCII file
+ */
+class FixFile {
+
+ public:
+ FixFile(TQFile*);
+ ~FixFile();
+
+ /**
+ * Read next line into <str>. Returns false on error or EOF.
+ */
+ bool nextLine(FixString& str);
+ bool exists() { return !_openError; }
+ unsigned len() { return _len; }
+ unsigned current() { return _current - _base; }
+ bool setCurrent(unsigned pos);
+ void rewind() { setCurrent(0); }
+
+ private:
+ char *_base, *_current;
+ TQByteArray _data;
+ unsigned _len, _currentLeft;
+ bool _used_mmap, _openError;
+ TQString _filename;
+};
+
+
+/**
+ * A list of pointers, only able to append items.
+ * Optimized for speed, not space.
+ */
+template<class type>
+class AppendList {
+
+ public:
+ AppendList();
+ ~AppendList() { clear(); }
+
+ void setAutoDelete(bool);
+ void clear();
+ void append(const type*);
+
+ unsigned count() const { return _count; }
+ unsigned containsRef(const type*) const;
+
+ type* current();
+ type* first();
+ type* next();
+
+ private:
+ static const int firstLen = 8;
+ static const int maxLen = 256;
+
+ struct AppendListChunk {
+ int size;
+ struct AppendListChunk* next;
+ type* data[1];
+ };
+
+ struct AppendListChunk *_next, *_current, *_last;
+ int _count, _currentIndex, _lastIndex;
+ bool _autoDelete;
+ type* _first[firstLen];
+};
+
+
+#endif
diff --git a/kdecachegrind/kdecachegrind/x-kcachegrind.desktop b/kdecachegrind/kdecachegrind/x-kcachegrind.desktop
new file mode 100644
index 0000000..b9bf93a
--- /dev/null
+++ b/kdecachegrind/kdecachegrind/x-kcachegrind.desktop
@@ -0,0 +1,44 @@
+[Desktop Entry]
+Comment=Cachegrind/Callgrind Profile Dump
+Comment[ca]=Resultat del anàlisis de Cachegrind/Callgring
+Comment[cs]=Data profilace Cachegrind/Callgrind
+Comment[cy]=Tomen Proffil Cachegrind/Callgrind
+Comment[da]=Cachegrind/Callgrind profile-dump
+Comment[de]=Cachegrind/Callgrind Profil-Ausgabe
+Comment[el]=Αποτύπωση προφίλ Cachegrind/Callgrind
+Comment[es]=Resultado de análisis de Cachegrind/Callgring
+Comment[et]=Cachegrind/Callgrind profileerimistõmmis
+Comment[eu]=Cachegrind/Callgrind profil iraulketa
+Comment[fa]=تخلیۀ Profile Cachegrind/Callgrind
+Comment[fi]=Cachegrind/Callgrind-profiilivedos
+Comment[fr]=Dépôt de profil Cachegrind / Callgrind
+Comment[gl]=Resultado da análise de Cachegrind/Callgrind
+Comment[hi]=केश-ग्रिंड/काल-ग्रिंड प्रोफ़ाइल डम्प
+Comment[hu]=Cachegrind/Callgrind teljesítményprofil-fájl
+Comment[is]=Niðurstaða afkastakönnunar á Cachegrind/Callgrind
+Comment[it]=Dump del profilo di Cachegrind/Callgrind
+Comment[ja]=Callgrind/Callgrind プロファイルダンプ
+Comment[ka]=Cachegrind/Callgrind პროფილის დამპი
+Comment[kk]=Cachegrind/Callgrind профилінің дампы
+Comment[nds]=Cachegrind/Callgrind-Profilutgaav
+Comment[ne]=Cachegrind/Callgrind प्रोफाइल डम्प
+Comment[nl]=Cachegrind/Callgrind Profieldump
+Comment[nn]=Cachegrind/Callgrind-profildump
+Comment[pl]=Zrzut profilowania Cachegrind/Callgrind
+Comment[pt]=Resultado da Análise do Cachegrind/Callgrind
+Comment[pt_BR]=Depósito de Perfil Cachegrind/Callgrind
+Comment[ru]=Дамп профилирования Cachegrind/Callgrind
+Comment[sk]=Výpis volaní Cachegrind/Callgrind
+Comment[sr]=Cachegrind-ов/Callgrind-ов избачај профила
+Comment[sr@Latn]=Cachegrind-ov/Callgrind-ov izbačaj profila
+Comment[sv]=Profileringsdump från Cachegrind/Callgrind
+Comment[ta]=இடைமாற்றகட்டம்/ அழைப்பு கட்டம் விவரக்குறி திணிப்பு
+Comment[tg]=Дампи профилкунии Cachegrind/Callgrind
+Comment[uk]=Звалювання профілювання Cachegrind/Callgrind
+Comment[zh_CN]=Cachegrind/Callgrind 配置文件转存
+Comment[zh_TW]=Cachegrind/Callgrind 分析資料傾印
+DefaultApp=kdecachegrind
+Icon=kdecachegrind
+Type=MimeType
+MimeType=application/x-kcachegrind
+Patterns=cachegrind.out*;callgrind.out*
diff --git a/kdecachegrind/tests/cg-badcompression1 b/kdecachegrind/tests/cg-badcompression1
new file mode 100644
index 0000000..6076bf9
--- /dev/null
+++ b/kdecachegrind/tests/cg-badcompression1
@@ -0,0 +1,17 @@
+# Test with bad callgrind format
+# Expected:
+# :13 - Redefinition of compressed file index 2 (was 'file1.c') to ''
+# :14 - Redefinition of compressed function index 1 (was 'main') to 'main2'
+# :16 - Undefined compressed function index 2
+# :16 - Invalid function, setting to unknown
+
+events: Ir
+
+fl=(2) file1.c
+fn=(1) main
+10 9
+fl=(2 )
+fn=(1) main2
+11 1
+fn=(2)
+12 1
diff --git a/kdecachegrind/tests/cg-badcostline1 b/kdecachegrind/tests/cg-badcostline1
new file mode 100644
index 0000000..224ff67
--- /dev/null
+++ b/kdecachegrind/tests/cg-badcostline1
@@ -0,0 +1,11 @@
+# Test with bad callgrind format
+# Expected:
+# :10 - ignored garbage at end of cost line ('30')
+# :11 - ignored garbage at end of cost line ('hello')
+
+events: Ir
+
+fn=main
+10 20 30
+11 hello
+12 10
diff --git a/kdecachegrind/tests/cg-badposition b/kdecachegrind/tests/cg-badposition
new file mode 100644
index 0000000..1be582c
--- /dev/null
+++ b/kdecachegrind/tests/cg-badposition
@@ -0,0 +1,15 @@
+# Test with bad callgrind format
+# Expected:
+# :11 - Negative line number -20
+# :12 - Garbage at end of cost line ('a 21')
+# :13 - Negative line number -91
+# :15 - Invalid line 'aa 40'
+
+events: Ir
+
+fn=main
+-20 1
+9a 21
+-100 20
+0x9a 30
+aa 40
diff --git a/kdecachegrind/version.h.in b/kdecachegrind/version.h.in
new file mode 100644
index 0000000..d88081b
--- /dev/null
+++ b/kdecachegrind/version.h.in
@@ -0,0 +1 @@
+#define KCACHEGRIND_VERSION "@KCACHEGRIND_VERSION@"