added libkomparediff2 and kompare

This commit is contained in:
Ivailo Monev 2014-11-19 18:58:05 +00:00
parent 8207bcada5
commit 6c4ee3dcc3
166 changed files with 30065 additions and 42 deletions

2
kompare/AUTHORS Normal file
View file

@ -0,0 +1,2 @@
Otto Bruggeman <otto.bruggeman@home.nl>
John Firebaugh <jfirebaugh@kde.org>

48
kompare/CMakeLists.txt Normal file
View file

@ -0,0 +1,48 @@
cmake_minimum_required(VERSION 2.6)
project(kompare)
# search packages used by KDE
find_package(KDE4 REQUIRED)
include(KDE4Defaults)
add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS})
find_package(LibKompareDiff2 REQUIRED)
include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES} ${LIBKOMPAREDIFF2_INCLUDE_DIR})
add_subdirectory( doc )
add_subdirectory( interfaces )
add_subdirectory( libdialogpages )
add_subdirectory( komparenavtreepart )
add_subdirectory( komparepart )
add_subdirectory( pics )
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/komparepart
${CMAKE_CURRENT_SOURCE_DIR}/libdialogpages
${CMAKE_CURRENT_SOURCE_DIR}/interfaces
${CMAKE_CURRENT_SOURCE_DIR}/komparenavtreepart
${CMAKE_CURRENT_SOURCE_DIR}/komparepart)
########### next target ###############
set(kompare_SRCS
main.cpp
kompare_shell.cpp
kompareurldialog.cpp
)
kde4_add_app_icon(kompare_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/pics/hi*-app-kompare.png")
kde4_add_executable(kompare ${kompare_SRCS})
target_link_libraries(kompare kompareinterface ${LIBKOMPAREDIFF2_LIBRARIES} komparedialogpages ${KDE4_KTEXTEDITOR_LIBS} )
install(TARGETS kompare ${INSTALL_TARGETS_DEFAULT_ARGS} )
########### install files ###############
install( PROGRAMS kompare.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} )
install( FILES kompareui.rc DESTINATION ${DATA_INSTALL_DIR}/kompare )
install( FILES komparenavigationpart.desktop kompareviewpart.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR} )

340
kompare/COPYING Normal file
View file

@ -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) 19yy <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) 19yy 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.

397
kompare/COPYING.DOC Normal file
View file

@ -0,0 +1,397 @@
GNU Free Documentation License
Version 1.2, November 2002
Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.
51 Franklin St, 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.
0. PREAMBLE
The purpose of this License is to make a manual, textbook, or other
functional and useful document "free" in the sense of freedom: to
assure everyone the effective freedom to copy and redistribute it,
with or without modifying it, either commercially or noncommercially.
Secondarily, this License preserves for the author and publisher a way
to get credit for their work, while not being considered responsible
for modifications made by others.
This License is a kind of "copyleft", which means that derivative
works of the document must themselves be free in the same sense. It
complements the GNU General Public License, which is a copyleft
license designed for free software.
We have designed this License in order to use it for manuals for free
software, because free software needs free documentation: a free
program should come with manuals providing the same freedoms that the
software does. But this License is not limited to software manuals;
it can be used for any textual work, regardless of subject matter or
whether it is published as a printed book. We recommend this License
principally for works whose purpose is instruction or reference.
1. APPLICABILITY AND DEFINITIONS
This License applies to any manual or other work, in any medium, that
contains a notice placed by the copyright holder saying it can be
distributed under the terms of this License. Such a notice grants a
world-wide, royalty-free license, unlimited in duration, to use that
work under the conditions stated herein. The "Document", below,
refers to any such manual or work. Any member of the public is a
licensee, and is addressed as "you". You accept the license if you
copy, modify or distribute the work in a way requiring permission
under copyright law.
A "Modified Version" of the Document means any work containing the
Document or a portion of it, either copied verbatim, or with
modifications and/or translated into another language.
A "Secondary Section" is a named appendix or a front-matter section of
the Document that deals exclusively with the relationship of the
publishers or authors of the Document to the Document's overall subject
(or to related matters) and contains nothing that could fall directly
within that overall subject. (Thus, if the Document is in part a
textbook of mathematics, a Secondary Section may not explain any
mathematics.) The relationship could be a matter of historical
connection with the subject or with related matters, or of legal,
commercial, philosophical, ethical or political position regarding
them.
The "Invariant Sections" are certain Secondary Sections whose titles
are designated, as being those of Invariant Sections, in the notice
that says that the Document is released under this License. If a
section does not fit the above definition of Secondary then it is not
allowed to be designated as Invariant. The Document may contain zero
Invariant Sections. If the Document does not identify any Invariant
Sections then there are none.
The "Cover Texts" are certain short passages of text that are listed,
as Front-Cover Texts or Back-Cover Texts, in the notice that says that
the Document is released under this License. A Front-Cover Text may
be at most 5 words, and a Back-Cover Text may be at most 25 words.
A "Transparent" copy of the Document means a machine-readable copy,
represented in a format whose specification is available to the
general public, that is suitable for revising the document
straightforwardly with generic text editors or (for images composed of
pixels) generic paint programs or (for drawings) some widely available
drawing editor, and that is suitable for input to text formatters or
for automatic translation to a variety of formats suitable for input
to text formatters. A copy made in an otherwise Transparent file
format whose markup, or absence of markup, has been arranged to thwart
or discourage subsequent modification by readers is not Transparent.
An image format is not Transparent if used for any substantial amount
of text. A copy that is not "Transparent" is called "Opaque".
Examples of suitable formats for Transparent copies include plain
ASCII without markup, Texinfo input format, LaTeX input format, SGML
or XML using a publicly available DTD, and standard-conforming simple
HTML, PostScript or PDF designed for human modification. Examples of
transparent image formats include PNG, XCF and JPG. Opaque formats
include proprietary formats that can be read and edited only by
proprietary word processors, SGML or XML for which the DTD and/or
processing tools are not generally available, and the
machine-generated HTML, PostScript or PDF produced by some word
processors for output purposes only.
The "Title Page" means, for a printed book, the title page itself,
plus such following pages as are needed to hold, legibly, the material
this License requires to appear in the title page. For works in
formats which do not have any title page as such, "Title Page" means
the text near the most prominent appearance of the work's title,
preceding the beginning of the body of the text.
A section "Entitled XYZ" means a named subunit of the Document whose
title either is precisely XYZ or contains XYZ in parentheses following
text that translates XYZ in another language. (Here XYZ stands for a
specific section name mentioned below, such as "Acknowledgements",
"Dedications", "Endorsements", or "History".) To "Preserve the Title"
of such a section when you modify the Document means that it remains a
section "Entitled XYZ" according to this definition.
The Document may include Warranty Disclaimers next to the notice which
states that this License applies to the Document. These Warranty
Disclaimers are considered to be included by reference in this
License, but only as regards disclaiming warranties: any other
implication that these Warranty Disclaimers may have is void and has
no effect on the meaning of this License.
2. VERBATIM COPYING
You may copy and distribute the Document in any medium, either
commercially or noncommercially, provided that this License, the
copyright notices, and the license notice saying this License applies
to the Document are reproduced in all copies, and that you add no other
conditions whatsoever to those of this License. You may not use
technical measures to obstruct or control the reading or further
copying of the copies you make or distribute. However, you may accept
compensation in exchange for copies. If you distribute a large enough
number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and
you may publicly display copies.
3. COPYING IN QUANTITY
If you publish printed copies (or copies in media that commonly have
printed covers) of the Document, numbering more than 100, and the
Document's license notice requires Cover Texts, you must enclose the
copies in covers that carry, clearly and legibly, all these Cover
Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
the back cover. Both covers must also clearly and legibly identify
you as the publisher of these copies. The front cover must present
the full title with all words of the title equally prominent and
visible. You may add other material on the covers in addition.
Copying with changes limited to the covers, as long as they preserve
the title of the Document and satisfy these conditions, can be treated
as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit
legibly, you should put the first ones listed (as many as fit
reasonably) on the actual cover, and continue the rest onto adjacent
pages.
If you publish or distribute Opaque copies of the Document numbering
more than 100, you must either include a machine-readable Transparent
copy along with each Opaque copy, or state in or with each Opaque copy
a computer-network location from which the general network-using
public has access to download using public-standard network protocols
a complete Transparent copy of the Document, free of added material.
If you use the latter option, you must take reasonably prudent steps,
when you begin distribution of Opaque copies in quantity, to ensure
that this Transparent copy will remain thus accessible at the stated
location until at least one year after the last time you distribute an
Opaque copy (directly or through your agents or retailers) of that
edition to the public.
It is requested, but not required, that you contact the authors of the
Document well before redistributing any large number of copies, to give
them a chance to provide you with an updated version of the Document.
4. MODIFICATIONS
You may copy and distribute a Modified Version of the Document under
the conditions of sections 2 and 3 above, provided that you release
the Modified Version under precisely this License, with the Modified
Version filling the role of the Document, thus licensing distribution
and modification of the Modified Version to whoever possesses a copy
of it. In addition, you must do these things in the Modified Version:
A. Use in the Title Page (and on the covers, if any) a title distinct
from that of the Document, and from those of previous versions
(which should, if there were any, be listed in the History section
of the Document). You may use the same title as a previous version
if the original publisher of that version gives permission.
B. List on the Title Page, as authors, one or more persons or entities
responsible for authorship of the modifications in the Modified
Version, together with at least five of the principal authors of the
Document (all of its principal authors, if it has fewer than five),
unless they release you from this requirement.
C. State on the Title page the name of the publisher of the
Modified Version, as the publisher.
D. Preserve all the copyright notices of the Document.
E. Add an appropriate copyright notice for your modifications
adjacent to the other copyright notices.
F. Include, immediately after the copyright notices, a license notice
giving the public permission to use the Modified Version under the
terms of this License, in the form shown in the Addendum below.
G. Preserve in that license notice the full lists of Invariant Sections
and required Cover Texts given in the Document's license notice.
H. Include an unaltered copy of this License.
I. Preserve the section Entitled "History", Preserve its Title, and add
to it an item stating at least the title, year, new authors, and
publisher of the Modified Version as given on the Title Page. If
there is no section Entitled "History" in the Document, create one
stating the title, year, authors, and publisher of the Document as
given on its Title Page, then add an item describing the Modified
Version as stated in the previous sentence.
J. Preserve the network location, if any, given in the Document for
public access to a Transparent copy of the Document, and likewise
the network locations given in the Document for previous versions
it was based on. These may be placed in the "History" section.
You may omit a network location for a work that was published at
least four years before the Document itself, or if the original
publisher of the version it refers to gives permission.
K. For any section Entitled "Acknowledgements" or "Dedications",
Preserve the Title of the section, and preserve in the section all
the substance and tone of each of the contributor acknowledgements
and/or dedications given therein.
L. Preserve all the Invariant Sections of the Document,
unaltered in their text and in their titles. Section numbers
or the equivalent are not considered part of the section titles.
M. Delete any section Entitled "Endorsements". Such a section
may not be included in the Modified Version.
N. Do not retitle any existing section to be Entitled "Endorsements"
or to conflict in title with any Invariant Section.
O. Preserve any Warranty Disclaimers.
If the Modified Version includes new front-matter sections or
appendices that qualify as Secondary Sections and contain no material
copied from the Document, you may at your option designate some or all
of these sections as invariant. To do this, add their titles to the
list of Invariant Sections in the Modified Version's license notice.
These titles must be distinct from any other section titles.
You may add a section Entitled "Endorsements", provided it contains
nothing but endorsements of your Modified Version by various
parties--for example, statements of peer review or that the text has
been approved by an organization as the authoritative definition of a
standard.
You may add a passage of up to five words as a Front-Cover Text, and a
passage of up to 25 words as a Back-Cover Text, to the end of the list
of Cover Texts in the Modified Version. Only one passage of
Front-Cover Text and one of Back-Cover Text may be added by (or
through arrangements made by) any one entity. If the Document already
includes a cover text for the same cover, previously added by you or
by arrangement made by the same entity you are acting on behalf of,
you may not add another; but you may replace the old one, on explicit
permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License
give permission to use their names for publicity for or to assert or
imply endorsement of any Modified Version.
5. COMBINING DOCUMENTS
You may combine the Document with other documents released under this
License, under the terms defined in section 4 above for modified
versions, provided that you include in the combination all of the
Invariant Sections of all of the original documents, unmodified, and
list them all as Invariant Sections of your combined work in its
license notice, and that you preserve all their Warranty Disclaimers.
The combined work need only contain one copy of this License, and
multiple identical Invariant Sections may be replaced with a single
copy. If there are multiple Invariant Sections with the same name but
different contents, make the title of each such section unique by
adding at the end of it, in parentheses, the name of the original
author or publisher of that section if known, or else a unique number.
Make the same adjustment to the section titles in the list of
Invariant Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled "History"
in the various original documents, forming one section Entitled
"History"; likewise combine any sections Entitled "Acknowledgements",
and any sections Entitled "Dedications". You must delete all sections
Entitled "Endorsements".
6. COLLECTIONS OF DOCUMENTS
You may make a collection consisting of the Document and other documents
released under this License, and replace the individual copies of this
License in the various documents with a single copy that is included in
the collection, provided that you follow the rules of this License for
verbatim copying of each of the documents in all other respects.
You may extract a single document from such a collection, and distribute
it individually under this License, provided you insert a copy of this
License into the extracted document, and follow this License in all
other respects regarding verbatim copying of that document.
7. AGGREGATION WITH INDEPENDENT WORKS
A compilation of the Document or its derivatives with other separate
and independent documents or works, in or on a volume of a storage or
distribution medium, is called an "aggregate" if the copyright
resulting from the compilation is not used to limit the legal rights
of the compilation's users beyond what the individual works permit.
When the Document is included in an aggregate, this License does not
apply to the other works in the aggregate which are not themselves
derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these
copies of the Document, then if the Document is less than one half of
the entire aggregate, the Document's Cover Texts may be placed on
covers that bracket the Document within the aggregate, or the
electronic equivalent of covers if the Document is in electronic form.
Otherwise they must appear on printed covers that bracket the whole
aggregate.
8. TRANSLATION
Translation is considered a kind of modification, so you may
distribute translations of the Document under the terms of section 4.
Replacing Invariant Sections with translations requires special
permission from their copyright holders, but you may include
translations of some or all Invariant Sections in addition to the
original versions of these Invariant Sections. You may include a
translation of this License, and all the license notices in the
Document, and any Warranty Disclaimers, provided that you also include
the original English version of this License and the original versions
of those notices and disclaimers. In case of a disagreement between
the translation and the original version of this License or a notice
or disclaimer, the original version will prevail.
If a section in the Document is Entitled "Acknowledgements",
"Dedications", or "History", the requirement (section 4) to Preserve
its Title (section 1) will typically require changing the actual
title.
9. TERMINATION
You may not copy, modify, sublicense, or distribute the Document except
as expressly provided for under this License. Any other attempt to
copy, modify, sublicense or distribute the Document 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.
10. FUTURE REVISIONS OF THIS LICENSE
The Free Software Foundation may publish new, revised versions
of the GNU Free Documentation 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. See
http://www.gnu.org/copyleft/.
Each version of the License is given a distinguishing version number.
If the Document specifies that a particular numbered version of this
License "or any later version" applies to it, you have the option of
following the terms and conditions either of that specified version or
of any later version that has been published (not as a draft) by the
Free Software Foundation. If the Document does not specify a version
number of this License, you may choose any version ever published (not
as a draft) by the Free Software Foundation.
ADDENDUM: How to use this License for your documents
To use this License in a document you have written, include a copy of
the License in the document and put the following copyright and
license notices just after the title page:
Copyright (c) YEAR YOUR NAME.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
replace the "with...Texts." line with this:
with the Invariant Sections being LIST THEIR TITLES, with the
Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
If you have Invariant Sections without Cover Texts, or some other
combination of the three, merge those two alternatives to suit the
situation.
If your document contains nontrivial examples of program code, we
recommend releasing these examples in parallel under your choice of
free software license, such as the GNU General Public License,
to permit their use in free software.

423
kompare/ChangeLog Normal file
View file

@ -0,0 +1,423 @@
Dec 27, 2004 : Jeff Snyder
* Fix for bug 95640 (nothing displayed when kompare is embedded in Ark
fixed by forcing the delivery of childEvents to komparesplitter at
the end of its constructor
Dec 20, 2004 : Jeff Snyder
* Things that have happened since 3.3:
(this list is not complete)
* Look & feel changed
Dec 20, 2004 : Jeff Snyder
* Things that were changed sometime between Nov 25, 2003 and KDE 3.3:
(this list is not complete)
* KompareConnectWidget became draggable, by replacing KompareViewFrame
with KompareSplitter.
Dec 20, 2004 : Jeff Snyder
* This changelog seems to have been neglected for over a year now. I'll
try to retroactively fix this as and when I remember things that have
been fixed - but it'll probably never be complete and accurate for the
Dec 2003 - Nov 2004 period. I'll be making entries concering what i'm
doing with kompare from now onwards.
Nov 25, 2003 : Otto Bruggeman
* Fix nasty looping to the end of the file when hitting previous difference on the first difference in the first file
Nov 25, 2003 : Laurent Montel
* Fix memleak, QStringList is implicitly shared so no need for a reference, it is already a pointer to data thing
Nov 23, 2003 : Otto Bruggeman
* Fixed version string (bug 68872)
* Fix for 68871 (added slotNextDifference to slotApplyDifference())
* Fix for a crash: dont call blendOriginalIntoModelList with Kompare::ShowingDiff
Nov 22, 2003 : Otto Bruggeman
* Fix to make the bugs.kde.org dialog pop up instead of sending a mail to John when pressing
Help->Report bug... Also added my homepage since it has always been kompare's home imo.
Nov 22, 2003 : Otto Bruggeman
* Rework the blendFile method so it actually works and as a bonus is a bit faster
This introduces a new form of show entire file when comparing, one that works
And because of it, it saves files properly now because the entire file is now available even if
you have a single line change in a million line file with only 2 context lines in the diff.
Nov 22, 2003 : Otto Bruggeman
* Remove the Show entire file option. It only causes problems at the moment
Fixes bug 68729
Nov 22, 2003 : Otto Bruggeman
* Commenting out a lot of debug output, it has served it's purpose well in levenshteintable.cpp
Nov 21, 2003 : Otto Bruggeman
* Also expand tabs to spaces in strings without or after Commands (in the INLINE_DIFFERENCES
code path and yes commands is a shitty name for them but i cant think of something decent)
Nov 21, 2003 : Otto Bruggeman
* Real Fix (tm) for activating the Swap source with destination action
Nov 21, 2003 : Otto Bruggeman
* Fix empty line drawing in the INLINE_DIFFERENCES code path
Nov 20, 2003 : Otto Bruggeman
* When swapping source with destination also change the windows caption and the statusbar text
* Make sure that when swapping and when there are changes, all changes that were made can be
saved, discarded or cancel the whole swap (strings are recycled from the queryClose method)
* Give a better parent to the KIO::NetAccess::download in komparemodellist.cpp
* Added some FIXME's for after the branching to make the urls appear in bold in the error message
* Make queryClose not use the isModified from the part but from the modellist
Nov 20, 2003 : Otto Bruggeman
* Fix for activating the Swap Source with Destination action.
Nov 19, 2003 : Otto Bruggeman
* Fixed bug 68570, it needed temp vars otherwise it was overwriting source with destination and then
overwriting that destination with source which was just changed into destination
Nov 17, 2003 : Otto Bruggeman
* Fix for empty -x and -X arguments.
* Fix bugs 58858 and 58531 by using Kompare::Custom instead of Kompare::Default
* Fix last selected url in the kurlcomboboxes
* Fix for inline differences when there is only 1 char left that still needs to be drawn
* Remove support for the -a Treat all files as text diff option. This caused all sorts of weird crashes
when parsing the diff output now with the custom options.
* Move the per preference page code in the diffprefs constructor into seperate methods per page
Nov 14, 2003 : Otto Bruggeman
* Fix to make Kompare listen to the kdisplayFontChanged signal and set the font properly and redraw with the new font.
Found by David Faure.
Nov 09, 2003 : Otto Bruggeman
* Implemented inline differences (deactivated until KDE3.2 has been branched)
* added support for the -x and -X options to diff (deactivated until KDE3.2 has been branched)
* Various other code cleanups/reindenting
Nov 09, 2003 : Otto Bruggeman
* Code cleanups
Nov 02, 2003 : Otto Bruggeman
* Fixed some more scrolling problems
lastItem->scrollId(), add lastItem->maxHeight() and substract the minScrollId()
That is the maxScrollId i need in the QScrollBar, took me long enough...
Oct 05, 2003 : Otto Bruggeman
* Fixed the scrolling problems, a stupid regression i introduced, i cant simplify mathematic expressions apparently
* Added an implementation for double clicking a difference in the view, but it is not properly connected yet
void contentsMouseDoubleClickEvent ( QMouseEvent* );
* Fixed embedding in Konqueror by implementing openURL()
* Removed m_maxScrollId, it is not necessary and only costs time, QScrollView::contentsHeight() does the same
* Fixed some more warnings about unused variables
* Fixed the initial drawing of the vertical and horizontal scrollbar
Oct 04, 2003 : Otto Bruggeman
* Added a call to m_modelList->openDirAndDiff to openDirAndDiff
* Fixed some error strings by swapping the %# thingies
* Added some useless debug output
* Fixed KompareModelList::openDirAndDiff to use the right models variable (m_models instead of models)
Oct 03, 2003 : Otto Bruggeman
* Fixed ApplyAll and UnApplyAll, stupid copy and paste error
* Fixed some warnings about signed and unsigned
* Fixed some warnings about unused variables
* Fixed some redrawing issues in the connection widget
Sep 27, 2003 : Otto Bruggeman
* Fixed the redrawing problems in the connect widget with a QTimer::singleShot()
* Undid a stupid commit that changed the keyboard shortcuts for next and previous difference
* Fixed another bug in the navigation part that made it emit a signal twice
* Fixed a bug in the listview drawing, still one left that i cant seem to solve :(
Sep 27, 2003 : Otto Bruggeman
* Moved the apply and navigation actions into the komparemodellist
* Fixed Ingo's problem with the next and prev difference KActions
Sep 26, 2003 : Otto Bruggeman
* Added a struct Info in the Kompare namespace. This one contains all the info about what kompare is doing
* Fixed splitting the path string in diffmodel
* Fixed showing the path in komparenavtreepart in the directory listviews
Sep 24, 2003 : Otto Bruggeman
* Fixes opening diffs, comparing files after moving all that code around
Sep 23, 2003 : Otto Bruggeman
* Moved a lot of url downloading to the kompare part and moved the opening and reading of the downloads to komparemodellist
Sep 22, 2003 : Otto Bruggeman
* Added openStdin() to KompareShell
* Fixed stupid implicit conversion from QString to QStringList in kompare_part.cpp
* Added openDiff( QStringList ) to the interface and to the part
Sep 14, 2003 : Otto Bruggeman
* Fixed exit status of the kompare process
Sep 13, 2003 : Otto Bruggeman
* Removed some files that apparently came back after the merge
Sep 07, 2003 : Otto Bruggeman
* Some changes to the interface. Made the copy ctor and assignment operator
and added a private d-pointer
* Removed the use of all deprecated methods and replaced them with undeprecated ones :)
Sep 02, 2003 : Scott Wheeler
* Made the interface pure virtual
Sep 01, 2003 : Scott Wheeler
* Fixed constness of the KompareModelList constructor
* Fixed another 2 warnings about comapring signed with unsigned ints
* Fixed the initialization of the difault var
Aug 27, 2003 : Otto Bruggeman
* After shitloads of trouble here finally some fixes for the stupid desktop
file stuff
* Fixes for when there are not enough args for a certain commandline option.
Aug 22, 2003 : Otto Bruggeman
* Fixed converting tabs to spaces in the view, i totally screwed up
* View settings now get applied to the view after pressing ok.
(Maybe i should make them apply on APlly instead of OK)
Aug 13, 2003 : Otto Bruggeman
* Komkommertijd :) InitialPreference=10 for kompare.desktop as
requested
Aug 10, 2003 : Otto Bruggeman
* Backported Helge Deller's changes from head to make_it_cool
(kompare_shell.cpp 1.33 -> 1.34). This is about roaming user fixes.
Thanks Helge !
Jul 19, 2003 : Otto Bruggeman
* Backported Ingo Klocker's changes from head to make_it_cool
(kompare_shell.cpp 1.34 -> 1.35). This is about being able to
configure the shortcuts from kompare_part as well. Thanks Ingo !
Jun 29, 2003 : Otto Bruggeman
* Fixed bug 58144 by adding a check for comparing dirs, in that case
destinationURL is a directory and not a file name so we need to
recreate the filename. This involved changing some code to use a
different enum value, so i hope i did it the right way, session
management may be broken now when the session was stored with 3.1.2
and restarted with 3.1.3. But that is unfortunately unfixable with a
kconf_update script.
Jun 29, 2003 : Otto Bruggeman
* Removed a lot of commented code since it is no longer used and will
never be used again.
* Added 2 methods to the interface: openDiff3(KURL) and
openDiff3(QStringList)
* Fixed context diff parsing as indicated in bugreport 57774
(the example works now, hope there are no regressions)
* Removed all references to MiscSettings and MiscPrefs.
These classes will disappear RSN.
* Fixed the history saving of the urls in the kompare dialog
* Parser is no longer a static class but one that needs to be
instanciated
* Added ViewSettings to KompareProcess, maybe it is better to merge the
diff and view settings into one class.
May 3, 2003 : Otto Bruggeman
* Implemented support for -I in the regular diff options (the one in
the kompare options dialog)
* Fixed the braindamage i created in main.cpp so that kompare no
longer stalls because of a missing mainwindow
* Made the kcomparedialog more generic and renamed it to
kompareurldialog so i can reuse it for blending too
* Removed some braindamage in the kompare/Makefile.am
* Some compile fixes because of changes to the CXXFLAGS
(QRegExp::match cant be used anymore, and some other old style stuff)
* Added an action to the menu for blending
* moved Open file (or in this case Open Diff) to the top of the file
menu
* Fixed the accel conflict in the file menu between open diff and
compare files
Apr 30, 2003 : Otto Bruggeman
* Implemented blending of a diff file with the original file
* Renamed General* View* (more appropriate)
* Renamed m_models into m_modelList since it is more appropriate in komparepart
* Small fixes to the view, but they break more than they fix :(
* Added commandline options for comparing, opening a diff file and
blending
Apr 20, 2003 : Otto Bruggeman
* Fixed bug 54264 with a statusbar that gets too wide when long
filenames are used
* Fixed the missing endline problem in the parser (bug 56552)
* Fixed all copyright years (probably too many but hey i'll change
those files some time this year so it will be valid :P)
* Added support for using a different diff program (Bug 55573)
* Added support for using a different tabsize in the viewer (Bug 38776)
* The interface is now final i guess so this fixes bug 42849, not
every method is implemented but i'll get to them eventually.
Apr 19, 2003 : Otto Bruggeman
* Fixed bug 56322 where openURL did not clear the models when called
again with a new diff
Aug 9, 2002 : Otto Bruggeman
* Fixed the whatsthis text for the compare button in the compare dialog
* Fixed the history of the comboboxes in the compare dialog
* Put the komparemodellist and all needed classes in a Diff2 namespace
* Implemented a better parser design (see parser.cpp/h)
* Removed the need to directly link to the komparepart for the shellapp
* Removed the need to link directly to the komparepart for the navigationpart
* Added support for perforce diffs in the new Parser classes
* Added a push design for the modified status instead of a pull design
* Added an interface to the Komparepart so people can use that to
reuse the komparepart
Jul 15, 2002 : Otto Bruggeman
* Fixed normal diff a bit more, filenames dont work yet
* Removed some code duplication
* Fixed diff output parsing with Common subdirectories in it
* Fixed Copyright years in the about box (thanks Carsten Niehaus)
* Removed the K3ShellProcess and replaced it with a K3Process
Feb 18, 2002 : Otto Bruggeman
* Fixed scrolling with a wheel mouse in the kompare(list)view and
connectwidget and added a config option for the number of lines
that is scrolled per wheelscroll.
* Fixed the history somehow in the compare dialog.
* Implemented the separate directory/file widget.
* Implemented reading from stdin by using - as file on the commandline.
* Partly implemented a better way for ed and rcs parsing, i'll
improve this before KDE 3.0 is released
Jan 10, 2002 : Otto Bruggeman
Comparing directories works now :) You can select them from the begin
dialog, and select a directory and then press ok. It will enter the
directory but dont select a file so it keeps the directory.
Known bug here is that directories need a trailing slash :(
Oct 07, 2001 : Otto Bruggeman
Fix crash when part is not found, basically dont use kapp->quit()
but use exit(int). Would be interested to know why it crashes though,
the bt gave nothing meaningful here. I should have compiled kompare with
debug code.
Sep 17/18, 2001 : Otto Bruggeman
Fixed some stuff dont know what anymore (writing this on oct 7)
Probably some more fixes for the klibloader.
Sep 17, 2001 : Otto Bruggeman
Moved to kdesdk and renamed to kompare with preservation of history.
Changed almost every occurence of kdiff to kompare (not in this file).
Sep 08, 2001 : Otto Bruggeman
Removed the qt3back dir, changed everything over to qt3,
qlist->qptrlist, qlistconstiterator->qptrlistconstiterator
Jul 29, 2001 : John Firebaugh
Add some tests.
Add the qregexp3 backport.
Use qregexp3 for diff parsing -- soooo much cleaner.
All the diff options work.
Jul 28, 2001 : John Firebaugh
Directories can be selected in the compare dialog
New base clase KDiff, holds some common stuff
Use an enum for format in preferences
Implement a save options dialog, displayed at "Save .diff"
The diff can be run in any directory, the paths to source
and destination will be automatically determined from this.
Save all.
Jul 25, 2001 : John Firebaugh
Prompt to save changes on close
Show [modified] caption
Clean up internal save mechanism
Jul 14, 2001 : John Firebaugh
New menu item "Swap source and destination".
Make empty selection work.
Jul 13, 2001 : John Firebaugh
Text view now works in compare mode.
Fix clicking difference to select it.
Don't scroll to difference when clicking to select it.
Give the diff view a nice frame.
Jul 12, 2001 : Otto Bruggeman
Stats work now, maybe they need more info but i dont know what yet.
Will think some more about it.
Jul 12, 2001 : John Firebaugh
When comparing files, you can apply or unapply changes and save
the result.
New menu item "Show Text View" (loads the diff in embedded text viewer).
Better status notification.
Set the window caption when comparing.
Jun 27, 2001 : John Firebaugh
Ported main view to QListView
Remove obsolete files
Clicking a difference in the main view selects it
Better scrolling
Jun 24, 2001 : John Firebaugh
Coverted to dock window and added navigation tree in a dock.
Multiple file diffs are now supported. Each file will show up
as an item in the tree, with differences as children.
Jun 22, 2001 : Otto Bruggeman
Tried implementing rcs and ed but they dont work atm, same for show
diffstats, will fix that asap.
May 22, 2001 : John Firebaugh
Reworking of most of the view code. Looks pretty.
May 18, 2001 : Otto Bruggeman
Context seems to work, implemented saving... might have some problems
left (saving that is)
May 15, 2001 : John Firebaugh
Make the settings work for all windows. Probably some more changes :)
May 14, 2001 : Otto Bruggeman
context diff does not work atm, there is some problem with the separa-
tion of old and new. Maybe the old and new needs to be reintegrated.
I fixed some functions and now diffmodel does no longer need static
functions. All loading is done from the kdiffpart and that is where
save should go as well. Removed determineDiffFormat because it is not
needed anymore.
May 13, 2001 : Otto Bruggeman
contextdiff is better implemented it finds all stuff in the diff atm
but it does not work.
May 04, 2001 : Otto Bruggeman
cleaned up the code by moving the part to a subdir
halfassed implementation of contextdiff, will update later today
Apr 10, 2001 : John Firebaugh
use new model/view architecture (not completely implemented yet)
NOTE: it will (should) compile, but you won't see any differences... a
work in progress
Apr 05, 2001 : Otto Bruggeman
Implemented the ability to move from chuck to chunk in the htmlview
Cleaned up the preferences, squashed a few bugs
Apr 04, 2001 : Otto Bruggeman
Normal format works as well
Apr 04, 2001 : Otto Bruggeman
Finally implemented the preferences menu... i still lack some nice
icons for it but that will be solved in the near future...
Mar 25, 2001 : Otto Bruggeman
Moved the application icons to the pics dir
Mar 20, 2001 : Otto Bruggeman
Fixed a stupid bug that caused the last line in the rightview not
to be colored.
Implemented slots for using the KHistoryCombo in the views to select
files with.
Still a nasty bug with regard to the initial directory in the
KFileDialog, needs to be fixed asap but i dont know the cause.
Still an error in the historylist and completionlist items. They are
not shown correctly.
Mar 19, 2001 : Otto Bruggeman
Added most of the preferences dialog
Some speed improvements
Some fixes to use the last used directory in KFileDialog

35
kompare/DESIGN Normal file
View file

@ -0,0 +1,35 @@
Kompare General design:
Kompare is split up into 4 parts:
- A shell around the parts
- A library with the modellist and the parser
- The navigation tree which uses the library
- The view part that also uses the library
The diffmodel is comparable to a document and the view part is comparable
to the view and the komparemodellist is comparable to a documentmanager.
The navtree can be viewed as a document view manager.
The model is fully separated from the view and all communication goes
through signals and slots. The view gets a model that contains all differences
for the compared files A and B. The view gets this model from the modellist,
the central entity in the part.
There is an interface to the komparepart that can be used in other programs,
simply link to the libkompareinterface.la and call its methods after you have
instanciated a komparepart. There is also a "hidden" signal and slot interface
that can be connected to from the shell app to get some information, and an
interface for communication between the navigation part and the komparepart.
There is no need to use the interface for the communication between the
navigation and kompare parts in the shell app.
Kompare has some debug areas:
8100 kompare
8101 kompare (libs)
8102 kompare (shell)
8103 kompare (part)
8104 kompare (list view)
8105 kompare (nav view)
8106 kompare (connect widget)

19
kompare/Mainpage.dox Normal file
View file

@ -0,0 +1,19 @@
/** @mainpage Kompare
*
* Kompare is a graphical difference viewer that allows you to visualize changes
* to a file. Whether you're a developer comparing source code, or you just want
* to see the difference between that research paper draft and the final document,
* Kompare is the tool you need.
*
* Kompare can
* - Compare two text files
* - Recursively compare directories
* - View patches generated by diff
* - Merge a patch into an existing directory
*
* Kompare can either be used as a standalone application, or embedded in another
* application - e.g. as a patch viewer in konqueror or in KDevelop.
*
* Kompare is part of the KDE SDK package, and it is released at the same time as
* the rest of KDE SDK and KDE.
*/

3
kompare/Messages.sh Normal file
View file

@ -0,0 +1,3 @@
#! /bin/sh
$EXTRACTRC *.rc */*.rc */*.ui >> rc.cpp || exit 11
$XGETTEXT `find . -name "*.cpp" -o -name "*.h"` -o $podir/kompare.pot

16
kompare/README Normal file
View file

@ -0,0 +1,16 @@
Kompare 2.0
Kompare is a program to view the differences between files. Features include:
* comparison of files or directories via a graphical interface
* bezier-based connection widget lets you see both source and destination
as they really appear
* graphical viewing of patch files in normal, context, unified and
diff formats
* interactive application of differences
* full network transparency
* ability to view plain-text diff output in embedded viewer
* easy navigation of multiple-file diffs with dockable navigation tree
* graphical interface to commonly used diff command line options
* switch source and destination with one command
* diff statistics

View file

@ -1,21 +0,0 @@
# Maintainer: Ivailo Monev <xakepa10@gmail.com>
version=4.14.3
description='Diff/Patch Frontend'
depends=('kde-runtime' 'libkomparediff2')
makedepends=('cmake' 'automoc4')
sources=("http://download.kde.org/stable/$version/src/kompare-$version.tar.xz")
src_compile() {
mkdir "$SOURCE_DIR/build" && cd "$SOURCE_DIR/build"
cmake ../kompare-$version \
-DCMAKE_BUILD_TYPE=Release \
-DKDE4_BUILD_TESTS=OFF \
-DCMAKE_INSTALL_PREFIX=
make
}
src_install() {
cd "$SOURCE_DIR/build"
make DESTDIR=$INSTALL_DIR install
}

34
kompare/TODO Normal file
View file

@ -0,0 +1,34 @@
!!! Must do before a merge back into HEAD !!!
* Write a kconfupdate script to convert the kconfigfile
* the diff options now have their own group
* the view options now have their own group
* the Recent Files group has been renamed to Recent Compare Files
Very important:
* Make sure unified and context actually work again !
* Implement the rest of the interface (compare3 etc.)
* Make sure the rest works too ! Still some problems parsing some files
* Other various things that need to be fixed asap (before 3.2 is released)
In descending order of importance:
* Add a kompare manual/document
* add support for handediting conflicts
* session management (should almost work)
* implement normal, ed and rcs format (normal got busted)
* merge text view GUI
* clicking in the connect widget should select a difference (tricky!)
* add support for incremental patch saving (i'll explain if anyone wants to know)
* Add support for diff3 (that is comparing 3 files at once)
Special requests:
Puetzk:
* Editing the TO pane
Falk:
* Allow only part of a change to be applied to the other file
Harlekin:
* Add search functionality, either in source, dest or both at the same time
HarryF:
* emit clicked() signal when on a diff with line number
aseigo:
* merge from dest to source instead of only from source to dest
(Workaround: swap source with destination and then apply the differences)

View file

@ -0,0 +1,4 @@
########### install files ###############
#
#
kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kompare)

BIN
kompare/doc/dock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 B

909
kompare/doc/index.docbook Normal file
View file

@ -0,0 +1,909 @@
<?xml version="1.0" ?>
<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
<!ENTITY kappname "&kompare;">
<!ENTITY version "4.4.0">
<!ENTITY package "kdesdk">
<!ENTITY % addindex "IGNORE">
<!ENTITY % English "INCLUDE">
]>
<book id="kompare" lang="&language;">
<bookinfo>
<title>The &kompare; Handbook</title>
<authorgroup>
<author><firstname>Sean</firstname><surname>Wheller</surname><email>sean@inwords.co.za</email></author>
<!-- TRANS:ROLES_OF_TRANSLATORS -->
</authorgroup>
<copyright>
<year>2007</year>
<holder>Sean Wheller</holder>
</copyright>
<legalnotice>&FDLNotice;</legalnotice>
<date>2010-07-22</date>
<releaseinfo>&version;</releaseinfo>
<!-- Abstract about this handbook -->
<abstract>
<para>
&kompare; is a &GUI; front-end program that enables differences between source files to be viewed and merged.
&kompare; can be used to compare differences on files or the contents of folders. &kompare; supports a variety
of diff formats and provide many options to customize the information level displayed.</para>
<para>This document describes &kompare; version &version;.</para>
</abstract>
<keywordset>
<keyword>KDE</keyword>
<keyword>Kompare</keyword>
<keyword>Diff</keyword>
<keyword>Merge</keyword>
<keyword>Patch</keyword>
<keyword>Hunk</keyword>
</keywordset>
</bookinfo>
<chapter id="introduction">
<title>Introduction</title>
<para>When two or more people are working on a file and passing it back and forth between one another, it becomes difficult to
see what changes have been made to a new version or copy of the file. Opening the new copy and the original, side-by-side in the
application used to create it is one solution but, laborious, time consuming, and prone to error. This is where a program to show
differences, diffs for short, is useful.</para>
<para>As would be expected, an appropriate name for such a program would be &quot;diff&quot;. As it happens, the program diff is installed on
most &Linux;-based systems and is used for exactly this purpose. Developers often use diff, as a command line tool, to show differences
between versions of a source code file. However, the use of diff is not limited to showing differences in code source files,
it can be used on many text-based file types.</para>
<para>Using diff from the command line can be confusing, learning the diff command syntax and deciphering the output can bewilder most people.
This is where &kompare; comes into play. Providing a graphical front-end to the diff program, the interface displays source and destination files
side-by-side with all differences automatically highlighted. From this starting point, changes in one file can be sequentially applied to the other file
on a selective and controlled basis. Not all changes need to be applied and if you do apply a change it can always be &apos;unapplied&apos;.
When all required changes have been applied they can be saved and will display as normal in the original application used to create the file.</para>
<para>In addition to displaying differences between a source and destination file, &kompare; can be used to create and view a special file called a &apos;diff&apos;.
This file captures the differences between the two sources into a single file that can be used to view and apply changes to any other copy of the file.
For example, if two people are editing a document. The first person wants to make changes and send just the changes made to the second person.
Normally, the first person would send a complete copy of the modified document to the second person, who would then have to compare the modified document
side-by-side with unmodified version. The process for this is much like what we have described in the previous paragraphs. With &kompare; the first person
would first make a local copy of the file to be modified, then make changes and compare the original and modified copy. Now using &kompare; a diff file
can be created that captures only the changes made. This can be sent to the second person in place of a whole file containing the changes.</para>
<para>Using &kompare; the second person can view the diff file, compare it to the local copy of the document and apply the changes made by the first person.
So the process can go on for many versions of the document, each person making changes, creating diffs, distributing them and applying them.
This process is commonly called &quot;patching&quot;, a term taken from the program named &quot;patch&quot; which is another command line
tool specifically designed for the purpose of applying diff files.</para>
<para>It sometimes happens that people edit a file at the same time. In this situation it is likely that people will make changes in the document at
exactly the same line. This creates a problem because, without applied caution, people could be overwriting each others work as they apply the diff files they receive.
Fortunately the developers of the diff and patch programs took this into consideration and so these tools will not allow such changes to be applied without manual intervention.
When this state is reached, it is known as a &quot;conflict&quot;. &kompare; will display conflicts so that you can manually resolve them, deciding
which changes should be applied to which file.</para>
<para>&kompare; is also a great program for comparison of file changes on a folder level. When used to compare folders &kompare; recursively examines subfolders
and their file contents for differences. In this use case, each file where differences are found are automatically opened and
listed by &kompare; where easy navigation between the various files is possible.</para>
</chapter>
<chapter id="using">
<title>Using &kompare;</title>
<sect1 id="getting-started">
<title>Getting Started</title>
<para>This section provides instructions for starting &kompare; and provides a quick tour to the &kompare; main interface.</para>
<sect2 id="starting-kompare">
<title>Starting &kompare;</title>
<para>A shortcut for starting &kompare; can be found in the K menu in the Development group
<menuchoice><guimenu>Development</guimenu><guimenuitem>Kompare</guimenuitem></menuchoice>.</para>
<para>When &kompare; starts the first thing it does is display a dialog from
which to select the files you wish to compare. Special settings for the properties of the diff and the appearance thereof can also be selected.
In the file form select a source and destination source to compare. This can be any two files, folders or a &URL; and a file.
Once the source and destination are selected click the <guibutton>Compare</guibutton> button.</para>
<para>Once &kompare; has discovered the differences it will display the main interface.
When comparing two files or a URL and a file the process takes just a few seconds. However, when comparing folders
with many subfolders and files, this process can take awhile.</para>
<para>For explanation of the options available from diff and appearance forms see <xref linkend="configure-preferences"/>.</para>
</sect2>
<sect2 id="main-interface">
<title>The Main Interface</title>
<para>This section provides a quick tour of the main interface which is comprised of the following areas:</para>
<itemizedlist>
<listitem><para>Menus</para></listitem>
<listitem><para>Toolbar</para></listitem>
<listitem><para>Source and Destination Folders</para></listitem>
<listitem><para>Source and Destination Files</para></listitem>
<listitem><para>Source and Destination Line Changes</para></listitem>
<listitem><para>Source and Destination Text View</para></listitem>
<listitem><para>Statusbar</para></listitem>
</itemizedlist>
<sect3 id="menus">
<title>Menus</title>
<para>&kompare; provides a menu driven interface. Explanation to the menu items and their options is provided in <xref linkend="command-reference"/>.</para>
</sect3>
<sect3 id="toolbar">
<title>Toolbar</title>
<para>The &kompare; toolbar provides shortcuts to the most frequently used diff and merge operations.
The toolbar orientation, text positioning, icon size properties and which shortcut icons are displayed can be customized from the
toolbar context menu accessed when right-clicking the toolbar with the mouse. The toolbar context menu also enables the toolbar to be hidden.
If the toolbar is hidden and you wish to unhide it, select <menuchoice><guimenu>Settings</guimenu><guimenuitem>Show Toolbar</guimenuitem></menuchoice>.</para>
</sect3>
<sect3 id="source-destination-folders">
<title>Source and Destination Folders</title>
<para>The source folder and destination folder panes display the folders in which compared files reside.
When many subfolders are included in the comparison, then selecting a folder will display the first document in
that folder where a difference was found between the source and destination.</para>
</sect3>
<sect3 id="source-destination-files">
<title>Source and Destination Files</title>
<para>The source and destination file pane displays files where a difference was found for the currently selected source or destination folder.
When a folder has multiple documents containing differences, all documents with a difference are listed. The selected document is displayed.</para>
</sect3>
<sect3 id="source-destination-lines">
<title>Source and Destination Line Changes</title>
<para>The source and destination line changes pane summarizes the differences found between the current source and destination documents.
Selecting a record within the pane highlights and selects the difference. This is a useful way to navigate and inspect long documents with many differences.</para>
</sect3>
<sect3 id="source-destination-view">
<title>Source and Destination View</title>
<para>The source and destination view is the main workspace of &kompare;.
The contents and highlighted differences of the currently selected source and destination file are displayed here with line numbers.</para>
</sect3>
<sect3 id="text-view">
<title>Text View</title>
<para>The <guilabel>Text View</guilabel> is not displayed by default. It can be opened by selecting
<menuchoice><guimenu>Settings</guimenu><guimenuitem>Show Text View</guimenuitem></menuchoice>.</para>
<!-- Other than a notepad, what is this text view good for? -->
</sect3>
<sect3 id="statusbar">
<title>Statusbar</title>
<para>The status bar provides a summary of the current source and destination file or folder under comparison.
The status bar also reports the number of changes found in the current document and counts the differences that have been applied.
Furthermore, the status bar shows the overall number of documents containing differences and the current document number selected from this set.
For example, a comparison run over two folders may return 1890 files with differences. The currently selected document is number 18 of 1890.</para>
</sect3>
</sect2>
</sect1>
<sect1 id="viewing-differences">
<title>Viewing Differences</title>
<sect2 id="managing-screen-real-estate">
<title>Managing Screen Real-Estate</title>
<para>&kompare; displays the source and destination file under using equal percentage of the main interface view work area.
This view area provides some features that help optimize use of screen real-estate while viewing differences, including:</para>
<variablelist>
<varlistentry>
<term>Dual Scrollbars</term>
<listitem><para>The most obvious feature is that scrollbars are provided both on the right and bottom edges of the view area.
Using the scrollbars it is possible to move rapidly through the comparison.</para></listitem>
</varlistentry>
<varlistentry>
<term>Share Grip Handle</term>
<listitem><para>The vertical space between the source and destination view not only makes it possible to clearly see the start and end of lines in each of the panes,
but is also a grip handle that allows adjustment of percentage occupied between the source and destinate views that comprise the view pane.
To change pane size for one of the views, hover the mouse pointer over the grip handle then hold down the mouse button and drag left or right.
Naturally, increasing the area of one pane will decrease the area available to the opposite pane within the view panel area.</para>
<para>A second horizontal handle is available between the navigation panel and the source and destination view.</para></listitem>
</varlistentry>
<varlistentry>
<term>Docking</term>
<listitem><para>The navigation panel can be undocked from the main interface by clicking the <inlinemediaobject>
<imageobject><imagedata fileref="undock.png" format="PNG"/></imageobject></inlinemediaobject> icon located top right of the panel.
This opens it in a window of its own, allowing you to move it across the screen. You can even hide the navigation panel by clicking the <inlinemediaobject><imageobject><imagedata fileref="dock.png" format="PNG"/></imageobject></inlinemediaobject> icon.
To display a hidden navigation bar again, click with the &RMB; into the menubar and select <guilabel>Navigation</guilabel> from the context menu.
</para></listitem>
</varlistentry>
<varlistentry>
<term>Statusbar Toggle</term>
<listitem>
<para>The status bar of the view panel can be toggled on and off by selecting <menuchoice><guimenu>Settings</guimenu><guimenuitem>Show Statusbar</guimenuitem></menuchoice>.</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="switching-source-and-destination-view">
<title>Switching Source and Destination Views</title>
<para>Sometimes it can be useful to consider what the file to which differences where to be applied as the source.
For example, when comparing two modified versions of a file and discovering that the one file has many more modifications that the other.
The file with more changed would be better as the source, since then fewer differences would need to be applied.</para>
<para>In this case select <menuchoice><guimenu>File</guimenu><guimenuitem>Swap Source with Destination</guimenuitem></menuchoice>.
This will switch the files displayed in all &kompare; panels.</para>
</sect2>
<sect2 id="display-difference-statistics">
<title>Displaying Difference Statistics</title>
<para>For a quick overview of the differences, select <menuchoice><guimenu>File</guimenu><guimenuitem>Show Statistics</guimenuitem></menuchoice>.
This will display the <guilabel>Diff Statistics</guilabel> dialog. The following information is provided:</para>
<variablelist>
<varlistentry>
<term><guilabel>Old file:</guilabel></term>
<listitem><para>The file name of what is usually the source file or file that is unmodified.</para></listitem>
</varlistentry>
<varlistentry>
<term><guilabel>New file:</guilabel></term>
<listitem><para>The file name of what is usually the destination file or file that is modified and to which differences will be applied.</para></listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Format:</guilabel></term>
<listitem><para>The diff format used to display the difference (see <xref linkend="diff-format"/>).</para></listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Number of hunks:</guilabel></term>
<listitem>
<para>The number of hunks found in the difference.</para>
<para>A hunk is a <quote>c<emphasis>hunk</emphasis></quote> of lines that have been marked as different between
source and destination and may include context lines depending on the diff format <guilabel>Lines of Context</guilabel> value (see <xref linkend="diff-format"/>).</para></listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Number of differences</guilabel></term>
<listitem><para>The actual number of differences found, not hunks. A hunk can contain one or more differences
when the line change range and the context lines of any two or more changes overlap.</para></listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="navigating-the-difference-view">
<title>Navigating the Difference View</title>
<para>&kompare; enables rapid navigation of differences on a file level and of multiple difference files when comparing folder trees.</para>
<sect3 id="selecting-a-difference">
<title>Selecting a Difference</title>
<para>A difference can be selected using by:</para>
<itemizedlist>
<listitem><para>clicking a line in the Source and Destination Line Changes pane (top right of the main window).</para></listitem>
<listitem><para>clicking the highlighted difference in the View pane.</para></listitem>
<listitem><para>traversing the listed differences in a comparison (see <xref linkend="traversing-differences"/>).</para></listitem>
</itemizedlist>
<para>When a difference is selected it is considered to be <quote>in focus</quote> and is displayed in a brighter color that non-selected differences.</para>
</sect3>
<sect3 id="traversing-differences">
<title>Traversing Differences</title>
<para>When a comparison finds many differences one of the best ways to approach reviewing them is to traverse the differences in a logical order, usually from top to bottom.</para>
<para>By default &kompare; selects the first difference found in a comparison. By selecting
<menuchoice><guimenu>Difference</guimenu><guimenuitem>Next Difference</guimenuitem></menuchoice>
(<keycombo action="simul">&Ctrl;<keycap>Down</keycap></keycombo>) the difference following the current selection is brought into focus.
To select the difference before the current difference
select <menuchoice><guimenu>Difference</guimenu><guimenuitem>Previous Difference</guimenuitem></menuchoice>
(<keycombo action="simul">&Ctrl;<keycap>Up</keycap></keycombo>).</para>
<para>In this way it is possible to traverse differences in an orderly manner, applying and unapply differences upon review.</para>
</sect3>
<sect3 id="switching-between-files">
<title>Switching Between Files</title>
<para>When a comparison is performed on folder level, many files may be found with differences.
A complete list of the files compared with difference found is provided in the <quote>Source and Destination Folders</quote>,
and <quote>Source and Destination Files</quote> panes. However, &kompare; displays differences between source and destination one comparison at time.</para>
<para>To switch between documents in this scenario the following options are available:</para>
<itemizedlist>
<listitem><para>Select the <quote>Source and Destination Folders</quote> pane to display file differences found in the
<quote>Source and Destination Files</quote> pane, then select a file.</para></listitem>
<listitem><para>Select <menuchoice><guimenu>Difference</guimenu><guimenuitem>Previous File</guimenuitem></menuchoice>
(<keycombo action="simul">&Ctrl;<keycap>PgUp</keycap></keycombo>) or
<menuchoice><guimenu>Difference</guimenu><guimenuitem>Next File</guimenuitem></menuchoice>
(<keycombo action="simul">&Ctrl;<keycap>PgDown</keycap></keycombo>) to
display the previous or next difference file found in the <quote>Source and Destination Files</quote> pane.</para>
</listitem>
</itemizedlist>
</sect3>
</sect2>
</sect1>
<sect1 id="merging-differences">
<title>Merging Differences</title>
<para>&kompare; makes the task of applying and unapplying differences as simple as point and click.
Multiple apply and unapply operations can be performed on a difference as all operations are performed in memory and not written to the files on disk until the save operation is performed.</para>
<sect2 id="applying-a-difference">
<title>Applying a Difference</title>
<para>To apply a difference, click the highlighted difference region, then select
<menuchoice><guimenu>Difference</guimenu><guimenuitem>Apply Difference</guimenuitem></menuchoice> (<keycombo><keycap>Space</keycap></keycombo>).</para>
</sect2>
<sect2 id="unapplying-a-difference">
<title>Unapplying a Difference</title>
<para>To unapply a difference, click the highlighted difference region previously applied, then select
<menuchoice><guimenu>Difference</guimenu><guimenuitem>Unapply Difference</guimenuitem></menuchoice> (<keycombo>&Backspace;</keycombo>).</para>
</sect2>
<sect2 id="applying-all-differences">
<title>Applying All Differences</title>
<para>After reviewing differences between files and finding all acceptable it is possible apply them all with a single operation by selecting
<menuchoice><guimenu>Difference</guimenu><guimenuitem>Apply All</guimenuitem></menuchoice> (<keycombo action="simul">&Ctrl;<keycap>A</keycap></keycombo>).</para>
</sect2>
<sect2 id="unapplying-all-differences">
<title>Unapplying All Differences</title>
<para>To revert all differences that have been applied previously select
<menuchoice><guimenu>Difference</guimenu><guimenuitem>Unapply All</guimenuitem></menuchoice> (<keycombo action="simul">&Ctrl;<keycap>U</keycap></keycombo>).</para>
</sect2>
<sect2 id="saving-changes">
<title>Saving Changes</title>
<para>Once differences have been applied they can be saved by selecting
<menuchoice><guimenu>File</guimenu><guimenuitem>Save</guimenuitem></menuchoice> or
<menuchoice><guimenu>File</guimenu><guimenuitem>Save All</guimenuitem></menuchoice>.</para>
<para>Applied differences are saved to both the source and destination file.</para>
</sect2>
</sect1>
<sect1 id="working-with-diff-files">
<title>Working with Diff Files</title>
<para>Diff files contain only the changes made between files, or a set of files within a folder system, and may or may not contain a number of context lines before and after line changes.
The sum of a line change and its context lines is known a hunk. A diff file therefore may contain multiple hunks from one or more files.
When the context lines of two or more hunks overlap, they are considered a single hunk. Diff files can be used to:</para>
<itemizedlist>
<listitem><para>Apply the changes contained in the hunks to an original file.</para></listitem>
<listitem><para>Apply the changes contained in the hunks to a file or set of original files within a folder system.</para></listitem>
<listitem><para>Modified before being applied to an original file or set of original files within a folder system.</para></listitem>
</itemizedlist>
<sect2 id="creating-a-diff">
<title>Creating a Diff</title>
<para>To create a diff file a comparison must be displayed in &kompare;. Assuming this is the case, then select <menuchoice><guimenu>File</guimenu><guimenuitem>Save Diff...</guimenuitem></menuchoice>
This will display the <guilabel>Diff Options</guilabel> dialog (see <xref linkend="diff-settings"/> for more information on diff formats and options).
After configuring these options, click the <guibutton>Save</guibutton> button and save the diff to a file with the extension <filename class="extension">.diff</filename>.</para>
</sect2>
<sect2 id="displaying-a-diff">
<title>Displaying a Diff</title>
<para>It is possible to display the contents of a diff file within &kompare; by opening the diff file from <menuchoice><guimenu>File</guimenu><guimenuitem>Open Diff...</guimenuitem></menuchoice>.</para>
<para>When viewing a diff file the hunks between the source and destination file are shown, remember that only the hunks are shown, no unmodified lines will be shown.
In some cases a diff file is created with 0 lines of context. In this case only the changed lines will be displayed.</para>
<para>When a diff file contains hunks from multiple files &kompare; displays the hunks from each file one at a time and you can
switch between files as though they were real files even though this information is only provided by the diff file contents.</para>
</sect2>
<sect2 id="applying-a-diff">
<title>Applying Differences in a Diff File</title>
<para>When viewing differences in a diff file it is possible to apply difference as you would when comparing source and destination files (see <xref linkend="merging-differences"/>).</para>
</sect2>
<sect2 id="blending-a-diff">
<title>Blending a &URL; with a Diff</title>
<para>In cases where a diff file is provided it is possible to compare the hunks in the diff against a file or folder.
To do this select <menuchoice><guimenu>File</guimenu><guimenuitem>Blend URL with Diff...</guimenuitem></menuchoice>.
Then input the <guilabel>File/Folder</guilabel> and <guilabel>Diff Output</guilabel> paths.</para>
<para>When viewing differences between a source file and a diff file it is possible to apply difference as you would when comparing source and destination files (see <xref linkend="merging-differences"/>).</para>
</sect2>
</sect1>
</chapter>
<chapter id="configure-preferences">
<title>Configuring Preferences</title>
<para>&kompare; enables users to set appearance preferences for difference formatting in the main interface and set behavioural properties of the diff program.
The <guilabel>Preferences</guilabel> dialog can be accessed by selecting
<menuchoice><guimenu>Settings</guimenu><guisubmenu>Configure &kompare;...</guisubmenu></menuchoice>.</para>
<para>To configure preferences for appearance select the <guilabel>View</guilabel> menu item (see <xref linkend="view-settings"/>).</para>
<para>To configure preferences for diff program properties select the <guilabel>Diff</guilabel> menu item (see <xref linkend="diff-settings"/>).</para>
<sect1 id="view-settings">
<title>View Settings</title>
<para>The <guimenu>View</guimenu> page in the <guilabel>Preferences</guilabel> dialog displays the <guilabel>Appearance</guilabel>
and <guilabel>Fonts</guilabel> tabbed forms.</para>
<sect2 id="appearance">
<title>Appearance</title>
<para>The <guilabel>Appearance</guilabel> form provides controls to manage the <guilabel>Colors</guilabel> used
to denote difference in the main interface, behaviour of the <guilabel>Mouse Wheel</guilabel> when jogging up and down
and how <guilabel>Tabs to Spaces</guilabel> conversion is managed.</para>
<screenshot>
<screeninfo>&kompare; Appearance Settings</screeninfo>
<mediaobject>
<imageobject>
<imagedata fileref="settings-view1.png" format="PNG"/>
</imageobject>
<textobject>
<phrase>&kompare; Appearance Settings</phrase>
</textobject>
</mediaobject>
</screenshot>
<variablelist>
<title>Color Group</title>
<para>To adjust color preferences used when displaying differences, click the color button to display the <guilabel>Select Color</guilabel> dialog for the following states:</para>
<varlistentry>
<term><guilabel>Removed color</guilabel></term>
<listitem><para>Lines that have been removed, do not exist, between source and destination.</para></listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Changed color</guilabel></term>
<listitem><para>Lines that have been changed, modified, between source and destination. </para></listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Added color</guilabel></term>
<listitem><para>Lines that have been added between source and destination.</para></listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Applied color</guilabel></term>
<listitem><para>Any of the above states where the difference has been applied between source and destination.</para></listitem>
</varlistentry>
</variablelist>
<variablelist>
<title>Mouse Wheel</title>
<varlistentry>
<term><guilabel>Number of lines</guilabel></term>
<listitem><para>The number of lines to jog the differences when turning the mouse wheel forward or backward.</para></listitem>
</varlistentry>
</variablelist>
<variablelist>
<title>Tabs to Spaces</title>
<varlistentry>
<term><guilabel>Number of spaces to convert a tab character to</guilabel></term>
<listitem><para>Convert each tab character to n space characters.</para></listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="fonts">
<title>Fonts</title>
<screenshot>
<screeninfo>&kompare; Fonts Settings</screeninfo>
<mediaobject>
<imageobject>
<imagedata fileref="settings-view2.png" format="PNG"/>
</imageobject>
<textobject>
<phrase>&kompare; Fonts Settings</phrase>
</textobject>
</mediaobject>
</screenshot>
<para>Select the font family and size to display when displaying differences.</para>
</sect2>
</sect1>
<sect1 id="diff-settings">
<title>Diff Settings</title>
<para>The <guimenu>Diff</guimenu> page in the <guilabel>Preferences</guilabel> dialog displays the <guilabel>Diff</guilabel>,
<guilabel>Format</guilabel>, <guilabel>Options</guilabel> and <guilabel>Exclude</guilabel> tabbed forms. These forms can be used to configure the
behavioural properties of the Diff program.</para>
<sect2 id="diff">
<title>Diff</title>
<screenshot>
<screeninfo>&kompare; Diff Settings</screeninfo>
<mediaobject>
<imageobject>
<imagedata fileref="settings-diff1.png" format="PNG"/>
</imageobject>
<textobject>
<phrase>&kompare; Diff Settings</phrase>
</textobject>
</mediaobject>
</screenshot>
<para>The command used to run the diff program (default <application>diff</application>).</para>
</sect2>
<sect2 id="diff-format">
<title>Format</title>
<screenshot>
<screeninfo>&kompare; Format Settings</screeninfo>
<mediaobject>
<imageobject>
<imagedata fileref="settings-diff2.png" format="PNG"/>
</imageobject>
<textobject>
<phrase>&kompare; Format Settings</phrase>
</textobject>
</mediaobject>
</screenshot>
<para>Adjust options for the <guilabel>Output Format</guilabel> and number of <guilabel>Lines of Context</guilabel>.</para>
<variablelist>
<title>Output Format</title>
<varlistentry>
<term><guilabel>Context</guilabel></term>
<listitem>
<para>The context output format adds several lines of context around the lines that differ.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Normal</guilabel></term>
<listitem>
<para>The normal output format displays differing lines without any surrounding lines of context. </para>
</listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Unified</guilabel></term>
<listitem>
<para>The unified output format is a variation on the context format. It is considered better than context because the
output is more compact than that of context as it omits redundant context lines.</para>
</listitem>
</varlistentry>
<!-- not in 3.5.1
<varlistentry>
<term><guilabel>Side-by-side</guilabel></term>
<listitem>
<para>Use the side by side output format which displays files listed in two columns with a gutter between them. This option is only available from the <guilabel>Diff Options</guilabel> dialog (see <xref linkend="creating-a-diff"/>).</para>
</listitem>
</varlistentry>
-->
</variablelist>
<variablelist>
<title>Lines of Context</title>
<varlistentry>
<term><guilabel>Number of context lines</guilabel></term>
<listitem>
<para>When performing a diff with context or unified output format use this parameter to control the number of context lines included.</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="options">
<title>Options</title>
<screenshot>
<screeninfo>&kompare; Options Settings</screeninfo>
<mediaobject>
<imageobject>
<imagedata fileref="settings-diff3.png" format="PNG"/>
</imageobject>
<textobject>
<phrase>&kompare; Options Settings</phrase>
</textobject>
</mediaobject>
</screenshot>
<para>The <guilabel>Options</guilabel> tab form allows configuration of the options supported by the diff program.</para>
<variablelist>
<title>General</title>
<varlistentry>
<term><guilabel>Treat new files as empty</guilabel></term>
<listitem><para>With this option enabled diff will treat a file that only exists in one of
the directories as empty in the other directory. This means that the file is
compared with an empty file and because of this will appear as one big
insertion or deletion.</para></listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Look for smaller changes</guilabel></term>
<listitem><para>Forces diff to display changes in case, punctuation, space, &etc; when checked.</para></listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Optimize for large files</guilabel></term>
<listitem><para>Switches diff to process files with high-speed when checked.</para></listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Ignore changes in case</guilabel></term>
<listitem><para>Lower and Uppercase character changes are omitted when this option is checked.</para></listitem>
</varlistentry>
</variablelist>
<variablelist>
<varlistentry>
<term><guilabel>Ignore regexp</guilabel></term>
<listitem><para>Ignore lines matching a regular expression.</para></listitem>
</varlistentry>
</variablelist>
<variablelist>
<title>Whitespace</title>
<varlistentry>
<term><guilabel>Expand tabs to spaces in output</guilabel></term>
<listitem><para>When checked diff outputs will converts tab characters to the number of spaces defined in the
<guilabel>Preferences</guilabel> dialog <guimenu>View</guimenu> menu <guilabel>Tabs to Spaces</guilabel> option.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Ignore added or removed empty lines</guilabel></term>
<listitem><para>lines of zero length that differ between source and destination are ignored when this option is checked.</para></listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Ignore changes in the amount of whitespace</guilabel></term>
<listitem><para>White space before, after and between lines may change depending on different editors.
When this option is checked such changes are ignored.</para></listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Ignore all whitespace</guilabel></term>
<listitem><para>when checked white space differences are completely ignored.</para></listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Ignore changes due to tab expansion</guilabel></term>
<listitem><para>when checked white space resulting from tab characters is ignored.</para></listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="exclude">
<title>Exclude</title>
<para>The <guilabel>Exclude</guilabel> form enables use of the filter options provided by the diff program.</para>
<screenshot>
<screeninfo>&kompare; Exclude Settings</screeninfo>
<mediaobject>
<imageobject>
<imagedata fileref="settings-diff4.png" format="PNG"/>
</imageobject>
<textobject>
<phrase>&kompare; Exclude Settings</phrase>
</textobject>
</mediaobject>
</screenshot>
<variablelist>
<title>File Pattern to Exclude</title>
<varlistentry>
<term><guilabel>File Pattern to Exclude</guilabel></term>
<listitem><para>Exclude files based on wild card filtering</para></listitem>
</varlistentry>
</variablelist>
<variablelist>
<title>File with Filenames to Exclude</title>
<varlistentry>
<term><guilabel>File with Filenames to Exclude</guilabel></term>
<listitem><para>Define the filter based on the content of an externally managed file.</para></listitem>
</varlistentry>
</variablelist>
</sect2>
</sect1>
</chapter>
<chapter id="command-reference">
<title>Command Reference</title>
<sect1 id="file-menu">
<title>The File Menu</title>
<variablelist>
<varlistentry>
<term><menuchoice>
<shortcut>
<keycombo action="simul">&Ctrl;<keycap>O</keycap></keycombo>
</shortcut>
<guimenu>File</guimenu><guimenuitem>Open Diff...</guimenuitem></menuchoice></term>
<listitem><para>Displays the <guilabel>Open</guilabel> dialog.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice>
<shortcut>
<keycombo action="simul">&Ctrl;<keycap>C</keycap></keycombo>
</shortcut>
<guimenu>File</guimenu><guimenuitem>Compare Files...</guimenuitem></menuchoice></term>
<listitem><para>Displays the <guilabel>Compare Files or Folders</guilabel> dialog.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice>
<shortcut>
<keycombo action="simul">&Ctrl;<keycap>B</keycap></keycombo>
</shortcut>
<guimenu>File</guimenu><guimenuitem>Blend URL with Diff...</guimenuitem></menuchoice></term>
<listitem><para>Displays the <guilabel>Blend File/Folder with diff Output</guilabel> dialog.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice>
<shortcut>
<keycombo action="simul">&Ctrl;<keycap>S</keycap></keycombo>
</shortcut>
<guimenu>File</guimenu><guimenuitem>Save</guimenuitem></menuchoice></term>
<listitem><para>Writes applied differences to current source and or destination file.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice><guimenu>File</guimenu><guimenuitem>Save All</guimenuitem></menuchoice></term>
<listitem><para>Writes applied differences to all source and or destination files.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice><guimenu>File</guimenu><guimenuitem>Save Diff...</guimenuitem></menuchoice></term>
<listitem><para>Displays the <guilabel>Diff Options</guilabel> dialog to define diff format and options.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice><guimenu>File</guimenu><guimenuitem>Swap Source with Destination</guimenuitem></menuchoice></term>
<listitem><para>Changes source and destination.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice>
<guimenu>File</guimenu><guimenuitem>Show Statistics</guimenuitem></menuchoice></term>
<listitem><para>Displays the <guilabel>Display Statistics</guilabel> dialog.</para></listitem>
</varlistentry>
<!-- Print Print Preview in 4.5.1-->
<varlistentry>
<term><menuchoice>
<shortcut>
<keycombo action="simul">&Ctrl;<keycap>Q</keycap></keycombo>
</shortcut>
<guimenu>File</guimenu><guimenuitem>Quit</guimenuitem></menuchoice></term>
<listitem><para>Exits &kompare;.</para></listitem>
</varlistentry>
</variablelist>
</sect1>
<sect1 id="difference-menu">
<title>The Difference Menu</title>
<variablelist>
<varlistentry>
<term><menuchoice>
<shortcut>
<keycombo action="simul">&Ctrl;<keycap>U</keycap></keycombo>
</shortcut>
<guimenu>Difference</guimenu><guimenuitem>Unapply All</guimenuitem></menuchoice></term>
<listitem><para>Unapply all differences previously applied between source and destination.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice>
<shortcut>&Backspace;</shortcut>
<guimenu>Difference</guimenu><guimenuitem>Unapply Difference</guimenuitem></menuchoice></term>
<listitem><para>Revert a selected difference previously applied.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice>
<shortcut><keycap>Space</keycap></shortcut>
<guimenu>Difference</guimenu><guimenuitem>Apply Difference</guimenuitem></menuchoice></term>
<listitem><para>Apply a selected difference.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice>
<shortcut>
<keycombo action="simul">&Ctrl;<keycap>A</keycap></keycombo>
</shortcut>
<guimenu>Difference</guimenu><guimenuitem>Apply All</guimenuitem></menuchoice></term>
<listitem><para>Apply all differences between source and destination.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice>
<shortcut>
<keycombo action="simul">&Ctrl;<keycap>PgUp</keycap></keycombo>
</shortcut>
<guimenu>Difference</guimenu><guimenuitem>Previous File</guimenuitem></menuchoice></term>
<listitem><para>Make the previous difference, in the list of differences, the current file in the view pane.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice>
<shortcut>
<keycombo action="simul">&Ctrl;<keycap>PgDown</keycap></keycombo>
</shortcut>
<guimenu>Difference</guimenu><guimenuitem>Next File</guimenuitem></menuchoice></term>
<listitem><para>Make the next difference, in the list of differences, the current file in the view pane.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice>
<shortcut>
<keycombo action="simul">&Ctrl;<keycap>Up</keycap></keycombo>
</shortcut>
<guimenu>Difference</guimenu><guimenuitem>Previous Difference</guimenuitem></menuchoice></term>
<listitem><para>Select the difference above the currently selected difference.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice>
<shortcut>
<keycombo action="simul">&Ctrl;<keycap>Down</keycap></keycombo>
</shortcut>
<guimenu>Difference</guimenu><guimenuitem>Next Difference</guimenuitem></menuchoice></term>
<listitem><para>Select the difference below the currently selected difference.</para></listitem>
</varlistentry>
</variablelist>
</sect1>
<sect1 id="settingsmenu">
<title>The Settings Menu</title>
<variablelist>
<varlistentry>
<term><menuchoice><guimenu>Settings</guimenu><guimenuitem>Show Toolbar</guimenuitem></menuchoice></term>
<listitem><para>Toggle the toolbar display ON/OFF.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice><guimenu>Settings</guimenu><guimenuitem>Show Statusbar</guimenuitem></menuchoice></term>
<listitem><para>Toggle the status bar display ON/OFF.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice><guimenu>Settings</guimenu><guimenuitem>Show Text View</guimenuitem></menuchoice></term>
<listitem><para>Display the <guilabel>Text View</guilabel> pane.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice><guimenu>Settings</guimenu><guimenuitem>Configure Shortcuts...</guimenuitem></menuchoice></term>
<listitem><para>Display the <guilabel>Configure Shortcuts</guilabel> dialog.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice><guimenu>Settings</guimenu><guimenuitem>Configure Toolbars...</guimenuitem></menuchoice></term>
<listitem><para>Display the <guilabel>Configure Toolbar</guilabel>.</para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice><guimenu>Settings</guimenu><guimenuitem>Configure &kompare;...</guimenuitem></menuchoice></term>
<listitem><para>Display the &kompare; <guilabel>Preference</guilabel> dialog.</para></listitem>
</varlistentry>
</variablelist>
</sect1>
<sect1 id="help-menu">
<title>The Help Menu</title>
&help.menu.documentation;
</sect1>
</chapter>
<chapter id="credits">
<title>Credits and License</title>
<para>
&kompare;
</para>
<para>
Program copyright 2001-2004, &John.Firebaugh; &John.Firebaugh.mail;
and Otto Bruggeman <email>otto.bruggeman@home.nl</email>
</para>
<para>
Documentation Copyright &copy; 2007 Sean Wheller <email>sean@inwords.co.za</email>
</para>
<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
&underFDL; <!-- FDL: do not remove -->
&underGPL; <!-- GPL License -->
</chapter>
<appendix id="installation">
<title>Installation</title>
<sect1 id="getting-kapp">
<title>How to obtain &kompare;</title>
&install.intro.documentation;
</sect1>
<sect1 id="compilation">
<title>Compilation and Installation</title>
&install.compile.documentation;
</sect1>
</appendix>
&documentation.index;
</book>
<!--
Local Variables:
mode: sgml
sgml-minimize-attributes:nil
sgml-general-insert-case:lower
sgml-indent-step:0
sgml-indent-data:nil
End:
// vim:ts=2:sw=2:tw=78:noet
-->

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
kompare/doc/undock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

View file

@ -0,0 +1,18 @@
########### next target ###############
set(kompareinterface_LIB_SRCS kompareinterface.cpp )
kde4_add_library(kompareinterface SHARED ${kompareinterface_LIB_SRCS})
target_link_libraries(kompareinterface ${KDE4_KDECORE_LIBS} )
set_target_properties(kompareinterface PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} )
install(TARGETS kompareinterface ${INSTALL_TARGETS_DEFAULT_ARGS} )
install(FILES kompareinterface.h DESTINATION ${INCLUDE_INSTALL_DIR}/kompare COMPONENT Devel )

View file

@ -0,0 +1,76 @@
/*
Copyright 2002-2004 Otto Bruggeman <otto.bruggeman@home.nl>
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) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
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, see <http://www.gnu.org/licenses/>.
*/
#include "kompareinterface.h"
class KompareInterfacePrivate
{
public:
KompareInterfacePrivate();
~KompareInterfacePrivate();
KompareInterfacePrivate( const KompareInterfacePrivate& );
KompareInterfacePrivate& operator=( const KompareInterfacePrivate& );
protected:
// Add all variables for the KompareInterface class here and access them through the kip pointer
};
KompareInterfacePrivate::KompareInterfacePrivate()
{
}
KompareInterfacePrivate::~KompareInterfacePrivate()
{
}
KompareInterfacePrivate::KompareInterfacePrivate( const KompareInterfacePrivate& /*kip*/ )
{
}
KompareInterfacePrivate& KompareInterfacePrivate::operator=(const KompareInterfacePrivate& /*kip*/ )
{
return *this;
}
KompareInterface::KompareInterface()
{
kip = new KompareInterfacePrivate();
}
KompareInterface::~KompareInterface()
{
delete kip;
}
KompareInterface::KompareInterface( const KompareInterface& ki )
{
kip = new KompareInterfacePrivate( *(ki.kip) );
}
KompareInterface& KompareInterface::operator=( const KompareInterface& ki )
{
kip = ki.kip;
return *this;
}
void KompareInterface::setEncoding( const QString& encoding )
{
m_encoding = encoding;
}

View file

@ -0,0 +1,133 @@
/*
Copyright 2002-2003 Otto Bruggeman <otto.bruggeman@home.nl>
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) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _KOMPARE_INTERFACE_H
#define _KOMPARE_INTERFACE_H
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <kdemacros.h>
class KConfig;
class KUrl;
class KompareInterfacePrivate;
class KDE_EXPORT KompareInterface
{
public:
KompareInterface();
virtual ~KompareInterface();
protected:
KompareInterface( const KompareInterface& );
KompareInterface& operator=(const KompareInterface& );
public:
/**
* Open and parse the diff file at url.
*/
virtual bool openDiff( const KUrl& diffUrl ) = 0;
/**
* Open and parse the supplied diff output
*/
virtual bool openDiff( const QString& diffOutput ) = 0;
/**
* Open and parse the diff3 file at url.
*/
virtual bool openDiff3( const KUrl& diff3Url ) = 0;
/**
* Open and parse the supplied diff3 output
*/
virtual bool openDiff3( const QString& diff3Output ) = 0;
/**
* Compare, with diff, source with destination, can also be used if you do not
* know what source and destination are. The part will try to figure out what
* they are (directory, file, diff output file) and call the
* appropriate method(s)
*/
virtual void compare( const KUrl& sourceFile, const KUrl& destinationFile ) = 0;
/**
* Compare a Source file to a custom Destination string
*/
virtual void compareFileString( const KUrl & sourceFile, const QString & destination) = 0;
/**
* Compare a custom Source string to a Destination file
*/
virtual void compareStringFile( const QString & source, const KUrl & destinationFile) = 0;
/**
* Compare, with diff, source with destination files
*/
virtual void compareFiles( const KUrl& sourceFile, const KUrl& destinationFile ) = 0;
/**
* Compare, with diff, source with destination directories
*/
virtual void compareDirs ( const KUrl& sourceDir, const KUrl& destinationDir ) = 0;
/**
* Compare, with diff3, originalFile with changedFile1 and changedFile2
*/
virtual void compare3Files( const KUrl& originalFile, const KUrl& changedFile1, const KUrl& changedFile2 ) = 0;
/**
* This will show the file and the file with the diff applied
*/
virtual void openFileAndDiff( const KUrl& file, const KUrl& diffFile ) = 0;
/**
* This will show the directory and the directory with the diff applied
*/
virtual void openDirAndDiff ( const KUrl& dir, const KUrl& diffFile ) = 0;
/**
* This will set the encoding to use for all files that are read or for the diffoutput
*/
virtual void setEncoding( const QString& encoding );
public:
/**
* Warning this should be in class Part in KDE 4.0, not here !
* Around that time the methods will disappear here
*/
virtual int readProperties( KConfig* config ) = 0;
virtual int saveProperties( KConfig* config ) = 0;
/**
* Warning this should be in class ReadWritePart in KDE 4.0, not here !
* Around that time the method will disappear here
*/
virtual bool queryClose() = 0;
protected:
// Add all variables to the KompareInterfacePrivate class and access them through the kip pointer
KompareInterfacePrivate* kip;
QString m_encoding;
};
Q_DECLARE_INTERFACE(KompareInterface, "com.kde.Kompare.KompareInterface/4.0")
#endif /* _KOMPARE_INTERFACE_H */

View file

@ -0,0 +1,37 @@
/***************************************************************************
* Copyright 2007 Andreas Pakulat <apaku@gmx.de> *
* Copyright 2006 Matt Rogers <mattr@kde.org> *
* Copyright 2004 Jarosław Staniek <staniek@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library 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 Library 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. *
***************************************************************************/
#ifndef KOMPAREINTERFACEEXPORT_H
#define KOMPAREINTERFACEEXPORT_H
/* needed for KDE_EXPORT macros */
#include <kdemacros.h>
#ifndef DIFF2_EXPORT
# ifdef MAKE_DIFF2_LIB
# define DIFF2_EXPORT KDE_EXPORT
# else
# define DIFF2_EXPORT KDE_IMPORT
# endif
#endif
#endif // KOMPAREINTERFACEEXPORT_H

138
kompare/kompare.desktop Executable file
View file

@ -0,0 +1,138 @@
# KDE Config File
[Desktop Entry]
Type=Application
Name=Kompare
Name[af]=K-vergelyk
Name[ast]=Kompare
Name[bg]=Kompare
Name[br]=Kompare
Name[bs]=Kompare
Name[ca]=Kompare
Name[ca@valencia]=Kompare
Name[cs]=Kompare
Name[cy]=Kompare
Name[da]=Kompare
Name[de]=Kompare
Name[el]=Kompare
Name[en_GB]=Kompare
Name[eo]=Komparilo
Name[es]=Kompare
Name[et]=Kompare
Name[eu]=Kompare
Name[fi]=Kompare
Name[fr]=Kompare
Name[ga]=Kompare
Name[gl]=Kompare
Name[he]=Kompare
Name[hr]=Kompare
Name[hu]=Kompare
Name[is]=Kompare
Name[it]=Kompare
Name[ja]=Kompare
Name[kk]=Kompare
Name[km]=Kompare
Name[ko]=Kompare
Name[lt]=Kompare
Name[lv]=Kompare
Name[mr]=
Name[ms]=Kompare
Name[nb]=Kompare
Name[nds]=Kompare
Name[ne]=
Name[nl]=Kompare
Name[nn]=Kompare
Name[pa]=-
Name[pl]=Kompare
Name[pt]=Kompare
Name[pt_BR]=Kompare
Name[ro]=Kompare
Name[ru]=Kompare
Name[sk]=Kompare
Name[sl]=Kompare
Name[sr]=Кпоређење
Name[sr@ijekavian]=Кпоређење
Name[sr@ijekavianlatin]=Kpoređenje
Name[sr@latin]=Kpoređenje
Name[sv]=Kompare
Name[ta]=
Name[tg]=Kompare
Name[tr]=Kompare
Name[ug]=Kompare
Name[uk]=Kompare
Name[vi]=Kompare
Name[wa]=Kompare
Name[xh]=Kompare
Name[x-test]=xxKomparexx
Name[zh_CN]=Kompare
Name[zh_TW]=Kompare
GenericName=Diff/Patch Frontend
GenericName[af]=Diff/Lap Voorprogram
GenericName[ast]=Interface Diff/Patch
GenericName[bg]=Интерфейс за Diff/Patch
GenericName[bs]=Poređenje datoteka za KDE pomoću Diff/Patch
GenericName[ca]=Frontal del Diff/Patch
GenericName[ca@valencia]=Frontal del Diff/Patch
GenericName[cs]=Rozhraní pro Diff/Patch
GenericName[cy]=Blaen Gwahaniaethau/Clytiau
GenericName[da]=Diff/patch-grænseflade
GenericName[de]=Oberfläche für Diff und Patch
GenericName[el]=Πρόγραμμα Diff/Patch
GenericName[en_GB]=Diff/Patch Frontend
GenericName[eo]=Fasado por la programoj "diff" kaj "patch"
GenericName[es]=Interfaz Diff/Patch
GenericName[et]=Diff/patch kasutajaliides
GenericName[eu]=Desberdintasun/Adabaki interfazea
GenericName[fa]=پایانه Diff/کژنه
GenericName[fi]=Diff/Patch-käyttöliittymä
GenericName[fr]=Interface graphique pour « Diff » et « Patch »
GenericName[ga]=Comhéadan Diff/Patch
GenericName[gl]=Interface para Diff/Patch
GenericName[he]=ממשק ל-Diff/Patch
GenericName[hr]=Sučelje za Diff/Patch
GenericName[hu]=Grafikus diff/patch
GenericName[is]=Myndrænt viðmót á Diff/Patch
GenericName[it]=Interfaccia per diff e patch
GenericName[ja]=Diff/Patch
GenericName[kk]=Diff/Patch интерфейсі
GenericName[km]= Diff/Patch
GenericName[ko]=Diff/Patch
GenericName[lt]=Diff/Patch naudotojo sąsaja
GenericName[lv]=Diff/Patch priekšpuse
GenericName[mr]=ि/
GenericName[ms]=Bahagian Depan Beza/Tampal
GenericName[nb]=Diff-/Patch-grensesnitt
GenericName[nds]=Böversiet för "diff" un "patch"
GenericName[ne]=Diff/Patch
GenericName[nl]=Diff/Patch-hulpprogramma
GenericName[nn]=Diff-/Patch-grensesnitt
GenericName[pa]=Diff/
GenericName[pl]=Interfejs dla programów diff i patch
GenericName[pt]=Interface do Diff/Patch
GenericName[pt_BR]=Interface do Diff/Patch
GenericName[ro]=Interfață grafică pentru diff și patch
GenericName[ru]=Утилита сравнения файлов
GenericName[sk]=Rozhranie Diff/Patch
GenericName[sl]=Začelje za diff/patch
GenericName[sr]=Прочеље за diff и patch
GenericName[sr@ijekavian]=Прочеље за diff и patch
GenericName[sr@ijekavianlatin]=Pročelje za diff i patch
GenericName[sr@latin]=Pročelje za diff i patch
GenericName[sv]=Gränssnitt för Diff/Patch
GenericName[ta]=ி/ ி
GenericName[tg]=Утилитаи баробаркунии файлҳо
GenericName[tr]=Diff/Patch Önyüzü
GenericName[ug]=سېلىشتۇرۇش/ياماش(Diff/Patch) نىڭ ئالدى ئۇچى
GenericName[uk]=Інтерфейс до diff/patch
GenericName[vi]=Diff/Patch Frontend
GenericName[xh]=Diff/Patch Frontend
GenericName[x-test]=xxDiff/Patch Frontendxx
GenericName[zh_CN]=Diff/Patch
GenericName[zh_TW]=Diff/Patch
MimeType=text/x-patch;
Exec=kompare -caption %c -o %U
Icon=kompare
X-DocPath=kompare/index.html
Terminal=false
X-DBUS-StartupType=Multi
Categories=Qt;KDE;Development;
InitialPreference=10

468
kompare/kompare_shell.cpp Normal file
View file

@ -0,0 +1,468 @@
/***************************************************************************
kompare_shell.cpp
-----------------
begin : Sun Mar 4 2001
Copyright 2001-2004,2009 Otto Bruggeman <bruggie@gmail.com>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2007-2011 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#include "kompare_shell.h"
#include <QtCore/QTextStream>
#include <QtGui/QDockWidget>
#include <ktexteditor/document.h>
#include <ktexteditor/view.h>
#include <kdebug.h>
#include <kedittoolbar.h>
#include <kencodingfiledialog.h>
#include <kiconloader.h>
#include <kshortcutsdialog.h>
#include <klibloader.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kparts/componentfactory.h>
#include <ksqueezedtextlabel.h>
#include <kstatusbar.h>
#include <kstandardaction.h>
#include <kmimetypetrader.h>
#include <kservicetypetrader.h>
#include <ktoggleaction.h>
// #include <kuserprofile.h>
#include <kactioncollection.h>
#include "kompareinterface.h"
#include "kompareurldialog.h"
#define ID_N_OF_N_DIFFERENCES 1
#define ID_N_OF_N_FILES 2
#define ID_GENERAL 3
KompareShell::KompareShell()
: KParts::MainWindow( ),
m_textViewPart( 0 ),
m_textViewWidget( 0 )
{
if ( !initialGeometrySet() )
resize( 800, 480 );
// set the shell's ui resource file
setXMLFile("kompareui.rc");
// then, setup our actions
setupActions();
setupStatusBar();
m_viewPart = KMimeTypeTrader::createInstanceFromQuery<KParts::ReadWritePart>("text/x-patch", "Kompare/ViewPart", this);
if ( m_viewPart )
{
setCentralWidget( m_viewPart->widget() );
// and integrate the part's GUI with the shell's
createGUI(m_viewPart);
}
else
{
// if we couldn't load our Part, we exit since the Shell by
// itself can't do anything useful
KMessageBox::error(this, i18n( "Could not load our KompareViewPart." ) );
exit(2);
}
m_navTreeDock = new QDockWidget( i18n( "Navigation" ), this );
m_navTreeDock->setObjectName( "Navigation" );
// This part is implemented in KompareNavTreePart
m_navTreePart = KServiceTypeTrader::createInstanceFromQuery<KParts::ReadOnlyPart>
("KParts/ReadOnlyPart", "'Kompare/NavigationPart' in ServiceTypes", m_navTreeDock);
if ( m_navTreePart )
{
m_navTreeDock->setWidget( m_navTreePart->widget() );
addDockWidget( Qt::TopDockWidgetArea, m_navTreeDock );
// m_navTreeDock->manualDock( m_mainViewDock, KDockWidget::DockTop, 20 );
}
else
{
// if we couldn't load our Part, we exit since the Shell by
// itself can't do anything useful
KMessageBox::error(this, i18n( "Could not load our KompareNavigationPart." ) );
exit(4);
}
// Hook up the inter part communication
connect( m_viewPart, SIGNAL( modelsChanged(const Diff2::DiffModelList*) ),
m_navTreePart, SLOT( slotModelsChanged( const Diff2::DiffModelList*) ) );
connect( m_viewPart, SIGNAL( kompareInfo(Kompare::Info*) ),
m_navTreePart, SLOT( slotKompareInfo(Kompare::Info*) ) );
connect( m_navTreePart, SIGNAL( selectionChanged(const Diff2::DiffModel*, const Diff2::Difference*) ),
m_viewPart, SIGNAL( selectionChanged(const Diff2::DiffModel*, const Diff2::Difference*) ) );
connect( m_viewPart, SIGNAL( setSelection(const Diff2::DiffModel*, const Diff2::Difference*) ),
m_navTreePart, SLOT( slotSetSelection(const Diff2::DiffModel*, const Diff2::Difference*) ) );
connect( m_navTreePart, SIGNAL( selectionChanged(const Diff2::Difference*) ),
m_viewPart, SIGNAL( selectionChanged(const Diff2::Difference*) ) );
connect( m_viewPart, SIGNAL( setSelection(const Diff2::Difference*) ),
m_navTreePart, SLOT( slotSetSelection(const Diff2::Difference*) ) );
// This is the interpart interface, it is signal and slot based so no "real" nterface here
// All you have to do is connect the parts from your application.
// These just point to the method with the same name in the KompareModelList or get called
// from the method with the same name in KompareModelList.
// There is currently no applying possible from the navtreepart to the viewpart
connect( m_viewPart, SIGNAL(applyDifference(bool)),
m_navTreePart, SLOT(slotApplyDifference(bool)) );
connect( m_viewPart, SIGNAL(applyAllDifferences(bool)),
m_navTreePart, SLOT(slotApplyAllDifferences(bool)) );
connect( m_viewPart, SIGNAL(applyDifference(const Diff2::Difference*, bool)),
m_navTreePart, SLOT(slotApplyDifference(const Diff2::Difference*, bool)) );
// Hook up the KomparePart -> KompareShell communication
connect( m_viewPart, SIGNAL( setStatusBarModelInfo( int, int, int, int, int ) ),
this, SLOT( slotUpdateStatusBar( int, int, int, int, int ) ) );
connect( m_viewPart, SIGNAL( setStatusBarText(const QString&) ),
this, SLOT( slotSetStatusBarText(const QString&) ) );
connect( m_viewPart, SIGNAL(diffString(const QString&)),
this, SLOT(slotSetDiffString(const QString&)) );
// Read basic main-view settings, and set to autosave
setAutoSaveSettings( "General Options" );
}
KompareShell::~KompareShell()
{
}
bool KompareShell::queryClose()
{
bool rv = m_viewPart->queryClose();
if ( rv )
KGlobal::deref();
return rv;
}
void KompareShell::openDiff(const KUrl& url)
{
kDebug(8102) << "Url = " << url.prettyUrl() << endl;
m_diffURL = url;
viewPart()->openDiff( url );
}
void KompareShell::openStdin()
{
kDebug(8102) << "Using stdin to read the diff" << endl;
QFile file;
file.open( stdin, QIODevice::ReadOnly );
QTextStream stream( &file );
QString diff = stream.readAll();
file.close();
viewPart()->openDiff( diff );
}
void KompareShell::compare(const KUrl& source,const KUrl& destination )
{
m_sourceURL = source;
m_destinationURL = destination;
viewPart()->compare( source, destination );
}
void KompareShell::blend( const KUrl& url1, const KUrl& diff )
{
m_sourceURL = url1;
m_destinationURL = diff;
viewPart()->openDirAndDiff( url1, diff );
}
void KompareShell::setupActions()
{
KAction *a;
a = actionCollection()->addAction(KStandardAction::Open, this, SLOT(slotFileOpen()));
a->setText( i18n( "&Open Diff..." ) );
a = actionCollection()->addAction("file_compare_files", this, SLOT(slotFileCompareFiles()));
a->setIcon(KIcon("document-open"));
a->setText(i18n("&Compare Files..."));
a->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_C));
a = actionCollection()->addAction("file_blend_url", this, SLOT(slotFileBlendURLAndDiff()));
a->setText(i18n("&Blend URL with Diff..."));
a->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_B));
actionCollection()->addAction(KStandardAction::Quit, this, SLOT( slotFileClose() ));
createStandardStatusBarAction();
setStandardToolBarMenuEnabled(true);
m_showTextView = new KToggleAction(i18n("Show T&ext View"), this);
// needs a KGuiItem, also the doc says explicitly not to do this
// m_showTextView->setCheckedState(i18n("Hide T&ext View"));
actionCollection()->addAction("options_show_text_view", m_showTextView);
connect(m_showTextView, SIGNAL(triggered(bool)), SLOT(slotShowTextView()));
KStandardAction::keyBindings(this, SLOT(optionsConfigureKeys()), actionCollection());
KStandardAction::configureToolbars(this, SLOT(optionsConfigureToolbars()), actionCollection());
}
void KompareShell::setupStatusBar()
{
// Made these entries permanent so they will appear on the right side
statusBar()->insertPermanentItem( i18n(" 0 of 0 differences "), ID_N_OF_N_DIFFERENCES, 0);
statusBar()->insertPermanentItem( i18n(" 0 of 0 files "), ID_N_OF_N_FILES, 0);
m_generalLabel = new KSqueezedTextLabel( "", 0 );
statusBar()->addWidget( m_generalLabel, 1 );
m_generalLabel->setAlignment( Qt::AlignLeft );
}
void KompareShell::slotUpdateStatusBar( int modelIndex, int differenceIndex, int modelCount, int differenceCount, int appliedCount )
{
kDebug(8102) << "KompareShell::updateStatusBar()" << endl;
QString fileStr;
QString diffStr;
if ( modelIndex >= 0 )
fileStr = i18np( " %2 of %1 file ", " %2 of %1 files ", modelCount, modelIndex + 1 );
else
fileStr = i18np( " %1 file ", " %1 files ", modelCount );
if ( differenceIndex >= 0 )
diffStr = i18np( " %2 of %1 difference, %3 applied ", " %2 of %1 differences, %3 applied ", differenceCount ,
differenceIndex + 1, appliedCount );
else
diffStr = i18np( " %1 difference ", " %1 differences ", differenceCount );
statusBar()->changeItem( fileStr, ID_N_OF_N_FILES );
statusBar()->changeItem( diffStr, ID_N_OF_N_DIFFERENCES );
}
void KompareShell::slotSetStatusBarText( const QString& text )
{
m_generalLabel->setText( text );
}
void KompareShell::saveProperties(KConfigGroup &config)
{
// The 'config' object points to the session managed
// config file. Anything you write here will be available
// later when this app is restored
if ( m_mode == Kompare::ComparingFiles )
{
config.writeEntry( "Mode", "ComparingFiles" );
config.writePathEntry( "SourceUrl", m_sourceURL.url() );
config.writePathEntry( "DestinationUrl", m_destinationURL.url() );
}
else if ( m_mode == Kompare::ShowingDiff )
{
config.writeEntry( "Mode", "ShowingDiff" );
config.writePathEntry( "DiffUrl", m_diffURL.url() );
}
viewPart()->saveProperties( config.config() );
}
void KompareShell::readProperties(const KConfigGroup &config)
{
// The 'config' object points to the session managed
// config file. This function is automatically called whenever
// the app is being restored. Read in here whatever you wrote
// in 'saveProperties'
QString mode = config.readEntry( "Mode", "ComparingFiles" );
if ( mode == "ComparingFiles" )
{
m_mode = Kompare::ComparingFiles;
m_sourceURL = config.readPathEntry( "SourceUrl", "" );
m_destinationURL = config.readPathEntry( "DestinationFile", "" );
viewPart()->readProperties( const_cast<KConfig *>(config.config()) );
viewPart()->compareFiles( m_sourceURL, m_destinationURL );
}
else if ( mode == "ShowingDiff" )
{
m_mode = Kompare::ShowingDiff;
m_diffURL = config.readPathEntry( "DiffUrl", "" );
viewPart()->readProperties( const_cast<KConfig *>(config.config()) );
m_viewPart->openUrl( m_diffURL );
}
else
{ // just in case something weird has happened, don't restore the diff then
// Bruggie: or when some idiot like me changes the possible values for mode
// IOW, a nice candidate for a kconf_update thingy :)
viewPart()->readProperties( const_cast<KConfig *>(config.config()) );
}
}
void KompareShell::slotFileOpen()
{
// FIXME: use different filedialog which gets encoding
KUrl url = KFileDialog::getOpenUrl( KUrl(), "text/x-patch", this );
if( !url.isEmpty() ) {
KompareShell* shell = new KompareShell();
KGlobal::ref();
shell->show();
shell->openDiff( url );
}
}
void KompareShell::slotFileBlendURLAndDiff()
{
KompareURLDialog dialog( this );
dialog.setCaption( i18n( "Blend File/Folder with diff Output" ) );
dialog.setFirstGroupBoxTitle( i18n( "File/Folder" ) );
dialog.setSecondGroupBoxTitle( i18n( "Diff Output" ) );
KGuiItem blendGuiItem( i18n( "Blend" ), QString(), i18n( "Blend this file or folder with the diff output" ), i18n( "If you have entered a file or folder name and a file that contains diff output in the fields in this dialog then this button will be enabled and pressing it will open kompare's main view where the output of the entered file or files from the folder are mixed with the diff output so you can then apply the difference(s) to a file or to the files. " ) );
dialog.setButtonGuiItem( KDialog::Ok, blendGuiItem );
dialog.setGroup( "Recent Blend Files" );
dialog.setFirstURLRequesterMode( KFile::File|KFile::Directory|KFile::ExistingOnly );
// diff output can not be a directory
dialog.setSecondURLRequesterMode( KFile::File|KFile::ExistingOnly );
if ( dialog.exec() == QDialog::Accepted )
{
m_sourceURL = dialog.getFirstURL();
m_destinationURL = dialog.getSecondURL();
// Leak???
KompareShell* shell = new KompareShell();
KGlobal::ref();
shell->show();
shell->viewPart()->setEncoding( dialog.encoding() );
shell->blend( m_sourceURL, m_destinationURL );
}
}
void KompareShell::slotFileCompareFiles()
{
KompareURLDialog dialog( this );
dialog.setCaption( i18n( "Compare Files or Folders" ) );
dialog.setFirstGroupBoxTitle( i18n( "Source" ) );
dialog.setSecondGroupBoxTitle( i18n( "Destination" ) );
KGuiItem compareGuiItem( i18n( "Compare" ), QString(), i18n( "Compare these files or folders" ), i18n( "If you have entered 2 filenames or 2 folders in the fields in this dialog then this button will be enabled and pressing it will start a comparison of the entered files or folders. " ) );
dialog.setButtonGuiItem( KDialog::Ok, compareGuiItem );
dialog.setGroup( "Recent Compare Files" );
dialog.setFirstURLRequesterMode( KFile::File|KFile::Directory|KFile::ExistingOnly );
dialog.setSecondURLRequesterMode( KFile::File|KFile::Directory|KFile::ExistingOnly );
if ( dialog.exec() == QDialog::Accepted )
{
m_sourceURL = dialog.getFirstURL();
m_destinationURL = dialog.getSecondURL();
KompareShell* shell = new KompareShell();
KGlobal::ref();
shell->show();
kDebug(8102) << "The encoding is: " << dialog.encoding() << endl;
shell->viewPart()->setEncoding( dialog.encoding() );
shell->compare( m_sourceURL, m_destinationURL );
}
}
void KompareShell::slotFileClose()
{
if ( m_viewPart->queryClose() )
{
KGlobal::deref();
}
}
void KompareShell::slotShowTextView()
{
if ( !m_textViewWidget )
{
QString error;
// FIXME: proper error checking
m_textViewWidget = new QDockWidget( i18n( "Text View" ), this );
m_textViewWidget->setObjectName( "Text View" );
// m_textViewWidget = createDockWidget( i18n("Text View"), SmallIcon( "text-x-generic") );
m_textViewPart = KServiceTypeTrader::createInstanceFromQuery<KTextEditor::Document>(
QString::fromLatin1("KTextEditor/Document"),
this, this, QString(), QVariantList(), &error );
if ( m_textViewPart )
{
m_textView = qobject_cast<KTextEditor::View*>( m_textViewPart->createView( this ) );
m_textViewWidget->setWidget( static_cast<QWidget*>(m_textView) );
m_textViewPart->setHighlightingMode( "Diff" );
m_textViewPart->setText( m_diffString );
}
m_textViewWidget->show();
connect( m_textViewWidget, SIGNAL(visibilityChanged(bool)), SLOT(slotVisibilityChanged(bool)) );
}
else if ( m_textViewWidget->isVisible() )
m_textViewWidget->hide();
else
m_textViewWidget->show();
addDockWidget( Qt::BottomDockWidgetArea, m_textViewWidget );
// m_textViewWidget->manualDock( m_mainViewDock, KDockWidget:: DockCenter );
}
void KompareShell::slotVisibilityChanged( bool visible )
{
m_showTextView->setChecked( visible );
}
void KompareShell::slotSetDiffString( const QString& diffString )
{
if ( m_textViewPart )
m_textViewPart->setText( diffString );
m_diffString = diffString;
}
void KompareShell::optionsConfigureKeys()
{
KShortcutsDialog dlg( KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsAllowed, this );
dlg.addCollection( actionCollection() );
if ( m_viewPart )
dlg.addCollection( m_viewPart->actionCollection() );
dlg.configure();
}
void KompareShell::optionsConfigureToolbars()
{
KConfigGroup group(KGlobal::config(), autoSaveGroup());
saveMainWindowSettings(group);
// use the standard toolbar editor
KEditToolBar dlg(factory());
connect(&dlg,SIGNAL(newToolbarConfig()),this,SLOT(newToolbarConfig()));
dlg.exec();
}
void KompareShell::newToolbarConfig()
{
KConfigGroup group(KGlobal::config(), autoSaveGroup());
applyMainWindowSettings(group);
}
KompareInterface* KompareShell::viewPart() const
{
return qobject_cast<KompareInterface *>(m_viewPart);
}
#include "kompare_shell.moc"

150
kompare/kompare_shell.h Normal file
View file

@ -0,0 +1,150 @@
/***************************************************************************
kompare_shell.h
----------------
begin : Sun Mar 4 2001
Copyright 2001-2003 Otto Bruggeman <otto.bruggeman@home.nl>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2007-2011 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#ifndef KOMPARESHELL_H
#define KOMPARESHELL_H
#include <kapplication.h>
#include <kparts/mainwindow.h>
#include <kompare.h>
class KompareInterface;
namespace KParts {
class ReadOnlyPart;
class ReadWritePart;
}
class KToggleAction;
class KSqueezedTextLabel;
class KomparePart;
class KompareNavTreePart;
namespace KTextEditor {
class Document;
class EditInterface;
class View;
}
/**
* This is the application "Shell". It has a menubar, toolbar, and
* statusbar but relies on the "Part" to do all the real work.
*
* Adapted the shell a bit so it now handles separate view and navigation parts
*
* @short Application Shell
* @author John Firebaugh <jfirebaugh@kde.org>
* @author Otto Bruggeman <bruggie@home.nl>
* @version 3.2.90
*/
class KompareShell : public KParts::MainWindow
{
Q_OBJECT
public:
/**
* Default Constructor
*/
KompareShell();
/**
* Default Destructor
*/
virtual ~KompareShell();
/**
* Use this method to load whatever file/URL you have
*/
void openDiff( const KUrl& url );
/**
* Use this method to load the diff from stdin
*/
void openStdin();
/**
* Use this method to compare 2 URLs (files or directories)
*/
void compare( const KUrl& source, const KUrl& destination );
/**
* Use this method to blend diff into url1 (file or directory)
*/
void blend( const KUrl& url1, const KUrl& diff );
public slots:
void slotUpdateStatusBar( int modelIndex, int differenceIndex, int modelCount, int differenceCount, int appliedCount );
KompareInterface* viewPart() const;
protected:
virtual bool queryClose();
/**
* This method is called when it is time for the app to save its
* properties for session management purposes.
*/
void saveProperties(KConfigGroup &);
/**
* This method is called when this app is restored. The KConfig
* object points to the session management config file that was saved
* with @ref saveProperties
*/
void readProperties(const KConfigGroup &);
private slots:
void slotSetStatusBarText( const QString& text );
void slotFileOpen();
void slotFileCompareFiles();
void slotFileBlendURLAndDiff();
void slotShowTextView();
void slotFileClose();
void optionsConfigureKeys();
void optionsConfigureToolbars();
void slotSetDiffString( const QString& diffString );
void newToolbarConfig();
void slotVisibilityChanged( bool visible );
private:
void setupAccel();
void setupActions();
void setupStatusBar();
private:
KUrl m_sourceURL;
KUrl m_destinationURL;
KUrl m_diffURL;
KParts::ReadWritePart* m_viewPart;
KParts::ReadOnlyPart* m_navTreePart;
KTextEditor::Document* m_textViewPart;
KTextEditor::View* m_textView;
// KTextEditor::EditInterface* m_textEditIface;
QDockWidget* m_textViewWidget;
QDockWidget* m_navTreeDock;
KToggleAction* m_showTextView;
enum Kompare::Mode m_mode;
// This is the statusbarwidget for displaying the general stuff
KSqueezedTextLabel* m_generalLabel;
QString m_diffString;
};
#endif // KOMPARE_H

View file

@ -0,0 +1,4 @@
[Desktop Entry]
Type=ServiceType
X-KDE-ServiceType=Kompare/NavigationPart
X-KDE-Derived=KParts/ReadOnlyPart

View file

@ -0,0 +1,22 @@
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../libdiff2 ${CMAKE_CURRENT_SOURCE_DIR}/../komparepart )
########### next target ###############
set(komparenavtreepart_PART_SRCS komparenavtreepart.cpp )
kde4_add_plugin(komparenavtreepart ${komparenavtreepart_PART_SRCS})
target_link_libraries(komparenavtreepart ${KDE4_KPARTS_LIBS} ${LIBKOMPAREDIFF2_LIBRARIES} )
install(TARGETS komparenavtreepart DESTINATION ${PLUGIN_INSTALL_DIR} )
########### install files ###############
install( FILES komparenavtreepart.desktop DESTINATION ${SERVICES_INSTALL_DIR} )

View file

@ -0,0 +1,780 @@
/***************************************************************************
KompareNavTreePart.cpp
----------------------
begin : Sun Mar 4 2001
Copyright 2001-2005,2009 Otto Bruggeman <bruggie@gmail.com>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2007-2011 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#include "komparenavtreepart.h"
#include <QtGui/QTreeWidgetItemIterator>
#include <kdebug.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kmimetype.h>
#include <kaboutdata.h>
#include <kcomponentdata.h>
#include <kpluginfactory.h>
#include "difference.h"
#include "diffmodel.h"
#include "diffmodellist.h"
#include "komparemodellist.h"
#define COL_SOURCE 0
#define COL_DESTINATION 1
#define COL_DIFFERENCE 2
using namespace Diff2;
KompareNavTreePart::KompareNavTreePart( QWidget* parentWidget, QObject* parent, const QVariantList& )
: KParts::ReadOnlyPart( parent ),
m_splitter( 0 ),
m_modelList( 0 ),
m_srcDirTree( 0 ),
m_destDirTree( 0 ),
m_fileList( 0 ),
m_changesList( 0 ),
m_srcRootItem( 0 ),
m_destRootItem( 0 ),
m_selectedModel( 0 ),
m_selectedDifference( 0 ),
m_source( "" ),
m_destination( "" ),
m_info( 0 )
{
m_splitter = new QSplitter( Qt::Horizontal, parentWidget );
setWidget( m_splitter );
m_srcDirTree = new QTreeWidget( m_splitter );
m_srcDirTree->setHeaderLabel( i18n("Source Folder") );
m_srcDirTree->setRootIsDecorated( false );
m_srcDirTree->setSortingEnabled( true );
m_srcDirTree->sortByColumn( 0, Qt::AscendingOrder );
m_destDirTree = new QTreeWidget( m_splitter );
m_destDirTree->setHeaderLabel( i18n("Destination Folder") );
m_destDirTree->setRootIsDecorated( false );
m_destDirTree->setSortingEnabled( true );
m_destDirTree->sortByColumn( 0, Qt::AscendingOrder );
m_fileList = new QTreeWidget( m_splitter );
m_fileList->setHeaderLabels( QStringList() << i18n("Source File") << i18n("Destination File") );
m_fileList->setAllColumnsShowFocus( true );
m_fileList->setRootIsDecorated( false );
m_fileList->setSortingEnabled( true );
m_fileList->sortByColumn( 0, Qt::AscendingOrder );
m_changesList = new QTreeWidget( m_splitter );
m_changesList->setHeaderLabels( QStringList() << i18n("Source Line") << i18n("Destination Line") << i18n("Difference") );
m_changesList->setAllColumnsShowFocus( true );
m_changesList->setRootIsDecorated( false );
m_changesList->setSortingEnabled( true );
m_changesList->sortByColumn( 0, Qt::AscendingOrder );
connect( m_srcDirTree, SIGNAL(currentItemChanged( QTreeWidgetItem*, QTreeWidgetItem* )),
this, SLOT(slotSrcDirTreeSelectionChanged( QTreeWidgetItem* )) );
connect( m_destDirTree, SIGNAL(currentItemChanged( QTreeWidgetItem*, QTreeWidgetItem* )),
this, SLOT(slotDestDirTreeSelectionChanged( QTreeWidgetItem* )) );
connect( m_fileList, SIGNAL(currentItemChanged( QTreeWidgetItem*, QTreeWidgetItem* )),
this, SLOT(slotFileListSelectionChanged( QTreeWidgetItem* )) );
connect( m_changesList, SIGNAL(currentItemChanged( QTreeWidgetItem*, QTreeWidgetItem* )),
this, SLOT(slotChangesListSelectionChanged( QTreeWidgetItem* )) );
}
KompareNavTreePart::~KompareNavTreePart()
{
m_modelList = 0;
m_selectedModel = 0;
m_selectedDifference = 0;
}
void KompareNavTreePart::slotKompareInfo( struct Kompare::Info* info )
{
m_info = info;
}
void KompareNavTreePart::slotModelsChanged( const DiffModelList* modelList )
{
kDebug(8105) << "Models (" << modelList << ") have changed... scanning the models... " << endl;
if ( modelList )
{
m_modelList = modelList;
m_srcDirTree->clear();
m_destDirTree->clear();
m_fileList->clear();
m_changesList->clear();
buildTreeInMemory();
}
else
{
m_modelList = modelList;
m_srcDirTree->clear();
m_destDirTree->clear();
m_fileList->clear();
m_changesList->clear();
}
}
void KompareNavTreePart::buildTreeInMemory()
{
kDebug(8105) << "BuildTreeInMemory called" << endl;
if ( m_modelList->count() == 0 )
{
kDebug(8105) << "No models... weird shit..." << endl;
return; // avoids a crash on clear()
}
if ( m_info == 0 )
{
kDebug(8105) << "No Info... weird shit..." << endl;
return;
}
QString srcBase;
QString destBase;
DiffModel* model;
model = m_modelList->first();
m_selectedModel = 0L;
switch ( m_info->mode )
{
case Kompare::ShowingDiff:
// BUG: 107489 No common root because it is a multi directory relative path diff
// We need to detect this and create a different rootitem / or so or should we always add this?
// Trouble we run into is that the directories do not start with a /
// so we have an unknown top root dir
// Thinking some more about it i guess it is best to use "" as base and simply show some string
// like Unknown filesystem path as root text but only in the case of dirs starting without a /
srcBase = model->sourcePath();
destBase = model->destinationPath();
// FIXME: these tests will not work on windows, we need something else
if ( srcBase[0] != '/' )
srcBase = "";
if ( destBase[0] != '/' )
destBase = "";
break;
case Kompare::ComparingFiles:
srcBase = model->sourcePath();
destBase = model->destinationPath();
break;
case Kompare::ComparingDirs:
srcBase = m_info->localSource;
if ( !srcBase.endsWith( '/' ) )
srcBase += '/';
destBase = m_info->localDestination;
if ( !destBase.endsWith( '/' ) )
destBase += '/';
break;
case Kompare::BlendingFile:
case Kompare::BlendingDir:
default:
kDebug(8105) << "Oops needs to implement this..." << endl;
}
// kDebug(8105) << "srcBase = " << srcBase << endl;
// kDebug(8105) << "destBase = " << destBase << endl;
m_srcRootItem = new KDirLVI( m_srcDirTree, srcBase );
m_destRootItem = new KDirLVI( m_destDirTree, destBase );
QString srcPath;
QString destPath;
// Create the tree from the models
DiffModelListConstIterator modelIt = m_modelList->begin();
DiffModelListConstIterator mEnd = m_modelList->end();
for ( ; modelIt != mEnd; ++modelIt )
{
model = *modelIt;
srcPath = model->sourcePath();
destPath = model->destinationPath();
kDebug(8105) << "srcPath = " << srcPath << endl;
kDebug(8105) << "destPath = " << destPath << endl;
m_srcRootItem->addModel( srcPath, model, &m_modelToSrcDirItemDict );
m_destRootItem->addModel( destPath, model, &m_modelToDestDirItemDict );
}
// m_srcDirTree->setSelected( m_srcDirTree->firstChild(), true );
}
void KompareNavTreePart::buildDirectoryTree()
{
// FIXME: afaict this can be deleted
// kDebug(8105) << "BuildDirTree called" << endl;
}
QString KompareNavTreePart::compareFromEndAndReturnSame(
const QString& string1,
const QString& string2 )
{
QString result;
int srcLen = string1.length();
int destLen = string2.length();
while ( srcLen != 0 && destLen != 0 )
{
if ( string1[--srcLen] == string2[--destLen] )
result.prepend( string1[srcLen] );
else
break;
}
if ( srcLen != 0 && destLen != 0 && result.startsWith( '/' ) )
result = result.remove( 0, 1 ); // strip leading /, we need it later
return result;
}
void KompareNavTreePart::slotSetSelection( const DiffModel* model, const Difference* diff )
{
kDebug(8105) << "KompareNavTreePart::slotSetSelection model = " << model << ", diff = " << diff << endl;
if ( model == m_selectedModel )
{
// model is the same, so no need to update that...
if ( diff != m_selectedDifference )
{
m_selectedDifference = diff;
setSelectedDifference( diff );
}
return;
}
// model is different so we need to find the right dirs, file and changeitems to select
// if m_selectedModel == NULL then everything needs to be done as well
if ( !m_selectedModel || model->sourcePath() != m_selectedModel->sourcePath() )
{ // dirs are different, so we need to update the dirviews as well
m_selectedModel = model;
m_selectedDifference = diff;
setSelectedDir( model );
setSelectedFile( model );
setSelectedDifference( diff );
return;
}
if ( !m_selectedModel || model->sourceFile() != m_selectedModel->sourceFile() )
{
m_selectedModel = model;
setSelectedFile( model );
m_selectedDifference = diff;
setSelectedDifference( diff );
}
}
void KompareNavTreePart::setSelectedDir( const DiffModel* model )
{
KDirLVI* currentDir;
currentDir = m_modelToSrcDirItemDict[ model ];
kDebug(8105) << "Manually setting selection in srcdirtree with currentDir = " << currentDir << endl;
m_srcDirTree->blockSignals( true );
m_srcDirTree->setCurrentItem( currentDir );
m_srcDirTree->scrollToItem( currentDir );
m_srcDirTree->blockSignals( false );
currentDir = m_modelToDestDirItemDict[ model ];
kDebug(8105) << "Manually setting selection in destdirtree with currentDir = " << currentDir << endl;
m_destDirTree->blockSignals( true );
m_destDirTree->setCurrentItem( currentDir );
m_destDirTree->scrollToItem( currentDir );
m_destDirTree->blockSignals( false );
m_fileList->blockSignals( true );
currentDir->fillFileList( m_fileList, &m_modelToFileItemDict );
m_fileList->blockSignals( false );
}
void KompareNavTreePart::setSelectedFile( const DiffModel* model )
{
KFileLVI* currentFile;
currentFile = m_modelToFileItemDict[ model ];
kDebug(8105) << "Manually setting selection in filelist" << endl;
m_fileList->blockSignals( true );
m_fileList->setCurrentItem( currentFile );
m_fileList->scrollToItem( currentFile );
m_fileList->blockSignals( false );
m_changesList->blockSignals( true );
currentFile->fillChangesList( m_changesList, &m_diffToChangeItemDict );
m_changesList->blockSignals( false );
}
void KompareNavTreePart::setSelectedDifference( const Difference* diff )
{
KChangeLVI* currentDiff;
currentDiff = m_diffToChangeItemDict[ diff ];
kDebug(8105) << "Manually setting selection in changeslist to " << currentDiff << endl;
m_changesList->blockSignals( true );
m_changesList->setCurrentItem( currentDiff );
m_changesList->scrollToItem( currentDiff );
m_changesList->blockSignals( false );
}
void KompareNavTreePart::slotSetSelection( const Difference* diff )
{
// kDebug(8105) << "Scotty i need more power !!" << endl;
if ( m_selectedDifference != diff )
{
// kDebug(8105) << "But sir, i am giving you all she's got" << endl;
m_selectedDifference = diff;
setSelectedDifference( diff );
}
}
void KompareNavTreePart::slotSrcDirTreeSelectionChanged( QTreeWidgetItem* item )
{
if (!item)
return;
kDebug(8105) << "Sent by the sourceDirectoryTree with item = " << item << endl;
m_srcDirTree->scrollToItem( item );
KDirLVI* dir = static_cast<KDirLVI*>(item);
// order the dest tree view to set its selected item to the same as here
QString path;
// We start with an empty path and after the call path contains the full path
path = dir->fullPath( path );
KDirLVI* selItem = m_destRootItem->setSelected( path );
m_destDirTree->blockSignals( true );
m_destDirTree->setCurrentItem( selItem );
m_destDirTree->scrollToItem( selItem );
m_destDirTree->blockSignals( false );
// fill the changes list
dir->fillFileList( m_fileList, &m_modelToFileItemDict );
}
void KompareNavTreePart::slotDestDirTreeSelectionChanged( QTreeWidgetItem* item )
{
if (!item)
return;
kDebug(8105) << "Sent by the destinationDirectoryTree with item = " << item << endl;
m_destDirTree->scrollToItem( item );
KDirLVI* dir = static_cast<KDirLVI*>(item);
// order the src tree view to set its selected item to the same as here
QString path;
// We start with an empty path and after the call path contains the full path
path = dir->fullPath( path );
KDirLVI* selItem = m_srcRootItem->setSelected( path );
m_srcDirTree->blockSignals( true );
m_srcDirTree->setCurrentItem( selItem );
m_srcDirTree->scrollToItem( selItem );
m_srcDirTree->blockSignals( false );
// fill the changes list
dir->fillFileList( m_fileList, &m_modelToFileItemDict );
}
void KompareNavTreePart::slotFileListSelectionChanged( QTreeWidgetItem* item )
{
if (!item)
return;
kDebug(8105) << "Sent by the fileList with item = " << item << endl;
KFileLVI* file = static_cast<KFileLVI*>(item);
m_selectedModel = file->model();
m_changesList->blockSignals( true );
file->fillChangesList( m_changesList, &m_diffToChangeItemDict );
m_changesList->blockSignals( false );
if ( m_changesList->currentItem() )
{
// FIXME: This is ugly...
m_selectedDifference = (static_cast<KChangeLVI*>(m_changesList->currentItem()))->difference();
}
emit selectionChanged( m_selectedModel, m_selectedDifference );
}
void KompareNavTreePart::slotChangesListSelectionChanged( QTreeWidgetItem* item )
{
if (!item)
return;
kDebug(8105) << "Sent by the changesList" << endl;
KChangeLVI* change = static_cast<KChangeLVI*>(item);
m_selectedDifference = change->difference();
emit selectionChanged( m_selectedDifference );
}
void KompareNavTreePart::slotApplyDifference( bool /*apply*/ )
{
KChangeLVI* clvi = m_diffToChangeItemDict[m_selectedDifference];
if ( clvi )
clvi->setDifferenceText();
}
void KompareNavTreePart::slotApplyAllDifferences( bool /*apply*/ )
{
QHash<const Diff2::Difference*, KChangeLVI*>::ConstIterator it = m_diffToChangeItemDict.constBegin();
QHash<const Diff2::Difference*, KChangeLVI*>::ConstIterator end = m_diffToChangeItemDict.constEnd();
kDebug(8105) << "m_diffToChangeItemDict.count() = " << m_diffToChangeItemDict.count() << endl;
for ( ; it != end ; ++it )
{
it.value()->setDifferenceText();
}
}
void KompareNavTreePart::slotApplyDifference( const Difference* diff, bool /*apply*/ )
{
// this applies to the currently selected difference
KChangeLVI* clvi = m_diffToChangeItemDict[diff];
if ( clvi )
clvi->setDifferenceText();
}
void KChangeLVI::setDifferenceText()
{
QString text;
switch( m_difference->type() ) {
case Difference::Change:
// Shouldn't this simply be diff->sourceLineCount() ?
// because you change the _number of lines_ lines in source, not in dest
if( m_difference->applied() )
text = i18np( "Applied: Changes made to %1 line undone", "Applied: Changes made to %1 lines undone",
m_difference->sourceLineCount() );
else
text = i18np( "Changed %1 line", "Changed %1 lines",
m_difference->sourceLineCount() );
break;
case Difference::Insert:
if( m_difference->applied() )
text = i18np( "Applied: Insertion of %1 line undone", "Applied: Insertion of %1 lines undone",
m_difference->destinationLineCount() );
else
text = i18np( "Inserted %1 line", "Inserted %1 lines",
m_difference->destinationLineCount() );
break;
case Difference::Delete:
if( m_difference->applied() )
text = i18np( "Applied: Deletion of %1 line undone", "Applied: Deletion of %1 lines undone",
m_difference->sourceLineCount() );
else
text = i18np( "Deleted %1 line", "Deleted %1 lines",
m_difference->sourceLineCount() );
break;
default:
kDebug(8105) << "Unknown or Unchanged enum value when checking for diff->type() in KChangeLVI's constructor" << endl;
text = "";
}
setText( 2, text );
}
KChangeLVI::KChangeLVI( QTreeWidget* parent, Difference* diff ) : QTreeWidgetItem( parent )
{
m_difference = diff;
setText( 0, QString::number( diff->sourceLineNumber() ) );
setText( 1, QString::number( diff->destinationLineNumber() ) );
setDifferenceText();
}
bool KChangeLVI::operator<( const QTreeWidgetItem& item ) const
{
int column = treeWidget()->sortColumn();
QString text1 = text(column);
QString text2 = item.text(column);
// Compare the numbers.
if (column < 2 && text1.length() != text2.length())
return text1.length() < text2.length();
return text1 < text2;
}
KChangeLVI::~KChangeLVI()
{
}
KFileLVI::KFileLVI( QTreeWidget* parent, DiffModel* model ) : QTreeWidgetItem( parent )
{
m_model = model;
QString src = model->sourceFile();
QString dst = model->destinationFile();
setText( 0, src );
setText( 1, dst );
setIcon( 0, SmallIcon( getIcon( src ) ) );
setIcon( 1, SmallIcon( getIcon( dst ) ) );
}
bool KFileLVI::hasExtension(const QString& extensions, const QString& fileName)
{
QStringList extList = extensions.split(' ');
foreach (const QString &ext, extList) {
if ( fileName.endsWith(ext, Qt::CaseInsensitive) ) {
return true;
}
}
return false;
}
const QString KFileLVI::getIcon(const QString& fileName)
{
// C++, C
if ( hasExtension( ".h .hpp", fileName ) ) {
return "text-x-c++hdr";
}
if ( hasExtension( ".cpp", fileName ) ) {
return "text-x-c++src";
}
if ( hasExtension( ".c", fileName ) ) {
return "text-x-csrc";
}
// Python
if ( hasExtension( ".py .pyw", fileName ) ) {
return "text-x-python";
}
// C#
if ( hasExtension( ".cs", fileName ) ) {
return "text-x-csharp";
}
// Objective-C
if ( hasExtension( ".m", fileName ) ) {
return "text-x-objcsrc";
}
// Java
if ( hasExtension( ".java", fileName ) ) {
return "text-x-java";
}
// Script
if ( hasExtension( ".sh", fileName ) ) {
return "text-x-script";
}
// Makefile
if ( hasExtension( ".cmake Makefile", fileName ) ) {
return "text-x-makefile";
}
// Ada
if ( hasExtension( ".ada .ads .adb", fileName ) ) {
return "text-x-adasrc";
}
// Pascal
if ( hasExtension( ".pas", fileName ) ) {
return "text-x-pascal";
}
// Patch
if ( hasExtension( ".diff", fileName ) ) {
return "text-x-patch";
}
// Tcl
if ( hasExtension( ".tcl", fileName ) ) {
return "text-x-tcl";
}
// Text
if ( hasExtension( ".txt", fileName ) ) {
return "text-plain";
}
// Xml
if ( hasExtension( ".xml", fileName ) ) {
return "text-xml";
}
// unknown or no file extension
return "text-plain";
}
void KFileLVI::fillChangesList( QTreeWidget* changesList, QHash<const Diff2::Difference*, KChangeLVI*>* diffToChangeItemDict )
{
changesList->clear();
diffToChangeItemDict->clear();
DifferenceListConstIterator diffIt = m_model->differences()->constBegin();
DifferenceListConstIterator dEnd = m_model->differences()->constEnd();
for ( ; diffIt != dEnd; ++diffIt )
{
KChangeLVI* change = new KChangeLVI( changesList, *diffIt );
diffToChangeItemDict->insert( *diffIt, change );
}
changesList->setCurrentItem( changesList->topLevelItem( 0 ) );
}
KFileLVI::~KFileLVI()
{
}
KDirLVI::KDirLVI( QTreeWidget* parent, QString& dir ) : QTreeWidgetItem( parent )
{
// kDebug(8105) << "KDirLVI (QTreeWidget) constructor called with dir = " << dir << endl;
m_rootItem = true;
m_dirName = dir;
setIcon( 0, SmallIcon( "folder" ) );
setExpanded( true );
if ( m_dirName.isEmpty() )
setText( 0, i18n( "Unknown" ) );
else
setText( 0, m_dirName );
}
KDirLVI::KDirLVI( KDirLVI* parent, QString& dir ) : QTreeWidgetItem( parent )
{
// kDebug(8105) << "KDirLVI (KDirLVI) constructor called with dir = " << dir << endl;
m_rootItem = false;
m_dirName = dir;
setIcon( 0, SmallIcon( "folder" ) );
setExpanded( true );
setText( 0, m_dirName );
}
// addModel always removes it own path from the beginning
void KDirLVI::addModel( QString& path, DiffModel* model, QHash<const Diff2::DiffModel*, KDirLVI*>* modelToDirItemDict )
{
// kDebug(8105) << "KDirLVI::addModel called with path = " << path << " from KDirLVI with m_dirName = " << m_dirName << endl;
if ( !m_dirName.isEmpty() )
{
if ( path.indexOf( m_dirName ) > -1 )
path = path.remove( path.indexOf( m_dirName ), m_dirName.length() );
}
// kDebug(8105) << "Path after removal of own dir (\"" << m_dirName << "\") = " << path << endl;
if ( path.isEmpty() ) {
m_modelList.append( model );
modelToDirItemDict->insert( model, this );
return;
}
KDirLVI* child;
QString dir = path.mid( 0, path.indexOf( "/", 0 ) + 1 );
child = findChild( dir );
if ( !child )
{
// does not exist yet so make it
// kDebug(8105) << "KDirLVI::addModel creating new KDirLVI because not found" << endl;
child = new KDirLVI( this, dir );
}
child->addModel( path, model, modelToDirItemDict );
}
KDirLVI* KDirLVI::findChild( QString dir )
{
// kDebug(8105) << "KDirLVI::findChild called with dir = " << dir << endl;
KDirLVI* child;
if ( ( child = static_cast<KDirLVI*>(this->child(0)) ) != 0L )
{ // has children, check if dir already exists, if so addModel
QTreeWidgetItemIterator it(child);
while (*it) {
child = static_cast<KDirLVI*>(*it);
if ( dir == child->dirName() )
return child;
++it;
}
}
return 0L;
}
void KDirLVI::fillFileList( QTreeWidget* fileList, QHash<const Diff2::DiffModel*, KFileLVI*>* modelToFileItemDict )
{
fileList->clear();
DiffModelListIterator modelIt = m_modelList.begin();
DiffModelListIterator mEnd = m_modelList.end();
for ( ;modelIt != mEnd; ++modelIt )
{
KFileLVI* file = new KFileLVI( fileList, *modelIt );
modelToFileItemDict->insert( *modelIt, file );
}
fileList->setCurrentItem( fileList->topLevelItem( 0 ) );
}
QString KDirLVI::fullPath( QString& path )
{
// if ( !path.isEmpty() )
// kDebug(8105) << "KDirLVI::fullPath called with path = " << path << endl;
// else
// kDebug(8105) << "KDirLVI::fullPath called with empty path..." << endl;
if ( m_rootItem ) // don't bother adding rootItem's dir...
return path;
path = path.prepend( m_dirName );
KDirLVI* lviParent = dynamic_cast<KDirLVI*>( parent() );
if ( lviParent )
{
path = lviParent->fullPath( path );
}
return path;
}
KDirLVI* KDirLVI::setSelected( QString dir )
{
// kDebug(8105) << "KDirLVI::setSelected called with dir = " << dir << endl;
// root item's dirName is never taken into account... remember that
if ( !m_rootItem )
{
dir = dir.remove( 0, m_dirName.length() );
}
if ( dir.isEmpty() )
{
return this;
}
KDirLVI* child = static_cast<KDirLVI*>(this->child(0));
if ( !child )
return 0L;
QTreeWidgetItemIterator it(child);
while (*it) {
child = static_cast<KDirLVI*>(*it);
if ( dir.startsWith( child->dirName() ) )
return child->setSelected( dir );
++it;
}
return 0L;
}
KDirLVI::~KDirLVI()
{
m_modelList.clear();
}
static KAboutData aboutData()
{
KAboutData about("komparenavtreepart", 0, ki18n("KompareNavTreePart"), "1.2");
about.addAuthor(ki18n("John Firebaugh"), ki18n("Author"), "jfirebaugh@kde.org");
about.addAuthor(ki18n("Otto Bruggeman"), ki18n("Author"), "bruggie@gmail.com" );
return about;
}
K_PLUGIN_FACTORY(KompareNavTreePartFactory,
registerPlugin<KompareNavTreePart>();
)
K_EXPORT_PLUGIN( KompareNavTreePartFactory(aboutData()) )
#include "komparenavtreepart.moc"

View file

@ -0,0 +1,67 @@
[Desktop Entry]
Name=KompareNavTreePart
Name[ast]=KompareNavTreePart
Name[bg]=KompareNavTreePart
Name[br]=KompareNavTreePart
Name[bs]=KompareNavTreePart
Name[ca]=KompareNavTreePart
Name[ca@valencia]=KompareNavTreePart
Name[cs]=KompareNavTreePart
Name[cy]=KompareNavTreePart
Name[da]=KompareNavTreePart
Name[de]=KompareNavTreePart
Name[el]=KompareNavTreePart
Name[en_GB]=KompareNavTreePart
Name[es]=KompareNavTreePart
Name[et]=KompareNavTreePart
Name[eu]=KompareNavTreePart
Name[fi]=KompareNavTreePart
Name[fr]=Composant de KompareNavTree
Name[ga]=KompareNavTreePart
Name[gl]=KompareNavTreePart
Name[he]=KompareNavTreePart
Name[hr]=KompareNavTreePart
Name[hu]=KompareNavTreePart
Name[is]=KompareNavTreePart
Name[it]=KompareNavTreePart
Name[ja]=KompareNavTreePart
Name[kk]=KompareNavTreePart
Name[km]=KompareNavTreePart
Name[ko]=KompareNavTreePart
Name[lt]=KompareNavTreePart
Name[lv]=KompareNavTreePart
Name[mr]=---
Name[ms]=KompareNavTreePart
Name[nb]=KompareNavTreePart
Name[nds]=KompareNavTreePart
Name[ne]=KompareNavTreePart
Name[nl]=KompareNavTreePart
Name[nn]=KompareNavTreePart
Name[pa]=KompareNavTreePart
Name[pl]=Komponent drzewa nawigacyjnego Kompare
Name[pt]=KompareNavTreePart
Name[pt_BR]=KompareNavTreePart
Name[ro]=KompareNavTreePart
Name[ru]=KompareNavTreePart
Name[sk]=KompareNavTreePart
Name[sl]=KompareNavTreePart
Name[sq]=KompareNavTreePart
Name[sr]=KompareNavTreePart
Name[sr@ijekavian]=KompareNavTreePart
Name[sr@ijekavianlatin]=KompareNavTreePart
Name[sr@latin]=KompareNavTreePart
Name[sv]=Kompare-navigeringsträdsdel
Name[ta]=
Name[tg]=KompareNavTreePart
Name[tr]=KompareNavTreePart
Name[ug]=KompareNavTreePart
Name[uk]=KompareNavTreePart
Name[xh]=KompareNavTreePart
Name[x-test]=xxKompareNavTreePartxx
Name[zh_CN]=KompareNavTreePart
Name[zh_TW]=KompareNavTreePart
MimeType=text/x-patch;
ServiceTypes=Kompare/NavigationPart
X-KDE-Library=komparenavtreepart
Type=Service
Icon=kompare

View file

@ -0,0 +1,169 @@
/***************************************************************************
komparenavtreepart.h
--------------------
begin : Mon Feb 26 2002
Copyright 2001-2004 Otto Bruggeman <otto.bruggeman@home.nl>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2007-2011 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#ifndef KOMPARENAVTREEPART_H
#define KOMPARENAVTREEPART_H
#include <QtCore/QHash>
#include <QtGui/QSplitter>
#include <QtGui/QTreeWidget>
#include <QtGui/QTreeWidgetItem>
#include <kparts/part.h>
#include <kompare.h>
#include <diffmodellist.h>
namespace Diff2 {
class DiffModel;
class Difference;
}
class KDirLVI;
class KFileLVI;
class KChangeLVI;
class KompareNavTreePart : public KParts::ReadOnlyPart
{
Q_OBJECT
public:
explicit KompareNavTreePart( QWidget* parentWidget, QObject* parent, const QVariantList& args );
virtual ~KompareNavTreePart();
public:
virtual bool openFile() { return false; };
public slots:
void slotSetSelection( const Diff2::DiffModel* model, const Diff2::Difference* diff );
void slotSetSelection( const Diff2::Difference* diff );
void slotModelsChanged( const Diff2::DiffModelList* modelList );
void slotKompareInfo( Kompare::Info* info );
signals:
void selectionChanged( const Diff2::DiffModel* model, const Diff2::Difference* diff );
void selectionChanged( const Diff2::Difference* diff );
private slots:
void slotSrcDirTreeSelectionChanged ( QTreeWidgetItem* item );
void slotDestDirTreeSelectionChanged( QTreeWidgetItem* item );
void slotFileListSelectionChanged ( QTreeWidgetItem* item );
void slotChangesListSelectionChanged( QTreeWidgetItem* item );
void slotApplyDifference( bool apply );
void slotApplyAllDifferences( bool apply );
void slotApplyDifference( const Diff2::Difference* diff, bool apply );
void buildTreeInMemory();
private:
void setSelectedDir( const Diff2::DiffModel* model );
void setSelectedFile( const Diff2::DiffModel* model );
void setSelectedDifference( const Diff2::Difference* diff );
void buildDirectoryTree();
QString compareFromEndAndReturnSame( const QString& string1, const QString& string2 );
void addDirToTreeView( enum Kompare::Target, const QString& filename );
QTreeWidgetItem* findDirInDirTree( const QTreeWidgetItem* parent, const QString& dir );
private:
QSplitter* m_splitter;
const Diff2::DiffModelList* m_modelList;
QHash<const Diff2::Difference*, KChangeLVI*> m_diffToChangeItemDict;
QHash<const Diff2::DiffModel*, KFileLVI*> m_modelToFileItemDict;
QHash<const Diff2::DiffModel*, KDirLVI*> m_modelToSrcDirItemDict;
QHash<const Diff2::DiffModel*, KDirLVI*> m_modelToDestDirItemDict;
QTreeWidget* m_srcDirTree;
QTreeWidget* m_destDirTree;
QTreeWidget* m_fileList;
QTreeWidget* m_changesList;
KDirLVI* m_srcRootItem;
KDirLVI* m_destRootItem;
const Diff2::DiffModel* m_selectedModel;
const Diff2::Difference* m_selectedDifference;
QString m_source;
QString m_destination;
struct Kompare::Info* m_info;
};
// These 3 classes are need to store the models into a tree so it is easier
// to extract the info we need for the navigation widgets
class KChangeLVI : public QTreeWidgetItem
{
public:
KChangeLVI( QTreeWidget* parent, Diff2::Difference* diff );
~KChangeLVI();
public:
Diff2::Difference* difference() { return m_difference; };
virtual bool operator<( const QTreeWidgetItem& item ) const;
void setDifferenceText();
private:
Diff2::Difference* m_difference;
};
class KFileLVI : public QTreeWidgetItem
{
public:
KFileLVI( QTreeWidget* parent, Diff2::DiffModel* model );
~KFileLVI();
public:
Diff2::DiffModel* model() { return m_model; };
void fillChangesList( QTreeWidget* changesList, QHash<const Diff2::Difference*, KChangeLVI*>* diffToChangeItemDict );
private:
bool hasExtension(const QString& extensions, const QString& fileName);
const QString getIcon(const QString& fileName);
private:
Diff2::DiffModel* m_model;
};
class KDirLVI : public QTreeWidgetItem
{
public:
KDirLVI( KDirLVI* parent, QString& dir );
KDirLVI( QTreeWidget* parent, QString& dir );
~KDirLVI();
public:
void addModel( QString& dir, Diff2::DiffModel* model, QHash<const Diff2::DiffModel*, KDirLVI*>* modelToDirItemDict );
QString& dirName() { return m_dirName; };
QString fullPath( QString& path );
KDirLVI* setSelected( QString dir );
void setSelected( bool selected ) { QTreeWidgetItem::setSelected( selected ); }
void fillFileList( QTreeWidget* fileList, QHash<const Diff2::DiffModel*, KFileLVI*>* modelToFileItemDict );
bool isRootItem() { return m_rootItem; };
private:
KDirLVI* findChild( QString dir );
private:
Diff2::DiffModelList m_modelList;
QString m_dirName;
bool m_rootItem;
};
#endif

View file

@ -0,0 +1,85 @@
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../libdialogpages ${CMAKE_CURRENT_SOURCE_DIR}/../interfaces )
########### next target ###############
set( komparepart_PART_SRCS
kompare_part.cpp
kompareconnectwidget.cpp
komparesplitter.cpp
komparelistview.cpp
kompareprefdlg.cpp
komparesaveoptionsbase.cpp
komparesaveoptionswidget.cpp
kompareview.cpp )
kde4_add_ui_files(komparepart_PART_SRCS komparesaveoptionsbase.ui )
kde4_add_plugin(komparepart ${komparepart_PART_SRCS})
target_link_libraries(komparepart ${KDE4_KPARTS_LIBS} komparedialogpages ${LIBKOMPAREDIFF2_LIBRARIES} kompareinterface )
install(TARGETS komparepart DESTINATION ${PLUGIN_INSTALL_DIR} )
########### install files ###############
install( FILES komparepart.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
install( FILES komparepartui.rc DESTINATION ${DATA_INSTALL_DIR}/kompare )
#original Makefile.am contents follow:
##########################################################################
## KPART SECTION
##########################################################################
#
#INCLUDES = \
# -I$(top_srcdir)/kompare/libdialogpages \
# -I$(top_srcdir)/kompare/interfaces \
# $(all_includes)
#
#noinst_HEADERS = \
# kompare_part.h \
# komparesplitter.h \
# kompareprefdlg.h \
# komparelistview.h \
# kompareconnectwidget.h \
# komparesaveoptionsbase.h \
# komparesaveoptionswidget.h \
# kompare_qsplitter.h
#
## let automoc handle all of the meta source files (moc)
#METASOURCES = AUTO
#
#kde_module_LTLIBRARIES = libkomparepart.la
#
## the Part's source, library search path, and link libraries
#libkomparepart_la_SOURCES = \
# kompare_part.cpp \
# kompareconnectwidget.cpp \
# komparesplitter.cpp \
# komparelistview.cpp \
# kompareprefdlg.cpp \
# komparesaveoptionsbase.ui \
# komparesaveoptionswidget.cpp
#
#libkomparepart_la_LDFLAGS = $(KDE_PLUGIN) $(all_libraries)
#libkomparepart_la_LIBADD = $(LIB_KPARTS) $(LIB_KFILE) \
# ../libdialogpages/libdialogpages.la \
# ../interfaces/libkompareinterface.la
#
## this is where the desktop file will go
#partdesktopdir = $(kde_servicesdir)
#partdesktop_DATA = komparepart.desktop
#
## this is where the part's XML-GUI resource file goes
#partrcdir = $(kde_datadir)/kompare
#partrc_DATA = komparepartui.rc
#

View file

@ -0,0 +1,956 @@
/***************************************************************************
kompare_part.cpp
----------------
begin : Sun Mar 4 2001
Copyright 2001-2005,2009 Otto Bruggeman <bruggie@gmail.com>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2004 Jeff Snyder <jeff@caffeinated.me.uk>
Copyright 2007-2011 Kevin Kofler <kevin.kofler@chello.at>
Copyright 2012 Jean-Nicolas Artaud <jeannicolasartaud@gmail.com>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#include "kompare_part.h"
#include <QtGui/QLayout>
#include <QtGui/QWidget>
#include <QPainter>
#include <QPrinter>
#include <QPrintDialog>
#include <QPrintPreviewDialog>
#include <kaboutdata.h>
#include <kaction.h>
#include <kactioncollection.h>
#include <kapplication.h>
#include <kcomponentdata.h>
#include <kdebug.h>
#include <kdeprintdialog.h>
#include <kfiledialog.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kstandardaction.h>
#include <kstandarddirs.h>
#include <kstandardshortcut.h>
#include <ktemporaryfile.h>
#include <ktempdir.h>
#include <kio/netaccess.h>
#include <kglobal.h>
#include "diffmodel.h"
#include "komparelistview.h"
#include "kompareconnectwidget.h"
#include "diffsettings.h"
#include "viewsettings.h"
#include "kompareprefdlg.h"
#include "komparesaveoptionswidget.h"
#include "komparesplitter.h"
#include "kompareview.h"
K_PLUGIN_FACTORY( KomparePartFactory, registerPlugin<KomparePart>(); )
K_EXPORT_PLUGIN( KomparePartFactory )
ViewSettings* KomparePart::m_viewSettings = 0L;
DiffSettings* KomparePart::m_diffSettings = 0L;
KomparePart::KomparePart( QWidget *parentWidget, QObject *parent, const QVariantList & /*args*/ ) :
KParts::ReadWritePart(parent),
m_tempDiff( 0 ),
m_info()
{
if( !m_viewSettings ) {
m_viewSettings = new ViewSettings( 0 );
}
if( !m_diffSettings ) {
m_diffSettings = new DiffSettings( 0 );
}
readProperties( KGlobal::config().data() );
m_view = new KompareView ( m_viewSettings, parentWidget );
setWidget( m_view );
m_splitter = m_view->splitter();
// This creates the "Model creator" and connects the signals and slots
m_modelList = new Diff2::KompareModelList( m_diffSettings, m_splitter, this, "komparemodellist" , KParts::ReadWritePart::isReadWrite());
Q_FOREACH(QAction* action, m_modelList->actionCollection()->actions())
{
actionCollection()->addAction(action->objectName(), action);
}
connect( m_modelList, SIGNAL(status( Kompare::Status )),
this, SLOT(slotSetStatus( Kompare::Status )) );
connect( m_modelList, SIGNAL(setStatusBarModelInfo( int, int, int, int, int )),
this, SIGNAL(setStatusBarModelInfo( int, int, int, int, int )) );
connect( m_modelList, SIGNAL(error( QString )),
this, SLOT(slotShowError( QString )) );
connect( m_modelList, SIGNAL(applyAllDifferences( bool )),
this, SLOT(updateActions()) );
connect( m_modelList, SIGNAL(applyDifference( bool )),
this, SLOT(updateActions()) );
connect( m_modelList, SIGNAL(applyAllDifferences( bool )),
this, SIGNAL(appliedChanged()) );
connect( m_modelList, SIGNAL(applyDifference( bool )),
this, SIGNAL(appliedChanged()) );
connect( m_modelList, SIGNAL(updateActions()), this, SLOT(updateActions()) );
// This is the stuff to connect the "interface" of the kompare part to the model inside
connect( m_modelList, SIGNAL(modelsChanged(const Diff2::DiffModelList*)),
this, SIGNAL(modelsChanged(const Diff2::DiffModelList*)) );
connect( m_modelList, SIGNAL(setSelection(const Diff2::DiffModel*, const Diff2::Difference*)),
this, SIGNAL(setSelection(const Diff2::DiffModel*, const Diff2::Difference*)) );
connect( this, SIGNAL(selectionChanged(const Diff2::DiffModel*, const Diff2::Difference*)),
m_modelList, SLOT(slotSelectionChanged(const Diff2::DiffModel*, const Diff2::Difference*)) );
connect( m_modelList, SIGNAL(setSelection(const Diff2::Difference*)),
this, SIGNAL(setSelection(const Diff2::Difference*)) );
connect( this, SIGNAL(selectionChanged(const Diff2::Difference*)),
m_modelList, SLOT(slotSelectionChanged(const Diff2::Difference*)) );
connect( m_modelList, SIGNAL(applyDifference(bool)),
this, SIGNAL(applyDifference(bool)) );
connect( m_modelList, SIGNAL(applyAllDifferences(bool)),
this, SIGNAL(applyAllDifferences(bool)) );
connect( m_modelList, SIGNAL(applyDifference(const Diff2::Difference*, bool)),
this, SIGNAL(applyDifference(const Diff2::Difference*, bool)) );
connect( m_modelList, SIGNAL(diffString(const QString&)),
this, SIGNAL(diffString(const QString&)) );
connect( this, SIGNAL(kompareInfo(Kompare::Info*)), m_modelList, SLOT(slotKompareInfo(Kompare::Info*)) );
// Here we connect the splitter to the modellist
connect( m_modelList, SIGNAL(setSelection(const Diff2::DiffModel*, const Diff2::Difference*)),
m_splitter, SLOT(slotSetSelection(const Diff2::DiffModel*, const Diff2::Difference*)) );
// connect( m_splitter, SIGNAL(selectionChanged(const Diff2::Difference*, const Diff2::Difference*)),
// m_modelList, SLOT(slotSelectionChanged(const Diff2::Difference*, const Diff2::Difference*)) );
connect( m_modelList, SIGNAL(setSelection(const Diff2::Difference*)),
m_splitter, SLOT(slotSetSelection(const Diff2::Difference*)) );
connect( m_splitter, SIGNAL(selectionChanged(const Diff2::Difference*)),
m_modelList, SLOT(slotSelectionChanged(const Diff2::Difference*)) );
connect( m_modelList, SIGNAL(applyDifference(bool)),
m_splitter, SLOT(slotApplyDifference(bool)) );
connect( m_modelList, SIGNAL(applyAllDifferences(bool)),
m_splitter, SLOT(slotApplyAllDifferences(bool)) );
connect( m_modelList, SIGNAL(applyDifference(const Diff2::Difference*, bool)),
m_splitter, SLOT(slotApplyDifference(const Diff2::Difference*, bool)) );
connect( this, SIGNAL(configChanged()), m_splitter, SIGNAL(configChanged()) );
setupActions();
// set our XML-UI resource file
setXMLFile( "komparepartui.rc" );
// we are read-write by default -> uhm what if we are opened by lets say konq in RO mode ?
// Then we should not be doing this...
setReadWrite( true );
// we are not modified since we haven't done anything yet
setModified( false );
}
KomparePart::~KomparePart()
{
// This is the only place allowed to call cleanUpTemporaryFiles
// because before there might still be a use for them (when swapping)
cleanUpTemporaryFiles();
}
void KomparePart::setupActions()
{
// create our actions
m_saveAll = actionCollection()->addAction("file_save_all", this, SLOT(saveAll()));
m_saveAll->setIcon(KIcon("document-save-all"));
m_saveAll->setText(i18n("Save &All"));
m_saveDiff = actionCollection()->addAction("file_save_diff", this, SLOT(saveDiff()));
m_saveDiff->setText(i18n("Save &Diff..."));
m_swap = actionCollection()->addAction("file_swap", this, SLOT(slotSwap()));
m_swap->setText(i18n("Swap Source with Destination"));
m_diffStats = actionCollection()->addAction("file_diffstats", this, SLOT(slotShowDiffstats()));
m_diffStats->setText(i18n("Show Statistics"));
m_diffRefresh = actionCollection()->addAction("file_refreshdiff", this, SLOT(slotRefreshDiff()));
m_diffRefresh->setIcon(KIcon("view-refresh"));
m_diffRefresh->setText(i18n("Refresh Diff"));
m_diffRefresh->setShortcut(KStandardShortcut::reload());
m_print = actionCollection()->addAction(KStandardAction::Print, this, SLOT( slotFilePrint() ));
m_printPreview = actionCollection()->addAction(KStandardAction::PrintPreview, this, SLOT( slotFilePrintPreview() ));
KStandardAction::preferences(this, SLOT(optionsPreferences()), actionCollection());
}
void KomparePart::updateActions()
{
m_saveAll->setEnabled ( m_modelList->hasUnsavedChanges() );
m_saveDiff->setEnabled ( m_modelList->mode() == Kompare::ComparingFiles || m_modelList->mode() == Kompare::ComparingDirs );
m_swap->setEnabled ( m_modelList->mode() == Kompare::ComparingFiles || m_modelList->mode() == Kompare::ComparingDirs );
m_diffRefresh->setEnabled ( m_modelList->mode() == Kompare::ComparingFiles || m_modelList->mode() == Kompare::ComparingDirs );
m_diffStats->setEnabled ( m_modelList->modelCount() > 0 );
m_print->setEnabled ( m_modelList->modelCount() > 0 ); // If modellist has models then we have something to print, it's that simple.
m_printPreview->setEnabled( m_modelList );
}
void KomparePart::setEncoding( const QString& encoding )
{
kDebug(8103) << "Encoding: " << encoding << endl;
m_modelList->setEncoding( encoding );
}
bool KomparePart::openDiff( const KUrl& url )
{
kDebug(8103) << "Url = " << url.url() << endl;
m_info.mode = Kompare::ShowingDiff;
m_info.source = url;
bool result = false;
fetchURL( url, true );
emit kompareInfo( &m_info );
if ( !m_info.localSource.isEmpty() )
{
kDebug(8103) << "Download succeeded " << endl;
result = m_modelList->openDiff( m_info.localSource );
updateActions();
updateCaption();
updateStatus();
}
else
{
kDebug(8103) << "Download failed !" << endl;
}
return result;
}
bool KomparePart::openDiff( const QString& diffOutput )
{
bool value = false;
m_info.mode = Kompare::ShowingDiff;
emit kompareInfo( &m_info );
if ( m_modelList->parseAndOpenDiff( diffOutput ) == 0 )
{
value = true;
updateActions();
updateCaption();
updateStatus();
}
return value;
}
bool KomparePart::openDiff3( const KUrl& diff3Url )
{
// FIXME: Implement this !!!
kDebug(8103) << "Not implemented yet. Filename is: " << diff3Url.prettyUrl() << endl;
return false;
}
bool KomparePart::openDiff3( const QString& diff3Output )
{
// FIXME: Implement this !!!
kDebug(8103) << "Not implemented yet. diff3 output is: " << endl;
kDebug(8103) << diff3Output << endl;
return false;
}
bool KomparePart::exists( const QString& url )
{
QFileInfo fi( url );
return fi.exists();
}
bool KomparePart::fetchURL( const KUrl& url, bool addToSource )
{
// Default value if there is an error is "", we rely on it!
QString tempFileName( "" );
// Only in case of error do we set result to false, don't forget!!
bool result = true;
KTempDir* tmpDir = 0;
if ( !url.isLocalFile() )
{
KIO::UDSEntry node;
KIO::NetAccess::stat( url, node, widget() );
if ( !node.isDir() )
{
if ( ! KIO::NetAccess::download( url, tempFileName, widget() ) )
{
slotShowError( i18n( "<qt>The URL <b>%1</b> cannot be downloaded.</qt>", url.prettyUrl() ) );
tempFileName = ""; // Not sure if download has already touched this tempFileName when there is an error
result = false;
}
}
else
{
tmpDir = new KTempDir(KStandardDirs::locateLocal("tmp", "kompare"));
tmpDir->setAutoRemove( true ); // Yes this is the default but just to make sure
if ( ! KIO::NetAccess::dircopy( url, KUrl( tmpDir->name() ), widget() ) )
{
slotShowError( i18n( "<qt>The URL <b>%1</b> cannot be downloaded.</qt>", url.prettyUrl() ) );
delete tmpDir;
tmpDir = 0;
result = false;
}
else
{
tempFileName = tmpDir->name();
kDebug(8101) << "tempFileName = " << tempFileName << endl;
// If a directory is copied into KTempDir then the directory in
// here is what I need to add to tempFileName
QDir dir( tempFileName );
QStringList entries = dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot );
if ( entries.size() == 1 ) // More than 1 entry in here means big problems!!!
{
if ( !tempFileName.endsWith( '/' ) )
tempFileName += '/';
tempFileName += entries.at( 0 );
tempFileName += '/';
}
else
{
kDebug(8101) << "Yikes, nothing downloaded?" << endl;
delete tmpDir;
tmpDir = 0;
tempFileName = "";
result = false;
}
}
}
}
else
{
// is Local already, check if exists
if ( exists( url.toLocalFile() ) )
tempFileName = url.toLocalFile();
else
{
slotShowError( i18n( "<qt>The URL <b>%1</b> does not exist on your system.</qt>", url.prettyUrl() ) );
result = false;
}
}
if ( addToSource )
{
m_info.localSource = tempFileName;
m_info.sourceKTempDir = tmpDir;
}
else
{
m_info.localDestination = tempFileName;
m_info.destinationKTempDir = tmpDir;
}
return result;
}
void KomparePart::cleanUpTemporaryFiles()
{
kDebug(8101) << "Cleaning temporary files." << endl;
if ( !m_info.localSource.isEmpty() )
{
if ( m_info.sourceKTempDir == 0 )
KIO::NetAccess::removeTempFile( m_info.localSource );
else
{
delete m_info.sourceKTempDir;
m_info.sourceKTempDir = 0;
}
m_info.localSource = "";
}
if ( !m_info.localDestination.isEmpty() )
{
if ( m_info.destinationKTempDir == 0 )
KIO::NetAccess::removeTempFile( m_info.localDestination );
else
{
delete m_info.destinationKTempDir;
m_info.destinationKTempDir = 0;
}
m_info.localDestination = "";
}
}
void KomparePart::compare( const KUrl& source, const KUrl& destination )
{
// FIXME: This is silly, i can use NetAccess::stat to figure out what it is and not
// wait until i am in the modellist to determine the mode we're supposed to be in.
// That should make the code more readable
// I should store the KTempDir(s)/File(s) in the Info struct as well and delete it at the right time
m_info.source = source;
m_info.destination = destination;
// FIXME: (Not urgent) But turn this into an enum, for now i cant find a nice name for the enum that has Source and Destination as values
// For now we do not do error checking, user has already been notified and if the localString is empty then we dont diff
fetchURL( source, true );
fetchURL( destination, false );
emit kompareInfo( &m_info );
compareAndUpdateAll();
}
void KomparePart::compareFileString( const KUrl & sourceFile, const QString & destination)
{
//Set the modeto specify that the source is a file, and the destination is a string
m_info.mode = Kompare::ComparingFileString;
m_info.source = sourceFile;
m_info.localDestination = destination;
fetchURL(sourceFile, true);
emit kompareInfo( &m_info );
compareAndUpdateAll();
}
void KomparePart::compareStringFile( const QString & source, const KUrl & destinationFile)
{
//Set the modeto specify that the source is a file, and the destination is a string
m_info.mode = Kompare::ComparingStringFile;
m_info.localSource = source;
m_info.destination = destinationFile;
fetchURL(destinationFile, false);
emit kompareInfo( &m_info );
compareAndUpdateAll();
}
void KomparePart::compareFiles( const KUrl& sourceFile, const KUrl& destinationFile )
{
m_info.mode = Kompare::ComparingFiles;
m_info.source = sourceFile;
m_info.destination = destinationFile;
// FIXME: (Not urgent) But turn this into an enum, for now i cant find a nice name for the enum that has Source and Destination as values
// For now we do not do error checking, user has already been notified and if the localString is empty then we dont diff
fetchURL( sourceFile, true );
fetchURL( destinationFile, false );
emit kompareInfo( &m_info );
compareAndUpdateAll();
}
void KomparePart::compareDirs( const KUrl& sourceDirectory, const KUrl& destinationDirectory )
{
m_info.mode = Kompare::ComparingDirs;
m_info.source = sourceDirectory;
m_info.destination = destinationDirectory;
fetchURL( sourceDirectory, true );
fetchURL( destinationDirectory, false );
emit kompareInfo( &m_info );
compareAndUpdateAll();
}
void KomparePart::compare3Files( const KUrl& /*originalFile*/, const KUrl& /*changedFile1*/, const KUrl& /*changedFile2*/ )
{
// FIXME: actually implement this some day :)
updateActions();
updateCaption();
updateStatus();
}
void KomparePart::openFileAndDiff( const KUrl& file, const KUrl& diffFile )
{
m_info.source = file;
m_info.destination = diffFile;
fetchURL( file, true );
fetchURL( diffFile, false );
m_info.mode = Kompare::BlendingFile;
emit kompareInfo( &m_info );
compareAndUpdateAll();
}
void KomparePart::openDirAndDiff ( const KUrl& dir, const KUrl& diffFile )
{
m_info.source = dir;
m_info.destination = diffFile;
fetchURL( dir, true );
fetchURL( diffFile, false );
m_info.mode = Kompare::BlendingDir;
emit kompareInfo( &m_info );
if ( !m_info.localSource.isEmpty() && !m_info.localDestination.isEmpty() )
{
m_modelList->openDirAndDiff();
//Must this be in here? couldn't we use compareAndUpdateAll as well?
updateActions();
updateCaption();
updateStatus();
}
}
bool KomparePart::openFile()
{
// This is called from openURL
// This is a little inefficient but i will do it anyway
openDiff( url() );
return true;
}
bool KomparePart::saveAll()
{
bool result = m_modelList->saveAll();
updateActions();
updateCaption();
updateStatus();
return result;
}
void KomparePart::saveDiff()
{
KDialog dlg( widget() );
dlg.setObjectName( "save_options" );
dlg.setModal( true );
dlg.setWindowTitle( i18n("Diff Options") );
dlg.setButtons( KDialog::Ok|KDialog::Cancel );
KompareSaveOptionsWidget* w = new KompareSaveOptionsWidget(
m_info.localSource,
m_info.localDestination,
m_diffSettings, &dlg );
dlg.setMainWidget( w );
dlg.setButtonGuiItem( KDialog::Ok, KStandardGuiItem::save() );
if( dlg.exec() ) {
w->saveOptions();
KSharedConfig::Ptr config = componentData().config();
saveProperties( config.data() );
config->sync();
while ( 1 )
{
KUrl url = KFileDialog::getSaveUrl( m_info.destination.url(),
i18n("*.diff *.dif *.patch|Patch Files"), widget(), i18n( "Save .diff" ) );
if ( KIO::NetAccess::exists( url, KIO::NetAccess::DestinationSide, widget() ) )
{
int result = KMessageBox::warningYesNoCancel( widget(), i18n("The file exists or is write-protected; do you want to overwrite it?"), i18n("File Exists"), KGuiItem(i18n("Overwrite")), KGuiItem(i18n("Do Not Overwrite")) );
if ( result == KMessageBox::Cancel )
{
break;
}
else if ( result == KMessageBox::No )
{
continue;
}
else
{
kDebug(8103) << "URL = " << url.prettyUrl() << endl;
kDebug(8103) << "Directory = " << w->directory() << endl;
kDebug(8103) << "DiffSettings = " << m_diffSettings << endl;
m_modelList->saveDiff( url.url(), w->directory(), m_diffSettings );
break;
}
}
else
{
kDebug(8103) << "URL = " << url.prettyUrl() << endl;
kDebug(8103) << "Directory = " << w->directory() << endl;
kDebug(8103) << "DiffSettings = " << m_diffSettings << endl;
m_modelList->saveDiff( url.url(), w->directory(), m_diffSettings );
break;
}
}
}
}
void KomparePart::slotFilePrint()
{
QPrinter printer;
printer.setOrientation( QPrinter::Landscape );
QPrintDialog* dlg = KdePrint::createPrintDialog( &printer, m_splitter );
if ( dlg->exec() == QDialog::Accepted )
{
// do some printing in qprinter
slotPaintRequested( &printer );
}
delete dlg;
}
void KomparePart::slotFilePrintPreview()
{
QPrinter printer;
printer.setOrientation( QPrinter::Landscape );
QPrintPreviewDialog dlg( &printer );
connect( &dlg, SIGNAL(paintRequested(QPrinter*)), this, SLOT(slotPaintRequested(QPrinter*)) );
dlg.exec();
}
void KomparePart::slotPaintRequested( QPrinter* printer )
{
kDebug(8103) << "Now paint something..." << endl;
QPainter p;
p.begin( printer );
QSize widgetWidth = m_view->size();
kDebug(8103) << "printer.width() = " << printer->width() << endl;
kDebug(8103) << "widgetWidth.width() = " << widgetWidth.width() << endl;
qreal factor = ((qreal)printer->width())/((qreal)widgetWidth.width());
kDebug(8103) << "factor = " << factor << endl;
p.scale( factor, factor );
m_view->render( &p );
p.end();
kDebug(8103) << "Done painting something..." << endl;
}
KAboutData* KomparePart::createAboutData()
{
KAboutData *about = new KAboutData("kompare", 0, ki18n("KomparePart"), "4.0");
about->addAuthor(ki18n("John Firebaugh"), ki18n("Author"), "jfirebaugh@kde.org");
about->addAuthor(ki18n("Otto Bruggeman"), ki18n("Author"), "bruggie@gmail.com" );
about->addAuthor(ki18n("Kevin Kofler"), ki18n("Author"), "kevin.kofler@chello.at" );
return about;
}
void KomparePart::slotSetStatus( enum Kompare::Status status )
{
updateActions();
switch( status ) {
case Kompare::RunningDiff:
emit setStatusBarText( i18n( "Running diff..." ) );
break;
case Kompare::Parsing:
emit setStatusBarText( i18n( "Parsing diff output..." ) );
break;
case Kompare::FinishedParsing:
updateStatus();
break;
case Kompare::FinishedWritingDiff:
updateStatus();
emit diffURLChanged();
break;
default:
break;
}
}
void KomparePart::updateCaption()
{
QString source = m_info.source.prettyUrl();
QString destination = m_info.destination.prettyUrl();
QString text;
switch ( m_info.mode )
{
case Kompare::ComparingFiles :
case Kompare::ComparingDirs :
case Kompare::BlendingFile :
case Kompare::BlendingDir :
text = source + " -- " + destination; // no need to translate this " -- "
break;
case Kompare::ShowingDiff :
text = source;
break;
default:
break;
}
emit setWindowCaption( text );
}
void KomparePart::updateStatus()
{
QString source = m_info.source.prettyUrl();
QString destination = m_info.destination.prettyUrl();
QString text;
switch ( m_info.mode )
{
case Kompare::ComparingFiles :
text = i18n( "Comparing file %1 with file %2" ,
source ,
destination );
break;
case Kompare::ComparingDirs :
text = i18n( "Comparing files in %1 with files in %2" ,
source ,
destination );
break;
case Kompare::ShowingDiff :
text = i18n( "Viewing diff output from %1", source );
break;
case Kompare::BlendingFile :
text = i18n( "Blending diff output from %1 into file %2" ,
source ,
destination );
break;
case Kompare::BlendingDir :
text = i18n( "Blending diff output from %1 into folder %2" ,
m_info.source.prettyUrl() ,
m_info.destination.prettyUrl() );
break;
default:
break;
}
emit setStatusBarText( text );
}
void KomparePart::compareAndUpdateAll()
{
if ( !m_info.localSource.isEmpty() && !m_info.localDestination.isEmpty() )
{
switch(m_info.mode)
{
default:
case Kompare::UnknownMode:
m_modelList->compare();
break;
case Kompare::ComparingStringFile:
case Kompare::ComparingFileString:
case Kompare::ComparingFiles:
case Kompare::ComparingDirs:
m_modelList->compare(m_info.mode);
break;
case Kompare::BlendingFile:
m_modelList->openFileAndDiff();
break;
}
updateCaption();
updateStatus();
}
updateActions();
}
void KomparePart::slotShowError( QString error )
{
KMessageBox::error( widget(), error );
}
void KomparePart::slotSwap()
{
if ( m_modelList->hasUnsavedChanges() )
{
int query = KMessageBox::warningYesNoCancel
(
widget(),
i18n( "You have made changes to the destination file(s).\n"
"Would you like to save them?" ),
i18n( "Save Changes?" ),
KStandardGuiItem::save(),
KStandardGuiItem::discard()
);
if ( query == KMessageBox::Yes )
m_modelList->saveAll();
if ( query == KMessageBox::Cancel )
return; // Abort prematurely so no swapping
}
// Swap the info in the Kompare::Info struct
m_info.swapSourceWithDestination();
// Update window caption and statusbar text
updateCaption();
updateStatus();
m_modelList->swap();
}
void KomparePart::slotRefreshDiff()
{
if ( m_modelList->hasUnsavedChanges() )
{
int query = KMessageBox::warningYesNoCancel
(
widget(),
i18n( "You have made changes to the destination file(s).\n"
"Would you like to save them?" ),
i18n( "Save Changes?" ),
KStandardGuiItem::save(),
KStandardGuiItem::discard()
);
if ( query == KMessageBox::Cancel )
return; // Abort prematurely so no refreshing
if ( query == KMessageBox::Yes )
m_modelList->saveAll();
}
// For this to work properly you have to refetch the files from their (remote) locations
cleanUpTemporaryFiles();
fetchURL( m_info.source, true );
fetchURL( m_info.destination, false );
m_modelList->refresh();
}
void KomparePart::slotShowDiffstats( void )
{
// Fetch all the args needed for komparestatsmessagebox
// oldfile, newfile, diffformat, noofhunks, noofdiffs
QString oldFile;
QString newFile;
QString diffFormat;
int filesInDiff;
int noOfHunks;
int noOfDiffs;
oldFile = m_modelList->selectedModel() ? m_modelList->selectedModel()->sourceFile() : QString( "" );
newFile = m_modelList->selectedModel() ? m_modelList->selectedModel()->destinationFile() : QString( "" );
if ( m_modelList->selectedModel() )
{
switch( m_info.format ) {
case Kompare::Unified :
diffFormat = i18n( "Unified" );
break;
case Kompare::Context :
diffFormat = i18n( "Context" );
break;
case Kompare::RCS :
diffFormat = i18n( "RCS" );
break;
case Kompare::Ed :
diffFormat = i18n( "Ed" );
break;
case Kompare::Normal :
diffFormat = i18n( "Normal" );
break;
case Kompare::UnknownFormat :
default:
diffFormat = i18n( "Unknown" );
break;
}
}
else
{
diffFormat = "";
}
filesInDiff = m_modelList->modelCount();
noOfHunks = m_modelList->selectedModel() ? m_modelList->selectedModel()->hunkCount() : 0;
noOfDiffs = m_modelList->selectedModel() ? m_modelList->selectedModel()->differenceCount() : 0;
if ( m_modelList->modelCount() == 0 ) { // no diff loaded yet
KMessageBox::information( 0L, i18n(
"No diff file, or no 2 files have been diffed. "
"Therefore no stats are available."),
i18n("Diff Statistics"), QString(), 0 );
}
else if ( m_modelList->modelCount() == 1 ) { // 1 file in diff, or 2 files compared
KMessageBox::information( 0L, i18n(
"Statistics:\n"
"\n"
"Old file: %1\n"
"New file: %2\n"
"\n"
"Format: %3\n"
"Number of hunks: %4\n"
"Number of differences: %5",
oldFile, newFile, diffFormat,
noOfHunks, noOfDiffs),
i18n("Diff Statistics"), QString(), 0 );
} else { // more than 1 file in diff, or 2 directories compared
KMessageBox::information( 0L, ki18n(
"Statistics:\n"
"\n"
"Number of files in diff file: %1\n"
"Format: %2\n"
"\n"
"Current old file: %3\n"
"Current new file: %4\n"
"\n"
"Number of hunks: %5\n"
"Number of differences: %6")
.subs(filesInDiff).subs(diffFormat).subs(oldFile)
.subs(newFile).subs(noOfHunks).subs(noOfDiffs)
.toString(),
i18n("Diff Statistics"), QString(), 0 );
}
}
bool KomparePart::queryClose()
{
if ( !m_modelList->hasUnsavedChanges() ) return true;
int query = KMessageBox::warningYesNoCancel
(
widget(),
i18n("You have made changes to the destination file(s).\n"
"Would you like to save them?" ),
i18n( "Save Changes?" ),
KStandardGuiItem::save(),
KStandardGuiItem::discard()
);
if( query == KMessageBox::Cancel )
return false;
if( query == KMessageBox::Yes )
return m_modelList->saveAll();
return true;
}
int KomparePart::readProperties( KConfig *config )
{
m_viewSettings->loadSettings( config );
m_diffSettings->loadSettings( config );
emit configChanged();
return 0;
}
int KomparePart::saveProperties( KConfig *config )
{
m_viewSettings->saveSettings( config );
m_diffSettings->saveSettings( config );
return 0;
}
void KomparePart::optionsPreferences()
{
// show preferences
KomparePrefDlg pref( m_viewSettings, m_diffSettings );
connect( &pref, SIGNAL(configChanged()), this, SIGNAL(configChanged()) );
if ( pref.exec() )
emit configChanged();
}
#include "kompare_part.moc"

View file

@ -0,0 +1,241 @@
/***************************************************************************
kompare_part.h
--------------
begin : Sun Mar 4 2001
Copyright 2001-2005,2009 Otto Bruggeman <bruggie@gmail.com>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2004 Jeff Snyder <jeff@caffeinated.me.uk>
Copyright 2007-2011 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#ifndef KOMPAREPART_H
#define KOMPAREPART_H
#include <kparts/factory.h>
#include <kparts/part.h>
#include <QVariantList>
#include <kompare.h>
#include "kompareinterface.h"
class QPrinter;
class QWidget;
class KTemporaryFile;
class KUrl;
class KAboutData;
class KAction;
namespace Diff2 {
class Difference;
class DiffModel;
class DiffModelList;
class KompareModelList;
}
class DiffSettings;
class ViewSettings;
class KompareSplitter;
class KompareView;
/**
* This is a "Part". It does all the real work in a KPart
* application.
*
* @short Main Part
* @author John Firebaugh <jfirebaugh@kde.org>
* @author Otto Bruggeman <bruggie@home.nl>
* @version 0.3
*/
class KomparePart : public KParts::ReadWritePart,
public KompareInterface
{
Q_OBJECT
Q_INTERFACES(KompareInterface)
public:
/**
* Default constructor
*/
KomparePart( QWidget *parentWidget, QObject *parent, const QVariantList & /*args*/);
/**
* Destructor
*/
virtual ~KomparePart();
// Sessionmanagement stuff, added to the kompare iface
// because they are not in the Part class where they belong
// Should be added when bic changes are allowed again (kde 4.0)
virtual int readProperties( KConfig *config );
virtual int saveProperties( KConfig *config );
// this one is called when the shell_app is about to close.
// we need it now to save the properties of the part when apps don't (can't)
// use the readProperties and saveProperties methods
virtual bool queryClose();
// Do we really want to expose this ???
const Diff2::KompareModelList* model() const { return m_modelList; };
static KAboutData *createAboutData();
public:
// Reimplemented from the KompareInterface
/**
* Open and parse the diff file at diffUrl.
*/
virtual bool openDiff( const KUrl& diffUrl );
/** Added on request of Harald Fernengel */
virtual bool openDiff( const QString& diffOutput );
/** Open and parse the diff3 file at diff3Url */
virtual bool openDiff3( const KUrl& diff3URL );
/** Open and parse the file diff3Output with the output of diff3 */
virtual bool openDiff3( const QString& diff3Output );
/** Compare, with diff, source with destination */
virtual void compare( const KUrl& sourceFile, const KUrl& destinationFile );
/** Compare a Source file to a custom Destination string */
virtual void compareFileString( const KUrl & sourceFile, const QString & destination);
/** Compare a custom Source string to a Destination file */
virtual void compareStringFile( const QString & source, const KUrl & destinationFile);
/** Compare, with diff, source with destination */
virtual void compareFiles( const KUrl& sourceFile, const KUrl& destinationFile );
/** Compare, with diff, source with destination */
virtual void compareDirs ( const KUrl& sourceDir, const KUrl& destinationDir );
/** Compare, with diff3, originalFile with changedFile1 and changedFile2 */
virtual void compare3Files( const KUrl& originalFile, const KUrl& changedFile1, const KUrl& changedFile2 );
/** This will show the file and the file with the diff applied */
virtual void openFileAndDiff( const KUrl& file, const KUrl& diffFile );
/** This will show the directory and the directory with the diff applied */
virtual void openDirAndDiff ( const KUrl& dir, const KUrl& diffFile );
/** Reimplementing this because this one knows more about the real part then the interface */
virtual void setEncoding( const QString& encoding );
// This is the interpart interface, it is signal and slot based so no "real" interface here
// All you have to do is connect the parts from your application.
// These just point to their counterpart in the KompareModelList or get called from their
// counterpart in KompareModelList.
signals:
void modelsChanged( const Diff2::DiffModelList* models );
void setSelection( const Diff2::DiffModel* model, const Diff2::Difference* diff );
void setSelection( const Diff2::Difference* diff );
void selectionChanged( const Diff2::DiffModel* model, const Diff2::Difference* diff );
void selectionChanged( const Diff2::Difference* diff );
void applyDifference( bool apply );
void applyAllDifferences( bool apply );
void applyDifference( const Diff2::Difference*, bool apply );
void configChanged();
/*
** This is emitted when a difference is clicked in the kompare view. You can connect to
** it so you can use it to jump to this particular line in the editor in your app.
*/
void differenceClicked( int lineNumber );
// Stuff that can probably be removed by putting it in the part where it belongs in my opinion
public slots:
/** Save all destinations. */
bool saveAll();
/** Save the results of a comparison as a diff file. */
void saveDiff();
/** To enable printing, the part has the only interesting printable content so putting it here */
void slotFilePrint();
void slotFilePrintPreview();
signals:
void appliedChanged();
void diffURLChanged();
void kompareInfo( Kompare::Info* info );
void setStatusBarModelInfo( int modelIndex, int differenceIndex, int modelCount, int differenceCount, int appliedCount );
// void setStatusBarText( const QString& text );
void diffString(const QString&);
protected:
/**
* This is the method that gets called when the file is opened,
* when using openURL( const KUrl& ) or in our case also openDiff( const KUrl& );
* return true when everything went ok, false if there were problems
*/
virtual bool openFile();
// ... Uhm we return true without saving ???
virtual bool saveFile() { return true; };
// patchFile
bool patchFile(KUrl&);
bool patchDir();
protected slots:
void slotSetStatus( Kompare::Status status );
void slotShowError( QString error );
void slotSwap();
void slotShowDiffstats();
void slotRefreshDiff();
void optionsPreferences();
void updateActions();
void updateCaption();
void updateStatus();
void compareAndUpdateAll();
void slotPaintRequested( QPrinter* );
private:
void cleanUpTemporaryFiles();
void setupActions();
bool exists( const QString& url );
bool isDirectory( const KUrl& url );
// FIXME (like in cpp file not urgent) Replace with enum, cant find a proper
// name now but it is private anyway so can not be used from outside
bool fetchURL( const KUrl& url, bool isSource );
private:
// Uhm why were these static again ???
// Ah yes, so multiple instances of kompare use the
// same settings after one of them changes them
static ViewSettings* m_viewSettings;
static DiffSettings* m_diffSettings;
Diff2::KompareModelList* m_modelList;
KompareView* m_view;
KompareSplitter* m_splitter;
KAction* m_saveAll;
KAction* m_saveDiff;
KAction* m_swap;
KAction* m_diffStats;
KAction* m_diffRefresh;
KAction* m_print;
KAction* m_printPreview;
KTemporaryFile* m_tempDiff;
struct Kompare::Info m_info;
};
#endif // KOMPAREPART_H

View file

@ -0,0 +1,258 @@
/***************************************************************************
kompareconnectwidget.cpp
------------------------
begin : Tue Jun 26 2001
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2001-2009 Otto Bruggeman <bruggie@gmail.com>
Copyright 2004 Jeff Snyder <jeff@caffeinated.me.uk>
Copyright 2007-2011 Kevin Kofler <kevin.kofler@chello.at>
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#include "kompareconnectwidget.h"
#include <QtGui/QApplication>
#include <QtGui/QPainter>
#include <QtGui/QPixmap>
#include <QtGui/QStyle>
#include <QtCore/QTimer>
#include <QtGui/QPaintEvent>
#include <QFrame>
#include <QtGui/QMouseEvent>
#include <kdebug.h>
#include "viewsettings.h"
#include "komparelistview.h"
#include "komparesplitter.h"
using namespace Diff2;
KompareConnectWidgetFrame::KompareConnectWidgetFrame( ViewSettings* settings,
KompareSplitter* parent,
const char* name ) :
QSplitterHandle(Qt::Horizontal, (QSplitter *)parent),
m_wid ( settings, this, name ),
m_label ( " ", this ), // putting a space here because Qt 4 computes different size hints for empty labels
m_layout ( this )
{
setObjectName( name );
setSizePolicy ( QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored) );
m_wid.setSizePolicy ( QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored) );
m_label.setSizePolicy ( QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed) );
m_label.setMargin(3);
QFrame* bottomLine = new QFrame(this);
bottomLine->setFrameShape(QFrame::HLine);
bottomLine->setFrameShadow ( QFrame::Plain );
bottomLine->setSizePolicy ( QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed) );
bottomLine->setFixedHeight(1);
m_layout.setSpacing(0);
m_layout.setMargin(0);
m_layout.addWidget(&m_label);
m_layout.addWidget(bottomLine);
m_layout.addWidget(&m_wid);
}
KompareConnectWidgetFrame::~KompareConnectWidgetFrame()
{
}
QSize KompareConnectWidgetFrame::sizeHint() const
{
return QSize(50, style()->pixelMetric( QStyle::PM_ScrollBarExtent ) );
}
#if 0
static int kMouseOffset;
void KompareConnectWidgetFrame::mouseMoveEvent( QMouseEvent *e )
{
if ( !(e->state()&Qt::LeftButton) )
return;
QCOORD pos = s->pick( parentWidget()->mapFromGlobal(e->globalPos()) )
- kMouseOffset;
((KompareSplitter*)s)->moveSplitter( pos, id() );
}
void KompareConnectWidgetFrame::mousePressEvent( QMouseEvent *e )
{
if ( e->button() == Qt::LeftButton )
kMouseOffset = s->pick( e->pos() );
QSplitterHandle::mousePressEvent(e);
}
void KompareConnectWidgetFrame::mouseReleaseEvent( QMouseEvent *e )
{
if ( !opaque() && e->button() == Qt::LeftButton ) {
QCOORD pos = s->pick( parentWidget()->mapFromGlobal(e->globalPos()) )
- kMouseOffset;
((KompareSplitter*)s)->moveSplitter( pos, id() );
}
}
#endif
KompareConnectWidget::KompareConnectWidget( ViewSettings* settings, QWidget* parent, const char* name )
: QWidget(parent),
m_settings( settings ),
m_selectedModel( 0 ),
m_selectedDifference( 0 )
{
setObjectName(name);
// connect( m_settings, SIGNAL( settingsChanged() ), this, SLOT( slotDelayedRepaint() ) );
setAttribute( Qt::WA_NoSystemBackground, true );
setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ) );
setFocusProxy( parent->parentWidget() );
}
KompareConnectWidget::~KompareConnectWidget()
{
m_settings = 0;
m_selectedModel = 0;
m_selectedDifference = 0;
}
void KompareConnectWidget::slotSetSelection( const DiffModel* model, const Difference* diff )
{
if( m_selectedModel == model && m_selectedDifference == diff )
return;
if ( m_selectedModel == model && m_selectedDifference != diff )
{
m_selectedDifference = diff;
slotDelayedRepaint();
return;
}
m_selectedModel = model;
m_selectedDifference = diff;
slotDelayedRepaint();
}
void KompareConnectWidget::slotDelayedRepaint()
{
QTimer::singleShot( 0, this, SLOT( repaint() ) );
}
void KompareConnectWidget::slotSetSelection( const Difference* diff )
{
if ( m_selectedDifference == diff )
return;
m_selectedDifference = diff;
slotDelayedRepaint();
}
void KompareConnectWidget::paintEvent( QPaintEvent* /* e */ )
{
QPixmap pixbuf(size());
QPainter paint(&pixbuf);
QPainter* p = &paint;
p->setRenderHint(QPainter::Antialiasing);
p->fillRect( 0, 0, pixbuf.width(), pixbuf.height(), palette().color( QPalette::Window ) );
p->translate(QPointF(0, 0.5));
KompareSplitter* splitter = static_cast<KompareSplitter*>( parent()->parent() );
int count = splitter->count();
KompareListView *leftView = count >= 2 ? static_cast<KompareListViewFrame*>( splitter->widget(0) )->view() : 0;
KompareListView *rightView = count >= 2 ? static_cast<KompareListViewFrame*>( splitter->widget(1) )->view() : 0;
if ( m_selectedModel && leftView && rightView )
{
int firstL = leftView->firstVisibleDifference();
int firstR = rightView->firstVisibleDifference();
int lastL = leftView->lastVisibleDifference();
int lastR = rightView->lastVisibleDifference();
int first = firstL < 0 ? firstR : qMin( firstL, firstR );
int last = lastL < 0 ? lastR : qMax( lastL, lastR );
// kDebug(8106) << " left: " << firstL << " - " << lastL << endl;
// kDebug(8106) << " right: " << firstR << " - " << lastR << endl;
// kDebug(8106) << " drawing: " << first << " - " << last << endl;
if ( first >= 0 && last >= 0 && first <= last )
{
const DifferenceList* differences = const_cast<DiffModel*>(m_selectedModel)->differences();
QRect leftRect, rightRect;
for ( int i = first; i <= last; ++i )
{
Difference* diff = differences->at(i );
bool selected = ( diff == m_selectedDifference );
if ( QApplication::isRightToLeft() )
{
leftRect = rightView->itemRect( i );
rightRect = leftView->itemRect( i );
}
else
{
leftRect = leftView->itemRect( i );
rightRect = rightView->itemRect( i );
}
int tl = leftRect.top();
int tr = rightRect.top();
int bl = leftRect.bottom();
int br = rightRect.bottom();
// Bah, stupid 16-bit signed shorts in that crappy X stuff...
tl = tl >= -32768 ? tl : -32768;
tr = tr >= -32768 ? tr : -32768;
bl = bl <= 32767 ? bl : 32767;
br = br <= 32767 ? br : 32767;
QPainterPath topBezier = makeBezier( tl, tr );
QPainterPath bottomBezier = makeBezier( bl, br );
QPainterPath poly(topBezier);
poly.connectPath(bottomBezier.toReversed());
poly.closeSubpath();
QColor bg = m_settings->colorForDifferenceType( diff->type(), selected, diff->applied() );
p->setPen( bg );
p->setBrush( bg );
p->drawPath(poly);
if(selected)
{
p->setPen( bg.dark( 135 ) );
p->setBrush( Qt::NoBrush );
p->drawPath( topBezier );
p->drawPath( bottomBezier.toReversed() );
}
}
}
}
// p->flush();
QPainter widgetPainter(this);
widgetPainter.drawImage(0, 0, pixbuf.toImage());
}
QPainterPath KompareConnectWidget::makeBezier( int leftHeight, int rightHeight ) const
{
int r = width();
int o = (int)((double)r*0.4); // 40% of width
QPainterPath p(QPointF(0, leftHeight));
if(leftHeight==rightHeight) {
p.lineTo(QPointF(r, rightHeight));
} else {
p.cubicTo(QPointF(o, leftHeight), QPointF(r-o, rightHeight), QPointF(r,rightHeight));
}
return p;
}
#include "kompareconnectwidget.moc"

View file

@ -0,0 +1,93 @@
/***************************************************************************
kompareconnectwidget.h
----------------------
begin : Tue Jun 26 2001
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2001-2004 Otto Bruggeman <otto.bruggeman@home.nl>
Copyright 2004 Jeff Snyder <jeff@caffeinated.me.uk>
Copyright 2007 Kevin Kofler <kevin.kofler@chello.at>
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#ifndef KOMPARECONNECTWIDGET_H
#define KOMPARECONNECTWIDGET_H
#include <QtGui/QWidget>
#include <QtGui/QSplitter>
#include <QtGui/QPaintEvent>
#include <QtGui/QMouseEvent>
#include <QVBoxLayout>
#include <QtGui/QLabel>
#include "komparemodellist.h"
namespace Diff2 {
class DiffModel;
}
class ViewSettings;
class KompareSplitter;
class KompareConnectWidget : public QWidget
{
Q_OBJECT
public:
KompareConnectWidget( ViewSettings* settings, QWidget* parent, const char* name = 0 );
~KompareConnectWidget();
public slots:
void slotSetSelection( const Diff2::DiffModel* model, const Diff2::Difference* diff );
void slotSetSelection( const Diff2::Difference* diff );
void slotDelayedRepaint();
signals:
void selectionChanged(const Diff2::Difference* diff);
protected:
void paintEvent( QPaintEvent* e );
QPainterPath makeBezier( int l, int r ) const;
private:
ViewSettings* m_settings;
const Diff2::DiffModel* m_selectedModel;
const Diff2::Difference* m_selectedDifference;
};
class KompareConnectWidgetFrame : public QSplitterHandle
{
Q_OBJECT
public:
KompareConnectWidgetFrame( ViewSettings* settings, KompareSplitter* parent, const char* name = 0 );
~KompareConnectWidgetFrame();
QSize sizeHint() const;
KompareConnectWidget* wid() { return &m_wid; }
protected:
// stop the parent QSplitterHandle painting
void paintEvent( QPaintEvent* /* e */ ) { }
#if 0
void mouseMoveEvent( QMouseEvent * );
void mousePressEvent( QMouseEvent * );
void mouseReleaseEvent( QMouseEvent * );
#endif
private:
KompareConnectWidget m_wid;
QLabel m_label;
QVBoxLayout m_layout;
};
#endif

View file

@ -0,0 +1,974 @@
/***************************************************************************
komparelistview.h
-----------------
begin : Sun Mar 4 2001
Copyright 2001-2009 Otto Bruggeman <bruggie@gmail.com>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2004 Jeff Snyder <jeff@caffeinated.me.uk>
Copyright 2007-2012 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#include "komparelistview.h"
#include <QtGui/QStyle>
#include <QtGui/QPainter>
#include <QtCore/QRegExp>
#include <QtCore/QTimer>
#include <QtGui/QResizeEvent>
#include <QtGui/QMouseEvent>
#include <QtGui/QWheelEvent>
#include <QtGui/QScrollBar>
#include <kdebug.h>
#include <kglobal.h>
#include <kglobalsettings.h>
#include "diffmodel.h"
#include "diffhunk.h"
#include "difference.h"
#include "viewsettings.h"
#include "komparemodellist.h"
#include "komparesplitter.h"
#define COL_LINE_NO 0
#define COL_MAIN 1
#define BLANK_LINE_HEIGHT 3
#define HUNK_LINE_HEIGHT 5
#define ITEM_MARGIN 3
using namespace Diff2;
KompareListViewFrame::KompareListViewFrame( bool isSource,
ViewSettings* settings,
KompareSplitter* parent,
const char* name ):
QFrame ( parent ),
m_view ( isSource, settings, this, name ),
m_label ( isSource?"Source":"Dest", this ),
m_layout ( this )
{
setSizePolicy ( QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored) );
m_label.setSizePolicy ( QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed) );
QFrame *bottomLine = new QFrame(this);
bottomLine->setFrameShape(QFrame::HLine);
bottomLine->setFrameShadow ( QFrame::Plain );
bottomLine->setSizePolicy ( QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed) );
bottomLine->setFixedHeight(1);
m_label.setMargin(3);
m_layout.setSpacing(0);
m_layout.setMargin(0);
m_layout.addWidget(&m_label);
m_layout.addWidget(bottomLine);
m_layout.addWidget(&m_view);
connect( &m_view, SIGNAL(differenceClicked(const Diff2::Difference*)),
parent, SLOT(slotDifferenceClicked(const Diff2::Difference*)) );
connect( parent, SIGNAL(scrollViewsToId(int)), &m_view, SLOT(scrollToId(int)) );
connect( parent, SIGNAL(setXOffset(int)), &m_view, SLOT(setXOffset(int)) );
connect( &m_view, SIGNAL(resized()), parent, SLOT(slotUpdateScrollBars()) );
}
void KompareListViewFrame::slotSetModel( const DiffModel* model )
{
if( model )
{
if( view()->isSource() ) {
if( !model->sourceRevision().isEmpty() )
m_label.setText( model->sourceFile() + " (" + model->sourceRevision() + ')' );
else
m_label.setText( model->sourceFile() );
} else {
if( !model->destinationRevision().isEmpty() )
m_label.setText( model->destinationFile() + " (" + model->destinationRevision() + ')' );
else
m_label.setText( model->destinationFile() );
}
} else {
m_label.setText( QString::null ); //krazy:exclude=nullstrassign for old broken gcc
}
}
KompareListView::KompareListView( bool isSource,
ViewSettings* settings,
QWidget* parent, const char* name ) :
QTreeWidget( parent ),
m_isSource( isSource ),
m_settings( settings ),
m_scrollId( -1 ),
m_selectedModel( 0 ),
m_selectedDifference( 0 )
{
setObjectName( name );
setItemDelegate( new KompareListViewItemDelegate( this ) );
setHeaderHidden( true );
setColumnCount( 3 ); // Line Number, Main, Blank
setAllColumnsShowFocus( true );
setRootIsDecorated( false );
setIndentation( 0 );
setFrameStyle( QFrame::NoFrame );
setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );
setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
setFocusPolicy( Qt::NoFocus );
setFont( m_settings->m_font );
setFocusProxy( parent->parentWidget() );
}
KompareListView::~KompareListView()
{
m_settings = 0;
m_selectedModel = 0;
m_selectedDifference = 0;
}
KompareListViewItem* KompareListView::itemAtIndex( int i )
{
return m_items[ i ];
}
int KompareListView::firstVisibleDifference()
{
QTreeWidgetItem* item = itemAt( QPoint( 0, 0 ) );
if( item == 0 )
{
kDebug(8104) << "no item at viewport coordinates (0,0)" << endl;
}
while( item ) {
KompareListViewLineItem* lineItem = dynamic_cast<KompareListViewLineItem*>(item);
if( lineItem && lineItem->diffItemParent()->difference()->type() != Difference::Unchanged )
break;
item = itemBelow(item);
}
if( item )
return m_items.indexOf( ((KompareListViewLineItem*)item)->diffItemParent() );
return -1;
}
int KompareListView::lastVisibleDifference()
{
QTreeWidgetItem* item = itemAt( QPoint( 0, visibleHeight() - 1 ) );
if( item == 0 )
{
kDebug(8104) << "no item at viewport coordinates (0," << visibleHeight() - 1 << ")" << endl;
// find last item
item = itemAt( QPoint( 0, 0 ) );
if( item ) {
QTreeWidgetItem* nextItem = item;
do {
item = nextItem;
nextItem = itemBelow( item );
} while( nextItem );
}
}
while( item ) {
KompareListViewLineItem* lineItem = dynamic_cast<KompareListViewLineItem*>(item);
if( lineItem && lineItem->diffItemParent()->difference()->type() != Difference::Unchanged )
break;
item = itemAbove(item);
}
if( item )
return m_items.indexOf( ((KompareListViewLineItem*)item)->diffItemParent() );
return -1;
}
QRect KompareListView::totalVisualItemRect( QTreeWidgetItem* item )
{
QRect total = visualItemRect( item );
int n = item->childCount();
for( int i=0; i<n; i++ ) {
QTreeWidgetItem* child = item->child( i );
if( !child->isHidden() )
total = total.united( totalVisualItemRect( child ) );
}
return total;
}
QRect KompareListView::itemRect( int i )
{
QTreeWidgetItem* item = itemAtIndex( i );
return totalVisualItemRect( item );
}
int KompareListView::minScrollId()
{
return visibleHeight() / 2;
}
int KompareListView::maxScrollId()
{
int n = topLevelItemCount();
if(!n) return 0;
KompareListViewItem* item = (KompareListViewItem*)topLevelItem( n-1 );
int maxId = item->scrollId() + item->maxHeight() - minScrollId();
kDebug(8104) << "Max ID = " << maxId << endl;
return maxId;
}
int KompareListView::contentsHeight()
{
return verticalScrollBar()->maximum() + viewport()->height() - style()->pixelMetric( QStyle::PM_ScrollBarExtent );
}
int KompareListView::contentsWidth()
{
return ( columnWidth(COL_LINE_NO) + columnWidth(COL_MAIN) );
}
int KompareListView::visibleHeight()
{
return viewport()->height();
}
int KompareListView::visibleWidth()
{
return viewport()->width();
}
int KompareListView::contentsX()
{
return horizontalOffset();
}
int KompareListView::contentsY()
{
return verticalOffset();
}
int KompareListView::nextPaintOffset() const
{
return m_nextPaintOffset;
}
void KompareListView::setNextPaintOffset(int offset)
{
m_nextPaintOffset = offset;
}
void KompareListView::setXOffset( int x )
{
kDebug(8104) << "SetXOffset : Scroll to x position: " << x << endl;
horizontalScrollBar()->setValue( x );
}
void KompareListView::scrollToId( int id )
{
// kDebug(8104) << "ScrollToID : Scroll to id : " << id << endl;
int n = topLevelItemCount();
KompareListViewItem* item = 0;
if( n ) {
int i = 1;
for( ; i<n; i++ ) {
if( ((KompareListViewItem*)topLevelItem( i ))->scrollId() > id )
break;
}
item = (KompareListViewItem*)topLevelItem( i-1 );
}
if( item ) {
QRect rect = totalVisualItemRect( item );
int pos = rect.top() + verticalOffset();
int itemId = item->scrollId();
int height = rect.height();
double r = (double)( id - itemId ) / (double)item->maxHeight();
int y = pos + (int)( r * (double)height ) - minScrollId();
// kDebug(8104) << "scrollToID: " << endl;
// kDebug(8104) << " id = " << id << endl;
// kDebug(8104) << " pos = " << pos << endl;
// kDebug(8104) << " itemId = " << itemId << endl;
// kDebug(8104) << " r = " << r << endl;
// kDebug(8104) << " height = " << height << endl;
// kDebug(8104) << " minID = " << minScrollId() << endl;
// kDebug(8104) << " y = " << y << endl;
// kDebug(8104) << "contentsHeight = " << contentsHeight() << endl;
// kDebug(8104) << " c - y = " << contentsHeight() - y << endl;
verticalScrollBar()->setValue( y );
}
m_scrollId = id;
}
int KompareListView::scrollId()
{
if( m_scrollId < 0 )
m_scrollId = minScrollId();
return m_scrollId;
}
void KompareListView::setSelectedDifference( const Difference* diff, bool scroll )
{
kDebug(8104) << "KompareListView::setSelectedDifference(" << diff << ", " << scroll << ")" << endl;
// When something other than a click causes this function to be called,
// it'll only get called once, and all is simple.
//
// When the user clicks on a diff, this function will get called once when
// komparesplitter::slotDifferenceClicked runs, and again when the
// setSelection signal from the modelcontroller arrives.
//
// the first call (which will always be from the splitter) will have
// scroll==false, and the second call will bail out here.
// Which is why clicking on a difference does not cause the listviews to
// scroll.
if ( m_selectedDifference == diff )
return;
m_selectedDifference = diff;
KompareListViewItem* item = m_itemDict[ diff ];
if( !item ) {
kDebug(8104) << "KompareListView::slotSetSelection(): couldn't find our selection!" << endl;
return;
}
// why does this not happen when the user clicks on a diff? see the comment above.
if( scroll )
scrollToId(item->scrollId());
setUpdatesEnabled( false );
int x = horizontalScrollBar()->value();
int y = verticalScrollBar()->value();
setCurrentItem( item );
horizontalScrollBar()->setValue( x );
verticalScrollBar()->setValue( y );
setUpdatesEnabled( true );
}
void KompareListView::slotSetSelection( const Difference* diff )
{
kDebug(8104) << "KompareListView::slotSetSelection( const Difference* diff )" << endl;
setSelectedDifference( diff, true );
}
void KompareListView::slotSetSelection( const DiffModel* model, const Difference* diff )
{
kDebug(8104) << "KompareListView::slotSetSelection( const DiffModel* model, const Difference* diff )" << endl;
if( m_selectedModel && m_selectedModel == model ) {
slotSetSelection( diff );
return;
}
clear();
m_items.clear();
m_itemDict.clear();
m_selectedModel = model;
DiffHunkListConstIterator hunkIt = model->hunks()->begin();
DiffHunkListConstIterator hEnd = model->hunks()->end();
KompareListViewItem* item = 0;
m_nextPaintOffset = 0;
for ( ; hunkIt != hEnd; ++hunkIt )
{
if( item )
item = new KompareListViewHunkItem( this, item, *hunkIt, model->isBlended() );
else
item = new KompareListViewHunkItem( this, *hunkIt, model->isBlended() );
DifferenceListConstIterator diffIt = (*hunkIt)->differences().begin();
DifferenceListConstIterator dEnd = (*hunkIt)->differences().end();
for ( ; diffIt != dEnd; ++diffIt )
{
item = new KompareListViewDiffItem( this, item, *diffIt );
int type = (*diffIt)->type();
if ( type != Difference::Unchanged )
{
m_items.append( (KompareListViewDiffItem*)item );
m_itemDict.insert( *diffIt, (KompareListViewDiffItem*)item );
}
}
}
resizeColumnToContents( COL_LINE_NO );
resizeColumnToContents( COL_MAIN );
slotSetSelection( diff );
}
KompareListViewDiffItem* KompareListView::diffItemAt( const QPoint& pos )
{
KompareListViewItem* item = static_cast<KompareListViewItem*>( itemAt( pos ) );
if( !item )
return 0;
switch( item->type() ) {
case KompareListViewItem::Hunk:
if( item->paintHeight() ) return 0; // no diff item here
// zero height (fake 1 pixel height), so a diff item shines through
return static_cast<KompareListViewDiffItem*>( itemBelow( item ) );
case KompareListViewItem::Line:
case KompareListViewItem::Blank:
return static_cast<KompareListViewLineItem*>( item )->diffItemParent();
case KompareListViewItem::Container:
return static_cast<KompareListViewLineContainerItem*>( item )->diffItemParent();
case KompareListViewItem::Diff:
return static_cast<KompareListViewDiffItem*>( item );
default:
return 0;
}
}
void KompareListView::mousePressEvent( QMouseEvent* e )
{
QPoint vp = e->pos();
KompareListViewDiffItem* diffItem = diffItemAt( vp );
if( diffItem && diffItem->difference()->type() != Difference::Unchanged ) {
emit differenceClicked( diffItem->difference() );
}
}
void KompareListView::mouseDoubleClickEvent( QMouseEvent* e )
{
QPoint vp = e->pos();
KompareListViewDiffItem* diffItem = diffItemAt( vp );
if ( diffItem && diffItem->difference()->type() != Difference::Unchanged ) {
// FIXME: make a new signal that does both
emit differenceClicked( diffItem->difference() );
emit applyDifference( !diffItem->difference()->applied() );
}
}
void KompareListView::renumberLines( void )
{
// kDebug( 8104 ) << "Begin" << endl;
unsigned int newLineNo = 1;
if( !topLevelItemCount() ) return;
KompareListViewItem* item = (KompareListViewItem*)topLevelItem( 0 );
while( item ) {
// kDebug( 8104 ) << "type: " << item->type() << endl;
if ( item->type() != KompareListViewItem::Container
&& item->type() != KompareListViewItem::Blank
&& item->type() != KompareListViewItem::Hunk )
{
// kDebug( 8104 ) << QString::number( newLineNo ) << endl;
item->setText( COL_LINE_NO, QString::number( newLineNo++ ) );
}
item = (KompareListViewItem*)itemBelow( item );
}
}
void KompareListView::slotApplyDifference( bool apply )
{
m_itemDict[ m_selectedDifference ]->applyDifference( apply );
// now renumber the line column if this is the destination
if ( !m_isSource )
renumberLines();
}
void KompareListView::slotApplyAllDifferences( bool apply )
{
QHash<const Diff2::Difference*, KompareListViewDiffItem*>::ConstIterator it = m_itemDict.constBegin();
QHash<const Diff2::Difference*, KompareListViewDiffItem*>::ConstIterator end = m_itemDict.constEnd();
for ( ; it != end; ++it )
it.value()->applyDifference( apply );
// now renumber the line column if this is the destination
if ( !m_isSource )
renumberLines();
update();
}
void KompareListView::slotApplyDifference( const Difference* diff, bool apply )
{
m_itemDict[ diff ]->applyDifference( apply );
// now renumber the line column if this is the destination
if ( !m_isSource )
renumberLines();
}
void KompareListView::wheelEvent( QWheelEvent* e )
{
e->ignore(); // we want the parent to catch wheel events
}
void KompareListView::resizeEvent( QResizeEvent* e )
{
QTreeWidget::resizeEvent(e);
emit resized();
}
KompareListViewItemDelegate::KompareListViewItemDelegate( QObject* parent )
: QStyledItemDelegate( parent )
{
}
KompareListViewItemDelegate::~KompareListViewItemDelegate()
{
}
void KompareListViewItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
int column = index.column();
QStyleOptionViewItemV4 changedOption = option;
if( column == COL_LINE_NO )
changedOption.displayAlignment = Qt::AlignRight;
KompareListViewItem* item = static_cast<KompareListViewItem*>( static_cast<KompareListView*>( parent() )->itemFromIndex( index ) );
item->paintCell( painter, changedOption, column );
}
QSize KompareListViewItemDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
KompareListViewItem* item = static_cast<KompareListViewItem*>( static_cast<KompareListView*>( parent() )->itemFromIndex( index ) );
QSize hint = QStyledItemDelegate::sizeHint( option, index );
return QSize( hint.width() + ITEM_MARGIN, item->height() );
}
KompareListViewItem::KompareListViewItem( KompareListView* parent, int type )
: QTreeWidgetItem( parent, type ),
m_scrollId( 0 ),
m_height( 0 ),
m_paintHeight( 0 ),
m_paintOffset( parent->nextPaintOffset() )
{
// kDebug(8104) << "Created KompareListViewItem with scroll id " << m_scrollId << endl;
}
KompareListViewItem::KompareListViewItem( KompareListView* parent, KompareListViewItem* after, int type )
: QTreeWidgetItem( parent, after, type ),
m_scrollId( after->scrollId() + after->maxHeight() ),
m_height( 0 ),
m_paintHeight( 0 ),
m_paintOffset( parent->nextPaintOffset() )
{
// kDebug(8104) << "Created KompareListViewItem with scroll id " << m_scrollId << endl;
}
KompareListViewItem::KompareListViewItem( KompareListViewItem* parent, int type )
: QTreeWidgetItem( parent, type ),
m_scrollId( 0 ),
m_height( 0 ),
m_paintHeight( 0 ),
m_paintOffset( parent->kompareListView()->nextPaintOffset() )
{
}
KompareListViewItem::KompareListViewItem( KompareListViewItem* parent, KompareListViewItem* /*after*/, int type )
: QTreeWidgetItem( parent, type ),
m_scrollId( 0 ),
m_height( 0 ),
m_paintHeight( 0 ),
m_paintOffset( parent->kompareListView()->nextPaintOffset() )
{
}
int KompareListViewItem::height() const
{
return m_height;
}
void KompareListViewItem::setHeight( int h )
{
m_height = m_paintHeight = h;
// QTreeWidget doesn't like zero height, fudge around it.
m_height -= m_paintOffset;
if( m_height <= 0 ) {
kompareListView()->setNextPaintOffset( 1 - m_height );
m_height = 1;
} else kompareListView()->setNextPaintOffset( 0 );
}
int KompareListViewItem::paintHeight() const
{
return m_paintHeight;
}
int KompareListViewItem::paintOffset() const
{
return m_paintOffset;
}
bool KompareListViewItem::isCurrent() const
{
return treeWidget()->currentItem() == this;
}
KompareListView* KompareListViewItem::kompareListView() const
{
return (KompareListView*)treeWidget();
}
void KompareListViewItem::paintCell( QPainter* p, const QStyleOptionViewItem& option, int column )
{
// Default implementation for zero-height items.
// We have to paint the item which shines through or we'll end up with glitches.
KompareListViewItem* nextItem = (KompareListViewItem*)kompareListView()->itemBelow(this);
if( nextItem ) {
QStyleOptionViewItemV4 changedOption = option;
changedOption.rect.translate( 0, height() );
nextItem->paintCell( p, changedOption, column );
}
}
KompareListViewDiffItem::KompareListViewDiffItem( KompareListView* parent, Difference* difference )
: KompareListViewItem( parent, Diff ),
m_difference( difference ),
m_sourceItem( 0L ),
m_destItem( 0L )
{
init();
}
KompareListViewDiffItem::KompareListViewDiffItem( KompareListView* parent, KompareListViewItem* after, Difference* difference )
: KompareListViewItem( parent, after, Diff ),
m_difference( difference ),
m_sourceItem( 0L ),
m_destItem( 0L )
{
init();
}
KompareListViewDiffItem::~KompareListViewDiffItem()
{
m_difference = 0;
}
void KompareListViewDiffItem::init()
{
setHeight( 0 );
setExpanded( true );
int nextPaintOffset = kompareListView()->nextPaintOffset();
m_destItem = new KompareListViewLineContainerItem( this, false );
kompareListView()->setNextPaintOffset(nextPaintOffset);
m_sourceItem = new KompareListViewLineContainerItem( this, true );
setVisibility();
}
void KompareListViewDiffItem::setVisibility()
{
m_sourceItem->setHidden( !(kompareListView()->isSource() || m_difference->applied()) );
m_destItem->setHidden( !m_sourceItem->isHidden() );
}
void KompareListViewDiffItem::applyDifference( bool apply )
{
kDebug(8104) << "KompareListViewDiffItem::applyDifference( " << apply << " )" << endl;
setVisibility();
}
int KompareListViewDiffItem::maxHeight()
{
int lines = qMax( m_difference->sourceLineCount(), m_difference->destinationLineCount() );
if( lines == 0 )
return BLANK_LINE_HEIGHT;
else
return lines * treeWidget()->fontMetrics().height();
}
KompareListViewLineContainerItem::KompareListViewLineContainerItem( KompareListViewDiffItem* parent, bool isSource )
: KompareListViewItem( parent, Container ),
m_blankLineItem( 0 ),
m_isSource( isSource )
{
// kDebug(8104) << "isSource ? " << (isSource ? " Yes!" : " No!") << endl;
setHeight( 0 );
setExpanded( true );
int lines = lineCount();
int line = lineNumber();
// kDebug(8104) << "LineNumber : " << lineNumber() << endl;
if( lines == 0 ) {
m_blankLineItem = new KompareListViewBlankLineItem( this );
return;
}
for( int i = 0; i < lines; i++, line++ ) {
new KompareListViewLineItem( this, line, lineAt( i ) );
}
}
KompareListViewLineContainerItem::~KompareListViewLineContainerItem()
{
}
KompareListViewDiffItem* KompareListViewLineContainerItem::diffItemParent() const
{
return (KompareListViewDiffItem*)parent();
}
int KompareListViewLineContainerItem::lineCount() const
{
return m_isSource ? diffItemParent()->difference()->sourceLineCount() :
diffItemParent()->difference()->destinationLineCount();
}
int KompareListViewLineContainerItem::lineNumber() const
{
return m_isSource ? diffItemParent()->difference()->sourceLineNumber() :
diffItemParent()->difference()->destinationLineNumber();
}
DifferenceString* KompareListViewLineContainerItem::lineAt( int i ) const
{
return m_isSource ? diffItemParent()->difference()->sourceLineAt( i ) :
diffItemParent()->difference()->destinationLineAt( i );
}
KompareListViewLineItem::KompareListViewLineItem( KompareListViewLineContainerItem* parent, int line, DifferenceString* text )
: KompareListViewItem( parent, Line )
{
init( line, text );
}
KompareListViewLineItem::KompareListViewLineItem( KompareListViewLineContainerItem* parent, int line, DifferenceString* text, int type )
: KompareListViewItem( parent, type )
{
init( line, text );
}
KompareListViewLineItem::~KompareListViewLineItem()
{
m_text = 0;
}
void KompareListViewLineItem::init( int line, DifferenceString* text )
{
setHeight( treeWidget()->fontMetrics().height() );
setText( COL_LINE_NO, QString::number( line ) );
setText( COL_MAIN, text->string() );
m_text = text;
}
void KompareListViewLineItem::paintCell( QPainter* p, const QStyleOptionViewItem& option, int column )
{
int width = option.rect.width();
Qt::Alignment align = option.displayAlignment;
p->setRenderHint(QPainter::Antialiasing);
p->translate(option.rect.topLeft());
p->translate(0, -paintOffset());
QColor bg( Qt::white ); // Always make the background white when it is not a real difference
if ( diffItemParent()->difference()->type() == Difference::Unchanged )
{
if ( column == COL_LINE_NO )
{
bg = QColor( Qt::lightGray );
}
}
else
{
bg = kompareListView()->settings()->colorForDifferenceType(
diffItemParent()->difference()->type(),
diffItemParent()->isCurrent(),
diffItemParent()->difference()->applied() );
}
// Paint background
p->fillRect( 0, 0, width, paintHeight(), bg );
// Paint foreground
if ( diffItemParent()->difference()->type() == Difference::Unchanged )
p->setPen( QColor( Qt::darkGray ) ); // always make normal text gray
else
p->setPen( QColor( Qt::black ) ); // make text with changes black
paintText( p, bg, column, width, align );
// Paint darker lines around selected item
if ( diffItemParent()->isCurrent() )
{
p->translate(0.5,0.5);
p->setPen( bg.dark(135) );
QTreeWidgetItem* parentItem = parent();
if ( this == parentItem->child( 0 ) )
p->drawLine( 0, 0, width, 0 );
if ( this == parentItem->child( parentItem->childCount() - 1 ) )
p->drawLine( 0, paintHeight() - 1, width, paintHeight() - 1 );
}
p->resetTransform();
}
void KompareListViewLineItem::paintText( QPainter* p, const QColor& bg, int column, int width, int align )
{
if ( column == COL_MAIN )
{
QString textChunk;
int offset = ITEM_MARGIN;
int prevValue = 0;
int charsDrawn = 0;
int chunkWidth;
QBrush changeBrush( bg, Qt::Dense3Pattern );
QBrush normalBrush( bg, Qt::SolidPattern );
QBrush brush;
if ( m_text->string().isEmpty() )
{
p->fillRect( 0, 0, width, paintHeight(), normalBrush );
return;
}
p->fillRect( 0, 0, offset, paintHeight(), normalBrush );
if ( !m_text->markerList().isEmpty() )
{
MarkerListConstIterator markerIt = m_text->markerList().begin();
MarkerListConstIterator mEnd = m_text->markerList().end();
Marker* m = *markerIt;
for ( ; markerIt != mEnd; ++markerIt )
{
m = *markerIt;
textChunk = m_text->string().mid( prevValue, m->offset() - prevValue );
// kDebug(8104) << "TextChunk = \"" << textChunk << "\"" << endl;
// kDebug(8104) << "c->offset() = " << c->offset() << endl;
// kDebug(8104) << "prevValue = " << prevValue << endl;
expandTabs(textChunk, kompareListView()->settings()->m_tabToNumberOfSpaces, charsDrawn);
charsDrawn += textChunk.length();
prevValue = m->offset();
if ( m->type() == Marker::End )
{
QFont font( p->font() );
font.setBold( true );
p->setFont( font );
// p->setPen( Qt::blue );
brush = changeBrush;
}
else
{
QFont font( p->font() );
font.setBold( false );
p->setFont( font );
// p->setPen( Qt::black );
brush = normalBrush;
}
chunkWidth = p->fontMetrics().width( textChunk );
p->fillRect( offset, 0, chunkWidth, paintHeight(), brush );
p->drawText( offset, 0,
chunkWidth, paintHeight(),
align, textChunk );
offset += chunkWidth;
}
}
if ( prevValue < m_text->string().length() )
{
// Still have to draw some string without changes
textChunk = m_text->string().mid( prevValue, qMax( 1, m_text->string().length() - prevValue ) );
expandTabs(textChunk, kompareListView()->settings()->m_tabToNumberOfSpaces, charsDrawn);
// kDebug(8104) << "TextChunk = \"" << textChunk << "\"" << endl;
QFont font( p->font() );
font.setBold( false );
p->setFont( font );
chunkWidth = p->fontMetrics().width( textChunk );
p->fillRect( offset, 0, chunkWidth, paintHeight(), normalBrush );
p->drawText( offset, 0,
chunkWidth, paintHeight(),
align, textChunk );
offset += chunkWidth;
}
p->fillRect( offset, 0, width - offset, paintHeight(), normalBrush );
}
else
{
p->fillRect( 0, 0, width, paintHeight(), bg );
p->drawText( ITEM_MARGIN, 0,
width - ITEM_MARGIN, paintHeight(),
align, text( column ) );
}
}
void KompareListViewLineItem::expandTabs(QString& text, int tabstop, int startPos) const
{
int index;
while((index = text.indexOf(QChar(9)))!= -1)
text.replace(index, 1, QString(tabstop-((startPos+index)%tabstop),' '));
}
KompareListViewDiffItem* KompareListViewLineItem::diffItemParent() const
{
KompareListViewLineContainerItem* p = (KompareListViewLineContainerItem*)parent();
return p->diffItemParent();
}
KompareListViewBlankLineItem::KompareListViewBlankLineItem( KompareListViewLineContainerItem* parent )
: KompareListViewLineItem( parent, 0, new DifferenceString(), Blank )
{
setHeight( BLANK_LINE_HEIGHT );
}
void KompareListViewBlankLineItem::paintText( QPainter* p, const QColor& bg, int column, int width, int /* align */ )
{
if ( column == COL_MAIN )
{
QBrush normalBrush( bg, Qt::SolidPattern );
p->fillRect( 0, 0, width, paintHeight(), normalBrush );
}
}
KompareListViewHunkItem::KompareListViewHunkItem( KompareListView* parent, DiffHunk* hunk, bool zeroHeight )
: KompareListViewItem( parent, Hunk ),
m_zeroHeight( zeroHeight ),
m_hunk( hunk )
{
setHeight( maxHeight() );
setFlags( flags() & ~Qt::ItemIsSelectable );
}
KompareListViewHunkItem::KompareListViewHunkItem( KompareListView* parent, KompareListViewItem* after, DiffHunk* hunk, bool zeroHeight )
: KompareListViewItem( parent, after, Hunk ),
m_zeroHeight( zeroHeight ),
m_hunk( hunk )
{
setHeight( maxHeight() );
setFlags( flags() & ~Qt::ItemIsSelectable );
}
KompareListViewHunkItem::~KompareListViewHunkItem()
{
m_hunk = 0;
}
int KompareListViewHunkItem::maxHeight()
{
if( m_zeroHeight ) {
return 0;
} else if( m_hunk->function().isEmpty() ) {
return HUNK_LINE_HEIGHT;
} else {
return treeWidget()->fontMetrics().height();
}
}
void KompareListViewHunkItem::paintCell( QPainter* p, const QStyleOptionViewItem& option, int column )
{
if( m_zeroHeight ) {
KompareListViewItem::paintCell( p, option, column );
} else {
int x = option.rect.left();
int y = option.rect.top() - paintOffset();
int width = option.rect.width();
Qt::Alignment align = option.displayAlignment;
p->fillRect( x, y, width, paintHeight(), QColor( Qt::lightGray ) ); // Hunk headers should be lightgray
p->setPen( QColor( Qt::black ) ); // Text color in hunk should be black
if( column == COL_MAIN ) {
p->drawText( x + ITEM_MARGIN, y, width - ITEM_MARGIN, paintHeight(),
align, m_hunk->function() );
}
}
}
#include "komparelistview.moc"

View file

@ -0,0 +1,271 @@
/***************************************************************************
komparelistview.h
-----------------
begin : Sun Mar 4 2001
Copyright 2001-2004,2009 Otto Bruggeman <bruggie@gmail.com>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2004 Jeff Snyder <jeff@caffeinated.me.uk>
Copyright 2011 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#ifndef KOMPARELISTVIEW_H
#define KOMPARELISTVIEW_H
#include <QHash>
#include <QLabel>
#include <QResizeEvent>
#include <QWheelEvent>
#include <QVBoxLayout>
#include <QMouseEvent>
#include <QFrame>
#include <QTreeWidget>
#include <QStyledItemDelegate>
namespace Diff2 {
class DiffModel;
class DiffHunk;
class Difference;
class DifferenceString;
}
class ViewSettings;
class KompareSplitter;
class KompareListView;
class KompareListViewItem;
class KompareListViewItemDelegate;
class KompareListViewDiffItem;
class KompareListViewLineContainerItem;
class KompareListView : public QTreeWidget
{
Q_OBJECT
friend class KompareListViewItemDelegate;
public:
KompareListView( bool isSource, ViewSettings* settings, QWidget* parent, const char* name = 0 );
virtual ~KompareListView();
KompareListViewItem* itemAtIndex( int i );
int firstVisibleDifference();
int lastVisibleDifference();
QRect itemRect( int i );
int minScrollId();
int maxScrollId();
int contentsHeight();
int contentsWidth();
int visibleHeight();
int visibleWidth();
int contentsX();
int contentsY();
int nextPaintOffset() const;
void setNextPaintOffset(int offset);
bool isSource() const { return m_isSource; };
ViewSettings* settings() const { return m_settings; };
void setSelectedDifference( const Diff2::Difference* diff, bool scroll );
public slots:
void slotSetSelection( const Diff2::DiffModel* model, const Diff2::Difference* diff );
void slotSetSelection( const Diff2::Difference* diff );
void setXOffset( int x );
void scrollToId( int id );
int scrollId();
void slotApplyDifference( bool apply );
void slotApplyAllDifferences( bool apply );
void slotApplyDifference( const Diff2::Difference* diff, bool apply );
signals:
void differenceClicked( const Diff2::Difference* diff );
void applyDifference( bool apply );
void resized();
protected:
virtual void wheelEvent( QWheelEvent* e );
virtual void resizeEvent( QResizeEvent* e );
virtual void mousePressEvent ( QMouseEvent * e );
virtual void mouseDoubleClickEvent ( QMouseEvent* );
virtual void mouseReleaseEvent ( QMouseEvent * ) {};
virtual void mouseMoveEvent ( QMouseEvent * ) {};
private:
QRect totalVisualItemRect( QTreeWidgetItem* item );
KompareListViewDiffItem* diffItemAt( const QPoint& pos );
void renumberLines( void );
QList<KompareListViewDiffItem*> m_items;
QHash<const Diff2::Difference*, KompareListViewDiffItem*> m_itemDict;
bool m_isSource;
ViewSettings* m_settings;
int m_scrollId;
int m_maxMainWidth;
const Diff2::DiffModel* m_selectedModel;
const Diff2::Difference* m_selectedDifference;
int m_nextPaintOffset;
};
class KompareListViewFrame : public QFrame
{
Q_OBJECT
public:
KompareListViewFrame( bool isSource, ViewSettings* settings, KompareSplitter* parent, const char* name = 0 );
virtual ~KompareListViewFrame() {};
KompareListView* view() { return &m_view; };
public slots:
void slotSetModel( const Diff2::DiffModel* model );
private:
KompareListView m_view;
QLabel m_label;
QVBoxLayout m_layout;
};
class KompareListViewItemDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
KompareListViewItemDelegate( QObject* parent );
virtual ~KompareListViewItemDelegate();
virtual void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
};
class KompareListViewItem : public QTreeWidgetItem
{
public:
KompareListViewItem( KompareListView* parent, int type );
KompareListViewItem( KompareListView* parent, KompareListViewItem* after, int type );
KompareListViewItem( KompareListViewItem* parent, int type );
KompareListViewItem( KompareListViewItem* parent, KompareListViewItem* after, int type );
virtual void paintCell( QPainter* p, const QStyleOptionViewItem& option, int column );
void repaint();
int height() const;
void setHeight( int h );
int paintHeight() const;
int paintOffset() const;
bool isCurrent() const;
int scrollId() const { return m_scrollId; };
virtual int maxHeight() = 0;
KompareListView* kompareListView() const;
enum ListViewItemType { Diff = QTreeWidgetItem::UserType + 1, Container = QTreeWidgetItem::UserType + 2, Line = QTreeWidgetItem::UserType + 3, Blank = QTreeWidgetItem::UserType + 4, Hunk = QTreeWidgetItem::UserType + 5 };
private:
int m_scrollId;
int m_height;
int m_paintHeight;
int m_paintOffset;
};
class KompareListViewDiffItem : public KompareListViewItem
{
public:
KompareListViewDiffItem( KompareListView* parent, Diff2::Difference* difference );
KompareListViewDiffItem( KompareListView* parent, KompareListViewItem* after, Diff2::Difference* difference );
~KompareListViewDiffItem();
void applyDifference( bool apply );
Diff2::Difference* difference() { return m_difference; };
virtual int maxHeight();
private:
void init();
void setVisibility();
private:
Diff2::Difference* m_difference;
KompareListViewLineContainerItem* m_sourceItem;
KompareListViewLineContainerItem* m_destItem;
};
class KompareListViewLineItem;
class KompareListViewBlankLineItem;
class KompareListViewLineContainerItem : public KompareListViewItem
{
public:
KompareListViewLineContainerItem( KompareListViewDiffItem* parent, bool isSource );
~KompareListViewLineContainerItem();
virtual int maxHeight() { return 0; }
KompareListViewDiffItem* diffItemParent() const;
private:
int lineCount() const;
int lineNumber() const;
Diff2::DifferenceString* lineAt( int i ) const;
private:
KompareListViewBlankLineItem* m_blankLineItem;
bool m_isSource;
};
class KompareListViewLineItem : public KompareListViewItem
{
public:
KompareListViewLineItem( KompareListViewLineContainerItem* parent, int line, Diff2::DifferenceString* text );
KompareListViewLineItem( KompareListViewLineContainerItem* parent, int line, Diff2::DifferenceString* text, int type );
~KompareListViewLineItem();
virtual int maxHeight() { return 0; }
virtual void paintCell( QPainter* p, const QStyleOptionViewItem& option, int column );
KompareListViewDiffItem* diffItemParent() const;
protected:
virtual void paintText( QPainter* p, const QColor& bg, int column, int width, int align );
private:
void init( int line, Diff2::DifferenceString* text );
void expandTabs(QString& text, int tabstop, int startPos = 0) const;
private:
Diff2::DifferenceString* m_text;
};
class KompareListViewBlankLineItem : public KompareListViewLineItem
{
public:
KompareListViewBlankLineItem( KompareListViewLineContainerItem* parent );
protected:
virtual void paintText( QPainter* p, const QColor& bg, int column, int width, int align );
};
class KompareListViewHunkItem : public KompareListViewItem
{
public:
KompareListViewHunkItem( KompareListView* parent, Diff2::DiffHunk* hunk, bool zeroHeight = false );
KompareListViewHunkItem( KompareListView* parent, KompareListViewItem* after, Diff2::DiffHunk* hunk, bool zeroHeight= false );
~KompareListViewHunkItem();
virtual void paintCell( QPainter* p, const QStyleOptionViewItem& option, int column );
virtual int maxHeight();
private:
bool m_zeroHeight;
Diff2::DiffHunk* m_hunk;
};
#endif

View file

@ -0,0 +1,72 @@
[Desktop Entry]
GenericComment=A part to graphically show the difference between 2 files
Name=KomparePart
Name[af]=K-vergelyk-deel
Name[ast]=KomparePart
Name[bg]=KomparePart
Name[br]=KomparePart
Name[bs]=KomparePart
Name[ca]=KomparePart
Name[ca@valencia]=KomparePart
Name[cs]=KomparePart
Name[cy]=KomparePart
Name[da]=KomparePart
Name[de]=Einbettungsfähige Komponente von Kompare
Name[el]=KomparePart
Name[en_GB]=KomparePart
Name[eo]=Komparo-parto
Name[es]=KomparePart
Name[et]=KomparePart
Name[eu]=KomparePart
Name[fi]=KomparePart
Name[fr]=Composant de Kompare
Name[ga]=KomparePart
Name[gl]=KomparePart
Name[he]=רכיב Kompare
Name[hr]=KomparePart
Name[hu]=KomparePart
Name[is]=KomparePart
Name[it]=KomparePart
Name[ja]=KomparePart
Name[kk]=KomparePart
Name[km]=KomparePart
Name[ko]=KomparePart
Name[lt]=KomparePart
Name[lv]=KomparePart
Name[mr]=-
Name[ms]=KomparePart
Name[nb]=KomparePart
Name[nds]=KomparePart
Name[ne]=KomparePart
Name[nl]=KomparePart
Name[nn]=KomparePart
Name[pa]=KomparePart
Name[pl]=Moduł Kompare
Name[pt]=KomparePart
Name[pt_BR]=KomparePart
Name[ro]=Componentă Kompare
Name[ru]=Компонент утилиты сравнения файлов
Name[sk]=KomparePart
Name[sl]=KomparePart
Name[sq]=KomparePart
Name[sr]=Кпоређење део
Name[sr@ijekavian]=Кпоређење део
Name[sr@ijekavianlatin]=Kpoređenje deo
Name[sr@latin]=Kpoređenje deo
Name[sv]=Kompare-del
Name[ta]=
Name[tg]=Қисмати утилитҳои баробаркунии файлҳо
Name[tr]=KomparePart
Name[ug]=KomparePart
Name[uk]=KomparePart
Name[vi]=KomparePart
Name[xh]=KomparePart
Name[x-test]=xxKomparePartxx
Name[zh_CN]=KomparePart
Name[zh_TW]=KomparePart
MimeType=text/x-patch;
ServiceTypes=Kompare/ViewPart,KParts/ReadWritePart,KParts/ReadOnlyPart
X-KDE-Library=komparepart
Type=Service
Icon=kompare
InitialPreference=10

View file

@ -0,0 +1,48 @@
<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
<kpartgui name="kompare_part" version="6">
<MenuBar>
<Menu name="file"><text>&amp;File</text>
<Action name="file_save"/>
<Action name="file_save_all"/>
<Action name="file_save_as"/>
<Action name="file_save_diff"/>
<Separator/>
<Action name="file_refreshdiff"/>
<Action name="file_swap"/>
<Action name="file_diffstats"/>
<Separator/>
<Action name="file_print"/>
<Action name="file_print_preview"/>
</Menu>
<Menu name="difference"><text>&amp;Difference</text>
<Action name="difference_unapplyall"/>
<Action name="difference_unapply"/>
<Action name="difference_apply"/>
<Action name="difference_applyall"/>
<Separator/>
<Action name="difference_previousfile"/>
<Action name="difference_nextfile"/>
<Separator/>
<Action name="difference_previous"/>
<Action name="difference_next"/>
</Menu>
<Menu name="settings"><text>&amp;Settings</text>
<Action name="options_configure"/>
</Menu>
</MenuBar>
<ToolBar name="mainToolBar">
<Action name="file_save"/>
<Action name="file_save_all"/>
<Separator/>
<Action name="difference_previousfile"/>
<Action name="difference_nextfile"/>
<Separator/>
<Action name="difference_previous"/>
<Action name="difference_next"/>
<Separator/>
<Action name="difference_unapplyall"/>
<Action name="difference_unapply"/>
<Action name="difference_apply"/>
<Action name="difference_applyall"/>
</ToolBar>
</kpartgui>

View file

@ -0,0 +1,160 @@
/***************************************************************************
kompareprefdlg.cpp
------------------
begin : Sun Mar 4 2001
Copyright 2001-2009 Otto Bruggeman <bruggie@gmail.com>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2007 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#include "kompareprefdlg.h"
#include <kdebug.h>
#include <kiconloader.h>
#include <klocale.h>
#include <ktabwidget.h>
#include <ktoolinvocation.h>
#include "diffpage.h"
#include "viewpage.h"
// implementation
KomparePrefDlg::KomparePrefDlg( ViewSettings* viewSets, DiffSettings* diffSets ) : KPageDialog( 0 )
{
setFaceType( KPageDialog::List );
setWindowTitle( i18n( "Preferences" ) );
setButtons( Help|Default|Ok|Apply|Cancel );
setDefaultButton( Ok );
setModal( true );
showButtonSeparator( true );
// ok i need some stuff in that pref dlg...
//setIconListAllVisible(true);
m_viewPage = new ViewPage();
KPageWidgetItem *item = addPage( m_viewPage, i18n( "View" ) );
item->setIcon( KIcon( "preferences-desktop-theme" ) );
item->setHeader( i18n( "View Settings" ) );
m_viewPage->setSettings( viewSets );
m_diffPage = new DiffPage();
item = addPage( m_diffPage, i18n( "Diff" ) );
item->setIcon( KIcon( "text-x-patch" ) );
item->setHeader( i18n( "Diff Settings" ) );
m_diffPage->setSettings( diffSets );
// frame = addVBoxPage( i18n( "" ), i18n( "" ), UserIcon( "" ) );
connect( this, SIGNAL(defaultClicked()), SLOT(slotDefault()) );
connect( this, SIGNAL(helpClicked()), SLOT(slotHelp()) );
connect( this, SIGNAL(applyClicked()), SLOT(slotApply()) );
connect( this, SIGNAL(okClicked()), SLOT(slotOk()) );
connect( this, SIGNAL(cancelClicked()), SLOT(slotCancel()) );
adjustSize();
}
KomparePrefDlg::~KomparePrefDlg()
{
}
/** No descriptions */
void KomparePrefDlg::slotDefault()
{
kDebug(8103) << "SlotDefault called -> Settings should be restored to defaults..." << endl;
// restore all defaults in the options...
m_viewPage->setDefaults();
m_diffPage->setDefaults();
}
/** No descriptions */
void KomparePrefDlg::slotHelp()
{
// figure out the current active page
QWidget* currentpage = currentPage()->widget();
if ( dynamic_cast<ViewPage*>(currentpage) )
{
// figure out the active tab
int currentTab = static_cast<ViewPage*>(currentpage)->m_tabWidget->currentIndex();
switch ( currentTab )
{
case 0:
KToolInvocation::invokeHelp( "appearance" );
break;
case 1:
KToolInvocation::invokeHelp( "fonts" );
break;
default:
KToolInvocation::invokeHelp( "view-settings" );
}
}
else if ( dynamic_cast<DiffPage*>(currentpage) )
{
// figure out the active tab
int currentTab = static_cast<DiffPage*>(currentpage)->m_tabWidget->currentIndex();
switch ( currentTab )
{
case 0:
KToolInvocation::invokeHelp( "diff" );
break;
case 1:
KToolInvocation::invokeHelp( "diff-format" );
break;
case 2:
KToolInvocation::invokeHelp( "options" );
break;
case 3:
KToolInvocation::invokeHelp( "exclude" );
break;
default:
KToolInvocation::invokeHelp( "diff-settings" );
}
}
else // Fallback since we had not added the code for the page/tab or forgotten about it
KToolInvocation::invokeHelp( "configure-preferences" );
}
/** No descriptions */
void KomparePrefDlg::slotApply()
{
kDebug(8103) << "SlotApply called -> Settings should be applied..." << endl;
// well apply the settings that are currently selected
m_viewPage->apply();
m_diffPage->apply();
emit configChanged();
}
/** No descriptions */
void KomparePrefDlg::slotOk()
{
kDebug(8103) << "SlotOk called -> Settings should be applied..." << endl;
// Apply the settings that are currently selected
m_viewPage->apply();
m_diffPage->apply();
//accept();
}
/** No descriptions */
void KomparePrefDlg::slotCancel()
{
// discard the current settings and use the present ones
m_viewPage->restore();
m_diffPage->restore();
//reject();
}
#include "kompareprefdlg.moc"

View file

@ -0,0 +1,56 @@
/***************************************************************************
kompareprefdlg.h
----------------
begin : Sun Mar 4 2001
Copyright 2001-2009 Otto Bruggeman <bruggie@gmail.com>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2007 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#ifndef KOMPAREPREFDLG_H
#define KOMPAREPREFDLG_H
#include <kpagedialog.h>
class DiffPage;
class DiffSettings;
class ViewPage;
class ViewSettings;
class KomparePrefDlg : public KPageDialog
{
Q_OBJECT
public:
KomparePrefDlg( ViewSettings*, DiffSettings* );
~KomparePrefDlg();
protected slots:
/** No descriptions */
virtual void slotOk();
/** No descriptions */
virtual void slotApply();
/** No descriptions */
virtual void slotHelp();
/** No descriptions */
virtual void slotDefault();
/** No descriptions */
virtual void slotCancel();
signals:
void configChanged();
private:
ViewPage* m_viewPage;
DiffPage* m_diffPage;
};
#endif

View file

@ -0,0 +1,48 @@
/***************************************************************************
komparesaveoptionsbase.cpp
--------------------------
Converted from komparesaveoptionsbase.ui using uic3, Tue Dec 4 2007
Copyright 2001-2003 Otto Bruggeman <otto.bruggeman@home.nl>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2007-2011 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
** 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.
***************************************************************************/
#include "komparesaveoptionsbase.h"
#include <QtCore/QVariant>
/*
* Constructs a KompareSaveOptionsBase as a child of 'parent', with the
* name 'name' and widget flags set to 'f'.
*/
KompareSaveOptionsBase::KompareSaveOptionsBase(QWidget* parent, Qt::WindowFlags fl)
: QWidget(parent, fl)
{
setupUi(this);
}
/*
* Destroys the object and frees any allocated resources
*/
KompareSaveOptionsBase::~KompareSaveOptionsBase()
{
// no need to delete child widgets, Qt does it all for us
}
/*
* Sets the strings of the subwidgets using the current
* language.
*/
void KompareSaveOptionsBase::languageChange()
{
retranslateUi(this);
}

View file

@ -0,0 +1,37 @@
/***************************************************************************
komparesaveoptionsbase.h
------------------------
Converted from komparesaveoptionsbase.ui using uic3, Tue Dec 4 2007
Copyright 2001-2003 Otto Bruggeman <otto.bruggeman@home.nl>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2007-2011 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
** 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.
***************************************************************************/
#ifndef KOMPARESAVEOPTIONSBASE_H
#define KOMPARESAVEOPTIONSBASE_H
#include <QtCore/QVariant>
#include "ui_komparesaveoptionsbase.h"
class KompareSaveOptionsBase : public QWidget, public Ui::KompareSaveOptionsBase
{
Q_OBJECT
public:
explicit KompareSaveOptionsBase(QWidget* parent = 0, Qt::WindowFlags fl = 0);
~KompareSaveOptionsBase();
protected slots:
virtual void languageChange();
};
#endif // KOMPARESAVEOPTIONSBASE_H

View file

@ -0,0 +1,284 @@
<ui version="4.0" stdsetdef="1" >
<class>KompareSaveOptionsBase</class>
<widget class="QWidget" name="KompareSaveOptionsBase" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>558</width>
<height>399</height>
</rect>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item rowspan="1" row="1" column="0" colspan="2" >
<widget class="QGroupBox" name="GroupBox2" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>1</hsizetype>
<vsizetype>1</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title" >
<string>Run Diff In</string>
</property>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>11</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="KUrlRequester" name="m_directoryRequester" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item rowspan="1" row="2" column="0" colspan="2" >
<widget class="QGroupBox" name="m_CommandLineGB" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>3</hsizetype>
<vsizetype>3</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title" >
<string>Command Line</string>
</property>
<property name="alignment" >
<set>Qt::AlignVCenter|Qt::AlignLeft</set>
</property>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>11</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="m_CommandLineLabel" >
<property name="text" >
<string>cd dir &amp;&amp; diff -udHprNa -- source destination</string>
</property>
<property name="wordWrap" >
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="1" >
<widget class="QGroupBox" name="m_OptionsGB" >
<property name="title" >
<string>Options</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>11</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QCheckBox" name="m_SmallerChangesCB" >
<property name="text" >
<string>Look for smaller changes</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_LargeFilesCB" >
<property name="text" >
<string>Optimize for large files</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_IgnoreCaseCB" >
<property name="text" >
<string>Ignore changes in case</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_ExpandTabsCB" >
<property name="text" >
<string>Expand tabs to spaces</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_IgnoreEmptyLinesCB" >
<property name="text" >
<string>Ignore added or removed empty lines</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_IgnoreWhiteSpaceCB" >
<property name="text" >
<string>Ignore changes in whitespace</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_FunctionNamesCB" >
<property name="text" >
<string>Show function names</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_RecursiveCB" >
<property name="text" >
<string>Compare folders recursively</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_NewFilesCB" >
<property name="text" >
<string>Treat new files as empty</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
<property name="tristate" >
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="0" >
<widget class="QGroupBox" name="m_FormatGB" >
<property name="title" >
<string>Format</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>11</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QRadioButton" name="m_ContextRB" >
<property name="text" >
<string>Context</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="m_EdRB" >
<property name="text" >
<string>Ed</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="m_NormalRB" >
<property name="text" >
<string>Normal</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="m_RCSRB" >
<property name="text" >
<string>RCS</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="m_UnifiedRB" >
<property name="text" >
<string>Unified</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="m_SideBySideRB" >
<property name="text" >
<string>Side-by-side</string>
</property>
<property name="checked" >
<bool>false</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="m_ContextLinesLabel" >
<property name="text" >
<string>Number of context lines:</string>
</property>
<property name="wordWrap" >
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="m_ContextLinesSB" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="maximum" >
<number>65535</number>
</property>
<property name="value" >
<number>3</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</ui>

View file

@ -0,0 +1,225 @@
/***************************************************************************
komparesaveoptionswidget.cpp
----------------------------
begin : Sun Mar 4 2001
Copyright 2001-2003 Otto Bruggeman <otto.bruggeman@home.nl>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2007-2011 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#include "komparesaveoptionswidget.h"
#include <QtGui/QCheckBox>
#include <QtGui/QLabel>
#include <QtGui/QRadioButton>
#include <QtGui/QSpinBox>
#include <kdebug.h>
#include <kfiledialog.h>
#include <kurlrequester.h>
#include "diffsettings.h"
KompareSaveOptionsWidget::KompareSaveOptionsWidget( QString source, QString destination,
DiffSettings * settings, QWidget * parent )
: KompareSaveOptionsBase( parent )
, m_source( source )
, m_destination( destination )
, m_FormatBG( new QButtonGroup(this) )
{
setObjectName("save options");
m_settings = settings;
m_directoryRequester->setMode(
KFile::ExistingOnly | KFile::Directory | KFile::LocalOnly );
KUrl sourceURL;
KUrl destinationURL;
sourceURL.setPath( source );
destinationURL.setPath( destination );
// Find a common root.
KUrl root( sourceURL );
while( root.isValid() && !root.isParentOf( destinationURL ) && root != root.upUrl() ) {
root = root.upUrl();
}
// If we found a common root, change to that directory and
// strip the common part from source and destination.
if( root.isValid() && root != root.upUrl() ) {
m_directoryRequester->setUrl( root.url() );
}
connect( m_SmallerChangesCB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
connect( m_LargeFilesCB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
connect( m_IgnoreCaseCB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
connect( m_ExpandTabsCB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
connect( m_IgnoreEmptyLinesCB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
connect( m_IgnoreWhiteSpaceCB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
connect( m_FunctionNamesCB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
connect( m_RecursiveCB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
connect( m_NewFilesCB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
connect( m_ContextRB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
connect( m_EdRB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
connect( m_NormalRB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
connect( m_RCSRB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
connect( m_UnifiedRB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
connect( m_SideBySideRB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
connect( m_ContextLinesSB, SIGNAL(valueChanged(int)), SLOT(updateCommandLine()) );
connect( m_directoryRequester, SIGNAL(textChanged(const QString&)), SLOT(updateCommandLine()) );
m_FormatBG->setExclusive(true);
m_FormatBG->addButton(m_ContextRB, Kompare::Context);
m_FormatBG->addButton(m_EdRB, Kompare::Ed);
m_FormatBG->addButton(m_NormalRB, Kompare::Normal);
m_FormatBG->addButton(m_UnifiedRB, Kompare::Unified);
m_FormatBG->addButton(m_RCSRB, Kompare::RCS);
m_FormatBG->addButton(m_SideBySideRB, Kompare::SideBySide);
loadOptions();
}
KompareSaveOptionsWidget::~KompareSaveOptionsWidget()
{
}
QString KompareSaveOptionsWidget::directory() const
{
return KUrl( m_directoryRequester->url() ).toLocalFile();
}
void KompareSaveOptionsWidget::updateCommandLine()
{
QString cmdLine = "diff";
QString options = "";
switch( static_cast<Kompare::Format>( m_FormatBG->checkedId() ) ) {
case Kompare::Unified :
cmdLine += " -U " + QString::number( m_ContextLinesSB->value() );
break;
case Kompare::Context :
cmdLine += " -C " + QString::number( m_ContextLinesSB->value() );
break;
case Kompare::RCS :
options += 'n';
break;
case Kompare::Ed :
options += 'e';
break;
case Kompare::SideBySide:
options += 'y';
break;
case Kompare::Normal :
case Kompare::UnknownFormat :
default:
break;
}
if ( m_SmallerChangesCB->isChecked() ) {
options += 'd';
}
if ( m_LargeFilesCB->isChecked() ) {
options += 'H';
}
if ( m_IgnoreCaseCB->isChecked() ){
options += 'i';
}
if ( m_ExpandTabsCB->isChecked() ) {
options += 't';
}
if ( m_IgnoreEmptyLinesCB->isChecked() ) {
options += 'B';
}
if ( m_IgnoreWhiteSpaceCB->isChecked() ) {
options += 'b';
}
if ( m_FunctionNamesCB->isChecked() ) {
options += 'p';
}
// if ( ) {
// cmdLine += " -w";
// }
if ( m_RecursiveCB->isChecked() ) {
options += 'r';
}
if( m_NewFilesCB->isChecked() ) {
options += 'N';
}
// if( m_AllTextCB->isChecked() ) {
// options += 'a';
// }
if( options.length() > 0 ) {
cmdLine += " -" + options;
}
cmdLine += " -- ";
cmdLine += constructRelativePath( m_directoryRequester->url().pathOrUrl(), m_source );
cmdLine += ' ';
cmdLine += constructRelativePath( m_directoryRequester->url().pathOrUrl(), m_destination );
m_CommandLineLabel->setText( cmdLine );
}
void KompareSaveOptionsWidget::loadOptions()
{
m_SmallerChangesCB->setChecked ( m_settings->m_createSmallerDiff );
m_LargeFilesCB->setChecked ( m_settings->m_largeFiles );
m_IgnoreCaseCB->setChecked ( m_settings->m_ignoreChangesInCase );
m_ExpandTabsCB->setChecked ( m_settings->m_convertTabsToSpaces );
m_IgnoreEmptyLinesCB->setChecked( m_settings->m_ignoreEmptyLines );
m_IgnoreWhiteSpaceCB->setChecked( m_settings->m_ignoreWhiteSpace );
m_FunctionNamesCB->setChecked ( m_settings->m_showCFunctionChange );
m_RecursiveCB->setChecked ( m_settings->m_recursive );
m_NewFilesCB->setChecked ( m_settings->m_newFiles );
// m_AllTextCB->setChecked ( m_settings->m_allText );
m_ContextLinesSB->setValue ( m_settings->m_linesOfContext );
m_FormatBG->button(m_settings->m_format)->setChecked(true);
updateCommandLine();
}
void KompareSaveOptionsWidget::saveOptions()
{
m_settings->m_createSmallerDiff = m_SmallerChangesCB->isChecked();
m_settings->m_largeFiles = m_LargeFilesCB->isChecked();
m_settings->m_ignoreChangesInCase = m_IgnoreCaseCB->isChecked();
m_settings->m_convertTabsToSpaces = m_ExpandTabsCB->isChecked();
m_settings->m_ignoreEmptyLines = m_IgnoreEmptyLinesCB->isChecked();
m_settings->m_ignoreWhiteSpace = m_IgnoreWhiteSpaceCB->isChecked();
m_settings->m_showCFunctionChange = m_FunctionNamesCB->isChecked();
m_settings->m_recursive = m_RecursiveCB->isChecked();
m_settings->m_newFiles = m_NewFilesCB->isChecked();
// m_settings->m_allText = m_AllTextCB->isChecked();
m_settings->m_linesOfContext = m_ContextLinesSB->value();
m_settings->m_format = static_cast<Kompare::Format>( m_FormatBG->checkedId() );
}
#include "komparesaveoptionswidget.moc"

View file

@ -0,0 +1,51 @@
/***************************************************************************
komparesaveoptionswidget.h
--------------------------
begin : Sun Mar 4 2001
Copyright 2001-2003 Otto Bruggeman <otto.bruggeman@home.nl>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#ifndef KOMPARESAVEOPTIONSWIDGET_H
#define KOMPARESAVEOPTIONSWIDGET_H
#include <kurl.h>
#include <kompare.h>
#include "komparesaveoptionsbase.h"
class DiffSettings;
class QButtonGroup;
class KompareSaveOptionsWidget : public KompareSaveOptionsBase, public KompareFunctions
{
Q_OBJECT
public:
KompareSaveOptionsWidget( QString source, QString destination, DiffSettings* settings, QWidget* parent );
~KompareSaveOptionsWidget();
void saveOptions();
QString directory() const;
protected slots:
void updateCommandLine();
private:
void loadOptions();
DiffSettings* m_settings;
QString m_source;
QString m_destination;
QButtonGroup* m_FormatBG;
};
#endif

View file

@ -0,0 +1,492 @@
/**************************************************************************
** komparesplitter.cpp
** -------------------
** begin : Wed Jan 14 2004
** Copyright 2004-2005 Jeff Snyder <jeff-webcvsspam@caffeinated.me.uk>
** Copyright 2007-2011 Kevin Kofler <kevin.kofler@chello.at>
***************************************************************************/
/**************************************************************************
**
** 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.
**
***************************************************************************/
// associated header
#include "komparesplitter.h"
// qt
#include <QtGui/QStyle>
#include <QtCore/QString>
#include <QtCore/QTimer>
#include <QtGui/QScrollBar>
#include <QtCore/QMap>
#include <QtGui/QSplitter>
#include <QtGui/QApplication>
#include <QtGui/QPainter>
#include <QtGui/QPixmap>
#include <QtGui/QKeyEvent>
#include <QtGui/QGridLayout>
#include <QtGui/QResizeEvent>
#include <QtCore/QChildEvent>
#include <QtCore/QEvent>
#include <QtGui/QWheelEvent>
// kde
#include <kdebug.h>
#include <kapplication.h>
#include <kglobalsettings.h>
// kompare
#include "komparelistview.h"
#include "viewsettings.h"
#include "kompareconnectwidget.h"
#include "diffmodel.h"
#include "difference.h"
using namespace Diff2;
KompareSplitter::KompareSplitter( ViewSettings *settings, QWidget *parent ) :
QSplitter( Qt::Horizontal, parent ),
m_settings( settings )
{
QFrame *scrollFrame = static_cast<QFrame *>(parent);
// Set up the scrollFrame
scrollFrame->setFrameStyle( QFrame::NoFrame | QFrame::Plain );
scrollFrame->setLineWidth(scrollFrame->style()->pixelMetric(QStyle::PM_DefaultFrameWidth));
QGridLayout *pairlayout = new QGridLayout(scrollFrame);
pairlayout->setSpacing(0);
pairlayout->setContentsMargins( 0, 0, 0, 0 );
m_vScroll = new QScrollBar( Qt::Vertical, scrollFrame );
pairlayout->addWidget( m_vScroll, 0, 1 );
m_hScroll = new QScrollBar( Qt::Horizontal, scrollFrame );
pairlayout->addWidget( m_hScroll, 1, 0 );
new KompareListViewFrame(true, m_settings, this, "source");
new KompareListViewFrame(false, m_settings, this, "destination");
pairlayout->addWidget( this, 0, 0 );
// set up our looks
setLineWidth( style()->pixelMetric( QStyle::PM_DefaultFrameWidth ) );
setHandleWidth(50);
setChildrenCollapsible( false );
setFrameStyle( QFrame::NoFrame );
setSizePolicy( QSizePolicy (QSizePolicy::Ignored, QSizePolicy::Ignored ));
setOpaqueResize( true );
setFocusPolicy( Qt::WheelFocus );
connect( this, SIGNAL(configChanged()), SLOT(slotConfigChanged()) );
connect( this, SIGNAL(configChanged()), SLOT(slotDelayedRepaintHandles()) );
connect( this, SIGNAL(configChanged()), SLOT(slotDelayedUpdateScrollBars()) );
// scrolling
connect( m_vScroll, SIGNAL(valueChanged(int)), SLOT(slotScrollToId(int)) );
connect( m_vScroll, SIGNAL(sliderMoved(int)), SLOT(slotScrollToId(int)) );
connect( m_hScroll, SIGNAL(valueChanged(int)), SIGNAL(setXOffset(int)) );
connect( m_hScroll, SIGNAL(sliderMoved(int)), SIGNAL(setXOffset(int)) );
m_scrollTimer=new QTimer(this);
m_restartTimer = false;
connect (m_scrollTimer, SIGNAL(timeout()), SLOT(timerTimeout()) );
// we need to receive childEvents now so that d->list is ready for when
// slotSetSelection(...) arrives
kapp->sendPostedEvents(this, QEvent::ChildAdded);
// init stuff
slotUpdateScrollBars();
}
KompareSplitter::~KompareSplitter()
{
}
QSplitterHandle* KompareSplitter::createHandle()
{
return new KompareConnectWidgetFrame(m_settings, this);
}
void KompareSplitter::slotDelayedRepaintHandles()
{
QTimer::singleShot(0, this, SLOT(slotRepaintHandles()));
}
void KompareSplitter::slotRepaintHandles()
{
const int end = count();
for ( int i = 1; i < end; ++i )
handle(i)->update();
}
void KompareSplitter::timerTimeout()
{
if ( m_restartTimer )
m_restartTimer = false;
else
m_scrollTimer->stop();
slotDelayedRepaintHandles();
emit scrollViewsToId( m_scrollTo );
slotRepaintHandles();
m_vScroll->setValue( m_scrollTo );
}
void KompareSplitter::slotScrollToId( int id )
{
m_scrollTo = id;
if( m_restartTimer )
return;
if( m_scrollTimer->isActive() )
{
m_restartTimer = true;
}
else
{
emit scrollViewsToId( id );
slotRepaintHandles();
m_vScroll->setValue( id );
m_scrollTimer->start( 30 );
}
}
void KompareSplitter::slotDelayedUpdateScrollBars()
{
QTimer::singleShot( 0, this, SLOT( slotUpdateScrollBars() ) );
}
void KompareSplitter::slotUpdateScrollBars()
{
const int end = count();
for ( int i = 0; i < end; ++i ) {
KompareListView* lv = listView(i);
int minHScroll = minHScrollId();
if (lv->contentsX() < minHScroll) {
lv->setXOffset(minHScroll);
}
}
int m_scrollDistance = m_settings->m_scrollNoOfLines * lineHeight();
int m_pageSize = pageSize();
if( needVScrollBar() )
{
m_vScroll->show();
m_vScroll->blockSignals( true );
m_vScroll->setRange( minVScrollId(),
maxVScrollId() );
m_vScroll->setValue( scrollId() );
m_vScroll->setSingleStep( m_scrollDistance );
m_vScroll->setPageStep( m_pageSize );
m_vScroll->blockSignals( false );
}
else
{
m_vScroll->hide();
}
if( needHScrollBar() )
{
m_hScroll->show();
m_hScroll->blockSignals( true );
m_hScroll->setRange( minHScrollId(), maxHScrollId() );
m_hScroll->setValue( maxContentsX() );
m_hScroll->setSingleStep( 10 );
m_hScroll->setPageStep( minVisibleWidth() - 10 );
m_hScroll->blockSignals( false );
}
else
{
m_hScroll->hide();
}
}
void KompareSplitter::slotDelayedUpdateVScrollValue()
{
QTimer::singleShot( 0, this, SLOT( slotUpdateVScrollValue() ) );
}
void KompareSplitter::slotUpdateVScrollValue()
{
m_vScroll->setValue( scrollId() );
}
void KompareSplitter::keyPressEvent( QKeyEvent* e )
{
//keyboard scrolling
switch ( e->key() ) {
case Qt::Key_Right:
case Qt::Key_L:
m_hScroll->triggerAction( QAbstractSlider::SliderSingleStepAdd );
break;
case Qt::Key_Left:
case Qt::Key_H:
m_hScroll->triggerAction( QAbstractSlider::SliderSingleStepSub );
break;
case Qt::Key_Up:
case Qt::Key_K:
m_vScroll->triggerAction( QAbstractSlider::SliderSingleStepSub );
break;
case Qt::Key_Down:
case Qt::Key_J:
m_vScroll->triggerAction( QAbstractSlider::SliderSingleStepAdd );
break;
case Qt::Key_PageDown:
m_vScroll->triggerAction( QAbstractSlider::SliderPageStepAdd );
break;
case Qt::Key_PageUp:
m_vScroll->triggerAction( QAbstractSlider::SliderPageStepSub );
break;
}
e->accept();
slotRepaintHandles();
}
void KompareSplitter::wheelEvent( QWheelEvent* e )
{
if ( e->orientation() == Qt::Vertical )
{
if ( e->modifiers() & Qt::ControlModifier ) {
if ( e->delta() < 0 ) // scroll down one page
m_vScroll->triggerAction( QAbstractSlider::SliderPageStepAdd );
else // scroll up one page
m_vScroll->triggerAction( QAbstractSlider::SliderPageStepSub );
} else {
if ( e->delta() < 0 ) // scroll down
m_vScroll->triggerAction( QAbstractSlider::SliderSingleStepAdd );
else // scroll up
m_vScroll->triggerAction( QAbstractSlider::SliderSingleStepSub );
}
}
else
{
if ( e->modifiers() & Qt::ControlModifier ) {
if ( e->delta() < 0 ) // scroll right one page
m_hScroll->triggerAction( QAbstractSlider::SliderPageStepAdd );
else // scroll left one page
m_hScroll->triggerAction( QAbstractSlider::SliderPageStepSub );
} else {
if ( e->delta() < 0 ) // scroll to the right
m_hScroll->triggerAction( QAbstractSlider::SliderSingleStepAdd );
else // scroll to the left
m_hScroll->triggerAction( QAbstractSlider::SliderSingleStepSub );
}
}
e->accept();
slotDelayedRepaintHandles();
}
/* FIXME: this should return/the scrollId() from the listview containing the
* /base/ of the diff. but there's bigger issues with that atm.
*/
int KompareSplitter::scrollId()
{
if(widget(0))
return listView(0)->scrollId();
return minVScrollId();
}
int KompareSplitter::lineHeight()
{
if(widget(0))
return listView(0)->fontMetrics().height();
return 1;
}
int KompareSplitter::pageSize()
{
if(widget(0)) {
KompareListView *view = listView(0);
return view->visibleHeight() - view->style()->pixelMetric( QStyle::PM_ScrollBarExtent );
}
return 1;
}
bool KompareSplitter::needVScrollBar()
{
int pagesize = pageSize();
const int end = count();
for ( int i = 0; i < end; ++i ) {
KompareListView *view = listView(i);
if( view ->contentsHeight() > pagesize)
return true;
}
return false;
}
int KompareSplitter::minVScrollId()
{
int min = -1;
int mSId;
const int end = count();
for ( int i = 0; i < end; ++i ) {
mSId = listView(i)->minScrollId();
if (mSId < min || min == -1)
min = mSId;
}
return ( min == -1 ) ? 0 : min;
}
int KompareSplitter::maxVScrollId()
{
int max = 0;
int mSId;
const int end = count();
for ( int i = 0; i < end; ++i ) {
mSId = listView(i)->maxScrollId();
if ( mSId > max )
max = mSId;
}
return max;
}
bool KompareSplitter::needHScrollBar()
{
const int end = count();
for ( int i = 0; i < end; ++i ) {
KompareListView *view = listView(i);
if ( view->contentsWidth() > view->visibleWidth() )
return true;
}
return false;
}
int KompareSplitter::minHScrollId()
{
// hardcode an offset to hide the tree controls
return 6;
}
int KompareSplitter::maxHScrollId()
{
int max = 0;
int mHSId;
const int end = count();
for ( int i = 0; i < end; ++i ) {
KompareListView *view = listView(i);
mHSId = view->contentsWidth() - view->visibleWidth();
if ( mHSId > max )
max = mHSId;
}
return max;
}
int KompareSplitter::maxContentsX()
{
int max = 0;
int mCX;
const int end = count();
for ( int i = 0; i < end; ++i ) {
mCX = listView(i)->contentsX();
if ( mCX > max )
max = mCX;
}
return max;
}
int KompareSplitter::minVisibleWidth()
{
// Why the hell do we want to know this?
// ah yes, it is because we use it to set the "page size" for horiz. scrolling.
// despite the fact that *none* has a pgright and pgleft key :P
// But we do have mousewheels with horizontal scrolling functionality,
// pressing shift and scrolling then goes left and right one page at the time
int min = -1;
int vW;
const int end = count();
for ( int i = 0; i < end; ++i ) {
vW = listView(i)->visibleWidth();
if ( vW < min || min == -1 )
min = vW;
}
return ( min == -1 ) ? 0 : min;
}
KompareListView* KompareSplitter::listView( int index )
{
return static_cast<KompareListViewFrame*>(widget(index))->view();
}
KompareConnectWidget* KompareSplitter::connectWidget( int index )
{
return static_cast<KompareConnectWidgetFrame*>(handle(index))->wid();
}
void KompareSplitter::slotSetSelection( const DiffModel* model, const Difference* diff )
{
const int end = count();
for ( int i = 0; i < end; ++i ) {
connectWidget(i)->slotSetSelection( model, diff );
listView(i)->slotSetSelection( model, diff );
static_cast<KompareListViewFrame*>(widget(i))->slotSetModel( model );
}
slotDelayedRepaintHandles();
slotDelayedUpdateScrollBars();
}
void KompareSplitter::slotSetSelection( const Difference* diff )
{
const int end = count();
for ( int i = 0; i < end; ++i ) {
connectWidget(i)->slotSetSelection( diff );
listView(i)->slotSetSelection( diff );
}
slotDelayedRepaintHandles();
slotDelayedUpdateScrollBars();
}
void KompareSplitter::slotApplyDifference( bool apply )
{
const int end = count();
for ( int i = 0; i < end; ++i )
listView(i)->slotApplyDifference( apply );
slotDelayedRepaintHandles();
}
void KompareSplitter::slotApplyAllDifferences( bool apply )
{
const int end = count();
for ( int i = 0; i < end; ++i )
listView(i)->slotApplyAllDifferences( apply );
slotDelayedRepaintHandles();
slotScrollToId( m_scrollTo ); // FIXME!
}
void KompareSplitter::slotApplyDifference( const Difference* diff, bool apply )
{
const int end = count();
for ( int i = 0; i < end; ++i )
listView(i)->slotApplyDifference( diff, apply );
slotDelayedRepaintHandles();
}
void KompareSplitter::slotDifferenceClicked( const Difference* diff )
{
const int end = count();
for ( int i = 0; i < end; ++i )
listView(i)->setSelectedDifference( diff, false );
emit selectionChanged( diff );
}
void KompareSplitter::slotConfigChanged()
{
const int end = count();
for ( int i = 0; i < end; ++i ) {
KompareListView *view = listView(i);
view->setFont( m_settings->m_font );
view->update();
}
}
#include "komparesplitter.moc"

View file

@ -0,0 +1,121 @@
/***************************************************************************
komparesplitter.h
-----------------
begin : Wed Jan 14 2004
Copyright 2004 Jeff Snyder <jeff@caffeinated.me.uk>
Copyright 2007-2011 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#ifndef _KOMPARESPLITTER_H_
#define _KOMPARESPLITTER_H_
#include <QtGui/QSplitter>
#include "komparemodellist.h"
class QSplitterHandle;
class QTimer;
class QScrollBar;
class QWheelEvent;
class QKeyEvent;
namespace Diff2 {
class DiffModel;
class Difference;
}
class ViewSettings;
class KompareListView;
class KompareConnectWidget;
class KompareSplitter : public QSplitter
{
Q_OBJECT
public:
KompareSplitter(ViewSettings *settings, QWidget *parent);
~KompareSplitter();
signals:
void configChanged();
void scrollViewsToId( int id );
void setXOffset( int x );
void selectionChanged( const Diff2::Difference* diff );
public slots:
void slotScrollToId( int id );
void slotDelayedUpdateScrollBars();
void slotUpdateScrollBars();
void slotDelayedUpdateVScrollValue();
void slotUpdateVScrollValue();
void keyPressEvent( QKeyEvent* e );
void slotApplyDifference( bool apply );
void slotApplyAllDifferences( bool apply );
void slotApplyDifference( const Diff2::Difference* diff, bool apply );
void slotSetSelection( const Diff2::DiffModel* model, const Diff2::Difference* diff );
void slotSetSelection( const Diff2::Difference* diff );
void slotDifferenceClicked( const Diff2::Difference* diff );
void slotConfigChanged();
protected:
void wheelEvent( QWheelEvent* e );
ViewSettings* settings() const { return m_settings; }
protected slots:
void slotDelayedRepaintHandles();
void slotRepaintHandles();
void timerTimeout();
private:
// override from QSplitter
QSplitterHandle* createHandle();
void setCursor( int id, const QCursor& cursor );
void unsetCursor( int id );
protected:
KompareListView* listView( int index );
KompareConnectWidget* connectWidget( int index );
private:
// Scrollbars. all this just for the goddamn scrollbars. i hate them.
int scrollId();
int lineHeight();
int pageSize();
bool needVScrollBar();
int minVScrollId();
int maxVScrollId();
bool needHScrollBar();
int minHScrollId();
int maxHScrollId();
int maxContentsX();
int minVisibleWidth();
QTimer* m_scrollTimer;
bool m_restartTimer;
int m_scrollTo;
ViewSettings* m_settings;
QScrollBar* m_vScroll;
QScrollBar* m_hScroll;
friend class KompareConnectWidgetFrame;
};
#endif //_KOMPARESPLITTER_H_

View file

@ -0,0 +1,28 @@
/**************************************************************************
** kompareview.cpp
** ---------------
** begin : Thu Nov 3 2011
** Copyright 2011 Kevin Kofler <kevin.kofler@chello.at>
***************************************************************************/
/**************************************************************************
**
** 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.
**
***************************************************************************/
// associated header
#include "kompareview.h"
// kompare
#include "komparesplitter.h"
KompareView::KompareView(ViewSettings *settings, QWidget *parent) :
QFrame( parent )
{
setObjectName( "scrollFrame" );
m_splitter = new KompareSplitter( settings, this );
}

View file

@ -0,0 +1,39 @@
/**************************************************************************
** kompareview.h
** -------------
** begin : Thu Nov 3 2011
** Copyright 2011 Kevin Kofler <kevin.kofler@chello.at>
***************************************************************************/
/**************************************************************************
**
** 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.
**
***************************************************************************/
#ifndef _KOMPAREVIEW_H_
#define _KOMPAREVIEW_H_
#include <QtGui/QFrame>
#include "komparemodellist.h"
class ViewSettings;
class KompareSplitter;
class KompareView : public QFrame
{
Q_OBJECT
public:
KompareView(ViewSettings *settings, QWidget *parent);
~KompareView() {}
KompareSplitter *splitter() { return m_splitter; }
private:
KompareSplitter *m_splitter;
};
#endif //_KOMPARESPLITTER_H_

33
kompare/kompareui.rc Normal file
View file

@ -0,0 +1,33 @@
<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
<kpartgui name="kompare_shell" version="9">
<MenuBar>
<Menu noMerge="1" name="file"><text>&amp;File</text>
<Action name="file_open"/>
<Action name="file_compare_files"/>
<Action name="file_blend_url"/>
<Separator/>
<Merge/>
<Separator/>
<Action name="file_quit"/>
</Menu>
<Merge/>
<Menu noMerge="1" name="settings"><text>&amp;Settings</text>
<Merge name="StandardToolBarMenuHandler" />
<Action name="options_show_toolbar"/>
<Action name="options_show_statusbar"/>
<Action name="options_show_text_view"/>
<Merge name="show_merge"/>
<Separator/>
<Action name="options_configure_keybinding"/>
<Action name="options_configure_toolbars"/>
<Merge name="configure_merge"/>
<Merge/>
</Menu>
</MenuBar>
<ToolBar noMerge="1" name="mainToolBar"><text>Main Toolbar</text>
<Action name="file_compare_files"/>
<Separator/>
<Merge/>
<Action name="help"/>
</ToolBar>
</kpartgui>

View file

@ -0,0 +1,190 @@
/***************************************************************************
kompareurldialog.cpp
--------------------
begin : Sun Mar 4 2001
Copyright 2001-2005,2009 Otto Bruggeman <bruggie@gmail.com>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2007 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#include "kompareurldialog.h"
#include <QShowEvent>
#include <QGroupBox>
#include <kapplication.h>
#include <kglobal.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kurlcombobox.h>
#include <kurlrequester.h>
#include "diffpage.h"
#include "diffsettings.h"
#include "filespage.h"
#include "filessettings.h"
#include "viewpage.h"
#include "viewsettings.h"
KompareURLDialog::KompareURLDialog( QWidget *parent, Qt::WFlags flags )
: KPageDialog( parent, flags )
{
setFaceType( List );
KSharedConfig::Ptr cfg = KGlobal::config();
m_filesPage = new FilesPage();
KPageWidgetItem *filesItem = addPage( m_filesPage, i18n( "Files" ) );
filesItem->setIcon( KIcon( "text-plain" ) );
filesItem->setHeader( i18n( "Here you can enter the files you want to compare." ) );
m_filesSettings = new FilesSettings( this );
m_filesSettings->loadSettings( cfg.data() );
m_filesPage->setSettings( m_filesSettings );
m_diffPage = new DiffPage();
KPageWidgetItem *diffItem = addPage( m_diffPage, i18n( "Diff" ) );
diffItem->setIcon( KIcon( "text-x-patch" ) );
diffItem->setHeader( i18n( "Here you can change the options for comparing the files." ) );
m_diffSettings = new DiffSettings( this );
m_diffSettings->loadSettings( cfg.data() );
m_diffPage->setSettings( m_diffSettings );
m_viewPage = new ViewPage();
KPageWidgetItem *viewItem = addPage( m_viewPage, i18n( "Appearance" ) );
viewItem->setIcon( KIcon( "preferences-desktop-theme" ) );
viewItem->setHeader( i18n( "Here you can change the options for the view." ) );
m_viewSettings = new ViewSettings( this );
m_viewSettings->loadSettings( cfg.data() );
m_viewPage->setSettings( m_viewSettings );
adjustSize();
showButtonSeparator( true );
connect( m_filesPage->firstURLRequester(), SIGNAL( textChanged( const QString& ) ),
this, SLOT( slotEnableOk() ) );
connect( m_filesPage->secondURLRequester(), SIGNAL( textChanged( const QString& ) ),
this, SLOT( slotEnableOk() ) );
}
KompareURLDialog::~KompareURLDialog()
{
}
void KompareURLDialog::showEvent ( QShowEvent * event )
{
if ( !event->spontaneous () )
{
slotEnableOk();
}
}
void KompareURLDialog::slotButtonClicked( int button )
{
if ( button == KDialog::Cancel )
{
reject();
return;
}
// BUG: 124121 File with filenames to be excluded does not exist so diff complains and no diffs are generated
kDebug(8102) << "Test to see if the file is an actual file that is given in the file with filenames to exclude field" << endl;
if ( m_diffPage->m_excludeFileNameGroupBox->isChecked() )
{
kDebug(8102) << "Ok the checkbox is active..." << endl;
if ( QFileInfo( m_diffPage->m_excludeFileURLComboBox->currentText() ).isDir() )
{
kDebug(8102) << "Don't enter directory names where filenames are expected..." << endl;
KMessageBox::sorry( this, i18n( "File used for excluding files cannot be found, please specify another file." ) );
reject();
return;
}
}
// Room for more checks for invalid input
m_filesPage->setURLsInComboBoxes();
KSharedConfig::Ptr cfg = KGlobal::config();
m_filesPage->apply();
m_diffPage->apply();
m_viewPage->apply();
m_filesSettings->saveSettings( cfg.data() );
m_diffSettings->saveSettings( cfg.data() );
m_viewSettings->saveSettings( cfg.data() );
cfg->sync();
accept();
}
void KompareURLDialog::slotEnableOk()
{
enableButtonOk( !m_filesPage->firstURLRequester()->url().isEmpty() &&
!m_filesPage->secondURLRequester()->url().isEmpty() );
}
/**
* Returns the first URL, which was entered.
* @return first URL
*/
KUrl KompareURLDialog::getFirstURL() const
{
return KUrl( m_filesPage->firstURLRequester()->url() );
}
/**
* Returns the second URL, which was entered.
* @return second URL
*/
KUrl KompareURLDialog::getSecondURL() const
{
return KUrl( m_filesPage->secondURLRequester()->url() );
}
/**
* Returns the encoding.
* @return encoding
*/
QString KompareURLDialog::encoding() const
{
return m_filesPage->encoding();
}
void KompareURLDialog::setFirstGroupBoxTitle( const QString& title )
{
m_filesPage->setFirstGroupBoxTitle( title );
}
void KompareURLDialog::setSecondGroupBoxTitle( const QString& title )
{
m_filesPage->setSecondGroupBoxTitle( title );
}
void KompareURLDialog::setGroup( const QString& groupName )
{
m_filesSettings->setGroup( groupName );
m_filesSettings->loadSettings( KGlobal::config().data() );
m_filesPage->setSettings( m_filesSettings );
}
void KompareURLDialog::setFirstURLRequesterMode( unsigned int mode )
{
m_filesPage->setFirstURLRequesterMode( mode );
}
void KompareURLDialog::setSecondURLRequesterMode( unsigned int mode )
{
m_filesPage->setSecondURLRequesterMode( mode );
}
#include "kompareurldialog.moc"

View file

@ -0,0 +1,74 @@
/***************************************************************************
kcompareurldialog.h
-------------------
begin : Sun Mar 4 2001
Copyright 2001-2004 Otto Bruggeman <otto.bruggeman@home.nl>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#ifndef KOMPAREURLDIALOG_H
#define KOMPAREURLDIALOG_H
#include <kpagedialog.h>
#include <kurl.h>
class FilesPage;
class FilesSettings;
class DiffPage;
class DiffSettings;
class ViewPage;
class ViewSettings;
/**
* Definition of class KompareURLDialog.
* @author Otto Bruggeman
* @author John Firebaugh
*/
class KompareURLDialog : public KPageDialog
{
Q_OBJECT
public:
explicit KompareURLDialog( QWidget *parent= 0, Qt::WFlags flags= 0 );
~KompareURLDialog();
KUrl getFirstURL() const;
KUrl getSecondURL() const;
QString encoding() const;
void setFirstGroupBoxTitle ( const QString& title );
void setSecondGroupBoxTitle( const QString& title );
void setGroup( const QString& groupName );
void setFirstURLRequesterMode ( unsigned int mode );
void setSecondURLRequesterMode( unsigned int mode );
protected slots:
virtual void slotButtonClicked( int button );
private slots:
void slotEnableOk();
protected:
void showEvent ( QShowEvent * event );
private:
FilesPage* m_filesPage;
FilesSettings* m_filesSettings;
DiffPage* m_diffPage;
DiffSettings* m_diffSettings;
ViewPage* m_viewPage;
ViewSettings* m_viewSettings;
};
#endif

View file

@ -0,0 +1,4 @@
[Desktop Entry]
Type=ServiceType
X-KDE-ServiceType=Kompare/ViewPart
X-KDE-Derived=KParts/ReadOnlyPart

View file

@ -0,0 +1,23 @@
########### next target ###############
set(dialogpages_PART_SRCS
filessettings.cpp
viewsettings.cpp
pagebase.cpp
diffpage.cpp
filespage.cpp
viewpage.cpp )
kde4_add_library(komparedialogpages SHARED ${dialogpages_PART_SRCS})
include_directories(${LIBKOMPAREDIFF2_INCLUDE_DIR})
target_link_libraries(komparedialogpages ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${LIBKOMPAREDIFF2_LIBRARIES})
set_target_properties(komparedialogpages PROPERTIES VERSION ${GENERIC_LIB_VERSION}
SOVERSION ${GENERIC_LIB_SOVERSION} )
install(TARGETS komparedialogpages ${INSTALL_TARGETS_DEFAULT_ARGS})

View file

@ -0,0 +1,37 @@
/***************************************************************************
* Copyright 2007 Andreas Pakulat <apaku@gmx.de> *
* Copyright 2006 Matt Rogers <mattr@kde.org> *
* Copyright 2004 Jarosław Staniek <staniek@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library 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 Library 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. *
***************************************************************************/
#ifndef LIBDIALOGPAGESEXPORT_H
#define LIBDIALOGPAGESEXPORT_H
/* needed for KDE_EXPORT macros */
#include <kdemacros.h>
#ifndef DIALOGPAGES_EXPORT
# ifdef MAKE_KOMPAREDIALOGPAGES_LIB
# define DIALOGPAGES_EXPORT KDE_EXPORT
# else
# define DIALOGPAGES_EXPORT KDE_IMPORT
# endif
#endif
#endif

View file

@ -0,0 +1,411 @@
/***************************************************************************
diffprefs.cpp
-------------
begin : Sun Mar 4 2001
Copyright 2001-2004 Otto Bruggeman <otto.bruggeman@home.nl>
Copyright 2007-2011 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#include "diffpage.h"
#include <QtGui/QCheckBox>
#include <QGroupBox>
#include <QtGui/QLabel>
#include <QtGui/QLayout>
#include <QtGui/QRadioButton>
#include <QtGui/QSpinBox>
#include <QtGui/QVBoxLayout>
#include <QtGui/QHBoxLayout>
#include <QtGui/QToolTip>
#include <QButtonGroup>
#include <kbuttongroup.h>
#include <kapplication.h>
#include <kcombobox.h>
#include <kdialog.h>
#include <keditlistwidget.h>
#include <klineedit.h>
#include <klocale.h>
#include <kurlcombobox.h>
#include <kurlrequester.h>
#include <kservicetypetrader.h>
#include <ktabwidget.h>
#include <kparts/componentfactory.h>
#include <kregexpeditorinterface.h>
#include <kglobal.h>
#include "diffsettings.h"
DiffPage::DiffPage() : PageBase(), m_ignoreRegExpDialog( 0 )
{
m_tabWidget = new KTabWidget( this );
addDiffTab();
addFormatTab();
addOptionsTab();
addExcludeTab();
}
DiffPage::~DiffPage()
{
m_settings = 0;
}
void DiffPage::setSettings( DiffSettings* setts )
{
m_settings = setts;
m_diffURLRequester->setUrl( m_settings->m_diffProgram );
m_newFilesCheckBox->setChecked ( m_settings->m_newFiles );
m_smallerCheckBox->setChecked ( m_settings->m_createSmallerDiff );
m_largerCheckBox->setChecked ( m_settings->m_largeFiles );
m_tabsCheckBox->setChecked ( m_settings->m_convertTabsToSpaces );
m_caseCheckBox->setChecked ( m_settings->m_ignoreChangesInCase );
m_linesCheckBox->setChecked ( m_settings->m_ignoreEmptyLines );
m_whitespaceCheckBox->setChecked ( m_settings->m_ignoreWhiteSpace );
m_allWhitespaceCheckBox->setChecked ( m_settings->m_ignoreAllWhiteSpace );
m_ignoreTabExpansionCheckBox->setChecked( m_settings->m_ignoreChangesDueToTabExpansion );
m_ignoreRegExpCheckBox->setChecked ( m_settings->m_ignoreRegExp );
m_ignoreRegExpEdit->setCompletedItems( m_settings->m_ignoreRegExpTextHistory );
m_ignoreRegExpEdit->setText ( m_settings->m_ignoreRegExpText );
m_locSpinBox->setValue( m_settings->m_linesOfContext );
m_modeButtonGroup->button( m_settings->m_format )->setChecked( true );
m_excludeFilePatternGroupBox->setChecked ( m_settings->m_excludeFilePattern );
slotExcludeFilePatternToggled ( m_settings->m_excludeFilePattern );
m_excludeFilePatternEditListBox->insertStringList( m_settings->m_excludeFilePatternList );
m_excludeFileNameGroupBox->setChecked( m_settings->m_excludeFilesFile );
slotExcludeFileToggled ( m_settings->m_excludeFilesFile );
m_excludeFileURLComboBox->setUrls( m_settings->m_excludeFilesFileHistoryList );
m_excludeFileURLComboBox->setUrl ( KUrl( m_settings->m_excludeFilesFileURL ) );
}
DiffSettings* DiffPage::settings( void )
{
return m_settings;
}
void DiffPage::restore()
{
// this shouldn't do a thing...
}
void DiffPage::apply()
{
m_settings->m_diffProgram = m_diffURLRequester->url().pathOrUrl();
m_settings->m_newFiles = m_newFilesCheckBox->isChecked();
m_settings->m_largeFiles = m_largerCheckBox->isChecked();
m_settings->m_createSmallerDiff = m_smallerCheckBox->isChecked();
m_settings->m_convertTabsToSpaces = m_tabsCheckBox->isChecked();
m_settings->m_ignoreChangesInCase = m_caseCheckBox->isChecked();
m_settings->m_ignoreEmptyLines = m_linesCheckBox->isChecked();
m_settings->m_ignoreWhiteSpace = m_whitespaceCheckBox->isChecked();
m_settings->m_ignoreAllWhiteSpace = m_allWhitespaceCheckBox->isChecked();
m_settings->m_ignoreChangesDueToTabExpansion = m_ignoreTabExpansionCheckBox->isChecked();
m_settings->m_ignoreRegExp = m_ignoreRegExpCheckBox->isChecked();
m_settings->m_ignoreRegExpText = m_ignoreRegExpEdit->text();
m_settings->m_ignoreRegExpTextHistory = m_ignoreRegExpEdit->completionObject()->items();
m_settings->m_linesOfContext = m_locSpinBox->value();
m_settings->m_format = static_cast<Kompare::Format>( m_modeButtonGroup->checkedId() );
m_settings->m_excludeFilePattern = m_excludeFilePatternGroupBox->isChecked();
m_settings->m_excludeFilePatternList = m_excludeFilePatternEditListBox->items();
m_settings->m_excludeFilesFile = m_excludeFileNameGroupBox->isChecked();
m_settings->m_excludeFilesFileURL = m_excludeFileURLComboBox->currentText();
m_settings->m_excludeFilesFileHistoryList = m_excludeFileURLComboBox->urls();
m_settings->saveSettings( KGlobal::config().data() );
}
void DiffPage::setDefaults()
{
m_diffURLRequester->setUrl( KUrl( "diff" ) );
m_newFilesCheckBox->setChecked( true );
m_smallerCheckBox->setChecked( true );
m_largerCheckBox->setChecked( true );
m_tabsCheckBox->setChecked( false );
m_caseCheckBox->setChecked( false );
m_linesCheckBox->setChecked( false );
m_whitespaceCheckBox->setChecked( false );
m_allWhitespaceCheckBox->setChecked( false );
m_ignoreTabExpansionCheckBox->setChecked( false );
m_ignoreRegExpCheckBox->setChecked( false );
m_ignoreRegExpEdit->setText( QString() );
m_locSpinBox->setValue( 3 );
m_modeButtonGroup->button( Kompare::Unified )->setChecked( true );
m_excludeFilePatternGroupBox->setChecked( false );
m_excludeFileNameGroupBox->setChecked( false );
}
void DiffPage::slotShowRegExpEditor()
{
if ( ! m_ignoreRegExpDialog )
m_ignoreRegExpDialog = KServiceTypeTrader::createInstanceFromQuery<QDialog>( "KRegExpEditor/KRegExpEditor", QString(), this );
KRegExpEditorInterface *iface = qobject_cast<KRegExpEditorInterface *>( m_ignoreRegExpDialog );
if ( !iface )
return;
iface->setRegExp( m_ignoreRegExpEdit->text() );
bool ok = m_ignoreRegExpDialog->exec();
if ( ok )
m_ignoreRegExpEdit->setText( iface->regExp() );
}
void DiffPage::slotExcludeFilePatternToggled( bool on )
{
m_excludeFilePatternEditListBox->setEnabled( on );
}
void DiffPage::slotExcludeFileToggled( bool on )
{
m_excludeFileURLComboBox->setEnabled( on );
m_excludeFileURLRequester->setEnabled( on );
}
void DiffPage::addDiffTab()
{
QWidget* page = new QWidget( this );
QVBoxLayout* layout = new QVBoxLayout( page );
layout->setSpacing( KDialog::spacingHint() );
layout->setMargin( KDialog::marginHint() );
// add diff program selector
m_diffProgramGroup = new QGroupBox( page );
layout->addWidget( m_diffProgramGroup );
QVBoxLayout* bgLayout = new QVBoxLayout( m_diffProgramGroup );
m_diffProgramGroup->setTitle( i18n( "Diff Program" ) );
//m_diffProgramGroup->setMargin( KDialog::marginHint() );
m_diffURLRequester = new KUrlRequester( m_diffProgramGroup);
m_diffURLRequester->setObjectName("diffURLRequester" );
m_diffURLRequester->setWhatsThis( i18n( "You can select a different diff program here. On Solaris the standard diff program does not support all the options that the GNU version does. This way you can select that version." ) );
bgLayout->addWidget( m_diffURLRequester );
layout->addStretch( 1 );
page->setMinimumSize( sizeHintForWidget( page ) );
m_tabWidget->addTab( page, i18n( "Diff" ) );
}
void DiffPage::addFormatTab()
{
QWidget* page = new QWidget( this );
QVBoxLayout* layout = new QVBoxLayout( page );
layout->setSpacing( KDialog::spacingHint() );
layout->setMargin( KDialog::marginHint() );
// add diff modes
m_modeButtonGroup = new QButtonGroup( page );
QGroupBox *box = new QGroupBox( page );
box->setWhatsThis( i18n( "Select the format of the output generated by diff. Unified is the one that is used most frequently because it is very readable. The KDE developers like this format the best so use it for sending patches." ) );
layout->addWidget( box );
QVBoxLayout* bgLayout = new QVBoxLayout( box );
box->setTitle( i18n( "Output Format" ) );
//m_modeButtonGroup->setMargin( KDialog::marginHint() );
QRadioButton *radioButton = new QRadioButton( i18n( "Context" ), box );
m_modeButtonGroup->addButton( radioButton, Kompare::Context);
bgLayout->addWidget( radioButton );
radioButton = new QRadioButton( i18n( "Normal" ), box );
m_modeButtonGroup->addButton( radioButton, Kompare::Normal);
bgLayout->addWidget( radioButton );
radioButton = new QRadioButton( i18n( "Unified" ), box );
m_modeButtonGroup->addButton( radioButton, Kompare::Unified);
bgLayout->addWidget( radioButton );
// #lines of context (loc)
QGroupBox* groupBox = new QGroupBox( page );
QHBoxLayout *groupLayout = new QHBoxLayout;
groupBox->setLayout( groupLayout );
layout->addWidget( groupBox );
groupBox->setTitle( i18n( "Lines of Context" ) );
groupBox->setWhatsThis( i18n( "The number of context lines is normally 2 or 3. This makes the diff readable and applicable in most cases. More than 3 lines will only bloat the diff unnecessarily." ) );
//groupBox->setMargin( KDialog::marginHint() );
QLabel* label = new QLabel( i18n( "Number of context lines:" ));
groupLayout->addWidget( label );
label->setWhatsThis( i18n( "The number of context lines is normally 2 or 3. This makes the diff readable and applicable in most cases. More than 3 lines will only bloat the diff unnecessarily." ) );
m_locSpinBox = new QSpinBox( groupBox );
m_locSpinBox->setRange( 0, 100 );
groupLayout->addWidget( m_locSpinBox );
m_locSpinBox->setWhatsThis( i18n( "The number of context lines is normally 2 or 3. This makes the diff readable and applicable in most cases. More than 3 lines will only bloat the diff unnecessarily." ) );
label->setBuddy( m_locSpinBox );
layout->addStretch( 1 );
page->setMinimumSize( sizeHintForWidget( page ) );
m_tabWidget->addTab( page, i18n( "Format" ) );
}
void DiffPage::addOptionsTab()
{
QWidget* page = new QWidget( this );
QVBoxLayout* layout = new QVBoxLayout( page );
layout->setSpacing( KDialog::spacingHint() );
layout->setMargin( KDialog::marginHint() );
// add diff options
KButtonGroup* optionButtonGroup = new KButtonGroup( page );
layout->addWidget( optionButtonGroup );
QVBoxLayout* bgLayout = new QVBoxLayout( optionButtonGroup );
optionButtonGroup->setTitle( i18n( "General" ) );
//optionButtonGroup->setMargin( KDialog::marginHint() );
m_newFilesCheckBox = new QCheckBox( i18n( "&Treat new files as empty" ), optionButtonGroup );
m_newFilesCheckBox->setToolTip( i18n( "This option corresponds to the -N diff option." ) );
m_newFilesCheckBox->setWhatsThis( i18n( "With this option enabled diff will treat a file that only exists in one of the directories as empty in the other directory. This means that the file is compared with an empty file and because of this will appear as one big insertion or deletion." ) );
bgLayout->addWidget( m_newFilesCheckBox );
m_smallerCheckBox = new QCheckBox( i18n( "&Look for smaller changes" ), optionButtonGroup );
m_smallerCheckBox->setToolTip( i18n( "This corresponds to the -d diff option." ) );
m_smallerCheckBox->setWhatsThis( i18n( "With this option enabled diff will try a little harder (at the cost of more memory) to find fewer changes." ) );
bgLayout->addWidget( m_smallerCheckBox );
m_largerCheckBox = new QCheckBox( i18n( "O&ptimize for large files" ), optionButtonGroup );
m_largerCheckBox->setToolTip( i18n( "This corresponds to the -H diff option." ) );
m_largerCheckBox->setWhatsThis( i18n( "This option lets diff makes better diffs when using large files. The definition of large is nowhere to be found though." ) );
bgLayout->addWidget( m_largerCheckBox );
m_caseCheckBox = new QCheckBox( i18n( "&Ignore changes in case" ), optionButtonGroup );
m_caseCheckBox->setToolTip( i18n( "This corresponds to the -i diff option." ) );
m_caseCheckBox->setWhatsThis( i18n( "With this option to ignore changes in case enabled, diff will not indicate a difference when something in one file is changed into SoMEthing in the other file." ) );
bgLayout->addWidget( m_caseCheckBox );
QHBoxLayout* groupLayout = new QHBoxLayout();
layout->addLayout( groupLayout );
groupLayout->setObjectName( "regexp_horizontal_layout" );
groupLayout->setSpacing( -1 );
groupLayout->setMargin( KDialog::marginHint() );
m_ignoreRegExpCheckBox = new QCheckBox( i18n( "Ignore regexp:" ), page );
m_ignoreRegExpCheckBox->setToolTip( i18n( "This option corresponds to the -I diff option." ) );
m_ignoreRegExpCheckBox->setWhatsThis( i18n( "When this checkbox is enabled, an option to diff is given that will make diff ignore lines that match the regular expression." ) );
groupLayout->addWidget( m_ignoreRegExpCheckBox );
m_ignoreRegExpEdit = new KLineEdit( QString::null, page); //krazy:exclude=nullstrassign for old broken gcc
m_ignoreRegExpEdit->setObjectName("regexplineedit" );
m_ignoreRegExpEdit->setToolTip( i18n( "Add the regular expression here that you want to use\nto ignore lines that match it." ) );
groupLayout->addWidget( m_ignoreRegExpEdit );
if ( !KServiceTypeTrader::self()->query("KRegExpEditor/KRegExpEditor").isEmpty() )
{
// Ok editor is available, use it
QPushButton* ignoreRegExpEditButton = new QPushButton( i18n( "&Edit..." ), page);
ignoreRegExpEditButton->setObjectName( "regexp_editor_button" );
ignoreRegExpEditButton->setToolTip( i18n( "Clicking this will open a regular expression dialog where\nyou can graphically create regular expressions." ) );
groupLayout->addWidget( ignoreRegExpEditButton );
connect( ignoreRegExpEditButton, SIGNAL( clicked() ), this, SLOT( slotShowRegExpEditor() ) );
}
KButtonGroup* moreOptionButtonGroup = new KButtonGroup( page );
layout->addWidget( moreOptionButtonGroup );
bgLayout = new QVBoxLayout( moreOptionButtonGroup );
moreOptionButtonGroup->setTitle( i18n( "Whitespace" ) );
//moreOptionButtonGroup->setMargin( KDialog::marginHint() );
m_tabsCheckBox = new QCheckBox( i18n( "E&xpand tabs to spaces in output" ), moreOptionButtonGroup );
m_tabsCheckBox->setToolTip( i18n( "This option corresponds to the -t diff option." ) );
m_tabsCheckBox->setWhatsThis( i18n( "This option does not always produce the right result. Due to this expansion Kompare may have problems applying the change to the destination file." ) );
bgLayout->addWidget( m_tabsCheckBox );
m_linesCheckBox = new QCheckBox( i18n( "I&gnore added or removed empty lines" ), moreOptionButtonGroup );
m_linesCheckBox->setToolTip( i18n( "This option corresponds to the -B diff option." ) );
m_linesCheckBox->setWhatsThis( i18n( "This can be very useful in situations where code has been reorganized and empty lines have been added or removed to improve legibility." ) );
bgLayout->addWidget( m_linesCheckBox );
m_whitespaceCheckBox = new QCheckBox( i18n( "Ig&nore changes in the amount of whitespace" ), moreOptionButtonGroup );
m_whitespaceCheckBox->setToolTip( i18n( "This option corresponds to the -b diff option." ) );
m_whitespaceCheckBox->setWhatsThis( i18n( "If you are uninterested in differences arising due to, for example, changes in indentation, then use this option." ) );
bgLayout->addWidget( m_whitespaceCheckBox );
m_allWhitespaceCheckBox = new QCheckBox( i18n( "Ign&ore all whitespace" ), moreOptionButtonGroup );
m_allWhitespaceCheckBox->setToolTip( i18n( "This option corresponds to the -w diff option." ) );
m_allWhitespaceCheckBox->setWhatsThis( i18n( "This is useful for seeing the significant changes without being overwhelmed by all the white space changes." ) );
bgLayout->addWidget( m_allWhitespaceCheckBox );
m_ignoreTabExpansionCheckBox = new QCheckBox( i18n( "Igno&re changes due to tab expansion" ), moreOptionButtonGroup );
m_ignoreTabExpansionCheckBox->setToolTip( i18n( "This option corresponds to the -E diff option." ) );
m_ignoreTabExpansionCheckBox->setWhatsThis( i18n( "If there is a change because tabs have been expanded into spaces in the other file, then this option will make sure that these do not show up. Kompare currently has some problems applying such changes so be careful when you use this option." ) );
bgLayout->addWidget( m_ignoreTabExpansionCheckBox );
layout->addStretch( 1 );
page->setMinimumSize( sizeHintForWidget( page ) );
m_tabWidget->addTab( page, i18n( "Options" ) );
}
void DiffPage::addExcludeTab()
{
QWidget* page = new QWidget( this );
QVBoxLayout* layout = new QVBoxLayout( page );
layout->setSpacing( KDialog::spacingHint() );
layout->setMargin( KDialog::marginHint() );
m_excludeFilePatternGroupBox = new QGroupBox( page );
m_excludeFilePatternGroupBox->setCheckable(true);
QHBoxLayout *excludeFileLayout = new QHBoxLayout;
m_excludeFilePatternGroupBox->setLayout( excludeFileLayout );
m_excludeFilePatternGroupBox->setTitle( i18n( "File Pattern to Exclude" ) );
m_excludeFilePatternGroupBox->setToolTip( i18n( "If this is checked you can enter a shell pattern in the text box on the right or select entries from the list." ) );
m_excludeFilePatternEditListBox = new KEditListWidget;
excludeFileLayout->addWidget( m_excludeFilePatternEditListBox );
m_excludeFilePatternEditListBox->setObjectName( "exclude_file_pattern_editlistbox" );
m_excludeFilePatternEditListBox->setButtons( KEditListWidget::Add|KEditListWidget::Remove );
m_excludeFilePatternEditListBox->setCheckAtEntering( false );
m_excludeFilePatternEditListBox->setToolTip( i18n( "Here you can enter or remove a shell pattern or select one or more entries from the list." ) );
layout->addWidget( m_excludeFilePatternGroupBox );
connect( m_excludeFilePatternGroupBox, SIGNAL(toggled(bool)), this, SLOT(slotExcludeFilePatternToggled(bool)));
m_excludeFileNameGroupBox = new QGroupBox( page );
m_excludeFileNameGroupBox->setCheckable( true );
excludeFileLayout = new QHBoxLayout;
m_excludeFileNameGroupBox->setLayout( excludeFileLayout );
m_excludeFileNameGroupBox->setTitle( i18n( "File with Filenames to Exclude" ) );
m_excludeFileNameGroupBox->setToolTip( i18n( "If this is checked you can enter a filename in the combo box below." ) );
m_excludeFileURLComboBox = new KUrlComboBox( KUrlComboBox::Files, true );
excludeFileLayout->addWidget( m_excludeFileURLComboBox );
m_excludeFileURLComboBox->setObjectName( "exclude_file_urlcombo" );
m_excludeFileURLComboBox->setToolTip( i18n( "Here you can enter the URL of a file with shell patterns to ignore during the comparison of the folders." ) );
m_excludeFileURLRequester = new KUrlRequester( m_excludeFileURLComboBox,m_excludeFileNameGroupBox );
excludeFileLayout->addWidget( m_excludeFileURLRequester );
m_excludeFileURLRequester->setObjectName("exclude_file_name_urlrequester" );
m_excludeFileURLRequester->setToolTip( i18n( "Any file you select in the dialog that pops up when you click it will be put in the dialog to the left of this button." ) );
layout->addWidget( m_excludeFileNameGroupBox );
connect( m_excludeFileNameGroupBox, SIGNAL(toggled(bool)), this, SLOT(slotExcludeFileToggled(bool)));
layout->addStretch( 1 );
page->setMinimumSize( sizeHintForWidget( page ) );
m_tabWidget->addTab( page, i18n( "Exclude" ) );
}
#include "diffpage.moc"
//kate: replace-tabs 0; indent-width 4; tab-width 4;

View file

@ -0,0 +1,103 @@
/***************************************************************************
diffprefs.h
-----------
begin : Sun Mar 4 2001
Copyright 2001-2004 Otto Bruggeman <otto.bruggeman@home.nl>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2007 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#ifndef DIFFPAGE_H
#define DIFFPAGE_H
#include "pagebase.h"
#include "dialogpagesexport.h"
class QCheckBox;
class QDialog;
class QSpinBox;
class QStringList;
class QButtonGroup;
class QGroupBox;
class KLineEdit;
class KEditListWidget;
class KTabWidget;
class KUrlComboBox;
class KUrlRequester;
class DiffSettings;
class DIALOGPAGES_EXPORT DiffPage : public PageBase
{
Q_OBJECT
public:
DiffPage();
~DiffPage();
public:
void setSettings( DiffSettings* );
DiffSettings* settings( void );
public:
virtual void restore();
virtual void apply();
virtual void setDefaults();
protected slots:
void slotShowRegExpEditor();
void slotExcludeFilePatternToggled( bool );
void slotExcludeFileToggled( bool );
private:
void addDiffTab();
void addFormatTab();
void addOptionsTab();
void addExcludeTab();
public:
DiffSettings* m_settings;
KUrlRequester* m_diffURLRequester;
QCheckBox* m_newFilesCheckBox;
QCheckBox* m_smallerCheckBox;
QCheckBox* m_largerCheckBox;
QCheckBox* m_tabsCheckBox;
QCheckBox* m_caseCheckBox;
QCheckBox* m_linesCheckBox;
QCheckBox* m_whitespaceCheckBox;
QCheckBox* m_allWhitespaceCheckBox;
QCheckBox* m_ignoreTabExpansionCheckBox;
QCheckBox* m_ignoreRegExpCheckBox;
KLineEdit* m_ignoreRegExpEdit;
QStringList* m_ignoreRegExpEditHistory;
QDialog* m_ignoreRegExpDialog;
QGroupBox* m_excludeFilePatternGroupBox;
KEditListWidget* m_excludeFilePatternEditListBox;
QGroupBox* m_excludeFileNameGroupBox;
KUrlComboBox* m_excludeFileURLComboBox;
KUrlRequester* m_excludeFileURLRequester;
// loc == lines of context
QSpinBox* m_locSpinBox;
QButtonGroup* m_modeButtonGroup;
QGroupBox* m_diffProgramGroup;
KTabWidget* m_tabWidget;
};
#endif

View file

@ -0,0 +1,162 @@
/***************************************************************************
filespage.cpp
-------------
begin : Sun Apr 18 2004
Copyright 2004 Otto Bruggeman <otto.bruggeman@home.nl>
Copyright 2007-2011 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#include "filespage.h"
#include <QtGui/QLayout>
#include <QGroupBox>
#include <QtGui/QVBoxLayout>
#include <QtGui/QHBoxLayout>
#include <kapplication.h>
#include <kcharsets.h>
#include <kconfig.h>
#include <kdebug.h>
#include <kdialog.h>
#include <klocale.h>
#include <kurlcombobox.h>
#include <kurlrequester.h>
#include "filessettings.h"
FilesPage::FilesPage() : PageBase()
{
QWidget* page = new QWidget( this );
QVBoxLayout* layout = new QVBoxLayout( page );
layout->setSpacing( KDialog::spacingHint() );
layout->setMargin( KDialog::marginHint() );
m_firstGB = new QGroupBox( "You have to set this moron :)", page );
layout->addWidget( m_firstGB );
QHBoxLayout* gb1Layout = new QHBoxLayout( m_firstGB );
m_firstURLComboBox = new KUrlComboBox( KUrlComboBox::Both, true, m_firstGB );
m_firstURLComboBox->setObjectName( "SourceURLComboBox" );
m_firstURLRequester = new KUrlRequester( m_firstURLComboBox, m_firstGB );
gb1Layout->addWidget( m_firstURLRequester );
m_firstURLRequester->setFocus();
m_secondGB = new QGroupBox( "This too moron !", page );
layout->addWidget( m_secondGB );
QHBoxLayout* gb2Layout = new QHBoxLayout( m_secondGB );
m_secondURLComboBox = new KUrlComboBox( KUrlComboBox::Both, true, m_secondGB );
m_secondURLComboBox->setObjectName( "DestURLComboBox" );
m_secondURLRequester = new KUrlRequester( m_secondURLComboBox, m_secondGB );
gb2Layout->addWidget( m_secondURLRequester );
m_thirdGB = new QGroupBox( i18n( "Encoding" ), page );
layout->addWidget( m_thirdGB );
QHBoxLayout* gb3Layout = new QHBoxLayout( m_thirdGB );
m_encodingComboBox = new KComboBox( false, m_thirdGB );
m_encodingComboBox->setObjectName( "encoding_combobox" );
m_encodingComboBox->insertItem( 0, "Default" );
m_encodingComboBox->insertItems( 1, KGlobal::charsets()->availableEncodingNames() );
gb3Layout->addWidget( m_encodingComboBox );
layout->addWidget( m_firstGB );
layout->addWidget( m_secondGB );
layout->addWidget( m_thirdGB );
layout->addStretch( 1 );
page->setMinimumSize( sizeHintForWidget( page ) );
//addTab( page, i18n( "&Files" ) );
}
FilesPage::~FilesPage()
{
m_settings = 0;
}
KUrlRequester* FilesPage::firstURLRequester() const
{
return m_firstURLRequester;
}
KUrlRequester* FilesPage::secondURLRequester() const
{
return m_secondURLRequester;
}
QString FilesPage::encoding() const
{
return m_encodingComboBox->currentText();
}
void FilesPage::setFirstGroupBoxTitle( const QString& title )
{
m_firstGB->setTitle( title );
}
void FilesPage::setSecondGroupBoxTitle( const QString& title )
{
m_secondGB->setTitle( title );
}
void FilesPage::setURLsInComboBoxes()
{
// kDebug() << "first : " << m_firstURLComboBox->currentText() << endl;
// kDebug() << "second: " << m_secondURLComboBox->currentText() << endl;
m_firstURLComboBox->setUrl( KUrl( m_firstURLComboBox->currentText() ) );
m_secondURLComboBox->setUrl( KUrl( m_secondURLComboBox->currentText() ) );
}
void FilesPage::setFirstURLRequesterMode( unsigned int mode )
{
m_firstURLRequester->setMode( (KFile::Mode) mode );
}
void FilesPage::setSecondURLRequesterMode( unsigned int mode )
{
m_secondURLRequester->setMode( (KFile::Mode) mode );
}
void FilesPage::setSettings( FilesSettings* settings )
{
m_settings = settings;
m_firstURLComboBox->setUrls( m_settings->m_recentSources );
m_firstURLComboBox->setUrl( KUrl( m_settings->m_lastChosenSourceURL ) );
m_secondURLComboBox->setUrls( m_settings->m_recentDestinations );
m_secondURLComboBox->setUrl( KUrl( m_settings->m_lastChosenDestinationURL ) );
m_encodingComboBox->setCurrentIndex( m_encodingComboBox->findText( m_settings->m_encoding, Qt::MatchFixedString ) );
}
void FilesPage::restore()
{
// this shouldn't do a thing...
}
void FilesPage::apply()
{
m_settings->m_recentSources = m_firstURLComboBox->urls();
m_settings->m_lastChosenSourceURL = m_firstURLComboBox->currentText();
m_settings->m_recentDestinations = m_secondURLComboBox->urls();
m_settings->m_lastChosenDestinationURL = m_secondURLComboBox->currentText();
m_settings->m_encoding = m_encodingComboBox->currentText();
}
void FilesPage::setDefaults()
{
m_firstURLComboBox->setUrls( QStringList() );
m_firstURLComboBox->setUrl( KUrl( "" ) );
m_secondURLComboBox->setUrls( QStringList() );
m_secondURLComboBox->setUrl( KUrl( "" ) );
m_encodingComboBox->setCurrentIndex( 0 ); // "Default"
}
#include "filespage.moc"

View file

@ -0,0 +1,76 @@
/***************************************************************************
kcompareurldialog.h
-------------------
begin : Sun Mar 4 2001
Copyright 2001-2004 Otto Bruggeman <otto.bruggeman@home.nl>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2007 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#ifndef FILESPAGE_H
#define FILESPAGE_H
#include "pagebase.h"
#include "dialogpagesexport.h"
class QGroupBox;
class KComboBox;
class KUrlComboBox;
class KUrlRequester;
class FilesSettings;
class DIALOGPAGES_EXPORT FilesPage : public PageBase
{
Q_OBJECT
public:
FilesPage();
virtual ~FilesPage();
public:
KUrlRequester* firstURLRequester() const;
KUrlRequester* secondURLRequester() const;
QString encoding() const;
void setFirstGroupBoxTitle ( const QString& title );
void setSecondGroupBoxTitle( const QString& title );
void setURLsInComboBoxes();
void setFirstURLRequesterMode( unsigned int mode );
void setSecondURLRequesterMode( unsigned int mode );
public:
virtual void setSettings( FilesSettings* settings );
virtual void restore();
virtual void apply();
virtual void setDefaults();
private:
QGroupBox* m_firstGB;
QGroupBox* m_secondGB;
QGroupBox* m_thirdGB;
KUrlComboBox* m_firstURLComboBox;
KUrlComboBox* m_secondURLComboBox;
KUrlRequester* m_firstURLRequester;
KUrlRequester* m_secondURLRequester;
// Use this bool to lock the connection between both KUrlRequesters.
// This prevents annoying behaviour
bool m_URLChanged;
KComboBox* m_encodingComboBox;
FilesSettings* m_settings;
};
#endif

View file

@ -0,0 +1,60 @@
/***************************************************************************
filessettings.cpp
-----------------
begin : Sun Apr 18 2004
Copyright 2004 Otto Bruggeman <otto.bruggeman@home.nl>
Copyright 2007 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
****************************************************************************/
#include "filessettings.h"
#include <kapplication.h>
#include <kconfig.h>
#include <kconfiggroup.h>
FilesSettings::FilesSettings( QWidget* parent )
: SettingsBase( parent )
{
}
FilesSettings::~FilesSettings()
{
}
void FilesSettings::loadSettings( KConfig* config )
{
KConfigGroup group( config, m_configGroupName );
m_recentSources = group.readEntry( "Recent Sources", QStringList() );
m_lastChosenSourceURL = group.readEntry ( "LastChosenSourceListEntry", "" );
m_recentDestinations = group.readEntry( "Recent Destinations", QStringList() );
m_lastChosenDestinationURL = group.readEntry ( "LastChosenDestinationListEntry", "" );
m_encoding = group.readEntry ( "Encoding", "default" );
}
void FilesSettings::saveSettings( KConfig* config )
{
KConfigGroup group( config, m_configGroupName );
group.writeEntry( "Recent Sources", m_recentSources );
group.writeEntry( "Recent Destinations", m_recentDestinations );
group.writeEntry( "LastChosenSourceListEntry", m_lastChosenSourceURL );
group.writeEntry( "LastChosenDestinationListEntry", m_lastChosenDestinationURL );
group.writeEntry( "Encoding", m_encoding );
config->sync();
}
void FilesSettings::setGroup( const QString& groupName )
{
m_configGroupName = groupName;
}
#include "filessettings.moc"

View file

@ -0,0 +1,54 @@
/***************************************************************************
filessettings.h
---------------
begin : Sun Apr 18 2004
Copyright 2004 Otto Bruggeman <otto.bruggeman@home.nl>
****************************************************************************/
/***************************************************************************
**
** 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.
**
****************************************************************************/
#ifndef FILESSETTINGS_H
#define FILESSETTINGS_H
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <settingsbase.h>
#include "dialogpagesexport.h"
class KConfig;
class DIALOGPAGES_EXPORT FilesSettings : public SettingsBase
{
Q_OBJECT
public:
FilesSettings( QWidget* parent );
virtual ~FilesSettings();
public:
// some virtual functions that will be overloaded from the base class
virtual void loadSettings( KConfig* config );
virtual void saveSettings( KConfig* config );
void setGroup( const QString& groupName );
public:
QString m_configGroupName;
QStringList m_recentSources;
QString m_lastChosenSourceURL;
QStringList m_recentDestinations;
QString m_lastChosenDestinationURL;
QString m_encoding;
};
#endif // FILESSETTINGS_H

View file

@ -0,0 +1,105 @@
/***************************************************************************
prefsbase.cpp
-------------
begin : Sun Mar 4 2001
Copyright 2001 Otto Bruggeman <otto.bruggeman@home.nl>
Copyright 2001 John Firebaugh <jfirebaugh@kde.org>
Copyright 2007 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#include "pagebase.h"
#include <QtCore/QObject>
#include <QtGui/QLayout>
PageBase::PageBase() : KVBox()
{
}
PageBase::~PageBase()
{
}
/** No descriptions */
QSize PageBase::sizeHintForWidget( QWidget* widget )
{
//
// The size is computed by adding the sizeHint().height() of all
// widget children and taking the width of the widest child and adding
// layout()->margin() and layout()->spacing()
//
// this code in this method has been ripped out of a file in kbabel
// so copyright goes to the kbabel authors.
QSize size;
int numChild = 0;
QList<QObject*> l = widget->children();
for( int i=0; i < l.count(); i++ )
{
QObject *o = l.at(i);
if( o->isWidgetType() )
{
numChild += 1;
QWidget *w=((QWidget*)o);
QSize s = w->sizeHint();
if( s.isEmpty() == true )
{
s = QSize( 50, 100 ); // Default size
}
size.setHeight( size.height() + s.height() );
if( s.width() > size.width() )
{
size.setWidth( s.width() );
}
}
}
if( numChild > 0 )
{
size.setHeight( size.height() + widget->layout()->spacing()*(numChild-1) );
size += QSize( widget->layout()->margin()*2, widget->layout()->margin()*2 + 1 );
}
else
{
size = QSize( 1, 1 );
}
return( size );
}
/** No descriptions */
void PageBase::apply()
{
}
/** No descriptions */
void PageBase::restore()
{
}
/** No descriptions */
void PageBase::setDefaults()
{
}
#include "pagebase.moc"

View file

@ -0,0 +1,45 @@
/***************************************************************************
prefsbase.h
-----------
begin : Sun Mar 4 2001
Copyright 2001 Otto Bruggeman <otto.bruggeman@home.nl>
Copyright 2001 John Firebaugh <jfirebaugh@kde.org>
Copyright 2007 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#ifndef PAGEBASE_H
#define PAGEBASE_H
#include <QtCore/QSize>
#include <kvbox.h>
#include <kompare.h>
class PageBase : public KVBox
{
Q_OBJECT
public:
PageBase();
~PageBase();
public:
/** No descriptions */
QSize sizeHintForWidget( QWidget* widget );
/** No descriptions */
virtual void restore();
/** No descriptions */
virtual void apply();
/** No descriptions */
virtual void setDefaults();
};
#endif

View file

@ -0,0 +1,216 @@
/***************************************************************************
viewprefs.cpp
-------------
begin : Sun Mar 4 2001
Copyright 2001-2002 Otto Bruggeman <otto.bruggeman@home.nl>
Copyright 2001-2002 John Firebaugh <jfirebaugh@kde.org>
Copyright 2007-2011 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#include "viewpage.h"
#include <QtGui/QCheckBox>
#include <QtGui/QGroupBox>
#include <QtGui/QLabel>
#include <QtGui/QLayout>
#include <QtGui/QSpinBox>
#include <QtGui/QVBoxLayout>
#include <QtGui/QGridLayout>
#include <QtGui/QFontComboBox>
#include <kapplication.h>
#include <kcolorbutton.h>
#include <kdialog.h>
#include <klocale.h>
#include <kglobal.h>
#include <ktabwidget.h>
#include "viewsettings.h"
ViewPage::ViewPage() : PageBase()
{
QWidget* page;
QVBoxLayout* layout;
QGridLayout* gridLayout;
QGroupBox* colorGroupBox;
QGroupBox* snolGroupBox;
QGroupBox* tabGroupBox;
QLabel* label;
m_tabWidget = new KTabWidget( this );
page = new QWidget( m_tabWidget );
layout = new QVBoxLayout( page );
layout->setSpacing( KDialog::spacingHint() );
layout->setMargin( KDialog::marginHint() );
// add a groupbox
colorGroupBox = new QGroupBox( page );
colorGroupBox->setTitle( i18n( "Colors" ) );
layout->addWidget( colorGroupBox );
//colorGroupBox->setMargin( KDialog::marginHint() );
gridLayout = new QGridLayout( colorGroupBox );
// add the removeColor
label = new QLabel( i18n( "Removed color:" ), colorGroupBox );
m_removedColorButton = new KColorButton( colorGroupBox );
label->setBuddy( m_removedColorButton );
gridLayout->addWidget( label, 0, 0 );
gridLayout->addWidget( m_removedColorButton, 0, 1 );
// add the changeColor
label = new QLabel( i18n( "Changed color:" ), colorGroupBox );
m_changedColorButton = new KColorButton( colorGroupBox );
label->setBuddy( m_changedColorButton );
gridLayout->addWidget( label, 1, 0 );
gridLayout->addWidget( m_changedColorButton, 1, 1 );
// add the addColor
label = new QLabel( i18n( "Added color:" ), colorGroupBox );
m_addedColorButton = new KColorButton( colorGroupBox );
label->setBuddy( m_addedColorButton );
gridLayout->addWidget( label, 2, 0 );
gridLayout->addWidget( m_addedColorButton, 2, 1 );
// add the appliedColor
label = new QLabel( i18n( "Applied color:" ), colorGroupBox );
m_appliedColorButton = new KColorButton( colorGroupBox );
label->setBuddy( m_appliedColorButton );
gridLayout->addWidget( label, 3, 0 );
gridLayout->addWidget( m_appliedColorButton, 3, 1 );
// scroll number of lines (snol)
snolGroupBox = new QGroupBox( page );
QHBoxLayout *snolLayout = new QHBoxLayout;
snolGroupBox->setLayout( snolLayout );
snolGroupBox->setTitle( i18n( "Mouse Wheel" ) );
layout->addWidget( snolGroupBox );
//snolGroupBox->setMargin( KDialog::marginHint() );
label = new QLabel( i18n( "Number of lines:" ) );
snolLayout->addWidget( label );
m_snolSpinBox = new QSpinBox( snolGroupBox );
m_snolSpinBox->setRange( 0, 50 );
snolLayout->addWidget( m_snolSpinBox );
label->setBuddy( m_snolSpinBox );
// Temporarily here for testing...
// number of spaces for a tab character stuff
tabGroupBox = new QGroupBox( page );
QHBoxLayout *tabLayout = new QHBoxLayout;
tabGroupBox->setLayout( tabLayout );
tabGroupBox->setTitle( i18n( "Tabs to Spaces" ) );
layout->addWidget( tabGroupBox );
//tabGroupBox->setMargin( KDialog::marginHint() );
label = new QLabel( i18n( "Number of spaces to convert a tab character to:" ) );
tabLayout->addWidget( label );
m_tabSpinBox = new QSpinBox( tabGroupBox );
m_tabSpinBox->setRange( 1, 16 );
tabLayout->addWidget( m_tabSpinBox );
label->setBuddy( m_tabSpinBox );
layout->addStretch( 1 );
page->setMinimumSize( sizeHintForWidget( page ) );
m_tabWidget->addTab( page, i18n( "Appearance" ) );
page = new QWidget( m_tabWidget );
layout = new QVBoxLayout( page );
layout->setSpacing( KDialog::spacingHint() );
layout->setMargin( KDialog::marginHint() );
QGroupBox* gb = new QGroupBox( page );
QHBoxLayout *layfont = new QHBoxLayout;
gb->setLayout( layfont );
gb->setTitle( i18n( "Text Font" ) );
layout->addWidget( gb );
//gb->setMargin( KDialog::marginHint() );
label = new QLabel( i18n( "Font:" ) );
m_fontCombo = new QFontComboBox;
layfont->addWidget( label );
layfont->addWidget( m_fontCombo );
m_fontCombo->setObjectName( "fontcombo" );
label->setBuddy( m_fontCombo );
label = new QLabel( i18n( "Size:" ) );
layfont->addWidget( label );
m_fontSizeSpinBox = new QSpinBox( gb );
m_fontSizeSpinBox->setRange( 6, 24 );
layfont->addWidget( m_fontSizeSpinBox );
label->setBuddy( m_fontSizeSpinBox );
layout->addStretch( 1 );
page->setMinimumSize( sizeHintForWidget( page ) );
m_tabWidget->addTab( page, i18n( "Fonts" ) );
}
ViewPage::~ViewPage()
{
}
void ViewPage::setSettings( ViewSettings* setts )
{
m_settings = setts;
m_addedColorButton->setColor ( m_settings->m_addColor );
m_changedColorButton->setColor( m_settings->m_changeColor );
m_removedColorButton->setColor( m_settings->m_removeColor );
m_appliedColorButton->setColor( m_settings->m_appliedColor );
m_snolSpinBox->setValue ( m_settings->m_scrollNoOfLines );
m_tabSpinBox->setValue ( m_settings->m_tabToNumberOfSpaces );
m_fontCombo->setCurrentFont ( m_settings->m_font.family() );
m_fontSizeSpinBox->setValue ( m_settings->m_font.pointSize() );
}
ViewSettings* ViewPage::settings( void )
{
return m_settings;
}
void ViewPage::restore()
{
}
void ViewPage::apply()
{
m_settings->m_addColor = m_addedColorButton->color();
m_settings->m_changeColor = m_changedColorButton->color();
m_settings->m_removeColor = m_removedColorButton->color();
m_settings->m_appliedColor = m_appliedColorButton->color();
m_settings->m_scrollNoOfLines = m_snolSpinBox->value();
m_settings->m_tabToNumberOfSpaces = m_tabSpinBox->value();
m_settings->m_font = QFont( m_fontCombo->currentFont() );
m_settings->m_font.setPointSize( m_fontSizeSpinBox->value() );
m_settings->saveSettings( KGlobal::config().data() );
}
void ViewPage::setDefaults()
{
m_addedColorButton->setColor ( ViewSettings::default_addColor );
m_changedColorButton->setColor( ViewSettings::default_changeColor );
m_removedColorButton->setColor( ViewSettings::default_removeColor );
m_appliedColorButton->setColor( ViewSettings::default_appliedColor );
m_snolSpinBox->setValue ( 3 );
m_tabSpinBox->setValue ( 4 );
// TODO: port
// m_fontCombo->setCurrentFont ( KGlobalSettings::fixedFont().family() );
m_fontSizeSpinBox->setValue ( 10 );
}
#include "viewpage.moc"

View file

@ -0,0 +1,65 @@
/***************************************************************************
generalprefs.h
--------------
begin : Sun Mar 4 2001
Copyright 2001-2003 Otto Bruggeman <otto.bruggeman@home.nl>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2007 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#ifndef VIEWPAGE_H
#define VIEWPAGE_H
#include "pagebase.h"
#include "dialogpagesexport.h"
class QFontComboBox;
class QSpinBox;
class KColorButton;
class KTabWidget;
class ViewSettings;
class DIALOGPAGES_EXPORT ViewPage : public PageBase
{
Q_OBJECT
public:
ViewPage();
~ViewPage();
public:
void setSettings( ViewSettings* );
ViewSettings* settings( void );
public:
ViewSettings* m_settings;
public:
virtual void restore();
virtual void apply();
virtual void setDefaults();
public:
KColorButton* m_removedColorButton;
KColorButton* m_changedColorButton;
KColorButton* m_addedColorButton;
KColorButton* m_appliedColorButton;
// snol == scroll number of lines
QSpinBox* m_snolSpinBox;
QSpinBox* m_tabSpinBox;
QFontComboBox* m_fontCombo;
QSpinBox* m_fontSizeSpinBox;
KTabWidget* m_tabWidget;
};
#endif

View file

@ -0,0 +1,101 @@
/***************************************************************************
generalsettings.cpp
-------------------
begin : Sun Mar 4 2001
Copyright 2001-2003 Otto Bruggeman <otto.bruggeman@home.nl>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2007 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#include "viewsettings.h"
#include <QtGui/QFont>
#include <kconfig.h>
#include <kglobalsettings.h>
#include <kconfiggroup.h>
using namespace Diff2;
const QColor ViewSettings::default_removeColor (190, 237, 190);
const QColor ViewSettings::default_changeColor (237, 190, 190);
const QColor ViewSettings::default_addColor (190, 190, 237);
const QColor ViewSettings::default_appliedColor(237, 237, 190);
ViewSettings::ViewSettings( QWidget* parent )
: SettingsBase( parent ),
m_removeColor( 0, 0, 0 ),
m_changeColor( 0, 0, 0),
m_addColor( 0, 0, 0),
m_appliedColor( 0, 0, 0),
m_scrollNoOfLines( 0 ),
m_tabToNumberOfSpaces( 0 )
{
}
ViewSettings::~ViewSettings()
{
}
void ViewSettings::loadSettings( KConfig* config )
{
KConfigGroup cfg( config, "View Options" );
m_removeColor = cfg.readEntry( "RemoveColor", default_removeColor );
m_changeColor = cfg.readEntry( "ChangeColor", default_changeColor );
m_addColor = cfg.readEntry( "AddColor", default_addColor );
m_appliedColor = cfg.readEntry( "AppliedColor", default_appliedColor );
m_scrollNoOfLines = cfg.readEntry ( "ScrollNoOfLines", 3 );
m_tabToNumberOfSpaces = cfg.readEntry ( "TabToNumberOfSpaces", 4 );
QFont stdFixed = KGlobalSettings::fixedFont();
stdFixed.setPointSize( 10 );
m_font = cfg.readEntry ( "TextFont", stdFixed );
}
void ViewSettings::saveSettings( KConfig* config )
{
KConfigGroup cfg( config, "View Options" );
cfg.writeEntry( "RemoveColor", m_removeColor );
cfg.writeEntry( "ChangeColor", m_changeColor );
cfg.writeEntry( "AddColor", m_addColor );
cfg.writeEntry( "AppliedColor", m_appliedColor );
cfg.writeEntry( "ScrollNoOfLines", m_scrollNoOfLines );
cfg.writeEntry( "TabToNumberOfSpaces", m_tabToNumberOfSpaces );
cfg.writeEntry( "TextFont", m_font );
}
QColor ViewSettings::colorForDifferenceType( int type, bool selected, bool applied )
{
// FIXME: does not belong here
QColor color;
if( applied )
color = m_appliedColor;
else
{
type = type & 0xFFFFFFEF; // remove the AppliedByBlend
switch( type ) {
case Difference::Unchanged: color = Qt::white; break;
case Difference::Change: color = m_changeColor; break;
case Difference::Insert: color = m_addColor; break;
case Difference::Delete: color = m_removeColor; break;
default: break;
}
}
if( selected )
color = color.light( 110 );
return color;
}
#include "viewsettings.moc"

View file

@ -0,0 +1,61 @@
/***************************************************************************
generalsettings.h
-----------------
begin : Sun Mar 4 2001
Copyright 2001-2003 Otto Bruggeman <otto.bruggeman@home.nl>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
#ifndef VIEWSETTINGS_H
#define VIEWSETTINGS_H
#include <QtGui/QColor>
#include <QtGui/QWidget>
#include <difference.h>
#include <settingsbase.h>
#include "dialogpagesexport.h"
class DIALOGPAGES_EXPORT ViewSettings : public SettingsBase
{
Q_OBJECT
public:
static const QColor default_removeColor;
static const QColor default_changeColor;
static const QColor default_addColor;
static const QColor default_appliedColor;
ViewSettings( QWidget* parent );
~ViewSettings();
public:
// some virtual functions that will be overloaded from the base class
virtual void loadSettings( KConfig* config );
virtual void saveSettings( KConfig* config );
QColor colorForDifferenceType( int type, bool selected = false, bool applied = false );
public:
QColor m_removeColor;
QColor m_changeColor;
QColor m_addColor;
QColor m_appliedColor;
QColor m_selectedRemoveColor;
QColor m_selectedChangeColor;
QColor m_selectedAddColor;
QColor m_selectedAppliedColor;
int m_scrollNoOfLines;
int m_tabToNumberOfSpaces;
QFont m_font;
};
#endif // VIEWSETTINGS_H

232
kompare/main.cpp Normal file
View file

@ -0,0 +1,232 @@
/***************************************************************************
main.cpp
--------
begin : Sun Mar 4 2001
Copyright 2001-2005,2009 Otto Bruggeman <bruggie@gmail.com>
Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
Copyright 2007-2012 Kevin Kofler <kevin.kofler@chello.at>
****************************************************************************/
/***************************************************************************
**
** 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.
**
***************************************************************************/
/**
* @file main.cpp
* This is the main entry point for Kompare.
* The command line arguments are handled and the application is started.
* @author Otto Bruggeman <otto.bruggeman@home.nl>
* @author John Firebaugh <jfirebaugh@kde.org>
* @author Kevin Kofler <kevin.kofler@chello.at>
*/
#include <kaboutdata.h>
#include <kcmdlineargs.h>
#include <kdebug.h>
#include <kfile.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kdialog.h>
#include "kompare_part.h"
#include "kompare_shell.h"
#include "kompareurldialog.h"
/**
* Program description.
*/
static const char description[] =
I18N_NOOP("A program to view the differences between files and optionally generate a diff" );
/**
* Version number.
*/
static const char version[] = "4.1.3";
/**
* Setting up the KAboutData structure.
* Parsing and handling of the given command line arguments.
* @param argc the number of arguments
* @param argv the array of arguments
* @return exit status
*/
int main(int argc, char *argv[])
{
KAboutData aboutData( "kompare", 0, ki18n("Kompare"), version, ki18n(description),
KAboutData::License_GPL,
ki18n("(c) 2001-2004 John Firebaugh, (c) 2001-2005,2009 Otto Bruggeman, (c) 2004-2005 Jeff Snyder, (c) 2007-2012 Kevin Kofler") );
aboutData.addAuthor( ki18n("John Firebaugh"), ki18n("Author"), "jfirebaugh@kde.org" );
aboutData.addAuthor( ki18n("Otto Bruggeman"), ki18n("Author"), "bruggie@gmail.com" );
aboutData.addAuthor( ki18n("Jeff Snyder"), ki18n("Developer"), "jeff@caffeinated.me.uk" );
aboutData.addCredit( ki18n("Kevin Kofler"), ki18n("Maintainer"), "kevin.kofler@chello.at" );
aboutData.addCredit( ki18n("Chris Luetchford"), ki18n("Kompare icon artist"), "chris@os11.com" );
aboutData.addCredit( ki18n("Malte Starostik"), ki18n("A lot of good advice"), "malte@kde.org" );
aboutData.addCredit( ki18n("Bernd Gehrmann"), ki18n("Cervisia diff viewer"), "bernd@physik.hu-berlin.de" );
KCmdLineArgs::init(argc, argv, &aboutData);
KCmdLineOptions options;
options.add("c", ki18n( "This will compare URL1 with URL2" ));
options.add("o", ki18n( "This will open URL1 and expect it to be diff output. URL1 can also be a '-' and then it will read from standard input. Can be used for instance for cvs diff | kompare -o -. Kompare will do a check to see if it can find the original file(s) and then blend the original file(s) into the diffoutput and show that in the viewer. -n disables the check." ));
options.add("b", ki18n( "This will blend URL2 into URL1, URL2 is expected to be diff output and URL1 the file or folder that the diffoutput needs to be blended into. " ));
options.add("n", ki18n( "Disables the check for automatically finding the original file(s) when using '-' as URL with the -o option." ));
options.add("e <encoding>", ki18n( "Use this to specify the encoding when calling it from the command line. It will default to the local encoding if not specified." ));
options.add("+[URL1 [URL2]]");
options.add("+-");
KCmdLineArgs::addCmdLineOptions( options );
KApplication kompare;
bool difault = false;
KompareShell* ks;
// see if we are starting with session management
if (kompare.isSessionRestored())
{
RESTORE(KompareShell)
}
else
{
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
ks = new KompareShell();
ks->setObjectName( "FirstKompareShell" );
kDebug( 8100 ) << "Arg Count = " << args->count() << endl;
for ( int i=0; i < args->count(); i++ )
{
kDebug( 8100 ) << "Argument " << (i+1) << ": " << args->arg( i ) << endl;
}
if ( args->isSet( "e" ) )
{
// Encoding given...
// FIXME: Need to implement this...
}
if ( args->isSet( "o" ) )
{
kDebug( 8100 ) << "Option -o is set" << endl;
if ( args->count() != 1 )
{
difault = true;
}
else
{
ks->show();
kDebug( 8100 ) << "OpenDiff..." << endl;
if ( args->arg(0) == QLatin1String("-") )
ks->openStdin();
else
ks->openDiff( args->url( 0 ) );
difault = false;
}
}
else if ( args->isSet( "c" ) )
{
kDebug( 8100 ) << "Option -c is set" << endl;
if ( args->count() != 2 )
{
KCmdLineArgs::usage( "kompare" );
difault = true;
}
else
{
ks->show();
KUrl url0 = args->url( 0 );
kDebug( 8100 ) << "URL0 = " << url0.url() << endl;
KUrl url1 = args->url( 1 );
kDebug( 8100 ) << "URL1 = " << url1.url() << endl;
ks->compare( url0, url1 );
difault = false;
}
}
else if ( args->isSet( "b" ) )
{
kDebug( 8100 ) << "Option -b is set" << endl;
if ( args->count() != 2 )
{
KCmdLineArgs::usage( "kompare" );
difault = true;
}
else
{
ks->show();
kDebug( 8100 ) << "blend..." << endl;
KUrl url0 = args->url( 0 );
kDebug( 8100 ) << "URL0 = " << url0.url() << endl;
KUrl url1 = args->url( 1 );
kDebug( 8100 ) << "URL1 = " << url1.url() << endl;
ks->blend( url0, url1 );
difault = false;
}
}
else if ( args->count() == 1 )
{
ks->show();
kDebug( 8100 ) << "Single file. so openDiff/openStdin is only possible..." << endl;
if ( args->arg(0) == QLatin1String("-") )
ks->openStdin();
else
ks->openDiff( args->url( 0 ) );
difault = false;
}
else if ( args->count() == 2 )
{
// In this case we are assuming you want to compare files/dirs
// and not blending because that is almost impossible to detect
ks->show();
kDebug( 8100 ) << "Dunno, we'll have to figure it out later, trying compare for now..." << endl;
KUrl url0 = args->url( 0 );
kDebug( 8100 ) << "URL0 = " << url0.url() << endl;
KUrl url1 = args->url( 1 );
kDebug( 8100 ) << "URL1 = " << url1.url() << endl;
ks->compare( url0, url1 );
difault = false;
}
else if ( args->count() == 0 ) // no options and no args
{
difault = true;
}
if ( difault )
{
KompareURLDialog dialog( 0 );
dialog.setCaption( i18n("Compare Files or Folders") );
dialog.setFirstGroupBoxTitle( i18n( "Source" ) );
dialog.setSecondGroupBoxTitle( i18n( "Destination" ) );
KGuiItem compareGuiItem( i18n( "Compare" ), QString(), i18n( "Compare these files or folder" ), i18n( "If you have entered 2 filenames or 2 folders in the fields in this dialog then this button will be enabled and pressing it will start a comparison of the entered files or folders. " ) );
dialog.setButtonGuiItem( KDialog::Ok, compareGuiItem );
dialog.setGroup( "Recent Compare Files" );
dialog.setFirstURLRequesterMode( KFile::File|KFile::Directory|KFile::ExistingOnly );
dialog.setSecondURLRequesterMode( KFile::File|KFile::Directory|KFile::ExistingOnly );
if( dialog.exec() == QDialog::Accepted )
{
ks->show();
ks->viewPart()->setEncoding( dialog.encoding() );
ks->compare( dialog.getFirstURL(), dialog.getSecondURL() );
}
else
{
return -1;
}
}
args->clear();
}
return kompare.exec();
}
/* vim: set ts=4 sw=4 noet: */

View file

@ -0,0 +1,5 @@
kde4_install_icons( ${ICON_INSTALL_DIR} )

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

View file

@ -0,0 +1,83 @@
Index: client/dcopfind.cpp
===================================================================
RCS file: /home/kde/kdelibs/dcop/client/dcopfind.cpp,v
retrieving revision 1.2
diff -c -r1.2 dcopfind.cpp
*** client/dcopfind.cpp 2001/10/31 01:17:39 1.2
--- client/dcopfind.cpp 2002/01/16 18:07:13
***************
*** 36,42 ****
static bool bAppIdOnly = 0;
static bool bLaunchApp = 0;
! bool findObject( const char* app, const char* obj, const char* func, int argc, char** args )
{
QString f = func; // Qt is better with unicode strings, so use one.
int left = f.find( '(' );
--- 36,42 ----
static bool bAppIdOnly = 0;
static bool bLaunchApp = 0;
! bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
{
QString f = func; // Qt is better with unicode strings, so use one.
int left = f.find( '(' );
***************
*** 118,124 ****
f = fc;
}
! if ( (int) types.count() != argc ) {
qWarning( "arguments do not match" );
exit(1);
}
--- 118,124 ----
f = fc;
}
! if ( types.count() != args.count() ) {
qWarning( "arguments do not match" );
exit(1);
}
***************
*** 128,136 ****
int i = 0;
for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
! marshall(arg, argc, args, i, *it);
}
! if ( (int) i != argc ) {
qWarning( "arguments do not match" );
exit(1);
}
--- 128,136 ----
int i = 0;
for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
! marshall(arg, args, i, *it);
}
! if ( (uint) i != args.count() ) {
qWarning( "arguments do not match" );
exit(1);
}
***************
*** 221,227 ****
argc = 0;
}
! findObject( app, objid, function, argc, args );
return 0;
}
--- 221,231 ----
argc = 0;
}
! QCStringList params;
! for( int i = 0; i < argc; i++ )
! params.append( args[ i ] );
!
! findObject( app, objid, function, params );
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,24 @@
Index: client/dcopfind.cpp
===================================================================
RCS file: /home/kde/kdelibs/dcop/client/dcopfind.cpp,v
retrieving revision 1.2
diff -e -r1.2 dcopfind.cpp
224c
QCStringList params;
for( int i = 0; i < argc; i++ )
params.append( args[ i ] );
findObject( app, objid, function, params );
.
133c
if ( (uint) i != args.count() ) {
.
131c
marshall(arg, args, i, *it);
.
121c
if ( types.count() != args.count() ) {
.
39c
bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
.

View file

@ -0,0 +1,692 @@
Index: client/dcop.cpp
===================================================================
RCS file: /home/kde/kdelibs/dcop/client/dcop.cpp,v
retrieving revision 1.26
diff -e -r1.26 dcop.cpp
343a
// vim: set ts=8 sts=4 sw=4 noet:
.
340a
}
int main( int argc, char** argv )
{
bool readStdin = false;
int numOptions = 0;
QString user;
Session session = DefaultSession;
QString sessionName;
// Scan for command-line options first
for( int pos = 1 ; pos <= argc - 1 ; pos++ )
{
if( strcmp( argv[ pos ], "--help" ) == 0 )
showHelp( 0 );
else if( strcmp( argv[ pos ], "--pipe" ) == 0 )
{
readStdin = true;
numOptions++;
}
else if( strcmp( argv[ pos ], "--user" ) == 0 )
{
if( pos <= argc - 2 )
{
user = QString::fromLocal8Bit( argv[ pos + 1] );
numOptions +=2;
pos++;
}
else
{
cerr << "Missing username for '--user' option!" << endl << endl;
showHelp( -1 );
}
}
else if( strcmp( argv[ pos ], "--all-users" ) == 0 )
{
user = "*";
numOptions ++;
}
else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 )
{
session = QuerySessions;
numOptions ++;
}
else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 )
{
session = AllSessions;
numOptions ++;
}
else if( argv[ pos ][ 0 ] == '-' )
{
cerr << "Unknown command-line option '" << argv[ pos ]
<< "'." << endl << endl;
showHelp( -1 );
}
else
break; // End of options
}
argc -= numOptions;
QCStringList args;
for( int i = numOptions; i < argc + numOptions - 1; i++ )
args.append( argv[ i + 1 ] );
if( readStdin && args.count() < 3 )
{
cerr << "--pipe option only supported for function calls!" << endl << endl;
showHelp( -1 );
}
if( user == "*" && args.count() < 3 && session != QuerySessions )
{
cerr << "ERROR: The --all-users option is only supported for function calls!" << endl << endl;
showHelp( -1 );
}
if( session == QuerySessions && !args.isEmpty() )
{
cerr << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl;
showHelp( -1 );
}
if( session == QuerySessions && user.isEmpty() )
{
cerr << "ERROR: The --list-sessions option can only be used with the --user or" << endl
<< "--all-users options!" << endl << endl;
showHelp( -1 );
}
if( session != DefaultSession && session != QuerySessions &&
args.count() < 3 )
{
cerr << "ERROR: The --session and --all-sessions options are only supported for function" << endl
<< "calls!" << endl << endl;
showHelp( -1 );
}
UserList users;
if( user == "*" )
users = userList();
else if( !user.isEmpty() )
users[ user ] = userList()[ user ];
runDCOP( args, users, session, sessionName, readStdin );
.
339a
if( users.count() > 1 || ( users.count() == 1 &&
( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) )
{
// Check for ICE authority file and if the file can be read by us
QString home = it.data();
QString iceFile = it.data() + "/.ICEauthority";
QFileInfo fi( iceFile );
if( iceFile.isEmpty() )
{
cerr << "WARNING: Cannot determine home directory for user "
<< it.key() << "!" << endl
<< "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
<< "calling dcop." << endl;
}
else if( fi.exists() )
{
if( fi.isReadable() )
{
char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() );
putenv( envStr );
//cerr << "ice: " << envStr << endl;
}
else
{
cerr << "WARNING: ICE authority file " << iceFile
<< "is not readable by you!" << endl
<< "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
<< "calling dcop." << endl;
}
}
else
{
if( users.count() > 1 )
continue;
else
{
cerr << "WARNING: Cannot find ICE authority file "
<< iceFile << "!" << endl
<< "Please check permissions or set the $ICEAUTHORITY"
<< " variable manually before" << endl
<< "calling dcop." << endl;
}
}
}
// Main loop
// If users is an empty list we're calling for the currently logged
// in user. In this case we don't have a session, but still want
// to iterate the loop once.
QStringList::Iterator sIt = sessions.begin();
for( ; sIt != sessions.end() || users.isEmpty(); sIt++ )
{
if( !presetDCOPServer && !users.isEmpty() )
{
QString dcopFile = it.data() + "/" + *sIt;
QFile f( dcopFile );
if( !f.open( IO_ReadOnly ) )
{
cerr << "Can't open " << dcopFile << " for reading!" << endl;
exit( -1 );
}
QStringList l( QStringList::split( '\n', f.readAll() ) );
dcopServer = l.first();
if( dcopServer.isEmpty() )
{
cerr << "WARNING: Unable to determine DCOP server for session "
<< *sIt << "!" << endl
<< "Please check permissions or set the $DCOPSERVER variable manually before" << endl
<< "calling dcop." << endl;
exit( -1 );
}
}
delete client;
client = new DCOPClient;
if( !dcopServer.isEmpty() )
client->setServerAddress( dcopServer.ascii() );
bool success = client->attach();
if( !success )
{
cerr << "ERROR: Couldn't attach to DCOP server!" << endl;
continue;
}
dcop = client;
switch ( args.count() )
{
case 0:
queryApplications("");
break;
case 1:
if (endsWith(app, '*'))
queryApplications(app);
else
queryObjects( app, "" );
break;
case 2:
if (endsWith(objid, '*'))
queryObjects(app, objid);
else
queryFunctions( app, objid );
break;
case 3:
default:
if( readStdin )
{
QCStringList::Iterator replaceArg = args.end();
QCStringList::Iterator it;
for( it = args.begin(); it != args.end(); it++ )
if( *it == "%1" )
replaceArg = it;
// Read from stdin until EOF and call function for each line read
char *buf = new char[ 1000 ];
while ( !feof( stdin ) )
{
fgets( buf, 1000, stdin );
if( replaceArg != args.end() )
*replaceArg = buf;
callFunction( app, objid, function, params );
}
}
else
{
// Just call function
// cout << "call " << app << ", " << objid << ", " << function << ", (params)" << endl;
callFunction( app, objid, function, params );
}
break;
}
// Another sIt++ would make the loop infinite...
if( users.isEmpty() )
break;
}
// Another it++ would make the loop infinite...
if( it == users.end() )
break;
.
308,338c
if( !args.isEmpty() )
app = args[ 0 ];
if( args.count() > 1 )
objid = args[ 1 ];
if( args.count() > 2 )
function = args[ 2 ];
if( args.count() > 3)
{
params = args;
params.remove( params.begin() );
params.remove( params.begin() );
params.remove( params.begin() );
}
}
bool firstRun = true;
UserList::Iterator it;
QStringList sessions;
bool presetDCOPServer = false;
// char *dcopStr = 0L;
QString dcopServer;
for( it = users.begin(); it != users.end() || firstRun; it++ )
{
firstRun = false;
//cout << "Iterating '" << it.key() << "'" << endl;
if( session == QuerySessions )
{
QStringList sessions = dcopSessionList( it.key(), it.data() );
if( sessions.isEmpty() )
{
cout << "No active sessions";
if( !( *it ).isEmpty() )
cout << " for user " << *it;
cout << endl;
}
else
{
cout << "Active sessions ";
if( !( *it ).isEmpty() )
cout << "for user " << *it << " ";
cout << ":" << endl;
QStringList::Iterator sIt;
for( sIt = sessions.begin(); sIt != sessions.end(); sIt++ )
cout << " " << *sIt << endl;
cout << endl;
}
continue;
}
if( getenv( "DCOPSERVER" ) )
{
sessions.append( getenv( "DCOPSERVER" ) );
presetDCOPServer = true;
}
if( users.count() > 1 || ( users.count() == 1 &&
( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) )
{
sessions = dcopSessionList( it.key(), it.data() );
if( sessions.isEmpty() )
{
if( users.count() > 1 )
continue;
else
{
cerr << "ERROR: No active KDE sessions!" << endl
<< "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
<< "before calling dcop." << endl;
exit( -1 );
}
}
else if( sessions.count() > 1 && session != AllSessions )
{
cerr << "ERROR: Multiple available KDE sessions!" << endl
<< "Please specify the correct session to use with --session or use the" << endl
<< "--all-sessions option to broadcast to all sessions." << endl;
exit( -1 );
}
}
.
289,304c
// WARNING: This part (until the closing '}') could very
// well be broken now. As I don't know how to trigger and test
// dcoprefs this code is *not* tested. It compiles and it looks
// ok to me, but that's all I can say - Martijn (2001/12/24)
int delimPos = args[ 0 ].findRev( ',' );
if( delimPos == -1 )
{
cerr << "Error: '" << args[ 0 ]
<< "' is not a valid DCOP reference." << endl;
exit( -1 );
}
args[ 0 ][ delimPos ] = 0;
app = args[ 0 ].mid( 8 );
delimPos++;
args[ 0 ][ args[ 0 ].length() - 1 ] = 0;
objid = args[ 0 ].mid( delimPos );
if( args.count() > 1 )
function = args[ 1 ];
if( args.count() > 2 )
{
params = args;
params.remove( params.begin() );
params.remove( params.begin() );
}
.
286,287c
QCStringList params;
DCOPClient *client = 0L;
if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
.
282a
/**
* Do the actual DCOP call
*/
void runDCOP( QCStringList args, UserList users, Session session,
const QString sessionName, bool readStdin )
{
.
279,281c
return result;
}
/**
* Return a list of available DCOP sessions for the specified user
* An empty list means no sessions are available, or an error occurred.
*/
QStringList dcopSessionList( const QString &user, const QString &home )
{
if( home.isEmpty() )
{
cerr << "WARNING: Cannot determine home directory for user "
<< user << "!" << endl
<< "Please check permissions or set the $DCOPSERVER variable manually before" << endl
<< "calling dcop." << endl;
return QStringList();
}
QStringList result;
QFileInfo dirInfo( home );
if( !dirInfo.exists() || !dirInfo.isReadable() )
return result;
QDir d( home );
d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
d.setNameFilter( ".DCOPserver*" );
const QFileInfoList *list = d.entryInfoList();
if( !list )
return result;
QFileInfoListIterator it( *list );
QFileInfo *fi;
while ( ( fi = it.current() ) != 0 )
{
if( fi->isReadable() )
result.append( fi->fileName() );
++it;
}
return result;
}
.
274,276c
QStringList l( QStringList::split( '\n', f.readAll() ) );
for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it )
{
QStringList userInfo( QStringList::split( ':', *it, true ) );
result[ userInfo[ 0 ] ] = userInfo[ 5 ];
.
272a
UserList result;
QFile f( "/etc/passwd" );
if( !f.open( IO_ReadOnly ) )
{
cerr << "Can't open /etc/passwd for reading!" << endl;
return result;
}
.
270,271c
/**
* Return a list of all users and their home directories.
* Returns an empty list if /etc/passwd cannot be read for some reason.
*/
static UserList userList()
.
268a
/**
* Show command-line help and exit
*/
void showHelp( int exitCode = 0 )
{
cout << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl
<< "" << endl
<< "Console DCOP client" << endl
<< "" << endl
<< "Generic options:" << endl
<< " --help Show help about options" << endl
<< "" << endl
<< "Options:" << endl
<< " --pipe Call DCOP for each line read from stdin" << endl
<< " --user <user> Connect to the given user's DCOP server. This option will" << endl
<< " ignore the values of the environment vars $DCOPSERVER and" << endl
<< " $ICEAUTHORITY, even if they are set." << endl
<< " If the user has more than one open session, you must also" << endl
<< " use one of the --list-sessions, --session or --als-sessions" << endl
<< " command-line options." << endl
<< " --all-users Send the same DCOP call to all users with a running DCOP" << endl
<< " server. Only failed calls to existing DCOP servers will"
<< " generate an error message. If no DCOP server is available" << endl
<< " at all, no error will be generated." << endl;
exit( exitCode );
}
.
246,250c
uint i = 0;
for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
marshall( arg, args, i, *it );
if ( i != args.count() )
{
.
164c
// exit(1);
return;
.
156,157c
uint a = (*it).contains(',');
if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
.
139c
if ( !ok && args.isEmpty() )
.
123d
121c
void callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
.
35a
static QTextStream cout( stdout, IO_WriteOnly );
static QTextStream cerr( stderr, IO_WriteOnly );
/**
* Session to send call to
* DefaultSession - current session. Current KDE session when called without
* --user or --all-users option. Otherwise this value ignores
* all users with more than one active session.
* AllSessions - Send to all sessions found. requires --user or --all-users.
* QuerySessions - Don't call DCOP, return a list of available sessions.
* CustomSession - Use the specified session
*/
enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
.
33a
typedef QMap<QString, QString> UserList;
.
28,30c
#include "../kdatastream.h"
.
25c
#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qmap.h>
#include <qstringlist.h>
#include <qtextstream.h>
#include <qvariant.h>
// putenv() is not available on all platforms, so make sure the emulation
// wrapper is available in those cases by loading config.h!
#include <config.h>
.
23c
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
.
Index: client/dcopfind.cpp
===================================================================
RCS file: /home/kde/kdelibs/dcop/client/dcopfind.cpp,v
retrieving revision 1.2
diff -e -r1.2 dcopfind.cpp
224c
QCStringList params;
for( int i = 0; i < argc; i++ )
params.append( args[ i ] );
findObject( app, objid, function, params );
.
133c
if ( (uint) i != args.count() ) {
.
131c
marshall(arg, args, i, *it);
.
121c
if ( types.count() != args.count() ) {
.
39c
bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
.
Index: client/marshall.cpp
===================================================================
RCS file: /home/kde/kdelibs/dcop/client/marshall.cpp,v
retrieving revision 1.3
diff -e -r1.3 marshall.cpp
347a
QByteArray dummy_data;
QDataStream dummy_arg(dummy_data, IO_WriteOnly);
uint j = i;
uint count = 0;
// Parse list to get the count
while (true) {
if( j > args.count() )
{
qWarning("List end-delimiter '%s' not found.", delim.latin1());
exit(1);
}
if( QString::fromLocal8Bit( args[ j ] ) == delim )
break;
marshall( dummy_arg, args, j, type );
count++;
}
arg << (Q_UINT32) count;
// Parse the list for real
while (true) {
if( i > args.count() )
{
qWarning("List end-delimiter '%s' not found.", delim.latin1());
exit(1);
}
if( QString::fromLocal8Bit( args[ i ] ) == delim )
break;
marshall( arg, args, i, type );
}
} else {
qWarning( "cannot handle datatype '%s'", type.latin1() );
exit(1);
}
i++;
.
319,346c
if ( type == "int" )
arg << s.toInt();
else if ( type == "uint" )
arg << s.toUInt();
else if ( type == "unsigned" )
arg << s.toUInt();
else if ( type == "unsigned int" )
arg << s.toUInt();
else if ( type == "long" )
arg << s.toLong();
else if ( type == "long int" )
arg << s.toLong();
else if ( type == "unsigned long" )
arg << s.toULong();
else if ( type == "unsigned long int" )
arg << s.toULong();
else if ( type == "float" )
arg << s.toFloat();
else if ( type == "double" )
arg << s.toDouble();
else if ( type == "bool" )
arg << mkBool( s );
else if ( type == "QString" )
arg << s;
else if ( type == "QCString" )
arg << QCString( args[ i ] );
else if ( type == "QColor" )
arg << mkColor( s );
else if ( type == "QPoint" )
arg << mkPoint( s );
else if ( type == "QSize" )
arg << mkSize( s );
else if ( type == "QRect" )
arg << mkRect( s );
else if ( type == "QVariant" ) {
if ( s == "true" || s == "false" )
arg << QVariant( mkBool( s ), 42 );
else if ( s.left( 4 ) == "int(" )
arg << QVariant( s.mid(4, s.length()-5).toInt() );
else if ( s.left( 7 ) == "QPoint(" )
arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
else if ( s.left( 6 ) == "QSize(" )
arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
else if ( s.left( 6 ) == "QRect(" )
arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
else if ( s.left( 7 ) == "QColor(" )
arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
else
arg << QVariant( s );
} else if ( type.startsWith("QValueList<")) {
type = type.mid(11, type.length() - 12);
QStringList list;
QString delim = s;
if (delim == "[")
delim = "]";
if (delim == "(")
delim = ")";
.
247,317c
if (type == "QStringList")
type = "QValueList<QString>";
if (type == "QCStringList")
type = "QValueList<QCString>";
if( i > args.count() )
{
qWarning("Not enough arguments.");
exit(1);
}
QString s = QString::fromLocal8Bit( args[ i ] );
.
245c
void marshall( QDataStream &arg, QCStringList args, uint &i, QString type )
.

View file

@ -0,0 +1,29 @@
Index: client/dcopfind.cpp
===================================================================
RCS file: /home/kde/kdelibs/dcop/client/dcopfind.cpp,v
retrieving revision 1.2
diff -r1.2 dcopfind.cpp
39c39
< bool findObject( const char* app, const char* obj, const char* func, int argc, char** args )
---
> bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
121c121
< if ( (int) types.count() != argc ) {
---
> if ( types.count() != args.count() ) {
131c131
< marshall(arg, argc, args, i, *it);
---
> marshall(arg, args, i, *it);
133c133
< if ( (int) i != argc ) {
---
> if ( (uint) i != args.count() ) {
224c224,228
< findObject( app, objid, function, argc, args );
---
> QCStringList params;
> for( int i = 0; i < argc; i++ )
> params.append( args[ i ] );
>
> findObject( app, objid, function, params );

View file

@ -0,0 +1,861 @@
Index: client/dcop.cpp
===================================================================
RCS file: /home/kde/kdelibs/dcop/client/dcop.cpp,v
retrieving revision 1.26
diff -r1.26 dcop.cpp
23c23,26
< #include <qvariant.h>
---
> #include <ctype.h>
> #include <stdio.h>
> #include <stdlib.h>
>
25c28,39
< #include "../kdatastream.h"
---
> #include <qdir.h>
> #include <qfile.h>
> #include <qfileinfo.h>
> #include <qmap.h>
> #include <qstringlist.h>
> #include <qtextstream.h>
> #include <qvariant.h>
>
> // putenv() is not available on all platforms, so make sure the emulation
> // wrapper is available in those cases by loading config.h!
> #include <config.h>
>
28,30c42
< #include <stdlib.h>
< #include <stdio.h>
< #include <ctype.h>
---
> #include "../kdatastream.h"
33a46,47
> typedef QMap<QString, QString> UserList;
>
35a50,63
> static QTextStream cout( stdout, IO_WriteOnly );
> static QTextStream cerr( stderr, IO_WriteOnly );
>
> /**
> * Session to send call to
> * DefaultSession - current session. Current KDE session when called without
> * --user or --all-users option. Otherwise this value ignores
> * all users with more than one active session.
> * AllSessions - Send to all sessions found. requires --user or --all-users.
> * QuerySessions - Don't call DCOP, return a list of available sessions.
> * CustomSession - Use the specified session
> */
> enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
>
121c149
< void callFunction( const char* app, const char* obj, const char* func, int argc, char** args )
---
> void callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
123d150
<
139c166
< if ( !ok && argc == 0 )
---
> if ( !ok && args.isEmpty() )
156,157c183,184
< int a = (*it).contains(',');
< if ( ( a == 0 && argc == 0) || ( a > 0 && a + 1 == argc ) )
---
> uint a = (*it).contains(',');
> if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
164c191,192
< exit(1);
---
> // exit(1);
> return;
246,250c274,279
< int i = 0;
< for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
< marshall(arg, argc, args, i, *it);
< }
< if ( i != argc ) {
---
> uint i = 0;
> for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
> marshall( arg, args, i, *it );
>
> if ( i != args.count() )
> {
268a298,324
> /**
> * Show command-line help and exit
> */
> void showHelp( int exitCode = 0 )
> {
> cout << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl
> << "" << endl
> << "Console DCOP client" << endl
> << "" << endl
> << "Generic options:" << endl
> << " --help Show help about options" << endl
> << "" << endl
> << "Options:" << endl
> << " --pipe Call DCOP for each line read from stdin" << endl
> << " --user <user> Connect to the given user's DCOP server. This option will" << endl
> << " ignore the values of the environment vars $DCOPSERVER and" << endl
> << " $ICEAUTHORITY, even if they are set." << endl
> << " If the user has more than one open session, you must also" << endl
> << " use one of the --list-sessions, --session or --als-sessions" << endl
> << " command-line options." << endl
> << " --all-users Send the same DCOP call to all users with a running DCOP" << endl
> << " server. Only failed calls to existing DCOP servers will"
> << " generate an error message. If no DCOP server is available" << endl
> << " at all, no error will be generated." << endl;
>
> exit( exitCode );
> }
270,271c326,330
<
< int main( int argc, char** argv )
---
> /**
> * Return a list of all users and their home directories.
> * Returns an empty list if /etc/passwd cannot be read for some reason.
> */
> static UserList userList()
272a332,340
> UserList result;
>
> QFile f( "/etc/passwd" );
>
> if( !f.open( IO_ReadOnly ) )
> {
> cerr << "Can't open /etc/passwd for reading!" << endl;
> return result;
> }
274,276c342,347
< if ( argc > 1 && argv[1][0] == '-' ) {
< fprintf( stderr, "Usage: dcop [ application [object [function [arg1] [arg2] [arg3] ... ] ] ] \n" );
< exit(0);
---
> QStringList l( QStringList::split( '\n', f.readAll() ) );
>
> for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it )
> {
> QStringList userInfo( QStringList::split( ':', *it, true ) );
> result[ userInfo[ 0 ] ] = userInfo[ 5 ];
279,281c350,391
< DCOPClient client;
< client.attach();
< dcop = &client;
---
> return result;
> }
>
> /**
> * Return a list of available DCOP sessions for the specified user
> * An empty list means no sessions are available, or an error occurred.
> */
> QStringList dcopSessionList( const QString &user, const QString &home )
> {
> if( home.isEmpty() )
> {
> cerr << "WARNING: Cannot determine home directory for user "
> << user << "!" << endl
> << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
> << "calling dcop." << endl;
> return QStringList();
> }
>
> QStringList result;
> QFileInfo dirInfo( home );
> if( !dirInfo.exists() || !dirInfo.isReadable() )
> return result;
>
> QDir d( home );
> d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
> d.setNameFilter( ".DCOPserver*" );
>
> const QFileInfoList *list = d.entryInfoList();
> if( !list )
> return result;
>
> QFileInfoListIterator it( *list );
> QFileInfo *fi;
>
> while ( ( fi = it.current() ) != 0 )
> {
> if( fi->isReadable() )
> result.append( fi->fileName() );
> ++it;
> }
> return result;
> }
282a393,398
> /**
> * Do the actual DCOP call
> */
> void runDCOP( QCStringList args, UserList users, Session session,
> const QString sessionName, bool readStdin )
> {
286,287c402,404
< char **args = 0;
< if ((argc > 1) && (strncmp(argv[1], "DCOPRef(", 8)) == 0)
---
> QCStringList params;
> DCOPClient *client = 0L;
> if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
289,304c406,429
< char *delim = strchr(argv[1], ',');
< if (!delim)
< {
< fprintf(stderr, "Error: '%s' is not a valid DCOP reference.\n", argv[1]);
< return 1;
< }
< *delim = 0;
< app = argv[1] + 8;
< delim++;
< delim[strlen(delim)-1] = 0;
< objid = delim;
< if (argc > 2)
< function = argv[2];
< if (argc > 3)
< args = &argv[3];
< argc++;
---
> // WARNING: This part (until the closing '}') could very
> // well be broken now. As I don't know how to trigger and test
> // dcoprefs this code is *not* tested. It compiles and it looks
> // ok to me, but that's all I can say - Martijn (2001/12/24)
> int delimPos = args[ 0 ].findRev( ',' );
> if( delimPos == -1 )
> {
> cerr << "Error: '" << args[ 0 ]
> << "' is not a valid DCOP reference." << endl;
> exit( -1 );
> }
> args[ 0 ][ delimPos ] = 0;
> app = args[ 0 ].mid( 8 );
> delimPos++;
> args[ 0 ][ args[ 0 ].length() - 1 ] = 0;
> objid = args[ 0 ].mid( delimPos );
> if( args.count() > 1 )
> function = args[ 1 ];
> if( args.count() > 2 )
> {
> params = args;
> params.remove( params.begin() );
> params.remove( params.begin() );
> }
308,338c433,516
< if (argc > 1)
< app = argv[1];
< if (argc > 2)
< objid = argv[2];
< if (argc > 3)
< function = argv[3];
< if (argc > 4)
< args = &argv[4];
< }
<
< switch ( argc ) {
< case 0:
< case 1:
< queryApplications("");
< break;
< case 2:
< if (endsWith(app, '*'))
< queryApplications(app);
< else
< queryObjects( app, "" );
< break;
< case 3:
< if (endsWith(objid, '*'))
< queryObjects(app, objid);
< else
< queryFunctions( app, objid );
< break;
< case 4:
< default:
< callFunction( app, objid, function, argc - 4, args );
< break;
---
> if( !args.isEmpty() )
> app = args[ 0 ];
> if( args.count() > 1 )
> objid = args[ 1 ];
> if( args.count() > 2 )
> function = args[ 2 ];
> if( args.count() > 3)
> {
> params = args;
> params.remove( params.begin() );
> params.remove( params.begin() );
> params.remove( params.begin() );
> }
> }
>
> bool firstRun = true;
> UserList::Iterator it;
> QStringList sessions;
> bool presetDCOPServer = false;
> // char *dcopStr = 0L;
> QString dcopServer;
>
> for( it = users.begin(); it != users.end() || firstRun; it++ )
> {
> firstRun = false;
>
> //cout << "Iterating '" << it.key() << "'" << endl;
>
> if( session == QuerySessions )
> {
> QStringList sessions = dcopSessionList( it.key(), it.data() );
> if( sessions.isEmpty() )
> {
> cout << "No active sessions";
> if( !( *it ).isEmpty() )
> cout << " for user " << *it;
> cout << endl;
> }
> else
> {
> cout << "Active sessions ";
> if( !( *it ).isEmpty() )
> cout << "for user " << *it << " ";
> cout << ":" << endl;
>
> QStringList::Iterator sIt;
> for( sIt = sessions.begin(); sIt != sessions.end(); sIt++ )
> cout << " " << *sIt << endl;
>
> cout << endl;
> }
> continue;
> }
>
> if( getenv( "DCOPSERVER" ) )
> {
> sessions.append( getenv( "DCOPSERVER" ) );
> presetDCOPServer = true;
> }
>
> if( users.count() > 1 || ( users.count() == 1 &&
> ( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) )
> {
> sessions = dcopSessionList( it.key(), it.data() );
> if( sessions.isEmpty() )
> {
> if( users.count() > 1 )
> continue;
> else
> {
> cerr << "ERROR: No active KDE sessions!" << endl
> << "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
> << "before calling dcop." << endl;
> exit( -1 );
> }
> }
> else if( sessions.count() > 1 && session != AllSessions )
> {
> cerr << "ERROR: Multiple available KDE sessions!" << endl
> << "Please specify the correct session to use with --session or use the" << endl
> << "--all-sessions option to broadcast to all sessions." << endl;
> exit( -1 );
> }
> }
339a518,660
> if( users.count() > 1 || ( users.count() == 1 &&
> ( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) )
> {
> // Check for ICE authority file and if the file can be read by us
> QString home = it.data();
> QString iceFile = it.data() + "/.ICEauthority";
> QFileInfo fi( iceFile );
> if( iceFile.isEmpty() )
> {
> cerr << "WARNING: Cannot determine home directory for user "
> << it.key() << "!" << endl
> << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
> << "calling dcop." << endl;
> }
> else if( fi.exists() )
> {
> if( fi.isReadable() )
> {
> char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() );
> putenv( envStr );
> //cerr << "ice: " << envStr << endl;
> }
> else
> {
> cerr << "WARNING: ICE authority file " << iceFile
> << "is not readable by you!" << endl
> << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
> << "calling dcop." << endl;
> }
> }
> else
> {
> if( users.count() > 1 )
> continue;
> else
> {
> cerr << "WARNING: Cannot find ICE authority file "
> << iceFile << "!" << endl
> << "Please check permissions or set the $ICEAUTHORITY"
> << " variable manually before" << endl
> << "calling dcop." << endl;
> }
> }
> }
>
> // Main loop
> // If users is an empty list we're calling for the currently logged
> // in user. In this case we don't have a session, but still want
> // to iterate the loop once.
> QStringList::Iterator sIt = sessions.begin();
> for( ; sIt != sessions.end() || users.isEmpty(); sIt++ )
> {
> if( !presetDCOPServer && !users.isEmpty() )
> {
> QString dcopFile = it.data() + "/" + *sIt;
> QFile f( dcopFile );
> if( !f.open( IO_ReadOnly ) )
> {
> cerr << "Can't open " << dcopFile << " for reading!" << endl;
> exit( -1 );
> }
>
> QStringList l( QStringList::split( '\n', f.readAll() ) );
> dcopServer = l.first();
>
> if( dcopServer.isEmpty() )
> {
> cerr << "WARNING: Unable to determine DCOP server for session "
> << *sIt << "!" << endl
> << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
> << "calling dcop." << endl;
> exit( -1 );
> }
> }
>
> delete client;
> client = new DCOPClient;
> if( !dcopServer.isEmpty() )
> client->setServerAddress( dcopServer.ascii() );
> bool success = client->attach();
> if( !success )
> {
> cerr << "ERROR: Couldn't attach to DCOP server!" << endl;
> continue;
> }
> dcop = client;
>
> switch ( args.count() )
> {
> case 0:
> queryApplications("");
> break;
> case 1:
> if (endsWith(app, '*'))
> queryApplications(app);
> else
> queryObjects( app, "" );
> break;
> case 2:
> if (endsWith(objid, '*'))
> queryObjects(app, objid);
> else
> queryFunctions( app, objid );
> break;
> case 3:
> default:
> if( readStdin )
> {
> QCStringList::Iterator replaceArg = args.end();
>
> QCStringList::Iterator it;
> for( it = args.begin(); it != args.end(); it++ )
> if( *it == "%1" )
> replaceArg = it;
>
> // Read from stdin until EOF and call function for each line read
> char *buf = new char[ 1000 ];
> while ( !feof( stdin ) )
> {
> fgets( buf, 1000, stdin );
>
> if( replaceArg != args.end() )
> *replaceArg = buf;
>
> callFunction( app, objid, function, params );
> }
> }
> else
> {
> // Just call function
> // cout << "call " << app << ", " << objid << ", " << function << ", (params)" << endl;
> callFunction( app, objid, function, params );
> }
> break;
> }
> // Another sIt++ would make the loop infinite...
> if( users.isEmpty() )
> break;
> }
>
> // Another it++ would make the loop infinite...
> if( it == users.end() )
> break;
340a662,767
> }
>
>
> int main( int argc, char** argv )
> {
> bool readStdin = false;
> int numOptions = 0;
> QString user;
> Session session = DefaultSession;
> QString sessionName;
>
> // Scan for command-line options first
> for( int pos = 1 ; pos <= argc - 1 ; pos++ )
> {
> if( strcmp( argv[ pos ], "--help" ) == 0 )
> showHelp( 0 );
> else if( strcmp( argv[ pos ], "--pipe" ) == 0 )
> {
> readStdin = true;
> numOptions++;
> }
> else if( strcmp( argv[ pos ], "--user" ) == 0 )
> {
> if( pos <= argc - 2 )
> {
> user = QString::fromLocal8Bit( argv[ pos + 1] );
> numOptions +=2;
> pos++;
> }
> else
> {
> cerr << "Missing username for '--user' option!" << endl << endl;
> showHelp( -1 );
> }
> }
> else if( strcmp( argv[ pos ], "--all-users" ) == 0 )
> {
> user = "*";
> numOptions ++;
> }
> else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 )
> {
> session = QuerySessions;
> numOptions ++;
> }
> else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 )
> {
> session = AllSessions;
> numOptions ++;
> }
> else if( argv[ pos ][ 0 ] == '-' )
> {
> cerr << "Unknown command-line option '" << argv[ pos ]
> << "'." << endl << endl;
> showHelp( -1 );
> }
> else
> break; // End of options
> }
>
> argc -= numOptions;
>
> QCStringList args;
> for( int i = numOptions; i < argc + numOptions - 1; i++ )
> args.append( argv[ i + 1 ] );
>
> if( readStdin && args.count() < 3 )
> {
> cerr << "--pipe option only supported for function calls!" << endl << endl;
> showHelp( -1 );
> }
>
> if( user == "*" && args.count() < 3 && session != QuerySessions )
> {
> cerr << "ERROR: The --all-users option is only supported for function calls!" << endl << endl;
> showHelp( -1 );
> }
>
> if( session == QuerySessions && !args.isEmpty() )
> {
> cerr << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl;
> showHelp( -1 );
> }
>
> if( session == QuerySessions && user.isEmpty() )
> {
> cerr << "ERROR: The --list-sessions option can only be used with the --user or" << endl
> << "--all-users options!" << endl << endl;
> showHelp( -1 );
> }
>
> if( session != DefaultSession && session != QuerySessions &&
> args.count() < 3 )
> {
> cerr << "ERROR: The --session and --all-sessions options are only supported for function" << endl
> << "calls!" << endl << endl;
> showHelp( -1 );
> }
>
> UserList users;
> if( user == "*" )
> users = userList();
> else if( !user.isEmpty() )
> users[ user ] = userList()[ user ];
>
> runDCOP( args, users, session, sessionName, readStdin );
343a771,773
>
> // vim: set ts=8 sts=4 sw=4 noet:
>
Index: client/dcopfind.cpp
===================================================================
RCS file: /home/kde/kdelibs/dcop/client/dcopfind.cpp,v
retrieving revision 1.2
diff -r1.2 dcopfind.cpp
39c39
< bool findObject( const char* app, const char* obj, const char* func, int argc, char** args )
---
> bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
121c121
< if ( (int) types.count() != argc ) {
---
> if ( types.count() != args.count() ) {
131c131
< marshall(arg, argc, args, i, *it);
---
> marshall(arg, args, i, *it);
133c133
< if ( (int) i != argc ) {
---
> if ( (uint) i != args.count() ) {
224c224,228
< findObject( app, objid, function, argc, args );
---
> QCStringList params;
> for( int i = 0; i < argc; i++ )
> params.append( args[ i ] );
>
> findObject( app, objid, function, params );
Index: client/marshall.cpp
===================================================================
RCS file: /home/kde/kdelibs/dcop/client/marshall.cpp,v
retrieving revision 1.3
diff -r1.3 marshall.cpp
245c245
< void marshall(QDataStream &arg, int argc, char **argv, int &i, QString type)
---
> void marshall( QDataStream &arg, QCStringList args, uint &i, QString type )
247,317c247,256
< if (type == "QStringList")
< type = "QValueList<QString>";
< if (type == "QCStringList")
< type = "QValueList<QCString>";
< if (i >= argc)
< {
< qWarning("Not enough arguments.");
< exit(1);
< }
< QString s = QString::fromLocal8Bit(argv[i]);
<
< if ( type == "int" )
< arg << s.toInt();
< else if ( type == "uint" )
< arg << s.toUInt();
< else if ( type == "unsigned" )
< arg << s.toUInt();
< else if ( type == "unsigned int" )
< arg << s.toUInt();
< else if ( type == "long" )
< arg << s.toLong();
< else if ( type == "long int" )
< arg << s.toLong();
< else if ( type == "unsigned long" )
< arg << s.toULong();
< else if ( type == "unsigned long int" )
< arg << s.toULong();
< else if ( type == "float" )
< arg << s.toFloat();
< else if ( type == "double" )
< arg << s.toDouble();
< else if ( type == "bool" )
< arg << mkBool( s );
< else if ( type == "QString" )
< arg << s;
< else if ( type == "QCString" )
< arg << QCString( argv[i] );
< else if ( type == "QColor" )
< arg << mkColor( s );
< else if ( type == "QPoint" )
< arg << mkPoint( s );
< else if ( type == "QSize" )
< arg << mkSize( s );
< else if ( type == "QRect" )
< arg << mkRect( s );
< else if ( type == "QVariant" ) {
< if ( s == "true" || s == "false" )
< arg << QVariant( mkBool( s ), 42 );
< else if ( s.left( 4 ) == "int(" )
< arg << QVariant( s.mid(4, s.length()-5).toInt() );
< else if ( s.left( 7 ) == "QPoint(" )
< arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
< else if ( s.left( 6 ) == "QSize(" )
< arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
< else if ( s.left( 6 ) == "QRect(" )
< arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
< else if ( s.left( 7 ) == "QColor(" )
< arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
< else
< arg << QVariant( s );
< } else if ( type.startsWith("QValueList<")) {
< type = type.mid(11, type.length() - 12);
< QStringList list;
< QString delim = s;
< if (delim == "[")
< delim = "]";
< if (delim == "(")
< delim = ")";
< i++;
< QByteArray dummy_data;
< QDataStream dummy_arg(dummy_data, IO_WriteOnly);
---
> if (type == "QStringList")
> type = "QValueList<QString>";
> if (type == "QCStringList")
> type = "QValueList<QCString>";
> if( i > args.count() )
> {
> qWarning("Not enough arguments.");
> exit(1);
> }
> QString s = QString::fromLocal8Bit( args[ i ] );
319,346c258,314
< int j = i;
< int count = 0;
< // Parse list to get the count
< while (true) {
< if (j >= argc)
< {
< qWarning("List end-delimiter '%s' not found.", delim.latin1());
< exit(1);
< }
< if (argv[j] == delim) break;
< marshall(dummy_arg, argc, argv, j, type);
< count++;
< }
< arg << (Q_UINT32) count;
< // Parse the list for real
< while (true) {
< if (i >= argc)
< {
< qWarning("List end-delimiter '%s' not found.", delim.latin1());
< exit(1);
< }
< if (argv[i] == delim) break;
< marshall(arg, argc, argv, i, type);
< }
< } else {
< qWarning( "cannot handle datatype '%s'", type.latin1() );
< exit(1);
< }
---
> if ( type == "int" )
> arg << s.toInt();
> else if ( type == "uint" )
> arg << s.toUInt();
> else if ( type == "unsigned" )
> arg << s.toUInt();
> else if ( type == "unsigned int" )
> arg << s.toUInt();
> else if ( type == "long" )
> arg << s.toLong();
> else if ( type == "long int" )
> arg << s.toLong();
> else if ( type == "unsigned long" )
> arg << s.toULong();
> else if ( type == "unsigned long int" )
> arg << s.toULong();
> else if ( type == "float" )
> arg << s.toFloat();
> else if ( type == "double" )
> arg << s.toDouble();
> else if ( type == "bool" )
> arg << mkBool( s );
> else if ( type == "QString" )
> arg << s;
> else if ( type == "QCString" )
> arg << QCString( args[ i ] );
> else if ( type == "QColor" )
> arg << mkColor( s );
> else if ( type == "QPoint" )
> arg << mkPoint( s );
> else if ( type == "QSize" )
> arg << mkSize( s );
> else if ( type == "QRect" )
> arg << mkRect( s );
> else if ( type == "QVariant" ) {
> if ( s == "true" || s == "false" )
> arg << QVariant( mkBool( s ), 42 );
> else if ( s.left( 4 ) == "int(" )
> arg << QVariant( s.mid(4, s.length()-5).toInt() );
> else if ( s.left( 7 ) == "QPoint(" )
> arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
> else if ( s.left( 6 ) == "QSize(" )
> arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
> else if ( s.left( 6 ) == "QRect(" )
> arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
> else if ( s.left( 7 ) == "QColor(" )
> arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
> else
> arg << QVariant( s );
> } else if ( type.startsWith("QValueList<")) {
> type = type.mid(11, type.length() - 12);
> QStringList list;
> QString delim = s;
> if (delim == "[")
> delim = "]";
> if (delim == "(")
> delim = ")";
347a316,349
> QByteArray dummy_data;
> QDataStream dummy_arg(dummy_data, IO_WriteOnly);
>
> uint j = i;
> uint count = 0;
> // Parse list to get the count
> while (true) {
> if( j > args.count() )
> {
> qWarning("List end-delimiter '%s' not found.", delim.latin1());
> exit(1);
> }
> if( QString::fromLocal8Bit( args[ j ] ) == delim )
> break;
> marshall( dummy_arg, args, j, type );
> count++;
> }
> arg << (Q_UINT32) count;
> // Parse the list for real
> while (true) {
> if( i > args.count() )
> {
> qWarning("List end-delimiter '%s' not found.", delim.latin1());
> exit(1);
> }
> if( QString::fromLocal8Bit( args[ i ] ) == delim )
> break;
> marshall( arg, args, i, type );
> }
> } else {
> qWarning( "cannot handle datatype '%s'", type.latin1() );
> exit(1);
> }
> i++;

View file

@ -0,0 +1,24 @@
Index: client/dcopfind.cpp
===================================================================
RCS file: /home/kde/kdelibs/dcop/client/dcopfind.cpp,v
retrieving revision 1.2
diff -n -r1.2 dcopfind.cpp
d39 1
a39 1
bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
d121 1
a121 1
if ( types.count() != args.count() ) {
d131 1
a131 1
marshall(arg, args, i, *it);
d133 1
a133 1
if ( (uint) i != args.count() ) {
d224 1
a224 5
QCStringList params;
for( int i = 0; i < argc; i++ )
params.append( args[ i ] );
findObject( app, objid, function, params );

View file

@ -0,0 +1,683 @@
Index: client/dcop.cpp
===================================================================
RCS file: /home/kde/kdelibs/dcop/client/dcop.cpp,v
retrieving revision 1.26
diff -n -r1.26 dcop.cpp
d23 1
a23 4
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
d25 1
a25 12
#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qmap.h>
#include <qstringlist.h>
#include <qtextstream.h>
#include <qvariant.h>
// putenv() is not available on all platforms, so make sure the emulation
// wrapper is available in those cases by loading config.h!
#include <config.h>
d28 3
a30 1
#include "../kdatastream.h"
a33 2
typedef QMap<QString, QString> UserList;
a35 14
static QTextStream cout( stdout, IO_WriteOnly );
static QTextStream cerr( stderr, IO_WriteOnly );
/**
* Session to send call to
* DefaultSession - current session. Current KDE session when called without
* --user or --all-users option. Otherwise this value ignores
* all users with more than one active session.
* AllSessions - Send to all sessions found. requires --user or --all-users.
* QuerySessions - Don't call DCOP, return a list of available sessions.
* CustomSession - Use the specified session
*/
enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
d121 1
a121 1
void callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
d123 1
d139 1
a139 1
if ( !ok && args.isEmpty() )
d156 2
a157 2
uint a = (*it).contains(',');
if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
d164 1
a164 2
// exit(1);
return;
d246 5
a250 6
uint i = 0;
for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
marshall( arg, args, i, *it );
if ( i != args.count() )
{
a268 27
/**
* Show command-line help and exit
*/
void showHelp( int exitCode = 0 )
{
cout << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl
<< "" << endl
<< "Console DCOP client" << endl
<< "" << endl
<< "Generic options:" << endl
<< " --help Show help about options" << endl
<< "" << endl
<< "Options:" << endl
<< " --pipe Call DCOP for each line read from stdin" << endl
<< " --user <user> Connect to the given user's DCOP server. This option will" << endl
<< " ignore the values of the environment vars $DCOPSERVER and" << endl
<< " $ICEAUTHORITY, even if they are set." << endl
<< " If the user has more than one open session, you must also" << endl
<< " use one of the --list-sessions, --session or --als-sessions" << endl
<< " command-line options." << endl
<< " --all-users Send the same DCOP call to all users with a running DCOP" << endl
<< " server. Only failed calls to existing DCOP servers will"
<< " generate an error message. If no DCOP server is available" << endl
<< " at all, no error will be generated." << endl;
exit( exitCode );
}
d270 2
a271 5
/**
* Return a list of all users and their home directories.
* Returns an empty list if /etc/passwd cannot be read for some reason.
*/
static UserList userList()
a272 9
UserList result;
QFile f( "/etc/passwd" );
if( !f.open( IO_ReadOnly ) )
{
cerr << "Can't open /etc/passwd for reading!" << endl;
return result;
}
d274 3
a276 6
QStringList l( QStringList::split( '\n', f.readAll() ) );
for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it )
{
QStringList userInfo( QStringList::split( ':', *it, true ) );
result[ userInfo[ 0 ] ] = userInfo[ 5 ];
d279 3
a281 42
return result;
}
/**
* Return a list of available DCOP sessions for the specified user
* An empty list means no sessions are available, or an error occurred.
*/
QStringList dcopSessionList( const QString &user, const QString &home )
{
if( home.isEmpty() )
{
cerr << "WARNING: Cannot determine home directory for user "
<< user << "!" << endl
<< "Please check permissions or set the $DCOPSERVER variable manually before" << endl
<< "calling dcop." << endl;
return QStringList();
}
QStringList result;
QFileInfo dirInfo( home );
if( !dirInfo.exists() || !dirInfo.isReadable() )
return result;
QDir d( home );
d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
d.setNameFilter( ".DCOPserver*" );
const QFileInfoList *list = d.entryInfoList();
if( !list )
return result;
QFileInfoListIterator it( *list );
QFileInfo *fi;
while ( ( fi = it.current() ) != 0 )
{
if( fi->isReadable() )
result.append( fi->fileName() );
++it;
}
return result;
}
a282 6
/**
* Do the actual DCOP call
*/
void runDCOP( QCStringList args, UserList users, Session session,
const QString sessionName, bool readStdin )
{
d286 2
a287 3
QCStringList params;
DCOPClient *client = 0L;
if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
d289 16
a304 24
// WARNING: This part (until the closing '}') could very
// well be broken now. As I don't know how to trigger and test
// dcoprefs this code is *not* tested. It compiles and it looks
// ok to me, but that's all I can say - Martijn (2001/12/24)
int delimPos = args[ 0 ].findRev( ',' );
if( delimPos == -1 )
{
cerr << "Error: '" << args[ 0 ]
<< "' is not a valid DCOP reference." << endl;
exit( -1 );
}
args[ 0 ][ delimPos ] = 0;
app = args[ 0 ].mid( 8 );
delimPos++;
args[ 0 ][ args[ 0 ].length() - 1 ] = 0;
objid = args[ 0 ].mid( delimPos );
if( args.count() > 1 )
function = args[ 1 ];
if( args.count() > 2 )
{
params = args;
params.remove( params.begin() );
params.remove( params.begin() );
}
d308 31
a338 84
if( !args.isEmpty() )
app = args[ 0 ];
if( args.count() > 1 )
objid = args[ 1 ];
if( args.count() > 2 )
function = args[ 2 ];
if( args.count() > 3)
{
params = args;
params.remove( params.begin() );
params.remove( params.begin() );
params.remove( params.begin() );
}
}
bool firstRun = true;
UserList::Iterator it;
QStringList sessions;
bool presetDCOPServer = false;
// char *dcopStr = 0L;
QString dcopServer;
for( it = users.begin(); it != users.end() || firstRun; it++ )
{
firstRun = false;
//cout << "Iterating '" << it.key() << "'" << endl;
if( session == QuerySessions )
{
QStringList sessions = dcopSessionList( it.key(), it.data() );
if( sessions.isEmpty() )
{
cout << "No active sessions";
if( !( *it ).isEmpty() )
cout << " for user " << *it;
cout << endl;
}
else
{
cout << "Active sessions ";
if( !( *it ).isEmpty() )
cout << "for user " << *it << " ";
cout << ":" << endl;
QStringList::Iterator sIt;
for( sIt = sessions.begin(); sIt != sessions.end(); sIt++ )
cout << " " << *sIt << endl;
cout << endl;
}
continue;
}
if( getenv( "DCOPSERVER" ) )
{
sessions.append( getenv( "DCOPSERVER" ) );
presetDCOPServer = true;
}
if( users.count() > 1 || ( users.count() == 1 &&
( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) )
{
sessions = dcopSessionList( it.key(), it.data() );
if( sessions.isEmpty() )
{
if( users.count() > 1 )
continue;
else
{
cerr << "ERROR: No active KDE sessions!" << endl
<< "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
<< "before calling dcop." << endl;
exit( -1 );
}
}
else if( sessions.count() > 1 && session != AllSessions )
{
cerr << "ERROR: Multiple available KDE sessions!" << endl
<< "Please specify the correct session to use with --session or use the" << endl
<< "--all-sessions option to broadcast to all sessions." << endl;
exit( -1 );
}
}
a339 143
if( users.count() > 1 || ( users.count() == 1 &&
( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) )
{
// Check for ICE authority file and if the file can be read by us
QString home = it.data();
QString iceFile = it.data() + "/.ICEauthority";
QFileInfo fi( iceFile );
if( iceFile.isEmpty() )
{
cerr << "WARNING: Cannot determine home directory for user "
<< it.key() << "!" << endl
<< "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
<< "calling dcop." << endl;
}
else if( fi.exists() )
{
if( fi.isReadable() )
{
char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() );
putenv( envStr );
//cerr << "ice: " << envStr << endl;
}
else
{
cerr << "WARNING: ICE authority file " << iceFile
<< "is not readable by you!" << endl
<< "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
<< "calling dcop." << endl;
}
}
else
{
if( users.count() > 1 )
continue;
else
{
cerr << "WARNING: Cannot find ICE authority file "
<< iceFile << "!" << endl
<< "Please check permissions or set the $ICEAUTHORITY"
<< " variable manually before" << endl
<< "calling dcop." << endl;
}
}
}
// Main loop
// If users is an empty list we're calling for the currently logged
// in user. In this case we don't have a session, but still want
// to iterate the loop once.
QStringList::Iterator sIt = sessions.begin();
for( ; sIt != sessions.end() || users.isEmpty(); sIt++ )
{
if( !presetDCOPServer && !users.isEmpty() )
{
QString dcopFile = it.data() + "/" + *sIt;
QFile f( dcopFile );
if( !f.open( IO_ReadOnly ) )
{
cerr << "Can't open " << dcopFile << " for reading!" << endl;
exit( -1 );
}
QStringList l( QStringList::split( '\n', f.readAll() ) );
dcopServer = l.first();
if( dcopServer.isEmpty() )
{
cerr << "WARNING: Unable to determine DCOP server for session "
<< *sIt << "!" << endl
<< "Please check permissions or set the $DCOPSERVER variable manually before" << endl
<< "calling dcop." << endl;
exit( -1 );
}
}
delete client;
client = new DCOPClient;
if( !dcopServer.isEmpty() )
client->setServerAddress( dcopServer.ascii() );
bool success = client->attach();
if( !success )
{
cerr << "ERROR: Couldn't attach to DCOP server!" << endl;
continue;
}
dcop = client;
switch ( args.count() )
{
case 0:
queryApplications("");
break;
case 1:
if (endsWith(app, '*'))
queryApplications(app);
else
queryObjects( app, "" );
break;
case 2:
if (endsWith(objid, '*'))
queryObjects(app, objid);
else
queryFunctions( app, objid );
break;
case 3:
default:
if( readStdin )
{
QCStringList::Iterator replaceArg = args.end();
QCStringList::Iterator it;
for( it = args.begin(); it != args.end(); it++ )
if( *it == "%1" )
replaceArg = it;
// Read from stdin until EOF and call function for each line read
char *buf = new char[ 1000 ];
while ( !feof( stdin ) )
{
fgets( buf, 1000, stdin );
if( replaceArg != args.end() )
*replaceArg = buf;
callFunction( app, objid, function, params );
}
}
else
{
// Just call function
// cout << "call " << app << ", " << objid << ", " << function << ", (params)" << endl;
callFunction( app, objid, function, params );
}
break;
}
// Another sIt++ would make the loop infinite...
if( users.isEmpty() )
break;
}
// Another it++ would make the loop infinite...
if( it == users.end() )
break;
a340 106
}
int main( int argc, char** argv )
{
bool readStdin = false;
int numOptions = 0;
QString user;
Session session = DefaultSession;
QString sessionName;
// Scan for command-line options first
for( int pos = 1 ; pos <= argc - 1 ; pos++ )
{
if( strcmp( argv[ pos ], "--help" ) == 0 )
showHelp( 0 );
else if( strcmp( argv[ pos ], "--pipe" ) == 0 )
{
readStdin = true;
numOptions++;
}
else if( strcmp( argv[ pos ], "--user" ) == 0 )
{
if( pos <= argc - 2 )
{
user = QString::fromLocal8Bit( argv[ pos + 1] );
numOptions +=2;
pos++;
}
else
{
cerr << "Missing username for '--user' option!" << endl << endl;
showHelp( -1 );
}
}
else if( strcmp( argv[ pos ], "--all-users" ) == 0 )
{
user = "*";
numOptions ++;
}
else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 )
{
session = QuerySessions;
numOptions ++;
}
else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 )
{
session = AllSessions;
numOptions ++;
}
else if( argv[ pos ][ 0 ] == '-' )
{
cerr << "Unknown command-line option '" << argv[ pos ]
<< "'." << endl << endl;
showHelp( -1 );
}
else
break; // End of options
}
argc -= numOptions;
QCStringList args;
for( int i = numOptions; i < argc + numOptions - 1; i++ )
args.append( argv[ i + 1 ] );
if( readStdin && args.count() < 3 )
{
cerr << "--pipe option only supported for function calls!" << endl << endl;
showHelp( -1 );
}
if( user == "*" && args.count() < 3 && session != QuerySessions )
{
cerr << "ERROR: The --all-users option is only supported for function calls!" << endl << endl;
showHelp( -1 );
}
if( session == QuerySessions && !args.isEmpty() )
{
cerr << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl;
showHelp( -1 );
}
if( session == QuerySessions && user.isEmpty() )
{
cerr << "ERROR: The --list-sessions option can only be used with the --user or" << endl
<< "--all-users options!" << endl << endl;
showHelp( -1 );
}
if( session != DefaultSession && session != QuerySessions &&
args.count() < 3 )
{
cerr << "ERROR: The --session and --all-sessions options are only supported for function" << endl
<< "calls!" << endl << endl;
showHelp( -1 );
}
UserList users;
if( user == "*" )
users = userList();
else if( !user.isEmpty() )
users[ user ] = userList()[ user ];
runDCOP( args, users, session, sessionName, readStdin );
a343 3
// vim: set ts=8 sts=4 sw=4 noet:
Index: client/dcopfind.cpp
===================================================================
RCS file: /home/kde/kdelibs/dcop/client/dcopfind.cpp,v
retrieving revision 1.2
diff -n -r1.2 dcopfind.cpp
d39 1
a39 1
bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
d121 1
a121 1
if ( types.count() != args.count() ) {
d131 1
a131 1
marshall(arg, args, i, *it);
d133 1
a133 1
if ( (uint) i != args.count() ) {
d224 1
a224 5
QCStringList params;
for( int i = 0; i < argc; i++ )
params.append( args[ i ] );
findObject( app, objid, function, params );
Index: client/marshall.cpp
===================================================================
RCS file: /home/kde/kdelibs/dcop/client/marshall.cpp,v
retrieving revision 1.3
diff -n -r1.3 marshall.cpp
d245 1
a245 1
void marshall( QDataStream &arg, QCStringList args, uint &i, QString type )
d247 71
a317 10
if (type == "QStringList")
type = "QValueList<QString>";
if (type == "QCStringList")
type = "QValueList<QCString>";
if( i > args.count() )
{
qWarning("Not enough arguments.");
exit(1);
}
QString s = QString::fromLocal8Bit( args[ i ] );
d319 28
a346 57
if ( type == "int" )
arg << s.toInt();
else if ( type == "uint" )
arg << s.toUInt();
else if ( type == "unsigned" )
arg << s.toUInt();
else if ( type == "unsigned int" )
arg << s.toUInt();
else if ( type == "long" )
arg << s.toLong();
else if ( type == "long int" )
arg << s.toLong();
else if ( type == "unsigned long" )
arg << s.toULong();
else if ( type == "unsigned long int" )
arg << s.toULong();
else if ( type == "float" )
arg << s.toFloat();
else if ( type == "double" )
arg << s.toDouble();
else if ( type == "bool" )
arg << mkBool( s );
else if ( type == "QString" )
arg << s;
else if ( type == "QCString" )
arg << QCString( args[ i ] );
else if ( type == "QColor" )
arg << mkColor( s );
else if ( type == "QPoint" )
arg << mkPoint( s );
else if ( type == "QSize" )
arg << mkSize( s );
else if ( type == "QRect" )
arg << mkRect( s );
else if ( type == "QVariant" ) {
if ( s == "true" || s == "false" )
arg << QVariant( mkBool( s ), 42 );
else if ( s.left( 4 ) == "int(" )
arg << QVariant( s.mid(4, s.length()-5).toInt() );
else if ( s.left( 7 ) == "QPoint(" )
arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
else if ( s.left( 6 ) == "QSize(" )
arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
else if ( s.left( 6 ) == "QRect(" )
arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
else if ( s.left( 7 ) == "QColor(" )
arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
else
arg << QVariant( s );
} else if ( type.startsWith("QValueList<")) {
type = type.mid(11, type.length() - 12);
QStringList list;
QString delim = s;
if (delim == "[")
delim = "]";
if (delim == "(")
delim = ")";
a347 34
QByteArray dummy_data;
QDataStream dummy_arg(dummy_data, IO_WriteOnly);
uint j = i;
uint count = 0;
// Parse list to get the count
while (true) {
if( j > args.count() )
{
qWarning("List end-delimiter '%s' not found.", delim.latin1());
exit(1);
}
if( QString::fromLocal8Bit( args[ j ] ) == delim )
break;
marshall( dummy_arg, args, j, type );
count++;
}
arg << (Q_UINT32) count;
// Parse the list for real
while (true) {
if( i > args.count() )
{
qWarning("List end-delimiter '%s' not found.", delim.latin1());
exit(1);
}
if( QString::fromLocal8Bit( args[ i ] ) == delim )
break;
marshall( arg, args, i, type );
}
} else {
qWarning( "cannot handle datatype '%s'", type.latin1() );
exit(1);
}
i++;

View file

@ -0,0 +1,50 @@
Index: client/dcopfind.cpp
===================================================================
RCS file: /home/kde/kdelibs/dcop/client/dcopfind.cpp,v
retrieving revision 1.2
diff -u -r1.2 dcopfind.cpp
--- client/dcopfind.cpp 2001/10/31 01:17:39 1.2
+++ client/dcopfind.cpp 2002/01/16 18:07:51
@@ -36,7 +36,7 @@
static bool bAppIdOnly = 0;
static bool bLaunchApp = 0;
-bool findObject( const char* app, const char* obj, const char* func, int argc, char** args )
+bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
{
QString f = func; // Qt is better with unicode strings, so use one.
int left = f.find( '(' );
@@ -118,7 +118,7 @@
f = fc;
}
- if ( (int) types.count() != argc ) {
+ if ( types.count() != args.count() ) {
qWarning( "arguments do not match" );
exit(1);
}
@@ -128,9 +128,9 @@
int i = 0;
for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
- marshall(arg, argc, args, i, *it);
+ marshall(arg, args, i, *it);
}
- if ( (int) i != argc ) {
+ if ( (uint) i != args.count() ) {
qWarning( "arguments do not match" );
exit(1);
}
@@ -221,7 +221,11 @@
argc = 0;
}
- findObject( app, objid, function, argc, args );
+ QCStringList params;
+ for( int i = 0; i < argc; i++ )
+ params.append( args[ i ] );
+
+ findObject( app, objid, function, params );
return 0;
}

View file

@ -0,0 +1,924 @@
Index: client/dcop.cpp
===================================================================
RCS file: /home/kde/kdelibs/dcop/client/dcop.cpp,v
retrieving revision 1.26
diff -u -r1.26 dcop.cpp
--- client/dcop.cpp 2001/10/31 01:17:39 1.26
+++ client/dcop.cpp 2002/01/16 18:06:14
@@ -20,19 +20,47 @@
******************************************************************/
-#include <qvariant.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+
#include <qcolor.h>
-#include "../kdatastream.h"
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qmap.h>
+#include <qstringlist.h>
+#include <qtextstream.h>
+#include <qvariant.h>
+
+// putenv() is not available on all platforms, so make sure the emulation
+// wrapper is available in those cases by loading config.h!
+#include <config.h>
+
#include "../dcopclient.h"
#include "../dcopref.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
+#include "../kdatastream.h"
#include "marshall.cpp"
+typedef QMap<QString, QString> UserList;
+
static DCOPClient* dcop = 0;
+static QTextStream cout( stdout, IO_WriteOnly );
+static QTextStream cerr( stderr, IO_WriteOnly );
+
+/**
+ * Session to send call to
+ * DefaultSession - current session. Current KDE session when called without
+ * --user or --all-users option. Otherwise this value ignores
+ * all users with more than one active session.
+ * AllSessions - Send to all sessions found. requires --user or --all-users.
+ * QuerySessions - Don't call DCOP, return a list of available sessions.
+ * CustomSession - Use the specified session
+ */
+enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
+
bool startsWith(const QCString &id, const char *str, int n)
{
return !n || (strncmp(id.data(), str, n) == 0);
@@ -118,9 +146,8 @@
}
}
-void callFunction( const char* app, const char* obj, const char* func, int argc, char** args )
+void callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
{
-
QString f = func; // Qt is better with unicode strings, so use one.
int left = f.find( '(' );
int right = f.find( ')' );
@@ -136,7 +163,7 @@
bool ok = false;
QCStringList funcs = dcop->remoteFunctions( app, obj, &ok );
QCString realfunc;
- if ( !ok && argc == 0 )
+ if ( !ok && args.isEmpty() )
goto doit;
if ( !ok )
{
@@ -153,15 +180,16 @@
if ( l > 0 && (*it).mid( s, l - s ) == func ) {
realfunc = (*it).mid( s );
- int a = (*it).contains(',');
- if ( ( a == 0 && argc == 0) || ( a > 0 && a + 1 == argc ) )
+ uint a = (*it).contains(',');
+ if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
break;
}
}
if ( realfunc.isEmpty() )
{
qWarning("no such function");
- exit(1);
+// exit(1);
+ return;
}
f = realfunc;
left = f.find( '(' );
@@ -243,11 +271,12 @@
QCString replyType;
QDataStream arg(data, IO_WriteOnly);
- int i = 0;
- for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
- marshall(arg, argc, args, i, *it);
- }
- if ( i != argc ) {
+ uint i = 0;
+ for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
+ marshall( arg, args, i, *it );
+
+ if ( i != args.count() )
+ {
qWarning( "arguments do not match" );
exit(1);
}
@@ -265,79 +294,480 @@
}
}
}
-
+/**
+ * Show command-line help and exit
+ */
+void showHelp( int exitCode = 0 )
+{
+ cout << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl
+ << "" << endl
+ << "Console DCOP client" << endl
+ << "" << endl
+ << "Generic options:" << endl
+ << " --help Show help about options" << endl
+ << "" << endl
+ << "Options:" << endl
+ << " --pipe Call DCOP for each line read from stdin" << endl
+ << " --user <user> Connect to the given user's DCOP server. This option will" << endl
+ << " ignore the values of the environment vars $DCOPSERVER and" << endl
+ << " $ICEAUTHORITY, even if they are set." << endl
+ << " If the user has more than one open session, you must also" << endl
+ << " use one of the --list-sessions, --session or --als-sessions" << endl
+ << " command-line options." << endl
+ << " --all-users Send the same DCOP call to all users with a running DCOP" << endl
+ << " server. Only failed calls to existing DCOP servers will"
+ << " generate an error message. If no DCOP server is available" << endl
+ << " at all, no error will be generated." << endl;
+
+ exit( exitCode );
+}
-int main( int argc, char** argv )
+/**
+ * Return a list of all users and their home directories.
+ * Returns an empty list if /etc/passwd cannot be read for some reason.
+ */
+static UserList userList()
{
+ UserList result;
+
+ QFile f( "/etc/passwd" );
+
+ if( !f.open( IO_ReadOnly ) )
+ {
+ cerr << "Can't open /etc/passwd for reading!" << endl;
+ return result;
+ }
- if ( argc > 1 && argv[1][0] == '-' ) {
- fprintf( stderr, "Usage: dcop [ application [object [function [arg1] [arg2] [arg3] ... ] ] ] \n" );
- exit(0);
+ QStringList l( QStringList::split( '\n', f.readAll() ) );
+
+ for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it )
+ {
+ QStringList userInfo( QStringList::split( ':', *it, true ) );
+ result[ userInfo[ 0 ] ] = userInfo[ 5 ];
}
- DCOPClient client;
- client.attach();
- dcop = &client;
+ return result;
+}
+
+/**
+ * Return a list of available DCOP sessions for the specified user
+ * An empty list means no sessions are available, or an error occurred.
+ */
+QStringList dcopSessionList( const QString &user, const QString &home )
+{
+ if( home.isEmpty() )
+ {
+ cerr << "WARNING: Cannot determine home directory for user "
+ << user << "!" << endl
+ << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
+ << "calling dcop." << endl;
+ return QStringList();
+ }
+
+ QStringList result;
+ QFileInfo dirInfo( home );
+ if( !dirInfo.exists() || !dirInfo.isReadable() )
+ return result;
+
+ QDir d( home );
+ d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
+ d.setNameFilter( ".DCOPserver*" );
+
+ const QFileInfoList *list = d.entryInfoList();
+ if( !list )
+ return result;
+
+ QFileInfoListIterator it( *list );
+ QFileInfo *fi;
+
+ while ( ( fi = it.current() ) != 0 )
+ {
+ if( fi->isReadable() )
+ result.append( fi->fileName() );
+ ++it;
+ }
+ return result;
+}
+/**
+ * Do the actual DCOP call
+ */
+void runDCOP( QCStringList args, UserList users, Session session,
+ const QString sessionName, bool readStdin )
+{
QCString app;
QCString objid;
QCString function;
- char **args = 0;
- if ((argc > 1) && (strncmp(argv[1], "DCOPRef(", 8)) == 0)
+ QCStringList params;
+ DCOPClient *client = 0L;
+ if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
{
- char *delim = strchr(argv[1], ',');
- if (!delim)
- {
- fprintf(stderr, "Error: '%s' is not a valid DCOP reference.\n", argv[1]);
- return 1;
- }
- *delim = 0;
- app = argv[1] + 8;
- delim++;
- delim[strlen(delim)-1] = 0;
- objid = delim;
- if (argc > 2)
- function = argv[2];
- if (argc > 3)
- args = &argv[3];
- argc++;
+ // WARNING: This part (until the closing '}') could very
+ // well be broken now. As I don't know how to trigger and test
+ // dcoprefs this code is *not* tested. It compiles and it looks
+ // ok to me, but that's all I can say - Martijn (2001/12/24)
+ int delimPos = args[ 0 ].findRev( ',' );
+ if( delimPos == -1 )
+ {
+ cerr << "Error: '" << args[ 0 ]
+ << "' is not a valid DCOP reference." << endl;
+ exit( -1 );
+ }
+ args[ 0 ][ delimPos ] = 0;
+ app = args[ 0 ].mid( 8 );
+ delimPos++;
+ args[ 0 ][ args[ 0 ].length() - 1 ] = 0;
+ objid = args[ 0 ].mid( delimPos );
+ if( args.count() > 1 )
+ function = args[ 1 ];
+ if( args.count() > 2 )
+ {
+ params = args;
+ params.remove( params.begin() );
+ params.remove( params.begin() );
+ }
}
else
{
- if (argc > 1)
- app = argv[1];
- if (argc > 2)
- objid = argv[2];
- if (argc > 3)
- function = argv[3];
- if (argc > 4)
- args = &argv[4];
- }
-
- switch ( argc ) {
- case 0:
- case 1:
- queryApplications("");
- break;
- case 2:
- if (endsWith(app, '*'))
- queryApplications(app);
- else
- queryObjects( app, "" );
- break;
- case 3:
- if (endsWith(objid, '*'))
- queryObjects(app, objid);
- else
- queryFunctions( app, objid );
- break;
- case 4:
- default:
- callFunction( app, objid, function, argc - 4, args );
- break;
+ if( !args.isEmpty() )
+ app = args[ 0 ];
+ if( args.count() > 1 )
+ objid = args[ 1 ];
+ if( args.count() > 2 )
+ function = args[ 2 ];
+ if( args.count() > 3)
+ {
+ params = args;
+ params.remove( params.begin() );
+ params.remove( params.begin() );
+ params.remove( params.begin() );
+ }
+ }
+
+ bool firstRun = true;
+ UserList::Iterator it;
+ QStringList sessions;
+ bool presetDCOPServer = false;
+// char *dcopStr = 0L;
+ QString dcopServer;
+
+ for( it = users.begin(); it != users.end() || firstRun; it++ )
+ {
+ firstRun = false;
+
+ //cout << "Iterating '" << it.key() << "'" << endl;
+
+ if( session == QuerySessions )
+ {
+ QStringList sessions = dcopSessionList( it.key(), it.data() );
+ if( sessions.isEmpty() )
+ {
+ cout << "No active sessions";
+ if( !( *it ).isEmpty() )
+ cout << " for user " << *it;
+ cout << endl;
+ }
+ else
+ {
+ cout << "Active sessions ";
+ if( !( *it ).isEmpty() )
+ cout << "for user " << *it << " ";
+ cout << ":" << endl;
+
+ QStringList::Iterator sIt;
+ for( sIt = sessions.begin(); sIt != sessions.end(); sIt++ )
+ cout << " " << *sIt << endl;
+
+ cout << endl;
+ }
+ continue;
+ }
+
+ if( getenv( "DCOPSERVER" ) )
+ {
+ sessions.append( getenv( "DCOPSERVER" ) );
+ presetDCOPServer = true;
+ }
+
+ if( users.count() > 1 || ( users.count() == 1 &&
+ ( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) )
+ {
+ sessions = dcopSessionList( it.key(), it.data() );
+ if( sessions.isEmpty() )
+ {
+ if( users.count() > 1 )
+ continue;
+ else
+ {
+ cerr << "ERROR: No active KDE sessions!" << endl
+ << "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
+ << "before calling dcop." << endl;
+ exit( -1 );
+ }
+ }
+ else if( sessions.count() > 1 && session != AllSessions )
+ {
+ cerr << "ERROR: Multiple available KDE sessions!" << endl
+ << "Please specify the correct session to use with --session or use the" << endl
+ << "--all-sessions option to broadcast to all sessions." << endl;
+ exit( -1 );
+ }
+ }
+ if( users.count() > 1 || ( users.count() == 1 &&
+ ( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) )
+ {
+ // Check for ICE authority file and if the file can be read by us
+ QString home = it.data();
+ QString iceFile = it.data() + "/.ICEauthority";
+ QFileInfo fi( iceFile );
+ if( iceFile.isEmpty() )
+ {
+ cerr << "WARNING: Cannot determine home directory for user "
+ << it.key() << "!" << endl
+ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
+ << "calling dcop." << endl;
+ }
+ else if( fi.exists() )
+ {
+ if( fi.isReadable() )
+ {
+ char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() );
+ putenv( envStr );
+ //cerr << "ice: " << envStr << endl;
+ }
+ else
+ {
+ cerr << "WARNING: ICE authority file " << iceFile
+ << "is not readable by you!" << endl
+ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
+ << "calling dcop." << endl;
+ }
+ }
+ else
+ {
+ if( users.count() > 1 )
+ continue;
+ else
+ {
+ cerr << "WARNING: Cannot find ICE authority file "
+ << iceFile << "!" << endl
+ << "Please check permissions or set the $ICEAUTHORITY"
+ << " variable manually before" << endl
+ << "calling dcop." << endl;
+ }
+ }
+ }
+
+ // Main loop
+ // If users is an empty list we're calling for the currently logged
+ // in user. In this case we don't have a session, but still want
+ // to iterate the loop once.
+ QStringList::Iterator sIt = sessions.begin();
+ for( ; sIt != sessions.end() || users.isEmpty(); sIt++ )
+ {
+ if( !presetDCOPServer && !users.isEmpty() )
+ {
+ QString dcopFile = it.data() + "/" + *sIt;
+ QFile f( dcopFile );
+ if( !f.open( IO_ReadOnly ) )
+ {
+ cerr << "Can't open " << dcopFile << " for reading!" << endl;
+ exit( -1 );
+ }
+
+ QStringList l( QStringList::split( '\n', f.readAll() ) );
+ dcopServer = l.first();
+
+ if( dcopServer.isEmpty() )
+ {
+ cerr << "WARNING: Unable to determine DCOP server for session "
+ << *sIt << "!" << endl
+ << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
+ << "calling dcop." << endl;
+ exit( -1 );
+ }
+ }
+
+ delete client;
+ client = new DCOPClient;
+ if( !dcopServer.isEmpty() )
+ client->setServerAddress( dcopServer.ascii() );
+ bool success = client->attach();
+ if( !success )
+ {
+ cerr << "ERROR: Couldn't attach to DCOP server!" << endl;
+ continue;
+ }
+ dcop = client;
+
+ switch ( args.count() )
+ {
+ case 0:
+ queryApplications("");
+ break;
+ case 1:
+ if (endsWith(app, '*'))
+ queryApplications(app);
+ else
+ queryObjects( app, "" );
+ break;
+ case 2:
+ if (endsWith(objid, '*'))
+ queryObjects(app, objid);
+ else
+ queryFunctions( app, objid );
+ break;
+ case 3:
+ default:
+ if( readStdin )
+ {
+ QCStringList::Iterator replaceArg = args.end();
+
+ QCStringList::Iterator it;
+ for( it = args.begin(); it != args.end(); it++ )
+ if( *it == "%1" )
+ replaceArg = it;
+
+ // Read from stdin until EOF and call function for each line read
+ char *buf = new char[ 1000 ];
+ while ( !feof( stdin ) )
+ {
+ fgets( buf, 1000, stdin );
+
+ if( replaceArg != args.end() )
+ *replaceArg = buf;
+
+ callFunction( app, objid, function, params );
+ }
+ }
+ else
+ {
+ // Just call function
+// cout << "call " << app << ", " << objid << ", " << function << ", (params)" << endl;
+ callFunction( app, objid, function, params );
+ }
+ break;
+ }
+ // Another sIt++ would make the loop infinite...
+ if( users.isEmpty() )
+ break;
+ }
+
+ // Another it++ would make the loop infinite...
+ if( it == users.end() )
+ break;
}
+}
+
+int main( int argc, char** argv )
+{
+ bool readStdin = false;
+ int numOptions = 0;
+ QString user;
+ Session session = DefaultSession;
+ QString sessionName;
+
+ // Scan for command-line options first
+ for( int pos = 1 ; pos <= argc - 1 ; pos++ )
+ {
+ if( strcmp( argv[ pos ], "--help" ) == 0 )
+ showHelp( 0 );
+ else if( strcmp( argv[ pos ], "--pipe" ) == 0 )
+ {
+ readStdin = true;
+ numOptions++;
+ }
+ else if( strcmp( argv[ pos ], "--user" ) == 0 )
+ {
+ if( pos <= argc - 2 )
+ {
+ user = QString::fromLocal8Bit( argv[ pos + 1] );
+ numOptions +=2;
+ pos++;
+ }
+ else
+ {
+ cerr << "Missing username for '--user' option!" << endl << endl;
+ showHelp( -1 );
+ }
+ }
+ else if( strcmp( argv[ pos ], "--all-users" ) == 0 )
+ {
+ user = "*";
+ numOptions ++;
+ }
+ else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 )
+ {
+ session = QuerySessions;
+ numOptions ++;
+ }
+ else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 )
+ {
+ session = AllSessions;
+ numOptions ++;
+ }
+ else if( argv[ pos ][ 0 ] == '-' )
+ {
+ cerr << "Unknown command-line option '" << argv[ pos ]
+ << "'." << endl << endl;
+ showHelp( -1 );
+ }
+ else
+ break; // End of options
+ }
+
+ argc -= numOptions;
+
+ QCStringList args;
+ for( int i = numOptions; i < argc + numOptions - 1; i++ )
+ args.append( argv[ i + 1 ] );
+
+ if( readStdin && args.count() < 3 )
+ {
+ cerr << "--pipe option only supported for function calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( user == "*" && args.count() < 3 && session != QuerySessions )
+ {
+ cerr << "ERROR: The --all-users option is only supported for function calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( session == QuerySessions && !args.isEmpty() )
+ {
+ cerr << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( session == QuerySessions && user.isEmpty() )
+ {
+ cerr << "ERROR: The --list-sessions option can only be used with the --user or" << endl
+ << "--all-users options!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( session != DefaultSession && session != QuerySessions &&
+ args.count() < 3 )
+ {
+ cerr << "ERROR: The --session and --all-sessions options are only supported for function" << endl
+ << "calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ UserList users;
+ if( user == "*" )
+ users = userList();
+ else if( !user.isEmpty() )
+ users[ user ] = userList()[ user ];
+
+ runDCOP( args, users, session, sessionName, readStdin );
+
return 0;
}
+
+// vim: set ts=8 sts=4 sw=4 noet:
+
Index: client/dcopfind.cpp
===================================================================
RCS file: /home/kde/kdelibs/dcop/client/dcopfind.cpp,v
retrieving revision 1.2
diff -u -r1.2 dcopfind.cpp
--- client/dcopfind.cpp 2001/10/31 01:17:39 1.2
+++ client/dcopfind.cpp 2002/01/16 18:06:14
@@ -36,7 +36,7 @@
static bool bAppIdOnly = 0;
static bool bLaunchApp = 0;
-bool findObject( const char* app, const char* obj, const char* func, int argc, char** args )
+bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
{
QString f = func; // Qt is better with unicode strings, so use one.
int left = f.find( '(' );
@@ -118,7 +118,7 @@
f = fc;
}
- if ( (int) types.count() != argc ) {
+ if ( types.count() != args.count() ) {
qWarning( "arguments do not match" );
exit(1);
}
@@ -128,9 +128,9 @@
int i = 0;
for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
- marshall(arg, argc, args, i, *it);
+ marshall(arg, args, i, *it);
}
- if ( (int) i != argc ) {
+ if ( (uint) i != args.count() ) {
qWarning( "arguments do not match" );
exit(1);
}
@@ -221,7 +221,11 @@
argc = 0;
}
- findObject( app, objid, function, argc, args );
+ QCStringList params;
+ for( int i = 0; i < argc; i++ )
+ params.append( args[ i ] );
+
+ findObject( app, objid, function, params );
return 0;
}
Index: client/marshall.cpp
===================================================================
RCS file: /home/kde/kdelibs/dcop/client/marshall.cpp,v
retrieving revision 1.3
diff -u -r1.3 marshall.cpp
--- client/marshall.cpp 2001/10/31 01:17:39 1.3
+++ client/marshall.cpp 2002/01/16 18:06:14
@@ -242,108 +242,110 @@
}
-void marshall(QDataStream &arg, int argc, char **argv, int &i, QString type)
+void marshall( QDataStream &arg, QCStringList args, uint &i, QString type )
{
- if (type == "QStringList")
- type = "QValueList<QString>";
- if (type == "QCStringList")
- type = "QValueList<QCString>";
- if (i >= argc)
- {
- qWarning("Not enough arguments.");
- exit(1);
- }
- QString s = QString::fromLocal8Bit(argv[i]);
-
- if ( type == "int" )
- arg << s.toInt();
- else if ( type == "uint" )
- arg << s.toUInt();
- else if ( type == "unsigned" )
- arg << s.toUInt();
- else if ( type == "unsigned int" )
- arg << s.toUInt();
- else if ( type == "long" )
- arg << s.toLong();
- else if ( type == "long int" )
- arg << s.toLong();
- else if ( type == "unsigned long" )
- arg << s.toULong();
- else if ( type == "unsigned long int" )
- arg << s.toULong();
- else if ( type == "float" )
- arg << s.toFloat();
- else if ( type == "double" )
- arg << s.toDouble();
- else if ( type == "bool" )
- arg << mkBool( s );
- else if ( type == "QString" )
- arg << s;
- else if ( type == "QCString" )
- arg << QCString( argv[i] );
- else if ( type == "QColor" )
- arg << mkColor( s );
- else if ( type == "QPoint" )
- arg << mkPoint( s );
- else if ( type == "QSize" )
- arg << mkSize( s );
- else if ( type == "QRect" )
- arg << mkRect( s );
- else if ( type == "QVariant" ) {
- if ( s == "true" || s == "false" )
- arg << QVariant( mkBool( s ), 42 );
- else if ( s.left( 4 ) == "int(" )
- arg << QVariant( s.mid(4, s.length()-5).toInt() );
- else if ( s.left( 7 ) == "QPoint(" )
- arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
- else if ( s.left( 6 ) == "QSize(" )
- arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
- else if ( s.left( 6 ) == "QRect(" )
- arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
- else if ( s.left( 7 ) == "QColor(" )
- arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
- else
- arg << QVariant( s );
- } else if ( type.startsWith("QValueList<")) {
- type = type.mid(11, type.length() - 12);
- QStringList list;
- QString delim = s;
- if (delim == "[")
- delim = "]";
- if (delim == "(")
- delim = ")";
- i++;
- QByteArray dummy_data;
- QDataStream dummy_arg(dummy_data, IO_WriteOnly);
+ if (type == "QStringList")
+ type = "QValueList<QString>";
+ if (type == "QCStringList")
+ type = "QValueList<QCString>";
+ if( i > args.count() )
+ {
+ qWarning("Not enough arguments.");
+ exit(1);
+ }
+ QString s = QString::fromLocal8Bit( args[ i ] );
- int j = i;
- int count = 0;
- // Parse list to get the count
- while (true) {
- if (j >= argc)
- {
- qWarning("List end-delimiter '%s' not found.", delim.latin1());
- exit(1);
- }
- if (argv[j] == delim) break;
- marshall(dummy_arg, argc, argv, j, type);
- count++;
- }
- arg << (Q_UINT32) count;
- // Parse the list for real
- while (true) {
- if (i >= argc)
- {
- qWarning("List end-delimiter '%s' not found.", delim.latin1());
- exit(1);
- }
- if (argv[i] == delim) break;
- marshall(arg, argc, argv, i, type);
- }
- } else {
- qWarning( "cannot handle datatype '%s'", type.latin1() );
- exit(1);
- }
+ if ( type == "int" )
+ arg << s.toInt();
+ else if ( type == "uint" )
+ arg << s.toUInt();
+ else if ( type == "unsigned" )
+ arg << s.toUInt();
+ else if ( type == "unsigned int" )
+ arg << s.toUInt();
+ else if ( type == "long" )
+ arg << s.toLong();
+ else if ( type == "long int" )
+ arg << s.toLong();
+ else if ( type == "unsigned long" )
+ arg << s.toULong();
+ else if ( type == "unsigned long int" )
+ arg << s.toULong();
+ else if ( type == "float" )
+ arg << s.toFloat();
+ else if ( type == "double" )
+ arg << s.toDouble();
+ else if ( type == "bool" )
+ arg << mkBool( s );
+ else if ( type == "QString" )
+ arg << s;
+ else if ( type == "QCString" )
+ arg << QCString( args[ i ] );
+ else if ( type == "QColor" )
+ arg << mkColor( s );
+ else if ( type == "QPoint" )
+ arg << mkPoint( s );
+ else if ( type == "QSize" )
+ arg << mkSize( s );
+ else if ( type == "QRect" )
+ arg << mkRect( s );
+ else if ( type == "QVariant" ) {
+ if ( s == "true" || s == "false" )
+ arg << QVariant( mkBool( s ), 42 );
+ else if ( s.left( 4 ) == "int(" )
+ arg << QVariant( s.mid(4, s.length()-5).toInt() );
+ else if ( s.left( 7 ) == "QPoint(" )
+ arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
+ else if ( s.left( 6 ) == "QSize(" )
+ arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
+ else if ( s.left( 6 ) == "QRect(" )
+ arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
+ else if ( s.left( 7 ) == "QColor(" )
+ arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
+ else
+ arg << QVariant( s );
+ } else if ( type.startsWith("QValueList<")) {
+ type = type.mid(11, type.length() - 12);
+ QStringList list;
+ QString delim = s;
+ if (delim == "[")
+ delim = "]";
+ if (delim == "(")
+ delim = ")";
i++;
+ QByteArray dummy_data;
+ QDataStream dummy_arg(dummy_data, IO_WriteOnly);
+
+ uint j = i;
+ uint count = 0;
+ // Parse list to get the count
+ while (true) {
+ if( j > args.count() )
+ {
+ qWarning("List end-delimiter '%s' not found.", delim.latin1());
+ exit(1);
+ }
+ if( QString::fromLocal8Bit( args[ j ] ) == delim )
+ break;
+ marshall( dummy_arg, args, j, type );
+ count++;
+ }
+ arg << (Q_UINT32) count;
+ // Parse the list for real
+ while (true) {
+ if( i > args.count() )
+ {
+ qWarning("List end-delimiter '%s' not found.", delim.latin1());
+ exit(1);
+ }
+ if( QString::fromLocal8Bit( args[ i ] ) == delim )
+ break;
+ marshall( arg, args, i, type );
+ }
+ } else {
+ qWarning( "cannot handle datatype '%s'", type.latin1() );
+ exit(1);
+ }
+ i++;
}

View file

@ -0,0 +1,27 @@
*** /home/John/lao Thu Apr 12 11:09:30 2001
--- /home/John/tzu Sat Jul 28 13:23:25 2001
***************
*** 1,7 ****
- The Way that can be told of is not the eternal Way;
- The name that can be named is not the eternal name.
The Nameless is the origin of Heaven and Earth;
! The Named is the mother of all things.
Therefore let there always be non-being,
so we may see their subtlety,
And let there always be being,
--- 1,6 ----
The Nameless is the origin of Heaven and Earth;
! The named is the mother of all things.
!
Therefore let there always be non-being,
so we may see their subtlety,
And let there always be being,
***************
*** 9,11 ****
--- 8,13 ----
The two are the same,
But after they are produced,
they have different names.
+ They both may be called deep and profound.
+ Deeper and more profound,
+ The door of all subtleties!

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,27 @@
*** /home/John/lao Thu Apr 12 11:09:30 2001
--- /home/John/tzu Sat Jul 28 13:23:25 2001
***************
*** 1,7 ****
- The Way that can be told of is not the eternal Way;
- The name that can be named is not the eternal name.
The Nameless is the origin of Heaven and Earth;
! The Named is the mother of all things.
Therefore let there always be non-being,
so we may see their subtlety,
And let there always be being,
--- 1,6 ----
The Nameless is the origin of Heaven and Earth;
! The named is the mother of all things.
!
Therefore let there always be non-being,
so we may see their subtlety,
And let there always be being,
*************** And let there always be being,
*** 9,11 ****
--- 8,13 ----
The two are the same,
But after they are produced,
they have different names.
+ They both may be called deep and profound.
+ Deeper and more profound,
+ The door of all subtleties!

View file

@ -0,0 +1,10 @@
11a
They both may be called deep and profound.
Deeper and more profound,
The door of all subtleties!
.
4c
The named is the mother of all things.
.
1,2d

680
kompare/tests/diff/edm.diff Normal file
View file

@ -0,0 +1,680 @@
diff -er dcop/client/dcop.cpp dcop2/client/dcop.cpp
343a
// vim: set ts=8 sts=4 sw=4 noet:
.
340a
}
int main( int argc, char** argv )
{
bool readStdin = false;
int numOptions = 0;
QString user;
Session session = DefaultSession;
QString sessionName;
// Scan for command-line options first
for( int pos = 1 ; pos <= argc - 1 ; pos++ )
{
if( strcmp( argv[ pos ], "--help" ) == 0 )
showHelp( 0 );
else if( strcmp( argv[ pos ], "--pipe" ) == 0 )
{
readStdin = true;
numOptions++;
}
else if( strcmp( argv[ pos ], "--user" ) == 0 )
{
if( pos <= argc - 2 )
{
user = QString::fromLocal8Bit( argv[ pos + 1] );
numOptions +=2;
pos++;
}
else
{
cerr << "Missing username for '--user' option!" << endl << endl;
showHelp( -1 );
}
}
else if( strcmp( argv[ pos ], "--all-users" ) == 0 )
{
user = "*";
numOptions ++;
}
else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 )
{
session = QuerySessions;
numOptions ++;
}
else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 )
{
session = AllSessions;
numOptions ++;
}
else if( argv[ pos ][ 0 ] == '-' )
{
cerr << "Unknown command-line option '" << argv[ pos ]
<< "'." << endl << endl;
showHelp( -1 );
}
else
break; // End of options
}
argc -= numOptions;
QCStringList args;
for( int i = numOptions; i < argc + numOptions - 1; i++ )
args.append( argv[ i + 1 ] );
if( readStdin && args.count() < 3 )
{
cerr << "--pipe option only supported for function calls!" << endl << endl;
showHelp( -1 );
}
if( user == "*" && args.count() < 3 && session != QuerySessions )
{
cerr << "ERROR: The --all-users option is only supported for function calls!" << endl << endl;
showHelp( -1 );
}
if( session == QuerySessions && !args.isEmpty() )
{
cerr << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl;
showHelp( -1 );
}
if( session == QuerySessions && user.isEmpty() )
{
cerr << "ERROR: The --list-sessions option can only be used with the --user or" << endl
<< "--all-users options!" << endl << endl;
showHelp( -1 );
}
if( session != DefaultSession && session != QuerySessions &&
args.count() < 3 )
{
cerr << "ERROR: The --session and --all-sessions options are only supported for function" << endl
<< "calls!" << endl << endl;
showHelp( -1 );
}
UserList users;
if( user == "*" )
users = userList();
else if( !user.isEmpty() )
users[ user ] = userList()[ user ];
runDCOP( args, users, session, sessionName, readStdin );
.
339a
if( users.count() > 1 || ( users.count() == 1 &&
( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) )
{
// Check for ICE authority file and if the file can be read by us
QString home = it.data();
QString iceFile = it.data() + "/.ICEauthority";
QFileInfo fi( iceFile );
if( iceFile.isEmpty() )
{
cerr << "WARNING: Cannot determine home directory for user "
<< it.key() << "!" << endl
<< "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
<< "calling dcop." << endl;
}
else if( fi.exists() )
{
if( fi.isReadable() )
{
char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() );
putenv( envStr );
//cerr << "ice: " << envStr << endl;
}
else
{
cerr << "WARNING: ICE authority file " << iceFile
<< "is not readable by you!" << endl
<< "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
<< "calling dcop." << endl;
}
}
else
{
if( users.count() > 1 )
continue;
else
{
cerr << "WARNING: Cannot find ICE authority file "
<< iceFile << "!" << endl
<< "Please check permissions or set the $ICEAUTHORITY"
<< " variable manually before" << endl
<< "calling dcop." << endl;
}
}
}
// Main loop
// If users is an empty list we're calling for the currently logged
// in user. In this case we don't have a session, but still want
// to iterate the loop once.
QStringList::Iterator sIt = sessions.begin();
for( ; sIt != sessions.end() || users.isEmpty(); sIt++ )
{
if( !presetDCOPServer && !users.isEmpty() )
{
QString dcopFile = it.data() + "/" + *sIt;
QFile f( dcopFile );
if( !f.open( IO_ReadOnly ) )
{
cerr << "Can't open " << dcopFile << " for reading!" << endl;
exit( -1 );
}
QStringList l( QStringList::split( '\n', f.readAll() ) );
dcopServer = l.first();
if( dcopServer.isEmpty() )
{
cerr << "WARNING: Unable to determine DCOP server for session "
<< *sIt << "!" << endl
<< "Please check permissions or set the $DCOPSERVER variable manually before" << endl
<< "calling dcop." << endl;
exit( -1 );
}
}
delete client;
client = new DCOPClient;
if( !dcopServer.isEmpty() )
client->setServerAddress( dcopServer.ascii() );
bool success = client->attach();
if( !success )
{
cerr << "ERROR: Couldn't attach to DCOP server!" << endl;
continue;
}
dcop = client;
switch ( args.count() )
{
case 0:
queryApplications("");
break;
case 1:
if (endsWith(app, '*'))
queryApplications(app);
else
queryObjects( app, "" );
break;
case 2:
if (endsWith(objid, '*'))
queryObjects(app, objid);
else
queryFunctions( app, objid );
break;
case 3:
default:
if( readStdin )
{
QCStringList::Iterator replaceArg = args.end();
QCStringList::Iterator it;
for( it = args.begin(); it != args.end(); it++ )
if( *it == "%1" )
replaceArg = it;
// Read from stdin until EOF and call function for each line read
char *buf = new char[ 1000 ];
while ( !feof( stdin ) )
{
fgets( buf, 1000, stdin );
if( replaceArg != args.end() )
*replaceArg = buf;
callFunction( app, objid, function, params );
}
}
else
{
// Just call function
// cout << "call " << app << ", " << objid << ", " << function << ", (params)" << endl;
callFunction( app, objid, function, params );
}
break;
}
// Another sIt++ would make the loop infinite...
if( users.isEmpty() )
break;
}
// Another it++ would make the loop infinite...
if( it == users.end() )
break;
.
308,338c
if( !args.isEmpty() )
app = args[ 0 ];
if( args.count() > 1 )
objid = args[ 1 ];
if( args.count() > 2 )
function = args[ 2 ];
if( args.count() > 3)
{
params = args;
params.remove( params.begin() );
params.remove( params.begin() );
params.remove( params.begin() );
}
}
bool firstRun = true;
UserList::Iterator it;
QStringList sessions;
bool presetDCOPServer = false;
// char *dcopStr = 0L;
QString dcopServer;
for( it = users.begin(); it != users.end() || firstRun; it++ )
{
firstRun = false;
//cout << "Iterating '" << it.key() << "'" << endl;
if( session == QuerySessions )
{
QStringList sessions = dcopSessionList( it.key(), it.data() );
if( sessions.isEmpty() )
{
cout << "No active sessions";
if( !( *it ).isEmpty() )
cout << " for user " << *it;
cout << endl;
}
else
{
cout << "Active sessions ";
if( !( *it ).isEmpty() )
cout << "for user " << *it << " ";
cout << ":" << endl;
QStringList::Iterator sIt;
for( sIt = sessions.begin(); sIt != sessions.end(); sIt++ )
cout << " " << *sIt << endl;
cout << endl;
}
continue;
}
if( getenv( "DCOPSERVER" ) )
{
sessions.append( getenv( "DCOPSERVER" ) );
presetDCOPServer = true;
}
if( users.count() > 1 || ( users.count() == 1 &&
( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) )
{
sessions = dcopSessionList( it.key(), it.data() );
if( sessions.isEmpty() )
{
if( users.count() > 1 )
continue;
else
{
cerr << "ERROR: No active KDE sessions!" << endl
<< "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
<< "before calling dcop." << endl;
exit( -1 );
}
}
else if( sessions.count() > 1 && session != AllSessions )
{
cerr << "ERROR: Multiple available KDE sessions!" << endl
<< "Please specify the correct session to use with --session or use the" << endl
<< "--all-sessions option to broadcast to all sessions." << endl;
exit( -1 );
}
}
.
289,304c
// WARNING: This part (until the closing '}') could very
// well be broken now. As I don't know how to trigger and test
// dcoprefs this code is *not* tested. It compiles and it looks
// ok to me, but that's all I can say - Martijn (2001/12/24)
int delimPos = args[ 0 ].findRev( ',' );
if( delimPos == -1 )
{
cerr << "Error: '" << args[ 0 ]
<< "' is not a valid DCOP reference." << endl;
exit( -1 );
}
args[ 0 ][ delimPos ] = 0;
app = args[ 0 ].mid( 8 );
delimPos++;
args[ 0 ][ args[ 0 ].length() - 1 ] = 0;
objid = args[ 0 ].mid( delimPos );
if( args.count() > 1 )
function = args[ 1 ];
if( args.count() > 2 )
{
params = args;
params.remove( params.begin() );
params.remove( params.begin() );
}
.
286,287c
QCStringList params;
DCOPClient *client = 0L;
if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
.
282a
/**
* Do the actual DCOP call
*/
void runDCOP( QCStringList args, UserList users, Session session,
const QString sessionName, bool readStdin )
{
.
279,281c
return result;
}
/**
* Return a list of available DCOP sessions for the specified user
* An empty list means no sessions are available, or an error occurred.
*/
QStringList dcopSessionList( const QString &user, const QString &home )
{
if( home.isEmpty() )
{
cerr << "WARNING: Cannot determine home directory for user "
<< user << "!" << endl
<< "Please check permissions or set the $DCOPSERVER variable manually before" << endl
<< "calling dcop." << endl;
return QStringList();
}
QStringList result;
QFileInfo dirInfo( home );
if( !dirInfo.exists() || !dirInfo.isReadable() )
return result;
QDir d( home );
d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
d.setNameFilter( ".DCOPserver*" );
const QFileInfoList *list = d.entryInfoList();
if( !list )
return result;
QFileInfoListIterator it( *list );
QFileInfo *fi;
while ( ( fi = it.current() ) != 0 )
{
if( fi->isReadable() )
result.append( fi->fileName() );
++it;
}
return result;
}
.
274,276c
QStringList l( QStringList::split( '\n', f.readAll() ) );
for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it )
{
QStringList userInfo( QStringList::split( ':', *it, true ) );
result[ userInfo[ 0 ] ] = userInfo[ 5 ];
.
272a
UserList result;
QFile f( "/etc/passwd" );
if( !f.open( IO_ReadOnly ) )
{
cerr << "Can't open /etc/passwd for reading!" << endl;
return result;
}
.
270,271c
/**
* Return a list of all users and their home directories.
* Returns an empty list if /etc/passwd cannot be read for some reason.
*/
static UserList userList()
.
268a
/**
* Show command-line help and exit
*/
void showHelp( int exitCode = 0 )
{
cout << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl
<< "" << endl
<< "Console DCOP client" << endl
<< "" << endl
<< "Generic options:" << endl
<< " --help Show help about options" << endl
<< "" << endl
<< "Options:" << endl
<< " --pipe Call DCOP for each line read from stdin" << endl
<< " --user <user> Connect to the given user's DCOP server. This option will" << endl
<< " ignore the values of the environment vars $DCOPSERVER and" << endl
<< " $ICEAUTHORITY, even if they are set." << endl
<< " If the user has more than one open session, you must also" << endl
<< " use one of the --list-sessions, --session or --als-sessions" << endl
<< " command-line options." << endl
<< " --all-users Send the same DCOP call to all users with a running DCOP" << endl
<< " server. Only failed calls to existing DCOP servers will"
<< " generate an error message. If no DCOP server is available" << endl
<< " at all, no error will be generated." << endl;
exit( exitCode );
}
.
246,250c
uint i = 0;
for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
marshall( arg, args, i, *it );
if ( i != args.count() )
{
.
164c
// exit(1);
return;
.
156,157c
uint a = (*it).contains(',');
if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
.
139c
if ( !ok && args.isEmpty() )
.
123d
121c
void callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
.
35a
static QTextStream cout( stdout, IO_WriteOnly );
static QTextStream cerr( stderr, IO_WriteOnly );
/**
* Session to send call to
* DefaultSession - current session. Current KDE session when called without
* --user or --all-users option. Otherwise this value ignores
* all users with more than one active session.
* AllSessions - Send to all sessions found. requires --user or --all-users.
* QuerySessions - Don't call DCOP, return a list of available sessions.
* CustomSession - Use the specified session
*/
enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
.
33a
typedef QMap<QString, QString> UserList;
.
28,30c
#include "../kdatastream.h"
.
25c
#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qmap.h>
#include <qstringlist.h>
#include <qtextstream.h>
#include <qvariant.h>
// putenv() is not available on all platforms, so make sure the emulation
// wrapper is available in those cases by loading config.h!
#include <config.h>
.
23c
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
.
diff -er dcop/client/dcopfind.cpp dcop2/client/dcopfind.cpp
224c
QCStringList params;
for( int i = 0; i < argc; i++ )
params.append( args[ i ] );
findObject( app, objid, function, params );
.
133c
if ( (uint) i != args.count() ) {
.
131c
marshall(arg, args, i, *it);
.
121c
if ( types.count() != args.count() ) {
.
39c
bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
.
diff -er dcop/client/marshall.cpp dcop2/client/marshall.cpp
347a
QByteArray dummy_data;
QDataStream dummy_arg(dummy_data, IO_WriteOnly);
uint j = i;
uint count = 0;
// Parse list to get the count
while (true) {
if( j > args.count() )
{
qWarning("List end-delimiter '%s' not found.", delim.latin1());
exit(1);
}
if( QString::fromLocal8Bit( args[ j ] ) == delim )
break;
marshall( dummy_arg, args, j, type );
count++;
}
arg << (Q_UINT32) count;
// Parse the list for real
while (true) {
if( i > args.count() )
{
qWarning("List end-delimiter '%s' not found.", delim.latin1());
exit(1);
}
if( QString::fromLocal8Bit( args[ i ] ) == delim )
break;
marshall( arg, args, i, type );
}
} else {
qWarning( "cannot handle datatype '%s'", type.latin1() );
exit(1);
}
i++;
.
319,346c
if ( type == "int" )
arg << s.toInt();
else if ( type == "uint" )
arg << s.toUInt();
else if ( type == "unsigned" )
arg << s.toUInt();
else if ( type == "unsigned int" )
arg << s.toUInt();
else if ( type == "long" )
arg << s.toLong();
else if ( type == "long int" )
arg << s.toLong();
else if ( type == "unsigned long" )
arg << s.toULong();
else if ( type == "unsigned long int" )
arg << s.toULong();
else if ( type == "float" )
arg << s.toFloat();
else if ( type == "double" )
arg << s.toDouble();
else if ( type == "bool" )
arg << mkBool( s );
else if ( type == "QString" )
arg << s;
else if ( type == "QCString" )
arg << QCString( args[ i ] );
else if ( type == "QColor" )
arg << mkColor( s );
else if ( type == "QPoint" )
arg << mkPoint( s );
else if ( type == "QSize" )
arg << mkSize( s );
else if ( type == "QRect" )
arg << mkRect( s );
else if ( type == "QVariant" ) {
if ( s == "true" || s == "false" )
arg << QVariant( mkBool( s ), 42 );
else if ( s.left( 4 ) == "int(" )
arg << QVariant( s.mid(4, s.length()-5).toInt() );
else if ( s.left( 7 ) == "QPoint(" )
arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
else if ( s.left( 6 ) == "QSize(" )
arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
else if ( s.left( 6 ) == "QRect(" )
arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
else if ( s.left( 7 ) == "QColor(" )
arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
else
arg << QVariant( s );
} else if ( type.startsWith("QValueList<")) {
type = type.mid(11, type.length() - 12);
QStringList list;
QString delim = s;
if (delim == "[")
delim = "]";
if (delim == "(")
delim = ")";
.
247,317c
if (type == "QStringList")
type = "QValueList<QString>";
if (type == "QCStringList")
type = "QValueList<QCString>";
if( i > args.count() )
{
qWarning("Not enough arguments.");
exit(1);
}
QString s = QString::fromLocal8Bit( args[ i ] );
.
245c
void marshall( QDataStream &arg, QCStringList args, uint &i, QString type )
.

View file

@ -0,0 +1,12 @@
1,2d0
< The Way that can be told of is not the eternal Way;
< The name that can be named is not the eternal name.
4c2,3
< The Named is the mother of all things.
---
> The named is the mother of all things.
>
11a11,13
> They both may be called deep and profound.
> Deeper and more profound,
> The door of all subtleties!

View file

@ -0,0 +1,849 @@
diff -r dcop/client/dcop.cpp dcop2/client/dcop.cpp
23c23,26
< #include <qvariant.h>
---
> #include <ctype.h>
> #include <stdio.h>
> #include <stdlib.h>
>
25c28,39
< #include "../kdatastream.h"
---
> #include <qdir.h>
> #include <qfile.h>
> #include <qfileinfo.h>
> #include <qmap.h>
> #include <qstringlist.h>
> #include <qtextstream.h>
> #include <qvariant.h>
>
> // putenv() is not available on all platforms, so make sure the emulation
> // wrapper is available in those cases by loading config.h!
> #include <config.h>
>
28,30c42
< #include <stdlib.h>
< #include <stdio.h>
< #include <ctype.h>
---
> #include "../kdatastream.h"
33a46,47
> typedef QMap<QString, QString> UserList;
>
35a50,63
> static QTextStream cout( stdout, IO_WriteOnly );
> static QTextStream cerr( stderr, IO_WriteOnly );
>
> /**
> * Session to send call to
> * DefaultSession - current session. Current KDE session when called without
> * --user or --all-users option. Otherwise this value ignores
> * all users with more than one active session.
> * AllSessions - Send to all sessions found. requires --user or --all-users.
> * QuerySessions - Don't call DCOP, return a list of available sessions.
> * CustomSession - Use the specified session
> */
> enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
>
121c149
< void callFunction( const char* app, const char* obj, const char* func, int argc, char** args )
---
> void callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
123d150
<
139c166
< if ( !ok && argc == 0 )
---
> if ( !ok && args.isEmpty() )
156,157c183,184
< int a = (*it).contains(',');
< if ( ( a == 0 && argc == 0) || ( a > 0 && a + 1 == argc ) )
---
> uint a = (*it).contains(',');
> if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
164c191,192
< exit(1);
---
> // exit(1);
> return;
246,250c274,279
< int i = 0;
< for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
< marshall(arg, argc, args, i, *it);
< }
< if ( i != argc ) {
---
> uint i = 0;
> for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
> marshall( arg, args, i, *it );
>
> if ( i != args.count() )
> {
268a298,324
> /**
> * Show command-line help and exit
> */
> void showHelp( int exitCode = 0 )
> {
> cout << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl
> << "" << endl
> << "Console DCOP client" << endl
> << "" << endl
> << "Generic options:" << endl
> << " --help Show help about options" << endl
> << "" << endl
> << "Options:" << endl
> << " --pipe Call DCOP for each line read from stdin" << endl
> << " --user <user> Connect to the given user's DCOP server. This option will" << endl
> << " ignore the values of the environment vars $DCOPSERVER and" << endl
> << " $ICEAUTHORITY, even if they are set." << endl
> << " If the user has more than one open session, you must also" << endl
> << " use one of the --list-sessions, --session or --als-sessions" << endl
> << " command-line options." << endl
> << " --all-users Send the same DCOP call to all users with a running DCOP" << endl
> << " server. Only failed calls to existing DCOP servers will"
> << " generate an error message. If no DCOP server is available" << endl
> << " at all, no error will be generated." << endl;
>
> exit( exitCode );
> }
270,271c326,330
<
< int main( int argc, char** argv )
---
> /**
> * Return a list of all users and their home directories.
> * Returns an empty list if /etc/passwd cannot be read for some reason.
> */
> static UserList userList()
272a332,340
> UserList result;
>
> QFile f( "/etc/passwd" );
>
> if( !f.open( IO_ReadOnly ) )
> {
> cerr << "Can't open /etc/passwd for reading!" << endl;
> return result;
> }
274,276c342,347
< if ( argc > 1 && argv[1][0] == '-' ) {
< fprintf( stderr, "Usage: dcop [ application [object [function [arg1] [arg2] [arg3] ... ] ] ] \n" );
< exit(0);
---
> QStringList l( QStringList::split( '\n', f.readAll() ) );
>
> for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it )
> {
> QStringList userInfo( QStringList::split( ':', *it, true ) );
> result[ userInfo[ 0 ] ] = userInfo[ 5 ];
279,281c350,391
< DCOPClient client;
< client.attach();
< dcop = &client;
---
> return result;
> }
>
> /**
> * Return a list of available DCOP sessions for the specified user
> * An empty list means no sessions are available, or an error occurred.
> */
> QStringList dcopSessionList( const QString &user, const QString &home )
> {
> if( home.isEmpty() )
> {
> cerr << "WARNING: Cannot determine home directory for user "
> << user << "!" << endl
> << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
> << "calling dcop." << endl;
> return QStringList();
> }
>
> QStringList result;
> QFileInfo dirInfo( home );
> if( !dirInfo.exists() || !dirInfo.isReadable() )
> return result;
>
> QDir d( home );
> d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
> d.setNameFilter( ".DCOPserver*" );
>
> const QFileInfoList *list = d.entryInfoList();
> if( !list )
> return result;
>
> QFileInfoListIterator it( *list );
> QFileInfo *fi;
>
> while ( ( fi = it.current() ) != 0 )
> {
> if( fi->isReadable() )
> result.append( fi->fileName() );
> ++it;
> }
> return result;
> }
282a393,398
> /**
> * Do the actual DCOP call
> */
> void runDCOP( QCStringList args, UserList users, Session session,
> const QString sessionName, bool readStdin )
> {
286,287c402,404
< char **args = 0;
< if ((argc > 1) && (strncmp(argv[1], "DCOPRef(", 8)) == 0)
---
> QCStringList params;
> DCOPClient *client = 0L;
> if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
289,304c406,429
< char *delim = strchr(argv[1], ',');
< if (!delim)
< {
< fprintf(stderr, "Error: '%s' is not a valid DCOP reference.\n", argv[1]);
< return 1;
< }
< *delim = 0;
< app = argv[1] + 8;
< delim++;
< delim[strlen(delim)-1] = 0;
< objid = delim;
< if (argc > 2)
< function = argv[2];
< if (argc > 3)
< args = &argv[3];
< argc++;
---
> // WARNING: This part (until the closing '}') could very
> // well be broken now. As I don't know how to trigger and test
> // dcoprefs this code is *not* tested. It compiles and it looks
> // ok to me, but that's all I can say - Martijn (2001/12/24)
> int delimPos = args[ 0 ].findRev( ',' );
> if( delimPos == -1 )
> {
> cerr << "Error: '" << args[ 0 ]
> << "' is not a valid DCOP reference." << endl;
> exit( -1 );
> }
> args[ 0 ][ delimPos ] = 0;
> app = args[ 0 ].mid( 8 );
> delimPos++;
> args[ 0 ][ args[ 0 ].length() - 1 ] = 0;
> objid = args[ 0 ].mid( delimPos );
> if( args.count() > 1 )
> function = args[ 1 ];
> if( args.count() > 2 )
> {
> params = args;
> params.remove( params.begin() );
> params.remove( params.begin() );
> }
308,338c433,516
< if (argc > 1)
< app = argv[1];
< if (argc > 2)
< objid = argv[2];
< if (argc > 3)
< function = argv[3];
< if (argc > 4)
< args = &argv[4];
< }
<
< switch ( argc ) {
< case 0:
< case 1:
< queryApplications("");
< break;
< case 2:
< if (endsWith(app, '*'))
< queryApplications(app);
< else
< queryObjects( app, "" );
< break;
< case 3:
< if (endsWith(objid, '*'))
< queryObjects(app, objid);
< else
< queryFunctions( app, objid );
< break;
< case 4:
< default:
< callFunction( app, objid, function, argc - 4, args );
< break;
---
> if( !args.isEmpty() )
> app = args[ 0 ];
> if( args.count() > 1 )
> objid = args[ 1 ];
> if( args.count() > 2 )
> function = args[ 2 ];
> if( args.count() > 3)
> {
> params = args;
> params.remove( params.begin() );
> params.remove( params.begin() );
> params.remove( params.begin() );
> }
> }
>
> bool firstRun = true;
> UserList::Iterator it;
> QStringList sessions;
> bool presetDCOPServer = false;
> // char *dcopStr = 0L;
> QString dcopServer;
>
> for( it = users.begin(); it != users.end() || firstRun; it++ )
> {
> firstRun = false;
>
> //cout << "Iterating '" << it.key() << "'" << endl;
>
> if( session == QuerySessions )
> {
> QStringList sessions = dcopSessionList( it.key(), it.data() );
> if( sessions.isEmpty() )
> {
> cout << "No active sessions";
> if( !( *it ).isEmpty() )
> cout << " for user " << *it;
> cout << endl;
> }
> else
> {
> cout << "Active sessions ";
> if( !( *it ).isEmpty() )
> cout << "for user " << *it << " ";
> cout << ":" << endl;
>
> QStringList::Iterator sIt;
> for( sIt = sessions.begin(); sIt != sessions.end(); sIt++ )
> cout << " " << *sIt << endl;
>
> cout << endl;
> }
> continue;
> }
>
> if( getenv( "DCOPSERVER" ) )
> {
> sessions.append( getenv( "DCOPSERVER" ) );
> presetDCOPServer = true;
> }
>
> if( users.count() > 1 || ( users.count() == 1 &&
> ( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) )
> {
> sessions = dcopSessionList( it.key(), it.data() );
> if( sessions.isEmpty() )
> {
> if( users.count() > 1 )
> continue;
> else
> {
> cerr << "ERROR: No active KDE sessions!" << endl
> << "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
> << "before calling dcop." << endl;
> exit( -1 );
> }
> }
> else if( sessions.count() > 1 && session != AllSessions )
> {
> cerr << "ERROR: Multiple available KDE sessions!" << endl
> << "Please specify the correct session to use with --session or use the" << endl
> << "--all-sessions option to broadcast to all sessions." << endl;
> exit( -1 );
> }
> }
339a518,660
> if( users.count() > 1 || ( users.count() == 1 &&
> ( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) )
> {
> // Check for ICE authority file and if the file can be read by us
> QString home = it.data();
> QString iceFile = it.data() + "/.ICEauthority";
> QFileInfo fi( iceFile );
> if( iceFile.isEmpty() )
> {
> cerr << "WARNING: Cannot determine home directory for user "
> << it.key() << "!" << endl
> << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
> << "calling dcop." << endl;
> }
> else if( fi.exists() )
> {
> if( fi.isReadable() )
> {
> char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() );
> putenv( envStr );
> //cerr << "ice: " << envStr << endl;
> }
> else
> {
> cerr << "WARNING: ICE authority file " << iceFile
> << "is not readable by you!" << endl
> << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
> << "calling dcop." << endl;
> }
> }
> else
> {
> if( users.count() > 1 )
> continue;
> else
> {
> cerr << "WARNING: Cannot find ICE authority file "
> << iceFile << "!" << endl
> << "Please check permissions or set the $ICEAUTHORITY"
> << " variable manually before" << endl
> << "calling dcop." << endl;
> }
> }
> }
>
> // Main loop
> // If users is an empty list we're calling for the currently logged
> // in user. In this case we don't have a session, but still want
> // to iterate the loop once.
> QStringList::Iterator sIt = sessions.begin();
> for( ; sIt != sessions.end() || users.isEmpty(); sIt++ )
> {
> if( !presetDCOPServer && !users.isEmpty() )
> {
> QString dcopFile = it.data() + "/" + *sIt;
> QFile f( dcopFile );
> if( !f.open( IO_ReadOnly ) )
> {
> cerr << "Can't open " << dcopFile << " for reading!" << endl;
> exit( -1 );
> }
>
> QStringList l( QStringList::split( '\n', f.readAll() ) );
> dcopServer = l.first();
>
> if( dcopServer.isEmpty() )
> {
> cerr << "WARNING: Unable to determine DCOP server for session "
> << *sIt << "!" << endl
> << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
> << "calling dcop." << endl;
> exit( -1 );
> }
> }
>
> delete client;
> client = new DCOPClient;
> if( !dcopServer.isEmpty() )
> client->setServerAddress( dcopServer.ascii() );
> bool success = client->attach();
> if( !success )
> {
> cerr << "ERROR: Couldn't attach to DCOP server!" << endl;
> continue;
> }
> dcop = client;
>
> switch ( args.count() )
> {
> case 0:
> queryApplications("");
> break;
> case 1:
> if (endsWith(app, '*'))
> queryApplications(app);
> else
> queryObjects( app, "" );
> break;
> case 2:
> if (endsWith(objid, '*'))
> queryObjects(app, objid);
> else
> queryFunctions( app, objid );
> break;
> case 3:
> default:
> if( readStdin )
> {
> QCStringList::Iterator replaceArg = args.end();
>
> QCStringList::Iterator it;
> for( it = args.begin(); it != args.end(); it++ )
> if( *it == "%1" )
> replaceArg = it;
>
> // Read from stdin until EOF and call function for each line read
> char *buf = new char[ 1000 ];
> while ( !feof( stdin ) )
> {
> fgets( buf, 1000, stdin );
>
> if( replaceArg != args.end() )
> *replaceArg = buf;
>
> callFunction( app, objid, function, params );
> }
> }
> else
> {
> // Just call function
> // cout << "call " << app << ", " << objid << ", " << function << ", (params)" << endl;
> callFunction( app, objid, function, params );
> }
> break;
> }
> // Another sIt++ would make the loop infinite...
> if( users.isEmpty() )
> break;
> }
>
> // Another it++ would make the loop infinite...
> if( it == users.end() )
> break;
340a662,767
> }
>
>
> int main( int argc, char** argv )
> {
> bool readStdin = false;
> int numOptions = 0;
> QString user;
> Session session = DefaultSession;
> QString sessionName;
>
> // Scan for command-line options first
> for( int pos = 1 ; pos <= argc - 1 ; pos++ )
> {
> if( strcmp( argv[ pos ], "--help" ) == 0 )
> showHelp( 0 );
> else if( strcmp( argv[ pos ], "--pipe" ) == 0 )
> {
> readStdin = true;
> numOptions++;
> }
> else if( strcmp( argv[ pos ], "--user" ) == 0 )
> {
> if( pos <= argc - 2 )
> {
> user = QString::fromLocal8Bit( argv[ pos + 1] );
> numOptions +=2;
> pos++;
> }
> else
> {
> cerr << "Missing username for '--user' option!" << endl << endl;
> showHelp( -1 );
> }
> }
> else if( strcmp( argv[ pos ], "--all-users" ) == 0 )
> {
> user = "*";
> numOptions ++;
> }
> else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 )
> {
> session = QuerySessions;
> numOptions ++;
> }
> else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 )
> {
> session = AllSessions;
> numOptions ++;
> }
> else if( argv[ pos ][ 0 ] == '-' )
> {
> cerr << "Unknown command-line option '" << argv[ pos ]
> << "'." << endl << endl;
> showHelp( -1 );
> }
> else
> break; // End of options
> }
>
> argc -= numOptions;
>
> QCStringList args;
> for( int i = numOptions; i < argc + numOptions - 1; i++ )
> args.append( argv[ i + 1 ] );
>
> if( readStdin && args.count() < 3 )
> {
> cerr << "--pipe option only supported for function calls!" << endl << endl;
> showHelp( -1 );
> }
>
> if( user == "*" && args.count() < 3 && session != QuerySessions )
> {
> cerr << "ERROR: The --all-users option is only supported for function calls!" << endl << endl;
> showHelp( -1 );
> }
>
> if( session == QuerySessions && !args.isEmpty() )
> {
> cerr << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl;
> showHelp( -1 );
> }
>
> if( session == QuerySessions && user.isEmpty() )
> {
> cerr << "ERROR: The --list-sessions option can only be used with the --user or" << endl
> << "--all-users options!" << endl << endl;
> showHelp( -1 );
> }
>
> if( session != DefaultSession && session != QuerySessions &&
> args.count() < 3 )
> {
> cerr << "ERROR: The --session and --all-sessions options are only supported for function" << endl
> << "calls!" << endl << endl;
> showHelp( -1 );
> }
>
> UserList users;
> if( user == "*" )
> users = userList();
> else if( !user.isEmpty() )
> users[ user ] = userList()[ user ];
>
> runDCOP( args, users, session, sessionName, readStdin );
343a771,773
>
> // vim: set ts=8 sts=4 sw=4 noet:
>
diff -r dcop/client/dcopfind.cpp dcop2/client/dcopfind.cpp
39c39
< bool findObject( const char* app, const char* obj, const char* func, int argc, char** args )
---
> bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
121c121
< if ( (int) types.count() != argc ) {
---
> if ( types.count() != args.count() ) {
131c131
< marshall(arg, argc, args, i, *it);
---
> marshall(arg, args, i, *it);
133c133
< if ( (int) i != argc ) {
---
> if ( (uint) i != args.count() ) {
224c224,228
< findObject( app, objid, function, argc, args );
---
> QCStringList params;
> for( int i = 0; i < argc; i++ )
> params.append( args[ i ] );
>
> findObject( app, objid, function, params );
diff -r dcop/client/marshall.cpp dcop2/client/marshall.cpp
245c245
< void marshall(QDataStream &arg, int argc, char **argv, int &i, QString type)
---
> void marshall( QDataStream &arg, QCStringList args, uint &i, QString type )
247,317c247,256
< if (type == "QStringList")
< type = "QValueList<QString>";
< if (type == "QCStringList")
< type = "QValueList<QCString>";
< if (i >= argc)
< {
< qWarning("Not enough arguments.");
< exit(1);
< }
< QString s = QString::fromLocal8Bit(argv[i]);
<
< if ( type == "int" )
< arg << s.toInt();
< else if ( type == "uint" )
< arg << s.toUInt();
< else if ( type == "unsigned" )
< arg << s.toUInt();
< else if ( type == "unsigned int" )
< arg << s.toUInt();
< else if ( type == "long" )
< arg << s.toLong();
< else if ( type == "long int" )
< arg << s.toLong();
< else if ( type == "unsigned long" )
< arg << s.toULong();
< else if ( type == "unsigned long int" )
< arg << s.toULong();
< else if ( type == "float" )
< arg << s.toFloat();
< else if ( type == "double" )
< arg << s.toDouble();
< else if ( type == "bool" )
< arg << mkBool( s );
< else if ( type == "QString" )
< arg << s;
< else if ( type == "QCString" )
< arg << QCString( argv[i] );
< else if ( type == "QColor" )
< arg << mkColor( s );
< else if ( type == "QPoint" )
< arg << mkPoint( s );
< else if ( type == "QSize" )
< arg << mkSize( s );
< else if ( type == "QRect" )
< arg << mkRect( s );
< else if ( type == "QVariant" ) {
< if ( s == "true" || s == "false" )
< arg << QVariant( mkBool( s ), 42 );
< else if ( s.left( 4 ) == "int(" )
< arg << QVariant( s.mid(4, s.length()-5).toInt() );
< else if ( s.left( 7 ) == "QPoint(" )
< arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
< else if ( s.left( 6 ) == "QSize(" )
< arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
< else if ( s.left( 6 ) == "QRect(" )
< arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
< else if ( s.left( 7 ) == "QColor(" )
< arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
< else
< arg << QVariant( s );
< } else if ( type.startsWith("QValueList<")) {
< type = type.mid(11, type.length() - 12);
< QStringList list;
< QString delim = s;
< if (delim == "[")
< delim = "]";
< if (delim == "(")
< delim = ")";
< i++;
< QByteArray dummy_data;
< QDataStream dummy_arg(dummy_data, IO_WriteOnly);
---
> if (type == "QStringList")
> type = "QValueList<QString>";
> if (type == "QCStringList")
> type = "QValueList<QCString>";
> if( i > args.count() )
> {
> qWarning("Not enough arguments.");
> exit(1);
> }
> QString s = QString::fromLocal8Bit( args[ i ] );
319,346c258,314
< int j = i;
< int count = 0;
< // Parse list to get the count
< while (true) {
< if (j >= argc)
< {
< qWarning("List end-delimiter '%s' not found.", delim.latin1());
< exit(1);
< }
< if (argv[j] == delim) break;
< marshall(dummy_arg, argc, argv, j, type);
< count++;
< }
< arg << (Q_UINT32) count;
< // Parse the list for real
< while (true) {
< if (i >= argc)
< {
< qWarning("List end-delimiter '%s' not found.", delim.latin1());
< exit(1);
< }
< if (argv[i] == delim) break;
< marshall(arg, argc, argv, i, type);
< }
< } else {
< qWarning( "cannot handle datatype '%s'", type.latin1() );
< exit(1);
< }
---
> if ( type == "int" )
> arg << s.toInt();
> else if ( type == "uint" )
> arg << s.toUInt();
> else if ( type == "unsigned" )
> arg << s.toUInt();
> else if ( type == "unsigned int" )
> arg << s.toUInt();
> else if ( type == "long" )
> arg << s.toLong();
> else if ( type == "long int" )
> arg << s.toLong();
> else if ( type == "unsigned long" )
> arg << s.toULong();
> else if ( type == "unsigned long int" )
> arg << s.toULong();
> else if ( type == "float" )
> arg << s.toFloat();
> else if ( type == "double" )
> arg << s.toDouble();
> else if ( type == "bool" )
> arg << mkBool( s );
> else if ( type == "QString" )
> arg << s;
> else if ( type == "QCString" )
> arg << QCString( args[ i ] );
> else if ( type == "QColor" )
> arg << mkColor( s );
> else if ( type == "QPoint" )
> arg << mkPoint( s );
> else if ( type == "QSize" )
> arg << mkSize( s );
> else if ( type == "QRect" )
> arg << mkRect( s );
> else if ( type == "QVariant" ) {
> if ( s == "true" || s == "false" )
> arg << QVariant( mkBool( s ), 42 );
> else if ( s.left( 4 ) == "int(" )
> arg << QVariant( s.mid(4, s.length()-5).toInt() );
> else if ( s.left( 7 ) == "QPoint(" )
> arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
> else if ( s.left( 6 ) == "QSize(" )
> arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
> else if ( s.left( 6 ) == "QRect(" )
> arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
> else if ( s.left( 7 ) == "QColor(" )
> arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
> else
> arg << QVariant( s );
> } else if ( type.startsWith("QValueList<")) {
> type = type.mid(11, type.length() - 12);
> QStringList list;
> QString delim = s;
> if (delim == "[")
> delim = "]";
> if (delim == "(")
> delim = ")";
347a316,349
> QByteArray dummy_data;
> QDataStream dummy_arg(dummy_data, IO_WriteOnly);
>
> uint j = i;
> uint count = 0;
> // Parse list to get the count
> while (true) {
> if( j > args.count() )
> {
> qWarning("List end-delimiter '%s' not found.", delim.latin1());
> exit(1);
> }
> if( QString::fromLocal8Bit( args[ j ] ) == delim )
> break;
> marshall( dummy_arg, args, j, type );
> count++;
> }
> arg << (Q_UINT32) count;
> // Parse the list for real
> while (true) {
> if( i > args.count() )
> {
> qWarning("List end-delimiter '%s' not found.", delim.latin1());
> exit(1);
> }
> if( QString::fromLocal8Bit( args[ i ] ) == delim )
> break;
> marshall( arg, args, i, type );
> }
> } else {
> qWarning( "cannot handle datatype '%s'", type.latin1() );
> exit(1);
> }
> i++;

View file

@ -0,0 +1,9 @@
d1 2
d4 1
a4 2
The named is the mother of all things.
a11 3
They both may be called deep and profound.
Deeper and more profound,
The door of all subtleties!

View file

@ -0,0 +1,671 @@
diff -nr dcop/client/dcop.cpp dcop2/client/dcop.cpp
d23 1
a23 4
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
d25 1
a25 12
#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qmap.h>
#include <qstringlist.h>
#include <qtextstream.h>
#include <qvariant.h>
// putenv() is not available on all platforms, so make sure the emulation
// wrapper is available in those cases by loading config.h!
#include <config.h>
d28 3
a30 1
#include "../kdatastream.h"
a33 2
typedef QMap<QString, QString> UserList;
a35 14
static QTextStream cout( stdout, IO_WriteOnly );
static QTextStream cerr( stderr, IO_WriteOnly );
/**
* Session to send call to
* DefaultSession - current session. Current KDE session when called without
* --user or --all-users option. Otherwise this value ignores
* all users with more than one active session.
* AllSessions - Send to all sessions found. requires --user or --all-users.
* QuerySessions - Don't call DCOP, return a list of available sessions.
* CustomSession - Use the specified session
*/
enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
d121 1
a121 1
void callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
d123 1
d139 1
a139 1
if ( !ok && args.isEmpty() )
d156 2
a157 2
uint a = (*it).contains(',');
if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
d164 1
a164 2
// exit(1);
return;
d246 5
a250 6
uint i = 0;
for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
marshall( arg, args, i, *it );
if ( i != args.count() )
{
a268 27
/**
* Show command-line help and exit
*/
void showHelp( int exitCode = 0 )
{
cout << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl
<< "" << endl
<< "Console DCOP client" << endl
<< "" << endl
<< "Generic options:" << endl
<< " --help Show help about options" << endl
<< "" << endl
<< "Options:" << endl
<< " --pipe Call DCOP for each line read from stdin" << endl
<< " --user <user> Connect to the given user's DCOP server. This option will" << endl
<< " ignore the values of the environment vars $DCOPSERVER and" << endl
<< " $ICEAUTHORITY, even if they are set." << endl
<< " If the user has more than one open session, you must also" << endl
<< " use one of the --list-sessions, --session or --als-sessions" << endl
<< " command-line options." << endl
<< " --all-users Send the same DCOP call to all users with a running DCOP" << endl
<< " server. Only failed calls to existing DCOP servers will"
<< " generate an error message. If no DCOP server is available" << endl
<< " at all, no error will be generated." << endl;
exit( exitCode );
}
d270 2
a271 5
/**
* Return a list of all users and their home directories.
* Returns an empty list if /etc/passwd cannot be read for some reason.
*/
static UserList userList()
a272 9
UserList result;
QFile f( "/etc/passwd" );
if( !f.open( IO_ReadOnly ) )
{
cerr << "Can't open /etc/passwd for reading!" << endl;
return result;
}
d274 3
a276 6
QStringList l( QStringList::split( '\n', f.readAll() ) );
for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it )
{
QStringList userInfo( QStringList::split( ':', *it, true ) );
result[ userInfo[ 0 ] ] = userInfo[ 5 ];
d279 3
a281 42
return result;
}
/**
* Return a list of available DCOP sessions for the specified user
* An empty list means no sessions are available, or an error occurred.
*/
QStringList dcopSessionList( const QString &user, const QString &home )
{
if( home.isEmpty() )
{
cerr << "WARNING: Cannot determine home directory for user "
<< user << "!" << endl
<< "Please check permissions or set the $DCOPSERVER variable manually before" << endl
<< "calling dcop." << endl;
return QStringList();
}
QStringList result;
QFileInfo dirInfo( home );
if( !dirInfo.exists() || !dirInfo.isReadable() )
return result;
QDir d( home );
d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
d.setNameFilter( ".DCOPserver*" );
const QFileInfoList *list = d.entryInfoList();
if( !list )
return result;
QFileInfoListIterator it( *list );
QFileInfo *fi;
while ( ( fi = it.current() ) != 0 )
{
if( fi->isReadable() )
result.append( fi->fileName() );
++it;
}
return result;
}
a282 6
/**
* Do the actual DCOP call
*/
void runDCOP( QCStringList args, UserList users, Session session,
const QString sessionName, bool readStdin )
{
d286 2
a287 3
QCStringList params;
DCOPClient *client = 0L;
if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
d289 16
a304 24
// WARNING: This part (until the closing '}') could very
// well be broken now. As I don't know how to trigger and test
// dcoprefs this code is *not* tested. It compiles and it looks
// ok to me, but that's all I can say - Martijn (2001/12/24)
int delimPos = args[ 0 ].findRev( ',' );
if( delimPos == -1 )
{
cerr << "Error: '" << args[ 0 ]
<< "' is not a valid DCOP reference." << endl;
exit( -1 );
}
args[ 0 ][ delimPos ] = 0;
app = args[ 0 ].mid( 8 );
delimPos++;
args[ 0 ][ args[ 0 ].length() - 1 ] = 0;
objid = args[ 0 ].mid( delimPos );
if( args.count() > 1 )
function = args[ 1 ];
if( args.count() > 2 )
{
params = args;
params.remove( params.begin() );
params.remove( params.begin() );
}
d308 31
a338 84
if( !args.isEmpty() )
app = args[ 0 ];
if( args.count() > 1 )
objid = args[ 1 ];
if( args.count() > 2 )
function = args[ 2 ];
if( args.count() > 3)
{
params = args;
params.remove( params.begin() );
params.remove( params.begin() );
params.remove( params.begin() );
}
}
bool firstRun = true;
UserList::Iterator it;
QStringList sessions;
bool presetDCOPServer = false;
// char *dcopStr = 0L;
QString dcopServer;
for( it = users.begin(); it != users.end() || firstRun; it++ )
{
firstRun = false;
//cout << "Iterating '" << it.key() << "'" << endl;
if( session == QuerySessions )
{
QStringList sessions = dcopSessionList( it.key(), it.data() );
if( sessions.isEmpty() )
{
cout << "No active sessions";
if( !( *it ).isEmpty() )
cout << " for user " << *it;
cout << endl;
}
else
{
cout << "Active sessions ";
if( !( *it ).isEmpty() )
cout << "for user " << *it << " ";
cout << ":" << endl;
QStringList::Iterator sIt;
for( sIt = sessions.begin(); sIt != sessions.end(); sIt++ )
cout << " " << *sIt << endl;
cout << endl;
}
continue;
}
if( getenv( "DCOPSERVER" ) )
{
sessions.append( getenv( "DCOPSERVER" ) );
presetDCOPServer = true;
}
if( users.count() > 1 || ( users.count() == 1 &&
( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) )
{
sessions = dcopSessionList( it.key(), it.data() );
if( sessions.isEmpty() )
{
if( users.count() > 1 )
continue;
else
{
cerr << "ERROR: No active KDE sessions!" << endl
<< "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
<< "before calling dcop." << endl;
exit( -1 );
}
}
else if( sessions.count() > 1 && session != AllSessions )
{
cerr << "ERROR: Multiple available KDE sessions!" << endl
<< "Please specify the correct session to use with --session or use the" << endl
<< "--all-sessions option to broadcast to all sessions." << endl;
exit( -1 );
}
}
a339 143
if( users.count() > 1 || ( users.count() == 1 &&
( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) )
{
// Check for ICE authority file and if the file can be read by us
QString home = it.data();
QString iceFile = it.data() + "/.ICEauthority";
QFileInfo fi( iceFile );
if( iceFile.isEmpty() )
{
cerr << "WARNING: Cannot determine home directory for user "
<< it.key() << "!" << endl
<< "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
<< "calling dcop." << endl;
}
else if( fi.exists() )
{
if( fi.isReadable() )
{
char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() );
putenv( envStr );
//cerr << "ice: " << envStr << endl;
}
else
{
cerr << "WARNING: ICE authority file " << iceFile
<< "is not readable by you!" << endl
<< "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
<< "calling dcop." << endl;
}
}
else
{
if( users.count() > 1 )
continue;
else
{
cerr << "WARNING: Cannot find ICE authority file "
<< iceFile << "!" << endl
<< "Please check permissions or set the $ICEAUTHORITY"
<< " variable manually before" << endl
<< "calling dcop." << endl;
}
}
}
// Main loop
// If users is an empty list we're calling for the currently logged
// in user. In this case we don't have a session, but still want
// to iterate the loop once.
QStringList::Iterator sIt = sessions.begin();
for( ; sIt != sessions.end() || users.isEmpty(); sIt++ )
{
if( !presetDCOPServer && !users.isEmpty() )
{
QString dcopFile = it.data() + "/" + *sIt;
QFile f( dcopFile );
if( !f.open( IO_ReadOnly ) )
{
cerr << "Can't open " << dcopFile << " for reading!" << endl;
exit( -1 );
}
QStringList l( QStringList::split( '\n', f.readAll() ) );
dcopServer = l.first();
if( dcopServer.isEmpty() )
{
cerr << "WARNING: Unable to determine DCOP server for session "
<< *sIt << "!" << endl
<< "Please check permissions or set the $DCOPSERVER variable manually before" << endl
<< "calling dcop." << endl;
exit( -1 );
}
}
delete client;
client = new DCOPClient;
if( !dcopServer.isEmpty() )
client->setServerAddress( dcopServer.ascii() );
bool success = client->attach();
if( !success )
{
cerr << "ERROR: Couldn't attach to DCOP server!" << endl;
continue;
}
dcop = client;
switch ( args.count() )
{
case 0:
queryApplications("");
break;
case 1:
if (endsWith(app, '*'))
queryApplications(app);
else
queryObjects( app, "" );
break;
case 2:
if (endsWith(objid, '*'))
queryObjects(app, objid);
else
queryFunctions( app, objid );
break;
case 3:
default:
if( readStdin )
{
QCStringList::Iterator replaceArg = args.end();
QCStringList::Iterator it;
for( it = args.begin(); it != args.end(); it++ )
if( *it == "%1" )
replaceArg = it;
// Read from stdin until EOF and call function for each line read
char *buf = new char[ 1000 ];
while ( !feof( stdin ) )
{
fgets( buf, 1000, stdin );
if( replaceArg != args.end() )
*replaceArg = buf;
callFunction( app, objid, function, params );
}
}
else
{
// Just call function
// cout << "call " << app << ", " << objid << ", " << function << ", (params)" << endl;
callFunction( app, objid, function, params );
}
break;
}
// Another sIt++ would make the loop infinite...
if( users.isEmpty() )
break;
}
// Another it++ would make the loop infinite...
if( it == users.end() )
break;
a340 106
}
int main( int argc, char** argv )
{
bool readStdin = false;
int numOptions = 0;
QString user;
Session session = DefaultSession;
QString sessionName;
// Scan for command-line options first
for( int pos = 1 ; pos <= argc - 1 ; pos++ )
{
if( strcmp( argv[ pos ], "--help" ) == 0 )
showHelp( 0 );
else if( strcmp( argv[ pos ], "--pipe" ) == 0 )
{
readStdin = true;
numOptions++;
}
else if( strcmp( argv[ pos ], "--user" ) == 0 )
{
if( pos <= argc - 2 )
{
user = QString::fromLocal8Bit( argv[ pos + 1] );
numOptions +=2;
pos++;
}
else
{
cerr << "Missing username for '--user' option!" << endl << endl;
showHelp( -1 );
}
}
else if( strcmp( argv[ pos ], "--all-users" ) == 0 )
{
user = "*";
numOptions ++;
}
else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 )
{
session = QuerySessions;
numOptions ++;
}
else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 )
{
session = AllSessions;
numOptions ++;
}
else if( argv[ pos ][ 0 ] == '-' )
{
cerr << "Unknown command-line option '" << argv[ pos ]
<< "'." << endl << endl;
showHelp( -1 );
}
else
break; // End of options
}
argc -= numOptions;
QCStringList args;
for( int i = numOptions; i < argc + numOptions - 1; i++ )
args.append( argv[ i + 1 ] );
if( readStdin && args.count() < 3 )
{
cerr << "--pipe option only supported for function calls!" << endl << endl;
showHelp( -1 );
}
if( user == "*" && args.count() < 3 && session != QuerySessions )
{
cerr << "ERROR: The --all-users option is only supported for function calls!" << endl << endl;
showHelp( -1 );
}
if( session == QuerySessions && !args.isEmpty() )
{
cerr << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl;
showHelp( -1 );
}
if( session == QuerySessions && user.isEmpty() )
{
cerr << "ERROR: The --list-sessions option can only be used with the --user or" << endl
<< "--all-users options!" << endl << endl;
showHelp( -1 );
}
if( session != DefaultSession && session != QuerySessions &&
args.count() < 3 )
{
cerr << "ERROR: The --session and --all-sessions options are only supported for function" << endl
<< "calls!" << endl << endl;
showHelp( -1 );
}
UserList users;
if( user == "*" )
users = userList();
else if( !user.isEmpty() )
users[ user ] = userList()[ user ];
runDCOP( args, users, session, sessionName, readStdin );
a343 3
// vim: set ts=8 sts=4 sw=4 noet:
diff -nr dcop/client/dcopfind.cpp dcop2/client/dcopfind.cpp
d39 1
a39 1
bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
d121 1
a121 1
if ( types.count() != args.count() ) {
d131 1
a131 1
marshall(arg, args, i, *it);
d133 1
a133 1
if ( (uint) i != args.count() ) {
d224 1
a224 5
QCStringList params;
for( int i = 0; i < argc; i++ )
params.append( args[ i ] );
findObject( app, objid, function, params );
diff -nr dcop/client/marshall.cpp dcop2/client/marshall.cpp
d245 1
a245 1
void marshall( QDataStream &arg, QCStringList args, uint &i, QString type )
d247 71
a317 10
if (type == "QStringList")
type = "QValueList<QString>";
if (type == "QCStringList")
type = "QValueList<QCString>";
if( i > args.count() )
{
qWarning("Not enough arguments.");
exit(1);
}
QString s = QString::fromLocal8Bit( args[ i ] );
d319 28
a346 57
if ( type == "int" )
arg << s.toInt();
else if ( type == "uint" )
arg << s.toUInt();
else if ( type == "unsigned" )
arg << s.toUInt();
else if ( type == "unsigned int" )
arg << s.toUInt();
else if ( type == "long" )
arg << s.toLong();
else if ( type == "long int" )
arg << s.toLong();
else if ( type == "unsigned long" )
arg << s.toULong();
else if ( type == "unsigned long int" )
arg << s.toULong();
else if ( type == "float" )
arg << s.toFloat();
else if ( type == "double" )
arg << s.toDouble();
else if ( type == "bool" )
arg << mkBool( s );
else if ( type == "QString" )
arg << s;
else if ( type == "QCString" )
arg << QCString( args[ i ] );
else if ( type == "QColor" )
arg << mkColor( s );
else if ( type == "QPoint" )
arg << mkPoint( s );
else if ( type == "QSize" )
arg << mkSize( s );
else if ( type == "QRect" )
arg << mkRect( s );
else if ( type == "QVariant" ) {
if ( s == "true" || s == "false" )
arg << QVariant( mkBool( s ), 42 );
else if ( s.left( 4 ) == "int(" )
arg << QVariant( s.mid(4, s.length()-5).toInt() );
else if ( s.left( 7 ) == "QPoint(" )
arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
else if ( s.left( 6 ) == "QSize(" )
arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
else if ( s.left( 6 ) == "QRect(" )
arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
else if ( s.left( 7 ) == "QColor(" )
arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
else
arg << QVariant( s );
} else if ( type.startsWith("QValueList<")) {
type = type.mid(11, type.length() - 12);
QStringList list;
QString delim = s;
if (delim == "[")
delim = "]";
if (delim == "(")
delim = ")";
a347 34
QByteArray dummy_data;
QDataStream dummy_arg(dummy_data, IO_WriteOnly);
uint j = i;
uint count = 0;
// Parse list to get the count
while (true) {
if( j > args.count() )
{
qWarning("List end-delimiter '%s' not found.", delim.latin1());
exit(1);
}
if( QString::fromLocal8Bit( args[ j ] ) == delim )
break;
marshall( dummy_arg, args, j, type );
count++;
}
arg << (Q_UINT32) count;
// Parse the list for real
while (true) {
if( i > args.count() )
{
qWarning("List end-delimiter '%s' not found.", delim.latin1());
exit(1);
}
if( QString::fromLocal8Bit( args[ i ] ) == delim )
break;
marshall( arg, args, i, type );
}
} else {
qWarning( "cannot handle datatype '%s'", type.latin1() );
exit(1);
}
i++;

View file

@ -0,0 +1,19 @@
--- /home/John/lao Thu Apr 12 11:09:30 2001
+++ /home/John/tzu Sat Jul 28 13:23:25 2001
@@ -1,7 +1,6 @@
-The Way that can be told of is not the eternal Way;
-The name that can be named is not the eternal name.
The Nameless is the origin of Heaven and Earth;
-The Named is the mother of all things.
+The named is the mother of all things.
+
Therefore let there always be non-being,
so we may see their subtlety,
And let there always be being,
@@ -9,3 +8,6 @@
The two are the same,
But after they are produced,
they have different names.
+They both may be called deep and profound.
+Deeper and more profound,
+The door of all subtleties!

View file

@ -0,0 +1,911 @@
diff -aur dcop/client/dcop.cpp dcop2/client/dcop.cpp
--- dcop/client/dcop.cpp Wed Jan 30 22:38:07 2002
+++ dcop2/client/dcop.cpp Wed Jan 30 22:37:04 2002
@@ -20,19 +20,47 @@
******************************************************************/
-#include <qvariant.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+
#include <qcolor.h>
-#include "../kdatastream.h"
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qmap.h>
+#include <qstringlist.h>
+#include <qtextstream.h>
+#include <qvariant.h>
+
+// putenv() is not available on all platforms, so make sure the emulation
+// wrapper is available in those cases by loading config.h!
+#include <config.h>
+
#include "../dcopclient.h"
#include "../dcopref.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
+#include "../kdatastream.h"
#include "marshall.cpp"
+typedef QMap<QString, QString> UserList;
+
static DCOPClient* dcop = 0;
+static QTextStream cout( stdout, IO_WriteOnly );
+static QTextStream cerr( stderr, IO_WriteOnly );
+
+/**
+ * Session to send call to
+ * DefaultSession - current session. Current KDE session when called without
+ * --user or --all-users option. Otherwise this value ignores
+ * all users with more than one active session.
+ * AllSessions - Send to all sessions found. requires --user or --all-users.
+ * QuerySessions - Don't call DCOP, return a list of available sessions.
+ * CustomSession - Use the specified session
+ */
+enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
+
bool startsWith(const QCString &id, const char *str, int n)
{
return !n || (strncmp(id.data(), str, n) == 0);
@@ -118,9 +146,8 @@
}
}
-void callFunction( const char* app, const char* obj, const char* func, int argc, char** args )
+void callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
{
-
QString f = func; // Qt is better with unicode strings, so use one.
int left = f.find( '(' );
int right = f.find( ')' );
@@ -136,7 +163,7 @@
bool ok = false;
QCStringList funcs = dcop->remoteFunctions( app, obj, &ok );
QCString realfunc;
- if ( !ok && argc == 0 )
+ if ( !ok && args.isEmpty() )
goto doit;
if ( !ok )
{
@@ -153,15 +180,16 @@
if ( l > 0 && (*it).mid( s, l - s ) == func ) {
realfunc = (*it).mid( s );
- int a = (*it).contains(',');
- if ( ( a == 0 && argc == 0) || ( a > 0 && a + 1 == argc ) )
+ uint a = (*it).contains(',');
+ if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
break;
}
}
if ( realfunc.isEmpty() )
{
qWarning("no such function");
- exit(1);
+// exit(1);
+ return;
}
f = realfunc;
left = f.find( '(' );
@@ -243,11 +271,12 @@
QCString replyType;
QDataStream arg(data, IO_WriteOnly);
- int i = 0;
- for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
- marshall(arg, argc, args, i, *it);
- }
- if ( i != argc ) {
+ uint i = 0;
+ for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
+ marshall( arg, args, i, *it );
+
+ if ( i != args.count() )
+ {
qWarning( "arguments do not match" );
exit(1);
}
@@ -266,78 +295,479 @@
}
}
+/**
+ * Show command-line help and exit
+ */
+void showHelp( int exitCode = 0 )
+{
+ cout << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl
+ << "" << endl
+ << "Console DCOP client" << endl
+ << "" << endl
+ << "Generic options:" << endl
+ << " --help Show help about options" << endl
+ << "" << endl
+ << "Options:" << endl
+ << " --pipe Call DCOP for each line read from stdin" << endl
+ << " --user <user> Connect to the given user's DCOP server. This option will" << endl
+ << " ignore the values of the environment vars $DCOPSERVER and" << endl
+ << " $ICEAUTHORITY, even if they are set." << endl
+ << " If the user has more than one open session, you must also" << endl
+ << " use one of the --list-sessions, --session or --als-sessions" << endl
+ << " command-line options." << endl
+ << " --all-users Send the same DCOP call to all users with a running DCOP" << endl
+ << " server. Only failed calls to existing DCOP servers will"
+ << " generate an error message. If no DCOP server is available" << endl
+ << " at all, no error will be generated." << endl;
+
+ exit( exitCode );
+}
-
-int main( int argc, char** argv )
+/**
+ * Return a list of all users and their home directories.
+ * Returns an empty list if /etc/passwd cannot be read for some reason.
+ */
+static UserList userList()
{
+ UserList result;
+
+ QFile f( "/etc/passwd" );
+
+ if( !f.open( IO_ReadOnly ) )
+ {
+ cerr << "Can't open /etc/passwd for reading!" << endl;
+ return result;
+ }
- if ( argc > 1 && argv[1][0] == '-' ) {
- fprintf( stderr, "Usage: dcop [ application [object [function [arg1] [arg2] [arg3] ... ] ] ] \n" );
- exit(0);
+ QStringList l( QStringList::split( '\n', f.readAll() ) );
+
+ for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it )
+ {
+ QStringList userInfo( QStringList::split( ':', *it, true ) );
+ result[ userInfo[ 0 ] ] = userInfo[ 5 ];
}
- DCOPClient client;
- client.attach();
- dcop = &client;
+ return result;
+}
+
+/**
+ * Return a list of available DCOP sessions for the specified user
+ * An empty list means no sessions are available, or an error occurred.
+ */
+QStringList dcopSessionList( const QString &user, const QString &home )
+{
+ if( home.isEmpty() )
+ {
+ cerr << "WARNING: Cannot determine home directory for user "
+ << user << "!" << endl
+ << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
+ << "calling dcop." << endl;
+ return QStringList();
+ }
+
+ QStringList result;
+ QFileInfo dirInfo( home );
+ if( !dirInfo.exists() || !dirInfo.isReadable() )
+ return result;
+
+ QDir d( home );
+ d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
+ d.setNameFilter( ".DCOPserver*" );
+
+ const QFileInfoList *list = d.entryInfoList();
+ if( !list )
+ return result;
+
+ QFileInfoListIterator it( *list );
+ QFileInfo *fi;
+
+ while ( ( fi = it.current() ) != 0 )
+ {
+ if( fi->isReadable() )
+ result.append( fi->fileName() );
+ ++it;
+ }
+ return result;
+}
+/**
+ * Do the actual DCOP call
+ */
+void runDCOP( QCStringList args, UserList users, Session session,
+ const QString sessionName, bool readStdin )
+{
QCString app;
QCString objid;
QCString function;
- char **args = 0;
- if ((argc > 1) && (strncmp(argv[1], "DCOPRef(", 8)) == 0)
+ QCStringList params;
+ DCOPClient *client = 0L;
+ if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
{
- char *delim = strchr(argv[1], ',');
- if (!delim)
- {
- fprintf(stderr, "Error: '%s' is not a valid DCOP reference.\n", argv[1]);
- return 1;
- }
- *delim = 0;
- app = argv[1] + 8;
- delim++;
- delim[strlen(delim)-1] = 0;
- objid = delim;
- if (argc > 2)
- function = argv[2];
- if (argc > 3)
- args = &argv[3];
- argc++;
+ // WARNING: This part (until the closing '}') could very
+ // well be broken now. As I don't know how to trigger and test
+ // dcoprefs this code is *not* tested. It compiles and it looks
+ // ok to me, but that's all I can say - Martijn (2001/12/24)
+ int delimPos = args[ 0 ].findRev( ',' );
+ if( delimPos == -1 )
+ {
+ cerr << "Error: '" << args[ 0 ]
+ << "' is not a valid DCOP reference." << endl;
+ exit( -1 );
+ }
+ args[ 0 ][ delimPos ] = 0;
+ app = args[ 0 ].mid( 8 );
+ delimPos++;
+ args[ 0 ][ args[ 0 ].length() - 1 ] = 0;
+ objid = args[ 0 ].mid( delimPos );
+ if( args.count() > 1 )
+ function = args[ 1 ];
+ if( args.count() > 2 )
+ {
+ params = args;
+ params.remove( params.begin() );
+ params.remove( params.begin() );
+ }
}
else
{
- if (argc > 1)
- app = argv[1];
- if (argc > 2)
- objid = argv[2];
- if (argc > 3)
- function = argv[3];
- if (argc > 4)
- args = &argv[4];
- }
-
- switch ( argc ) {
- case 0:
- case 1:
- queryApplications("");
- break;
- case 2:
- if (endsWith(app, '*'))
- queryApplications(app);
- else
- queryObjects( app, "" );
- break;
- case 3:
- if (endsWith(objid, '*'))
- queryObjects(app, objid);
- else
- queryFunctions( app, objid );
- break;
- case 4:
- default:
- callFunction( app, objid, function, argc - 4, args );
- break;
+ if( !args.isEmpty() )
+ app = args[ 0 ];
+ if( args.count() > 1 )
+ objid = args[ 1 ];
+ if( args.count() > 2 )
+ function = args[ 2 ];
+ if( args.count() > 3)
+ {
+ params = args;
+ params.remove( params.begin() );
+ params.remove( params.begin() );
+ params.remove( params.begin() );
+ }
+ }
+
+ bool firstRun = true;
+ UserList::Iterator it;
+ QStringList sessions;
+ bool presetDCOPServer = false;
+// char *dcopStr = 0L;
+ QString dcopServer;
+
+ for( it = users.begin(); it != users.end() || firstRun; it++ )
+ {
+ firstRun = false;
+
+ //cout << "Iterating '" << it.key() << "'" << endl;
+
+ if( session == QuerySessions )
+ {
+ QStringList sessions = dcopSessionList( it.key(), it.data() );
+ if( sessions.isEmpty() )
+ {
+ cout << "No active sessions";
+ if( !( *it ).isEmpty() )
+ cout << " for user " << *it;
+ cout << endl;
+ }
+ else
+ {
+ cout << "Active sessions ";
+ if( !( *it ).isEmpty() )
+ cout << "for user " << *it << " ";
+ cout << ":" << endl;
+
+ QStringList::Iterator sIt;
+ for( sIt = sessions.begin(); sIt != sessions.end(); sIt++ )
+ cout << " " << *sIt << endl;
+
+ cout << endl;
+ }
+ continue;
+ }
+
+ if( getenv( "DCOPSERVER" ) )
+ {
+ sessions.append( getenv( "DCOPSERVER" ) );
+ presetDCOPServer = true;
+ }
+
+ if( users.count() > 1 || ( users.count() == 1 &&
+ ( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) )
+ {
+ sessions = dcopSessionList( it.key(), it.data() );
+ if( sessions.isEmpty() )
+ {
+ if( users.count() > 1 )
+ continue;
+ else
+ {
+ cerr << "ERROR: No active KDE sessions!" << endl
+ << "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
+ << "before calling dcop." << endl;
+ exit( -1 );
+ }
+ }
+ else if( sessions.count() > 1 && session != AllSessions )
+ {
+ cerr << "ERROR: Multiple available KDE sessions!" << endl
+ << "Please specify the correct session to use with --session or use the" << endl
+ << "--all-sessions option to broadcast to all sessions." << endl;
+ exit( -1 );
+ }
+ }
+ if( users.count() > 1 || ( users.count() == 1 &&
+ ( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) )
+ {
+ // Check for ICE authority file and if the file can be read by us
+ QString home = it.data();
+ QString iceFile = it.data() + "/.ICEauthority";
+ QFileInfo fi( iceFile );
+ if( iceFile.isEmpty() )
+ {
+ cerr << "WARNING: Cannot determine home directory for user "
+ << it.key() << "!" << endl
+ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
+ << "calling dcop." << endl;
+ }
+ else if( fi.exists() )
+ {
+ if( fi.isReadable() )
+ {
+ char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() );
+ putenv( envStr );
+ //cerr << "ice: " << envStr << endl;
+ }
+ else
+ {
+ cerr << "WARNING: ICE authority file " << iceFile
+ << "is not readable by you!" << endl
+ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
+ << "calling dcop." << endl;
+ }
+ }
+ else
+ {
+ if( users.count() > 1 )
+ continue;
+ else
+ {
+ cerr << "WARNING: Cannot find ICE authority file "
+ << iceFile << "!" << endl
+ << "Please check permissions or set the $ICEAUTHORITY"
+ << " variable manually before" << endl
+ << "calling dcop." << endl;
+ }
+ }
+ }
+
+ // Main loop
+ // If users is an empty list we're calling for the currently logged
+ // in user. In this case we don't have a session, but still want
+ // to iterate the loop once.
+ QStringList::Iterator sIt = sessions.begin();
+ for( ; sIt != sessions.end() || users.isEmpty(); sIt++ )
+ {
+ if( !presetDCOPServer && !users.isEmpty() )
+ {
+ QString dcopFile = it.data() + "/" + *sIt;
+ QFile f( dcopFile );
+ if( !f.open( IO_ReadOnly ) )
+ {
+ cerr << "Can't open " << dcopFile << " for reading!" << endl;
+ exit( -1 );
+ }
+
+ QStringList l( QStringList::split( '\n', f.readAll() ) );
+ dcopServer = l.first();
+
+ if( dcopServer.isEmpty() )
+ {
+ cerr << "WARNING: Unable to determine DCOP server for session "
+ << *sIt << "!" << endl
+ << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
+ << "calling dcop." << endl;
+ exit( -1 );
+ }
+ }
+
+ delete client;
+ client = new DCOPClient;
+ if( !dcopServer.isEmpty() )
+ client->setServerAddress( dcopServer.ascii() );
+ bool success = client->attach();
+ if( !success )
+ {
+ cerr << "ERROR: Couldn't attach to DCOP server!" << endl;
+ continue;
+ }
+ dcop = client;
+
+ switch ( args.count() )
+ {
+ case 0:
+ queryApplications("");
+ break;
+ case 1:
+ if (endsWith(app, '*'))
+ queryApplications(app);
+ else
+ queryObjects( app, "" );
+ break;
+ case 2:
+ if (endsWith(objid, '*'))
+ queryObjects(app, objid);
+ else
+ queryFunctions( app, objid );
+ break;
+ case 3:
+ default:
+ if( readStdin )
+ {
+ QCStringList::Iterator replaceArg = args.end();
+
+ QCStringList::Iterator it;
+ for( it = args.begin(); it != args.end(); it++ )
+ if( *it == "%1" )
+ replaceArg = it;
+
+ // Read from stdin until EOF and call function for each line read
+ char *buf = new char[ 1000 ];
+ while ( !feof( stdin ) )
+ {
+ fgets( buf, 1000, stdin );
+
+ if( replaceArg != args.end() )
+ *replaceArg = buf;
+
+ callFunction( app, objid, function, params );
+ }
+ }
+ else
+ {
+ // Just call function
+// cout << "call " << app << ", " << objid << ", " << function << ", (params)" << endl;
+ callFunction( app, objid, function, params );
+ }
+ break;
+ }
+ // Another sIt++ would make the loop infinite...
+ if( users.isEmpty() )
+ break;
+ }
+
+ // Another it++ would make the loop infinite...
+ if( it == users.end() )
+ break;
}
+}
+
+
+int main( int argc, char** argv )
+{
+ bool readStdin = false;
+ int numOptions = 0;
+ QString user;
+ Session session = DefaultSession;
+ QString sessionName;
+
+ // Scan for command-line options first
+ for( int pos = 1 ; pos <= argc - 1 ; pos++ )
+ {
+ if( strcmp( argv[ pos ], "--help" ) == 0 )
+ showHelp( 0 );
+ else if( strcmp( argv[ pos ], "--pipe" ) == 0 )
+ {
+ readStdin = true;
+ numOptions++;
+ }
+ else if( strcmp( argv[ pos ], "--user" ) == 0 )
+ {
+ if( pos <= argc - 2 )
+ {
+ user = QString::fromLocal8Bit( argv[ pos + 1] );
+ numOptions +=2;
+ pos++;
+ }
+ else
+ {
+ cerr << "Missing username for '--user' option!" << endl << endl;
+ showHelp( -1 );
+ }
+ }
+ else if( strcmp( argv[ pos ], "--all-users" ) == 0 )
+ {
+ user = "*";
+ numOptions ++;
+ }
+ else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 )
+ {
+ session = QuerySessions;
+ numOptions ++;
+ }
+ else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 )
+ {
+ session = AllSessions;
+ numOptions ++;
+ }
+ else if( argv[ pos ][ 0 ] == '-' )
+ {
+ cerr << "Unknown command-line option '" << argv[ pos ]
+ << "'." << endl << endl;
+ showHelp( -1 );
+ }
+ else
+ break; // End of options
+ }
+
+ argc -= numOptions;
+
+ QCStringList args;
+ for( int i = numOptions; i < argc + numOptions - 1; i++ )
+ args.append( argv[ i + 1 ] );
+
+ if( readStdin && args.count() < 3 )
+ {
+ cerr << "--pipe option only supported for function calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( user == "*" && args.count() < 3 && session != QuerySessions )
+ {
+ cerr << "ERROR: The --all-users option is only supported for function calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( session == QuerySessions && !args.isEmpty() )
+ {
+ cerr << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( session == QuerySessions && user.isEmpty() )
+ {
+ cerr << "ERROR: The --list-sessions option can only be used with the --user or" << endl
+ << "--all-users options!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( session != DefaultSession && session != QuerySessions &&
+ args.count() < 3 )
+ {
+ cerr << "ERROR: The --session and --all-sessions options are only supported for function" << endl
+ << "calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ UserList users;
+ if( user == "*" )
+ users = userList();
+ else if( !user.isEmpty() )
+ users[ user ] = userList()[ user ];
+
+ runDCOP( args, users, session, sessionName, readStdin );
return 0;
}
+
+// vim: set ts=8 sts=4 sw=4 noet:
+
diff -aur dcop/client/dcopfind.cpp dcop2/client/dcopfind.cpp
--- dcop/client/dcopfind.cpp Wed Jan 30 22:38:07 2002
+++ dcop2/client/dcopfind.cpp Wed Jan 30 22:37:04 2002
@@ -36,7 +36,7 @@
static bool bAppIdOnly = 0;
static bool bLaunchApp = 0;
-bool findObject( const char* app, const char* obj, const char* func, int argc, char** args )
+bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
{
QString f = func; // Qt is better with unicode strings, so use one.
int left = f.find( '(' );
@@ -118,7 +118,7 @@
f = fc;
}
- if ( (int) types.count() != argc ) {
+ if ( types.count() != args.count() ) {
qWarning( "arguments do not match" );
exit(1);
}
@@ -128,9 +128,9 @@
int i = 0;
for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
- marshall(arg, argc, args, i, *it);
+ marshall(arg, args, i, *it);
}
- if ( (int) i != argc ) {
+ if ( (uint) i != args.count() ) {
qWarning( "arguments do not match" );
exit(1);
}
@@ -221,7 +221,11 @@
argc = 0;
}
- findObject( app, objid, function, argc, args );
+ QCStringList params;
+ for( int i = 0; i < argc; i++ )
+ params.append( args[ i ] );
+
+ findObject( app, objid, function, params );
return 0;
}
diff -aur dcop/client/marshall.cpp dcop2/client/marshall.cpp
--- dcop/client/marshall.cpp Wed Jan 30 22:38:07 2002
+++ dcop2/client/marshall.cpp Wed Jan 30 22:37:04 2002
@@ -242,108 +242,110 @@
}
-void marshall(QDataStream &arg, int argc, char **argv, int &i, QString type)
+void marshall( QDataStream &arg, QCStringList args, uint &i, QString type )
{
- if (type == "QStringList")
- type = "QValueList<QString>";
- if (type == "QCStringList")
- type = "QValueList<QCString>";
- if (i >= argc)
- {
- qWarning("Not enough arguments.");
- exit(1);
- }
- QString s = QString::fromLocal8Bit(argv[i]);
-
- if ( type == "int" )
- arg << s.toInt();
- else if ( type == "uint" )
- arg << s.toUInt();
- else if ( type == "unsigned" )
- arg << s.toUInt();
- else if ( type == "unsigned int" )
- arg << s.toUInt();
- else if ( type == "long" )
- arg << s.toLong();
- else if ( type == "long int" )
- arg << s.toLong();
- else if ( type == "unsigned long" )
- arg << s.toULong();
- else if ( type == "unsigned long int" )
- arg << s.toULong();
- else if ( type == "float" )
- arg << s.toFloat();
- else if ( type == "double" )
- arg << s.toDouble();
- else if ( type == "bool" )
- arg << mkBool( s );
- else if ( type == "QString" )
- arg << s;
- else if ( type == "QCString" )
- arg << QCString( argv[i] );
- else if ( type == "QColor" )
- arg << mkColor( s );
- else if ( type == "QPoint" )
- arg << mkPoint( s );
- else if ( type == "QSize" )
- arg << mkSize( s );
- else if ( type == "QRect" )
- arg << mkRect( s );
- else if ( type == "QVariant" ) {
- if ( s == "true" || s == "false" )
- arg << QVariant( mkBool( s ), 42 );
- else if ( s.left( 4 ) == "int(" )
- arg << QVariant( s.mid(4, s.length()-5).toInt() );
- else if ( s.left( 7 ) == "QPoint(" )
- arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
- else if ( s.left( 6 ) == "QSize(" )
- arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
- else if ( s.left( 6 ) == "QRect(" )
- arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
- else if ( s.left( 7 ) == "QColor(" )
- arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
- else
- arg << QVariant( s );
- } else if ( type.startsWith("QValueList<")) {
- type = type.mid(11, type.length() - 12);
- QStringList list;
- QString delim = s;
- if (delim == "[")
- delim = "]";
- if (delim == "(")
- delim = ")";
- i++;
- QByteArray dummy_data;
- QDataStream dummy_arg(dummy_data, IO_WriteOnly);
+ if (type == "QStringList")
+ type = "QValueList<QString>";
+ if (type == "QCStringList")
+ type = "QValueList<QCString>";
+ if( i > args.count() )
+ {
+ qWarning("Not enough arguments.");
+ exit(1);
+ }
+ QString s = QString::fromLocal8Bit( args[ i ] );
- int j = i;
- int count = 0;
- // Parse list to get the count
- while (true) {
- if (j >= argc)
- {
- qWarning("List end-delimiter '%s' not found.", delim.latin1());
- exit(1);
- }
- if (argv[j] == delim) break;
- marshall(dummy_arg, argc, argv, j, type);
- count++;
- }
- arg << (Q_UINT32) count;
- // Parse the list for real
- while (true) {
- if (i >= argc)
- {
- qWarning("List end-delimiter '%s' not found.", delim.latin1());
- exit(1);
- }
- if (argv[i] == delim) break;
- marshall(arg, argc, argv, i, type);
- }
- } else {
- qWarning( "cannot handle datatype '%s'", type.latin1() );
- exit(1);
- }
+ if ( type == "int" )
+ arg << s.toInt();
+ else if ( type == "uint" )
+ arg << s.toUInt();
+ else if ( type == "unsigned" )
+ arg << s.toUInt();
+ else if ( type == "unsigned int" )
+ arg << s.toUInt();
+ else if ( type == "long" )
+ arg << s.toLong();
+ else if ( type == "long int" )
+ arg << s.toLong();
+ else if ( type == "unsigned long" )
+ arg << s.toULong();
+ else if ( type == "unsigned long int" )
+ arg << s.toULong();
+ else if ( type == "float" )
+ arg << s.toFloat();
+ else if ( type == "double" )
+ arg << s.toDouble();
+ else if ( type == "bool" )
+ arg << mkBool( s );
+ else if ( type == "QString" )
+ arg << s;
+ else if ( type == "QCString" )
+ arg << QCString( args[ i ] );
+ else if ( type == "QColor" )
+ arg << mkColor( s );
+ else if ( type == "QPoint" )
+ arg << mkPoint( s );
+ else if ( type == "QSize" )
+ arg << mkSize( s );
+ else if ( type == "QRect" )
+ arg << mkRect( s );
+ else if ( type == "QVariant" ) {
+ if ( s == "true" || s == "false" )
+ arg << QVariant( mkBool( s ), 42 );
+ else if ( s.left( 4 ) == "int(" )
+ arg << QVariant( s.mid(4, s.length()-5).toInt() );
+ else if ( s.left( 7 ) == "QPoint(" )
+ arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
+ else if ( s.left( 6 ) == "QSize(" )
+ arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
+ else if ( s.left( 6 ) == "QRect(" )
+ arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
+ else if ( s.left( 7 ) == "QColor(" )
+ arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
+ else
+ arg << QVariant( s );
+ } else if ( type.startsWith("QValueList<")) {
+ type = type.mid(11, type.length() - 12);
+ QStringList list;
+ QString delim = s;
+ if (delim == "[")
+ delim = "]";
+ if (delim == "(")
+ delim = ")";
i++;
+ QByteArray dummy_data;
+ QDataStream dummy_arg(dummy_data, IO_WriteOnly);
+
+ uint j = i;
+ uint count = 0;
+ // Parse list to get the count
+ while (true) {
+ if( j > args.count() )
+ {
+ qWarning("List end-delimiter '%s' not found.", delim.latin1());
+ exit(1);
+ }
+ if( QString::fromLocal8Bit( args[ j ] ) == delim )
+ break;
+ marshall( dummy_arg, args, j, type );
+ count++;
+ }
+ arg << (Q_UINT32) count;
+ // Parse the list for real
+ while (true) {
+ if( i > args.count() )
+ {
+ qWarning("List end-delimiter '%s' not found.", delim.latin1());
+ exit(1);
+ }
+ if( QString::fromLocal8Bit( args[ i ] ) == delim )
+ break;
+ marshall( arg, args, i, type );
+ }
+ } else {
+ qWarning( "cannot handle datatype '%s'", type.latin1() );
+ exit(1);
+ }
+ i++;
}

Some files were not shown because too many files have changed in this diff Show more