diff options
Diffstat (limited to 'kimagemapeditor')
61 files changed, 11221 insertions, 0 deletions
diff --git a/kimagemapeditor/AUTHORS b/kimagemapeditor/AUTHORS new file mode 100644 index 00000000..7aee7c48 --- /dev/null +++ b/kimagemapeditor/AUTHORS @@ -0,0 +1 @@ +Jan Sch�fer <[email protected]> diff --git a/kimagemapeditor/COPYING b/kimagemapeditor/COPYING new file mode 100644 index 00000000..c7aea189 --- /dev/null +++ b/kimagemapeditor/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, 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 diff --git a/kimagemapeditor/ChangeLog b/kimagemapeditor/ChangeLog new file mode 100644 index 00000000..55983873 --- /dev/null +++ b/kimagemapeditor/ChangeLog @@ -0,0 +1,105 @@ +1.0 : +- New features : + * French translation - Thanks to Germain Chazot + - KImageMapEditor is now translated to 4 languages : + German, spanish, french and dutch + * Improved session management + * Made it possible to start with the last opened document + * The ImageMapChoosDialog is only shown, if there are more then one map to choose. +- Bug fixes : + * Fixed the bug that prevents from dropping html or image files + * Fixed another Mandrake compilation problem + * The area preview image size can now be changed by the properties dialog + * The highlight and show alt tag settings are now saved when used within Quanta. + * Completed spanish translation - Thanks to Antonio Crevill�n + +1.0b3 : +- New features : + * Added dutch translation - Thanks to Fabrice Mous +- Bug fixes : + * added namespace to cout : std::cout to solve the compilation problem under Mandrake + * saveAs works now + * made the KPart readwrite only to work within Quanta correctly + +1.0b2 : +- Bug fixes : + * Opening of an image over the toolbar or the menu entry file->open add + the image now correctly to the image list. + * The command line option --stdout works again. + +1.0b : +- Note : Because of various internal modifications, this is intended to be a beta + release. So it's possible that KImageMapEditor may crash and/or + the content of the currently editing html file could be corrupted + or be lost at all. + KImageMapEditor therefore creates a backup file everytime you + save an html file. It ends with a ~. + Please only delete this file if you are sure that the original file + isn't corrupted. +- New features : + * Converted the program to the KPart architecture, it can now be used as a + imagemap viewer plugin in Konqueror or as an edit plugin in Quanta. + * It's now possible to really edit a html file instead of creating always + a new one with only one imagemap. + * Added a listview of all imagemaps of the current editing html files. + It's now possible to switch between the different maps, to delete maps and + to add new maps to the html file. + * Added a listview of all images that are contained in the current html file. + It's now possible to switch between these images. + * Spanish translation - Thanks to Antonio Crevill�n +- Bug fixes : + * When KImageMapEditor was not properly installed with make install and + the required image files couldn't be found, KImageMapEditor now shows + an error message and exit(1), instead of crashing. + +0.9.5 : +- New features : + * Tool for adding and removing points to/from a polygon with the mouse + * Freehand tool for drawing polygons + * German translation + * More zoom modes +- Bug fixes : + * Some undo bugs which results in a crash -> fixed + * When switching from non-highlight mode to highlight mode the areas + weren't highlighted correctly -> fixed + * Crash when moving an area outside the drawing zone -> fixed + +0.9.4 : +- New features : + * Areas can be highlighted + * Alt. text can be shown + * PHP-files can be read + * Property dialog extended + * New action : close file + +0.9.3 : +- New features : + * Multiselection + * Keyboard can be used better + * New mouse cursors + * New Action : delete + * other new Actions + +0.9.2 : +- New features : + * Undo / Redo for almost all actions + * Middle mouse click opens the properties dialog + * Possiblity of enable / disable the default area + +- Bug fixes : + * It's now possible to save to a file without an *.html,*.htm extension + * Creating a rectangle with a negative size ( and a following crash ) is no longer possible. + +0.9.1 : +- New features : + * Better way of editing the area coordinates manually + - Possibility of adding and removing points to a polygon + * Cursor shape changes to indicate moving or resizing + * Circle drawing is now perfekt + * Possibility of changing the order of the areas + +- Bug fixes : + * When saving to an HTML file the ending </html> tag is no longer missing. + * When adding an area and pressing cancel the area will not be added. + * Restoring the window size works now + diff --git a/kimagemapeditor/INSTALL b/kimagemapeditor/INSTALL new file mode 100644 index 00000000..02a4a074 --- /dev/null +++ b/kimagemapeditor/INSTALL @@ -0,0 +1,167 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes a while. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Type `make install' to install the programs and any data files and + documentation. + + 4. You can remove the program binaries and object files from the + source code directory by typing `make clean'. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/kimagemapeditor/Makefile.am b/kimagemapeditor/Makefile.am new file mode 100644 index 00000000..3f2ed486 --- /dev/null +++ b/kimagemapeditor/Makefile.am @@ -0,0 +1,63 @@ +SUBDIRS = pics + +bin_PROGRAMS = kimagemapeditor +kde_module_LTLIBRARIES = libkimagemapeditor.la + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libkimagemapeditorcommon.la + +libkimagemapeditorcommon_la_SOURCES = \ + qextfileinfo.cpp \ + areacreator.cpp \ + kimearea.cpp \ + kimecommands.cpp \ + kimedialogs.cpp \ + kimagemapeditor.cpp \ + drawzone.cpp \ + arealistview.cpp \ + imageslistview.cpp \ + mapslistview.cpp + +libkimagemapeditor_la_SOURCES = \ + dummy.cpp + +kimagemapeditor_SOURCES = \ + main.cpp \ + kimeshell.cpp + + +noinst_HEADERS = \ + qextfileinfo.h \ + areacreator.h \ + kimearea.h \ + kimecommands.h \ + kimedialogs.h \ + kimagemapeditor.h \ + drawzone.h \ + kimeshell.h + + +libkimagemapeditor_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +libkimagemapeditor_la_LIBADD = libkimagemapeditorcommon.la $(LIB_KFILE) $(LIB_KPARTS) $(LIB_KHTML) + +kimagemapeditor_LDFLAGS = $(all_libraries) $(KDE_RPATH) +kimagemapeditor_LDADD = libkimagemapeditorcommon.la $(LIB_KFILE) $(LIB_KPARTS) $(LIB_KHTML) + +# set the include path for X, qt and KDE +INCLUDES= $(all_includes) + +xdg_apps_DATA = kimagemapeditor.desktop + +rcdir = $(kde_datadir)/kimagemapeditor +rc_DATA = kimagemapeditorui.rc \ + kimagemapeditorpartui.rc + +kde_services_DATA = kimagemapeditorpart.desktop + +messages: rc.cpp + LIST=`find . -name \*.h -o -name \*.hh -o -name \*.H -o -name \*.hxx -o -name \*.hpp -o -name \*.cpp -o -name \*.cc -o -name \*.cxx -o -name \*.ecpp -o -name \*.C`; \ + if test -n "$$LIST"; then \ + $(XGETTEXT) $$LIST -o $(podir)/kimagemapeditor.pot; \ + fi + diff --git a/kimagemapeditor/NEWS b/kimagemapeditor/NEWS new file mode 100644 index 00000000..3957e33d --- /dev/null +++ b/kimagemapeditor/NEWS @@ -0,0 +1,13 @@ +1.0 : +- New features : + * French translation - Thanks to Germain Chazot + - KImageMapEditor is now translated to 4 languages : + German, spanish, french and dutch + * Session management + * Made it possible to start with the last opened document +- Bug fixes : + * Fixed the bug that prevents from dropping html or image files + * Fixed another Mandrake compilation problem + * The area preview image size can now be changed by the properties dialog + * The highlight and show alt tag settings are now saved when used within Quanta. + * Completed spanish translation - Thanks to Antonio Crevill�n diff --git a/kimagemapeditor/README b/kimagemapeditor/README new file mode 100644 index 00000000..b04c6794 --- /dev/null +++ b/kimagemapeditor/README @@ -0,0 +1,12 @@ + + --------------------------------- + + KImageMapEditor + + An HTML image map editor + + Jan Sch�fer + + + --------------------------------- diff --git a/kimagemapeditor/TODO b/kimagemapeditor/TODO new file mode 100644 index 00000000..c629ca1d --- /dev/null +++ b/kimagemapeditor/TODO @@ -0,0 +1,5 @@ +- Create a handbook +- Add Tip Of The Day +- Translate to more languages ( help would be really appreciated ) +- Have fun with it ;-) + diff --git a/kimagemapeditor/VERSION b/kimagemapeditor/VERSION new file mode 100644 index 00000000..51164aba --- /dev/null +++ b/kimagemapeditor/VERSION @@ -0,0 +1 @@ +KImageMapEditor v1.0.1 diff --git a/kimagemapeditor/areacreator.cpp b/kimagemapeditor/areacreator.cpp new file mode 100644 index 00000000..739409fc --- /dev/null +++ b/kimagemapeditor/areacreator.cpp @@ -0,0 +1,44 @@ +/*************************************************************************** + areacreator.cpp - description + ------------------- + begin : Wed Apr 3 2002 + copyright : (C) 2002 by Jan Sch�fer + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 "areacreator.h" + + + +Area* AreaCreator::create( Area::ShapeType type) +{ + switch ( type ) { + case Area::Rectangle : return new RectArea(); + case Area::Circle : return new CircleArea(); + case Area::Polygon : return new PolyArea(); + case Area::Default : return new DefaultArea(); + case Area::Selection : return new AreaSelection(); + default : return new Area(); + } +} + + +Area* AreaCreator::create( KImageMapEditor::ToolType type) +{ + switch ( type ) { + case KImageMapEditor::Rectangle : return new RectArea(); + case KImageMapEditor::Circle : return new CircleArea(); + case KImageMapEditor::Polygon : return new PolyArea(); + case KImageMapEditor::Freehand : return new PolyArea(); + default : return new Area(); + } +} diff --git a/kimagemapeditor/areacreator.h b/kimagemapeditor/areacreator.h new file mode 100644 index 00000000..c232d4f3 --- /dev/null +++ b/kimagemapeditor/areacreator.h @@ -0,0 +1,35 @@ +/*************************************************************************** + areacreator.h - description + ------------------- + begin : Wed Apr 3 2002 + copyright : (C) 2002 by Jan Sch�fer + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 AREACREATOR_H +#define AREACREATOR_H + + +#include "kimagemapeditor.h" + +/** + * A small creator class which follows the + * factory method pattern + */ +class AreaCreator +{ + public : + static Area* create( Area::ShapeType ); + static Area* create( KImageMapEditor::ToolType); +}; + +#endif diff --git a/kimagemapeditor/arealistview.cpp b/kimagemapeditor/arealistview.cpp new file mode 100644 index 00000000..80cd3265 --- /dev/null +++ b/kimagemapeditor/arealistview.cpp @@ -0,0 +1,67 @@ +/*************************************************************************** + arealistview.cpp - description + ------------------- + begin : Weg Feb 26 2003 + copyright : (C) 2003 by Jan Sch�fer + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +// QT +#include <klistview.h> +#include <qpushbutton.h> +#include <qhbox.h> +#include <qwhatsthis.h> +#include <qtooltip.h> + +// KDE +#include <kiconloader.h> +#include <klocale.h> + +// local +#include "kimearea.h" +#include "arealistview.h" + + +AreaListView::AreaListView(QWidget *parent, const char *name) + : QVBox(parent, name) +{ + listView = new KListView(this); + listView->addColumn(i18n("Areas")); + listView->addColumn(i18n("Preview")); + + listView->setMultiSelection(true); + listView->setSelectionMode( QListView::Extended ); + listView->setSorting(-1); // The user can't sort by clicking on the header + listView->setFullWidth(true); + + + QWhatsThis::add( listView, i18n("<h3>Area List</h3>The area list shows you all areas of the map.<br>" + "The left column shows the link associated with the area; the right " + "column shows the part of the image that is covered by the area.<br>" + "The maximum size of the preview images can be configured.")); + QToolTip::add( listView, i18n("A list of all areas")); + + QHBox *hbox= new QHBox(this); + upBtn= new QPushButton("",hbox); + upBtn->setIconSet(SmallIconSet("up")); + + downBtn= new QPushButton("",hbox); + downBtn->setIconSet(SmallIconSet("down")); + +} + + +AreaListView::~AreaListView() +{ +} + +#include "arealistview.moc" diff --git a/kimagemapeditor/arealistview.h b/kimagemapeditor/arealistview.h new file mode 100644 index 00000000..6037f5ee --- /dev/null +++ b/kimagemapeditor/arealistview.h @@ -0,0 +1,47 @@ +/*************************************************************************** + arealistview.h - description + ------------------- + begin : Weg Feb 26 2003 + copyright : (C) 2003 by Jan Sch�fer + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 _AREALISTVIEW_H_ +#define _AREALISTVIEW_H_ + +#include <qwidget.h> +#include <qvbox.h> + +class KListView; +class QPushButton; +class Area; + +/** + * This class consists of a ListView and two arrow buttons on the bottom. + * It shows all Areas of the current map. + * Jan Schaefer + **/ +class AreaListView : public QVBox +{ + Q_OBJECT + +public: + AreaListView(QWidget *parent, const char *name); + ~AreaListView(); + + KListView* listView; + QPushButton *upBtn; + QPushButton *downBtn; + +}; + +#endif diff --git a/kimagemapeditor/configure.in.in b/kimagemapeditor/configure.in.in new file mode 100644 index 00000000..f9c208de --- /dev/null +++ b/kimagemapeditor/configure.in.in @@ -0,0 +1,6 @@ +#MIN_CONFIG + +AM_INIT_AUTOMAKE(kimagemapeditor, 1.0) +AC_C_BIGENDIAN +AC_CHECK_KDEMAXPATHLEN + diff --git a/kimagemapeditor/drawzone.cpp b/kimagemapeditor/drawzone.cpp new file mode 100644 index 00000000..a5bf5612 --- /dev/null +++ b/kimagemapeditor/drawzone.cpp @@ -0,0 +1,896 @@ +/*************************************************************************** + drawzone.cpp - description + ------------------- + begin : Wed Apr 4 2001 + copyright : (C) 2001 by Jan Sch�er + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +// QT +#include <qbitmap.h> +#include <qpainter.h> +#include <qdragobject.h> +#include <qpixmap.h> + +// KDE +#include <kdebug.h> +#include <kurldrag.h> +#include <kglobal.h> +#include <kstandarddirs.h> +#include <kapplication.h> +#include <kmimetype.h> + +// Local +#include "drawzone.h" +#include "kimagemapeditor.h" +#include "kimecommands.h" +#include "areacreator.h" + +#include "kimecommon.h" + +DrawZone::DrawZone(QWidget *parent,KImageMapEditor* _imageMapEditor) + : QScrollView(parent) +{ + imageMapEditor=_imageMapEditor; +// setPicture(QImage()); + currentAction=None; + currentArea=0L; + oldArea=0L; + _zoom=1; + if (imageMapEditor->isReadWrite()) { + viewport()->setMouseTracking(true); + viewport()->setAcceptDrops(true); + this->setAcceptDrops(true); + } + else + viewport()->setMouseTracking(false); + + setDragAutoScroll(true); + + // The cross rectangle cursor + QBitmap b(32,32,true); + QBitmap b2(32,32,true); + QPainter p(&b); + // the cross + p.drawLine(0,8,6,8); + p.drawLine(10,8,16,8); + p.drawLine(8,0,8,6); + p.drawLine(8,10,8,16); + // the rectangle + p.drawRect(17,17,8,6); + + p.end(); + + p.begin(&b2); + // the cross black lines + p.drawLine(0,8,6,8); + p.drawLine(10,8,16,8); + p.drawLine(8,0,8,6); + p.drawLine(8,10,8,16); + + // the cross white lines + p.drawLine(0,7,6,7); + p.drawLine(10,7,16,7); + p.drawLine(7,0,7,6); + p.drawLine(7,10,7,16); + + // the cross white lines + p.drawLine(0,9,6,9); + p.drawLine(10,9,16,9); + p.drawLine(9,0,9,6); + p.drawLine(9,10,9,16); + + // the rectangles + p.drawRect(17,17,8,6); // black + p.drawRect(18,18,6,4); // white + p.drawRect(16,16,10,8); // white + + p.end(); + + RectangleCursor = QCursor(b,b2,8,8); + + + // The cross circle cursor + b = QBitmap(32,32,true); + b2 = QBitmap(32,32,true); + p.begin(&b); + // the cross + p.drawLine(0,8,6,8); + p.drawLine(10,8,16,8); + p.drawLine(8,0,8,6); + p.drawLine(8,10,8,16); + // the circle + p.drawEllipse(17,17,8,8); + + p.end(); + + p.begin(&b2); + // the cross black lines + p.drawLine(0,8,6,8); + p.drawLine(10,8,16,8); + p.drawLine(8,0,8,6); + p.drawLine(8,10,8,16); + + // the cross white lines + p.drawLine(0,7,6,7); + p.drawLine(10,7,16,7); + p.drawLine(7,0,7,6); + p.drawLine(7,10,7,16); + + // the cross white lines + p.drawLine(0,9,6,9); + p.drawLine(10,9,16,9); + p.drawLine(9,0,9,6); + p.drawLine(9,10,9,16); + + // the circles + p.drawEllipse(17,17,8,8); // black + p.drawEllipse(16,16,10,10); // white + p.drawEllipse(18,18,6,6); // white + + p.end(); + + CircleCursor = QCursor(b,b2,8,8); + + QString path = KGlobal::dirs()->findResourceDir( "data", "kimagemapeditor/polygoncursor.png" ) + "kimagemapeditor/polygoncursor.png"; + PolygonCursor = QCursor(QPixmap(path),8,8); + + path = KGlobal::dirs()->findResourceDir( "data", "kimagemapeditor/freehandcursor.png" ) + "kimagemapeditor/freehandcursor.png"; + FreehandCursor = QCursor(QPixmap(path),8,8); + + path = KGlobal::dirs()->findResourceDir( "data", "kimagemapeditor/addpointcursor.png" ) + "kimagemapeditor/addpointcursor.png"; + AddPointCursor = QCursor(QPixmap(path),8,8); + + path = KGlobal::dirs()->findResourceDir( "data", "kimagemapeditor/removepointcursor.png" ) + "kimagemapeditor/removepointcursor.png"; + RemovePointCursor = QCursor(QPixmap(path),8,8); +} + +DrawZone::~DrawZone(){ +} + +void DrawZone::setPicture(const QImage &_image) { + image=_image; +//- zoomedImage.convertFromImage(image); + setZoom(_zoom); +} + +void DrawZone::setZoom(double z) +{ + _zoom=z; + imageRect.setHeight(myround(image.height()*_zoom)); + imageRect.setWidth(myround(image.width()*_zoom)); + zoomedImage=QPixmap(imageRect.width(),imageRect.height()); + QPainter p(&zoomedImage); + p.scale(z,z); + QPixmap pix; + pix.convertFromImage(image); + // if the picture has transparent areas, + // fill them with Gimp like background + if (pix.mask()) { + QPixmap backPix(32,32); + QPainter p2(&backPix); + p2.fillRect(0,0,32,32,QColor(156,149,156)); + p2.fillRect(0,16,16,16,QColor(98,105,98)); + p2.fillRect(16,0,16,16,QColor(98,105,98)); + p2.flush(); + p.setPen(QPen()); + p.fillRect(imageRect.left(),imageRect.top(),imageRect.width(),imageRect.height(),QBrush(QColor("black"),backPix)); + } + p.drawPixmap(imageRect.left(),imageRect.top(),pix); + p.flush(); + resizeContents(visibleWidth()>imageRect.width() ? visibleWidth() : imageRect.width(), + visibleHeight()>imageRect.height() ? visibleHeight() : imageRect.height()); + repaintContents(0,0,contentsWidth(),contentsHeight(),true); +} + +QPoint DrawZone::translateFromZoom(const QPoint & p) const { + return QPoint((int)(p.x()/_zoom),(int)(p.y()/_zoom)); +} + +QRect DrawZone::translateFromZoom(const QRect & p) const { + return QRect((int)(p.x()/_zoom),(int) (p.y()/_zoom), + (int)(p.width()/_zoom),(int)(p.height()/_zoom)); +} + +QPoint DrawZone::translateToZoom(const QPoint & p) const { + return QPoint(myround(p.x()*_zoom),myround(p.y()*_zoom)); +} + +QRect DrawZone::translateToZoom(const QRect & r) const { +// return QRect(round(r.x()*_zoom),round(r.y()*_zoom), +// round(r.width()*_zoom),round(r.height()*_zoom)); + return QRect((int)(r.x()*_zoom),(int)(r.y()*_zoom), + (int)(r.width()*_zoom+2),(int)(r.height()*_zoom+2)); +} + +void DrawZone::contentsMouseDoubleClickEvent(QMouseEvent* e) { + if ( ! imageMapEditor->isReadWrite()) + return; + + QPoint point=e->pos(); + point-=imageRect.topLeft(); + point=translateFromZoom(point); + if ( currentAction==None && + (currentArea=imageMapEditor->onArea(point))) + { + imageMapEditor->deselectAll(); + imageMapEditor->select(currentArea); + currentArea=imageMapEditor->selected(); + imageMapEditor->showTagEditor(imageMapEditor->selected()); + } + +} + +void DrawZone::contentsMousePressEvent(QMouseEvent* e) +{ + if ( ! imageMapEditor->isReadWrite()) + return; + + drawStart=e->pos(); + // Check if it's on picture if not + // move it to the picture's border + if (!imageRect.contains(drawStart)) { + if (drawStart.x()>imageRect.right()) + drawStart.setX(imageRect.right()); + if (drawStart.x()<imageRect.left()) + drawStart.setX(imageRect.left()); + if (drawStart.y()>imageRect.bottom()) + drawStart.setY(imageRect.bottom()); + if (drawStart.y()<imageRect.top()) + drawStart.setY(imageRect.top()); + } + + // Translate it to picture coordinates + drawStart-=imageRect.topLeft(); + QPoint zoomedPoint = drawStart; + drawStart=translateFromZoom(drawStart); + delete oldArea; + oldArea=0L; + + if (currentArea) + { + oldArea=currentArea->clone(); + } + + if ( currentAction==None ) { + if (e->button()==RightButton) + { + if ( (currentArea=imageMapEditor->onArea(drawStart)) ) + { + if ( ! currentArea->isSelected()) + { + imageMapEditor->deselectAll(); + imageMapEditor->select(currentArea); + } + currentArea=imageMapEditor->selected(); + } + + imageMapEditor->slotShowMainPopupMenu(e->globalPos()); + + } + else + if (e->button()==MidButton) { + contentsMouseDoubleClickEvent(e); + } + else // LeftClick on selectionpoint + if ((currentArea=imageMapEditor->selected()) && + (currentSelectionPoint=currentArea->onSelectionPoint(zoomedPoint,_zoom))) + { + oldArea=currentArea->clone(); + + if ( (imageMapEditor->currentToolType() == KImageMapEditor::RemovePoint) && + (imageMapEditor->selected()->selectionPoints()->count()>3) ) + { + currentAction=RemovePoint; + } + else + { + currentAction=MoveSelectionPoint; + currentArea->setMoving(true); + } + + } else // leftclick not on selectionpoint but on area + if ((currentArea=imageMapEditor->onArea(drawStart))) + { + if ( imageMapEditor->currentToolType() == KImageMapEditor::AddPoint ) + { + currentAction=AddPoint; + viewport()->setCursor(AddPointCursor); + oldArea=currentArea->clone(); + } + else + { + currentAction=MoveArea; + viewport()->setCursor(sizeAllCursor); + + if ( currentArea->isSelected() ) { + if ( (e->state() & ControlButton) ) + imageMapEditor->deselect(currentArea); + } else + { + if ( (e->state() & ControlButton) ) + imageMapEditor->select( currentArea ); + else { + imageMapEditor->deselectAll(); + imageMapEditor->select( currentArea ); + } + } + + currentArea = imageMapEditor->selected(); + currentArea->setMoving(true); + + oldArea=currentArea->clone(); + } + } + else // leftclick on the background + if ( (imageMapEditor->currentToolType()==KImageMapEditor::Rectangle) || + (imageMapEditor->currentToolType()==KImageMapEditor::Circle) || + (imageMapEditor->currentToolType()==KImageMapEditor::Polygon) || + (imageMapEditor->currentToolType()==KImageMapEditor::Freehand)) + { + currentArea=AreaCreator::create(imageMapEditor->currentToolType()); + + currentArea->setRect(QRect(drawStart,drawStart)); + currentArea->setSelected(false); + imageMapEditor->deselectAll(); + + switch (imageMapEditor->currentToolType()) { + case KImageMapEditor::Rectangle : currentAction=DrawRectangle; break; + case KImageMapEditor::Circle : currentAction=DrawCircle; break; + case KImageMapEditor::Polygon : + currentAction=DrawPolygon; + currentArea->addCoord(drawStart); + currentSelectionPoint=currentArea->selectionPoints()->last(); + break; + case KImageMapEditor::Freehand : + currentAction=DrawFreehand; + //currentArea->addCoord(drawStart); + currentArea->setFinished(false); + break; + default: break; + } + } + else + // leftclicked with the arrow at an areafree position + if (imageMapEditor->currentToolType()==KImageMapEditor::Selection) + { + currentArea=0L; + imageMapEditor->deselectAll(); + // Start drawing a selection rectangle + currentAction=DoSelect; + oldSelectionRect = imageRect; + } + } else + if ( currentAction==DrawPolygon) { + + } + + QRect r; + if (oldArea) + r=oldArea->selectionRect(); + if (currentArea) { + r= r | currentArea->selectionRect(); + repaintContents(translateToZoom(r),false); + } + + +} + +void DrawZone::contentsMouseReleaseEvent(QMouseEvent *e) { + if ( ! imageMapEditor->isReadWrite()) + return; + + QPoint drawEnd=e->pos(); + + // Check if it's on picture if not + // move it to the picture's border + if (!imageRect.contains(drawEnd)) { + if (drawEnd.x()>imageRect.right()) + drawEnd.setX(imageRect.right()); + if (drawEnd.x()<imageRect.left()) + drawEnd.setX(imageRect.left()); + if (drawEnd.y()>imageRect.bottom()) + drawEnd.setY(imageRect.bottom()); + if (drawEnd.y()<imageRect.top()) + drawEnd.setY(imageRect.top()); + } + // Translate it to picture coordinates + drawEnd-=imageRect.topLeft(); + QPoint zoomedPoint=drawEnd; + + drawEnd=translateFromZoom(drawEnd); + + if (currentAction==DrawCircle || currentAction==DrawRectangle) { + currentAction=None; + imageMapEditor->commandHistory()->addCommand( + new CreateCommand( imageMapEditor, currentArea ), true); + } else + if (currentAction==DrawPolygon) { + // If the number of Polygonpoints is more than 2 + // and clicked on the first PolygonPoint or + // the right Button was pressed the Polygon is finished + if ((currentArea->selectionPoints()->count()>2) + && (currentArea->selectionPoints()->first()->contains(drawEnd) + || (e->button()==RightButton))) + { + currentArea->setFinished(true); + currentAction=None; + imageMapEditor->commandHistory()->addCommand( + new CreateCommand( imageMapEditor, currentArea ), true); + } else + { + currentArea->insertCoord(currentArea->countSelectionPoints()-1, drawEnd); + currentSelectionPoint=currentArea->selectionPoints()->last(); + } + } else + if (currentAction==DrawFreehand) + { + currentArea->setFinished(true); + currentArea->simplifyCoords(); + currentAction=None; + imageMapEditor->commandHistory()->addCommand( + new CreateCommand( imageMapEditor, currentArea ), true); + } else + if (currentAction==MoveArea) { + QPoint p1 = oldArea->rect().topLeft(); + QPoint p2 = imageMapEditor->selected()->rect().topLeft(); + + if (p1 != p2) + { + imageMapEditor->commandHistory()->addCommand( + new MoveCommand( imageMapEditor, imageMapEditor->selected(), oldArea->rect().topLeft()),true); + imageMapEditor->slotAreaChanged(currentArea); + } else + imageMapEditor->updateSelection(); + + currentAction=None; + } else + if (currentAction==MoveSelectionPoint) { + imageMapEditor->commandHistory()->addCommand( + new ResizeCommand( imageMapEditor, imageMapEditor->selected(), oldArea),true); + imageMapEditor->slotAreaChanged(currentArea); + currentAction=None; + } else + if (currentAction==RemovePoint) { + if (currentSelectionPoint==currentArea->onSelectionPoint(zoomedPoint,_zoom)) + { + currentArea->removeSelectionPoint(currentSelectionPoint); + + imageMapEditor->commandHistory()->addCommand( + new RemovePointCommand( imageMapEditor, imageMapEditor->selected(), oldArea),true); + imageMapEditor->slotAreaChanged(currentArea); + } + currentAction=None; + } else + if (currentAction==AddPoint) + { + if (currentArea==imageMapEditor->onArea(drawEnd)) + { + imageMapEditor->commandHistory()->addCommand( + new AddPointCommand( imageMapEditor, imageMapEditor->selected(), drawEnd),true); + imageMapEditor->slotAreaChanged(currentArea); + } + currentAction=None; + } else + if (currentAction==DoSelect) { + currentAction=None; + + QRect r(drawStart.x(),drawStart.y(),drawCurrent.x()-drawStart.x(),drawCurrent.y()-drawStart.y()); + r = r.normalize(); + + AreaListIterator it=imageMapEditor->areaList(); + for ( ; it.current() != 0L ; ++it ) { + if ( it.current()->rect().intersects(r) ) + { + if (!it.current()->isSelected() ) + imageMapEditor->selectWithoutUpdate( it.current() ); + } + else + if (it.current()->isSelected()) + imageMapEditor->deselectWithoutUpdate( it.current() ); + } + + imageMapEditor->updateActionAccess(); + imageMapEditor->updateSelection(); + repaintContents(imageRect,false); + } else { + currentAction=None; + } + imageMapEditor->slotChangeStatusCoords(drawEnd.x(),drawEnd.y()); + if (currentArea) + { + currentArea->setMoving(false); + repaintArea(*currentArea); + } + delete oldArea; + oldArea=0L; +// repaintContents(0,0,contentsWidth(),contentsHeight(),false); + imageMapEditor->slotUpdateSelectionCoords(); +} + + +void DrawZone::contentsMouseMoveEvent(QMouseEvent *e) +{ + if ( ! imageMapEditor->isReadWrite()) + return; + + + drawCurrent=e->pos(); + + // If outside the image + // set it to the border + if (!imageRect.contains(drawCurrent)) { + if (drawCurrent.x()>imageRect.right()) + drawCurrent.setX(imageRect.right()); + if (drawCurrent.x()<imageRect.left()) + drawCurrent.setX(imageRect.left()); + if (drawCurrent.y()>imageRect.bottom()) + drawCurrent.setY(imageRect.bottom()); + if (drawCurrent.y()<imageRect.top()) + drawCurrent.setY(imageRect.top()); + } + + // Translate to image coordinates + drawCurrent-=imageRect.topLeft(); + QPoint zoomedPoint=drawCurrent; + drawCurrent=translateFromZoom(drawCurrent); + + if (currentAction==DrawRectangle) { + // To avoid flicker, only repaint the minimum rect + QRect oldRect=translateToZoom(currentArea->rect()); + currentArea->setRect(QRect(drawStart,drawCurrent).normalize()); + QRect newRect=translateToZoom(currentArea->selectionRect()); + QRect r=oldRect | newRect; + repaintContents(r,false); + imageMapEditor->slotUpdateSelectionCoords( currentArea->rect() ); + } else + if (currentAction==DrawCircle) { + QRect oldRect=translateToZoom(currentArea->rect()); + + // We don't want ellipses + int maxDistance=myabs(drawStart.x()-drawCurrent.x()) > + myabs(drawStart.y()-drawCurrent.y()) ? + myabs(drawStart.x()-drawCurrent.x()) : + myabs(drawStart.y()-drawCurrent.y()) ; + + int xDiff=maxDistance; + int yDiff=maxDistance; + + if ( drawStart.x()-drawCurrent.x() > 0) + xDiff=-xDiff; + + if ( drawStart.y()-drawCurrent.y() > 0) + yDiff=-yDiff; + + QPoint endPoint( drawStart.x()+xDiff, drawStart.y()+yDiff); + + currentArea->setRect(QRect(drawStart,endPoint).normalize()); + QRect newRect=translateToZoom(currentArea->rect()); + QRect r=oldRect | newRect; + repaintContents(r,false); + imageMapEditor->slotUpdateSelectionCoords( currentArea->rect() ); + } else + if ( currentAction==DrawPolygon ) { + QRect oldRect=translateToZoom(currentArea->rect()); + currentArea->moveSelectionPoint(currentSelectionPoint,drawCurrent); + QRect newRect=translateToZoom(currentArea->rect()); + QRect r=oldRect | newRect; + repaintContents(r,false); + } else + if ( currentAction==DrawFreehand) { + QRect oldRect=translateToZoom(currentArea->rect()); + currentArea->insertCoord(currentArea->countSelectionPoints(), drawCurrent); + QRect newRect=translateToZoom(currentArea->rect()); + QRect r=oldRect | newRect; + repaintContents(r,false); + } else + if ( currentAction==MoveArea ) { + QRect oldRect=translateToZoom(currentArea->selectionRect()); + currentArea->moveBy((drawCurrent-drawStart).x(),(drawCurrent-drawStart).y()); + QRect newRect=translateToZoom(currentArea->selectionRect()); + QRect r=oldRect | newRect; + currentArea->setMoving(true); + repaintContents(r,false); + drawStart=drawCurrent; + imageMapEditor->slotUpdateSelectionCoords(); + } else + if ( currentAction==MoveSelectionPoint ) { + QRect oldRect=translateToZoom(currentArea->selectionRect()); + currentArea->moveSelectionPoint(currentSelectionPoint,drawCurrent); + QRect newRect=translateToZoom(currentArea->selectionRect()); + QRect r=oldRect | newRect; + repaintContents(r,false); + imageMapEditor->slotUpdateSelectionCoords(); + } else + if (currentAction==DoSelect) { + + QRect r(drawStart.x(),drawStart.y(),drawCurrent.x()-drawStart.x(),drawCurrent.y()-drawStart.y()); + r = r.normalize(); +// r = translateFromZoom(r); +/* + AreaListIterator it=imageMapEditor->areaList(); + for ( ; it.current() != 0L ; ++it ) { + if ( it.current()->rect().intersects(r) ) + { + if (!it.current()->isSelected() ) + imageMapEditor->selectWithoutUpdate( it.current() ); + } + else + if (it.current()->isSelected()) + imageMapEditor->deselectWithoutUpdate( it.current() ); + } +*/ + // We don't have to repaint the hole selection rectangle + // only the borders have to be repainted. + // So we have to create 4 rectangles for every rectangle + // which represent the borders and then repaint them. + + QRect lb,rb,tb,bb; + createBorderRectangles(translateToZoom(r),lb,rb,tb,bb); + repaintContents(lb,false); + repaintContents(rb,false); + repaintContents(tb,false); + repaintContents(bb,false); + + createBorderRectangles(translateToZoom(oldSelectionRect),lb,rb,tb,bb); + repaintContents(lb,false); + repaintContents(rb,false); + repaintContents(tb,false); + repaintContents(bb,false); + +// repaintContents(oldSelectionRect | r,false); + oldSelectionRect = r; +// repaintContents(translateToZoom(r),false); +//+ imageMapEditor->updateSelection(); + + +// QRect r(drawStart.x(),drawStart.y(),drawCurrent.x()-drawStart.x(),drawCurrent.y()-drawStart.y()); +// r = r.normalize(); +// QRect r2(drawStart.x(),drawStart.y(),drawOld.x()-drawStart.x(),drawOld.y()-drawStart.y()); +// r2 = r2.normalize(); +// r = translateToZoom(r | r2); +// repaintContents(r,false); + } else + if ( currentAction==None ) + { + if ( imageMapEditor->selected() && + imageMapEditor->selected()->onSelectionPoint(zoomedPoint,_zoom )) + { + if (imageMapEditor->selected()->type()==Area::Polygon) + { + if ((imageMapEditor->currentToolType()==KImageMapEditor::RemovePoint) && + (imageMapEditor->selected()->selectionPoints()->count()>3) ) + { + viewport()->setCursor(RemovePointCursor); + } + else + { + viewport()->setCursor(pointingHandCursor); + } + } + else + { + QPoint center=imageMapEditor->selected()->rect().center(); + if (drawCurrent.x() < center.x()) { + if (drawCurrent.y() < center.y()) + viewport()->setCursor(sizeFDiagCursor); + else + viewport()->setCursor(sizeBDiagCursor); + } + else { + if (drawCurrent.y() < center.y()) + viewport()->setCursor(sizeBDiagCursor); + else + viewport()->setCursor(sizeFDiagCursor); + } + } + } else + if ( imageMapEditor->onArea(drawCurrent) ) + { + if (imageMapEditor->currentToolType()==KImageMapEditor::AddPoint) + { + viewport()->setCursor(AddPointCursor); + } + else + { + viewport()->setCursor(sizeAllCursor); + } + } + else + if (imageMapEditor->currentToolType()==KImageMapEditor::Rectangle) { + viewport()->setCursor(RectangleCursor); +// kdDebug() << "KImageMapEditor::DrawZone: viewport()->setCursor to Rectangle" << endl; + } + else + if (imageMapEditor->currentToolType()==KImageMapEditor::Circle) + viewport()->setCursor(CircleCursor); + else + if (imageMapEditor->currentToolType()==KImageMapEditor::Polygon) + viewport()->setCursor(PolygonCursor); + else + if (imageMapEditor->currentToolType()==KImageMapEditor::Freehand) + viewport()->setCursor(FreehandCursor); + else + viewport()->setCursor(arrowCursor); + + } + imageMapEditor->slotChangeStatusCoords(drawCurrent.x(),drawCurrent.y()); +} + +void DrawZone::createBorderRectangles(const QRect & r,QRect & rb,QRect & lb,QRect & tb,QRect & bb) +{ + int bw; + bw = (int) (2+2*_zoom); // Border width + + rb.setX(r.x()+r.width()-bw); + rb.setY(r.y()); + rb.setWidth(bw+1); + rb.setHeight(r.height()); + + lb.setX(r.x()); + lb.setY(r.y()); + lb.setWidth(bw); + lb.setHeight(r.height()); + + tb.setX(r.x()); + tb.setY(r.y()); + tb.setWidth(r.width()); + tb.setHeight(bw); + + bb.setX(r.x()); + bb.setY(r.y()+r.height()-bw); + bb.setWidth(r.width()); + bb.setHeight(bw+1); +} + + +void DrawZone::resizeEvent(QResizeEvent* e) { + QScrollView::resizeEvent(e); + int width=(int) (image.width()*_zoom); + int height=(int) (image.height()*_zoom); + if (visibleWidth()>width) + width=visibleWidth(); + if (visibleHeight()>height) + height=visibleHeight(); + + resizeContents(width,height); + + imageRect.setLeft(0); + imageRect.setTop(0); + imageRect.setHeight((int)(image.height()*_zoom)); + imageRect.setWidth((int)(image.width()*_zoom)); + +} + +void DrawZone::cancelDrawing() +{ + if ( (currentAction == DrawPolygon ) + || (currentAction == DrawRectangle ) + || (currentAction == DrawCircle ) + ) + { + currentAction = None; + QRect r = translateToZoom(currentArea->selectionRect()); + delete currentArea; + currentArea = 0L; + repaintContents(r,false); + imageMapEditor->slotUpdateSelectionCoords(); + } +} + +void DrawZone::repaintArea(const Area & a) { + repaintContents(translateToZoom(a.selectionRect()),false); +} + +void DrawZone::repaintRect(const QRect & r) { + repaintContents(translateToZoom(r),false); +} + +void DrawZone::drawContents(QPainter* p,int clipx,int clipy,int clipw,int cliph) +{ + +// Erase background without flicker + QRect updateRect(clipx,clipy,clipw,cliph); + + // Pixmap for double-buffering + QPixmap doubleBuffer(updateRect.size()); + if (doubleBuffer.isNull()) + return; + + QPainter p2(&doubleBuffer); + p2.drawPixmap(0,0,zoomedImage,clipx,clipy,clipw,cliph); + p2.setBackgroundColor(p->backgroundColor()); + + if (zoomedImage.width() < (clipw+clipx) ) { + int eraseWidth = clipw+clipx - zoomedImage.width(); + p2.eraseRect( QRect(clipw-eraseWidth,0,eraseWidth,cliph) ); + } + + if (zoomedImage.height() < (cliph+clipy) ) { + int eraseHeight = cliph+clipy - zoomedImage.height(); + p2.eraseRect( QRect(0,cliph-eraseHeight,clipw,eraseHeight) ); + } + + p2.translate(-clipx, -clipy); + p2.scale(_zoom,_zoom); + + QRect areaUpdateRect; + areaUpdateRect.setX(myround(clipx/_zoom)-1); + areaUpdateRect.setY(myround(clipy/_zoom)-1); + areaUpdateRect.setWidth(myround(clipw/_zoom)+2); + areaUpdateRect.setHeight(myround(cliph/_zoom)+2); + + AreaListIterator it=imageMapEditor->areaList(); + for ( it.toLast();it.current() != 0L; --it) + { + if (it.current()->rect().intersects(areaUpdateRect)) + it.current()->draw(p2); + } + + // Draw the current drawing Area + if (currentAction != MoveArea && + currentAction != MoveSelectionPoint && + currentAction != None && + currentAction != DoSelect) + { + currentArea->draw(p2); + } + + if (currentAction == DoSelect ) + { + QPen pen = QPen(QColor("white"),1); + p2.setRasterOp(Qt::XorROP); + pen.setStyle(Qt::DotLine); + p2.setPen(pen); + + QRect r( drawStart.x(),drawStart.y(),drawCurrent.x()-drawStart.x(),drawCurrent.y()-drawStart.y()); + r = r.normalize(); + p2.drawRect(r); + } + + + + p2.end(); + + // Copy the double buffer into the widget + p->drawPixmap(clipx,clipy,doubleBuffer); + + +} + +void DrawZone::contentsDragEnterEvent(QDragEnterEvent*e) { + if (!KURLDrag::canDecode(e)) + return; + +// bool accept = false; + KURL::List uris; + KURLDrag::decode(e,uris); + KMimeType::Ptr ptr = KMimeType::findByURL(uris.first()); +// kdDebug() << "***** " << ptr.data()->name() << endl; + if ((ptr.data()->name() == "text/html") + || (ptr.data()->name().left(6) == "image/")) + e->accept(); +} + +void DrawZone::contentsDropEvent( QDropEvent* e) { + viewportDropEvent(e); +} + + + +void DrawZone::viewportDropEvent( QDropEvent* e) { + KURL::List urlList; + // A file from konqueror was dropped + if (KURLDrag::decode(e,urlList)) { + imageMapEditor->openFile(urlList.first()); + } +} diff --git a/kimagemapeditor/drawzone.h b/kimagemapeditor/drawzone.h new file mode 100644 index 00000000..764e6951 --- /dev/null +++ b/kimagemapeditor/drawzone.h @@ -0,0 +1,122 @@ +/*************************************************************************** + imagemap.h - description + ------------------- + begin : Wed Apr 4 2001 + copyright : (C) 2001 by Jan Sch�fer + email : [email protected] +***************************************************************************/ + +/*************************************************************************** +* * +* 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 IMAGEMAP_H +#define IMAGEMAP_H + +#include <qscrollview.h> +#include <qimage.h> +#include <qpoint.h> +#include <qrect.h> +#include <qcursor.h> + +#include "kdeversion.h" + +class KImageMapEditor; +class Area; + +/** + *@short Draws the image and areas and handle the draw actions + *@author Jan Schäfer + *@internal + *@see Area + */ +class DrawZone : public QScrollView { +public: + + DrawZone(QWidget *parent,KImageMapEditor* _imageMapEditor); + ~DrawZone(); + + QImage picture() const; + void repaintArea(const Area & a); + void repaintRect(const QRect & r); + void cancelDrawing(); + + void setPicture(const QImage &_image); + void setZoom(double z); + + QPoint translateFromZoom(const QPoint & p) const; + QRect translateFromZoom(const QRect & p) const; + QPoint translateToZoom(const QPoint & p) const; + QRect translateToZoom(const QRect & p) const; + + QRect getImageRect() const { return image.rect(); } + + +protected: + + virtual void contentsMouseDoubleClickEvent(QMouseEvent*); + virtual void contentsMousePressEvent(QMouseEvent*); + virtual void contentsMouseReleaseEvent(QMouseEvent*); + virtual void contentsMouseMoveEvent(QMouseEvent*); + virtual void resizeEvent(QResizeEvent*); + virtual void drawContents(QPainter*,int,int,int,int); + virtual void viewportDropEvent(QDropEvent*); + virtual void contentsDragEnterEvent(QDragEnterEvent*); + virtual void contentsDropEvent(QDropEvent*); + + /** + * Represents whats currently going on + * @li None : Nothing + * @li DrawCircle : The user is drawing a circle + * @li DrawRectangle : The user is drawing a rectangle + * @li MoveSelectionPoint : The user is resizing an @ref Area or moving a polygon point + * @li MoveArea : The user is moving an @ref Area + * @li DoSelect : The user makes a selection rectangle + */ + enum DrawAction { None, DrawCircle, DrawRectangle, DrawPolygon, DrawFreehand, MoveSelectionPoint, MoveArea, DoSelect, RemovePoint, AddPoint }; + + void createBorderRectangles(const QRect & r,QRect & rb,QRect & lb,QRect & tb,QRect & bb); + +private: + + DrawAction currentAction; + // The currently drawing area + Area *currentArea; + // Needed when moving selectionpoints + QRect *currentSelectionPoint; + // The point where the user clicked the mouse + QPoint drawStart; + QPoint drawCurrent; + // The original image + QImage image; + KImageMapEditor *imageMapEditor; + // Only the rect of the zoomed image, perhaps redundant + QRect imageRect; + // Only for repaint issues + Area *oldArea; + + QRect oldSelectionRect; + // Holds the zoomed image for efficiency reasons + QPixmap zoomedImage; + // The current zoom-factor + double _zoom; + + QCursor RectangleCursor; + QCursor CircleCursor; + QCursor PolygonCursor; + QCursor FreehandCursor; + QCursor AddPointCursor; + QCursor RemovePointCursor; +}; + +inline QImage DrawZone::picture() const { + return image; +} + + +#endif diff --git a/kimagemapeditor/dummy.cpp b/kimagemapeditor/dummy.cpp new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/kimagemapeditor/dummy.cpp diff --git a/kimagemapeditor/imagemap.cpp b/kimagemapeditor/imagemap.cpp new file mode 100644 index 00000000..665ef000 --- /dev/null +++ b/kimagemapeditor/imagemap.cpp @@ -0,0 +1,395 @@ +/*************************************************************************** + imagemap.cpp - description + ------------------- + begin : Wed Apr 4 2001 + copyright : (C) 2001 by Jan Sch�fer + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 "imagemap.h" +#include "kimagemapeditor.h" +#include "qpainter.h" +#include "kdebug.h" +#include <qbitmap.h> + +int round(double d) { + if ( (d-((int) d)) < 0.5 ) + return (int) d; + else + return ((int) d)+1; +} + +ImageMap::ImageMap(QWidget *parent,KImageMapEditor* _imageMapEditor) + : QScrollView(parent) +{ + imageMapEditor=_imageMapEditor; +// setPicture(QImage()); + currentAction=None; + currentArea=0L; + eraseOldArea=false; + oldArea=0L; + _zoom=1; + viewport()->setMouseTracking(true); + + +} + +ImageMap::~ImageMap(){ +} + +void ImageMap::setPicture(const QImage &_image) { + image=_image; + zoomedImage.convertFromImage(image); + setZoom(_zoom); +} + +void ImageMap::setZoom(double z) { + _zoom=z; + imageRect.setHeight(image.height()*_zoom); + imageRect.setWidth(image.width()*_zoom); + zoomedImage=QPixmap(imageRect.width(),imageRect.height()); + QPainter p(&zoomedImage); + p.scale(z,z); + QPixmap pix; + pix.convertFromImage(image); + // if the picture has transparent areas, + // fill them with Gimp like background + if (pix.mask()) { + QPixmap backPix(32,32); + QPainter p2(&backPix); + p2.fillRect(0,0,32,32,QColor(156,149,156)); + p2.fillRect(0,16,16,16,QColor(98,105,98)); + p2.fillRect(16,0,16,16,QColor(98,105,98)); + p2.flush(); + p.setPen(QPen()); + p.fillRect(imageRect.left(),imageRect.top(),imageRect.width(),imageRect.height(),QBrush(QColor("black"),backPix)); + } + p.drawPixmap(imageRect.left(),imageRect.top(),pix); + p.flush(); + resizeContents(visibleWidth()>imageRect.width() ? visibleWidth() : imageRect.width(), + visibleHeight()>imageRect.height() ? visibleHeight() : imageRect.height()); + repaintContents(0,0,contentsWidth(),contentsHeight(),true); +} + +QPoint ImageMap::translateFromZoom(const QPoint & p) const { + return QPoint(p.x()/_zoom,p.y()/_zoom); +} + +QPoint ImageMap::translateToZoom(const QPoint & p) const { + return QPoint(round(p.x()*_zoom),round(p.y()*_zoom)); +} + +QRect ImageMap::translateToZoom(const QRect & r) const { + return QRect(round(r.x()*_zoom),round(r.y()*_zoom), + round(r.width()*_zoom),round(r.height()*_zoom)); +} + +void ImageMap::contentsMouseDoubleClickEvent(QMouseEvent* e) { + QPoint point=e->pos(); + point-=imageRect.topLeft(); + point=translateFromZoom(point); + if ( currentAction==None && + (currentArea=imageMapEditor->onArea(point))) + imageMapEditor->showTagEditor(currentArea); + +} + +void ImageMap::contentsMousePressEvent(QMouseEvent* e) { + drawStart=e->pos(); + // Check if it's on picture if not + // move it to the picture's border + if (!imageRect.contains(drawStart)) { + if (drawStart.x()>imageRect.right()) + drawStart.setX(imageRect.right()); + if (drawStart.x()<imageRect.left()) + drawStart.setX(imageRect.left()); + if (drawStart.y()>imageRect.bottom()) + drawStart.setY(imageRect.bottom()); + if (drawStart.y()<imageRect.top()) + drawStart.setY(imageRect.top()); + } + + // Translate it to picture coordinates + drawStart-=imageRect.topLeft(); + drawStart=translateFromZoom(drawStart); + if (currentArea) + oldArea=new Area(*currentArea); + + if ( currentAction==None ) { + if (e->button()==RightButton) { + currentArea=imageMapEditor->onArea(drawStart); + imageMapEditor->select(currentArea); + imageMapEditor->slotShowPopupMenu(e->globalPos()); + } else + if ((currentArea=imageMapEditor->selected()) && + (currentSelectionPoint=currentArea->onSelectionPoint(drawStart))) + { + currentAction=MoveSelectionPoint; + } else + if ((currentArea=imageMapEditor->onArea(drawStart))) { + currentAction=MoveArea; + imageMapEditor->select(currentArea); + } else + if (imageMapEditor->currentShapeType()!=Area::None) { + currentArea=new Area(imageMapEditor->currentShapeType()); + currentArea->setRect(QRect(drawStart,drawStart)); + currentArea->setSelected(false); + if (imageMapEditor->selected()) + imageMapEditor->selected()->setSelected(false); + switch (currentArea->type()) { + case Area::Rectangle : currentAction=DrawRectangle; break; + case Area::Circle : currentAction=DrawCircle; break; + case Area::Polygon : + currentAction=DrawPolygon; + currentArea->addCoord(drawStart); + currentSelectionPoint=currentArea->selectionPoints()->last(); + + break; + default: break; + } + } + // Clicked with the arrow at an areafree position + else { + currentArea=0L; + imageMapEditor->deselectAll(); + } + } else + if ( currentAction==DrawPolygon) { + + } + + QRect r; + if (oldArea) + r=oldArea->selectionRect(); + if (currentArea) { + r= r | currentArea->selectionRect(); + repaintContents(translateToZoom(r),false); + } + +} + +void ImageMap::contentsMouseReleaseEvent(QMouseEvent *e) { + drawEnd=e->pos(); + + // Check if it's on picture if not + // move it to the picture's border + if (!imageRect.contains(drawEnd)) { + if (drawEnd.x()>imageRect.right()) + drawEnd.setX(imageRect.right()); + if (drawEnd.x()<imageRect.left()) + drawEnd.setX(imageRect.left()); + if (drawEnd.y()>imageRect.bottom()) + drawEnd.setY(imageRect.bottom()); + if (drawEnd.y()<imageRect.top()) + drawEnd.setY(imageRect.top()); + } + // Translate it to picture coordinates + drawEnd-=imageRect.topLeft(); + drawEnd=translateFromZoom(drawEnd); + + if (currentAction==DrawCircle || currentAction==DrawRectangle) { + imageMapEditor->addArea(currentArea); + imageMapEditor->select(currentArea); + //imageMapEditor->slotAreaChanged(currentArea); + currentAction=None; + } else + if (currentAction==DrawPolygon) { + // If the number of Polygonpoints is more than 2 + // and clicked on the first PolygonPoint or + // the right Button was pressed the Polygon is finished + if ((currentArea->selectionPoints()->count()>2) + && (currentArea->selectionPoints()->first()->contains(drawEnd) + || (e->button()==RightButton))) + { + currentArea->setFinished(true); + imageMapEditor->addArea(currentArea); + currentAction=None; + } else + { + currentArea->addCoord(drawEnd); + currentSelectionPoint=currentArea->selectionPoints()->last(); + } + +// currentArea->addCoord(drawEnd); +// currentSelectionPoint=currentArea->selectionPoints()->last(); + } else + if (currentAction==MoveArea || currentAction==MoveSelectionPoint) { + imageMapEditor->slotAreaChanged(currentArea); + currentAction=None; + } + else { + currentAction=None; + } + imageMapEditor->slotChangeStatusCoords(drawEnd.x(),drawEnd.y()); + imageMapEditor->slotUpdateSelectionCoords(); + + if (currentArea) + repaintArea(*currentArea); +// repaintContents(0,0,contentsWidth(),contentsHeight(),false); +} + + +void ImageMap::contentsMouseMoveEvent(QMouseEvent *e) { + drawCurrent=e->pos(); + + // If outside the image + // set it to the border + if (!imageRect.contains(drawCurrent)) { + if (drawCurrent.x()>imageRect.right()) + drawCurrent.setX(imageRect.right()); + if (drawCurrent.x()<imageRect.left()) + drawCurrent.setX(imageRect.left()); + if (drawCurrent.y()>imageRect.bottom()) + drawCurrent.setY(imageRect.bottom()); + if (drawCurrent.y()<imageRect.top()) + drawCurrent.setY(imageRect.top()); + } + + // Translate to image coordinates + drawCurrent-=imageRect.topLeft(); + drawCurrent=translateFromZoom(drawCurrent); + + if (currentAction==DrawRectangle) { + // To avoid flicker, only repaint the minimum rect + QRect oldRect=translateToZoom(currentArea->rect()); + currentArea->setRect(QRect(drawStart,drawCurrent).normalize()); + QRect newRect=translateToZoom(currentArea->rect()); + QRect r=oldRect | newRect; + repaintContents(r,false); + imageMapEditor->slotUpdateSelectionCoords(currentArea->rect()); + } else + if (currentAction==DrawCircle) { + QRect oldRect=translateToZoom(currentArea->rect()); + currentArea->setRect(QRect(drawStart,drawCurrent).normalize()); + QRect newRect=translateToZoom(currentArea->rect()); + QRect r=oldRect | newRect; + repaintContents(r,false); + imageMapEditor->slotUpdateSelectionCoords(currentArea->rect()); + } else + if ( currentAction==DrawPolygon ) { + QRect oldRect=translateToZoom(currentArea->rect()); + currentArea->moveSelectionPoint(currentSelectionPoint,drawCurrent); + QRect newRect=translateToZoom(currentArea->rect()); + QRect r=oldRect | newRect; + repaintContents(r,false); + imageMapEditor->slotUpdateSelectionCoords(currentArea->rect()); + } else + if ( currentAction==MoveArea ) { + QRect oldRect=translateToZoom(currentArea->selectionRect()); + currentArea->moveBy((drawCurrent-drawStart).x(),(drawCurrent-drawStart).y()); + QRect newRect=translateToZoom(currentArea->selectionRect()); + QRect r=oldRect | newRect; + repaintContents(r,false); + drawStart=drawCurrent; + imageMapEditor->slotUpdateSelectionCoords(); + } else + if ( currentAction==MoveSelectionPoint ) { + QRect oldRect=translateToZoom(currentArea->selectionRect()); + currentArea->moveSelectionPoint(currentSelectionPoint,drawCurrent); + QRect newRect=translateToZoom(currentArea->selectionRect()); + QRect r=oldRect | newRect; + repaintContents(r,false); + imageMapEditor->slotUpdateSelectionCoords(); + } + imageMapEditor->slotChangeStatusCoords(drawCurrent.x(),drawCurrent.y()); +} + +void ImageMap::resizeEvent(QResizeEvent* e) { + QScrollView::resizeEvent(e); + int width=(int) (image.width()*_zoom); + int height=(int) (image.height()*_zoom); + if (visibleWidth()>width) + width=visibleWidth(); + if (visibleHeight()>height) + height=visibleHeight(); + + resizeContents(width,height); + + imageRect.setLeft(0); + imageRect.setTop(0); + imageRect.setHeight(image.height()*_zoom); + imageRect.setWidth(image.width()*_zoom); + +} + +void ImageMap::repaintArea(const Area & a) { + repaintContents(translateToZoom(a.selectionRect()),false); +} + +void ImageMap::drawContents(QPainter* p,int clipx,int clipy,int clipw,int cliph) { +// kdDebug() << "drawing\n" << endl; +// p.scale(rect.width()*2,rect.height()*2); +// if (e->rect()!=rect()) { +// p.setClipping(true); +// p.setClipRect(e->rect()); +// } else +/* if (currentAction==DrawRectangle) { + p->setClipping(true); + QRect r(currentArea->rect()); + r.moveBy(imageRect.left()-5,imageRect.top()-5); + r.setSize(r.size()+QSize(10,10)); + p->setClipRegion(r); + } +*/ + + QRect updateRect(clipx,clipy,clipw,cliph); + QPixmap doubleBuffer(updateRect.size()); // Pixmap for double-buffering + QPainter p2(&doubleBuffer); + p2.drawPixmap(0,0,zoomedImage,clipx,clipy,clipw,cliph); + p2.translate(-updateRect.x(), -updateRect.y()); + p2.scale(_zoom,_zoom); + + AreaList *list=imageMapEditor->areaList(); + for (Area* s=list->first();s != 0L; s=list->next()) + s->draw(p2); + + // Draw the current drawing Area + if (currentAction != MoveArea && + currentAction != MoveSelectionPoint && + currentAction != None) + { + currentArea->draw(p2); + } + + p2.end(); + + // Copy the double buffer into the widget + p->drawPixmap(clipx,clipy,doubleBuffer); + // Erase background without flicker + QRegion region(contentsX(),contentsY(),visibleWidth(),visibleHeight()); + region=region.subtract(QRegion(imageRect)); + for (int i=0;i<region.rects().count();i++) { + p->eraseRect(region.rects()[i]); + } + + + // Draw our picture +// p->drawPixmap(imageRect.left(),imageRect.top(),zoomedImage); +// +// +// p->scale(_zoom,_zoom); +// p->translate(imageRect.left(),imageRect.top()); +// +// AreaList *list=imageMapEditor->areaList(); +// for (Area* s=list->first();s != 0L; s=list->next()) +// s->draw(*p); +// +// // Draw the current drawing Area +// if (currentAction != MoveArea && +// currentAction != MoveSelectionPoint && +// currentAction != None) +// { +// currentArea->draw(*p); +// } + + +} diff --git a/kimagemapeditor/imagemap.h b/kimagemapeditor/imagemap.h new file mode 100644 index 00000000..7576baa0 --- /dev/null +++ b/kimagemapeditor/imagemap.h @@ -0,0 +1,77 @@ +/*************************************************************************** + imagemap.h - description + ------------------- + begin : Wed Apr 4 2001 + copyright : (C) 2001 by Jan Sch�fer + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 IMAGEMAP_H +#define IMAGEMAP_H + +#include <qscrollview.h> +#include <qimage.h> +#include <qpoint.h> +#include <qrect.h> + +#include "kdeversion.h" + +/** + *@author Jan Sch�fer + */ +class KImageMapEditor; +class Area; + +class ImageMap : public QScrollView { +public: + enum DrawAction { None, DrawCircle, DrawRectangle, DrawPolygon, MoveSelectionPoint, MoveArea }; +private: + QRect imageRect; + QPoint drawStart; + QPoint drawCurrent; + QPoint drawEnd; + bool eraseOldArea; + Area *oldArea; + // Holds the original image + QImage image; + // Holds the zoomed image for efficiency reasons + QPixmap zoomedImage; + Area *currentArea; + DrawAction currentAction; + QRect *currentSelectionPoint; + KImageMapEditor *imageMapEditor; + double _zoom; +public: + ImageMap(QWidget *parent,KImageMapEditor* _imageMapEditor); + ~ImageMap(); + void setZoom(double z); + void setPicture(const QImage &_image); + void repaintArea(const Area & a); + QImage picture() const; + QPoint translateFromZoom(const QPoint & p) const; + QPoint translateToZoom(const QPoint & p) const; + QRect translateToZoom(const QRect & p) const; +protected: + virtual void contentsMousePressEvent(QMouseEvent* e); + virtual void contentsMouseDoubleClickEvent(QMouseEvent* e); + virtual void contentsMouseReleaseEvent(QMouseEvent *e); + virtual void contentsMouseMoveEvent(QMouseEvent *e); + virtual void resizeEvent(QResizeEvent* e); + virtual void drawContents(QPainter* p,int clipx,int clipy,int clipw,int cliph); +}; + +inline QImage ImageMap::picture() const { + return image; +} + + +#endif diff --git a/kimagemapeditor/imageslistview.cpp b/kimagemapeditor/imageslistview.cpp new file mode 100644 index 00000000..55992101 --- /dev/null +++ b/kimagemapeditor/imageslistview.cpp @@ -0,0 +1,157 @@ +/*************************************************************************** + imageslistview.cpp - description + ------------------- + begin : Weg Feb 26 2003 + copyright : (C) 2003 by Jan Sch�fer + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +// QT +#include <qptrlist.h> + + +// KDE +#include <klocale.h> +#include <kdebug.h> + +// locale +#include "imageslistview.h" + +ImagesListViewItem::ImagesListViewItem(ImagesListView* parent, ImageTag* tag) + : QListViewItem(parent) +{ + _imageTag = tag; + update(); +} + + +void ImagesListViewItem::update() { + QString src=""; + QString usemap=""; + if (_imageTag->find("src")) + src=*_imageTag->find("src"); + if (_imageTag->find("usemap")) + usemap=*_imageTag->find("usemap"); + + setText(0,src); + setText(1,usemap); +} + +ImageTag* ImagesListViewItem::imageTag() { + return _imageTag; +} + + +ImagesListView::ImagesListView(QWidget *parent, const char *name) + : KListView(parent, name) +{ + addColumn(i18n("Images")); + addColumn(i18n("Usemap")); + //addColumn(i18n("Preview")); + setFullWidth(true); + + + connect( this, SIGNAL( selectionChanged(QListViewItem*)), + this, SLOT( slotSelectionChanged(QListViewItem*))); +} + + +ImagesListView::~ImagesListView() +{ +} + +void ImagesListView::addImage(ImageTag* tag) +{ + if (!tag) { + kdDebug() << "ImageListView::addImage: Parameter is null !" << endl; + return; + } + + new ImagesListViewItem(this, tag); +} + +void ImagesListView::addImages(QPtrList<ImageTag> * images) +{ + for (ImageTag *tag = images->first(); tag!=0L; tag=images->next()) { + addImage(tag); + } +} + +void ImagesListView::clear() { + QListView::clear(); +} + +void ImagesListView::removeImage(ImageTag* tag) { + ImagesListViewItem *item = findListViewItem(tag); + if (item) { + takeItem(item); + setSelected(currentItem(),true); + } + else { + kdDebug() << "ImageListView::removeImage: ListViewItem was not found !" << endl; + } +} + +void ImagesListView::updateImage(ImageTag* tag) { + ImagesListViewItem *item = findListViewItem(tag); + if (item) + item->update(); + else { + kdDebug() << "ImageListView::updateImage: ListViewItem was not found !" << endl; + } +} + +ImagesListViewItem* ImagesListView::findListViewItem(ImageTag* tag) { + + kdDebug() << "ImageListView::findListViewItem: start searching ... " << endl; + + for (QListViewItem* item = firstChild(); item ; item = item->nextSibling()) { + ImagesListViewItem *imageItem = static_cast<ImagesListViewItem*>(item); + if (imageItem->imageTag() == tag) { + kdDebug() << "ImageListView::findListViewItem: found it " << endl; + + return imageItem; + } + } + + kdDebug() << "ImageListView::findListViewItem: found nothing " << endl; + return 0L; + +} + +void ImagesListView::slotSelectionChanged(QListViewItem* item) { + QString src = item->text(0); + + emit imageSelected(KURL(_baseUrl,src)); +} + +ImageTag* ImagesListView::selectedImage() { + ImagesListViewItem* item = static_cast<ImagesListViewItem*>(selectedItem()); + if ( ! item) { + kdDebug() << "ImagesListView::selectedImage: No Image is selected !" << endl; + return 0L; + } + + return item->imageTag(); + + +} + +void ImagesListView::selectImage(ImageTag* tag) { + ImagesListViewItem* item = findListViewItem(tag); + if (item) { + setSelected(item, true); + } +} + +#include "imageslistview.moc" + diff --git a/kimagemapeditor/imageslistview.h b/kimagemapeditor/imageslistview.h new file mode 100644 index 00000000..55680405 --- /dev/null +++ b/kimagemapeditor/imageslistview.h @@ -0,0 +1,111 @@ +/*************************************************************************** + imageslistview.h - description + ------------------- + begin : Weg Feb 26 2003 + copyright : (C) 2003 by Jan Sch�fer + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 _IMAGESLISTVIEW_H_ +#define _IMAGESLISTVIEW_H_ + +#include <klistview.h> +#include <kurl.h> + +#include "kimagemapeditor.h" + +class ImagesListView; + +class ImagesListViewItem : public QListViewItem +{ + public: + ImagesListViewItem(ImagesListView*, ImageTag*); + ImageTag* imageTag(); + + /** + * Re-reads the contents of the ImageTag and updates + * itself accordingly + */ + void update(); + protected: + ImageTag* _imageTag; +}; + +/** + * Simple class that shows a list of imagenames with a preview + * Jan Schaefer + **/ +class ImagesListView : public KListView +{ + Q_OBJECT + +public: + ImagesListView(QWidget *parent, const char *name); + virtual ~ImagesListView(); + + /** + * Adds an image + */ + void addImage(ImageTag*); + + /** + * Adds images + */ + void addImages(QPtrList<ImageTag> *); + + /** + * Removes the given image from the list + */ + void removeImage(ImageTag*); + + /** + * Updates the listview item with the given ImageTag + */ + void updateImage(ImageTag*); + + /** + * Removes all images + */ + void clear(); + + /** + * Returns the filename of the current selected Image + */ + ImageTag* selectedImage(); + + /** + * Selects the given image + */ + void selectImage(ImageTag*); + + /** + * Sets the base URL of all images + */ + void setBaseUrl(const KURL & url) { _baseUrl = url; }; + +protected slots: + void slotSelectionChanged(QListViewItem*); + +signals: + void imageSelected(const KURL &); + +protected: + KURL _baseUrl; + + /** + * Finds the first ImageListViewItem with the given ImageTag + * Returns 0L if no item was found + */ + ImagesListViewItem* findListViewItem(ImageTag*); +}; + +#endif diff --git a/kimagemapeditor/kimagemapeditor.cpp b/kimagemapeditor/kimagemapeditor.cpp new file mode 100644 index 00000000..ebfb0c7f --- /dev/null +++ b/kimagemapeditor/kimagemapeditor.cpp @@ -0,0 +1,2819 @@ +/*************************************************************************** + imagemapeditor.cpp - description + ------------------- + begin : Wed Apr 4 2001 + copyright : (C) 2001 by Jan Sch�er + email : [email protected] +***************************************************************************/ + +/*************************************************************************** +* * +* 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 <iostream> +#include <assert.h> + +// QT +#include <qlayout.h> +#include <qlistview.h> +#include <qpushbutton.h> +#include <qvbox.h> +#include <qpixmap.h> +#include <qcombobox.h> +#include <qsplitter.h> +#include <qfileinfo.h> +#include <qmultilineedit.h> +#include <qtextstream.h> +#include <qpopupmenu.h> +#include <qdict.h> +#include <qwhatsthis.h> +#include <qtooltip.h> +#include <qpainter.h> +#include <qtabwidget.h> +#include <qfontdatabase.h> +#include <qfile.h> + +// KDE +#include <kcommand.h> +#include <kdebug.h> +#include <klocale.h> +#include <kaction.h> +#include <kaccel.h> +#include <kstdaction.h> +#include <kiconloader.h> +#include <kfiledialog.h> +#include <kmessagebox.h> +#include <kapplication.h> +#include <kkeydialog.h> +#include <kedittoolbar.h> +#include <klineeditdlg.h> +#include <kglobal.h> +#include <kstandarddirs.h> +#include <kstatusbar.h> +#include <kxmlguifactory.h> +#include <kdockwidget.h> +#include <kio/job.h> +#if KDE_IS_VERSION(3,1,90) +#include <kinputdialog.h> +#else +#include <qinputdialog.h> +#endif + +// local +#include "kimagemapeditor.h" +#include "kimagemapeditor.moc" +#include "drawzone.h" +#include "kimedialogs.h" +#include "kimecommands.h" +#include "qextfileinfo.h" +#include "areacreator.h" +#include "arealistview.h" +#include "imageslistview.h" +#include "mapslistview.h" +#include "kimecommon.h" + +#include <kparts/genericfactory.h> +#include <kinstance.h> + +// Factory code for KDE 3 +typedef KParts::GenericFactory<KImageMapEditor> KimeFactory; +K_EXPORT_COMPONENT_FACTORY( libkimagemapeditor , KimeFactory ) + +KImageMapEditor::KImageMapEditor(QWidget *parentWidget, const char *, + QObject *parent, const char *name, const QStringList & ) + : KParts::ReadWritePart(parent,name) +{ + setInstance( KimeFactory::instance() ); + +// KDockMainWindow* mainWidget; + + // Test if the MainWindow can handle DockWindows, if so create DockWidgets + // instead of a Splitter + mainDock = dynamic_cast<KDockMainWindow*>(parent) ; + QSplitter * splitter = 0L; + tabWidget = 0L; + + if (mainDock) { +// kdDebug() << "KImageMapEditor: We got a KDockMainWindow !" << endl; + + KDockWidget* parentDock = mainDock->getMainDockWidget(); + areaDock = mainDock->createDockWidget( "Areas", 0L, 0L, i18n("Areas"), i18n("Areas")); + mapsDock = mainDock->createDockWidget( "Maps", 0L, 0L, i18n("Maps"), i18n("Maps")); + imagesDock = mainDock->createDockWidget( "Images", 0L, 0L, i18n("Images"), i18n("Images")); + + areaListView = new AreaListView(areaDock,"AreaListView"); + mapsListView = new MapsListView(mapsDock, "MapsListView"); + imagesListView = new ImagesListView(imagesDock, "ImagesListView"); + + areaDock->setWidget(areaListView); + mapsDock->setWidget(mapsListView); + imagesDock->setWidget(imagesListView); + + areaDock->manualDock( (KDockWidget*) parentDock, KDockWidget::DockLeft, 30); + mapsDock->manualDock( (KDockWidget*) areaDock, KDockWidget::DockCenter); + imagesDock->manualDock( (KDockWidget*) mapsDock, KDockWidget::DockCenter); + + connect( mainDock->manager(), SIGNAL(change()), this, SLOT(dockingStateChanged())); + } + else + { + areaDock = 0L; + mapsDock = 0L; + imagesDock = 0L; + splitter = new QSplitter(parentWidget); + tabWidget = new QTabWidget(splitter); + areaListView = new AreaListView(tabWidget,"AreaListView"); + mapsListView = new MapsListView(tabWidget, "MapsListView"); + imagesListView = new ImagesListView(tabWidget, "ImagesListView"); + + tabWidget->addTab(areaListView,i18n("Areas")); + tabWidget->addTab(mapsListView,i18n("Maps")); + tabWidget->addTab(imagesListView,i18n("Images")); + } + + + connect( areaListView->listView, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged())); + connect( areaListView->listView, SIGNAL(doubleClicked(QListViewItem*)), this, SLOT(showTagEditor(QListViewItem*))); + connect( areaListView->listView, SIGNAL(rightButtonPressed(QListViewItem*,const QPoint &,int)), this, + SLOT(slotShowPopupMenu(QListViewItem*,const QPoint &))); + + connect( mapsListView, SIGNAL( mapSelected(const QString &)), + this, SLOT( setMap(const QString &))); + + connect( mapsListView, SIGNAL( mapRenamed(const QString &)), + this, SLOT( setMapName(const QString &))); + + connect( mapsListView->listView(), SIGNAL(rightButtonPressed(QListViewItem*,const QPoint &,int)), this, + SLOT(slotShowMapPopupMenu(QListViewItem*,const QPoint &))); + + connect( imagesListView, SIGNAL( imageSelected(const KURL &)), + this, SLOT( setPicture(const KURL &))); + + connect( imagesListView, SIGNAL(rightButtonPressed(QListViewItem*,const QPoint &,int)), this, + SLOT(slotShowImagePopupMenu(QListViewItem*,const QPoint &))); + + // Shows the text: + // "Drop an image or html file" +/* QString path = KGlobal::dirs()->findResourceDir( "data", "kimagemapeditor/dropimage.png" ) + "kimagemapeditor/dropimage.png"; + if ( ! QFileInfo(path).exists() ) { + kdError() << "Couldn't find needed dropimage.png file in " + "the data directory of KImageMapEditor.\n" + "Perhaps you have forgotten to do a make install !" << endl; + exit(1); + } +*/ + + if (splitter) { + drawZone = new DrawZone(splitter,this); + splitter->setResizeMode(drawZone,QSplitter::Stretch); + splitter->setResizeMode(tabWidget,QSplitter::KeepSize); + setWidget(splitter); + } else { + drawZone = new DrawZone(parentWidget,this); + setWidget(drawZone); + } + + + areas = new AreaList(); + currentSelected= new AreaSelection(); + _currentToolType=KImageMapEditor::Selection; + copyArea=0L; + defaultArea=0L; + currentMapElement = 0L; + + setupActions(); + setupStatusBar(); + + setXMLFile("kimagemapeditorpartui.rc"); + + setPicture(getBackgroundImage()); + _htmlContent.setAutoDelete(true); + + init(); + readConfig(); +} + +KImageMapEditor::~KImageMapEditor() { + writeConfig(); + + #if KDE_VERSION < 300 + delete accel; + #endif + delete areas; + + delete currentSelected; + delete copyArea; + delete defaultArea; + + // Delete our DockWidgets + if (areaDock) { + areaDock->hide(); + mapsDock->hide(); + imagesDock->hide(); + + delete areaDock; + delete mapsDock; + delete imagesDock; + } + +} + +MapTag::MapTag() { + modified = false; + name = QString::null; +} + +void KImageMapEditor::init() +{ + _htmlContent.clear(); + _imageUrl = QString::null; + m_url = QString::null; + HtmlElement* el = new HtmlElement("<html>\n"); + _htmlContent.append(el); + el = new HtmlElement("<head>\n"); + _htmlContent.append(el); + el = new HtmlElement("</head>\n"); + _htmlContent.append(el); + el = new HtmlElement("<body>\n"); + _htmlContent.append(el); + + addMap(i18n("unnamed")); + + el = new HtmlElement("</body>\n"); + _htmlContent.append(el); + el = new HtmlElement("</html>\n"); + _htmlContent.append(el); + + setImageActionsEnabled(false); +} + +KAboutData* KImageMapEditor::createAboutData() +{ + KAboutData* aboutData = + new KAboutData( "kimagemapeditor", I18N_NOOP("KImageMapEditor"), + "1.0", I18N_NOOP( "An HTML imagemap editor" ), + KAboutData::License_GPL, + "(c) 2001-2003 Jan Schäfer <[email protected]>"); + return aboutData; +} + + +void KImageMapEditor::setReadWrite(bool) +{ + + // For now it doesn't matter if its readwrite or readonly + // it is always readwrite, because Quanta only supports ReadOnlyParts + // at this moment and in that case it should be readwrite, too. + ReadWritePart::setReadWrite(true); + /* + if (rw) + ; + else + { + actionCollection()->remove(arrowAction); + actionCollection()->remove(circleAction); + actionCollection()->remove(rectangleAction); + actionCollection()->remove(polygonAction); + actionCollection()->remove(freehandAction); + actionCollection()->remove(addPointAction); + actionCollection()->remove(removePointAction); + + actionCollection()->remove(cutAction); + actionCollection()->remove(deleteAction); + actionCollection()->remove(copyAction); + actionCollection()->remove(pasteAction); + + actionCollection()->remove(mapNewAction); + actionCollection()->remove(mapDeleteAction); + actionCollection()->remove(mapNameAction); + actionCollection()->remove(mapDefaultAreaAction); + + actionCollection()->remove(areaPropertiesAction); + + actionCollection()->remove(moveLeftAction); + actionCollection()->remove(moveRightAction); + actionCollection()->remove(moveUpAction); + actionCollection()->remove(moveDownAction); + + actionCollection()->remove(increaseWidthAction); + actionCollection()->remove(decreaseWidthAction); + actionCollection()->remove(increaseHeightAction); + actionCollection()->remove(decreaseHeightAction); + + actionCollection()->remove(toFrontAction); + actionCollection()->remove(toBackAction); + actionCollection()->remove(forwardOneAction); + actionCollection()->remove(backOneAction); + + actionCollection()->remove(imageRemoveAction); + actionCollection()->remove(imageAddAction); + actionCollection()->remove(imageUsemapAction); + + } + */ + +} + +void KImageMapEditor::setModified(bool modified) +{ + // get a handle on our Save action and make sure it is valid + KAction *save = actionCollection()->action(KStdAction::stdName(KStdAction::Save)); + if (!save) + return; + + // if so, we either enable or disable it based on the current + // state + if (modified) + save->setEnabled(true); + else + save->setEnabled(false); + + // in any event, we want our parent to do it's thing + ReadWritePart::setModified(modified); +} + + +KConfig *KImageMapEditor::config() +{ + return KimeFactory::instance()->config(); +} + +void KImageMapEditor::readConfig(KConfig* config) { + recentFilesAction->loadEntries(config,"Data"); +} + +void KImageMapEditor::writeConfig(KConfig* config) { + config->writeEntry("highlightareas",highlightAreasAction->isChecked()); + config->writeEntry("showalt",showAltAction->isChecked()); + recentFilesAction->saveEntries(config,"Data"); + saveLastURL(config); + +} + +void KImageMapEditor::readConfig() { + config()->setGroup("General Options"); + readConfig(config()); + slotConfigChanged(); +} + +void KImageMapEditor::writeConfig() { + config()->setGroup("General Options"); + writeConfig(config()); + config()->sync(); +} + + +void KImageMapEditor::saveProperties(KConfig *config) +{ + saveLastURL(config); +} + +void KImageMapEditor::readProperties(KConfig * config) +{ + openLastURL(config); +} + +void KImageMapEditor::slotConfigChanged() +{ + config()->setGroup("Appearance"); + int newHeight=config()->readNumEntry("maximum-preview-height",50); + config()->setGroup("General Options"); + _commandHistory->setUndoLimit(config()->readNumEntry("undo-level",20)); + _commandHistory->setRedoLimit(config()->readNumEntry("redo-level",20)); + Area::highlightArea = config()->readBoolEntry("highlightareas",true); + highlightAreasAction->setChecked(Area::highlightArea); + Area::showAlt = config()->readBoolEntry("showalt",true); + showAltAction->setChecked(Area::showAlt); + + // if the image preview size changed update all images + if (maxAreaPreviewHeight!=newHeight) { + maxAreaPreviewHeight=newHeight; + } + + updateAllAreas(); + drawZone->viewport()->repaint(); +} + +void KImageMapEditor::openLastURL(KConfig* config) { + KURL lastURL ( config->readPathEntry("lastopenurl") ); + QString lastMap = config->readEntry("lastactivemap"); + QString lastImage = config->readPathEntry("lastactiveimage"); + + +// kdDebug() << "loading from group : " << config->group() << endl; + +// kdDebug() << "loading entry lastopenurl : " << lastURL.path() << endl; +// KMessageBox::information(0L, config->group()+" "+lastURL.path()); + if (!lastURL.isEmpty()) { +// kdDebug() << "opening HTML file with map " << lastMap << " and image " << lastImage << endl; + if ( openHTMLFile(lastURL, lastMap, lastImage) ) + m_url = lastURL; + else + m_url = QString::null; + } +} + +void KImageMapEditor::saveLastURL(KConfig* config) { + config->writePathEntry("lastopenurl",url().path()); + config->writeEntry("lastactivemap",mapName()); + config->writePathEntry("lastactiveimage",_imageUrl.path()); +// kdDebug() << "writing entry lastopenurl : " << url().path() << endl; +// kdDebug() << "writing entry lastactivemap : " << mapName() << endl; +// kdDebug() << "writing entry lastactiveimage : " << _imageUrl.path() << endl; + //KMessageBox::information(0L, QString("Group: %1 Saving ... %2").arg(config->group()).arg(url().path())); +} + +void KImageMapEditor::setupActions() +{ + // File Open + KAction *temp=KStdAction::open(this, SLOT(fileOpen()), actionCollection()); + QMimeSourceFactory::defaultFactory()->setPixmap( "openimage", SmallIcon("fileopen") ); + temp->setWhatsThis(i18n("<h3>Open File</h3>Click this to <em>open</em> a new picture or HTML file.")); + temp->setToolTip(i18n("Open new picture or HTML file")); + + // File Open Recent + recentFilesAction = KStdAction::openRecent(this, SLOT(openURL(const KURL&)), + actionCollection()); + // File Save + temp =KStdAction::save(this, SLOT(fileSave()), actionCollection()); + QMimeSourceFactory::defaultFactory()->setPixmap( "saveimage", SmallIcon("filesave") ); + temp->setWhatsThis(i18n("<h3>Save File</h3>Click this to <em>save</em> the changes to the HTML file.")); + temp->setToolTip(i18n("Save HTML file")); + + + // File Save As + (void)KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection()); + + // File Close + temp=KStdAction::close(this, SLOT(fileClose()), actionCollection()); + QMimeSourceFactory::defaultFactory()->setPixmap( "closeimage", SmallIcon("fileclose") ); + temp->setWhatsThis(i18n("<h3>Close File</h3>Click this to <em>close</em> the currently open HTML file.")); + temp->setToolTip(i18n("Close HTML file")); + + // Edit Copy + copyAction=KStdAction::copy(this, SLOT(slotCopy()), actionCollection()); + QMimeSourceFactory::defaultFactory()->setPixmap( "editcopyimage", SmallIcon("editcopy") ); + copyAction->setWhatsThis(i18n("<h3>Copy</h3>" + "Click this to <em>copy</em> the selected area.")); + copyAction->setEnabled(false); + + // Edit Cut + cutAction=KStdAction::cut(this, SLOT(slotCut()), actionCollection()); + QMimeSourceFactory::defaultFactory()->setPixmap( "editcutimage", SmallIcon("editcut") ); + cutAction->setWhatsThis(i18n("<h3>Cut</h3>" + "Click this to <em>cut</em> the selected area.")); + cutAction->setEnabled(false); + + // Edit Paste + pasteAction=KStdAction::paste(this, SLOT(slotPaste()), actionCollection()); + QMimeSourceFactory::defaultFactory()->setPixmap( "editpasteimage", SmallIcon("editpaste") ); + pasteAction->setWhatsThis(i18n("<h3>Paste</h3>" + "Click this to <em>paste</em> the copied area.")); + pasteAction->setEnabled(false); + + + // Edit Delete + deleteAction=new KAction(i18n("&Delete"), "editdelete", + Key_Delete,this,SLOT (slotDelete()),actionCollection(), "edit_delete"); + QMimeSourceFactory::defaultFactory()->setPixmap( "editdeleteimage", SmallIcon("editdelete") ); + deleteAction->setWhatsThis(i18n("<h3>Delete</h3>" + "Click this to <em>delete</em> the selected area.")); + deleteAction->setEnabled(false); + + // Edit Undo/Redo + _commandHistory = new KCommandHistory( actionCollection(), true); + + // Edit Properties + areaPropertiesAction= new KAction(i18n("Pr&operties"),0,this,SLOT(showTagEditor()), + actionCollection(), "edit_properties"); + areaPropertiesAction->setEnabled(false); + + // View Zoom In + zoomInAction=KStdAction::zoomIn(this, SLOT(slotZoomIn()), actionCollection()); + // View Zoom Out + zoomOutAction=KStdAction::zoomOut(this, SLOT(slotZoomOut()), actionCollection()); + + // View Zoom + zoomAction=new KSelectAction(i18n("Zoom"), 0,this,SLOT (slotZoom()), + actionCollection(), "view_zoom"); + zoomAction->setWhatsThis(i18n("<h3>Zoom</h3>" + "Choose the desired zoom level.")); + zoomAction->setItems(QStringList() + << i18n("25%") + << i18n("50%") + << i18n("100%") + << i18n("150%") + << i18n("200%") + << i18n("250%") + << i18n("300%") + << i18n("500%") + << i18n("750%") + << i18n("1000%")); + + zoomAction->setCurrentItem(2); + + highlightAreasAction = new KToggleAction(i18n("Highlight Areas"),0, this, SLOT (slotHightlightAreas()), + actionCollection(), "view_highlightareas"); + + showAltAction = new KToggleAction(i18n("Show Alt Tag"),0, this, SLOT (slotShowAltTag()), + actionCollection(), "view_showalt"); +#if KDE_IS_VERSION(3,2,90) + showAltAction->setCheckedState(i18n("Hide Alt Tag")); +#endif + + mapNameAction= new KAction(i18n("Map &Name..."),0,this,SLOT(mapEditName()), + actionCollection(), "map_name"); + + mapNewAction = new KAction(i18n("Ne&w Map..."),0,this,SLOT(mapNew()), + actionCollection(), "map_new"); + mapNewAction->setToolTip(i18n("Create a new map")); + + mapDeleteAction = new KAction(i18n("D&elete Map"),0,this,SLOT(mapDelete()), + actionCollection(), "map_delete"); + mapDeleteAction->setToolTip(i18n("Delete the current active map")); + + mapDefaultAreaAction = new KAction(i18n("Edit &Default Area..."),0,this,SLOT(mapDefaultArea()), + actionCollection(), "map_defaultarea"); + mapDefaultAreaAction->setToolTip(i18n("Edit the default area of the current active map")); + + temp = new KAction(i18n("&Preview"),0,this,SLOT(mapPreview()), + actionCollection(), "map_preview"); + temp->setToolTip(i18n("Show a preview")); + + // IMAGE + i18n("&Image"); + + imageAddAction = new KAction(i18n("Add Image..."),0,this,SLOT(imageAdd()), + actionCollection(), "image_add"); + imageAddAction->setToolTip(i18n("Add a new image")); + + imageRemoveAction = new KAction(i18n("Remove Image"),0,this,SLOT(imageRemove()), + actionCollection(), "image_remove"); + imageRemoveAction->setToolTip(i18n("Remove the current visible image")); + + imageUsemapAction = new KAction(i18n("Edit Usemap..."),0,this,SLOT(imageUsemap()), + actionCollection(), "image_usemap"); + imageUsemapAction->setToolTip(i18n("Edit the usemap tag of the current visible image")); + + temp= new KAction(i18n("Show &HTML"),0,this,SLOT(mapShowHTML()), + actionCollection(), "map_showhtml"); + + + // Selection Tool + arrowAction=new KRadioAction(i18n("&Selection"), "arrow", + 0,this,SLOT (slotDrawArrow()), + actionCollection(), "tool_arrow"); + QMimeSourceFactory::defaultFactory()->setPixmap( "arrowimage", SmallIcon("arrow") ); + arrowAction->setWhatsThis(i18n("<h3>Selection</h3>" + "Click this to select areas.")); + arrowAction->setExclusiveGroup("drawing"); + arrowAction->setChecked(true); + + // Circle + circleAction=new KRadioAction(i18n("&Circle"), "circle", + 0,this,SLOT (slotDrawCircle()), + actionCollection(), "tool_circle"); + QMimeSourceFactory::defaultFactory()->setPixmap( "circleimage", SmallIcon("drawcircle") ); + circleAction->setWhatsThis(i18n("<h3>Circle</h3>" + "Click this to start drawing a circle.")); + circleAction->setExclusiveGroup("drawing"); + + // Rectangle + rectangleAction=new KRadioAction(i18n("&Rectangle"), "rectangle", + 0,this,SLOT (slotDrawRectangle()), + actionCollection(), "tool_rectangle"); + QMimeSourceFactory::defaultFactory()->setPixmap( "rectangleimage", SmallIcon("drawrectangle") ); + rectangleAction->setWhatsThis(i18n("<h3>Rectangle</h3>" + "Click this to start drawing a rectangle.")); + rectangleAction->setExclusiveGroup("drawing"); + + // Polygon + polygonAction=new KRadioAction(i18n("&Polygon"), "polygon", + 0,this,SLOT (slotDrawPolygon()), + actionCollection(), "tool_polygon"); + QMimeSourceFactory::defaultFactory()->setPixmap( "polygonimage", SmallIcon("drawpolygon") ); + polygonAction->setWhatsThis(i18n("<h3>Polygon</h3>" + "Click this to start drawing a polygon.")); + polygonAction->setExclusiveGroup("drawing"); + + // Freehand + freehandAction=new KRadioAction(i18n("&Freehand Polygon"), "freehand", + 0,this,SLOT (slotDrawFreehand()), + actionCollection(), "tool_freehand"); + QMimeSourceFactory::defaultFactory()->setPixmap( "freehandimage", SmallIcon("freehand") ); + freehandAction->setWhatsThis(i18n("<h3>Freehandpolygon</h3>" + "Click this to start drawing a freehand polygon.")); + freehandAction->setExclusiveGroup("drawing"); + + // Add Point + addPointAction=new KRadioAction(i18n("&Add Point"), "addpoint", + 0,this,SLOT (slotDrawAddPoint()), + actionCollection(), "tool_addpoint"); + QMimeSourceFactory::defaultFactory()->setPixmap( "addpointimage", SmallIcon("addpoint") ); + addPointAction->setWhatsThis(i18n("<h3>Add Point</h3>" + "Click this to add points to a polygon.")); + addPointAction->setExclusiveGroup("drawing"); + + // Remove Point + removePointAction=new KRadioAction(i18n("&Remove Point"), "removepoint", + 0,this,SLOT (slotDrawRemovePoint()), + actionCollection(), "tool_removepoint"); + QMimeSourceFactory::defaultFactory()->setPixmap( "removepointimage", SmallIcon("removepoint") ); + removePointAction->setWhatsThis(i18n("<h3>Remove Point</h3>" + "Click this to remove points from a polygon.")); + removePointAction->setExclusiveGroup("drawing"); + +#if KDE_VERSION < 300 + KAction *cancelAction = +#endif + new KAction(i18n("Cancel Drawing"), Key_Escape, this, SLOT( slotCancelDrawing() ), + actionCollection(), "canceldrawing" ); + + moveLeftAction = new KAction(i18n("Move Left"), Key_Left, this, SLOT( slotMoveLeft() ), + actionCollection() , "moveleft" ); + + moveRightAction = new KAction(i18n("Move Right"), Key_Right, this, SLOT( slotMoveRight() ), + actionCollection() , "moveright" ); + + moveUpAction = new KAction(i18n("Move Up"), Key_Up, this, SLOT( slotMoveUp() ), + actionCollection() , "moveup" ); + + moveDownAction = new KAction(i18n("Move Down"), Key_Down, this, SLOT( slotMoveDown() ), + actionCollection() , "movedown" ); + + increaseWidthAction = new KAction(i18n("Increase Width"), Key_Right + SHIFT, this, SLOT( slotIncreaseWidth() ), + actionCollection() , "increasewidth" ); + + decreaseWidthAction = new KAction(i18n("Decrease Width"), Key_Left + SHIFT, this, SLOT( slotDecreaseWidth() ), + actionCollection() , "decreasewidth" ); + + increaseHeightAction = new KAction(i18n("Increase Height"), Key_Up + SHIFT, this, SLOT( slotIncreaseHeight() ), + actionCollection() , "increaseheight" ); + + decreaseHeightAction = new KAction(i18n("Decrease Height"), Key_Down + SHIFT, this, SLOT( slotDecreaseHeight() ), + actionCollection() , "decreaseheight" ); +#if KDE_VERSION < 300 + accel = new KAccel(widget()); + cancelAction->plugAccel(accel, true); + moveLeftAction->plugAccel(accel, true); + moveRightAction->plugAccel(accel, true); + moveUpAction->plugAccel(accel, true); + moveDownAction->plugAccel(accel, true); + increaseWidthAction->plugAccel(accel, true); + decreaseWidthAction->plugAccel(accel, true); + increaseHeightAction->plugAccel(accel, true); + decreaseHeightAction->plugAccel(accel, true); +#endif + + toFrontAction = new KAction(i18n("Bring to Front"), 0 , this, SLOT( slotToFront() ), + actionCollection() , "tofront" ); + + toBackAction = new KAction(i18n("Send to Back"), 0 , this, SLOT( slotToBack() ), + actionCollection() , "toback" ); + + forwardOneAction = new KAction(i18n("Bring Forward One"), "raise" ,0, this, SLOT( slotForwardOne() ), + actionCollection() , "forwardone" ); + backOneAction = new KAction(i18n("Send Back One"), "lower" ,0, this, SLOT( slotBackOne() ), + actionCollection() , "backone" ); + + forwardOneAction->plug(areaListView->upBtn); + backOneAction->plug(areaListView->downBtn); + + connect( areaListView->upBtn, SIGNAL(pressed()), forwardOneAction, SLOT(activate())); + connect( areaListView->downBtn, SIGNAL(pressed()), backOneAction, SLOT(activate())); + + new KAction( i18n("Configure KImageMapEditor..."), "configure", 0, + this, SLOT(slotShowPreferences()), + actionCollection(), "configure_kimagemapeditor" ); + + if (areaDock) { + configureShowAreaListAction = new KToggleAction( i18n("Show Area List"), 0L, 0, + this, SLOT(configureShowAreaList()), + actionCollection(), "configure_show_arealist" ); + + configureShowMapListAction = new KToggleAction( i18n("Show Map List"), 0L, 0, + this, SLOT(configureShowMapList()), + actionCollection(), "configure_show_maplist" ); + + configureShowImageListAction = new KToggleAction( i18n("Show Image List"), 0L, 0, + this, SLOT(configureShowImageList()), + actionCollection(), "configure_show_imagelist" ); +#if KDE_IS_VERSION(3,2,90) + configureShowAreaListAction->setCheckedState(i18n("Hide Area List")); + configureShowMapListAction->setCheckedState(i18n("Hide Map List")); + configureShowImageListAction->setCheckedState(i18n("Hide Image List")); +#endif + } + + updateActionAccess(); +} + +void KImageMapEditor::setupStatusBar() +{ + +// We can't do this with a KPart ! +// widget()->statusBar()->insertItem(i18n(" Cursor")+" : x: 0 ,y: 0",STATUS_CURSOR); +// widget()->statusBar()->insertItem(i18n(" Selection")+" : - ",STATUS_SELECTION); + emit setStatusBarText( i18n(" Selection: - Cursor: x: 0, y: 0 ")); +} + +void KImageMapEditor::slotShowPreferences() +{ + PreferencesDialog *dialog = new PreferencesDialog(widget(),config()); + connect(dialog, SIGNAL(applyClicked()), this, SLOT(slotConfigChanged())); + dialog->exec(); + delete dialog; +} + + +void KImageMapEditor::showPopupMenu(const QPoint & pos, const QString & name) +{ + QPopupMenu* pop = static_cast<QPopupMenu *>(factory()->container(name, this)); + + if (!pop) { + kdWarning() << QString("KImageMapEditorPart: Missing XML definition for %1\n").arg(name) << endl; + return; + } + + pop->popup(pos); +} + +void KImageMapEditor::slotShowMainPopupMenu(const QPoint & pos) +{ + showPopupMenu(pos,"popup_main"); +} + +void KImageMapEditor::slotShowMapPopupMenu(QListViewItem* item,const QPoint & pos) +{ + if (isReadWrite()) { + mapDeleteAction->setEnabled(item); + mapNameAction->setEnabled(item); + mapDefaultAreaAction->setEnabled(item); + } + + if (item) + mapsListView->selectMap(item); + + showPopupMenu(pos,"popup_map"); +} + +void KImageMapEditor::slotShowImagePopupMenu(QListViewItem* item,const QPoint & pos) +{ + imageRemoveAction->setEnabled(item); + imageUsemapAction->setEnabled(item); + + if (item) + imagesListView->setSelected(item,true); + + showPopupMenu(pos,"popup_image"); +} + +void KImageMapEditor::slotShowPopupMenu(QListViewItem* item,const QPoint & p) +{ + if (!item) + return; + + if (!item->isSelected()) + { + deselectAll(); + select(item); + } + + slotShowMainPopupMenu(p); +} + +void KImageMapEditor::updateStatusBar() +{ + emit setStatusBarText(selectionStatusText+" "+cursorStatusText); +} + +void KImageMapEditor::slotChangeStatusCoords(int x,int y) +{ +// statusBar()->changeItem(QString(" Cursor : x: %1 ,y: %2 ").arg(x).arg(y),STATUS_CURSOR); + cursorStatusText = i18n(" Cursor: x: %1, y: %2 ").arg(x).arg(y); + updateStatusBar(); +} + +void KImageMapEditor::slotUpdateSelectionCoords() { + if (selected()->count()>0) { + QRect r=selected()->rect(); +// statusBar()->changeItem( + selectionStatusText = i18n(" Selection: x: %1, y: %2, w: %3, h: %4 ").arg(r.left()).arg(r.top()).arg(r.width()).arg(r.height()); + +// ,STATUS_SELECTION); + kapp->processEvents(); + } else + selectionStatusText = i18n(" Selection: - "); + //statusBar()->changeItem(" Selection : - ",STATUS_SELECTION); + + updateStatusBar(); +} + +void KImageMapEditor::slotUpdateSelectionCoords( const QRect & r ) +{ + selectionStatusText = i18n(" Selection: x: %1, y: %2, w: %3, h: %4 ").arg(r.left()).arg(r.top()).arg(r.width()).arg(r.height()); + updateStatusBar(); + kapp->processEvents(); +} + +KApplication* KImageMapEditor::app() const +{ + return kapp; +} + + +void KImageMapEditor::drawToCenter(QPainter* p, const QString & str, int y, int width) { + int xmid = width / 2; + + QFontMetrics fm = p->fontMetrics(); + QRect strBounds = fm.boundingRect(str); + + p->drawText(xmid-(strBounds.width()/2),y,str); +} + + +QImage KImageMapEditor::getBackgroundImage() { + + // Lazy initialisation + if ( _backgroundImage.isNull() ) { + + +// QString filename = QString("dropimage_")+KGlobal::locale()->language()+".png"; +// QString path = QString::null; //KGlobal::dirs()->findResourceDir( "data", "kimagemapeditor/"+filename ) + "kimagemapeditor/"+filename; +// kdDebug() << "getBackgroundPic : loaded image : " << path << endl; + +// if ( ! QFileInfo(path).exists() ) { + int width = 400; + int height = 400; + int border = 20; + int fontSize = 58; + + QPixmap pix(width,height); + pix.fill(QColor(74,76,74)); + QPainter p(&pix); + + QFont font; + font.setFamily("Sans"); + font.setPixelSize(fontSize); + font.setBold(true); + p.setFont( font ); + + p.setRasterOp(Qt::CopyROP); + p.setPen(QPen(QColor(112,114,112),1)); + + // The translated string must be divided into + // parts with about the same size that fit to the image + QString str = i18n("Drop an image or HTML file"); + QStringList strList = QStringList::split(" ",str); + + // Get the string parts + QString tmp; + QStringList outputStrList; + QFontMetrics fm = p.fontMetrics(); + + for ( QStringList::Iterator it = strList.begin(); it != strList.end(); ++it ) { + QString tmp2 = tmp + *it; + + if (fm.boundingRect(tmp2).width() > width-border) { + outputStrList.append(tmp); + tmp = *it + " "; + } + else + tmp = tmp2 + " "; + } + + // Last one was forgotten so add it. + outputStrList.append(tmp); + + // Try to adjust the text vertically centered + int step = myround(float(height) / (outputStrList.size()+1)); + int y = step; + + for ( QStringList::Iterator it = outputStrList.begin(); it != outputStrList.end(); ++it ) { + drawToCenter(&p, *it, y, pix.width()); + y += step; + } + + p.end(); + + _backgroundImage = pix.convertToImage(); + } + + + return _backgroundImage; + +/* + QFontDatabase fdb; + QStringList families = fdb.families(); + for ( QStringList::Iterator f = families.begin(); f != families.end(); ++f ) { + QString family = *f; + qDebug( family ); + QStringList styles = fdb.styles( family ); + for ( QStringList::Iterator s = styles.begin(); s != styles.end(); ++s ) { + QString style = *s; + QString dstyle = "\t" + style + " ("; + QValueList<int> smoothies = fdb.smoothSizes( family, style ); + for ( QValueList<int>::Iterator points = smoothies.begin(); + points != smoothies.end(); ++points ) { + dstyle += QString::number( *points ) + " "; + } + dstyle = dstyle.left( dstyle.length() - 1 ) + ")"; + qDebug( dstyle ); + } + } + + + path = KGlobal::dirs()->saveLocation( "data", "kimagemapeditor/" ) +filename; + kdDebug() << "getBackgroundPic : save new image to : " << path << endl; + pix.save(path,"PNG",100); + } + + if ( ! QFileInfo(path).exists() ) { + kdError() << "Couldn't find needed " << filename << " file in " + "the data directory of KImageMapEditor.\n" + "Perhaps you have forgotten to do a make install !" << endl; + exit(1); + } +*/ +} + + +void KImageMapEditor::addArea(Area* area) { + if (!area) return; + + // Perhaps we've got a selection of areas + // so test it and add all areas of the selection + // nested selections are possible but doesn't exist + AreaSelection *selection=0L; + if ( (selection = dynamic_cast <AreaSelection*> ( area ) ) ) + { + AreaList list = selection->getAreaList(); + + for (Area* a = list.first(); a != 0L; a = list.next() ) + { + areas->prepend(a); + a->setListViewItem(new QListViewItem(areaListView->listView,a->attribute("href"))); + a->listViewItem()->setPixmap(1,makeListViewPix(*a)); + } + } + else + { + areas->prepend(area); + area->setListViewItem(new QListViewItem(areaListView->listView,area->attribute("href"))); + area->listViewItem()->setPixmap(1,makeListViewPix(*area)); + } + + setModified(true); + +} + +void KImageMapEditor::addAreaAndEdit(Area* s) +{ + areas->prepend(s); + s->setListViewItem(new QListViewItem(areaListView->listView,s->attribute("href"))); + s->listViewItem()->setPixmap(1,makeListViewPix(*s)); + deselectAll(); + select(s); + if (!showTagEditor(selected())) { + // If the user has pressed cancel + // he undos the creation + commandHistory()->undo(); + } +} + +void KImageMapEditor::deleteArea( Area * area ) +{ + if (!area) return; + + // only for repaint reasons + QRect redrawRect = area->selectionRect(); + + // Perhaps we've got a selection of areas + // so test it and delete the whole selection + // nested selections are possible but doesn't exist + AreaSelection *selection=0L; + if ( (selection = dynamic_cast <AreaSelection*> ( area ) ) ) + { + AreaList list = selection->getAreaList(); + + for (Area* a = list.first(); a != 0L; a = list.next() ) + { + currentSelected->remove(a); + areas->remove( a ); + a->deleteListViewItem(); + } + } + else + { + deselect( area ); + areas->remove( area ); + area->deleteListViewItem(); + } + + drawZone->repaintRect(redrawRect); + + + // Only to disable cut and copy actions + if (areas->count()==0) + deselectAll(); + + setModified(true); +} + +void KImageMapEditor::deleteSelected() { + + Area *a; + AreaList list=currentSelected->getAreaList(); + + for ( a=list.first(); a != 0; a=list.next() ) { + currentSelected->remove( a ); + areas->remove( a ); + delete a->listViewItem(); + } + + + drawZone->repaintArea( *currentSelected ); + // Only to disable cut and copy actions + if (areas->count()==0) + deselectAll(); + + setModified(true); +} + +void KImageMapEditor::deleteAllAreas() +{ + for (Area* a=areas->first();a!=0L;) + { + deselect( a ); + areas->remove( a ); + a->deleteListViewItem(); + a=areas->first(); // because the current is deleted + } + + drawZone->viewport()->repaint(); + +} + +void KImageMapEditor::updateAllAreas() +{ +// kdDebug() << "KImageMapEditor::updateAllAreas" << endl; + for (Area* a=areas->first();a!=0L;a=areas->next()) { + a->listViewItem()->setPixmap(1,makeListViewPix(*a)); + } + drawZone->viewport()->repaint(); +} + +void KImageMapEditor::updateSelection() const { + areaListView->listView->triggerUpdate(); +} + +AreaSelection* KImageMapEditor::selected() const { + return currentSelected; +} + +void KImageMapEditor::select(Area* a) +{ + if (!a) return; + + currentSelected->add(a); + updateActionAccess(); + slotUpdateSelectionCoords(); +// drawZone->repaintArea( *a); + +} + +void KImageMapEditor::selectWithoutUpdate(Area* a) +{ + if (!a) return; + currentSelected->add(a); +} + +void KImageMapEditor::slotSelectionChanged() +{ + AreaListIterator it = areaList(); + AreaList list = currentSelected->getAreaList(); + + for ( ; it.current() != 0L; ++it) + { + if ( it.current()->listViewItem()->isSelected() != (list.containsRef(it.current()) > 0) ) + { + it.current()->listViewItem()->isSelected() + ? select( it.current() ) + : deselect( it.current() ); + + drawZone->repaintArea( *it.current()); + } + } + +} + +void KImageMapEditor::select( QListViewItem* item) +{ + + AreaListIterator it = areaList(); + + for ( ; it.current() != 0L; ++it) + { + if (it.current()->listViewItem() == item ) + { + select( it.current() ); + drawZone->repaintArea( *it.current()); + } + } + + +} + +AreaListIterator KImageMapEditor::areaList() const { + AreaListIterator it(*areas); + return it; +} + + +void KImageMapEditor::slotAreaChanged(Area *area) +{ + if (!area) + return; + + setModified(true); + + AreaSelection *selection=0L; + if ( (selection = dynamic_cast <AreaSelection*> ( area ) ) ) + { + AreaListIterator it = selection->getAreaListIterator(); + + for ( ; it.current() != 0L; ++it ) + { + if (it.current()->listViewItem()) { + it.current()->listViewItem()->setText(0,it.current()->attribute("href")); + it.current()->listViewItem()->setPixmap(1,makeListViewPix(*it.current())); + } + } + + } + else + if (area->listViewItem()) { + area->listViewItem()->setText(0,area->attribute("href")); + area->listViewItem()->setPixmap(1,makeListViewPix(*area)); + } + + drawZone->repaintArea(*area); + +} + +void KImageMapEditor::deselect(Area* a) +{ + if (a) { + currentSelected->remove(a); +// drawZone->repaintArea(*a); + updateActionAccess(); + slotUpdateSelectionCoords(); + } +} + +void KImageMapEditor::deselectWithoutUpdate(Area* a) +{ + if (a) { + currentSelected->remove(a); + } +} + + +/** +* Makes sure, that the actions cut, copy, delete and +* show properties +* can only be executed if sth. is selected. +**/ +void KImageMapEditor::updateActionAccess() +{ + if (!isReadWrite()) + return; + + if ( 0 < selected()->count()) + { + areaPropertiesAction->setEnabled(true); + deleteAction->setEnabled(true); + copyAction->setEnabled(true); + cutAction->setEnabled(true); + moveLeftAction->setEnabled(true); + moveRightAction->setEnabled(true); + moveUpAction->setEnabled(true); + moveDownAction->setEnabled(true); + toFrontAction->setEnabled(true); + toBackAction->setEnabled(true); + + if ( (selected()->count() == 1) ) + { + if (selected()->type()==Area::Polygon) + { + increaseWidthAction->setEnabled(false); + decreaseWidthAction->setEnabled(false); + increaseHeightAction->setEnabled(false); + decreaseHeightAction->setEnabled(false); + addPointAction->setEnabled(true); + removePointAction->setEnabled(true); + } + else + { + increaseWidthAction->setEnabled(true); + decreaseWidthAction->setEnabled(true); + increaseHeightAction->setEnabled(true); + decreaseHeightAction->setEnabled(true); + addPointAction->setEnabled(false); + removePointAction->setEnabled(false); + } + + } + else + { + increaseWidthAction->setEnabled(false); + decreaseWidthAction->setEnabled(false); + increaseHeightAction->setEnabled(false); + decreaseHeightAction->setEnabled(false); + addPointAction->setEnabled(false); + removePointAction->setEnabled(false); + } + + } + else + { + areaPropertiesAction->setEnabled(false); + deleteAction->setEnabled(false); + copyAction->setEnabled(false); + cutAction->setEnabled(false); + moveLeftAction->setEnabled(false); + moveRightAction->setEnabled(false); + moveUpAction->setEnabled(false); + moveDownAction->setEnabled(false); + increaseWidthAction->setEnabled(false); + decreaseWidthAction->setEnabled(false); + increaseHeightAction->setEnabled(false); + decreaseHeightAction->setEnabled(false); + toFrontAction->setEnabled(false); + toBackAction->setEnabled(false); + addPointAction->setEnabled(false); + removePointAction->setEnabled(false); + + } + + updateUpDownBtn(); +} + +void KImageMapEditor::updateUpDownBtn() +{ + if (!isReadWrite()) + return; + + AreaList list = currentSelected->getAreaList(); + + if (list.isEmpty() || (areas->count() < 2)) + { + forwardOneAction->setEnabled(false); + areaListView->upBtn->setEnabled(false); + backOneAction->setEnabled(false); + areaListView->downBtn->setEnabled(false); + return; + } + // if the first Area is in the selection can't move up + if (list.find( areas->getFirst() ) == -1) + { + forwardOneAction->setEnabled(true); + areaListView->upBtn->setEnabled(true); + } + else { + forwardOneAction->setEnabled(false); + areaListView->upBtn->setEnabled(false); + } + + drawZone->repaintArea(*currentSelected); + + // if the last Area is in the selection can't move down + if (list.find( areas->getLast() ) == -1) + { + backOneAction->setEnabled(true); + areaListView->downBtn->setEnabled(true); + } + else { + backOneAction->setEnabled(false); + areaListView->downBtn->setEnabled(false); + } + +} + +void KImageMapEditor::deselectAll() +{ + QRect redrawRect= currentSelected->selectionRect(); + currentSelected->reset(); + drawZone->repaintRect(redrawRect); + updateActionAccess(); +} + +Area* KImageMapEditor::onArea(const QPoint & p) const { + for (Area* s=areas->first();s!=0L;s=areas->next()) { + if (s->contains(p)) + return s; + } + return 0L; +} + + +int KImageMapEditor::showTagEditor(Area *a) { + if (!a) return 0; + drawZone->repaintArea(*a); + + AreaDialog *dialog= new AreaDialog(this,a); + connect (dialog, SIGNAL(areaChanged(Area*)), this, SLOT(slotAreaChanged(Area*))); + + int result = dialog->exec(); + + return result; + + +} + +int KImageMapEditor::showTagEditor(QListViewItem *item) { + if (!item) return 0; + for (Area* a=areas->first();a!=0L;a=areas->next()) { + if (a->listViewItem()==item) { + return showTagEditor(a); + } + } + return 0; +} + +int KImageMapEditor::showTagEditor() { + return showTagEditor(selected()); +} + + +QString KImageMapEditor::getHTMLImageMap() const { + QString retStr; + retStr+="<map "+QString("name=\"")+_mapName+"\">\n"; + + for (Area* a=areas->first();a!=0L;a=areas->next()) { + retStr+=" "+a->getHTMLCode()+"\n"; + } + + if (defaultArea && defaultArea->finished()) + retStr+=" "+defaultArea->getHTMLCode()+"\n"; + + retStr+="</map>"; + return retStr; +} + +QPixmap KImageMapEditor::makeListViewPix(Area & a) +{ + QPixmap pix=a.cutOut(drawZone->picture()); + + double shrinkFactor=1; + + // picture fits into max row height ? + if (maxAreaPreviewHeight < pix.height()) + shrinkFactor = ( (double) maxAreaPreviewHeight / pix.height() ); + + QPixmap pix2((int)(pix.width()*shrinkFactor), (int)(pix.height()*shrinkFactor)); + + // Give all pixels a defined color + pix2.fill(Qt::white); + + QPainter p(&pix2); + + p.scale(shrinkFactor,shrinkFactor); + p.drawPixmap(0,0,pix); + + return pix2; +} + +void KImageMapEditor::setMapName(const QString & s) { + mapsListView->changeMapName(_mapName, s); + _mapName=s; + currentMapElement->mapTag->name = s; +} + + +void KImageMapEditor::setPicture(const KURL & url) { + _imageUrl=url; + if (QFileInfo(url.path()).exists()) { + QImage img(url.path()); + + if (!img.isNull()) { + setPicture(img); + imageRemoveAction->setEnabled(true); + imageUsemapAction->setEnabled(true); + } + else + kdError() << QString("The image %1 could not be opened.").arg(url.path()) << endl; + } + else + kdError() << QString("The image %1 does not exist.").arg(url.path()) << endl; +} + +void KImageMapEditor::setPicture(const QImage & pix) { + drawZone->setPicture(pix); + updateAllAreas(); +} + + +void KImageMapEditor::slotDrawArrow() { + _currentToolType=KImageMapEditor::Selection; + +} + +void KImageMapEditor::slotDrawCircle() { + _currentToolType=KImageMapEditor::Circle; + +} + +void KImageMapEditor::slotDrawRectangle() { + _currentToolType=KImageMapEditor::Rectangle; + +} + +void KImageMapEditor::slotDrawPolygon() { + _currentToolType=KImageMapEditor::Polygon; +} + +void KImageMapEditor::slotDrawFreehand() { + _currentToolType=KImageMapEditor::Freehand; +} + +void KImageMapEditor::slotDrawAddPoint() { + _currentToolType=KImageMapEditor::AddPoint; +} + +void KImageMapEditor::slotDrawRemovePoint() { + _currentToolType=KImageMapEditor::RemovePoint; +} + + +void KImageMapEditor::slotZoom() { + + int i=zoomAction->currentItem(); + switch (i) { + case 0 : drawZone->setZoom(0.25);break; + case 1 : drawZone->setZoom(0.5);break; + case 2 : drawZone->setZoom(1);break; + case 3 : drawZone->setZoom(1.5);break; + case 4 : drawZone->setZoom(2.0);break; + case 5 : drawZone->setZoom(2.5);break; + case 6 : drawZone->setZoom(3);break; + case 7 : drawZone->setZoom(5);break; + case 8 : drawZone->setZoom(7.5);break; + case 9 : drawZone->setZoom(10);break; + } + if (i<10) + zoomInAction->setEnabled(true); + else + zoomInAction->setEnabled(false); + + if (i>0) + zoomOutAction->setEnabled(true); + else + zoomOutAction->setEnabled(false); +} + +void KImageMapEditor::slotZoomIn() { + if (zoomAction->currentItem()==(int)(zoomAction->items().count()-1)) + return; + + zoomAction->setCurrentItem(zoomAction->currentItem()+1); + slotZoom(); +} + +void KImageMapEditor::slotZoomOut() { + if (zoomAction->currentItem()==0) + return; + + zoomAction->setCurrentItem(zoomAction->currentItem()-1); + slotZoom(); +} + +void KImageMapEditor::mapDefaultArea() +{ + if (defaultArea) + showTagEditor(defaultArea); + else { + defaultArea= new DefaultArea(); + showTagEditor(defaultArea); + } + +} + +void KImageMapEditor::mapEditName() +{ + bool ok=false; +#if KDE_IS_VERSION(3, 1, 90) + QString input = KInputDialog::getText(i18n("Enter Map Name"), + i18n("Enter the name of the map:"), + _mapName,&ok,widget()); +#else + QString input = KLineEditDlg::getText(i18n("Enter Map Name"), + i18n("Enter the name of the map:"), + _mapName,&ok,widget()); +#endif + if (ok) { + if (input != _mapName) { + if (mapsListView->nameAlreadyExists(input)) + KMessageBox::sorry(this->widget(), i18n("The name <em>%1</em> already exists.").arg(input)); + else { + setMapName(input); + } + } + } +} + +void KImageMapEditor::mapShowHTML() +{ + KDialogBase *dialog= new KDialogBase(widget(),QString::null,true,i18n("HTML Code of Map"),KDialogBase::Ok); + QMultiLineEdit *edit = new QMultiLineEdit(dialog); + + edit->setText(getHtmlCode()); + edit->setReadOnly(true); + edit->setWordWrap(QTextEdit::NoWrap); + dialog->setMainWidget(edit); +// dialog->resize(dialog->calculateSize(edit->maxLineWidth(),edit->numLines()*)); +// dialog->adjustSize(); + dialog->resize(600,400); + dialog->exec(); +} + +void KImageMapEditor::openFile(const KURL & url) { + if ( ! url.isEmpty()) { + QString ext=QFileInfo(url.path()).extension().lower(); + + if (ext=="png" || ext=="jpg" || ext=="jpeg" || ext=="gif" || + ext=="bmp" || ext=="xbm" || ext=="xpm" || ext=="mng" || ext=="pnm") + addImage(url); + else + openURL(url); + } +} + +bool KImageMapEditor::openURL(const KURL & url) { + // If a local file does not exist + // we start with an empty file, so + // that we can return true here. + // For non local files, we cannot check + // the existance + if (url.isLocalFile() && + ! QFile::exists(url.path())) + return true; + return KParts::ReadOnlyPart::openURL(url); +} + +void KImageMapEditor::fileOpen() { + + QString fileName = KFileDialog::getOpenFileName(QString::null, + i18n("*.png *.jpg *.jpeg *.gif *.htm *.html|Web File\n" + "*.png *.jpg *.jpeg *.gif *.bmp *.xbm *.xpm *.pnm *.mng|Images\n" + "*.htm *.html|HTML Files\n" + "*.png|PNG Images\n*.jpg *.jpeg|JPEG Images\n*.gif|GIF-Images\n*|All Files"), + widget(),i18n("Choose File to Open")); + + openFile(KURL( fileName )); +} + + + +void KImageMapEditor::fileClose() +{ + if (! closeURL()) + return; + + + setPicture(getBackgroundImage()); + recentFilesAction->setCurrentItem(-1); + setModified(false); +} + +void KImageMapEditor::fileSave() +{ + // if we aren't read-write, return immediately + if ( ! isReadWrite() ) + return; + + if (url().isEmpty()) { + fileSaveAs(); + } + else { + saveFile(); + setModified(false); + } + + +} + +void KImageMapEditor::fileSaveAs() { + + KURL url = KFileDialog::getSaveURL(0L,"*.htm *.html|" + i18n( "HTML File" ) + + "\n*.txt|" + i18n( "Text File" ) + "\n*|" + i18n( "All Files" ),widget()); + if (url.isEmpty() || !url.isValid()) { + return; + } + + + QFileInfo fileInfo(url.path()); + + if ( fileInfo.exists() ) + { + if (KMessageBox::warningContinueCancel(widget(), + i18n("<qt>The file <em>%1</em> already exists.<br>Do you want to overwrite it?</qt>").arg(fileInfo.fileName()), + i18n("Overwrite File?"), i18n("Overwrite"))==KMessageBox::Cancel) + return; + + if(!fileInfo.isWritable()) { + KMessageBox::sorry(widget(), i18n("<qt>You do not have write permission for the file <em>%1</em>.</qt>").arg(fileInfo.fileName())); + return; + } + } + + + saveAs(url); + recentFilesAction->addURL(url); + +} + + +bool KImageMapEditor::openFile() +{ + QFileInfo fileInfo(url().path()); + + if ( !fileInfo.exists() ) + { + KMessageBox::information(widget(), + i18n("<qt>The file <b>%1</b> does not exist.</qt>").arg(fileInfo.fileName()), + i18n("File Does Not Exist")); + return false; + } + + openHTMLFile(url()); + + drawZone->viewport()->repaint(); + recentFilesAction->addURL(url()); + setModified(false); + backupFileCreated = false; + return true; +} + +/** + * This methods supposes that the given QTextStream s has just read + * the < of a tag. It now reads all attributes of the tag until a > + * The tagname itself is also read and stored as a <em>tagname</em> + * attribute. After parsing the whole tag it returns a QDict<QString> + * with all attributes and their values. It stores the whole read text in the + * parameter readText. + */ +QDict<QString> KImageMapEditor::getTagAttributes(QTextStream & s, QString & readText) +{ + QDict<QString> dict(17,false); + // the "<" is already read + QChar w; + QString attr,value; + + readText = QString::null; + + // get the tagname + while (!s.atEnd() && w!=" ") { + s >> w; + readText.append(w); + if (w==" " || w==">") { + dict.insert("tagname",new QString(value)); + break; + } + value+=w; + } + + + // do we have a comment ? + // read the comment and return + if (value.right(3)=="-->") + return dict; + + if (value.startsWith("!--")) { + while (!s.atEnd()) { + s >> w; + readText.append(w); + + if (w=="-") { + s >> w; + readText.append(w); + if (w=="-") { + s >> w; + readText.append(w); + if (w==">") + return dict; + } + } + } + } + + bool attrRead=true; // currently reading an attribute ? + bool equalSign=false; // an equalsign was read? + bool valueRead=false; // currently reading a value ? + QChar quotation='\0'; // currently reading a value with quotation marks ? + bool php=false; // currently reading a php script + attr=QString::null; + value=QString::null; + + //get the other attributes + while (!s.atEnd() && w!=">") + { + s >> w; + readText.append(w); + + // End of PHP Script ? + if (php && (w=="?") ) + { + s >> w; + readText.append(w); + + if (valueRead) + value+=w; + + if (w==">") + { + php = false; + s >> w; + readText.append(w); + } + } + + // Wrong syntax or PHP-Skript ! + if (!php && (w=="<")) + { + if (valueRead) + value+=w; + s >> w; + readText.append(w); + if (valueRead) + value+=w; + + if (w=="?") + { + php = true; + } + } else + // finished ? + if (w==">") { + if (valueRead) + dict.insert(attr,new QString(value)); + return dict; + } else + // currently reading an attribute ? + if (attrRead) { + // if there is a whitespace the attributename has finished + // possibly there isn't any value e.g. noshade + if (w==" ") + attrRead=false; + else + // an equal sign signals that the value follows + if (w=="=") { + attrRead=false; + equalSign=true; + } else + attr+=w; + } else + // an equal sign was read ? delete every whitespace + if (equalSign) { + if (w!=" ") { + equalSign=false; + valueRead=true; + if (w=="\"" || w=="'") + quotation=w; + } + } else + // currently reading the value + if (valueRead) { + // if php, read without regarding anything + if (php) + value+=w; + // if value within quotation marks is read + // only stop when another quotationmark is found + else + if (quotation != '\0') { + if (quotation!=w) { + value+=w; + } else { + quotation='\0'; + valueRead=false; + dict.insert(attr,new QString(value)); + attr = value = QString::null; + + } + } else + // a whitespace indicates that the value has finished + if (w==" ") { + valueRead=false; + dict.insert(attr,new QString(value)); + attr = value = QString::null; + } + } else { + if (w!=" ") { + attrRead=true; + attr+=w; + } + } + } + + return dict; + +} + + +bool KImageMapEditor::openHTMLFile(const KURL & url, const QString & mapName, const QString & imagePath) +{ + QFile f(url.path()); + if ( !f.exists () ) + return false; + f.open(IO_ReadOnly); + QTextStream s(&f); + QString str; + QChar w; + QDict<QString> *attr=0L; + QPtrList<ImageTag> *images= new QPtrList<ImageTag>; + MapTag *map=0L; + QPtrList<MapTag> *maps = new QPtrList<MapTag>; + + _htmlContent.clear(); + currentMapElement = 0L; + + QString temp; + QString origcode; + + bool readMap=false; + + while (!s.atEnd()) { + + s >> w; + if (w=="<") + { + if (!readMap && !origcode.isEmpty()) { + _htmlContent.append( new HtmlElement(origcode)); + origcode = QString::null; + } + + origcode.append("<"); + attr=new QDict<QString>(getTagAttributes(s,temp)); + origcode.append(temp); + + if (attr->find("tagname")) { + + if (attr->find("tagname")->lower()=="img") { + HtmlImgElement *el = new HtmlImgElement(origcode); + el->imgTag = static_cast<ImageTag*>(attr); + images->append(el->imgTag); + _htmlContent.append(el); + + origcode = QString::null; + } else + if (attr->find("tagname")->lower()=="map") { + map = new MapTag(); + map->name=(*attr->find("name")); + readMap=true; + } else + if (attr->find("tagname")->lower()=="/map") { + readMap=false; + maps->append(map); + HtmlMapElement *el = new HtmlMapElement(origcode); + el->mapTag = map; + _htmlContent.append(el); + + origcode = QString::null; + } else + if (readMap) { + if (attr->find("tagname")->lower()=="area") { + map->prepend(attr); + } + } else { + _htmlContent.append(new HtmlElement(origcode)); + origcode = QString::null; + } + + } + } // w != "<" + else { + origcode.append(w); + } + } + + if (!origcode.isEmpty()) { + _htmlContent.append(new HtmlElement(origcode)); + } + + f.close(); + + KURL imageUrl; + map = 0L; + + + + // If there is a preselection of map and image + // don't let the user choose something + if (imagePath.isNull() || mapName.isNull()) { + // If we have more than on map or more than one image + // Let the user choose, otherwise take the only ones + if (maps->count() == 1) { + map = maps->first(); + } + + if (images->count() == 1) { + if (images->first()) { + ImageTag* imgTag = images->first(); + QString *src = imgTag->find("src"); + if (src) + imageUrl = KURL(url,*src); + } + } + + // If there is only one map and more than one image + // try to find out the image with the according usemap tag + if (maps->count() == 1 && images->count() > 1) { + ImageTag* imageTag; + for ( imageTag = images->first(); imageTag; imageTag = images->next() ) + { + QString *usemap = imageTag->find("usemap"); + if (usemap) { + // Remove the # + QString usemapName = usemap->right(usemap->length()-1); + if (usemapName == map->name) { + QString *src = imageTag->find("src"); + if (src) + imageUrl = KURL(url,*src); + } + } + } + } + + + // If there are more than one map or there wasn't + // found a fitting image and there is something to choose + // let the user choose + if (maps->count() >1 || (imageUrl.isEmpty() && images->count() > 1)) + { + ImageMapChooseDialog dialog(widget(),maps,images,url); + dialog.exec(); + map=dialog.currentMap; + imageUrl=dialog.pixUrl; + } + } + else + imageUrl = imagePath; + + imagesListView->clear(); + imagesListView->setBaseUrl(url); + imagesListView->addImages(images); + + mapsListView->clear(); + mapsListView->addMaps(maps); + + + setMapActionsEnabled(false); + + if (map) { + mapsListView->selectMap(map->name); + } + else if ( ! mapName.isNull()) { + mapsListView->selectMap(mapName); + } else { + if (tabWidget) + tabWidget->showPage(mapsListView); + } + + if (!imageUrl.isEmpty()) { + setPicture(imageUrl); + } else { + setPicture(getBackgroundImage()); + if (tabWidget) + tabWidget->showPage(imagesListView); + } + + + emit setWindowCaption(url.fileName()); + setModified(false); + return true; +} + +/** + * Finds the first html element which contains the given text. + * Returns the first matching element. + * Returns 0L if no element was found. + */ +HtmlElement* KImageMapEditor::findHtmlElement(const QString & containingText) { + for (HtmlElement * el = _htmlContent.first(); el; el = _htmlContent.next() ) { + if (el->htmlCode.contains(containingText,false)) { + return el; + } + } + return 0L; +} + +/** + * Finds the first html element which contains the given ImageTag. + * Returns the first matching element. + * Returns 0L if no element was found. + */ +HtmlImgElement* KImageMapEditor::findHtmlImgElement(ImageTag* tag) { + for (HtmlElement * el = _htmlContent.first(); el; el = _htmlContent.next() ) { + HtmlImgElement* imgEl = dynamic_cast<HtmlImgElement*>(el); + + if (imgEl && imgEl->imgTag == tag) + return imgEl; + } + return 0L; +} + +void KImageMapEditor::addMap(const QString & name = QString::null) { + HtmlMapElement* el = new HtmlMapElement("\n<map></map>"); + MapTag* map = new MapTag(); + map->name = name; + el->mapTag = map; + + // Try to find the body tag + HtmlElement* bodyTag = findHtmlElement("<body"); + + // if we found one add the new map right after the body tag + if (bodyTag) { + uint index = _htmlContent.find(bodyTag); + + // Add a newline before the map + _htmlContent.insert(index+1, new HtmlElement("\n")); + + _htmlContent.insert(index+2, el); + } // if there is no body tag we add the map to the end of the file + else { + // Add a newline before the map + _htmlContent.append(new HtmlElement("\n")); + + _htmlContent.append(el); + kdDebug() << "KImageMapEditor::addMap : No <body found ! Appending new map to the end." << endl; + } + + mapsListView->addMap(name); + mapsListView->selectMap(name); +} + +/** + * Finds the HtmlMapElement in the HtmlContent, that corresponds + * to the given map name.<br> + * Returns 0L if there exists no map with the given name + */ +HtmlMapElement* KImageMapEditor::findHtmlMapElement(const QString & mapName) { + for (HtmlElement * el = _htmlContent.first(); el; el = _htmlContent.next() ) { + if (dynamic_cast<HtmlMapElement*>(el)) { + HtmlMapElement *tagEl = static_cast<HtmlMapElement*>(el); + if (tagEl->mapTag->name == mapName) { + return tagEl; + } + } + } + + kdWarning() << "KImageMapEditor::findHtmlMapElement: couldn't find map '" << mapName << "'" << endl; + return 0L; +} + +/** + * Calls setMap with the HtmlMapElement with the given map name + */ +void KImageMapEditor::setMap(const QString & mapName) { + HtmlMapElement* el = findHtmlMapElement(mapName); + if (!el) { + kdWarning() << "KImageMapEditor::setMap : Couldn't set map '" << mapName << "', because it wasn't found !" << endl; + return; + } + + setMap(el); + +} + +void KImageMapEditor::setMap(MapTag* map) { + for (HtmlElement * el = _htmlContent.first(); el; el = _htmlContent.next() ) { + HtmlMapElement *tagEl = dynamic_cast<HtmlMapElement*>(el); + if (tagEl) { + if (tagEl->mapTag == map) { + setMap(tagEl); + break; + } + } + } + +} + +void KImageMapEditor::saveAreasToMapTag(MapTag* map) { + map->clear(); + for (Area* a=areas->first();a!=0L;a=areas->next()) { + QDict<QString> *dict = new QDict<QString>(17,false); + QString *shapeStr = 0L; + + switch (a->type()) { + case Area::Rectangle : shapeStr = new QString("rect");break; + case Area::Circle : shapeStr = new QString("circle");break; + case Area::Polygon : shapeStr = new QString("poly");break; + default : continue; + } + + dict->insert("shape",shapeStr); + + for (AttributeIterator it = a->firstAttribute();it!=a->lastAttribute();++it) { + dict->insert(it.key(),new QString(it.data())); + } + + dict->insert("coords",new QString(a->coordsToString())); + + map->append(dict); + + } + + if (defaultArea && defaultArea->finished()) { + QDict<QString> *dict = new QDict<QString>(17,false); + dict->insert("shape",new QString("default")); + + for (AttributeIterator it = defaultArea->firstAttribute();it!=defaultArea->lastAttribute();++it) { + dict->insert(it.key(),new QString(it.data())); + } + + map->append(dict); + } + +} + +void KImageMapEditor::setMap(HtmlMapElement* mapElement) { + if (currentMapElement) { + currentMapElement->mapTag->modified=true; + currentMapElement->htmlCode = getHTMLImageMap(); + saveAreasToMapTag(currentMapElement->mapTag); + } + + currentMapElement = mapElement; + MapTag* map = currentMapElement->mapTag; + + // Remove old areas only if a new map is loaded + deleteAllAreas(); + delete defaultArea; + defaultArea = 0L; +// kdDebug() << "KImageMapEditor::setMap : Setting new map : " << map->name << endl; + _mapName = map->name; + for (AreaTag *tag=map->first();tag!=0L;tag=map->next()) + { + QString shape="rect"; + if (tag->find("shape")) + shape=*tag->find("shape"); + + Area::ShapeType type=Area::Rectangle; + if (shape=="circle") + type=Area::Circle; + else if (shape=="poly") + type=Area::Polygon; + else if (shape=="default") + type=Area::Default; + + Area* a=AreaCreator::create(type); + + if (tag->find("href")) + a->setAttribute("href",*tag->find("href")); + + if (tag->find("alt")) + a->setAttribute("alt",*tag->find("alt")); + + if (tag->find("target")) + a->setAttribute("target",*tag->find("target")); + + if (tag->find("title")) + a->setAttribute("title",*tag->find("title")); + + if (tag->find("onclick")) + a->setAttribute("onclick",*tag->find("onclick")); + + if (tag->find("onmousedown")) + a->setAttribute("onmousedown",*tag->find("onmousedown")); + + if (tag->find("onmouseup")) + a->setAttribute("onmouseup",*tag->find("onmouseup")); + + if (tag->find("onmouseover")) + a->setAttribute("onmouseover",*tag->find("onmouseover")); + + if (tag->find("onmousemove")) + a->setAttribute("onmousemove",*tag->find("onmousemove")); + + if (tag->find("onmouseout")) + a->setAttribute("onmouseout",*tag->find("onmouseout")); + + + + if (type==Area::Default) { + defaultArea=a; + defaultArea->setFinished(true); + continue; + } + + if (tag->find("coords")) + a->setCoords(*tag->find("coords")); + + a->setMoving(false); + addArea(a); + } + + updateAllAreas(); + + setMapActionsEnabled(true); +} + +/** + * Sets wether actions that depend on an selected map + * are enabled + */ +void KImageMapEditor::setMapActionsEnabled(bool b) { + mapDeleteAction->setEnabled(b); + mapDefaultAreaAction->setEnabled(b); + mapNameAction->setEnabled(b); + + arrowAction->setChecked(true); + slotDrawArrow(); + + arrowAction->setEnabled(b); + circleAction->setEnabled(b); + rectangleAction->setEnabled(b); + polygonAction->setEnabled(b); + freehandAction->setEnabled(b); + addPointAction->setEnabled(b); + removePointAction->setEnabled(b); + +} + +QString KImageMapEditor::getHtmlCode() { + if (currentMapElement) { + currentMapElement->htmlCode = getHTMLImageMap(); + } + + QString result; + + HtmlElement *el; + for ( el = _htmlContent.first(); el; el = _htmlContent.next() ) { + result += el->htmlCode; + //kdDebug() << "KImageMapEditor::getHtmlCode : Writing : " << el->htmlCode << endl; + + } + return result; +} + +void KImageMapEditor::saveImageMap(const KURL & url) +{ + QFileInfo fileInfo(url.path()); + + if (!QFileInfo(url.directory()).isWritable()) { + KMessageBox::error(widget(), + i18n("<qt>The file <i>%1</i> could not be saved, because you do not have the required write permissions.</qt>").arg(url.path())); + return; + } + + if (!backupFileCreated) { + QString backupFile = url.path()+"~"; + KIO::file_copy(url, KURL::fromPathOrURL( backupFile ), -1, true, false, false); + backupFileCreated = true; + } + + setModified(false); + + if (mapName().isEmpty()) { + mapEditName(); + } + QFile file(url.path()); + file.open(IO_WriteOnly); + + QTextStream t(&file); + + if (_htmlContent.isEmpty()) { + t << "<html>\n" + << "<head>\n" + << " <title></title>\n" + << "</head>\n" + << "<body>\n" + << " " << getHTMLImageMap() + << "\n" + << " <img src=\"" << QExtFileInfo::toRelative(_imageUrl,KURL( url.directory() )).path() << "\"" + << " usemap=\"#" << _mapName << "\"" + << " width=\"" << drawZone->picture().width() << "\"" + << " height=\"" << drawZone->picture().height() << "\">\n" + << "</body>\n" + << "</html>"; + } else + { + t << getHtmlCode(); + } + + file.close(); + +} + + +void KImageMapEditor::slotCut() +{ + if ( 0 == currentSelected->count() ) + return; + delete copyArea; + + copyArea= static_cast< AreaSelection* > (currentSelected->clone()); + pasteAction->setEnabled(true); + KCommand *command= new CutCommand(this,*currentSelected); + commandHistory()->addCommand( command ,true); +} + + +void KImageMapEditor::slotDelete() +{ + if ( 0 == currentSelected->count() ) + return; + + KCommand *command= new DeleteCommand(this,*currentSelected); + commandHistory()->addCommand( command ,true); +} + +void KImageMapEditor::slotCopy() +{ + delete copyArea; + + copyArea = static_cast< AreaSelection* > (currentSelected->clone()); + pasteAction->setEnabled(true); +} + +void KImageMapEditor::slotPaste() +{ + if (!copyArea) + return; + + copyArea->moveBy(5,5); + if (copyArea->rect().x()>= drawZone->getImageRect().width() || + copyArea->rect().y()>= drawZone->getImageRect().height()) + copyArea->moveTo(0,0); + + if (copyArea->rect().width()>drawZone->getImageRect().width() || + copyArea->rect().height()>drawZone->getImageRect().height()) + return; + + AreaSelection *a=static_cast< AreaSelection* > (copyArea->clone()); + commandHistory()->addCommand( new PasteCommand(this,*a),true); + delete a; +// addAreaAndEdit(a); +} + + + +void KImageMapEditor::slotBackOne() +{ + if (currentSelected->isEmpty()) + return; + + AreaList list = currentSelected->getAreaList(); + + + Area *a = 0L; + // move every selected Area one step lower + for (int i=areas->count()-2; i > -1; i--) + { + if (list.find( areas->at(i) ) > -1 ) + { + a = areas->at(i); + areas->remove(a); + areas->insert((uint)i+1,a); + a->listViewItem()->moveItem( areas->at(i)->listViewItem() ); + } + } + // to update the up and down buttons + updateUpDownBtn(); + +} + +void KImageMapEditor::slotForwardOne() +{ + if (currentSelected->isEmpty()) + return; + + AreaList list = currentSelected->getAreaList(); + + Area *a = 0L; + // move every selected Area one step higher + for (int i=1; i < (int)areas->count(); i++) + { + if (list.find( areas->at(i) ) > -1 ) + { + a = areas->at(i); + areas->remove(a); + areas->insert((uint)i-1,a); + areas->at(i)->listViewItem()->moveItem( a->listViewItem() ); + } + } + // to update the up and down buttons + updateUpDownBtn(); +} + +void KImageMapEditor::slotToBack() +{ + if (currentSelected->isEmpty()) + return; + + while (backOneAction->isEnabled()) + slotBackOne(); +} + +void KImageMapEditor::slotToFront() +{ + if (currentSelected->isEmpty()) + return; + + while (forwardOneAction->isEnabled()) + slotForwardOne(); +} + + +void KImageMapEditor::slotMoveUp() +{ + QRect r=selected()->rect(); + selected()->setMoving(true); + selected()->moveBy(0,-1); + + commandHistory()->addCommand( + new MoveCommand( this, selected(), r.topLeft() ) ,true ); + selected()->setMoving(false); + slotAreaChanged(selected()); + slotUpdateSelectionCoords(); +} + +void KImageMapEditor::slotMoveDown() +{ + QRect r=selected()->rect(); + selected()->setMoving(true); + selected()->moveBy(0,1); + + commandHistory()->addCommand( + new MoveCommand( this, selected(), r.topLeft() ) ,true ); + selected()->setMoving(false); + slotAreaChanged(selected()); + slotUpdateSelectionCoords(); +} + +void KImageMapEditor::slotMoveLeft() +{ + QRect r=selected()->rect(); + selected()->setMoving(true); + selected()->moveBy(-1,0); + + commandHistory()->addCommand( + new MoveCommand( this, selected(), r.topLeft() ) ,true ); + selected()->setMoving(false); + slotAreaChanged(selected()); + slotUpdateSelectionCoords(); +} + +void KImageMapEditor::slotMoveRight() +{ + QRect r=selected()->rect(); + selected()->setMoving(true); + selected()->moveBy(1,0); + + commandHistory()->addCommand( + new MoveCommand( this, selected(), r.topLeft() ) ,true ); + selected()->setMoving(false); + slotAreaChanged(selected()); + slotUpdateSelectionCoords(); +} + +void KImageMapEditor::slotCancelDrawing() +{ + drawZone->cancelDrawing(); +} + +void KImageMapEditor::slotIncreaseHeight() +{ + Area *oldArea=selected()->clone(); + + QRect r = selected()->rect(); + r.setHeight( r.height()+1 ); + r.moveBy(0,-1); + + selected()->setRect(r); + + commandHistory()->addCommand( + new ResizeCommand( this, selected(), oldArea ) ,true ); + slotAreaChanged(selected()); + slotUpdateSelectionCoords(); +} + +void KImageMapEditor::slotDecreaseHeight() +{ + Area *oldArea=selected()->clone(); + + QRect r = selected()->rect(); + r.setHeight( r.height()-1 ); + r.moveBy(0,1); + + selected()->setRect(r); + + commandHistory()->addCommand( + new ResizeCommand( this, selected(), oldArea ) ,true ); + slotAreaChanged(selected()); + slotUpdateSelectionCoords(); +} + +void KImageMapEditor::slotIncreaseWidth() +{ + Area *oldArea=selected()->clone(); + + QRect r = selected()->rect(); + r.setWidth( r.width()+1 ); + + selected()->setRect(r); + + commandHistory()->addCommand( + new ResizeCommand( this, selected(), oldArea ) ,true ); + slotAreaChanged(selected()); + slotUpdateSelectionCoords(); +} + +void KImageMapEditor::slotDecreaseWidth() +{ + Area *oldArea=selected()->clone(); + + QRect r = selected()->rect(); + r.setWidth( r.width()-1 ); + + selected()->setRect(r); + + commandHistory()->addCommand( + new ResizeCommand( this, selected(), oldArea ) ,true ); + slotAreaChanged(selected()); + slotUpdateSelectionCoords(); +} + +void KImageMapEditor::slotHightlightAreas() +{ + bool b = highlightAreasAction->isChecked(); + +// highlightAreasAction->setChecked(b); + Area::highlightArea = b; + updateAllAreas(); + drawZone->viewport()->repaint(); +} + +void KImageMapEditor::slotShowAltTag() +{ + bool b = showAltAction->isChecked(); +// showAltAction->setChecked(b); + Area::showAlt = b; + drawZone->viewport()->repaint(); +} + +void KImageMapEditor::mapNew() +{ + QString mapName = mapsListView->getUnusedMapName(); + addMap(mapName); + mapEditName(); +} + +void KImageMapEditor::mapDelete() +{ + if (mapsListView->count() == 0) + return; + + QString selectedMap = mapsListView->selectedMap(); + + int result = KMessageBox::warningContinueCancel(widget(), + i18n("<qt>Are you sure you want to delete the map <i>%1</i>?" + " <br><b>There is no way to undo this.</b></qt>").arg(selectedMap), + i18n("Delete Map?"),KGuiItem(i18n("&Delete"),"editdelete")); + + if (result == KMessageBox::No) + return; + + + + mapsListView->removeMap(selectedMap); + HtmlMapElement* mapEl = findHtmlMapElement(selectedMap); + _htmlContent.remove(mapEl); + if (mapsListView->count() == 0) { + + currentMapElement = 0L; + deleteAllAreas(); + setMapActionsEnabled(false); + } + else { + // The old one was deleted, so the new one got selected + setMap(mapsListView->selectedMap()); + } +} + +void KImageMapEditor::mapPreview() { + HTMLPreviewDialog dialog(widget(), url(), getHtmlCode()); + dialog.exec(); +} + +void KImageMapEditor::deleteAllMaps() +{ + deleteAllAreas(); + mapsListView->clear(); + if (isReadWrite()) { + mapDeleteAction->setEnabled(false); + mapDefaultAreaAction->setEnabled(false); + mapNameAction->setEnabled(false); + } +} + +/** + * Doesn't call the closeURL method, because + * we need the URL for the session management + */ +bool KImageMapEditor::queryClose() { + if ( ! isModified() ) + return true; + + switch ( KMessageBox::warningYesNoCancel( widget(), + i18n("<qt>The file <i>%1</i> has been modified.<br>Do you want to save it?</qt>").arg(url().fileName()), QString::null, KStdGuiItem::save(), KStdGuiItem::discard()) ) { + case KMessageBox::Yes : + saveFile(); + return true; + case KMessageBox::No : + return true; + default: + return false; + } +} + +bool KImageMapEditor::closeURL() +{ + bool result = KParts::ReadWritePart::closeURL(); + if (!result) + return false; + + _htmlContent.clear(); + deleteAllMaps(); + imagesListView->clear(); + + delete copyArea; + copyArea=0L; + + delete defaultArea; + defaultArea=0L; + + currentMapElement = 0L; + + init(); + emit setWindowCaption(""); + + return true; + +} + +void KImageMapEditor::addImage(const KURL & imgUrl) { + if (imgUrl.isEmpty()) + return; + + QString relativePath ( QExtFileInfo::toRelative(imgUrl, KURL( url().directory() )).path() ); + + QString imgHtml = QString("<img src=\"")+relativePath+QString("\">"); + ImageTag *imgTag = new ImageTag(); + imgTag->insert("tagname",new QString("img")); + imgTag->insert("src", new QString(relativePath)); + + HtmlImgElement *imgEl = new HtmlImgElement(imgHtml); + imgEl->imgTag = imgTag; + + HtmlElement *bodyEl = findHtmlElement("<body"); + if (bodyEl) { + int bodyIndex = _htmlContent.find(bodyEl); + _htmlContent.insert(bodyIndex+1, new HtmlElement("\n")); + _htmlContent.insert(bodyIndex+2, imgEl); + } + else { + _htmlContent.append(new HtmlElement("\n")); + _htmlContent.append(imgEl); + } + + imagesListView->addImage(imgTag); + imagesListView->selectImage(imgTag); + setImageActionsEnabled(true); + + setModified(true); +} + +/** + * Sets whether the image actions that depend on an + * selected image are enabled + */ +void KImageMapEditor::setImageActionsEnabled(bool b) { + imageRemoveAction->setEnabled(b); + imageUsemapAction->setEnabled(b); +} + + +void KImageMapEditor::imageAdd() { + KURL imgUrl = KFileDialog::getImageOpenURL(); + addImage(imgUrl); +} + +void KImageMapEditor::imageRemove() { + ImageTag* imgTag = imagesListView->selectedImage(); + HtmlImgElement* imgEl = findHtmlImgElement(imgTag); + imagesListView->removeImage(imgTag); + _htmlContent.remove(imgEl); + + if (imagesListView->childCount() == 0) { + setPicture(getBackgroundImage()); + setImageActionsEnabled(false); + } + else { + ImageTag* selected = imagesListView->selectedImage(); + if (selected) { + QString *url = selected->find("src"); + if (url) { + setPicture(KURL(*url)); + } + } + } + + setModified(true); +} + +void KImageMapEditor::imageUsemap() { + + bool ok=false; + ImageTag* imageTag = imagesListView->selectedImage(); + if ( ! imageTag) + return; + + QString usemap; + + if (imageTag->find("usemap")) + usemap=*imageTag->find("usemap"); + + QStringList maps = mapsListView->getMaps(); + int index = maps.findIndex(usemap); + if (index == -1) { + maps.prepend(""); + index = 0; + } + +#if KDE_IS_VERSION(3, 1, 90) + QString input = KInputDialog::getItem(i18n("Enter Usemap"), +#else + QString input = QInputDialog::getItem(i18n("Enter Usemap"), +#endif + i18n("Enter the usemap value:"), + maps,index,true,&ok,widget()); + if (ok) { + imageTag->replace("usemap", new QString(input)); + imagesListView->updateImage(imageTag); + setModified(true); + + // Update the htmlCode of the HtmlElement + HtmlImgElement* imgEl = findHtmlImgElement(imageTag); + + imgEl->htmlCode = "<"; + QString *tagName = imgEl->imgTag->find("tagname"); + imgEl->htmlCode += QString(*tagName); + + QDictIterator<QString> it( *imgEl->imgTag ); + for( ; it.current(); ++it ) { + if (it.currentKey() != "tagname") { + imgEl->htmlCode += " " + it.currentKey() + "=\""; + imgEl->htmlCode += *it.current(); + imgEl->htmlCode += "\""; + } + } + + imgEl->htmlCode += ">"; + + } +} + +void KImageMapEditor::configureShowAreaList() { + if (configureShowAreaListAction->isChecked()) + mainDock->makeDockVisible(areaDock); + else + mainDock->makeDockInvisible(areaDock); +} + +void KImageMapEditor::configureShowMapList() { + if (configureShowMapListAction->isChecked()) + mainDock->makeDockVisible(mapsDock); + else + mainDock->makeDockInvisible(mapsDock); +} + +void KImageMapEditor::configureShowImageList() { + if (configureShowImageListAction->isChecked()) + mainDock->makeDockVisible(imagesDock); + else + mainDock->makeDockInvisible(imagesDock); +} + +void KImageMapEditor::dockingStateChanged() { + if (areaDock) { + configureShowImageListAction->setChecked( imagesDock->isVisible() ); + configureShowAreaListAction->setChecked( areaDock->isVisible() ); + configureShowMapListAction->setChecked( mapsDock->isVisible() ); + } +} diff --git a/kimagemapeditor/kimagemapeditor.desktop b/kimagemapeditor/kimagemapeditor.desktop new file mode 100644 index 00000000..263c7536 --- /dev/null +++ b/kimagemapeditor/kimagemapeditor.desktop @@ -0,0 +1,55 @@ +[Desktop Entry] +Type=Application +MimeType=text/html; +Exec=kimagemapeditor -caption "%c" %i %m +Icon=kimagemapeditor +Terminal=false +Name=KImageMapEditor +Name[ne]=केडीई छवि मानचित्र सम्पादक +Name[pt_BR]=KEditor de Mapeamento de Imagem +Name[sk]=KImage editor mapy +Name[sv]=Kimagemapeditor +Name[ta]=Kவடிவம் வரைப்படம் திருத்தி +Name[tg]=KМуҳаррири тасвири ҳарита +Name[tr]=K Resim Haritası Düzenleyicisi +GenericName=HTML Image Map Editor +GenericName[bg]=Редактор на маркирания на изображения за HTML +GenericName[ca]=Un editor de mapes d'imatge HTML +GenericName[cs]=Editor HTML map +GenericName[da]=HTML editor af kortbilleder +GenericName[de]=Editor für HTML-Bildkarten (Imagemaps) +GenericName[el]=HTML επεξεργαστής εικόνων +GenericName[es]=Editor de mapas de imágenes HTML +GenericName[et]=Hüperpildiredaktor +GenericName[eu]=HTML irudi-mapa editorea +GenericName[fa]=ویرایشگر نگاشت تصویر زنگام +GenericName[fi]=HTML-kuvaeditori +GenericName[fr]=Éditeur d'hyperimages HTML +GenericName[gl]=Editor de mapas de imaxes HTML +GenericName[hu]=HTML-térképszerkesztő +GenericName[is]=HTML myndakortsritill +GenericName[it]=Editor per le mappe di immagini HTML +GenericName[ja]=HTML イメージマップエディタ +GenericName[ka]=HTML გამოსახულების რუქის რედაქტორი +GenericName[lt]=HTML paveikslėlių žemėlapių rengyklė +GenericName[ms]=Penyunting Peta Imej HTML +GenericName[nds]=Editor för HTML-Bildkoorten +GenericName[ne]=एचटीएमएल छवि मानचित्र सम्पादक +GenericName[nl]=HTML imagemap editor +GenericName[pa]=HTML ਚਿੱਤਰ ਨਕਸ਼ਾ ਸੰਪਾਦਕ +GenericName[pl]=Edytor map obrazków HTML +GenericName[pt]=Editor de Mapas de Imagem HTML +GenericName[pt_BR]=Editor de Mapeamento de Imagem HTML +GenericName[sk]=Editor HTML mapy obrázkov +GenericName[sl]=Urejevalnik slikovnih zemljevidov v HTML +GenericName[sr]=Уређивач HTML сликовне мапе +GenericName[sr@Latn]=Uređivač HTML slikovne mape +GenericName[sv]=Redigering av HTML-bildkartor +GenericName[ta]=HTML வடிவம் வரைப்படம் திருத்தி +GenericName[tg]=Муҳаррири тасвири ҳаритаи HTML +GenericName[tr]=HTML Resim Haritası Düzenleyicisi +GenericName[uk]=Редактор карт зображень HTML +GenericName[zh_CN]=HTML 图像映射编辑器 +GenericName[zh_HK]=HTML 影像地圖編輯器 +GenericName[zh_TW]=HTML 影像地圖編輯器 +Categories=Qt;KDE;Development;WebDevelopment; diff --git a/kimagemapeditor/kimagemapeditor.h b/kimagemapeditor/kimagemapeditor.h new file mode 100644 index 00000000..bf76349e --- /dev/null +++ b/kimagemapeditor/kimagemapeditor.h @@ -0,0 +1,460 @@ +/*************************************************************************** + imagemapeditor.h - description + ------------------- + begin : Wed Apr 4 2001 + copyright : (C) 2001 by Jan Sch�?fer + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 KIMAGEMAPDIALOG_H +#define KIMAGEMAPDIALOG_H + +#include <qptrlist.h> +#include <qobjectlist.h> +#include <qdict.h> +#include <qimage.h> +#include <kurl.h> +#include <kparts/part.h> +#include <kparts/browserextension.h> +#include <kparts/factory.h> + +#include <kdeversion.h> + +#include "kimearea.h" + +/** + *@author Jan Schaefer + */ + + +class QListView; +class QPushButton; +class DrawZone; +class QComboBox; +class QListViewItem; +class KToggleAction; + + + + +/** + * Stores an area tag and all its attributes + */ +typedef QDict<QString> AreaTag; + +/** + * Stores an image tag and all its attributes + * the origcode attribute hold the original htmlcode + * of this tag + */ +typedef QDict<QString> ImageTag; + +/** + * Only a small class to give a list of AreaTags a name + */ +class MapTag : public QPtrList<AreaTag> { +public: + MapTag(); + QString name; + bool modified; +}; + + +class HtmlElement { +public: + HtmlElement(const QString & s) { + htmlCode = s; + }; + virtual ~HtmlElement() {} + ; + QString htmlCode; +}; + +class HtmlMapElement : public HtmlElement { +public: + HtmlMapElement(const QString & s) : HtmlElement(s) { + mapTag = 0L; + }; + + virtual ~HtmlMapElement() {}; + + MapTag *mapTag; +}; + +class HtmlImgElement : public HtmlElement { +public: +HtmlImgElement(const QString & s) : HtmlElement(s) { + imgTag = 0L; + }; + virtual ~HtmlImgElement() {} + ; + ImageTag *imgTag; +}; + +/** + * Stores the hole HTML content in a List. + */ +class HtmlContent : public QPtrList<HtmlElement> {} +; + + +class KSelectAction; +class KRadioAction; +class KRecentFilesAction; +class KAction; +#if KDE_VERSION < 300 + class KAccel; +#endif +///class QListViewItem; +class KCommandHistory; +class KApplication; +class QTabWidget; +class AreaListView; +class ImagesListView; +class MapsListView; +class KDockWidget; +class KDockMainWindow; + +// needed by the statusbar +#define STATUS_CURSOR 1000 +#define STATUS_SELECTION 1001 + +class KImageMapEditor : public KParts::ReadWritePart { + Q_OBJECT +public : + enum ToolType { Selection, Rectangle, Circle, Polygon, Freehand, AddPoint, RemovePoint }; + + KImageMapEditor(QWidget *parentWidget, const char *, + QObject *parent, const char *name, const QStringList & args = QStringList()); + virtual ~KImageMapEditor(); + + static KAboutData *createAboutData(); + static KConfig *config(); + + /** + * Makes sure, that the actions cut, copy, delete and + * show properties + * can only be executed if sth. is selected. + **/ + void updateActionAccess(); + + DrawZone* getDrawZone() { + return drawZone; + }; + + void addAreaAndEdit(Area*); + void addArea(Area*); + AreaListIterator areaList() const; + KImageMapEditor::ToolType currentToolType() const; + void deleteSelected(); + void deleteArea( Area * area); + void deleteAllAreas(); + void deselectAll(); + void deselect(Area* s); + void deselectWithoutUpdate(Area*); + QString getHTMLImageMap() const; + Area* onArea(const QPoint & p) const; + QPixmap makeListViewPix(Area &) ; + QString mapName() const; + void select(Area*); + void selectWithoutUpdate(Area*); + void select(QListViewItem*); + AreaSelection* selected() const; + void setPicture(const QImage & pix); + int showTagEditor(Area *); + KCommandHistory *commandHistory() const; + + KApplication* app() const; + + // Only refreshes the listView + void updateSelection() const; + + void readConfig(); + void writeConfig(); + + virtual void readProperties(KConfig *); + virtual void saveProperties(KConfig *); + virtual bool closeURL(); + bool queryClose(); + virtual void setReadWrite(bool); + QString getHtmlCode(); + + /** + * Reimplemented to disable and enable Save action + */ + virtual void setModified(bool); + + /** + * Opens the given file. + * If it's an HTML file openURL is called + * If it's an Image, the image is added to the image list + */ + void openFile(const KURL &); + + /** + * Opens the last URL the user worked with. + * Sets also, the last map and the last image + */ + void openLastURL(KConfig*); + + void readConfig(KConfig*); + void writeConfig(KConfig*); + + virtual bool openURL(const KURL & url); + +protected: + void init(); + bool openHTMLFile(const KURL &, const QString & mapName = QString::null, const QString & imagePath = QString::null); + void saveImageMap(const KURL &); + + /** + * Returns a language dependend background picture, with + * the text : Drop an image or html file + */ + QImage getBackgroundImage(); + + + /** + * Saves information to restore the last working state + */ + void saveLastURL(KConfig*); + + +private: + // Stores the hole html file in a List + // The entries are either a MapTag an ImageTag or a QString + HtmlContent _htmlContent; + + // the url of the working image; + KURL _imageUrl; + QString _mapName; + QImage _backgroundImage; + + bool backupFileCreated; + + KImageMapEditor::ToolType _currentToolType; + AreaList *areas; + AreaSelection *currentSelected; + AreaSelection *copyArea; + Area *defaultArea; + DrawZone* drawZone; + QTabWidget* tabWidget; + AreaListView *areaListView; + ImagesListView* imagesListView; + MapsListView* mapsListView; + HtmlMapElement* currentMapElement; + + // + // Actions + // + KSelectAction* zoomAction; + KRadioAction *arrowAction; + KRadioAction *circleAction; + KRadioAction *rectangleAction; + KRadioAction *polygonAction; + KRadioAction *freehandAction; + KRadioAction *addPointAction; + KRadioAction *removePointAction; + + KAction *cutAction; + KAction *deleteAction; + KAction *copyAction; + KAction *pasteAction; + KAction *zoomInAction; + KAction *zoomOutAction; + + KAction *mapNewAction; + KAction *mapDeleteAction; + KAction *mapNameAction; + KAction *mapDefaultAreaAction; + + KAction *imageAddAction; + KAction *imageRemoveAction; + KAction *imageUsemapAction; + + KToggleAction *highlightAreasAction; + KToggleAction *showAltAction; + + KAction *areaPropertiesAction; + + KAction *moveLeftAction; + KAction *moveRightAction; + KAction *moveUpAction; + KAction *moveDownAction; + + KAction *increaseWidthAction; + KAction *decreaseWidthAction; + KAction *increaseHeightAction; + KAction *decreaseHeightAction; + + KAction *toFrontAction; + KAction *toBackAction; + KAction *forwardOneAction; + KAction *backOneAction; + + KToggleAction* configureShowAreaListAction; + KToggleAction* configureShowMapListAction; + KToggleAction* configureShowImageListAction; + + + KRecentFilesAction* recentFilesAction; + + #if KDE_VERSION < 300 + KAccel *accel; + #endif + + KDockMainWindow *mainDock; + KDockWidget* areaDock; + KDockWidget* mapsDock; + KDockWidget* imagesDock; + + KCommandHistory *_commandHistory; + int maxAreaPreviewHeight; + + QString cursorStatusText; + QString selectionStatusText; + + void setupActions(); + void setupStatusBar(); + void updateStatusBar(); + /* refreshes all Areas, only used by preferences dialog + * updates only the preview pictures*/ + void updateAllAreas(); + void updateUpDownBtn(); + + QDict<QString> getTagAttributes(QTextStream & s,QString &); + + void setMap(HtmlMapElement*); + void setMap(MapTag*); + void addMap(const QString &); + + // Returns the entire html file as a String + HtmlElement* findHtmlElement(const QString &); + HtmlImgElement* findHtmlImgElement(ImageTag*); + HtmlMapElement* findHtmlMapElement(const QString &); + void deleteAllMaps(); + void addImage(const KURL &); + void setImageActionsEnabled(bool); + void setMapActionsEnabled(bool); + + void saveAreasToMapTag(MapTag*); + void showPopupMenu(const QPoint &, const QString &); + void drawToCenter(QPainter* p, const QString & str, int y, int width); + +public slots: + void slotChangeStatusCoords(int x,int y); + void slotUpdateSelectionCoords(); + void slotUpdateSelectionCoords( const QRect &); + void slotAreaChanged(Area *); + void slotShowMainPopupMenu(const QPoint &); + void slotShowMapPopupMenu(QListViewItem *, const QPoint &); + void slotShowImagePopupMenu(QListViewItem *, const QPoint &); + void slotConfigChanged(); + void setPicture(const KURL & url); + void setMap(const QString &); + void setMapName(const QString & s); + + +protected slots: + // overriden from KReadWritePart + virtual bool openFile(); + + virtual bool saveFile() { + saveImageMap( url() ); +// setModified(false); + return true; + } + + void fileOpen(); + void fileSaveAs(); + void fileSave(); + void fileClose(); + + void slotShowPopupMenu(QListViewItem*,const QPoint &); + void slotShowPreferences(); + void slotHightlightAreas(); + void slotShowAltTag(); + void slotSelectionChanged(); + + int showTagEditor(QListViewItem *item); + int showTagEditor(); + + void slotZoom(); + void slotZoomIn(); + void slotZoomOut(); + + void slotCut(); + void slotCopy(); + void slotPaste(); + void slotDelete(); + + void slotDrawArrow(); + void slotDrawCircle(); + void slotDrawRectangle(); + void slotDrawPolygon(); + void slotDrawFreehand(); + void slotDrawAddPoint(); + void slotDrawRemovePoint(); + + void mapDefaultArea(); + void mapNew(); + void mapDelete(); + void mapEditName(); + void mapShowHTML(); + void mapPreview(); + + void slotBackOne(); + void slotForwardOne(); + void slotToBack(); + void slotToFront(); + + void slotMoveUp(); + void slotMoveDown(); + void slotMoveLeft(); + void slotMoveRight(); + + void slotIncreaseHeight(); + void slotDecreaseHeight(); + void slotIncreaseWidth(); + void slotDecreaseWidth(); + + void slotCancelDrawing(); + + void configureShowAreaList(); + void configureShowMapList(); + void configureShowImageList(); + + + // void slotPreferences(); + void imageAdd(); + void imageRemove(); + void imageUsemap(); + + void dockingStateChanged(); + +}; + + +inline KImageMapEditor::ToolType KImageMapEditor::currentToolType() const { + return _currentToolType; +} + +inline QString KImageMapEditor::mapName() const { + return _mapName; +} + +inline KCommandHistory* KImageMapEditor::commandHistory() const { + return _commandHistory; +} + + +#endif diff --git a/kimagemapeditor/kimagemapeditorpart.desktop b/kimagemapeditor/kimagemapeditorpart.desktop new file mode 100644 index 00000000..758b510a --- /dev/null +++ b/kimagemapeditor/kimagemapeditorpart.desktop @@ -0,0 +1,54 @@ +[Desktop Entry] +Type=Service +MimeType=text/html +Icon=kimagemapeditor +ServiceTypes=KParts/ReadWritePart +X-KDE-Library=libkimagemapeditor +Comment=An HTML imagemap editor +Comment[bg]=Редактор на маркирания на изображения за HTML +Comment[ca]=Un editor de mapes d'imatge HTML +Comment[cs]=Editor HTML map +Comment[da]=En HTML-editor af kortbilleder +Comment[de]=Ein Editor für HTML-Bildkarten (Imagemaps) +Comment[el]=HTML επεξεργαστής εικόνων +Comment[es]=Un editor de mapas de imágenes HTML +Comment[et]=Hüperpildiredaktor +Comment[eu]=HTML irudi-mapa editore bat +Comment[fa]=یک ویرایشگر نگاشت تصویر زنگام +Comment[fi]=HTML-imagemap -editori +Comment[fr]=Éditeur d'hyperimages HTML +Comment[gl]=Un editor de mapas de imaxes HTML +Comment[hu]=HTML-térképszerkesztő +Comment[is]=HTML myndakortsritill +Comment[it]=Un editor per le mappe di immagini HTML +Comment[ja]=HTML イメージマップエディタ +Comment[ka]=HTML გამოსახულების რუქის რედაქტორი +Comment[lt]=HTML paveikslėlių žemėlapių rengyklė +Comment[ms]=Penyunting Peta Imej HTML +Comment[nds]=En Editor för HTML-Bildkoorten +Comment[ne]=एउटा एचटीएमएल छवि मानचित्र सम्पादकस +Comment[nl]=Een hulpmiddel om HTML imagemaps te maken +Comment[pl]=Edytor map obrazków HTML +Comment[pt]=Editor de Mapas de Imagem HTML +Comment[pt_BR]=Um editor de mapeamento de imagem HTML +Comment[ru]=Редактор HTML imagemap +Comment[sk]=Editor HTML mapy obrázkov +Comment[sl]=Urejevalnik slikovnih zemljevidov v HTML +Comment[sr]=Уређивач HTML сликовне мапе +Comment[sr@Latn]=Uređivač HTML slikovne mape +Comment[sv]=En editor för HTML-bildkartor +Comment[ta]=An HTML வடிவம் வரைப்படம் திருத்தி +Comment[tg]=Муҳаррири тасвири ҳаритаи HTML +Comment[tr]=Bir HTML resim_haritası düzenleyicisi +Comment[uk]=Редактор imagemap HTML +Comment[zh_CN]=HTML 图像映射编辑器 +Comment[zh_HK]=一個 HTML 影像地圖的編輯器 +Comment[zh_TW]=一個 HTML 影像地圖的編輯器 +Name=KImageMapEditor +Name[ne]=केडीई छवि मानचित्र सम्पादक +Name[pt_BR]=KEditor de Mapeamento de Imagem +Name[sk]=KImage editor mapy +Name[sv]=Kimagemapeditor +Name[ta]=Kவடிவம் வரைப்படம் திருத்தி +Name[tg]=KМуҳаррири тасвири ҳарита +Name[tr]=K Resim Haritası Düzenleyicisi diff --git a/kimagemapeditor/kimagemapeditorpartui.rc b/kimagemapeditor/kimagemapeditorpartui.rc new file mode 100644 index 00000000..6f6df968 --- /dev/null +++ b/kimagemapeditor/kimagemapeditorpartui.rc @@ -0,0 +1,150 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui name="kimagemapeditorpart" version="20"> + <MenuBar> + <Menu name="file"> + <Action name="file_open"/> + <Action name="file_open_recent"/> + <Separator/> + <Action name="file_save"/> + <Action name="file_save_as"/> + <Separator/> + <Action name="file_close"/> + </Menu> + <Menu name="edit" noMerge="1"> + <text>&Edit</text> + <Action name="edit_undo" /> + <Action name="edit_redo" /> + <Separator/> + <Action name="edit_cut" /> + <Action name="edit_copy" /> + <Action name="edit_paste" /> + <Action name="edit_delete" /> + <Separator/> + <Action name="tofront" /> + <Action name="toback" /> + <Action name="forwardone" /> + <Action name="backone" /> + <Separator/> + <Action name="edit_properties" /> + </Menu> + <Menu name="view" > + <text>&View</text> + <Action name="view_zoom_in"/> + <Action name="view_zoom_out"/> + <Action name="view_zoom"/> + <Separator/> + <Action name="view_highlightareas"/> + <Action name="view_showalt"/> + </Menu> + <Menu name="tools" > + <text>&Tools</text> + <Action name="tool_arrow" /> + <Action name="tool_circle" /> + <Action name="tool_rectangle" /> + <Action name="tool_polygon" /> + <Action name="tool_freehand" /> + <Action name="tool_addpoint" /> + <Action name="tool_removepoint" /> + </Menu> + <Menu name="map" > + <text>&Map</text> + <Action name="map_name" /> + <Action name="map_new" /> + <Action name="map_delete" /> + <Separator/> + <Action name="map_defaultarea" /> + <Separator/> + <Action name="map_showhtml" /> + <Action name="map_preview" /> + </Menu> + <Menu name="images" > + <text>&Image</text> + <Action name="image_usemap" /> + <Action name="image_remove" /> + <Action name="image_add" /> + </Menu> + <Menu name="settings"><text>&Settings</text> + <Separator/> + <Action name="configure_show_arealist" group="settings_show"/> + <Action name="configure_show_maplist" group="settings_show"/> + <Action name="configure_show_imagelist" group="settings_show"/> + <Separator/> + <Action name="configure_kimagemapeditor" group="settings_configure"/> + </Menu> + </MenuBar> + <StatusBar/> + <ToolBar name="mainToolBar"> + <text>KImageMapEditor Main Toolbar</text> + <Action name="file_open"/> + <Action name="file_save"/> + <Action name="file_save_as"/> + <Separator/> + <Action name="edit_undo" /> + <Action name="edit_redo" /> + <Separator/> + <Action name="edit_cut" /> + <Action name="edit_copy" /> + <Action name="edit_paste" /> + <Action name="edit_delete" /> + <Separator/> + <Action name="view_zoom_in"/> + <Action name="view_zoom_out"/> + <Action name="view_zoom"/> + <Separator/> + </ToolBar> + <ToolBar noMerge="1" name="kImageMapEditorPartDrawToolBar"> + <text>KImageMapEditor Draw Toolbar</text> + <Action name="tool_arrow" /> + <Action name="tool_circle" /> + <Action name="tool_rectangle" /> + <Action name="tool_polygon" /> + <Action name="tool_freehand" /> + <Action name="tool_addpoint" /> + <Action name="tool_removepoint" /> + </ToolBar> + <Menu name="popup_main"> + <Action name="edit_properties" /> + <Separator/> + <Action name="edit_cut" /> + <Action name="edit_copy" /> + <Action name="edit_paste" /> + <Action name="edit_delete" /> + <Separator/> + <Action name="tofront" /> + <Action name="toback" /> + <Action name="forwardone" /> + <Action name="backone" /> + </Menu> + <Menu name="popup_map"> + <Action name="map_name" /> + <Action name="map_new" /> + <Action name="map_delete" /> + <Action name="map_defaultarea" /> + </Menu> + <Menu name="popup_image"> + <Action name="image_usemap" /> + <Action name="image_remove" /> + <Action name="image_add" /> + </Menu> + + + <ActionProperties> + <Action shortcut="Left" name="moveleft" /> + <Action shortcut="Right" name="moveright" /> + <Action shortcut="Down" name="movedown" /> + <Action shortcut="Up" name="moveup" /> + <Action shortcut="Shift+Left" name="decreasewidth" /> + <Action shortcut="Shift+Right" name="increasewidth" /> + <Action shortcut="Shift+Down" name="decreaseheight" /> + <Action shortcut="Shift+Up" name="increaseheight" /> + <Action shortcut="Escape" name="canceldrawing" /> + + </ActionProperties> +</kpartgui> + + + + + + + diff --git a/kimagemapeditor/kimagemapeditorui.rc b/kimagemapeditor/kimagemapeditorui.rc new file mode 100644 index 00000000..68bb713a --- /dev/null +++ b/kimagemapeditor/kimagemapeditorui.rc @@ -0,0 +1,25 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui name="kimagemapeditor" version="16"> + <MenuBar> + <Menu name="file"><text>&File</text> + <Merge/> + </Menu> + <Menu name="settings"> + <DefineGroup name="settings_show" append="show_merge"/> + <DefineGroup name="settings_configure" append="configure_merge"/> + </Menu> + <Merge/> + </MenuBar> + <StatusBar/> + <ToolBar noMerge="1" name="mainToolBar"> + <text>KImageMapEditor Main Toolbar</text> + <Action name="file_new" /> + </ToolBar> +</kpartgui> + + + + + + + diff --git a/kimagemapeditor/kimearea.cpp b/kimagemapeditor/kimearea.cpp new file mode 100644 index 00000000..cb873564 --- /dev/null +++ b/kimagemapeditor/kimearea.cpp @@ -0,0 +1,1749 @@ +/*************************************************************************** + kimearea.cpp - description + ------------------- + begin : Thu Jun 14 2001 + copyright : (C) 2001 by Jan Schaefer + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 <qbitmap.h> +#include <qpointarray.h> +#include <qpainter.h> +#include <qpixmap.h> +#include <qimage.h> +#include <qpen.h> +#include <qbrush.h> +#include <qpalette.h> +#include <qcolor.h> +#include <qlistview.h> + +#include <kdebug.h> + +#include "kimearea.h" +#include "kimecommon.h" + + +#define SELSIZE 7 + + +bool Area::highlightArea; +bool Area::showAlt; + + +Area::Area() +{ + _coords=new QPointArray(); + _selectionPoints= new SelectionPointList(); + _selectionPoints->setAutoDelete(true); + _finished=false; + _isSelected=false; + _name=i18n("noname"); + _listViewItem=0L; + currentHighlighted=-1; + _type=Area::None; + _highlightedPixmap=0L; + +} + +Area* Area::clone() const +{ + Area* areaClone = new Area(); + areaClone->setArea( *this ); + return areaClone; +} + +QPointArray* Area::coords() const { + return _coords; +} + +QString Area::getHTMLAttributes() const +{ + QString retStr=""; + + for (AttributeIterator it = firstAttribute();it!=lastAttribute();++it) + { + retStr+=it.key()+"=\""+it.data()+"\" "; + } + + return retStr; +} + + +Area::~Area() { + delete _coords; + delete _selectionPoints; + delete _highlightedPixmap; + +} + +bool Area::contains(const QPoint &) const { + return false; +} + +QString Area::getHTMLCode() const { + return ""; +} + +QString Area::attribute(const QString & name) const +{ + return _attributes[name.lower()]; +} + +void Area::setAttribute(const QString & name, const QString & value) +{ + _attributes.replace(name.lower(),value); + if (value.isEmpty()) + _attributes.remove(name.lower()); +} + +AttributeIterator Area::firstAttribute() const +{ + return _attributes.begin(); +} + +AttributeIterator Area::lastAttribute() const +{ + return _attributes.end(); +} + + +bool Area::setCoords(const QString &) { + return true; +} + +void Area::moveSelectionPoint(QRect*, const QPoint &) +{} + + + // Default implementation; is specified by subclasses +QString Area::coordsToString() const +{ + return ""; +} + + +Area::ShapeType Area::type() const { + return _type; +} + +void Area::setArea(const Area & copy) +{ + delete _coords; + delete _selectionPoints; + _coords=new QPointArray(copy.coords()->copy()); + _selectionPoints= new SelectionPointList(); + currentHighlighted=-1; + + // Need a deep copy of the list + for (QRect *r=copy.selectionPoints()->first();r!=0L;r=copy.selectionPoints()->next()) + _selectionPoints->append(new QRect( r->topLeft(),r->bottomRight() ) ); + + _finished=copy.finished(); + _isSelected=copy.isSelected(); + _rect = copy.rect(); + + for (AttributeIterator it = copy.firstAttribute();it!=copy.lastAttribute();++it) + { + setAttribute(it.key(),it.data()); + } + + setMoving(copy.isMoving()); + +// _listViewItem=0L; + +} + +void Area::setListViewItem(QListViewItem* item) { + _listViewItem=item; +} + +void Area::deleteListViewItem() +{ + delete _listViewItem; + _listViewItem = 0L; +} + + +void Area::setRect(const QRect & r) +{ + _rect=r; + updateSelectionPoints(); +} + +QRect Area::rect() const { + return _rect; +} + +void Area::setMoving(bool b) { + _isMoving=b; +} + + +void Area::moveBy(int dx, int dy) { + _rect.moveBy(dx,dy); + for (uint i=0;i<_coords->size();i++) { + int newX=_coords->point(i).x()+dx; + int newY=_coords->point(i).y()+dy; + _coords->setPoint(i,newX,newY); + } + + for (QRect *r=_selectionPoints->first();r!=0L;r=_selectionPoints->next()) { + r->moveBy(dx,dy); + } +} + + +void Area::moveTo(int x, int y) { + int dx=x-rect().left(); + int dy=y-rect().top(); + moveBy(dx,dy); +} + +uint Area::countSelectionPoints() const +{ + return (uint) selectionPoints()->count(); +} + +int Area::addCoord(const QPoint & p) +{ + _coords->resize(_coords->size()+1); + _coords->setPoint(_coords->size()-1,p); + + QRect *r= new QRect(0,0,SELSIZE,SELSIZE); + r->moveCenter(p); + _selectionPoints->append(r); + setRect(_coords->boundingRect()); + + return _coords->size()-1; +} + +void Area::insertCoord(int pos, const QPoint & p) +{ + +/* + kdDebug() << p.x() << "," << p.y() << endl; + + if ( _coords->size()>0 ) + { + for (int i=0; i<_coords->size(); i++) + { + if (p==_coords->point(i)) + { + kdDebug() << "same Point already exists" << endl; + return; + } + + } + } +*/ + _coords->resize(_coords->size()+1); + + + for (int i=_coords->size()-1;i>pos;i--) { + _coords->setPoint(i,_coords->point(i-1)); + } + _coords->setPoint(pos, p); + + QRect *r= new QRect(0,0,SELSIZE,SELSIZE); + r->moveCenter(p); + _selectionPoints->insert(pos,r); + setRect(_coords->boundingRect()); +} + +void Area::removeCoord(int pos) { + + int count=_coords->size(); + + if (count<4) + { + kdDebug() << "Danger : trying to remove coordinate from Area with less then 4 coordinates !" << endl; + return; + } + + for (int i=pos;i<(count-1);i++) + _coords->setPoint(i, _coords->point(i+1)); + + _coords->resize(count-1); + _selectionPoints->remove(pos); + setRect(_coords->boundingRect()); +} + +bool Area::removeSelectionPoint(QRect * r) +{ + if (_selectionPoints->contains(r)) + { + removeCoord(_selectionPoints->find(r)); + return true; + } + + return false; +} + + +void Area::moveCoord(int pos, const QPoint & p) { + _coords->setPoint(pos,p); + _selectionPoints->at(pos)->moveCenter(p); + setRect(_coords->boundingRect()); +} + +void Area::setSelected(bool b) +{ + _isSelected=b; + if (_listViewItem) { + _listViewItem->setSelected(b); + } +} + +void Area::highlightSelectionPoint(int number){ + currentHighlighted=number; +} + +QRect Area::selectionRect() const { + QRect r = rect(); + r.moveBy(-SELSIZE*2,-SELSIZE*2); + r.setSize(r.size()+QSize(SELSIZE*4,SELSIZE*4)); + + return r; +} + +void Area::drawHighlighting(QPainter & p) +{ + if (Area::highlightArea && !isMoving() && _highlightedPixmap) + { + p.setRasterOp(Qt::CopyROP); + + QPoint point = QPoint(rect().x(),rect().y()); + if (point.x()<0) + point.setX(0); + if (point.y()<0) + point.setY(0); + + p.drawPixmap( point, *_highlightedPixmap); + + } +} + +void Area::drawAlt(QPainter & p) +{ + double x,y; + + double scalex = p.worldMatrix().m11(); +// double scaley = p.worldMatrix().m12(); + + QWMatrix oldMatrix = p.worldMatrix(); + + p.setWorldMatrix(QWMatrix(1,oldMatrix.m12(), oldMatrix.m21(), 1, oldMatrix.dx(), oldMatrix.dy() )); + + x = (rect().x()+rect().width()/2)*scalex; + y = (rect().y()+rect().height()/2)*scalex; + + QFontMetrics metrics = p.fontMetrics(); + + int w = metrics.width(attribute("alt")); + x -= w/2; + y += metrics.height()/4; + + + + if (highlightArea) + { + p.setRasterOp(Qt::CopyROP); + p.setPen(Qt::black); + } + else + { + p.setRasterOp(Qt::XorROP); + p.setPen(QPen(QColor("white"),1)); + } + + p.drawText(myround(x),myround(y),attribute("alt")); + + p.setWorldMatrix(oldMatrix); +} + +void Area::draw(QPainter & p) +{ + + // Only draw the selection points at base class + // the rest is done in the derived classes + if (_isSelected) + { + int i=0; + + double scalex = p.worldMatrix().m11(); +// double scaley = p.worldMatrix().m12(); + + QWMatrix oldMatrix = p.worldMatrix(); + + p.setWorldMatrix(QWMatrix(1,oldMatrix.m12(), oldMatrix.m21(), 1, oldMatrix.dx(), oldMatrix.dy() )); + + for (QRect *r=_selectionPoints->first();r!=0L;r=_selectionPoints->next()) { + + // Draw a green circle around the selected point ( only when editing a polygon ) + if (i==currentHighlighted) { + QRect r2(0,0,15,15); + r2.moveCenter(r->center()*scalex); + p.setRasterOp(Qt::CopyROP); + p.setPen(QPen(QColor("lightgreen"),2)); + p.drawEllipse(r2); + p.setRasterOp(Qt::XorROP); + p.setPen(QPen(QColor("white"),1)); + } + + // Draw the selection point + p.setRasterOp(Qt::XorROP); + + QRect r3(*r); + int d = 1; + if (scalex > 2) d=0; + + r3.moveCenter( QPoint((int)(r3.center().x()*scalex),(int)(r3.center().y()*scalex)) ); + + p.fillRect(r3,QBrush("white")); +/* + QRect r3(*r); + r3.moveTopLeft( QPoint(r3.left()*scalex+2*(scalex-1), r3.top()*scalex+2*(scalex-1)) ); + + r3.setSize(r3.size()+QSize(2,2)); +//+ r3.moveBy(-1,-1); + p.setRasterOp(Qt::CopyROP); + p.setPen(QPen(QColor("lightgreen"),1)); + p.setBrush(QColor("lightgreen")); + p.drawPie(r3,0,5760); + p.setPen(QPen(QColor("black"),1)); + r3.setSize(r3.size()+QSize(2,2)); + r3.moveBy(-1,-1); + p.drawEllipse(r3); +*/ + i++; + } + p.setWorldMatrix(oldMatrix); + + + } + + if (showAlt) + { + drawAlt(p); + } + p.setRasterOp(Qt::XorROP); + +} + +QRect* Area::onSelectionPoint(const QPoint & p, double zoom) const +{ + for (QRect *r=_selectionPoints->first();r!=0L;r=_selectionPoints->next()) + { + QRect r2(r->topLeft(),r->bottomRight()); + + r2.moveCenter(r2.center()*zoom); + + if (r2.contains(p)) + { + + return r; + } + } + + return 0L; +} + + + + +/** + * returns only the part of the image which is + * covered by the area + */ +QPixmap Area::cutOut(const QImage & image) +{ + if ( 0>=rect().width() || + 0>=rect().height() || + !rect().intersects(image.rect()) ) + { + QPixmap dummyPix(10,10); + dummyPix.fill(); + delete _highlightedPixmap; + _highlightedPixmap = 0L; + return dummyPix; + } + + // Get the mask from the subclasses + QBitmap mask=getMask(); + + // The rectangle which is part of the image + QRect partOfImage=rect(); + QRect partOfMask(0,0,mask.width(),mask.height()); + + + // If the area is outside of the image make the + // preview smaller + if ( (rect().x()+rect().width()) > image.width() ) { + partOfImage.setWidth( image.width()-rect().x() ); + partOfMask.setWidth( image.width()-rect().x() ); + } + + if ( (rect().x() < 0) ) { + partOfImage.setX(0); + partOfMask.setX(myabs(rect().x())); + } + + if ( (rect().y()+rect().height()) > image.height() ) { + partOfImage.setHeight( image.height()-rect().y() ); + partOfMask.setHeight ( image.height()-rect().y() ); + } + + if ( (rect().y() < 0) ) { + partOfImage.setY(0); + partOfMask.setY(myabs(rect().y())); + } + + QImage tempImage=mask.convertToImage().copy(partOfMask); + mask.convertFromImage(tempImage); + +// partOfImage = partOfImage.normalize(); + QImage cut=image.copy(partOfImage); + + QPixmap pix; + +// partOfMask = partOfMask.normalize(); + if (!partOfMask.isValid()) + kdDebug() << "PartofMask not valid : " << partOfMask.x() << "," << partOfMask.y() << "," + << partOfMask.width() << "," << partOfMask.height() << "," << endl; + +/* + QBitmap mask2(partOfMask.width(), partOfMask.height()); + QPainter p4(&mask2); + p4.drawPixmap( QPoint(0,0) ,mask,partOfMask); + p4.flush(); + p4.end(); +*/ + + pix.convertFromImage(cut); + + setHighlightedPixmap(cut, mask); + + QPixmap retPix(pix.width(),pix.height()); + QPainter p3(&retPix); + + // if transparent image fill the background + // with gimp-like rectangles + if (pix.mask()) { + QPixmap backPix(32,32); + + // Gimp like transparent rectangle + QPainter p2(&backPix); + p2.fillRect(0,0,32,32,QColor(156,149,156)); + p2.fillRect(0,16,16,16,QColor(98,105,98)); + p2.fillRect(16,0,16,16,QColor(98,105,98)); + p2.flush(); + + p3.setPen(QPen()); + p3.fillRect(0,0,pix.width(),pix.height(),QBrush(QColor("black"),backPix)); + } + + + p3.drawPixmap(QPoint(0,0),pix); + p3.flush(); + p3.end(); + retPix.setMask(mask); + + return retPix; +} + +QBitmap Area::getMask() const +{ + QBitmap b; + return b; +} + +void Area::setHighlightedPixmap( QImage & im, QBitmap & mask ) +{ + if (!Area::highlightArea) + return; + + delete _highlightedPixmap; + + QImage image = im.convertDepth( 32 ); + QSize size = image.size(); + QColor pixel; + double r,g,b; + + + // highlight every pixel + for (int y=0; y < size.height(); y++) + { + for (int x=0; x < size.width(); x++) + { + r = qRed(image.pixel(x,y)); + g = qGreen(image.pixel(x,y)); + b = qBlue(image.pixel(x,y)); + r = (r *123 / 255)+132; + g = (g *123 / 255)+132; + b = (b *123 / 255)+132; + + pixel.setRgb( (int) r, (int) g, (int) b); + image.setPixel(x,y, pixel.rgb()); + } + } + + _highlightedPixmap = new QPixmap(); + _highlightedPixmap->convertFromImage( image ); + _highlightedPixmap->setMask( mask ); + + if (_highlightedPixmap->isNull()) + kdDebug() << "HighlightedPixmap is null" << endl; + +} + +/******************************************************************** + * RECTANGLE + *******************************************************************/ + + +RectArea::RectArea() + : Area() +{ + QRect *p = new QRect(0,0,SELSIZE,SELSIZE); + _selectionPoints->append(p); + p = new QRect(0,0,SELSIZE,SELSIZE); + _selectionPoints->append(p); + p = new QRect(0,0,SELSIZE,SELSIZE); + _selectionPoints->append(p); + p = new QRect(0,0,SELSIZE,SELSIZE); + _selectionPoints->append(p); + _type=Area::Rectangle; + +} + +RectArea::~RectArea() { +} + +Area* RectArea::clone() const +{ + Area* areaClone = new RectArea(); + areaClone->setArea( *this ); + return areaClone; +} + +void RectArea::draw(QPainter & p) +{ + + drawHighlighting(p); +// p.setRasterOp(Qt::CopyROP); +// p.setRasterOp(Qt:: OrROP); +// QBrush b(QBrush::SolidPattern); +// QBrush b(QBrush::Dense4Pattern); +// QBrush b(QBrush::BDiagPattern); +// b.setColor(QColor(32,32,32)); +// p.fillRect(rect(), b); + + p.setRasterOp(Qt::XorROP); + p.setPen(QPen(QColor("white"),1)); + QRect r(rect()); + r.setWidth(r.width()+1); + r.setHeight(r.height()+1); + p.drawRect(r); + + Area::draw(p); +} + +QBitmap RectArea::getMask() const +{ + QBitmap mask(rect().width(),rect().height()); + + mask.fill(Qt::color0); + QPainter p(&mask); + p.setBackgroundColor(Qt::color0); + p.setPen(Qt::color1); + p.setBrush(Qt::color1); + mask.fill(Qt::color1); + p.end(); + + return mask; +} + +QString RectArea::coordsToString() const +{ + QString retStr=QString("%1,%2,%3,%4") + .arg(rect().left()) + .arg(rect().top()) + .arg(rect().right()) + .arg(rect().bottom()); + + return retStr; +} + +bool RectArea::contains(const QPoint & p) const{ + return rect().contains(p); +} + +void RectArea::moveSelectionPoint(QRect* selectionPoint, const QPoint & p) +{ + selectionPoint->moveCenter(p); + int i=0; + for (QRect *r=_selectionPoints->first();r!=0L;r=_selectionPoints->next()) { + if (r==selectionPoint) + break; + i++; + } + QRect r2(_rect); + switch (i) { + case 0 : _rect.setLeft(p.x()); + _rect.setTop(p.y()); + break; + case 1 : _rect.setRight(p.x()); + _rect.setTop(p.y()); + break; + case 2 : _rect.setLeft(p.x()); + _rect.setBottom(p.y()); + break; + case 3 : _rect.setRight(p.x()); + _rect.setBottom(p.y()); + break; + } + if ( ! _rect.isValid()) + _rect=r2; + + updateSelectionPoints(); +} + +void RectArea::updateSelectionPoints() +{ + _selectionPoints->first()->moveCenter(_rect.topLeft()); + _selectionPoints->next()->moveCenter(_rect.topRight()+QPoint(1,0)); + _selectionPoints->next()->moveCenter(_rect.bottomLeft()+QPoint(0,1)); + _selectionPoints->next()->moveCenter(_rect.bottomRight()+QPoint(1,1)); +} + +bool RectArea::setCoords(const QString & s) +{ + _finished=true; + + QStringList list=QStringList::split(",",s); + QRect r; + bool ok=true; + QStringList::Iterator it = list.begin(); + r.setLeft((*it).toInt(&ok,10));it++; + r.setTop((*it).toInt(&ok,10));it++; + r.setRight((*it).toInt(&ok,10));it++; + r.setBottom((*it).toInt(&ok,10)); + if (ok) { + setRect(r); + return true; + } else + return false; +} + +QString RectArea::getHTMLCode() const { + QString retStr; + retStr+="<area "; + retStr+="shape=\"rect\" "; + + retStr+=getHTMLAttributes(); + + retStr+="coords=\""+coordsToString()+"\" "; + retStr+="/>"; + return retStr; + +} + +/******************************************************************** + * CIRCLE + *******************************************************************/ + + +CircleArea::CircleArea() + : Area() +{ + _type=Area::Circle; + QRect *p = new QRect(0,0,SELSIZE,SELSIZE); + _selectionPoints->append(p); + p = new QRect(0,0,SELSIZE,SELSIZE); + _selectionPoints->append(p); + p = new QRect(0,0,SELSIZE,SELSIZE); + _selectionPoints->append(p); + p = new QRect(0,0,SELSIZE,SELSIZE); + _selectionPoints->append(p); +} + +CircleArea::~CircleArea() { +} + +Area* CircleArea::clone() const +{ + Area* areaClone = new CircleArea(); + areaClone->setArea( *this ); + return areaClone; +} + +void CircleArea::draw(QPainter & p) +{ + drawHighlighting(p); + +/* + p.setRasterOp(Qt::CopyROP); + QBrush bold = p.brush(); + QBrush b(QBrush::Dense5Pattern); + b.setColor(QColor("green")); + p.setBrush(b); + QRect r = _rect; + r.moveBy(1,1); + r.setSize( r.size()-QSize(2,2) ); + p.drawChord(r,0,5760); + p.setBrush(bold); +*/ + p.setRasterOp(Qt::XorROP); + p.setPen(QPen(QColor("white"),1)); + + QRect r(_rect); + r.setWidth(r.width()+1); + r.setHeight(r.height()+1); + p.drawEllipse(r); + + Area::draw(p); +} + +QBitmap CircleArea::getMask() const +{ + QBitmap mask(_rect.width(),_rect.height()); + + mask.fill(Qt::color0); + QPainter p(&mask); + p.setBackgroundColor(Qt::color0); + p.setPen(Qt::color1); + p.setBrush(Qt::color1); + p.drawPie(QRect(0,0,_rect.width(),_rect.height()),0,5760); + p.flush(); + p.end(); + + + return mask; + +} + +QString CircleArea::coordsToString() const +{ + QString retStr=QString("%1,%2,%3") + .arg(_rect.center().x()) + .arg(_rect.center().y()) + .arg(_rect.width()/2); + + return retStr; +} + +bool CircleArea::contains(const QPoint & p) const +{ + QRegion r(_rect,QRegion::Ellipse); + return r.contains(p); +} + +void CircleArea::moveSelectionPoint(QRect* selectionPoint, const QPoint & p) +{ + selectionPoint->moveCenter(p); + + int i=0; + for (QRect *r=_selectionPoints->first();r!=0L;r=_selectionPoints->next()) { + if (r==selectionPoint) + break; + i++; + } + + // The code below really sucks, but I have no better idea. + // it only makes sure that the circle is perfektly round + QPoint newPoint; + int diff=myabs(p.x()-_rect.center().x()); + if (myabs(p.y()-_rect.center().y())>diff) + diff=myabs(p.y()-_rect.center().y()); + + newPoint.setX( p.x()-_rect.center().x()<0 + ? _rect.center().x()-diff + : _rect.center().x()+diff); + + newPoint.setY( p.y()-_rect.center().y()<0 + ? _rect.center().y()-diff + : _rect.center().y()+diff); + + switch (i) { + case 0 : if (newPoint.x() < _rect.center().x() && + newPoint.y() < _rect.center().y()) + { + _rect.setLeft(newPoint.x()); + _rect.setTop(newPoint.y()); + } + break; + case 1 : if (newPoint.x() > _rect.center().x() && + newPoint.y() < _rect.center().y()) + { + _rect.setRight(newPoint.x()); + _rect.setTop(newPoint.y()); + } + break; + case 2 : if (newPoint.x() < _rect.center().x() && + newPoint.y() > _rect.center().y()) + { + _rect.setLeft(newPoint.x()); + _rect.setBottom(newPoint.y()); + } + break; + case 3 : if (newPoint.x() > _rect.center().x() && + newPoint.y() > _rect.center().y()) + { + _rect.setRight(newPoint.x()); + _rect.setBottom(newPoint.y()); + } + break; + } + + + + updateSelectionPoints(); + +} + +void CircleArea::setRect(const QRect & r) +{ + QRect r2 = r; + if ( r2.height() != r2.width() ) + r2.setHeight( r2.width() ); + + Area::setRect(r2); +} + + +void CircleArea::updateSelectionPoints() +{ + _selectionPoints->first()->moveCenter(_rect.topLeft()); + _selectionPoints->next()->moveCenter(_rect.topRight()); + _selectionPoints->next()->moveCenter(_rect.bottomLeft()); + _selectionPoints->next()->moveCenter(_rect.bottomRight()); +} + +bool CircleArea::setCoords(const QString & s) +{ + _finished=true; + QStringList list=QStringList::split(",",s); + bool ok=true; + QStringList::Iterator it = list.begin(); + int x=(*it).toInt(&ok,10);it++; + int y=(*it).toInt(&ok,10);it++; + int rad=(*it).toInt(&ok,10); + if (!ok) return false; + QRect r; + r.setWidth(rad*2); + r.setHeight(rad*2); + r.moveCenter(QPoint(x,y)); + setRect(r); + return true; +} + +QString CircleArea::getHTMLCode() const { + QString retStr; + retStr+="<area "; + retStr+="shape=\"circle\" "; + + retStr+=getHTMLAttributes(); + + retStr+="coords=\""+coordsToString()+"\" "; + retStr+="/>"; + return retStr; + +} + + +/******************************************************************** + * POLYGON + *******************************************************************/ + + +PolyArea::PolyArea() + : Area() +{ + _type=Area::Polygon; +} + +PolyArea::~PolyArea() { +} + +Area* PolyArea::clone() const +{ + Area* areaClone = new PolyArea(); + areaClone->setArea( *this ); + return areaClone; +} + +void PolyArea::draw(QPainter & p) +{ + drawHighlighting(p); + + p.setRasterOp(Qt::XorROP); + p.setPen(QPen(QColor("white"),1)); + if (_coords->count()==0) return; + + + + if (_finished) + p.drawPolygon ( *_coords,false,0,_coords->count()); + else + p.drawPolyline ( *_coords,0,_coords->count()); + +/* + p.moveTo(_coords->point(0)); + for (int i=1;i<_coords->count();i++) + p.lineTo(_coords->point(i)); + + if (_finished) + p.lineTo(_coords->point(0)); +*/ + Area::draw(p); +} + +QBitmap PolyArea::getMask() const +{ + QBitmap mask(_rect.width(),_rect.height()); + + mask.fill(Qt::color0); + QPainter p(&mask); + p.setBackgroundColor(Qt::color0); + p.setPen(Qt::color1); + p.setBrush(Qt::color1); + p.setClipping(true); + QRegion r(*_coords); + r.translate(-_rect.left(),-_rect.top()); + p.setClipRegion(r); + p.fillRect(QRect(0,0,_rect.width(),_rect.height()),Qt::color1); + p.flush(); + p.end(); + + return mask; +} + +QString PolyArea::coordsToString() const +{ + QString retStr; + + for (uint i=0;i<_coords->count();i++) { + retStr.append(QString("%1,%2,") + .arg(_coords->point(i).x()) + .arg(_coords->point(i).y())); + } + + retStr.remove(retStr.length()-1,1); + + return retStr; +} + +int PolyArea::distance(const QPoint &p1, const QPoint &p2) +{ + QPoint temp = p1-p2; + return temp.manhattanLength(); +} + +bool PolyArea::isBetween(const QPoint &p, const QPoint &p1, const QPoint &p2) +{ + int dist = distance(p,p1)+distance(p,p2)-distance(p1,p2); + + if (myabs(dist)<1) + return true; + else + return false; +} + +void PolyArea::simplifyCoords() +{ + if (_coords->size()<4) + return; + + QPoint p = _coords->point(0) - _coords->point(1); + + uint i = 1; + + + while( (i<_coords->size()) && (_coords->size() > 3) ) + { + p = _coords->point(i-1) - _coords->point(i); + + if (p.manhattanLength() < 3) + removeCoord(i); + else + i++; + } + + p = _coords->point(0) - _coords->point(1); + + double angle2; + double angle1; + + if (p.y()==0) + angle1 = 1000000000; + else + angle1 = (double) p.x() / (double) p.y(); + + i=2; + + while( (i<_coords->size()) && (_coords->size() > 3) ) + { + p = _coords->point(i-1) - _coords->point(i); + + if (p.y()==0) + angle2 = 1000000000; + else + angle2 = (double) p.x() / (double) p.y(); + + if ( angle2==angle1 ) + { + kdDebug() << "removing " << i-1 << endl; + removeCoord(i-1); + } + else + { + i++; + kdDebug() << "skipping " << i-1 << " cause " << angle1 << "!= " << angle2 << endl; + angle1 = angle2; + + } + + } + + + +} + + +int PolyArea::addCoord(const QPoint & p) +{ + if (_coords->size()<3) + { + return Area::addCoord(p); + } + + if (_coords->point(_coords->size()-1) == p) + { + kdDebug() << "equal Point added" << endl; + return -1; + + } + + int n=_coords->size(); + +// QPoint temp = p-_coords->point(0); + int nearest = 0; + int olddist = distance(p,_coords->point(0)); + int mindiff = 999999999; + + // find the two points, which are the nearest one to the new point + for (int i=1; i <= n; i++) + { + int dist = distance(p,_coords->point(i%n)); + int dist2 = distance(_coords->point(i-1),_coords->point(i%n)); + int diff = myabs(dist+olddist-dist2); + if ( diff<mindiff ) + { + mindiff = diff; + nearest = i%n; + } + olddist=dist; + } + + insertCoord(nearest, p); + + return nearest; + +} + +bool PolyArea::contains(const QPoint & p) const +{ + // A line can't contain a point + if (_coords->count() >2 ) { + QRegion r(*_coords); + return r.contains(p); + } + else + return false; +} + +void PolyArea::moveSelectionPoint(QRect* selectionPoint, const QPoint & p) +{ + selectionPoint->moveCenter(p); + + int i=0; + for (QRect *r=_selectionPoints->first();r!=0L;r=_selectionPoints->next()) { + if (r==selectionPoint) + break; + i++; + } + _coords->setPoint(i,p); + _rect=_coords->boundingRect(); +} + +void PolyArea::updateSelectionPoints() +{ + QRect *r; + r=_selectionPoints->first(); + + for (uint i=0;i<_coords->size();i++) + { + r->moveCenter(_coords->point(i)); + r=_selectionPoints->next(); + } + +} + +bool PolyArea::setCoords(const QString & s) +{ + _finished=true; + QStringList list=QStringList::split(",",s); + _coords=new QPointArray(); + _selectionPoints= new SelectionPointList(); + + for (QStringList::Iterator it = list.begin(); it !=list.end(); ++it) + { + bool ok=true; + int newXCoord=(*it).toInt(&ok,10); + if (!ok) return false; + it++; + if (it==list.end()) break; + int newYCoord=(*it).toInt(&ok,10); + if (!ok) return false; + insertCoord(_coords->size(), QPoint(newXCoord,newYCoord)); + } + + return true; + +} + +QString PolyArea::getHTMLCode() const { + QString retStr; + retStr+="<area "; + retStr+="shape=\"poly\" "; + + retStr+=getHTMLAttributes(); + + retStr+="coords=\""+coordsToString()+"\" "; + retStr+="/>"; + return retStr; + +} + +void PolyArea::setFinished(bool b) +{ + // The last Point is the same as the first + // so delete it + _coords->resize(_coords->size()-1); + _selectionPoints->removeLast(); + _finished=b; +} + +QRect PolyArea::selectionRect() const +{ + QRect r = _rect; + + r.moveBy(-10,-10); + r.setSize(r.size()+QSize(21,21)); + + return r; +} + + + +/******************************************************************** + * DEFAULT + *******************************************************************/ + + +DefaultArea::DefaultArea() + : Area() +{ + _type=Area::Default; +} + +DefaultArea::~DefaultArea() { +} + +Area* DefaultArea::clone() const +{ + Area* areaClone = new DefaultArea(); + areaClone->setArea( *this ); + return areaClone; +} + +void DefaultArea::draw(QPainter &) +{} + + +QString DefaultArea::getHTMLCode() const { + QString retStr; + retStr+="<area "; + retStr+="shape=\"default\" "; + + retStr+=getHTMLAttributes(); + + retStr+="/>"; + return retStr; + +} + + +/******************************************************************** + * AreaSelection + *******************************************************************/ + +AreaSelection::AreaSelection() + : Area() +{ + _areas = new AreaList(); + _name = "Selection"; + invalidate(); +} + +AreaSelection::~AreaSelection() { + delete _areas; +} + +Area* AreaSelection::clone() const +{ + AreaSelection* areaClone = new AreaSelection(); + + // we want a deep copy of the Areas + AreaListIterator it=getAreaListIterator(); + + for ( ; it.current() != 0L; ++it ) + { + areaClone->add( it.current()->clone() ); + } + +// areaClone->setArea( *this ); + + return areaClone; +} + + +void AreaSelection::add(Area *a) +{ + + // if a selection of areas was added get the areas of it + AreaSelection *selection=0L; + if ( (selection = dynamic_cast <AreaSelection*> ( a ) ) ) + { + AreaList list = selection->getAreaList(); + + for (Area* area = list.first(); area != 0L; area = list.next() ) + { + if ( _areas->find( area ) == -1 ) { + _areas->append( area ); // Must come before area->setSelected + area->setSelected( true ); + } + } + } + else + { + if ( _areas->find( a ) == -1 ) { + _areas->append( a ); // Must come before a->setSelected + a->setSelected( true ); + } + } + + invalidate(); +} + +void AreaSelection::remove(Area *a) +{ + if (_areas->find(a) == -1) + return; + + a->setSelected( false ); + _areas->remove( a ); + invalidate(); +} + +void AreaSelection::reset() +{ + AreaListIterator it=getAreaListIterator(); + + for ( ; it.current() != 0L; ++it ) + { + it.current()->setSelected( false ); + } + + _areas->clear(); + invalidate(); +} + +bool AreaSelection::contains(const QPoint & p) const +{ + bool b=false; + AreaListIterator it=getAreaListIterator(); + + for ( ; it.current() != 0L; ++it ) + { + if ( it.current()->contains( p ) ) + { + b=true; + break; + } + } + + return b; +} + +QRect* AreaSelection::onSelectionPoint(const QPoint & p, double zoom) const +{ + AreaListIterator it=getAreaListIterator(); + + if (it.count() != 1) + return 0L; + + QRect* retRect=0L; + + for ( ; it.current() != 0L; ++it ) + { + if ( (retRect = it.current()->onSelectionPoint( p , zoom) ) ) + { + break; + } + } + + return retRect; +} + +void AreaSelection::moveSelectionPoint(QRect* selectionPoint, const QPoint & p) +{ + // It's only possible to move a SelectionPoint if only one Area is selected + if (_areas->count() != 1) + return; + + _areas->getFirst()->moveSelectionPoint(selectionPoint,p); + + invalidate(); +} + + +void AreaSelection::moveBy(int dx, int dy) +{ + AreaListIterator it=getAreaListIterator(); + + for ( ; it.current() != 0L; ++it ) + it.current()->moveBy(dx,dy); + + Area::moveBy( dx, dy ); + + invalidate(); +} + +QString AreaSelection::typeString() const +{ + // if there is only one Area selected + // show the name of that Area + if ( _areas->count()==0 ) + return ""; + else if ( _areas->count()==1 ) + return _areas->getFirst()->typeString(); + else + return i18n("Number of Areas"); + +} + +Area::ShapeType AreaSelection::type() const +{ + // if there is only one Area selected + // take the type of that Area + if ( _areas->count()==0 ) + return Area::None; + else if ( _areas->count()==1 ) + return _areas->getFirst()->type(); + else + return Area::Selection; +} + +void AreaSelection::updateSelectionPoints() +{ + + AreaListIterator it=getAreaListIterator(); + + for ( ; it.current() != 0L; ++it ) + { + it.current()->updateSelectionPoints(); + } + + invalidate(); + +} + + + +QRect AreaSelection::selectionRect() const +{ + if (!_selectionCacheValid) + { + _selectionCacheValid=true; + QRect r; + AreaListIterator it=getAreaListIterator(); + + for ( ; it.current() != 0L; ++it ) + r = r | it.current()->selectionRect(); + + _cachedSelectionRect=r; + } + + return _cachedSelectionRect; +} + +uint AreaSelection::count() const { + return _areas->count(); +} + +bool AreaSelection::isEmpty() const +{ + return _areas->isEmpty(); +} + + +AreaList AreaSelection::getAreaList() const { + AreaList list(*_areas); + return list; +} + +AreaListIterator AreaSelection::getAreaListIterator() const { + AreaListIterator it(*_areas); + return it; +} + +void AreaSelection::setArea(const Area & copy) +{ + Area *area = copy.clone(); + AreaSelection *selection = dynamic_cast<AreaSelection*>(area); + if (selection) + setAreaSelection(*selection); + else { + Area::setArea(copy); + invalidate(); + } +} + +void AreaSelection::setAreaSelection(const AreaSelection & copy) +{ + AreaListIterator it=getAreaListIterator(); + AreaListIterator it2=copy.getAreaListIterator(); + + if (it.count() != it2.count()) + return; + + for ( ; it.current() != 0L; ++it, ++it2 ) + it.current()->setArea(*it2.current()); + + Area::setArea(copy); + invalidate(); +} + +void AreaSelection::setAreaList( const AreaList & areas ) +{ + delete _areas; + _areas = new AreaList(areas); + invalidate(); +} + +void AreaSelection::setRect(const QRect & r) +{ + if ( _areas->count()==1 ) + { + _areas->getFirst()->setRect(r); + } + + invalidate(); + _rect=rect(); + updateSelectionPoints(); +} + +QRect AreaSelection::rect() const +{ + if (!_rectCacheValid) + { + _rectCacheValid=true; + QRect r; + AreaListIterator it=getAreaListIterator(); + + for ( ; it.current() != 0L; ++it ) + r = r | it.current()->rect(); + + _cachedRect=r; + } + + return _cachedRect; +} + + +int AreaSelection::addCoord(const QPoint & p) +{ + if ( _areas->count()==1 ) + { + return _areas->getFirst()->addCoord(p); + invalidate(); + } + + return 0; +} + +void AreaSelection::insertCoord(int pos, const QPoint & p) +{ + if ( _areas->count()==1 ) + { + _areas->getFirst()->insertCoord(pos, p); + invalidate(); + } +} + +void AreaSelection::removeCoord(int pos) +{ + if ( _areas->count()==1 ) + { + _areas->getFirst()->removeCoord(pos); + invalidate(); + } +} + +bool AreaSelection::removeSelectionPoint(QRect * r) +{ + bool result=false; + + if ( _areas->count()==1 ) + { + result = _areas->getFirst()->removeSelectionPoint(r); + invalidate(); + } + + return result; +} + +SelectionPointList* AreaSelection::selectionPoints() const +{ + if ( _areas->count()==1 ) + { + return _areas->getFirst()->selectionPoints(); + } + + return _selectionPoints; +} + + +void AreaSelection::moveCoord(int pos,const QPoint & p) +{ + if ( _areas->count()==1 ) + { + _areas->getFirst()->moveCoord(pos,p); + invalidate(); + } +} + +void AreaSelection::highlightSelectionPoint(int i) +{ + if ( _areas->count()==1 ) + { + _areas->getFirst()->highlightSelectionPoint(i); + invalidate(); + } +} + + +QPointArray* AreaSelection::coords() const +{ + if ( _areas->count()==1 ) + { + return _areas->getFirst()->coords(); + } + + return Area::coords(); +} + +QString AreaSelection::attribute(const QString & name) const +{ + if ( _areas->count()==1 ) + { + return _areas->getFirst()->attribute(name); + } + + return Area::attribute(name); +} + +void AreaSelection::setAttribute(const QString & name, const QString & value) +{ + AreaListIterator it=getAreaListIterator(); + + for ( ; it.current() != 0L; ++it ) + it.current()->setAttribute(name,value); + + Area::setAttribute(name,value); +} + +AttributeIterator AreaSelection::firstAttribute() const +{ + if ( _areas->count()==1 ) + { + return _areas->getFirst()->firstAttribute(); + } + + return _attributes.begin(); +} + +AttributeIterator AreaSelection::lastAttribute() const +{ + if ( _areas->count()==1 ) + { + return _areas->getFirst()->lastAttribute(); + } + + return _attributes.end(); +} + +void AreaSelection::setMoving(bool b) +{ + AreaListIterator it=getAreaListIterator(); + + for ( ; it.current() != 0L; ++it ) + it.current()->setMoving(b); + + Area::setMoving(b); +} + +bool AreaSelection::isMoving() const +{ + if ( _areas->count()==1 ) + { + return _areas->getFirst()->isMoving(); + } + + return Area::isMoving(); +} + + +/** + * Checks if an area is outside the rectangle parameter + * returns false if an area has no pixel in common with the rectangle parameter + **/ +bool AreaSelection::allAreasWithin(const QRect & r) const +{ + if ( ! r.contains(rect()) ) + { + AreaListIterator it=getAreaListIterator(); + + for ( ; it.current() != 0L; ++it ) + if (!it.current()->rect().intersects(r)) + return false; + } + + return true; +} + + +void AreaSelection::draw(QPainter &) +{} + + diff --git a/kimagemapeditor/kimearea.h b/kimagemapeditor/kimearea.h new file mode 100644 index 00000000..581bba94 --- /dev/null +++ b/kimagemapeditor/kimearea.h @@ -0,0 +1,392 @@ +/*************************************************************************** + kimearea.h - description + ------------------- + begin : Thu Jun 14 2001 + copyright : (C) 2001 by Jan Sch�fer + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 KIMEAREA_H +#define KIMEAREA_H + +#include <qrect.h> +#include <qpoint.h> +#include <qptrlist.h> +#include <klocale.h> +#include <qmap.h> + +#include "kdeversion.h" + +class QPainter; +class QPointArray; +class QListViewItem; +class QBitmap; + +typedef QPtrList<QRect> SelectionPointList; + +typedef QMap<QString,QString> AttributeMap; +typedef QMapConstIterator<QString,QString> AttributeIterator; + + + +class Area +{ +public: + enum ShapeType { None, Rectangle, Circle, Polygon, Default, Selection }; + static bool highlightArea; + static bool showAlt; + +protected: + QRect _rect; + ShapeType _type; + QString _name; + QString _href; + QString _alt; + QString _target; + AttributeMap _attributes; + bool _isSelected; + bool _finished; + bool _isMoving; + int currentHighlighted; + QListViewItem* _listViewItem; + // Only used for Polygons + QPointArray *_coords; + SelectionPointList *_selectionPoints; + QPixmap *_highlightedPixmap; + + void drawHighlighting(QPainter & p); + void drawAlt(QPainter & p); + QString getHTMLAttributes() const; + +public: + Area(); + virtual ~Area(); + + virtual Area* clone() const; + // Default implementation; is specified by subclasses + virtual bool contains(const QPoint &) const; + // Default implementation; is specified by subclasses + virtual QString coordsToString() const; + virtual void draw(QPainter &); + + virtual QBitmap getMask() const; + virtual QString getHTMLCode() const; + + virtual void setHighlightedPixmap( QImage &, QBitmap &); + + virtual void moveBy(int, int); + virtual void moveTo(int, int); + virtual void moveSelectionPoint(QRect*, const QPoint &); + + virtual QRect* onSelectionPoint(const QPoint &,double zoom) const; + virtual bool removeSelectionPoint(QRect * r); + virtual SelectionPointList* selectionPoints() const { return _selectionPoints; } + + virtual QRect rect() const; + + virtual QRect selectionRect() const; + virtual void setArea(const Area &); + virtual bool setCoords(const QString &); + /** finished drawing only important for polygon */ + virtual void setFinished(bool b) { _finished=b; } + virtual void setRect(const QRect &); + virtual void setMoving(bool b); + virtual bool isMoving() const; + // Default implementation; is specified by subclasses + virtual QString typeString() const { return ""; } + virtual ShapeType type() const; + + virtual void updateSelectionPoints() {}; + + // Only interesting for Polygons + virtual void simplifyCoords() {}; + virtual int addCoord(const QPoint &); + virtual void insertCoord(int, const QPoint &); + virtual void removeCoord(int); + virtual void moveCoord(int,const QPoint &); + virtual QPointArray* coords() const; + virtual void highlightSelectionPoint(int); + + virtual QString attribute(const QString &) const; + virtual void setAttribute(const QString &, const QString &); + virtual AttributeIterator firstAttribute() const; + virtual AttributeIterator lastAttribute() const; + + QPixmap cutOut(const QImage &) ; + void setListViewItem(QListViewItem*); + void deleteListViewItem(); + QListViewItem* listViewItem() const; + void setName(const QString &); + QString name() const; + void setSelected(bool b); + bool isSelected() const; + bool finished() const; + uint countSelectionPoints() const; + +}; + + + +inline QListViewItem* Area::listViewItem() const { + return _listViewItem; +} + +inline void Area::setName(const QString & name) { + _name=name; +} + +inline QString Area::name() const { + return _name; +} + +inline bool Area::isMoving() const { + return _isMoving; +} + + +inline bool Area::isSelected() const { + return _isSelected; +} + + +inline bool Area::finished() const { + return _finished; +} + +/** + * Represents a Rectangle Area + **/ +class RectArea : public Area +{ + public: + RectArea(); + virtual ~RectArea(); + + virtual Area* clone() const; + virtual bool contains(const QPoint & p) const; + virtual QString coordsToString() const; + virtual void draw(QPainter & p); + virtual void moveSelectionPoint(QRect* selectionPoint, const QPoint & p); + virtual bool setCoords(const QString & s); + virtual QString typeString() const { return i18n("Rectangle"); } + virtual QBitmap getMask() const; + virtual QString getHTMLCode() const; + virtual void updateSelectionPoints(); +}; + + +/** + * Represents a Circle Area + **/ +class CircleArea : public Area +{ + public: + CircleArea(); + virtual ~CircleArea(); + + virtual Area* clone() const; + virtual bool contains(const QPoint & p) const; + virtual QString coordsToString() const; + virtual void draw(QPainter & p); + virtual void moveSelectionPoint(QRect* selectionPoint, const QPoint & p); + virtual bool setCoords(const QString & s); + virtual void setRect(const QRect & r); + virtual QString typeString() const { return i18n("Circle"); } + virtual QBitmap getMask() const; + virtual QString getHTMLCode() const; + virtual void updateSelectionPoints(); + +}; + +/** + * Represents a Rectangle Area + **/ +class PolyArea :public Area +{ + public: + PolyArea(); + virtual ~PolyArea(); + + virtual Area* clone() const; + virtual bool contains(const QPoint & p) const; + virtual QString coordsToString() const; + virtual void draw(QPainter & p); + virtual void moveSelectionPoint(QRect* selectionPoint, const QPoint & p); + virtual void simplifyCoords(); + virtual int addCoord(const QPoint & p); + virtual bool setCoords(const QString & s); + virtual QRect selectionRect() const; + virtual void setFinished(bool b); + virtual QString typeString() const { return i18n("Polygon"); } + virtual QBitmap getMask() const; + virtual QString getHTMLCode() const; + virtual void updateSelectionPoints(); + + private: + static int distance(const QPoint &p1, const QPoint &p2); + static bool isBetween(const QPoint &p, const QPoint &p1, const QPoint &p2); + +}; + +/** + * Represents the default Area + **/ +class DefaultArea :public Area +{ + public: + DefaultArea(); + virtual ~DefaultArea(); + + virtual Area* clone() const; + // the default area isn't drawn + virtual void draw(QPainter & p); + virtual QString typeString() const { return i18n("Default"); } + virtual QString getHTMLCode() const; + +}; + + +typedef QPtrList<Area> AreaList; +typedef QPtrListIterator<Area> AreaListIterator; + +/** + * This class represents a selection of areas + * all operations performed on this class + * will be performed on the selected Areas + * the only actions that can be used is the + * move action + **/ +class AreaSelection : public Area { + public : + AreaSelection(); + virtual ~AreaSelection(); + + /** + * New Methods + */ + + // Adding automatically selects the area + void add(Area *a); + + // Removing automatically deselects the area + void remove(Area *a); + + // Removes all areas from the list and deselects them + void reset(); + + uint count() const; + + AreaList getAreaList() const; + AreaListIterator getAreaListIterator() const; + void setAreaList( const AreaList & areas ); + + bool isEmpty() const; + + /** + * Overiden Methods of the Area class + */ + virtual bool contains(const QPoint & p) const; + + /** + * + **/ + virtual QRect* onSelectionPoint(const QPoint & p, double zoom) const; + + /** + * Only if one Area is selected the moveSelectionPoint method + * of that Area will be called + **/ + virtual void moveSelectionPoint(QRect* selectionPoint, const QPoint & p); + + virtual SelectionPointList* selectionPoints() const; + + /** + * All Areas will be moved by dx and dy + **/ + virtual void moveBy(int dx, int dy); + + /** + * Calls for every selected Area the setArea with the + * corresponding Area in the copy Selection. + * IMPORTANT : works only if the copy Area is an AreaSelection + * and have the same number of Areas + **/ + virtual void setArea(const Area & copy); + virtual void setAreaSelection(const AreaSelection & copy); + + /** + * If only one Area is selected the setRect method of that Area + * will be called + **/ + virtual void setRect(const QRect & r); + virtual QRect rect() const; + + + virtual QString typeString() const; + virtual ShapeType type() const; + + // The selection is only a container + // so it is never drawn + virtual void draw(QPainter & p); + + + /** + * A deep copy of the Areas + **/ + virtual Area* clone() const; + + virtual void updateSelectionPoints(); + virtual int addCoord(const QPoint & p); + virtual void insertCoord(int pos, const QPoint & p); + virtual void removeCoord(int pos); + virtual bool removeSelectionPoint(QRect * r); + virtual void moveCoord(int pos,const QPoint & p); + virtual QPointArray* coords() const; + virtual void highlightSelectionPoint(int); + + virtual QRect selectionRect() const; + + virtual QString attribute(const QString & name) const; + virtual void setAttribute(const QString & name, const QString & value); + virtual AttributeIterator firstAttribute() const; + virtual AttributeIterator lastAttribute() const; + + virtual void setMoving(bool b); + virtual bool isMoving() const; + + + bool allAreasWithin(const QRect & r) const; + + // makes the cache invalid + void invalidate(); + private : + + AreaList *_areas; + + // The selectionRect and the rect are cached + // so even in const functions they must be changeable + mutable QRect _cachedSelectionRect; + mutable QRect _cachedRect; + mutable bool _selectionCacheValid; + mutable bool _rectCacheValid; + +}; + + +inline void AreaSelection::invalidate() { + _selectionCacheValid=false; + _rectCacheValid=false; +} + +#endif + + diff --git a/kimagemapeditor/kimecommands.cpp b/kimagemapeditor/kimecommands.cpp new file mode 100644 index 00000000..e061a463 --- /dev/null +++ b/kimagemapeditor/kimecommands.cpp @@ -0,0 +1,384 @@ +/*************************************************************************** + kimecommands.cpp - description + ------------------- + begin : Fri May 25 2001 + copyright : (C) 2001 by Jan Sch�fer + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 <qstring.h> +#include <kdebug.h> +#include <klocale.h> + +#include "kimagemapeditor.h" +#include "kimecommands.h" +#include "drawzone.h" + +CutCommand::CutCommand(KImageMapEditor * document, const AreaSelection & a) + : + +#if KDE_VERSION < 300 +KCommand +#else +KNamedCommand +#endif + (i18n( "Cut %1" ).arg( a.typeString() )) +{ + _document=document; + _cutAreaSelection=new AreaSelection(); + _cutAreaSelection->setAreaList( a.getAreaList() ); + _cutted=true; +} + + +CutCommand::~CutCommand() +{ + if (_cutted) + { + AreaList list = _cutAreaSelection->getAreaList(); + for ( Area *a=list.first(); a != 0; a=list.next() ) { + delete a; + } + } + + delete _cutAreaSelection; +} + +void CutCommand::execute() +{ + // The Area won't be really delete + // it only gets removed from the AreaList + _document->deleteArea(_cutAreaSelection ); + _document->updateActionAccess(); + _cutted=true; +} + +void CutCommand::unexecute() +{ + if (_document) { + _document->addArea( _cutAreaSelection ); + _document->select( _cutAreaSelection ); + _document->slotAreaChanged( _cutAreaSelection ); + _cutted=false; + } +} + +DeleteCommand::DeleteCommand(KImageMapEditor * document, const AreaSelection & a) + : CutCommand(document,a) +{ + setName(i18n( "Delete %1" ).arg( a.typeString() )); +} + +PasteCommand::PasteCommand(KImageMapEditor *document, const AreaSelection & a) + : +#if KDE_VERSION < 300 +KCommand +#else +KNamedCommand +#endif + (i18n( "Paste %1" ).arg( a.typeString() )) +{ + _document=document; + _pasteAreaSelection=new AreaSelection(); + _pasteAreaSelection->setAreaList( a.getAreaList() ); + _pasted=true; + _wasUndoed=false; +} + +PasteCommand::~PasteCommand () +{ + if ( ! _pasted ) { + AreaList list=_pasteAreaSelection->getAreaList(); + for (Area* a=list.first(); a != 0; a=list.next() ) { + delete a; + } + } + + delete _pasteAreaSelection; +} + +void PasteCommand::execute() +{ + _document->deselectAll(); + _document->addArea( _pasteAreaSelection ); + _document->select( _pasteAreaSelection ); + _document->slotAreaChanged( _pasteAreaSelection ); + _pasted=true; +} + +void PasteCommand::unexecute() +{ + _document->deleteArea(_pasteAreaSelection ); + _pasted=false; + _wasUndoed=true; +} + + +MoveCommand::MoveCommand (KImageMapEditor *document, AreaSelection * a, const QPoint & oldPoint) + : +#if KDE_VERSION < 300 +KCommand +#else +KNamedCommand +#endif +(i18n( "Move %1" ).arg( a->typeString() )) +{ + _document=document; + _areaSelection=new AreaSelection(); + _areaSelection->setAreaList( a->getAreaList() ); + _oldPoint.setX(oldPoint.x()); + _oldPoint.setY(oldPoint.y()); + + _newPoint.setX(a->rect().left()); + _newPoint.setY(a->rect().top()); +} + +MoveCommand::~MoveCommand () { + delete _areaSelection; +} + +void MoveCommand::execute() +{ + // only for repainting reasons + Area* tempArea = _areaSelection->clone(); + + _areaSelection->moveTo( _newPoint.x(), _newPoint.y() ); + + if (!_areaSelection->allAreasWithin(_document->getDrawZone()->getImageRect())) + _areaSelection->moveTo( _oldPoint.x(), _oldPoint.y() ); + + _document->selected()->invalidate(); + + + _document->slotAreaChanged( tempArea ); + _document->slotAreaChanged( _areaSelection ); + + delete tempArea; + +} + +void MoveCommand::unexecute() +{ + // only to erase the old Area + Area* tempArea = _areaSelection->clone(); + + _areaSelection->setMoving(true); + _areaSelection->moveTo( _oldPoint.x(), _oldPoint.y() ); + _areaSelection->setMoving(false); + + _document->selected()->invalidate(); + + _document->slotAreaChanged( tempArea ); + _document->slotAreaChanged( _areaSelection ); + + delete tempArea; + +} + + +ResizeCommand::ResizeCommand (KImageMapEditor *document, AreaSelection *a, Area *oldArea) + : +#if KDE_VERSION < 300 +KCommand +#else +KNamedCommand +#endif +(i18n( "Resize %1" ).arg( a->typeString() )) +{ + _areaSelection=new AreaSelection(); + _areaSelection->setAreaList( a->getAreaList() ); + + _newArea = a->clone(); + _oldArea = oldArea->clone(); + _document=document; +} + +ResizeCommand::~ResizeCommand () +{ + delete _newArea; + delete _oldArea; + delete _areaSelection; +} + +void ResizeCommand::execute() +{ + _areaSelection->setArea ( *_newArea); + _areaSelection->setMoving(false); + + _document->slotAreaChanged( _areaSelection ); + _document->slotAreaChanged( _oldArea ); + + +} + +void ResizeCommand::unexecute() +{ + _areaSelection->setArea ( *_oldArea); + _areaSelection->setMoving(false); + + _document->slotAreaChanged( _areaSelection ); + _document->slotAreaChanged( _newArea ); + +} + + + +AddPointCommand::AddPointCommand (KImageMapEditor *document, AreaSelection *a, const QPoint & p) + : +#if KDE_VERSION < 300 +KCommand +#else +KNamedCommand +#endif +(i18n( "Add point to %1" ).arg( a->typeString() )) +{ + if (a->type()!=Area::Polygon) + { + kdDebug() << "trying to add a point to a " << a->typeString() << endl; + return; + } + + _areaSelection=new AreaSelection(); + _areaSelection->setAreaList( a->getAreaList() ); + + _point = p; + _document=document; +} + +AddPointCommand::~AddPointCommand () +{ + delete _areaSelection; +} + +void AddPointCommand::execute() +{ + _coordpos = _areaSelection->addCoord(_point); + _areaSelection->setMoving(false); + + _document->slotAreaChanged( _areaSelection ); +} + +void AddPointCommand::unexecute() +{ +// QRect *selectionPoint = _areaSelection->onSelectionPoint(_point); + Area* repaintArea = _areaSelection->clone(); + + _areaSelection->removeCoord(_coordpos); + _areaSelection->setMoving(false); + + _document->slotAreaChanged( _areaSelection ); + _document->slotAreaChanged( repaintArea ); + + delete repaintArea; +} + +RemovePointCommand::RemovePointCommand (KImageMapEditor *document, AreaSelection *a, Area *oldArea) + : +#if KDE_VERSION < 300 +KCommand +#else +KNamedCommand +#endif +(i18n( "Remove point from %1" ).arg( a->typeString() )) +{ + if (a->type()!=Area::Polygon) + { + kdDebug() << "trying to remove a point to a " << a->typeString() << endl; + return; + } + + _areaSelection=new AreaSelection(); + _areaSelection->setAreaList( a->getAreaList() ); + + _newArea = a->clone(); + _oldArea = oldArea->clone(); + _document=document; +} + +RemovePointCommand::~RemovePointCommand () +{ + delete _newArea; + delete _oldArea; + delete _areaSelection; +} + +void RemovePointCommand::execute() +{ + _areaSelection->setArea ( *_newArea); + _areaSelection->setMoving(false); + + _document->slotAreaChanged( _areaSelection ); + _document->slotAreaChanged( _oldArea ); + + +} + +void RemovePointCommand::unexecute() +{ + _areaSelection->setArea ( *_oldArea); + _areaSelection->setMoving(false); + + _document->slotAreaChanged( _areaSelection ); + _document->slotAreaChanged( _newArea ); + +} + + + +CreateCommand::CreateCommand (KImageMapEditor *document, Area *area) + : +#if KDE_VERSION < 300 +KCommand +#else +KNamedCommand +#endif +(i18n( "Create %1" ).arg( area->typeString() )) +{ + _document=document; + _area=area; + _created=true; + _wasUndoed=false; + +} + +CreateCommand::~CreateCommand () +{ + if ( ! _created) + delete _area; +} + +void CreateCommand::execute() +{ + if (_document) { + + if ( _wasUndoed ) { + _document->addArea( _area ); + _document->deselectAll(); + _document->select( _area ); + _document->slotAreaChanged( _area ); + } + else + _document->addAreaAndEdit( _area ); + + _created=true; + } + +} + +void CreateCommand::unexecute() +{ + if (_document) { + _document->deleteArea( _area ); + _created=false; + _wasUndoed=true; + } + +} diff --git a/kimagemapeditor/kimecommands.h b/kimagemapeditor/kimecommands.h new file mode 100644 index 00000000..946c09b4 --- /dev/null +++ b/kimagemapeditor/kimecommands.h @@ -0,0 +1,198 @@ +/*************************************************************************** + kimecommands.h - description + ------------------- + begin : Fri May 25 2001 + copyright : (C) 2001 by Jan Sch�fer + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 KIMECOMMANDS_H +#define KIMECOMMANDS_H + + +#include <kcommand.h> + +#include <kdeversion.h> + +class KImageMapEditor; +class AreaSelection; + + + +class CutCommand : public + +#if KDE_VERSION < 300 +KCommand +#else +KNamedCommand +#endif + +{ + public: + CutCommand (KImageMapEditor * document, const AreaSelection & selection); + virtual ~CutCommand(); + + virtual void execute(); + virtual void unexecute(); + + protected: + AreaSelection *_cutAreaSelection; + KImageMapEditor* _document; + bool _cutted; +}; + +/** + * Does the same like the cut command + * only have a different name in the Undo-History + **/ +class DeleteCommand : public CutCommand +{ + public : + DeleteCommand (KImageMapEditor * document, const AreaSelection & selection); +}; + +class PasteCommand : public +#if KDE_VERSION < 300 +KCommand +#else +KNamedCommand +#endif +{ + public: + PasteCommand (KImageMapEditor * document, const AreaSelection & selection); + ~PasteCommand (); + + virtual void execute(); + virtual void unexecute(); + + protected: + AreaSelection *_pasteAreaSelection; + KImageMapEditor* _document; + bool _pasted; + bool _wasUndoed; + +}; + +class MoveCommand : public +#if KDE_VERSION < 300 +KCommand +#else +KNamedCommand +#endif +{ + public: + MoveCommand (KImageMapEditor *document, AreaSelection *a,const QPoint & oldPoint); + ~MoveCommand (); + + virtual void execute(); + virtual void unexecute(); + + protected: + QPoint _newPoint; + QPoint _oldPoint; + + KImageMapEditor* _document; + AreaSelection *_areaSelection; +//- Area *_oldArea; +}; + +class ResizeCommand : public +#if KDE_VERSION < 300 +KCommand +#else +KNamedCommand +#endif +{ + public: + ResizeCommand (KImageMapEditor *document, AreaSelection *a, Area *oldArea); + ~ResizeCommand (); + + virtual void execute(); + virtual void unexecute(); + + protected: + + KImageMapEditor* _document; + AreaSelection *_areaSelection; + Area *_oldArea; + Area *_newArea; +}; + +class AddPointCommand : public +#if KDE_VERSION < 300 +KCommand +#else +KNamedCommand +#endif +{ + public: + AddPointCommand (KImageMapEditor *document, AreaSelection *a, const QPoint & p); + ~AddPointCommand (); + + virtual void execute(); + virtual void unexecute(); + + protected: + + KImageMapEditor* _document; + AreaSelection *_areaSelection; + QPoint _point; + int _coordpos; +}; + +class RemovePointCommand : public +#if KDE_VERSION < 300 +KCommand +#else +KNamedCommand +#endif +{ + public: + RemovePointCommand (KImageMapEditor *document, AreaSelection *a, Area *oldArea); + ~RemovePointCommand (); + + virtual void execute(); + virtual void unexecute(); + + protected: + + KImageMapEditor* _document; + AreaSelection *_areaSelection; + Area *_oldArea; + Area *_newArea; +}; + + +class CreateCommand : public +#if KDE_VERSION < 300 +KCommand +#else +KNamedCommand +#endif +{ + public: + CreateCommand (KImageMapEditor *document, Area *area); + ~CreateCommand (); + + virtual void execute(); + virtual void unexecute(); + + protected: + + KImageMapEditor* _document; + Area *_area; + bool _created; + bool _wasUndoed; +}; + + +#endif diff --git a/kimagemapeditor/kimecommon.h b/kimagemapeditor/kimecommon.h new file mode 100644 index 00000000..4cc2d59f --- /dev/null +++ b/kimagemapeditor/kimecommon.h @@ -0,0 +1,52 @@ +/*************************************************************************** + kimecommon.h - description + ------------------- + begin : Thu Apr 23 2002 + copyright : (C) 2002 by Jan Sch�fer + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 __KIMECOMMON_H__ +#define __KIMECOMMON_H__ + +inline int myabs(int i) { + if (i < 0) + return -i; + else + return i; +} + +inline double myabs(double i) { + if (i < 0) + return -i; + else + return i; +} + +inline int myround(double d) { + if ( (d-((int) d)) < 0.5 ) + return (int) d; + else + return ((int) d)+1; +} + +inline int roundUp(double d) +{ + if ( (d-((int) d)) == 0) + return (int) d; + else + return ((int) d)+1; +} + + +#endif diff --git a/kimagemapeditor/kimedialogs.cpp b/kimagemapeditor/kimedialogs.cpp new file mode 100644 index 00000000..27f104cb --- /dev/null +++ b/kimagemapeditor/kimedialogs.cpp @@ -0,0 +1,874 @@ +/*************************************************************************** + kimedialogs.cpp - description + ------------------- + begin : Tue Apr 17 2001 + copyright : (C) 2001 by Jan Sch�er + email : [email protected] +***************************************************************************/ + +/*************************************************************************** +* * +* 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. * +* * +***************************************************************************/ + +// QT +//#include <qstring.h> +#include <qcheckbox.h> +#include <qmultilineedit.h> +#include <qlayout.h> +#include <qlabel.h> +#include <qhbox.h> +#include <qvbox.h> +#include <qlineedit.h> +#include <qlistbox.h> +#include <qtable.h> +#include <qgroupbox.h> +#include <qspinbox.h> +#include <qtabwidget.h> +#include <qpointarray.h> +#include <qimage.h> +//#include <qwidget.h> +// KDE +#include <kiconloader.h> +#include <kfiledialog.h> +#include <klocale.h> +#include <kdebug.h> +#include <kapplication.h> +#include <khtmlview.h> +#include <khtml_part.h> +#include <ktempfile.h> +#include <kpushbutton.h> +#include <kstdguiitem.h> + +// LOCAL +#include "kimedialogs.h" + +CoordsEdit::CoordsEdit(QWidget *parent, Area* a) + : QWidget(parent) +{ + area=a; +} + +void CoordsEdit::applyChanges() { + return; +} + +void CoordsEdit::slotTriggerUpdate() { + applyChanges(); + emit update(); +} + +CoordsEdit::~CoordsEdit() +{ +} + +RectCoordsEdit::RectCoordsEdit(QWidget *parent, Area* a) + : CoordsEdit(parent,a) +{ + QGridLayout *layout= new QGridLayout(this,5,2,5,5); + + topXSpin = new QSpinBox(this); + topXSpin->setMaxValue(INT_MAX); + topXSpin->setMinValue(0); + topXSpin->setValue(a->rect().left()); + layout->addWidget(topXSpin,0,1); + connect( topXSpin, SIGNAL(valueChanged(const QString &)), this, SLOT(slotTriggerUpdate())); + + QLabel *lbl= new QLabel(i18n("Top &X:"),this); + lbl->setBuddy(topXSpin); + layout->addWidget(lbl,0,0); + + topYSpin = new QSpinBox(this); + topYSpin->setMaxValue(INT_MAX); + topYSpin->setMinValue(0); + topYSpin->setValue(a->rect().top()); + layout->addWidget(topYSpin,1,1); + connect( topYSpin, SIGNAL(valueChanged(const QString &)), this, SLOT(slotTriggerUpdate())); + + lbl= new QLabel(i18n("Top &Y:"),this); + lbl->setBuddy(topYSpin); + layout->addWidget(lbl,1,0); + + widthSpin = new QSpinBox(this); + widthSpin->setMaxValue(INT_MAX); + widthSpin->setMinValue(0); + widthSpin->setValue(a->rect().width()); + layout->addWidget(widthSpin,2,1); + connect( widthSpin, SIGNAL(valueChanged(const QString &)), this, SLOT(slotTriggerUpdate())); + + lbl= new QLabel(i18n("&Width:"),this); + lbl->setBuddy(widthSpin); + layout->addWidget(lbl,2,0); + + heightSpin = new QSpinBox(this); + heightSpin->setMaxValue(INT_MAX); + heightSpin->setMinValue(0); + heightSpin->setValue(a->rect().height()); + layout->addWidget(heightSpin,3,1); + connect( heightSpin, SIGNAL(valueChanged(const QString &)), this, SLOT(slotTriggerUpdate())); + + lbl= new QLabel(i18n("Hei&ght:"),this); + lbl->setBuddy(heightSpin); + layout->addWidget(lbl,3,0); + + layout->setRowStretch(4,10); +} + +void RectCoordsEdit::applyChanges() { + QRect r; + r.setLeft(topXSpin->text().toInt()); + r.setTop(topYSpin->text().toInt()); + r.setWidth(widthSpin->text().toInt()); + r.setHeight(heightSpin->text().toInt()); + area->setRect(r); +} + +CircleCoordsEdit::CircleCoordsEdit(QWidget *parent, Area* a) + : CoordsEdit(parent,a) +{ + QGridLayout *layout= new QGridLayout(this,4,2,5,5); + + centerXSpin = new QSpinBox(this); + centerXSpin->setMaxValue(INT_MAX); + centerXSpin->setMinValue(0); + centerXSpin->setValue(a->rect().center().x()); + layout->addWidget(centerXSpin,0,1); + connect( centerXSpin, SIGNAL(valueChanged(const QString &)), this, SLOT(slotTriggerUpdate())); + + QLabel *lbl= new QLabel(i18n("Center &X:"),this); + lbl->setBuddy(centerXSpin); + layout->addWidget(lbl,0,0); + + centerYSpin = new QSpinBox(this); + centerYSpin->setMaxValue(INT_MAX); + centerYSpin->setMinValue(0); + centerYSpin->setValue(a->rect().center().y()); + layout->addWidget(centerYSpin,1,1); + connect( centerYSpin, SIGNAL(valueChanged(const QString &)), this, SLOT(slotTriggerUpdate())); + + + lbl= new QLabel(i18n("Center &Y:"),this); + lbl->setBuddy(centerYSpin); + layout->addWidget(lbl,1,0); + + radiusSpin = new QSpinBox(this); + radiusSpin->setMaxValue(INT_MAX); + radiusSpin->setMinValue(0); + radiusSpin->setValue(a->rect().width()/2); + layout->addWidget(radiusSpin,2,1); + connect( radiusSpin, SIGNAL(valueChanged(const QString &)), this, SLOT(slotTriggerUpdate())); + + + lbl= new QLabel(i18n("&Radius:"),this); + lbl->setBuddy(radiusSpin); + layout->addWidget(lbl,2,0); + + layout->setRowStretch(3,10); + +} + +void CircleCoordsEdit::applyChanges() { + QRect r; + r.setWidth(radiusSpin->text().toInt()*2); + r.setHeight(radiusSpin->text().toInt()*2); + r.moveCenter(QPoint(centerXSpin->text().toInt(), + centerYSpin->text().toInt())); + area->setRect(r); +} + +PolyCoordsEdit::PolyCoordsEdit(QWidget *parent, Area* a) + : CoordsEdit(parent,a) +{ + if (!a) return; + QVBoxLayout *layout= new QVBoxLayout(this); + int numPoints=a->coords()->count(); + coordsTable= new QTable(numPoints,2,this); + coordsTable->horizontalHeader()->setLabel(0,"X"); + coordsTable->horizontalHeader()->setLabel(1,"Y"); + coordsTable->verticalHeader()->hide(); + coordsTable->setLeftMargin(0); + coordsTable->setSelectionMode( QTable::Single ); + + + for (int i=0;i<numPoints;i++) { + coordsTable->setText(i,0, QString::number(area->coords()->point(i).x()) ); + coordsTable->setText(i,1, QString::number(area->coords()->point(i).y()) ); + } + + connect( coordsTable, SIGNAL(currentChanged(int,int)), this, SLOT(slotHighlightPoint(int))); + +// coordsTable->setMinimumHeight(50); +// coordsTable->setMaximumHeight(400); +// coordsTable->resizeContents(100,100); + coordsTable->resize(coordsTable->width(),100); + layout->addWidget(coordsTable); + layout->setStretchFactor(coordsTable,-1); + QHBox *hbox= new QHBox(this); + QPushButton *addBtn=new QPushButton(i18n("Add"),hbox); + connect( addBtn, SIGNAL(pressed()), this, SLOT(slotAddPoint())); + QPushButton *removeBtn=new QPushButton(i18n("Remove"),hbox); + connect( removeBtn, SIGNAL(pressed()), this, SLOT(slotRemovePoint())); + + layout->addWidget(hbox); + slotHighlightPoint(1); +} + +PolyCoordsEdit::~PolyCoordsEdit() { + if (area) + area->highlightSelectionPoint(-1); +} + +void PolyCoordsEdit::slotHighlightPoint(int row) { + if (!area) return; + area->highlightSelectionPoint(row); + emit update(); +} + + +void PolyCoordsEdit::slotAddPoint() { + int newPos= coordsTable->currentRow(); + QPoint currentPoint=area->coords()->point(newPos); + area->insertCoord(newPos,currentPoint); + + int count=area->coords()->size(); + + coordsTable->setNumRows(count); + + for (int i=0;i<count;i++) { + coordsTable->setText(i,0, QString::number(area->coords()->point(i).x()) ); + coordsTable->setText(i,1, QString::number(area->coords()->point(i).y()) ); + } + + emit update(); +} + +void PolyCoordsEdit::slotRemovePoint() { + int currentPos= coordsTable->currentRow(); + + area->removeCoord(currentPos); + + int count=area->coords()->size(); + + coordsTable->setNumRows(count); + + for (int i=0;i<count;i++) { + coordsTable->setText(i,0, QString::number(area->coords()->point(i).x()) ); + coordsTable->setText(i,1, QString::number(area->coords()->point(i).y()) ); + } + + emit update(); +} + +void PolyCoordsEdit::applyChanges() { + int count=coordsTable->numRows(); + + for (int i=0;i<count;i++) { + QPoint newPoint( coordsTable->text(i,0).toInt(), + coordsTable->text(i,1).toInt()); + + area->moveCoord(i,newPoint); + } +} + +SelectionCoordsEdit::SelectionCoordsEdit(QWidget *parent, Area* a) + : CoordsEdit(parent,a) +{ + QGridLayout *layout= new QGridLayout(this,2,2); + + topXSpin = new QSpinBox(this); + topXSpin->setMaxValue(INT_MAX); + topXSpin->setMinValue(0); + topXSpin->setValue(a->rect().left()); + layout->addWidget(topXSpin,0,1); + connect( topXSpin, SIGNAL(valueChanged(const QString &)), this, SLOT(slotTriggerUpdate())); + + QLabel *lbl= new QLabel(i18n("Top &X"),this); + lbl->setBuddy(topXSpin); + layout->addWidget(lbl,0,0); + + topYSpin = new QSpinBox(this); + topYSpin->setMaxValue(INT_MAX); + topYSpin->setMinValue(0); + topYSpin->setValue(a->rect().top()); + layout->addWidget(topYSpin,1,1); + connect( topYSpin, SIGNAL(valueChanged(const QString &)), this, SLOT(slotTriggerUpdate())); + + lbl= new QLabel(i18n("Top &Y"),this); + lbl->setBuddy(topYSpin); + layout->addWidget(lbl,1,0); +} + +void SelectionCoordsEdit::applyChanges() { + area->moveTo(topXSpin->text().toInt(), topYSpin->text().toInt()); +} + + + +QLineEdit* AreaDialog::createLineEdit(QWidget* parent, QGridLayout *layout, int y, const QString & value, const QString & name) +{ + QLineEdit* edit=new QLineEdit(value,parent); + layout->addWidget(edit,y,2); + QLabel* lbl=new QLabel(name,parent); + lbl->setBuddy(edit); + layout->addWidget(lbl,y,1); + + return edit; +} + +QWidget* AreaDialog::createGeneralPage() +{ + QFrame* page = new QFrame(this); + QGridLayout* layout = new QGridLayout(page,5,2,5,5); + + + QHBox *hbox= new QHBox(page); + hrefEdit = new QLineEdit(area->attribute("href"),hbox); + QPushButton *btn = new QPushButton("",hbox); + btn->setPixmap(SmallIcon("fileopen")); + connect( btn, SIGNAL(pressed()), this, SLOT(slotChooseHref())); + hbox->setMinimumHeight(hbox->height()); + + layout->addWidget(hbox,0,2); + QLabel *lbl=new QLabel(i18n( "&HREF:" ),page); + lbl->setBuddy(hrefEdit); + layout->addWidget(lbl,0,1); + + altEdit = createLineEdit(page,layout,1,area->attribute("alt"),i18n("Alt. &Text:")); + targetEdit = createLineEdit(page,layout,2,area->attribute("target"),i18n("Tar&get:")); + titleEdit = createLineEdit(page,layout,3,area->attribute("title"),i18n("Tit&le:")); + + if (area->type()==Area::Default) + { + defaultAreaChk = new QCheckBox(i18n("Enable default map"),page); + if (area->finished()) + defaultAreaChk->setChecked(true); + layout->addWidget(defaultAreaChk,3,2); + } + + + layout->setRowStretch(4,10); + + return page; +} + +QWidget* AreaDialog::createCoordsPage() +{ + QFrame* page = new QFrame(this); + QVBoxLayout *layout = new QVBoxLayout(page); + layout->setMargin(5); + + coordsEdit = createCoordsEdit(page,area); + layout->addWidget(coordsEdit); + connect( coordsEdit, SIGNAL(update()), this, SLOT(slotUpdateArea())); + + return page; +} + +QWidget* AreaDialog::createJavascriptPage() +{ + QFrame* page = new QFrame(this); + QGridLayout* layout = new QGridLayout(page,8,2,5,5); + + onClickEdit = createLineEdit(page,layout,0,area->attribute("onClick"),i18n("OnClick:")); + onDblClickEdit = createLineEdit(page,layout,1,area->attribute("onDblClick"),i18n("OnDblClick:")); + onMouseDownEdit = createLineEdit(page,layout,2,area->attribute("onMouseDown"),i18n("OnMouseDown:")); + onMouseUpEdit = createLineEdit(page,layout,3,area->attribute("onMouseUp"),i18n("OnMouseUp:")); + onMouseOverEdit = createLineEdit(page,layout,4,area->attribute("onMouseOver"),i18n("OnMouseOver:")); + onMouseMoveEdit = createLineEdit(page,layout,5,area->attribute("onMouseMove"),i18n("OnMouseMove:")); + onMouseOutEdit = createLineEdit(page,layout,6,area->attribute("onMouseOut"),i18n("OnMouseOut:")); + + layout->setRowStretch(7,10); + + + return page; +} + +QWidget* AreaDialog::createButtonBar() +{ + QHBox *box = new QHBox(this); + QWidget *spacer = new QWidget(box); + QPushButton *okBtn = new KPushButton(KStdGuiItem::ok(),box); + QPushButton *applyBtn = new KPushButton(KStdGuiItem::apply(),box); + QPushButton *cancelBtn = new KPushButton(KStdGuiItem::cancel(),box); + + connect(okBtn, SIGNAL(clicked()), this, SLOT(slotOk())); + connect(applyBtn, SIGNAL(clicked()), this, SLOT(slotApply())); + connect(cancelBtn, SIGNAL(clicked()), this, SLOT(slotCancel())); + + box->setSpacing(5); + box->setStretchFactor(spacer,10); + + okBtn->setDefault(true); + + return box; + +} + +AreaDialog::AreaDialog(KImageMapEditor* parent,Area * a) + : KDialog(parent->widget(),"",true) +// : KDialogBase(Tabbed,i18n("Area Tag Editor"),Ok|Apply|Cancel,Ok,parent,"") +// : KDialogBase(parent,"",true,"Area Tag Editor",Ok|Apply|Cancel,Ok,true) +{ + if (!a) { + slotCancel(); + return; + } + + _document=parent; + + setCaption(i18n("Area Tag Editor")); + + area=a; + QString shape="Default"; + areaCopy= a->clone(); + oldArea= new Area(); + oldArea->setRect( a->rect() ); + + switch (a->type()) { + case Area::Rectangle : shape=i18n("Rectangle");break; + case Area::Circle : shape=i18n("Circle");break; + case Area::Polygon : shape=i18n("Polygon");break; + case Area::Selection : shape=i18n("Selection");break; + default : break; + } + + + // To get a margin around everything + + QVBoxLayout *layout = new QVBoxLayout(this); + + layout->setMargin(5); + + QLabel *lbl = new QLabel("<b>"+shape+"</b>",this); + lbl->setTextFormat(Qt::RichText); + layout->addWidget(lbl); + + QFrame *line = new QFrame(this); + line->setFrameStyle(QFrame::HLine | QFrame::Sunken); + line->setFixedHeight(10); + layout->addWidget(line); + + QTabWidget *tab = new QTabWidget(this); + + layout->addWidget(tab); + + tab->addTab(createGeneralPage(),i18n("&General")); + + if (a->type()==Area::Default) + { + shape=i18n("Default"); + } + else + tab->addTab(createCoordsPage(),i18n("Coor&dinates")); + + tab->addTab(createJavascriptPage(),i18n("&JavaScript")); + + line = new QFrame(this); + line->setFrameStyle(QFrame::HLine | QFrame::Sunken); + line->setFixedHeight(10); + layout->addWidget(line); + + layout->addWidget(createButtonBar()); + + setMinimumHeight(360); + setMinimumWidth(327); + + resize(327,360); +} + +AreaDialog::~AreaDialog() { + delete areaCopy; + delete oldArea; +} + +CoordsEdit* AreaDialog::createCoordsEdit(QWidget *parent, Area *a) { + if (!a) return 0; + switch (a->type()) { + case Area::Rectangle : + return new RectCoordsEdit(parent,a); + break; + case Area::Circle : + return new CircleCoordsEdit(parent,a); + break; + case Area::Polygon : + return new PolyCoordsEdit(parent,a); + break; + case Area::Selection : + return new SelectionCoordsEdit(parent,a); + break; + case Area::Default : return new CoordsEdit(parent,a); break; + default : return new CoordsEdit(parent,a);break; + } +} + +void AreaDialog::slotChooseHref() { + KURL url=KFileDialog::getOpenURL(QString::null, "*|" + i18n( "All Files" ), this, i18n("Choose File")); + if (!url.isEmpty()) { + hrefEdit->setText(url.url()); + } +} + +void AreaDialog::slotOk() { + if (area) + { + area->highlightSelectionPoint(-1); + if (area->type()==Area::Default) + area->setFinished(defaultAreaChk->isChecked()); + } + slotApply(); + accept(); + +} + +void AreaDialog::slotApply() { + if (area) { + if (area->type()!=Area::Default) + coordsEdit->applyChanges(); + + area->setAttribute("href",hrefEdit->text()); + area->setAttribute("alt",altEdit->text()); + area->setAttribute("target",targetEdit->text()); + area->setAttribute("title",titleEdit->text()); + area->setAttribute("onclick",onClickEdit->text()); + area->setAttribute("ondblclick",onDblClickEdit->text()); + area->setAttribute("onmousedown",onMouseDownEdit->text()); + area->setAttribute("onmouseup",onMouseUpEdit->text()); + area->setAttribute("onmousemove",onMouseMoveEdit->text()); + area->setAttribute("onmouseover",onMouseOverEdit->text()); + area->setAttribute("onmouseout",onMouseOutEdit->text()); + + // redraw old area to get rid of it + emit areaChanged(oldArea); + // draw new area + emit areaChanged(area); + oldArea->setRect(area->rect()); + } +} + +void AreaDialog::slotCancel() { + if (area) { + AreaSelection *selection=0L; + if ( (selection=dynamic_cast<AreaSelection*>(areaCopy)) ) + area->setArea(*selection); + else + area->setArea(*areaCopy); + area->highlightSelectionPoint(-1); + emit areaChanged(oldArea); + emit areaChanged(area); + } + reject(); +} + +void AreaDialog::slotUpdateArea() { + emit areaChanged(oldArea); + // draw new area + emit areaChanged(area); + oldArea->setRect(area->rect()); +} + +ImageMapChooseDialog::ImageMapChooseDialog(QWidget* parent,QPtrList<MapTag> *_maps,QPtrList<ImageTag> *_images,const KURL & _baseUrl) + : KDialogBase(parent,"",true,i18n( "Choose Map & Image to Edit" ),Ok,Ok,true) +{ + baseUrl=_baseUrl; + maps=_maps; + images=_images; + currentMap=0L; + QWidget *page=new QWidget(this); + setMainWidget(page); + setCaption(baseUrl.fileName()); + QVBoxLayout *layout = new QVBoxLayout(page,5,5); + + QLabel *lbl= new QLabel(i18n("Select an image and/or a map that you want to edit"),page); + lbl->setFont(QFont("Sans Serif",12, QFont::Bold)); + layout->addWidget(lbl); + QFrame *line= new QFrame(page); + line->setFrameStyle(QFrame::HLine | QFrame::Sunken); + line->setFixedHeight(10); + layout->addWidget(line,0); + + QGridLayout *gridLayout= new QGridLayout(layout,2,3,5); + gridLayout->setRowStretch(0,0); + gridLayout->setRowStretch(1,100); + lbl=new QLabel(i18n("&Maps"),page); + mapListBox= new QListBox(page); + lbl->setBuddy(mapListBox); + gridLayout->addWidget(lbl,0,0); + gridLayout->addWidget(mapListBox,1,0); + + line= new QFrame(page); + line->setFrameStyle(QFrame::VLine | QFrame::Sunken); + line->setFixedWidth(10); +// line->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding)); + gridLayout->addWidget(line,1,1); + + lbl=new QLabel(i18n("Image Preview"),page); + gridLayout->addWidget(lbl,0,2); + + imagePreview= new QLabel(page); + imagePreview->setFixedSize(310,210); + imagePreview->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding)); + imagePreview->setFrameStyle(QLabel::Panel | QLabel::Sunken); + imagePreview->setIndent(5); + imagePreview->setBackgroundColor(QColor("white")); +// imagePreview->setLineWidth(2); +// imagePreview->setScaledContents(true); +// lbl= new QLabel(i18n("&Maps"),page); +// lbl->setBuddy(mapListBox); + gridLayout->addWidget(imagePreview,1,2); +// layout->addLayout(gridLayout,1); + + line= new QFrame(page); + line->setFrameStyle(QFrame::HLine | QFrame::Sunken); + line->setFixedHeight(10); + layout->addWidget(line,0); + + + if (maps->isEmpty()) { + mapListBox->insertItem(i18n("No maps found")); + mapListBox->setEnabled(false); + } + else { + for (MapTag *tag = maps->first(); tag!=0L; tag=maps->next()) { + mapListBox->insertItem(tag->name); + } + connect (mapListBox, SIGNAL(highlighted(int)), this, SLOT(slotMapChanged(int))); + } + + initImageListTable(page); + + if (! maps->isEmpty()) { + mapListBox->setCurrentItem(0); + slotMapChanged(0); + } + + resize(510,460); +} + +void ImageMapChooseDialog::initImageListTable(QWidget* parent) { + + + if (images->isEmpty()) { + imageListTable= new QTable(1,1,parent); + imageListTable->setText(0,0,i18n("No images found")); + imageListTable->setEnabled(false); + imageListTable->horizontalHeader()->hide(); + imageListTable->setTopMargin(0); + imageListTable->setColumnStretchable(0,true); + } else { + imageListTable= new QTable(images->count(),2,parent); + imageListTable->setColumnStretchable(0,true); + } + + imageListTable->verticalHeader()->hide(); + imageListTable->setLeftMargin(0); + + QLabel *lbl= new QLabel(i18n("&Images"),parent); + lbl->setBuddy(imageListTable); + + parent->layout()->add(lbl); + parent->layout()->add(imageListTable); + + if (images->isEmpty()) + return; + + imageListTable->horizontalHeader()->setLabel(0,i18n("Path")); + imageListTable->horizontalHeader()->setLabel(1,"usemap"); + + imageListTable->setSelectionMode(QTable::SingleRow); + imageListTable->setFocusStyle(QTable::FollowStyle); + imageListTable->clearSelection(true); + + + int row=0; + for (ImageTag *tag = images->first(); tag!=0L; tag=images->next()) { + QString src=""; + QString usemap=""; + if (tag->find("src")) + src=*tag->find("src"); + if (tag->find("usemap")) + usemap=*tag->find("usemap"); + + imageListTable->setText(row,0,src); + imageListTable->setText(row,1,usemap); + row++; + } + connect (imageListTable, SIGNAL(selectionChanged()), this, SLOT(slotImageChanged())); + + imageListTable->selectRow(0); + slotImageChanged(); + + +} + +ImageMapChooseDialog::~ImageMapChooseDialog() { +} + +void ImageMapChooseDialog::slotImageChanged() +{ + int i=imageListTable->currentRow(); + QImage pix; + if (images->at(i)->find("src")) { + QString str=*images->at(i)->find("src"); + // relative url + pixUrl=KURL(baseUrl,str); + pix=QImage(pixUrl.path()); + double zoom1=1; + double zoom2=1; + if (pix.width()>300) + zoom1=(double) 300/pix.width(); + if (pix.height()>200) + zoom2=(double) 200/pix.height(); + + + zoom1= zoom1 < zoom2 ? zoom1 : zoom2; + pix=pix.smoothScale((int)(pix.width()*zoom1),int(pix.height()*zoom1)); + } + QPixmap pix2; + pix2.convertFromImage(pix); + imagePreview->setPixmap(pix2); + +// imagePreview->repaint(); +} + +void ImageMapChooseDialog::selectImageWithUsemap(const QString & usemap) { + for (int i=0; i<imageListTable->numRows(); i++) { + if (imageListTable->text(i,1)==usemap) { + imageListTable->selectRow(i); + slotImageChanged(); + return; + } + } +} + +void ImageMapChooseDialog::slotMapChanged(int i) { + currentMap=maps->at(i); + selectImageWithUsemap(currentMap->name); +} + +PreferencesDialog::PreferencesDialog(QWidget *parent, KConfig* conf) + : KDialogBase(parent,"",true,i18n("Preferences"),Ok|Apply|Cancel,Ok,true) +{ + config = conf; + QVBox *page=new QVBox(this); + page->setSpacing(6); + setMainWidget(page); + + QHBox *hbox= new QHBox(page); + + QLabel *lbl = new QLabel(i18n("&Maximum image preview height:")+" ",hbox); + rowHeightSpinBox = new QSpinBox(hbox); + lbl->setBuddy(rowHeightSpinBox); + + config->setGroup("Appearance"); + rowHeightSpinBox->setMaxValue(1000); + rowHeightSpinBox->setMinValue(15); + rowHeightSpinBox->setFixedWidth(60); + rowHeightSpinBox->setValue(config->readNumEntry("maximum-preview-height",50)); + + config->setGroup("General"); + + hbox= new QHBox(page); + lbl = new QLabel(i18n("&Undo limit:")+" ",hbox); + undoSpinBox = new QSpinBox(hbox); + undoSpinBox->setFixedWidth(60); + lbl->setBuddy(undoSpinBox); + + undoSpinBox->setMaxValue(100); + undoSpinBox->setMinValue(1); + undoSpinBox->setValue(config->readNumEntry("undo-level",20)); + + hbox= new QHBox(page); + lbl = new QLabel(i18n("&Redo limit:")+" ",hbox); + + redoSpinBox = new QSpinBox(hbox); + redoSpinBox->setFixedWidth(60); + redoSpinBox->setMaxValue(100); + redoSpinBox->setMinValue(1); + redoSpinBox->setValue(config->readNumEntry("redo-level",20)); + lbl->setBuddy(redoSpinBox); + + startWithCheck = new QCheckBox(i18n("&Start with last used document"),page); + startWithCheck->setChecked(config->readBoolEntry("start-with-last-used-document",true)); + +/* + hbox= new QHBox(page); + (void)new QLabel(i18n("Highlight Areas")+" ",hbox); + + colorizeAreaChk = new QCheckBox(hbox); + colorizeAreaChk->setFixedWidth(60); + colorizeAreaChk->setChecked(kapp->config()->readBoolEntry("highlightareas",true)); + + hbox= new QHBox(page); + (void)new QLabel(i18n("Show alternative text")+" ",hbox); + + showAltChk = new QCheckBox(hbox); + showAltChk->setFixedWidth(60); + showAltChk->setChecked(kapp->config()->readBoolEntry("showalt",true)); +*/ +} + +PreferencesDialog::~PreferencesDialog() { +} + +void PreferencesDialog::slotDefault( void ) { + rowHeightSpinBox->setValue(50); +} + +void PreferencesDialog::slotOk( void ) { + slotApply(); + accept(); +} + +void PreferencesDialog::slotApply( void ) { + config->setGroup("Appearance"); + config->writeEntry("maximum-preview-height",rowHeightSpinBox->cleanText().toInt()); + + config->setGroup("General Options"); + config->writeEntry("undo-level",undoSpinBox->cleanText().toInt()); + config->writeEntry("redo-level",redoSpinBox->cleanText().toInt()); + config->writeEntry("start-with-last-used-document", startWithCheck->isChecked()); + + config->sync(); + emit applyClicked(); +} + +HTMLPreviewDialog::HTMLPreviewDialog(QWidget* parent, KURL url, const QString & htmlCode) + : KDialogBase(parent, "", true, i18n("Preview"), KDialogBase::Ok) +{ + tempFile = new KTempFile(url.directory(false), ".html"); + tempFile->setAutoDelete(true); + (*tempFile->textStream()) << htmlCode; + kdDebug() << "HTMLPreviewDialog: TempFile : " << tempFile->name() << endl; + tempFile->close(); + + QVBox *page = makeVBoxMainWidget(); + + htmlPart = new KHTMLPart(page,"htmlpart"); +// htmlView = new KHTMLView(htmlPart, page); +// htmlView->setVScrollBarMode(QScrollView::Auto); +// htmlView->setHScrollBarMode(QScrollView::Auto); +// dialog->resize(dialog->calculateSize(edit->maxLineWidth(),edit->numLines()*)); +// dialog->adjustSize(); + QLabel* lbl = new QLabel(page,"urllabel"); + + connect( htmlPart, SIGNAL( onURL(const QString&)), lbl, SLOT( setText(const QString&))); +} + +HTMLPreviewDialog::~HTMLPreviewDialog() { + delete tempFile; + delete htmlPart; +} + +void HTMLPreviewDialog::show() { + KDialogBase::show(); + htmlPart->openURL(KURL( tempFile->name() )); +// htmlView->layout(); +// htmlView->repaint(); + resize(800,600); +} + +#include "kimedialogs.moc" diff --git a/kimagemapeditor/kimedialogs.h b/kimagemapeditor/kimedialogs.h new file mode 100644 index 00000000..c87f8dfe --- /dev/null +++ b/kimagemapeditor/kimedialogs.h @@ -0,0 +1,207 @@ +/*************************************************************************** + kimedialogs.h - description + ------------------- + begin : Tue Apr 17 2001 + copyright : (C) 2001 by Jan Sch�fer + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 KIMEDIALOGS_H +#define KIMEDIALOGS_H + +#include <kdialog.h> +#include <kdialogbase.h> + +#include <kurl.h> +#include "kimagemapeditor.h" + +#include "kdeversion.h" + +class QLineEdit; +class QMultiLineEdit; +class QSpinBox; + + +class CoordsEdit : public QWidget { +Q_OBJECT + public : + CoordsEdit(QWidget *parent, Area* a); + virtual ~CoordsEdit(); + virtual void applyChanges(); + protected: + Area *area; // The working area + protected slots: + void slotTriggerUpdate(); + signals: + void update(); +}; + +class RectCoordsEdit : public CoordsEdit { + public: + RectCoordsEdit(QWidget *parent, Area* a); + virtual void applyChanges(); + private: + QSpinBox *topXSpin; + QSpinBox *topYSpin; + QSpinBox *widthSpin; + QSpinBox *heightSpin; +}; + +class CircleCoordsEdit : public CoordsEdit { + public: + CircleCoordsEdit(QWidget *parent, Area* a); + virtual void applyChanges(); + private: + QSpinBox *centerXSpin; + QSpinBox *centerYSpin; + QSpinBox *radiusSpin; +}; + +class QTable; + +class PolyCoordsEdit : public CoordsEdit { +Q_OBJECT + public: + PolyCoordsEdit(QWidget *parent, Area* a); + ~PolyCoordsEdit(); + virtual void applyChanges(); + private: + QTable *coordsTable; + protected slots: + void slotAddPoint(); + void slotRemovePoint(); + void slotHighlightPoint(int); + +}; + +class SelectionCoordsEdit : public CoordsEdit { +Q_OBJECT + public: + SelectionCoordsEdit(QWidget *parent, Area* a); + virtual void applyChanges(); + private: + QSpinBox *topXSpin; + QSpinBox *topYSpin; + +}; + + +class QCheckBox; +class QGridLayout; + +class AreaDialog : public KDialog { +Q_OBJECT + private: + Area *area; + Area *oldArea; // Only for drawing reasons + Area *areaCopy; // A copy for restoring the original area if user press cancel + QLineEdit *hrefEdit; + QLineEdit *altEdit; + QLineEdit *targetEdit; + QLineEdit *titleEdit; + + QLineEdit *onClickEdit; + QLineEdit *onDblClickEdit; + QLineEdit *onMouseDownEdit; + QLineEdit *onMouseUpEdit; + QLineEdit *onMouseOverEdit; + QLineEdit *onMouseMoveEdit; + QLineEdit *onMouseOutEdit; + + CoordsEdit *coordsEdit; + CoordsEdit* createCoordsEdit(QWidget *parent, Area *a); + QCheckBox *defaultAreaChk; + KImageMapEditor *_document; + + + public: + AreaDialog(KImageMapEditor* parent,Area * a); + ~AreaDialog(); + protected slots: + virtual void slotOk(); + virtual void slotApply(); + virtual void slotCancel(); + void slotChooseHref(); + void slotUpdateArea(); + + QLineEdit* createLineEdit(QWidget* parent, QGridLayout *layout, int y, const QString & value, const QString & name); + QWidget* createGeneralPage(); + QWidget* createCoordsPage(); + QWidget* createJavascriptPage(); + QWidget* createButtonBar(); + signals: + void areaChanged(Area* a); +}; + +class QLineEdit; +class QListBox; +class QLabel; + + +class ImageMapChooseDialog : public KDialogBase { +Q_OBJECT + private: + QTable *imageListTable; + QLabel *imagePreview; + QListBox *mapListBox; + QLineEdit *mapNameEdit; + QPtrList<MapTag> *maps; + QPtrList<ImageTag> *images; + KURL baseUrl; + void initImageListTable(QWidget*); + public: + ImageMapChooseDialog(QWidget* parent,QPtrList<MapTag> *_maps,QPtrList<ImageTag> *_images, const KURL & _baseUrl); + ~ImageMapChooseDialog(); + KURL pixUrl; + MapTag* currentMap; + protected slots: + void slotImageChanged(); + void slotMapChanged(int i); + void selectImageWithUsemap(const QString & usemap); + +}; + +class KConfig; + +class PreferencesDialog : public KDialogBase { +Q_OBJECT + public: + PreferencesDialog(QWidget *parent,KConfig*); + ~PreferencesDialog(); + protected slots: + virtual void slotDefault( void ); + virtual void slotOk( void ); + virtual void slotApply( void ); + private: + QSpinBox *rowHeightSpinBox; + QSpinBox *undoSpinBox; + QSpinBox *redoSpinBox; +// QCheckBox *colorizeAreaChk; +// QCheckBox *showAltChk; + QCheckBox *startWithCheck; + KConfig *config; +}; + +class KHTMLPart; +class KTempFile; + +class HTMLPreviewDialog : public KDialogBase { + public: + HTMLPreviewDialog(QWidget *, KURL, const QString &); + ~HTMLPreviewDialog(); + virtual void show(); + private: + KHTMLPart* htmlPart; + KTempFile* tempFile; +}; + +#endif diff --git a/kimagemapeditor/kimeshell.cpp b/kimagemapeditor/kimeshell.cpp new file mode 100644 index 00000000..d919d2b7 --- /dev/null +++ b/kimagemapeditor/kimeshell.cpp @@ -0,0 +1,296 @@ +/*************************************************************************** + kimepart.cpp - description + ------------------- + begin : Mon Aug 5 2002 + copyright : (C) 2002 by Jan Sch�er + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 <iostream> + +#include <kaction.h> +#include <kiconloader.h> +#include <kstandarddirs.h> +#include <kfiledialog.h> +#include <kmessagebox.h> +#include <kkeydialog.h> +#include <kedittoolbar.h> +#include <kstatusbar.h> +#include <kapplication.h> +#include <kdebug.h> + +#include <qhbox.h> + +#include "drawzone.h" +#include "kimagemapeditor.h" // the KPart +#include "kimeshell.h" +#include "kimeshell.moc" + +KimeShell::KimeShell(const char *name ) + : KParts::DockMainWindow( 0L, name ) +{ + setXMLFile("kimagemapeditorui.rc"); + + + KDockWidget* mainDock; + mainDock = createDockWidget( "MainDockWidget", 0L, 0L, "main_dock_widget"); + QWidget *w = new QHBox( mainDock ); +// QLayout* layout = new QGridLayout( mainDock ); + + mainDock->setWidget( w ); + // allow others to dock to the 4 sides + mainDock->setDockSite(KDockWidget::DockCorner); + // forbit docking abilities of mainDock itself + mainDock->setEnableDocking(KDockWidget::DockNone); + setView( mainDock); // central widget in a KDE mainwindow + setMainDockWidget( mainDock); // master dockwidget + m_part = new KImageMapEditor( w, "kimagemapeditor", this, "kimagemapeditor"); + + +// setCentralWidget( part->widget() ); + + setupActions(); + + _stdout=false; + +// createGUI( part ); + createShellGUI( true ); + guiFactory()->addClient( m_part ); + KParts::GUIActivateEvent ev( true ); + QApplication::sendEvent( m_part, &ev ); + //setCentralWidget(part->widget()); + + if (!initialGeometrySet()) + resize( QSize(725, 525).expandedTo(minimumSizeHint())); + + connect( m_part, SIGNAL(setStatusBarText(const QString &)), + this, SLOT(slotSetStatusBarText ( const QString & ))); + + connect( m_part, SIGNAL(setWindowCaption(const QString &)), + this, SLOT(setCaption( const QString &))); + + setAutoSaveSettings( "General Options" ); + +} + +KimeShell::~KimeShell() +{ +// delete part; +} + +bool KimeShell::queryClose() +{ + if (_stdout) { + std::cout << m_part->getHtmlCode() << std::endl; + } + + return m_part->queryClose(); +} + + +bool KimeShell::queryExit() +{ +// writeConfig(); + saveProperties(kapp->config()); + + return true; +} + + +void KimeShell::setupActions() +{ + (void)KStdAction::openNew(this, SLOT(fileNew()), actionCollection()); + + // File Quit + (void)KStdAction::quit(this, SLOT(close()),actionCollection()); + + + (void)KStdAction::showToolbar(this, SLOT(optionsShowToolbar()), actionCollection()); + (void)KStdAction::keyBindings(this, SLOT(optionsConfigureKeys()), actionCollection()); + (void)KStdAction::configureToolbars(this, SLOT(optionsConfigureToolbars()), actionCollection()); + (void)KStdAction::showStatusbar(this, SLOT(optionsShowStatusbar()), actionCollection()); + + +} + +void KimeShell::fileNew() +{ + // this slot is called whenever the File->New menu is selected, + // the New shortcut is pressed (usually CTRL+N) or the New toolbar + // button is clicked + + // About this function, the style guide ( + // http://developer.kde.org/documentation/standards/kde/style/basics/index.html ) + // says that it should open a new window if the document is _not_ + // in its initial state. This is what we do here.. + if ( ! m_part->url().isEmpty() || m_part->isModified() ) + { + KimeShell * newShell = new KimeShell(); + + newShell->show(); + newShell->readConfig(); + }; +} + +void KimeShell::openFile(const KURL & url) +{ + m_part->openFile(url); +} + +void KimeShell::openLastFile() +{ + if (m_part->config()->readBoolEntry("start-with-last-used-document",true)) + m_part->openLastURL(m_part->config()); +} + +void KimeShell::fileOpen() +{ + KURL url=KFileDialog::getOpenURL(QString::null, + "*.png *.jpg *.jpeg *.gif *.htm *.html|" + i18n( "Web Files" ) + "\n" + "*.png *.jpg *.jpeg *.gif *.bmp *.xbm *.xpm *.pnm *.mng|" + i18n( "Images" ) + "\n" + "*.htm *.html|" + i18n( "HTML Files" ) + "\n" + "*.png|" + i18n( "PNG Images" ) + "\n*.jpg *.jpeg|" + i18n( "JPEG Images" ) + "\n*.gif|" + i18n( "GIF Images" ) + "\n*|" + i18n( "All Files" ) + ,this,i18n("Choose Picture to Open")); + + if (!url.isEmpty()) { + // About this function, the style guide ( + // http://developer.kde.org/documentation/standards/kde/style/basics/index.html ) + // says that it should open a new window if the document is _not_ + // in its initial state. This is what we do here.. + if ( m_part->url().isEmpty() && ! m_part->isModified() ) + { + // we open the file in this window... + m_part->openURL(url); + } + else + { + // we open the file in a new window... + KimeShell* newWin = new KimeShell; + newWin->openFile( url ); + newWin->show(); + } + } +} + + + +void KimeShell::readConfig() { + KConfig *config; + + config = kapp->config(); + + config->setGroup("General Options"); + readConfig(config); + +} + +void KimeShell::readConfig(KConfig* config) { +// applyMainWindowSettings(config); +// restoreWindowSize(config); + readDockConfig(config); +} + +void KimeShell::writeConfig() { + KConfig *config; + + config = kapp->config(); + + config->setGroup("General Options"); + writeConfig(config); +} + +void KimeShell::writeConfig(KConfig* config) { + saveMainWindowSettings(config); + saveWindowSize(config); + writeDockConfig(config); + config->sync(); + +} + + +void KimeShell::saveProperties(KConfig *config) +{ + //writeConfig(config); + m_part->saveProperties(config); + writeConfig(); + +} + +void KimeShell::readProperties(KConfig *config) +{ + readConfig(); + m_part->readProperties(config); + + +} + + +void KimeShell::optionsConfigureKeys() { +// KKeyDialog::configureKeys(actionCollection(), "testprog_shell.rc"); + + KKeyDialog dlg; + dlg.insert(actionCollection()); + dlg.insert(m_part->actionCollection()); + dlg.configure(); +} + +void KimeShell::optionsConfigureToolbars() +{ +#if defined(KDE_MAKE_VERSION) +# if KDE_VERSION >= KDE_MAKE_VERSION(3,1,0) + saveMainWindowSettings(KGlobal::config(), autoSaveGroup()); +# else + saveMainWindowSettings(KGlobal::config() ); +# endif +#else + saveMainWindowSettings(KGlobal::config() ); +#endif + + // use the standard toolbar editor + KEditToolbar dlg(factory()); + connect(&dlg, SIGNAL(newToolbarConfig()), + this, SLOT(applyNewToolbarConfig())); + dlg.exec(); +} + +void KimeShell::applyNewToolbarConfig() +{ +#if defined(KDE_MAKE_VERSION) +# if KDE_VERSION >= KDE_MAKE_VERSION(3,1,0) + applyMainWindowSettings(KGlobal::config(), autoSaveGroup()); +# else + applyMainWindowSettings(KGlobal::config()); +# endif +#else + applyMainWindowSettings(KGlobal::config()); +#endif +} + + +void KimeShell::optionsShowToolbar() +{ + if (toolBar()->isVisible()) + toolBar()->hide(); + else + toolBar()->show(); +} + +void KimeShell::optionsShowStatusbar() +{ + if (statusBar()->isVisible()) + statusBar()->hide(); + else + statusBar()->show(); +} + + diff --git a/kimagemapeditor/kimeshell.h b/kimagemapeditor/kimeshell.h new file mode 100644 index 00000000..28026524 --- /dev/null +++ b/kimagemapeditor/kimeshell.h @@ -0,0 +1,81 @@ +/*************************************************************************** + kimeshell.h - description + ------------------- + begin : Mon Aug 5 2002 + copyright : (C) 2002 by Jan Sch�fer + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 KIMESHELL_H +#define KIMESHELL_H + +#include <kparts/dockmainwindow.h> + +class KImageMapEditor; + +class KimeShell : public KParts::DockMainWindow +{ + Q_OBJECT + +public: + KimeShell( const char *name=0 ); + virtual ~KimeShell(); + + void setStdout(bool b); + void openFile(const KURL & url); + + /** + * Opens the last open file, if the + * user has configured to open the last + * file. Otherwise does nothing + */ + void openLastFile(); + void readConfig(); + void writeConfig(); + +protected: + void setupActions(); + void readConfig(KConfig*); + void writeConfig(KConfig*); + +// virtual bool queryClose(); + virtual void readProperties(KConfig *config); + virtual void saveProperties(KConfig *config); + + virtual bool queryClose(); + virtual bool queryExit(); + + +private slots: + void fileNew(); + void fileOpen(); + void optionsShowToolbar(); + void optionsShowStatusbar(); + void optionsConfigureKeys(); + void optionsConfigureToolbars(); + + void applyNewToolbarConfig(); +private: + KImageMapEditor *m_part; + + bool _stdout; // write HTML-Code to stdout on exit ? + + + +}; + +inline void KimeShell::setStdout(bool b) { + _stdout=b; +} + + +#endif diff --git a/kimagemapeditor/main.cpp b/kimagemapeditor/main.cpp new file mode 100644 index 00000000..626a6e44 --- /dev/null +++ b/kimagemapeditor/main.cpp @@ -0,0 +1,91 @@ +/*************************************************************************** + main.cpp - description + ------------------- + begin : Die Apr 10 19:46:49 CEST 2001 + copyright : (C) 2001 by Jan Sch�er + email : [email protected] +***************************************************************************/ + +/*************************************************************************** +* * +* 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 <kcmdlineargs.h> +#include <kaboutdata.h> +#include <klocale.h> +#include <kapplication.h> +#include <dcopclient.h> + +#include "kimeshell.h" +#include <config.h> + +static const char *description = + I18N_NOOP("An HTML imagemap editor"); + + +static KCmdLineOptions options[] = +{ + { "c", 0, 0 }, + { "stdout", I18N_NOOP("Write HTML-Code to stdout on exit"), 0 }, + { "+[File]", I18N_NOOP("File to open"), 0 }, + { 0, 0, 0 } + // INSERT YOUR COMMANDLINE OPTIONS HERE +}; + +int main(int argc, char *argv[]) +{ + + KAboutData aboutData( "kimagemapeditor", I18N_NOOP("KImageMapEditor"), + VERSION, description, KAboutData::License_GPL, + "(C) 2001-2008 Jan Schaefer", 0, "http://www.nongnu.org/kimagemap/", "[email protected]"); + aboutData.addAuthor("Jan Schaefer",0, "[email protected]"); + aboutData.addCredit("Joerg Jaspert",I18N_NOOP("For helping me with the Makefiles, and creating the Debian package")); + aboutData.addCredit("Aaron Seigo and Michael",I18N_NOOP("For helping me fixing --enable-final mode")); + aboutData.addCredit("Antonio Crevillen",I18N_NOOP("For the Spanish translation")); + aboutData.addCredit("Fabrice Mous",I18N_NOOP("For the Dutch translation")); + aboutData.addCredit("Germain Chazot",I18N_NOOP("For the French translation")); + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); // Add our own options. + + KApplication a; + a.dcopClient()->registerAs(a.name()); + + + + if (a.isRestored()) + { + RESTORE(KimeShell); + } + else + { + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + if ( args->count() == 0 ) + { + KimeShell *kimeShell = new KimeShell(); + kimeShell->setStdout(args->isSet("stdout")); + kimeShell->readConfig(); + kimeShell->show(); + kimeShell->openLastFile(); + } + else + { + int i = 0; + for (; i < args->count(); i++ ) + { + KimeShell *kimeShell = new KimeShell(); + kimeShell->setStdout(args->isSet("stdout")); + kimeShell->readConfig(); + kimeShell->show(); + kimeShell->openFile(args->url(i)); + } + } + args->clear(); + } + + return a.exec(); +} diff --git a/kimagemapeditor/mapslistview.cpp b/kimagemapeditor/mapslistview.cpp new file mode 100644 index 00000000..ec89ae4a --- /dev/null +++ b/kimagemapeditor/mapslistview.cpp @@ -0,0 +1,174 @@ +/*************************************************************************** + mapslistview.cpp - description + ------------------- + begin : Weg Feb 26 2003 + copyright : (C) 2003 by Jan SchÃ?fer + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +// KDE +#include <klistview.h> +#include <klocale.h> +#include <kdebug.h> + +// locale +#include "mapslistview.h" + + +MapsListView::MapsListView(QWidget *parent, const char *name) +: QVBox(parent, name) { + _listView = new KListView(this); + _listView->addColumn(i18n("Maps")); + _listView->setFullWidth(true); + _listView->setSelectionMode(QListView::Single); + _listView->setItemsRenameable(true); + + connect( _listView, SIGNAL( selectionChanged(QListViewItem*)), + this, SLOT( slotSelectionChanged(QListViewItem*))); + + connect( _listView, SIGNAL( itemRenamed(QListViewItem*)), + this, SLOT( slotItemRenamed(QListViewItem*))); +} + + +MapsListView::~MapsListView() { +} + +void MapsListView::addMap(const QString & name = QString::null) { + new QListViewItem(_listView,name); + //kdDebug() << "MapsListView::addMap : Added map '" << name << "'" << endl; + +} + +void MapsListView::addMaps(QPtrList<MapTag> * maps) { + + for (MapTag *tag = maps->first(); tag!=0L; tag=maps->next()) { + addMap(tag->name); + } +} + +void MapsListView::selectMap(const QString & name) { + QListViewItem* item = _listView->findItem(name,0); + if (item) { + selectMap(item); + } else + kdWarning() << "MapsListView::selectMap : Couldn't found map '" << name << "'" << endl; + +} + +void MapsListView::selectMap(QListViewItem* item) { + if (item) + _listView->setSelected(item,true); +} + + +QString MapsListView::selectedMap() { + QString result; + + QListViewItem* item = _listView->selectedItem(); + if (item) + result = item->text(0); + else + kdWarning() << "MapsListView::selectedMap : No map selected !" << endl; + + return result; +} + +void MapsListView::removeMap(const QString & name) { + QListViewItem* item = _listView->findItem(name,0); + if (item) { + _listView->takeItem(item); + _listView->setSelected(_listView->currentItem(),true); +// kdDebug() << "MapsListView::removeMap : Removed map '" << name << "'" << endl; + } else + kdWarning() << "MapsListView::removeMap : Couldn't found map '" << name << "'" << endl; +} + +void MapsListView::clear() { + _listView->clear(); +} + +void MapsListView::slotSelectionChanged(QListViewItem* item) { + QString name = item->text(0); + emit mapSelected(name); +} + +void MapsListView::slotItemRenamed(QListViewItem* item) { + QString name = item->text(0); + emit mapRenamed(name); +} + +void MapsListView::changeMapName(const QString & oldName, const QString & newName) { +// kdDebug() << "MapsListView::changeMapName : " << oldName << " to " << newName << endl; + QListViewItem* item = _listView->findItem(oldName,0); + if (item) { + item->setText(0,newName); +// kdDebug() << "MapsListView::changeMapName : successful" << endl; + } + else { + kdWarning() << "MapsListView::changeMapName : Chouldn't find map with name '" << oldName << "'" << endl; + } + +} + + +bool MapsListView::nameAlreadyExists(const QString & name) { +// kdDebug() << "MapsListView::nameAlreadyExists : " << name << " ? " << endl; + bool result = false; + QListViewItem* item = 0L; + for(item = _listView->firstChild(); item; item = item->nextSibling()) { + QString otherMap = item->text(0); + if(name == otherMap) { + result = true; + break; + } + } + +// kdDebug() << "MapsListView::nameAlreadyExists : " << name << " : " << result << endl; + + return result; +} + +QStringList MapsListView::getMaps() { + QStringList result; + + QListViewItem* item = 0L; + for(item = _listView->firstChild(); item; item = item->nextSibling()) { + QString map = item->text(0); + result << map; + } + + return result; +} + +QString MapsListView::getUnusedMapName() { + QString result; + QString attempt; + int i=0; + while(result.isEmpty()) { + i++; + attempt = i18n("unnamed"); + attempt += QString::number(i); + if (nameAlreadyExists(attempt)) + continue; + + result = attempt; + } + +// kdDebug() << "MapsListView::getUnusedMapName : Found an unused name : '" << result << "'" << endl; + return result; +} + +uint MapsListView::count() { + return _listView->childCount(); +} + +#include "mapslistview.moc" diff --git a/kimagemapeditor/mapslistview.h b/kimagemapeditor/mapslistview.h new file mode 100644 index 00000000..559725a2 --- /dev/null +++ b/kimagemapeditor/mapslistview.h @@ -0,0 +1,126 @@ +/*************************************************************************** + mapslistview.h - description + ------------------- + begin : Weg Feb 26 2003 + copyright : (C) 2003 by Jan Sch�fer + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 _MAPSLISTVIEW_H_ +#define _MAPSLISTVIEW_H_ + +#include <qvbox.h> + +#include "kimagemapeditor.h" +class KListView; + +/** + * Simple class that shows all map tags of the current open html file in a ListView + * + * Jan Schaefer + **/ +class MapsListView : public QVBox +{ +Q_OBJECT +public: + MapsListView(QWidget *parent, const char *name); + ~MapsListView(); + + /** + * Adds the given map to the ListView + */ + void addMap(const QString &); + + /** + * Adds all maps of the given QList to the ListView + */ + void addMaps(QPtrList<MapTag> *); + + /** + * Removes the given map from the ListView + */ + void removeMap(const QString &); + + /** + * Set the the given map selected in the ListView. + * it does not emit mapSelected afterwards. + */ + void selectMap(const QString &); + + /** + * Selects the given ListViewItem and deselects the current selected item + */ + void selectMap(QListViewItem* item); + + /** + * Changes the name of the map with the @p oldName to @p newName + */ + void changeMapName(const QString & oldName, const QString & newName); + + /** + * Returns the current selected map + */ + QString selectedMap(); + + + /** + * Removes all maps from the ListView + */ + void clear(); + + /** + * Returns a name for a map which is not used yet. + * Returns for example Unnamed1 + */ + QString getUnusedMapName(); + + /** + * Wether or not the given map name already exists + */ + bool nameAlreadyExists(const QString &); + + /** + * Returns a QStringList of all maps + */ + QStringList getMaps(); + + /** + * Returns the number of maps + */ + uint count(); + + KListView* listView() { return _listView; } +protected: + KListView* _listView; + +protected slots: + void slotSelectionChanged(QListViewItem*); + void slotItemRenamed(QListViewItem*); + +signals: + + /** + * Gets emitted when the user selects a map in + * the ListView + */ + void mapSelected(const QString &); + + + /** + * Emitted when the user has renamed a map in the ListView + */ + void mapRenamed(const QString & newName); + + +}; + +#endif diff --git a/kimagemapeditor/pics/Makefile.am b/kimagemapeditor/pics/Makefile.am new file mode 100644 index 00000000..4d7ead61 --- /dev/null +++ b/kimagemapeditor/pics/Makefile.am @@ -0,0 +1,8 @@ +KDE_ICON = kimagemapeditor + +appicondir = $(kde_datadir)/kimagemapeditor/icons +appicon_ICON = addpoint arrow circle circle2 freehand lower polygon raise rectangle removepoint + +picturesdir = $(kde_datadir)/kimagemapeditor +pictures_DATA = addpointcursor.png freehandcursor.png polygoncursor.png removepointcursor.png + diff --git a/kimagemapeditor/pics/addpointcursor.png b/kimagemapeditor/pics/addpointcursor.png Binary files differnew file mode 100644 index 00000000..0fe9f853 --- /dev/null +++ b/kimagemapeditor/pics/addpointcursor.png diff --git a/kimagemapeditor/pics/freehandcursor.png b/kimagemapeditor/pics/freehandcursor.png Binary files differnew file mode 100644 index 00000000..2f7f1163 --- /dev/null +++ b/kimagemapeditor/pics/freehandcursor.png diff --git a/kimagemapeditor/pics/hi16-app-kimagemapeditor.png b/kimagemapeditor/pics/hi16-app-kimagemapeditor.png Binary files differnew file mode 100644 index 00000000..cfdea0a0 --- /dev/null +++ b/kimagemapeditor/pics/hi16-app-kimagemapeditor.png diff --git a/kimagemapeditor/pics/hi22-action-addpoint.png b/kimagemapeditor/pics/hi22-action-addpoint.png Binary files differnew file mode 100644 index 00000000..51114fdf --- /dev/null +++ b/kimagemapeditor/pics/hi22-action-addpoint.png diff --git a/kimagemapeditor/pics/hi22-action-arrow.png b/kimagemapeditor/pics/hi22-action-arrow.png Binary files differnew file mode 100644 index 00000000..dfbeabaa --- /dev/null +++ b/kimagemapeditor/pics/hi22-action-arrow.png diff --git a/kimagemapeditor/pics/hi22-action-circle.png b/kimagemapeditor/pics/hi22-action-circle.png Binary files differnew file mode 100644 index 00000000..e0e616ce --- /dev/null +++ b/kimagemapeditor/pics/hi22-action-circle.png diff --git a/kimagemapeditor/pics/hi22-action-circle2.png b/kimagemapeditor/pics/hi22-action-circle2.png Binary files differnew file mode 100644 index 00000000..45394d3b --- /dev/null +++ b/kimagemapeditor/pics/hi22-action-circle2.png diff --git a/kimagemapeditor/pics/hi22-action-freehand.png b/kimagemapeditor/pics/hi22-action-freehand.png Binary files differnew file mode 100644 index 00000000..7ff9ce46 --- /dev/null +++ b/kimagemapeditor/pics/hi22-action-freehand.png diff --git a/kimagemapeditor/pics/hi22-action-lower.png b/kimagemapeditor/pics/hi22-action-lower.png Binary files differnew file mode 100644 index 00000000..18742bf0 --- /dev/null +++ b/kimagemapeditor/pics/hi22-action-lower.png diff --git a/kimagemapeditor/pics/hi22-action-polygon.png b/kimagemapeditor/pics/hi22-action-polygon.png Binary files differnew file mode 100644 index 00000000..66786d16 --- /dev/null +++ b/kimagemapeditor/pics/hi22-action-polygon.png diff --git a/kimagemapeditor/pics/hi22-action-raise.png b/kimagemapeditor/pics/hi22-action-raise.png Binary files differnew file mode 100644 index 00000000..3e2e1287 --- /dev/null +++ b/kimagemapeditor/pics/hi22-action-raise.png diff --git a/kimagemapeditor/pics/hi22-action-rectangle.png b/kimagemapeditor/pics/hi22-action-rectangle.png Binary files differnew file mode 100644 index 00000000..8ff0b2b7 --- /dev/null +++ b/kimagemapeditor/pics/hi22-action-rectangle.png diff --git a/kimagemapeditor/pics/hi22-action-removepoint.png b/kimagemapeditor/pics/hi22-action-removepoint.png Binary files differnew file mode 100644 index 00000000..065912bf --- /dev/null +++ b/kimagemapeditor/pics/hi22-action-removepoint.png diff --git a/kimagemapeditor/pics/hi32-app-kimagemapeditor.png b/kimagemapeditor/pics/hi32-app-kimagemapeditor.png Binary files differnew file mode 100644 index 00000000..cb7558c2 --- /dev/null +++ b/kimagemapeditor/pics/hi32-app-kimagemapeditor.png diff --git a/kimagemapeditor/pics/hi48-app-kimagemapeditor.png b/kimagemapeditor/pics/hi48-app-kimagemapeditor.png Binary files differnew file mode 100644 index 00000000..c95bd08c --- /dev/null +++ b/kimagemapeditor/pics/hi48-app-kimagemapeditor.png diff --git a/kimagemapeditor/pics/lo16-app-kimagemapeditor.png b/kimagemapeditor/pics/lo16-app-kimagemapeditor.png Binary files differnew file mode 100644 index 00000000..0985586b --- /dev/null +++ b/kimagemapeditor/pics/lo16-app-kimagemapeditor.png diff --git a/kimagemapeditor/pics/lo32-app-kimagemapeditor.png b/kimagemapeditor/pics/lo32-app-kimagemapeditor.png Binary files differnew file mode 100644 index 00000000..12542c8a --- /dev/null +++ b/kimagemapeditor/pics/lo32-app-kimagemapeditor.png diff --git a/kimagemapeditor/pics/polygoncursor.png b/kimagemapeditor/pics/polygoncursor.png Binary files differnew file mode 100644 index 00000000..e315aa51 --- /dev/null +++ b/kimagemapeditor/pics/polygoncursor.png diff --git a/kimagemapeditor/pics/removepointcursor.png b/kimagemapeditor/pics/removepointcursor.png Binary files differnew file mode 100644 index 00000000..91187d1d --- /dev/null +++ b/kimagemapeditor/pics/removepointcursor.png diff --git a/kimagemapeditor/qextfileinfo.cpp b/kimagemapeditor/qextfileinfo.cpp new file mode 100644 index 00000000..c52c48b5 --- /dev/null +++ b/kimagemapeditor/qextfileinfo.cpp @@ -0,0 +1,347 @@ +/* + From WebMaker - KDE HTML Editor + Copyright (C) 1998, 1999 Alexei Dets <[email protected]> + + Rewritten for Quanta Plus: (C) 2002 Andras Mantia <[email protected]> + + 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. +*/ + + +//qt includes +#include <qdir.h> +#include <qapplication.h> +#include <qptrlist.h> +#include <qstringlist.h> +#include <qregexp.h> +#include <qtimer.h> + +//kde includes +#include <kurl.h> +#include <kio/job.h> +#include <kio/netaccess.h> +#include <kio/scheduler.h> +#include <kdirlister.h> +#include <kfileitem.h> +#include <kglobal.h> +#include <kdebug.h> + +//app includes +#include "qextfileinfo.h" + +QString QExtFileInfo::lastErrorMsg = ""; + +/** create a relative short url based in baseURL*/ +KURL QExtFileInfo::toRelative(const KURL& urlToConvert,const KURL& baseURL) +{ + KURL resultURL = urlToConvert; + if (urlToConvert.protocol() == baseURL.protocol()) + { + QString path = urlToConvert.path(); + QString basePath = baseURL.path(1); + if (path.startsWith("/")) + { + path.remove(0, 1); + basePath.remove(0, 1); + if ( basePath.right(1) != "/" ) basePath.append("/"); + + int pos=0; + int pos1=0; + for (;;) + { + pos=path.find("/"); + pos1=basePath.find("/"); + if ( pos<0 || pos1<0 ) break; + if ( path.left(pos+1 ) == basePath.left(pos1+1) ) + { + path.remove(0, pos+1); + basePath.remove(0, pos1+1); + } + else + break; + }; + + if ( basePath == "/" ) basePath=""; + int level = basePath.contains("/"); + for (int i=0; i<level; i++) + { + path="../"+path; + }; + } + + resultURL.setPath(QDir::cleanDirPath(path)); + } + + if (urlToConvert.path().endsWith("/")) resultURL.adjustPath(1); + return resultURL; +} +/** convert relative filename to absolute */ +KURL QExtFileInfo::toAbsolute(const KURL& urlToConvert,const KURL& baseURL) +{ + KURL resultURL = urlToConvert; + if (urlToConvert.protocol() == baseURL.protocol() && !urlToConvert.path().startsWith("/")) + { + int pos; + QString cutname = urlToConvert.path(); + QString cutdir = baseURL.path(1); + while ( (pos = cutname.find("../")) >=0 ) + { + cutname.remove( 0, pos+3 ); + cutdir.remove( cutdir.length()-1, 1 ); + cutdir.remove( cutdir.findRev('/')+1 , 1000); + } + resultURL.setPath(QDir::cleanDirPath(cutdir+cutname)); + } + + if (urlToConvert.path().endsWith("/")) resultURL.adjustPath(1); + return resultURL; +} + +/** All files in a dir. + The return will also contain the name of the subdirectories. + This is needed for empty directory adding/handling. (Andras) + Currently works only for local directories +*/ +KURL::List QExtFileInfo::allFiles( const KURL& path, const QString& mask) +{ + QExtFileInfo internalFileInfo; + return internalFileInfo.allFilesInternal(path, mask); +} + +KURL::List QExtFileInfo::allFilesRelative( const KURL& path, const QString& mask) +{ + QExtFileInfo internalFileInfo; + KURL::List r = internalFileInfo.allFilesInternal( path, mask); + + KURL::List::Iterator it; + for ( it = r.begin(); it != r.end(); ++it ) + { + *it = QExtFileInfo::toRelative( *it, path ); + } + + return r; +} + +bool QExtFileInfo::createDir( const KURL& path ) +{ + int i=0; + bool result; + KURL dir1, dir2 = KURL(); + while ( !exists(path) && dir2.path() != path.path() ) + { + dir1 = path; + dir2 = path; + + dir1=cdUp(dir1); + while ( !exists(dir1) && dir1.path() != "/" ) + { + dir1=cdUp(dir1); + dir2=cdUp(dir2); + // debug(d1); + } + // dir2.setPath(dir2.path(-1)); + result = KIO::NetAccess::mkdir(dir2, 0L, -1); + i++; + } + result = exists(path); + return result; +} + +KURL QExtFileInfo::cdUp(const KURL &url) +{ + KURL u = url; + QString dir = u.path(-1); + while ( !dir.isEmpty() && dir.right(1) != "/" ) + { + dir.remove( dir.length()-1,1); + } + u.setPath(dir); + return u; +} + +QString QExtFileInfo::shortName(const QString &fname) +{ + return fname.section("/",-1); +} + +KURL QExtFileInfo::path( const KURL &url ) +{ + return KURL( url.directory(false,false) ); +} + +KURL QExtFileInfo::home() +{ + KURL url; + url.setPath(QDir::currentDirPath()+"/"); + return url; +} + + +bool QExtFileInfo::exists(const KURL& a_url) +{ +// Andras: Don't use it now, as it brings up an extra dialog and need manual +// intervention when usign fish +// return KIO::NetAccess::exists(a_url, false); + +// No dialog when stating. + if ( a_url.isLocalFile() ) + { + return QFile::exists( a_url.path() ); + } else + { + QExtFileInfo internalFileInfo; + return internalFileInfo.internalExists(a_url); + } +} + +/* Synchronouse copy, like NetAccess::file_copy in KDE 3.2 */ +bool QExtFileInfo::copy( const KURL& src, const KURL& target, int permissions, + bool overwrite, bool resume, QWidget* window ) +{ + QExtFileInfo internalFileInfo; + return internalFileInfo.internalCopy( src, target, permissions, overwrite, resume, window ); +} + +/** No descriptions */ +KURL::List QExtFileInfo::allFilesInternal(const KURL& startURL, const QString& mask) +{ + dirListItems.clear(); + if (internalExists(startURL)) + { + lstFilters.setAutoDelete(true); + lstFilters.clear(); + // Split on white space + QStringList list = QStringList::split( ' ', mask ); + for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) + lstFilters.append( new QRegExp(*it, false, true ) ); + + bJobOK = true; + KIO::ListJob *job = KIO::listRecursive(startURL, false, true); + connect(job, SIGNAL(entries(KIO::Job *, const KIO::UDSEntryList&)), + this, SLOT(slotNewEntries(KIO::Job *, const KIO::UDSEntryList&))); + connect( job, SIGNAL( result (KIO::Job *) ), + this, SLOT( slotResult (KIO::Job *) ) ); + + // kdDebug(24000) << "Now listing: " << startURL.url() << endl; + enter_loop(); + lstFilters.clear(); + if (!bJobOK) + { + // kdDebug(24000) << "Error while listing "<< startURL.url() << endl; + dirListItems.clear(); + } + } + return dirListItems; +} + + +//Some hackery from KIO::NetAccess as they do not do exactly what we want +/* return true if the url exists*/ +bool QExtFileInfo::internalExists(const KURL& url) +{ + bJobOK = true; + // kdDebug(24000)<<"QExtFileInfo::internalExists"<<endl; + KIO::StatJob * job = KIO::stat( url, false); + job->setDetails(0); + job->setSide(false); //check the url for writing + connect( job, SIGNAL( result (KIO::Job *) ), + this, SLOT( slotResult (KIO::Job *) ) ); + + //To avoid lock-ups, start a timer. + QTimer::singleShot(10*1000, this,SLOT(slotTimeout())); +// kdDebug(24000)<<"QExtFileInfo::internalExists:before enter_loop"<<endl; + enter_loop(); +// kdDebug(24000)<<"QExtFileInfo::internalExists:after enter_loop"<<endl; + return bJobOK; +} + +bool QExtFileInfo::internalCopy(const KURL& src, const KURL& target, int permissions, + bool overwrite, bool resume, QWidget* window) +{ + bJobOK = true; // success unless further error occurs + + KIO::Scheduler::checkSlaveOnHold(true); + KIO::Job * job = KIO::file_copy( src, target, permissions, overwrite, resume ); + job->setWindow (window); + connect( job, SIGNAL( result (KIO::Job *) ), + this, SLOT( slotResult (KIO::Job *) ) ); + + enter_loop(); + return bJobOK; +} + + +void qt_enter_modal( QWidget *widget ); +void qt_leave_modal( QWidget *widget ); + +void QExtFileInfo::enter_loop() +{ + QWidget dummy(0,0,WType_Dialog | WShowModal); + dummy.setFocusPolicy( QWidget::NoFocus ); + qt_enter_modal(&dummy); +// kdDebug(24000)<<"QExtFileInfo::enter_loop:before qApp->enter_loop()"<<endl; + qApp->enter_loop(); +// kdDebug(24000)<<"QExtFileInfo::enter_loop:after qApp->enter_loop()"<<endl; + qt_leave_modal(&dummy); +} + +void QExtFileInfo::slotResult( KIO::Job * job ) +{ + bJobOK = !job->error(); + if ( !bJobOK ) + { + if ( !lastErrorMsg ) + lastErrorMsg = job->errorString(); + } + if ( job->isA("KIO::StatJob") ) + m_entry = static_cast<KIO::StatJob *>(job)->statResult(); + qApp->exit_loop(); +} + +void QExtFileInfo::slotNewEntries(KIO::Job *job, const KIO::UDSEntryList& udsList) +{ + KURL url = static_cast<KIO::ListJob *>(job)->url(); + url.adjustPath(-1); + // avoid creating these QStrings again and again + static const QString& dot = KGlobal::staticQString("."); + static const QString& dotdot = KGlobal::staticQString(".."); + + KIO::UDSEntryListConstIterator it = udsList.begin(); + KIO::UDSEntryListConstIterator end = udsList.end(); + KURL itemURL; + for ( ; it != end; ++it ) + { + QString name; + + // find out about the name + KIO::UDSEntry::ConstIterator entit = (*it).begin(); + for( ; entit != (*it).end(); ++entit ) + if ( (*entit).m_uds == KIO::UDS_NAME ) + { + name = (*entit).m_str; + break; + } + + if ( ! name.isEmpty() && name != dot && name != dotdot) + { + KFileItem* item = new KFileItem( *it, url, false, true ); + itemURL = item->url(); + if (item->isDir()) itemURL.adjustPath(1); + for ( QPtrListIterator<QRegExp> filterIt( lstFilters ); filterIt.current(); ++filterIt ) + if ( filterIt.current()->exactMatch( item->text() ) ) + dirListItems.append(itemURL); + delete item; + } + } +} + +/** Timeout occured while waiting for some network function to return. */ +void QExtFileInfo::slotTimeout() +{ + bJobOK = false; + qApp->exit_loop(); +} +#include "qextfileinfo.moc" diff --git a/kimagemapeditor/qextfileinfo.h b/kimagemapeditor/qextfileinfo.h new file mode 100644 index 00000000..20294bde --- /dev/null +++ b/kimagemapeditor/qextfileinfo.h @@ -0,0 +1,75 @@ +/* + From WebMaker - KDE HTML Editor + Copyright (C) 1998, 1999 Alexei Dets <[email protected]> + Rewritten for Quanta Plus: (C) 2002 Andras Mantia <[email protected]> + + 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 _QEXTFILEINFO_H_ +#define _QEXTFILEINFO_H_ + +#include <kio/global.h> +#include <kio/job.h> +#include <kurl.h> +#include <kfileitem.h> + +#include <qobject.h> +#include <qptrlist.h> +#include <qregexp.h> + +class QExtFileInfo:public QObject +{ + Q_OBJECT +public: + QExtFileInfo() {}; + ~QExtFileInfo() {}; + + /** create to ralative short name */ + static KURL toRelative(const KURL& urlToConvert,const KURL& baseURL); + /** convert relative filename to absolute */ + static KURL toAbsolute(const KURL& urlToConvert,const KURL& baseURL); + /** recurse function for all files in dir */ + static KURL::List allFiles( const KURL& path, const QString &mask); + static KURL::List allFilesRelative( const KURL& path, const QString &mask); + /** create dir if don't exists */ + static bool createDir(const KURL & path ); + static KURL cdUp(const KURL &dir); + static QString shortName(const QString &fname ); + static KURL path(const KURL &); + static KURL home(); + static bool exists(const KURL& url); + static bool copy( const KURL& src, const KURL& dest, int permissions=-1, + bool overwrite=false, bool resume=false, QWidget* window = 0L ); + + void enter_loop(); + +private: + bool internalExists(const KURL& url); + bool internalCopy(const KURL& src, const KURL& target, int permissions, + bool overwrite, bool resume, QWidget* window); + + bool bJobOK; + static QString lastErrorMsg; + KIO::UDSEntry m_entry; + KURL::List dirListItems; + QPtrList<QRegExp> lstFilters; + + /** No descriptions */ + KURL::List allFilesInternal(const KURL& startURL, const QString& mask); + +// friend class I_like_this_class; + +private slots: + void slotResult( KIO::Job * job ); + void slotNewEntries(KIO::Job *job, const KIO::UDSEntryList& udsList); +public slots: // Public slots + /** Timeout occured while waiting for some network function to return. */ + void slotTimeout(); +}; + + +#endif |