summaryrefslogtreecommitdiffstats
path: root/tdecachegrind
diff options
context:
space:
mode:
authorTimothy Pearson <kb9vqf@pearsoncomputing.net>2012-01-30 20:20:24 -0600
committerTimothy Pearson <kb9vqf@pearsoncomputing.net>2012-01-30 20:20:24 -0600
commitcfccedd9c8db3af36d7c5635ca212fa170bb6ff5 (patch)
treec80df038c9b6e40b4e28c26203de0dd9b1cd1593 /tdecachegrind
parent2020f146a7175288d0aaf15cd91b95e545bbb915 (diff)
downloadtdesdk-cfccedd9c8db3af36d7c5635ca212fa170bb6ff5.zip
tdesdk-cfccedd9c8db3af36d7c5635ca212fa170bb6ff5.tar.gz
Part 2 of prior commit
Diffstat (limited to 'tdecachegrind')
-rw-r--r--tdecachegrind/AUTHORS1
-rw-r--r--tdecachegrind/COPYING340
-rw-r--r--tdecachegrind/ChangeLog89
-rw-r--r--tdecachegrind/INSTALL167
-rw-r--r--tdecachegrind/Makefile.am6
-rw-r--r--tdecachegrind/NEWS0
-rw-r--r--tdecachegrind/README62
-rw-r--r--tdecachegrind/TODO100
-rw-r--r--tdecachegrind/configure.in.in8
-rw-r--r--tdecachegrind/converters/Makefile.am2
-rw-r--r--tdecachegrind/converters/README24
-rw-r--r--tdecachegrind/converters/dprof2calltree199
-rw-r--r--tdecachegrind/converters/hotshot2calltree394
-rwxr-xr-xtdecachegrind/converters/memprof2calltree38
-rwxr-xr-xtdecachegrind/converters/op2calltree238
-rw-r--r--tdecachegrind/converters/pprof2calltree218
-rw-r--r--tdecachegrind/pics/Makefile.am3
-rw-r--r--tdecachegrind/pics/hicolor/Makefile.am2
-rw-r--r--tdecachegrind/pics/hicolor/hi16-action-fromrec.pngbin0 -> 226 bytes
-rw-r--r--tdecachegrind/pics/hicolor/hi16-action-percent.pngbin0 -> 261 bytes
-rw-r--r--tdecachegrind/pics/hicolor/hi16-action-recrec.pngbin0 -> 266 bytes
-rw-r--r--tdecachegrind/pics/hicolor/hi16-action-torec.pngbin0 -> 238 bytes
-rw-r--r--tdecachegrind/pics/hicolor/hi22-action-percent.pngbin0 -> 351 bytes
-rw-r--r--tdecachegrind/pics/hicolor/hi32-action-percent.pngbin0 -> 417 bytes
-rw-r--r--tdecachegrind/tdecachegrind.lsm.in11
-rw-r--r--tdecachegrind/tdecachegrind.spec.in55
-rw-r--r--tdecachegrind/tdecachegrind/Doxyfile157
-rw-r--r--tdecachegrind/tdecachegrind/Makefile.am62
-rw-r--r--tdecachegrind/tdecachegrind/cachegrindloader.cpp1323
-rw-r--r--tdecachegrind/tdecachegrind/callgraphview.cpp2734
-rw-r--r--tdecachegrind/tdecachegrind/callgraphview.h501
-rw-r--r--tdecachegrind/tdecachegrind/callitem.cpp185
-rw-r--r--tdecachegrind/tdecachegrind/callitem.h50
-rw-r--r--tdecachegrind/tdecachegrind/callmapview.cpp999
-rw-r--r--tdecachegrind/tdecachegrind/callmapview.h130
-rw-r--r--tdecachegrind/tdecachegrind/callview.cpp256
-rw-r--r--tdecachegrind/tdecachegrind/callview.h56
-rw-r--r--tdecachegrind/tdecachegrind/configdlg.cpp398
-rw-r--r--tdecachegrind/tdecachegrind/configdlg.h65
-rw-r--r--tdecachegrind/tdecachegrind/configdlgbase.ui653
-rw-r--r--tdecachegrind/tdecachegrind/configuration.cpp490
-rw-r--r--tdecachegrind/tdecachegrind/configuration.h101
-rw-r--r--tdecachegrind/tdecachegrind/costlistitem.cpp136
-rw-r--r--tdecachegrind/tdecachegrind/costlistitem.h52
-rw-r--r--tdecachegrind/tdecachegrind/costtypeitem.cpp149
-rw-r--r--tdecachegrind/tdecachegrind/costtypeitem.h50
-rw-r--r--tdecachegrind/tdecachegrind/costtypeview.cpp310
-rw-r--r--tdecachegrind/tdecachegrind/costtypeview.h54
-rw-r--r--tdecachegrind/tdecachegrind/coverage.cpp329
-rw-r--r--tdecachegrind/tdecachegrind/coverage.h102
-rw-r--r--tdecachegrind/tdecachegrind/coverageitem.cpp343
-rw-r--r--tdecachegrind/tdecachegrind/coverageitem.h82
-rw-r--r--tdecachegrind/tdecachegrind/coverageview.cpp321
-rw-r--r--tdecachegrind/tdecachegrind/coverageview.h57
-rw-r--r--tdecachegrind/tdecachegrind/dumpmanager.cpp50
-rw-r--r--tdecachegrind/tdecachegrind/dumpmanager.h59
-rw-r--r--tdecachegrind/tdecachegrind/dumpselection.cpp33
-rw-r--r--tdecachegrind/tdecachegrind/dumpselection.h30
-rw-r--r--tdecachegrind/tdecachegrind/dumpselectionbase.ui1082
-rw-r--r--tdecachegrind/tdecachegrind/fixcost.cpp174
-rw-r--r--tdecachegrind/tdecachegrind/fixcost.h171
-rw-r--r--tdecachegrind/tdecachegrind/functionitem.cpp236
-rw-r--r--tdecachegrind/tdecachegrind/functionitem.h58
-rw-r--r--tdecachegrind/tdecachegrind/functionselection.cpp871
-rw-r--r--tdecachegrind/tdecachegrind/functionselection.h86
-rw-r--r--tdecachegrind/tdecachegrind/functionselectionbase.ui163
-rw-r--r--tdecachegrind/tdecachegrind/hi32-app-tdecachegrind.pngbin0 -> 2411 bytes
-rw-r--r--tdecachegrind/tdecachegrind/hi48-app-tdecachegrind.pngbin0 -> 9010 bytes
-rw-r--r--tdecachegrind/tdecachegrind/instritem.cpp469
-rw-r--r--tdecachegrind/tdecachegrind/instritem.h86
-rw-r--r--tdecachegrind/tdecachegrind/instrview.cpp949
-rw-r--r--tdecachegrind/tdecachegrind/instrview.h83
-rw-r--r--tdecachegrind/tdecachegrind/listutils.cpp266
-rw-r--r--tdecachegrind/tdecachegrind/listutils.h65
-rw-r--r--tdecachegrind/tdecachegrind/lo16-app-tdecachegrind.pngbin0 -> 377 bytes
-rw-r--r--tdecachegrind/tdecachegrind/lo32-app-tdecachegrind.pngbin0 -> 576 bytes
-rw-r--r--tdecachegrind/tdecachegrind/loader.cpp85
-rw-r--r--tdecachegrind/tdecachegrind/loader.h80
-rw-r--r--tdecachegrind/tdecachegrind/main.cpp95
-rw-r--r--tdecachegrind/tdecachegrind/multiview.cpp224
-rw-r--r--tdecachegrind/tdecachegrind/multiview.h67
-rw-r--r--tdecachegrind/tdecachegrind/partgraph.cpp534
-rw-r--r--tdecachegrind/tdecachegrind/partgraph.h132
-rw-r--r--tdecachegrind/tdecachegrind/partlistitem.cpp189
-rw-r--r--tdecachegrind/tdecachegrind/partlistitem.h54
-rw-r--r--tdecachegrind/tdecachegrind/partselection.cpp567
-rw-r--r--tdecachegrind/tdecachegrind/partselection.h96
-rw-r--r--tdecachegrind/tdecachegrind/partselectionbase.ui89
-rw-r--r--tdecachegrind/tdecachegrind/partview.cpp235
-rw-r--r--tdecachegrind/tdecachegrind/partview.h55
-rw-r--r--tdecachegrind/tdecachegrind/pool.cpp258
-rw-r--r--tdecachegrind/tdecachegrind/pool.h107
-rw-r--r--tdecachegrind/tdecachegrind/sourceitem.cpp444
-rw-r--r--tdecachegrind/tdecachegrind/sourceitem.h84
-rw-r--r--tdecachegrind/tdecachegrind/sourceview.cpp813
-rw-r--r--tdecachegrind/tdecachegrind/sourceview.h71
-rw-r--r--tdecachegrind/tdecachegrind/stackbrowser.cpp417
-rw-r--r--tdecachegrind/tdecachegrind/stackbrowser.h109
-rw-r--r--tdecachegrind/tdecachegrind/stackitem.cpp116
-rw-r--r--tdecachegrind/tdecachegrind/stackitem.h56
-rw-r--r--tdecachegrind/tdecachegrind/stackselection.cpp230
-rw-r--r--tdecachegrind/tdecachegrind/stackselection.h81
-rw-r--r--tdecachegrind/tdecachegrind/stackselectionbase.ui80
-rw-r--r--tdecachegrind/tdecachegrind/subcost.cpp62
-rw-r--r--tdecachegrind/tdecachegrind/subcost.h66
-rw-r--r--tdecachegrind/tdecachegrind/tabview.cpp890
-rw-r--r--tdecachegrind/tdecachegrind/tabview.h174
-rw-r--r--tdecachegrind/tdecachegrind/tdecachegrind.desktop103
-rw-r--r--tdecachegrind/tdecachegrind/tdecachegrindui.rc57
-rw-r--r--tdecachegrind/tdecachegrind/tips141
-rw-r--r--tdecachegrind/tdecachegrind/toplevel.cpp2389
-rw-r--r--tdecachegrind/tdecachegrind/toplevel.h275
-rw-r--r--tdecachegrind/tdecachegrind/tracedata.cpp5068
-rw-r--r--tdecachegrind/tdecachegrind/tracedata.h1967
-rw-r--r--tdecachegrind/tdecachegrind/traceitemview.cpp443
-rw-r--r--tdecachegrind/tdecachegrind/traceitemview.h206
-rw-r--r--tdecachegrind/tdecachegrind/treemap.cpp3214
-rw-r--r--tdecachegrind/tdecachegrind/treemap.h759
-rw-r--r--tdecachegrind/tdecachegrind/utils.cpp483
-rw-r--r--tdecachegrind/tdecachegrind/utils.h164
-rw-r--r--tdecachegrind/tdecachegrind/x-tdecachegrind.desktop44
-rw-r--r--tdecachegrind/tests/cg-badcompression117
-rw-r--r--tdecachegrind/tests/cg-badcostline111
-rw-r--r--tdecachegrind/tests/cg-badposition15
-rw-r--r--tdecachegrind/version.h.in1
125 files changed, 38950 insertions, 0 deletions
diff --git a/tdecachegrind/AUTHORS b/tdecachegrind/AUTHORS
new file mode 100644
index 0000000..ded6005
--- /dev/null
+++ b/tdecachegrind/AUTHORS
@@ -0,0 +1 @@
+Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
diff --git a/tdecachegrind/COPYING b/tdecachegrind/COPYING
new file mode 100644
index 0000000..c13faf0
--- /dev/null
+++ b/tdecachegrind/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/tdecachegrind/ChangeLog b/tdecachegrind/ChangeLog
new file mode 100644
index 0000000..05f3081
--- /dev/null
+++ b/tdecachegrind/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, tdecachegrindui.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/tdecachegrind/INSTALL b/tdecachegrind/INSTALL
new file mode 100644
index 0000000..02a4a07
--- /dev/null
+++ b/tdecachegrind/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/tdecachegrind/Makefile.am b/tdecachegrind/Makefile.am
new file mode 100644
index 0000000..e93f6af
--- /dev/null
+++ b/tdecachegrind/Makefile.am
@@ -0,0 +1,6 @@
+SUBDIRS = tdecachegrind pics converters
+
+EXTRA_DIST = \
+ AUTHORS COPYING NEWS ChangeLog INSTALL README TODO \
+ tdecachegrind.lsm tdecachegrind.spec version.h
+
diff --git a/tdecachegrind/NEWS b/tdecachegrind/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tdecachegrind/NEWS
diff --git a/tdecachegrind/README b/tdecachegrind/README
new file mode 100644
index 0000000..0866eb8
--- /dev/null
+++ b/tdecachegrind/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://tdecachegrind.sourceforge.net/cgi-bin/show.cgi )
+
+
+
+Happy Profiling,
+ Josef Weidendorfer
diff --git a/tdecachegrind/TODO b/tdecachegrind/TODO
new file mode 100644
index 0000000..1eca67e
--- /dev/null
+++ b/tdecachegrind/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/tdecachegrind/configure.in.in b/tdecachegrind/configure.in.in
new file mode 100644
index 0000000..dfc8508
--- /dev/null
+++ b/tdecachegrind/configure.in.in
@@ -0,0 +1,8 @@
+TDECACHEGRIND_VERSION=0.4.6kde
+AC_SUBST(TDECACHEGRIND_VERSION)
+
+AC_FUNC_MMAP
+
+dnl AC_OUTPUT( tdecachegrind/version.h )
+dnl AC_OUTPUT( tdecachegrind/tdecachegrind.spec )
+dnl AC_OUTPUT( tdecachegrind/tdecachegrind.lsm )
diff --git a/tdecachegrind/converters/Makefile.am b/tdecachegrind/converters/Makefile.am
new file mode 100644
index 0000000..08b3696
--- /dev/null
+++ b/tdecachegrind/converters/Makefile.am
@@ -0,0 +1,2 @@
+bin_SCRIPTS = hotshot2calltree op2calltree pprof2calltree dprof2calltree \
+ memprof2calltree
diff --git a/tdecachegrind/converters/README b/tdecachegrind/converters/README
new file mode 100644
index 0000000..c27d3c6
--- /dev/null
+++ b/tdecachegrind/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 (tdecachegrind.sf.net).
+
+Josef
+
diff --git a/tdecachegrind/converters/dprof2calltree b/tdecachegrind/converters/dprof2calltree
new file mode 100644
index 0000000..f276e18
--- /dev/null
+++ b/tdecachegrind/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 tdecachegrind 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 tdecachegrind 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/tdecachegrind/converters/hotshot2calltree b/tdecachegrind/converters/hotshot2calltree
new file mode 100644
index 0000000..f62a46e
--- /dev/null
+++ b/tdecachegrind/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 tdecachegrind.
+#
+# 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 tdecachegrind:
+# tdecachegrind cachegrind.out.0
+#
+# TODO:
+# * es gibt Probleme mit rekursiven (direkt und indirekt) Aufrufen - dann
+# stimmen die Kosten nicht.
+#
+# * einige Funktionen werden mit "?" als Name angezeigt. Evtl sind
+# das nur die C/C++ extensions.
+#
+# * es fehlt noch ein Funktionsnamen Mangling, dass die Filenamen berücksichtigt,
+# zZ sind alle __init__'s und alle run's schwer unterscheidbar :-(
+#
+version = "$Revision$"
+progname = "hotshot2cachegrind"
+
+import os, sys
+from hotshot import stats,log
+import os.path
+
+file_limit=0
+
+what2text = {
+ log.WHAT_ADD_INFO : "ADD_INFO",
+ log.WHAT_DEFINE_FUNC : "DEFINE_FUNC",
+ log.WHAT_DEFINE_FILE : "DEFINE_FILE",
+ log.WHAT_LINENO : "LINENO",
+ log.WHAT_EXIT : "EXIT",
+ log.WHAT_ENTER : "ENTER"}
+
+# a pseudo caller on the caller stack. This represents
+# the Python interpreter that executes the given python
+# code.
+root_caller = ("PythonInterpreter",0,"execute")
+
+class CallStack:
+ """A tiny Stack implementation, based on python lists"""
+ def __init__(self):
+ self.stack = []
+ self.recursion_counter = {}
+ def push(self, elem):
+ """put something on the stack"""
+ self.stack.append(elem)
+ rc = self.recursion_counter.get(elem, 0)
+ self.recursion_counter[elem] = rc + 1
+
+ def pop(self):
+ """get the head element of the stack and remove it from teh stack"""
+ elem = self.stack[-1:][0]
+ rc = self.recursion_counter.get(elem) - 1
+ if rc>0:
+ self.recursion_counter[elem] = rc
+ else:
+ del self.recursion_counter[elem]
+ return self.stack.pop()
+
+ def top(self):
+ """get the head element of the stack, stack is unchanged."""
+ return self.stack[-1:][0]
+ def handleLineCost(self, tdelta):
+ p, c = self.stack.pop()
+ self.stack.append( (p,c + tdelta) )
+ def size(self):
+ """ return how many elements the stack has"""
+ return len(self.stack)
+
+ def __str__(self):
+ return "[stack: %s]" % self.stack
+
+ def recursion(self, pos):
+ return self.recursion_counter.get(pos, 0)
+ #return self.recursion_dict.has_key((entry[0][0], entry[0][2]))
+
+def return_from_call(caller_stack, call_dict, cost_now):
+ """return from a function call
+ remove the function from the caller stack,
+ add the costs to the calling function.
+ """
+ called, cost_at_enter = caller_stack.pop()
+ caller, caller_cost = caller_stack.top()
+
+ #print "return_from_call: %s ruft %s" % (caller, called,)
+
+ per_file_dict = call_dict.get(called[0], {})
+ per_caller_dict = per_file_dict.get(called[2], {})
+ cost_so_far, call_counter = per_caller_dict.get(caller, (0, 0))
+
+ if caller_stack.recursion(called):
+ per_caller_dict[caller] = (cost_so_far, call_counter + 1)
+ else:
+ per_caller_dict[caller] = (cost_so_far + cost_now - cost_at_enter, call_counter + 1)
+
+ per_file_dict[called[2]] = per_caller_dict
+ call_dict[called[0]] = per_file_dict
+
+
+def updateStatus(filecount):
+ sys.stdout.write("reading File #%d \r" % filecount)
+ sys.stdout.flush()
+def convertProfFiles(output, inputfilenames):
+ """convert all the given input files into one tdecachegrind
+ 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 tdecachegrind
+ 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 tdecachegrind
+ 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 tdecachegrind, 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/tdecachegrind/converters/memprof2calltree b/tdecachegrind/converters/memprof2calltree
new file mode 100755
index 0000000..e82d6e8
--- /dev/null
+++ b/tdecachegrind/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/tdecachegrind/converters/op2calltree b/tdecachegrind/converters/op2calltree
new file mode 100755
index 0000000..ca121a2
--- /dev/null
+++ b/tdecachegrind/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/tdecachegrind/converters/pprof2calltree b/tdecachegrind/converters/pprof2calltree
new file mode 100644
index 0000000..0e70e1c
--- /dev/null
+++ b/tdecachegrind/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 tdecachegrind. 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 tdecachegrind compatible output to $outfile\n";
+fwrite($OUT, $buffer);
+
+function usage()
+{
+ print <<<EOD
+pprof2calltree -f <tracefile>
+
+EOD;
+ exit(1);
+}
+?>
diff --git a/tdecachegrind/pics/Makefile.am b/tdecachegrind/pics/Makefile.am
new file mode 100644
index 0000000..f4a3186
--- /dev/null
+++ b/tdecachegrind/pics/Makefile.am
@@ -0,0 +1,3 @@
+tdecachegrindicondir = $(kde_datadir)/tdecachegrind/icons
+tdecachegrindicon_ICON = AUTO
+SUBDIRS = hicolor
diff --git a/tdecachegrind/pics/hicolor/Makefile.am b/tdecachegrind/pics/hicolor/Makefile.am
new file mode 100644
index 0000000..068e319
--- /dev/null
+++ b/tdecachegrind/pics/hicolor/Makefile.am
@@ -0,0 +1,2 @@
+tdecachegrindicondir = $(kde_datadir)/tdecachegrind/icons
+tdecachegrindicon_ICON = AUTO
diff --git a/tdecachegrind/pics/hicolor/hi16-action-fromrec.png b/tdecachegrind/pics/hicolor/hi16-action-fromrec.png
new file mode 100644
index 0000000..a5cb430
--- /dev/null
+++ b/tdecachegrind/pics/hicolor/hi16-action-fromrec.png
Binary files differ
diff --git a/tdecachegrind/pics/hicolor/hi16-action-percent.png b/tdecachegrind/pics/hicolor/hi16-action-percent.png
new file mode 100644
index 0000000..7a4ba47
--- /dev/null
+++ b/tdecachegrind/pics/hicolor/hi16-action-percent.png
Binary files differ
diff --git a/tdecachegrind/pics/hicolor/hi16-action-recrec.png b/tdecachegrind/pics/hicolor/hi16-action-recrec.png
new file mode 100644
index 0000000..ec11bfa
--- /dev/null
+++ b/tdecachegrind/pics/hicolor/hi16-action-recrec.png
Binary files differ
diff --git a/tdecachegrind/pics/hicolor/hi16-action-torec.png b/tdecachegrind/pics/hicolor/hi16-action-torec.png
new file mode 100644
index 0000000..c092c01
--- /dev/null
+++ b/tdecachegrind/pics/hicolor/hi16-action-torec.png
Binary files differ
diff --git a/tdecachegrind/pics/hicolor/hi22-action-percent.png b/tdecachegrind/pics/hicolor/hi22-action-percent.png
new file mode 100644
index 0000000..c64a378
--- /dev/null
+++ b/tdecachegrind/pics/hicolor/hi22-action-percent.png
Binary files differ
diff --git a/tdecachegrind/pics/hicolor/hi32-action-percent.png b/tdecachegrind/pics/hicolor/hi32-action-percent.png
new file mode 100644
index 0000000..e876c30
--- /dev/null
+++ b/tdecachegrind/pics/hicolor/hi32-action-percent.png
Binary files differ
diff --git a/tdecachegrind/tdecachegrind.lsm.in b/tdecachegrind/tdecachegrind.lsm.in
new file mode 100644
index 0000000..fab7ced
--- /dev/null
+++ b/tdecachegrind/tdecachegrind.lsm.in
@@ -0,0 +1,11 @@
+Begin3
+Title: tdecachegrind
+Version: @TDECACHEGRIND_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://tdecachegrind.sourceforge.net
+Platforms: Linux and other Unices
+Copying-policy: GNU Public License
+End
diff --git a/tdecachegrind/tdecachegrind.spec.in b/tdecachegrind/tdecachegrind.spec.in
new file mode 100644
index 0000000..42b3e24
--- /dev/null
+++ b/tdecachegrind/tdecachegrind.spec.in
@@ -0,0 +1,55 @@
+Summary: KDE Profiling Visualisation Tool
+Name: tdecachegrind
+Version: @TDECACHEGRIND_VERSION@
+Release: 1
+Copyright: GPL
+Group: Development/Tools
+Vendor: (none)
+URL: http://tdecachegrind.sourceforge.net
+Packager: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+Source: tdecachegrind-@TDECACHEGRIND_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.tdecachegrind
+find . -type f | sed 's,^\.,\%attr(-\,root\,root) ,' >> $RPM_BUILD_DIR/file.list.tdecachegrind
+find . -type l | sed 's,^\.,\%attr(-\,root\,root) ,' >> $RPM_BUILD_DIR/file.list.tdecachegrind
+
+%clean
+rm -rf $RPM_BUILD_ROOT/*
+rm -rf $RPM_BUILD_DIR/tdecachegrind
+rm -rf ../file.list.tdecachegrind
+
+
+%files -f ../file.list.tdecachegrind
diff --git a/tdecachegrind/tdecachegrind/Doxyfile b/tdecachegrind/tdecachegrind/Doxyfile
new file mode 100644
index 0000000..9d5d050
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/Doxyfile
@@ -0,0 +1,157 @@
+# Doxygen configuration generated by Doxywizard version 0.1
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = tdecachegrind
+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/tdecachegrind/tdecachegrind/Makefile.am b/tdecachegrind/tdecachegrind/Makefile.am
new file mode 100644
index 0000000..53cd35d
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/Makefile.am
@@ -0,0 +1,62 @@
+bin_PROGRAMS = tdecachegrind
+
+tdecachegrind_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
+
+tdecachegrind_COMPILE_FIRST = ../version.h
+
+tdecachegrind_LDADD = $(LIB_KIO)
+
+KDE_ICON = AUTO
+
+xdg_apps_DATA = tdecachegrind.desktop
+
+mimeapplicationdir = $(kde_mimedir)/application
+mimeapplication_DATA = x-tdecachegrind.desktop
+
+EXTRA_DIST = \
+ tdecachegrind.desktop \
+ x-tdecachegrind.desktop \
+ hi32-app-tdecachegrind.png \
+ hi48-app-tdecachegrind.png \
+ Doxyfile \
+ tdecachegrindui.rc
+
+# set the include path for X, qt and KDE
+INCLUDES= $(all_includes)
+
+METASOURCES = AUTO
+
+# the library search path.
+tdecachegrind_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_KIO) -lktexteditor
+
+rcdir = $(kde_datadir)/tdecachegrind
+rc_DATA = tdecachegrindui.rc
+
+tipdir = $(kde_datadir)/tdecachegrind
+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)/tdecachegrind.pot; \
+ fi
+ rm -f tips.txt
+
diff --git a/tdecachegrind/tdecachegrind/cachegrindloader.cpp b/tdecachegrind/tdecachegrind/cachegrindloader.cpp
new file mode 100644
index 0000000..4fe57d3
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/callgraphview.cpp b/tdecachegrind/tdecachegrind/callgraphview.cpp
new file mode 100644
index 0000000..bc01da8
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/callgraphview.h b/tdecachegrind/tdecachegrind/callgraphview.h
new file mode 100644
index 0000000..4db619d
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/callitem.cpp b/tdecachegrind/tdecachegrind/callitem.cpp
new file mode 100644
index 0000000..ebca490
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/callitem.h b/tdecachegrind/tdecachegrind/callitem.h
new file mode 100644
index 0000000..94191b8
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/callmapview.cpp b/tdecachegrind/tdecachegrind/callmapview.cpp
new file mode 100644
index 0000000..0e4d5e3
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/callmapview.h b/tdecachegrind/tdecachegrind/callmapview.h
new file mode 100644
index 0000000..860743f
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/callview.cpp b/tdecachegrind/tdecachegrind/callview.cpp
new file mode 100644
index 0000000..317d137
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/callview.h b/tdecachegrind/tdecachegrind/callview.h
new file mode 100644
index 0000000..be644f9
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/configdlg.cpp b/tdecachegrind/tdecachegrind/configdlg.cpp
new file mode 100644
index 0000000..e0b4547
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/configdlg.h b/tdecachegrind/tdecachegrind/configdlg.h
new file mode 100644
index 0000000..5ef6bab
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/configdlgbase.ui b/tdecachegrind/tdecachegrind/configdlgbase.ui
new file mode 100644
index 0000000..dc0ee9e
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/configuration.cpp b/tdecachegrind/tdecachegrind/configuration.cpp
new file mode 100644
index 0000000..02d5c09
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/configuration.h b/tdecachegrind/tdecachegrind/configuration.h
new file mode 100644
index 0000000..478f617
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/costlistitem.cpp b/tdecachegrind/tdecachegrind/costlistitem.cpp
new file mode 100644
index 0000000..1e777b0
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/costlistitem.h b/tdecachegrind/tdecachegrind/costlistitem.h
new file mode 100644
index 0000000..99f654e
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/costtypeitem.cpp b/tdecachegrind/tdecachegrind/costtypeitem.cpp
new file mode 100644
index 0000000..dc35cb2
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/costtypeitem.h b/tdecachegrind/tdecachegrind/costtypeitem.h
new file mode 100644
index 0000000..d34973d
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/costtypeview.cpp b/tdecachegrind/tdecachegrind/costtypeview.cpp
new file mode 100644
index 0000000..3f5417e
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/costtypeview.h b/tdecachegrind/tdecachegrind/costtypeview.h
new file mode 100644
index 0000000..ee9963e
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/coverage.cpp b/tdecachegrind/tdecachegrind/coverage.cpp
new file mode 100644
index 0000000..86e6f7f
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/coverage.h b/tdecachegrind/tdecachegrind/coverage.h
new file mode 100644
index 0000000..50c5936
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/coverageitem.cpp b/tdecachegrind/tdecachegrind/coverageitem.cpp
new file mode 100644
index 0000000..26e5b36
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/coverageitem.h b/tdecachegrind/tdecachegrind/coverageitem.h
new file mode 100644
index 0000000..ba442aa
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/coverageview.cpp b/tdecachegrind/tdecachegrind/coverageview.cpp
new file mode 100644
index 0000000..6657e92
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/coverageview.h b/tdecachegrind/tdecachegrind/coverageview.h
new file mode 100644
index 0000000..09c5de0
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/dumpmanager.cpp b/tdecachegrind/tdecachegrind/dumpmanager.cpp
new file mode 100644
index 0000000..2f0891a
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/dumpmanager.h b/tdecachegrind/tdecachegrind/dumpmanager.h
new file mode 100644
index 0000000..4925819
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/dumpselection.cpp b/tdecachegrind/tdecachegrind/dumpselection.cpp
new file mode 100644
index 0000000..4d812ef
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/dumpselection.h b/tdecachegrind/tdecachegrind/dumpselection.h
new file mode 100644
index 0000000..49ca532
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/dumpselectionbase.ui b/tdecachegrind/tdecachegrind/dumpselectionbase.ui
new file mode 100644
index 0000000..b8ad1b0
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/fixcost.cpp b/tdecachegrind/tdecachegrind/fixcost.cpp
new file mode 100644
index 0000000..4102926
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/fixcost.h b/tdecachegrind/tdecachegrind/fixcost.h
new file mode 100644
index 0000000..7e90fb4
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/functionitem.cpp b/tdecachegrind/tdecachegrind/functionitem.cpp
new file mode 100644
index 0000000..3b694dd
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/functionitem.h b/tdecachegrind/tdecachegrind/functionitem.h
new file mode 100644
index 0000000..d8f98f4
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/functionselection.cpp b/tdecachegrind/tdecachegrind/functionselection.cpp
new file mode 100644
index 0000000..c5646dd
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/functionselection.h b/tdecachegrind/tdecachegrind/functionselection.h
new file mode 100644
index 0000000..c5f7810
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/functionselectionbase.ui b/tdecachegrind/tdecachegrind/functionselectionbase.ui
new file mode 100644
index 0000000..eec019d
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/hi32-app-tdecachegrind.png b/tdecachegrind/tdecachegrind/hi32-app-tdecachegrind.png
new file mode 100644
index 0000000..bd41dae
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/hi32-app-tdecachegrind.png
Binary files differ
diff --git a/tdecachegrind/tdecachegrind/hi48-app-tdecachegrind.png b/tdecachegrind/tdecachegrind/hi48-app-tdecachegrind.png
new file mode 100644
index 0000000..58c2efd
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/hi48-app-tdecachegrind.png
Binary files differ
diff --git a/tdecachegrind/tdecachegrind/instritem.cpp b/tdecachegrind/tdecachegrind/instritem.cpp
new file mode 100644
index 0000000..ce5e81b
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/instritem.h b/tdecachegrind/tdecachegrind/instritem.h
new file mode 100644
index 0000000..2bbce71
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/instrview.cpp b/tdecachegrind/tdecachegrind/instrview.cpp
new file mode 100644
index 0000000..3df1679
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/instrview.h b/tdecachegrind/tdecachegrind/instrview.h
new file mode 100644
index 0000000..79d3d76
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/listutils.cpp b/tdecachegrind/tdecachegrind/listutils.cpp
new file mode 100644
index 0000000..0053646
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/listutils.h b/tdecachegrind/tdecachegrind/listutils.h
new file mode 100644
index 0000000..e3e13fb
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/lo16-app-tdecachegrind.png b/tdecachegrind/tdecachegrind/lo16-app-tdecachegrind.png
new file mode 100644
index 0000000..0985586
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/lo16-app-tdecachegrind.png
Binary files differ
diff --git a/tdecachegrind/tdecachegrind/lo32-app-tdecachegrind.png b/tdecachegrind/tdecachegrind/lo32-app-tdecachegrind.png
new file mode 100644
index 0000000..12542c8
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/lo32-app-tdecachegrind.png
Binary files differ
diff --git a/tdecachegrind/tdecachegrind/loader.cpp b/tdecachegrind/tdecachegrind/loader.cpp
new file mode 100644
index 0000000..a4aecf5
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/loader.h b/tdecachegrind/tdecachegrind/loader.h
new file mode 100644
index 0000000..f79f13d
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/main.cpp b/tdecachegrind/tdecachegrind/main.cpp
new file mode 100644
index 0000000..fd9df1b
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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 TDECACHEGRIND_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("tdecachegrind",
+ I18N_NOOP("KCachegrind"),
+ TDECACHEGRIND_VERSION,
+ I18N_NOOP("KDE Frontend for Cachegrind"),
+ KAboutData::License_GPL,
+ I18N_NOOP("(C) 2002, 2003, 2004"), 0,
+ "http://tdecachegrind.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/tdecachegrind/tdecachegrind/multiview.cpp b/tdecachegrind/tdecachegrind/multiview.cpp
new file mode 100644
index 0000000..4288e2d
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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/tdecachegrind/tdecachegrind/multiview.h b/tdecachegrind/tdecachegrind/multiview.h
new file mode 100644
index 0000000..9d77101
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/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
+ *