commit 5de3dd4762ca33a0f92e79ffa4fe2ff67069d531 Author: tpearson Date: Wed Feb 24 01:49:02 2010 +0000 Added KDE3 version of ktechlab git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/ktechlab@1095338 283d02a7-25f6-0310-bc7c-ecb5cbfe19da diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..93eb7fb --- /dev/null +++ b/AUTHORS @@ -0,0 +1,2 @@ +David Saxton +Daniel Clarke diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..ffe677b --- /dev/null +++ b/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..6f407f3 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,56 @@ +New or improved components: +* Transistors (NPN and PNP). +* Inductor. +* Ideal opamp. +* Rotary switch. +* Bus connection. +* Matrix display and driver. +* Magnitude comparator. +* Voltage and current probes for oscilloscope. +* Simulated bouncing for switches. +* Serial and parallel port components (interface with computer hardware). + +Project Management: +* Complete rewrite... +* Support for building targets, with processing and linking options. + +FlowCode / Microbe: +* Can read from keypads and display on seven segment displays. +* Add warning for floating connections in FlowCode. +* Generated assembly is now heavily optimized. + +Debugging: +* High level language support (SDCC, Microbe). +* Mouse-over variable inspection. +* Symbol Viewer. + +Optimization: +* Cache simulation data for circuits with discrete set of inputs (and no + reactive components). +* Speed up calculation of diode operating point. +* Optimized mixed logic and non-logic simulation. +* Optimized recording of boolean data from logic probes. + +Interface: +* Translations into French, Spanish and Italian. +* Replaced KMDI with KateMDI (toolviews remember sizes, lots of other + improvements). +* Modularised GUI - menus and toolbars are hidden / shown as appropriate for + the document being edited. +* Toolbar item editor is now squashable. +* Lots of icon improvements. + +Polishing: +* Removed flicker when resizing the work area. +* Remember cursor position in text documents on save / restore. +* Removed flicker when joining / splitting connectors. +* Save undo / redo state after editing data. +* Remember connection routing selection. +* Try and retain upwards position of text when rotating / reflecting components. +* Editing of real numbers now always uses three significant figures. +* Give LEDs a nice selection of predefined LED colours. + +Miscellaneous Features: +* PIC program uploading (via the use of external programs). +* Allow changing of the z-ordering of items. +* Added support for gpsim-0.21.11 and gpsim-0.21.12. diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..02a4a07 --- /dev/null +++ b/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/Makefile.am b/Makefile.am new file mode 100644 index 0000000..b74d98c --- /dev/null +++ b/Makefile.am @@ -0,0 +1,5 @@ +AUTOMAKE_OPTIONS = foreign 1.5 + +include admin/deps.am + +SUBDIRS=$(TOPSUBDIRS) diff --git a/Makefile.cvs b/Makefile.cvs new file mode 100644 index 0000000..4c0afd1 --- /dev/null +++ b/Makefile.cvs @@ -0,0 +1,10 @@ +all: + @echo "This Makefile is only for the CVS repository" + @echo "This will be deleted before making the distribution" + @echo "" + $(MAKE) -f admin/Makefile.common cvs + +dist: + $(MAKE) -f admin/Makefile.common dist + +.SILENT: diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/README b/README new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/README @@ -0,0 +1 @@ + diff --git a/TODO b/TODO new file mode 100644 index 0000000..ccca9ec --- /dev/null +++ b/TODO @@ -0,0 +1,49 @@ +0.4 targets: +* Replace QCanvas with own optimized implementation. +* "Tutorial" tool (e.g. for learning about electronic circuits and PICs) tailored to education. +* Only use IDs for items, etc, in ItemDocumentData - otherwise they lead to too many bugs. +* More intelligent connector routing. +* Variable time step in Simulation. +* Improved ItemEditor (free scaling preview buttons, moved buttons around, toolbar needs work, etc). +* Remove insert / duplicate functionality for ViewContainers, and replace it with concept of empty panes. +* Fix subcircuits so that they are saved in an itemdocument. +* Fully i18n'izable (e.g. see string lists bug below, some buttons too big with non-english text, etc). +* Full complement of basic electronic devices (e.g. mosfet, jfet). +* Debugging support for FlowCode. + +New components: +* ALU components (shifters, multipliers) +* Displays: double-digit LCD display +* Audio: buzzers, speakers. +* Different types of signals (e.g. square, triangular) for current and voltage signal components. + +Bugs: +* At the moment, KTechlab auto-detects a point in the circuit to use as ground, according to a set of priorities (e.g. the Ground component has the highest priority, then voltage elements, etc etc). However, some circuits do not have any point which should be considered ground, e.g. "(+9V)-------(Battery)". Suggested solution: detect a point to have as a fixed voltage, that can be anything including 0V. +* Some string lists for item properties are not i18n-safe. Scaling {Linear, Logarithmic}; Polarity {Row Cathode, Column Cathode } / {Common Cathode, Common Anode}; Edge {Rising, Falling}; Unary Operation {Rotate Left, Rotate Right, Increment, Decremement} +* Microbe should give "noline" where applicable in show-source (such as in delay routines). + +Features: +* Bookmarks in the oscilloscope. +* Draw an outline of the component / flowpart / etc being dragged from the list on the left to show where it will be placed. This will probably involve adding static functions to all Item subclasses that will do the drawing, and returning a pointer to the function in the LibraryItem the subclass returns. +* Allow inserting a component into a wire, so that the wire is broken in two with the component connecting at either end. +* Some intelligent connect tool that will connect up pins between components - e.g. if the pins are dragged over each other, or horizontaly next to each other. +* Work area text: allow clickable URIs, rich text editor. +* Indicate the direction of current flow in a wire when hovering the mouse over. +* Allow editing of embedded code in the FlowCode element in a TextView, instead of a popup dialog. +* Be able to "shake" an item to get rid of attached connectors. +* Allow creating a flowcontainer by dragging a rectangle. +* Templates for different file types (making use of the microcontroller selected). +* "Show All" zoom action (zooms in / out to a level that shows everything in the work area). + +General TODO: +* Finish serial and parallel port components. +* optimize microbe some more? + +Polishing: +* Make sure that when context help refers to "advanced" variables (i.e. only editable from the Item Editor tab), it makes clear how to edit them. +* Informational message when user attempts to paste flowcode into a circuit (can't do so; must save and load into pic). +* On program startup, use "text blobs" pointing to sidebars to explain what they do. +* Update register info even when PIC is paused. +* Move the "merge" button to individual property entries. +* replace "refresh rate" slider in settings dialog with standard one. +* flicker of bottom horizontal scrollbar when initially moving a component downwards from having no vertical scrollbar to having one. diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 0000000..ff08dec --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,11630 @@ +## -*- autoconf -*- + +dnl This file is part of the KDE libraries/packages +dnl Copyright (C) 1997 Janos Farkas (chexum@shadow.banki.hu) +dnl (C) 1997,98,99 Stephan Kulow (coolo@kde.org) + +dnl This file is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Library General Public +dnl License as published by the Free Software Foundation; either +dnl version 2 of the License, or (at your option) any later version. + +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Library General Public License for more details. + +dnl You should have received a copy of the GNU Library General Public License +dnl along with this library; see the file COPYING.LIB. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +dnl Boston, MA 02110-1301, USA. + +dnl IMPORTANT NOTE: +dnl Please do not modify this file unless you expect your modifications to be +dnl carried into every other module in the repository. +dnl +dnl Single-module modifications are best placed in configure.in for kdelibs +dnl and kdebase or configure.in.in if present. + +# KDE_PATH_X_DIRECT +dnl Internal subroutine of AC_PATH_X. +dnl Set ac_x_includes and/or ac_x_libraries. +AC_DEFUN([KDE_PATH_X_DIRECT], +[ +AC_REQUIRE([KDE_CHECK_LIB64]) + +if test "$ac_x_includes" = NO; then + # Guess where to find include files, by looking for this one X11 .h file. + test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h + + # First, try using that file with no special directory specified. +AC_TRY_CPP([#include <$x_direct_test_include>], +[# We can compile using X headers with no special include directory. +ac_x_includes=], +[# Look for the header file in a standard set of common directories. +# Check X11 before X11Rn because it is often a symlink to the current release. + for ac_dir in \ + /usr/X11/include \ + /usr/X11R6/include \ + /usr/X11R5/include \ + /usr/X11R4/include \ + \ + /usr/include/X11 \ + /usr/include/X11R6 \ + /usr/include/X11R5 \ + /usr/include/X11R4 \ + \ + /usr/local/X11/include \ + /usr/local/X11R6/include \ + /usr/local/X11R5/include \ + /usr/local/X11R4/include \ + \ + /usr/local/include/X11 \ + /usr/local/include/X11R6 \ + /usr/local/include/X11R5 \ + /usr/local/include/X11R4 \ + \ + /usr/X386/include \ + /usr/x386/include \ + /usr/XFree86/include/X11 \ + \ + /usr/include \ + /usr/local/include \ + /usr/unsupported/include \ + /usr/athena/include \ + /usr/local/x11r5/include \ + /usr/lpp/Xamples/include \ + \ + /usr/openwin/include \ + /usr/openwin/share/include \ + ; \ + do + if test -r "$ac_dir/$x_direct_test_include"; then + ac_x_includes=$ac_dir + break + fi + done]) +fi # $ac_x_includes = NO + +if test "$ac_x_libraries" = NO; then + # Check for the libraries. + + test -z "$x_direct_test_library" && x_direct_test_library=Xt + test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc + + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS="$LIBS" + LIBS="-l$x_direct_test_library $LIBS" +AC_TRY_LINK([#include ], [${x_direct_test_function}(1)], +[LIBS="$ac_save_LIBS" +# We can link X programs with no special library path. +ac_x_libraries=], +[LIBS="$ac_save_LIBS" +# First see if replacing the include by lib works. +# Check X11 before X11Rn because it is often a symlink to the current release. +for ac_dir in `echo "$ac_x_includes" | sed s/include/lib${kdelibsuff}/` \ + /usr/X11/lib${kdelibsuff} \ + /usr/X11R6/lib${kdelibsuff} \ + /usr/X11R5/lib${kdelibsuff} \ + /usr/X11R4/lib${kdelibsuff} \ + \ + /usr/lib${kdelibsuff}/X11 \ + /usr/lib${kdelibsuff}/X11R6 \ + /usr/lib${kdelibsuff}/X11R5 \ + /usr/lib${kdelibsuff}/X11R4 \ + \ + /usr/local/X11/lib${kdelibsuff} \ + /usr/local/X11R6/lib${kdelibsuff} \ + /usr/local/X11R5/lib${kdelibsuff} \ + /usr/local/X11R4/lib${kdelibsuff} \ + \ + /usr/local/lib${kdelibsuff}/X11 \ + /usr/local/lib${kdelibsuff}/X11R6 \ + /usr/local/lib${kdelibsuff}/X11R5 \ + /usr/local/lib${kdelibsuff}/X11R4 \ + \ + /usr/X386/lib${kdelibsuff} \ + /usr/x386/lib${kdelibsuff} \ + /usr/XFree86/lib${kdelibsuff}/X11 \ + \ + /usr/lib${kdelibsuff} \ + /usr/local/lib${kdelibsuff} \ + /usr/unsupported/lib${kdelibsuff} \ + /usr/athena/lib${kdelibsuff} \ + /usr/local/x11r5/lib${kdelibsuff} \ + /usr/lpp/Xamples/lib${kdelibsuff} \ + /lib/usr/lib${kdelibsuff}/X11 \ + \ + /usr/openwin/lib${kdelibsuff} \ + /usr/openwin/share/lib${kdelibsuff} \ + ; \ +do +dnl Don't even attempt the hair of trying to link an X program! + for ac_extension in a so sl; do + if test -r $ac_dir/lib${x_direct_test_library}.$ac_extension; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done]) +fi # $ac_x_libraries = NO +]) + + +dnl ------------------------------------------------------------------------ +dnl Find a file (or one of more files in a list of dirs) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_FIND_FILE], +[ +$3=NO +for i in $2; +do + for j in $1; + do + echo "configure: __oline__: $i/$j" >&AC_FD_CC + if test -r "$i/$j"; then + echo "taking that" >&AC_FD_CC + $3=$i + break 2 + fi + done +done +]) + +dnl KDE_FIND_PATH(program-name, variable-name, list-of-dirs, +dnl if-not-found, test-parameter, prepend-path) +dnl +dnl Look for program-name in list-of-dirs+$PATH. +dnl If prepend-path is set, look in $PATH+list-of-dirs instead. +dnl If found, $variable-name is set. If not, if-not-found is evaluated. +dnl test-parameter: if set, the program is executed with this arg, +dnl and only a successful exit code is required. +AC_DEFUN([KDE_FIND_PATH], +[ + AC_MSG_CHECKING([for $1]) + if test -n "$$2"; then + kde_cv_path="$$2"; + else + kde_cache=`echo $1 | sed 'y%./+-%__p_%'` + + AC_CACHE_VAL(kde_cv_path_$kde_cache, + [ + kde_cv_path="NONE" + kde_save_IFS=$IFS + IFS=':' + dirs="" + for dir in $PATH; do + dirs="$dirs $dir" + done + if test -z "$6"; then dnl Append dirs in PATH (default) + dirs="$3 $dirs" + else dnl Prepend dirs in PATH (if 6th arg is set) + dirs="$dirs $3" + fi + IFS=$kde_save_IFS + + for dir in $dirs; do + if test -x "$dir/$1"; then + if test -n "$5" + then + evalstr="$dir/$1 $5 2>&1 " + if eval $evalstr; then + kde_cv_path="$dir/$1" + break + fi + else + kde_cv_path="$dir/$1" + break + fi + fi + done + + eval "kde_cv_path_$kde_cache=$kde_cv_path" + + ]) + + eval "kde_cv_path=\"`echo '$kde_cv_path_'$kde_cache`\"" + + fi + + if test -z "$kde_cv_path" || test "$kde_cv_path" = NONE; then + AC_MSG_RESULT(not found) + $4 + else + AC_MSG_RESULT($kde_cv_path) + $2=$kde_cv_path + + fi +]) + +AC_DEFUN([KDE_MOC_ERROR_MESSAGE], +[ + AC_MSG_ERROR([No Qt meta object compiler (moc) found! +Please check whether you installed Qt correctly. +You need to have a running moc binary. +configure tried to run $ac_cv_path_moc and the test didn't +succeed. If configure shouldn't have tried this one, set +the environment variable MOC to the right one before running +configure. +]) +]) + +AC_DEFUN([KDE_UIC_ERROR_MESSAGE], +[ + AC_MSG_WARN([No Qt ui compiler (uic) found! +Please check whether you installed Qt correctly. +You need to have a running uic binary. +configure tried to run $ac_cv_path_uic and the test didn't +succeed. If configure shouldn't have tried this one, set +the environment variable UIC to the right one before running +configure. +]) +]) + + +AC_DEFUN([KDE_CHECK_UIC_FLAG], +[ + AC_MSG_CHECKING([whether uic supports -$1 ]) + kde_cache=`echo $1 | sed 'y% .=/+-%____p_%'` + AC_CACHE_VAL(kde_cv_prog_uic_$kde_cache, + [ + cat >conftest.ui < +EOT + ac_uic_testrun="$UIC_PATH -$1 $2 conftest.ui >/dev/null" + if AC_TRY_EVAL(ac_uic_testrun); then + eval "kde_cv_prog_uic_$kde_cache=yes" + else + eval "kde_cv_prog_uic_$kde_cache=no" + fi + rm -f conftest* + ]) + + if eval "test \"`echo '$kde_cv_prog_uic_'$kde_cache`\" = yes"; then + AC_MSG_RESULT([yes]) + : + $3 + else + AC_MSG_RESULT([no]) + : + $4 + fi +]) + + +dnl ------------------------------------------------------------------------ +dnl Find the meta object compiler and the ui compiler in the PATH, +dnl in $QTDIR/bin, and some more usual places +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_PATH_QT_MOC_UIC], +[ + AC_REQUIRE([KDE_CHECK_PERL]) + qt_bindirs="" + for dir in $kde_qt_dirs; do + qt_bindirs="$qt_bindirs $dir/bin $dir/src/moc" + done + qt_bindirs="$qt_bindirs /usr/bin /usr/X11R6/bin /usr/local/qt/bin" + if test ! "$ac_qt_bindir" = "NO"; then + qt_bindirs="$ac_qt_bindir $qt_bindirs" + fi + + KDE_FIND_PATH(moc, MOC, [$qt_bindirs], [KDE_MOC_ERROR_MESSAGE]) + if test -z "$UIC_NOT_NEEDED"; then + KDE_FIND_PATH(uic, UIC_PATH, [$qt_bindirs], [UIC_PATH=""]) + if test -z "$UIC_PATH" ; then + KDE_UIC_ERROR_MESSAGE + exit 1 + else + UIC=$UIC_PATH + + if test $kde_qtver = 3; then + KDE_CHECK_UIC_FLAG(L,[/nonexistent],ac_uic_supports_libpath=yes,ac_uic_supports_libpath=no) + KDE_CHECK_UIC_FLAG(nounload,,ac_uic_supports_nounload=yes,ac_uic_supports_nounload=no) + + if test x$ac_uic_supports_libpath = xyes; then + UIC="$UIC -L \$(kde_widgetdir)" + fi + if test x$ac_uic_supports_nounload = xyes; then + UIC="$UIC -nounload" + fi + fi + fi + else + UIC="echo uic not available: " + fi + + AC_SUBST(MOC) + AC_SUBST(UIC) + + UIC_TR="i18n" + if test $kde_qtver = 3; then + UIC_TR="tr2i18n" + fi + + AC_SUBST(UIC_TR) +]) + +AC_DEFUN([KDE_1_CHECK_PATHS], +[ + KDE_1_CHECK_PATH_HEADERS + + KDE_TEST_RPATH= + + if test -n "$USE_RPATH"; then + + if test -n "$kde_libraries"; then + KDE_TEST_RPATH="-R $kde_libraries" + fi + + if test -n "$qt_libraries"; then + KDE_TEST_RPATH="$KDE_TEST_RPATH -R $qt_libraries" + fi + + if test -n "$x_libraries"; then + KDE_TEST_RPATH="$KDE_TEST_RPATH -R $x_libraries" + fi + + KDE_TEST_RPATH="$KDE_TEST_RPATH $KDE_EXTRA_RPATH" + fi + +AC_MSG_CHECKING([for KDE libraries installed]) +ac_link='$LIBTOOL_SHELL --silent --mode=link ${CXX-g++} -o conftest $CXXFLAGS $all_includes $CPPFLAGS $LDFLAGS $all_libraries conftest.$ac_ext $LIBS -lkdecore $LIBQT $KDE_TEST_RPATH 1>&5' + +if AC_TRY_EVAL(ac_link) && test -s conftest; then + AC_MSG_RESULT(yes) +else + AC_MSG_ERROR([your system fails at linking a small KDE application! +Check, if your compiler is installed correctly and if you have used the +same compiler to compile Qt and kdelibs as you did use now. +For more details about this problem, look at the end of config.log.]) +fi + +if eval `KDEDIR= ./conftest 2>&5`; then + kde_result=done +else + kde_result=problems +fi + +KDEDIR= ./conftest 2> /dev/null >&5 # make an echo for config.log +kde_have_all_paths=yes + +KDE_SET_PATHS($kde_result) + +]) + +AC_DEFUN([KDE_SET_PATHS], +[ + kde_cv_all_paths="kde_have_all_paths=\"yes\" \ + kde_htmldir=\"$kde_htmldir\" \ + kde_appsdir=\"$kde_appsdir\" \ + kde_icondir=\"$kde_icondir\" \ + kde_sounddir=\"$kde_sounddir\" \ + kde_datadir=\"$kde_datadir\" \ + kde_locale=\"$kde_locale\" \ + kde_cgidir=\"$kde_cgidir\" \ + kde_confdir=\"$kde_confdir\" \ + kde_kcfgdir=\"$kde_kcfgdir\" \ + kde_mimedir=\"$kde_mimedir\" \ + kde_toolbardir=\"$kde_toolbardir\" \ + kde_wallpaperdir=\"$kde_wallpaperdir\" \ + kde_templatesdir=\"$kde_templatesdir\" \ + kde_bindir=\"$kde_bindir\" \ + kde_servicesdir=\"$kde_servicesdir\" \ + kde_servicetypesdir=\"$kde_servicetypesdir\" \ + kde_moduledir=\"$kde_moduledir\" \ + kde_styledir=\"$kde_styledir\" \ + kde_widgetdir=\"$kde_widgetdir\" \ + xdg_appsdir=\"$xdg_appsdir\" \ + xdg_menudir=\"$xdg_menudir\" \ + xdg_directorydir=\"$xdg_directorydir\" \ + kde_result=$1" +]) + +AC_DEFUN([KDE_SET_DEFAULT_PATHS], +[ +if test "$1" = "default"; then + + if test -z "$kde_htmldir"; then + if test -f /etc/debian_version; then + if dpkg -s kdelibs4 | grep Status | grep not-installed 2>&1 >/dev/null; then + kde_htmldir='\${prefix}/share/doc/HTML'; + else + kde_htmldir='\${prefix}/share/doc/kde/HTML' + fi + else + kde_htmldir='\${prefix}/share/doc/HTML' + fi + fi + + if test -z "$kde_appsdir"; then + kde_appsdir='\${datadir}/applnk' + fi + if test -z "$kde_icondir"; then + kde_icondir='\${datadir}/icons' + fi + if test -z "$kde_sounddir"; then + kde_sounddir='\${datadir}/sounds' + fi + if test -z "$kde_datadir"; then + kde_datadir='\${datadir}/apps' + fi + if test -z "$kde_locale"; then + kde_locale='\${datadir}/locale' + fi + if test -z "$kde_cgidir"; then + kde_cgidir='\${exec_prefix}/cgi-bin' + fi + if test -z "$kde_confdir"; then + kde_confdir='\${datadir}/config' + fi + if test -z "$kde_kcfgdir"; then + kde_kcfgdir='\${datadir}/config.kcfg' + fi + if test -z "$kde_mimedir"; then + kde_mimedir='\${datadir}/mimelnk' + fi + if test -z "$kde_toolbardir"; then + kde_toolbardir='\${datadir}/toolbar' + fi + if test -z "$kde_wallpaperdir"; then + kde_wallpaperdir='\${datadir}/wallpapers' + fi + if test -z "$kde_templatesdir"; then + kde_templatesdir='\${datadir}/templates' + fi + if test -z "$kde_bindir"; then + kde_bindir='\${exec_prefix}/bin' + fi + if test -z "$kde_servicesdir"; then + kde_servicesdir='\${datadir}/services' + fi + if test -z "$kde_servicetypesdir"; then + kde_servicetypesdir='\${datadir}/servicetypes' + fi + if test -z "$kde_moduledir"; then + if test "$kde_qtver" = "2"; then + kde_moduledir='\${libdir}/kde2' + else + kde_moduledir='\${libdir}/kde3' + fi + fi + if test -z "$kde_styledir"; then + kde_styledir='\${libdir}/kde3/plugins/styles' + fi + if test -z "$kde_widgetdir"; then + kde_widgetdir='\${libdir}/kde3/plugins/designer' + fi + if test -z "$xdg_appsdir"; then + xdg_appsdir='\${datadir}/applications/kde' + fi + if test -z "$xdg_menudir"; then + xdg_menudir='\${sysconfdir}/xdg/menus' + fi + if test -z "$xdg_directorydir"; then + xdg_directorydir='\${datadir}/desktop-directories' + fi + + KDE_SET_PATHS(defaults) + +else + + if test $kde_qtver = 1; then + AC_MSG_RESULT([compiling]) + KDE_1_CHECK_PATHS + else + AC_MSG_ERROR([path checking not yet supported for KDE 2]) + fi + +fi +]) + +AC_DEFUN([KDE_CHECK_PATHS_FOR_COMPLETENESS], +[ if test -z "$kde_htmldir" || test -z "$kde_appsdir" || + test -z "$kde_icondir" || test -z "$kde_sounddir" || + test -z "$kde_datadir" || test -z "$kde_locale" || + test -z "$kde_cgidir" || test -z "$kde_confdir" || + test -z "$kde_kcfgdir" || + test -z "$kde_mimedir" || test -z "$kde_toolbardir" || + test -z "$kde_wallpaperdir" || test -z "$kde_templatesdir" || + test -z "$kde_bindir" || test -z "$kde_servicesdir" || + test -z "$kde_servicetypesdir" || test -z "$kde_moduledir" || + test -z "$kde_styledir" || test -z "kde_widgetdir" || + test -z "$xdg_appsdir" || test -z "$xdg_menudir" || test -z "$xdg_directorydir" || + test "x$kde_have_all_paths" != "xyes"; then + kde_have_all_paths=no + fi +]) + +AC_DEFUN([KDE_MISSING_PROG_ERROR], +[ + AC_MSG_ERROR([The important program $1 was not found! +Please check whether you installed KDE correctly. +]) +]) + +AC_DEFUN([KDE_MISSING_ARTS_ERROR], +[ + AC_MSG_ERROR([The important program $1 was not found! +Please check whether you installed aRts correctly or use +--without-arts to compile without aRts support (this will remove functionality). +]) +]) + +AC_DEFUN([KDE_SET_DEFAULT_BINDIRS], +[ + kde_default_bindirs="/usr/bin /usr/local/bin /opt/local/bin /usr/X11R6/bin /opt/kde/bin /opt/kde3/bin /usr/kde/bin /usr/local/kde/bin" + test -n "$KDEDIR" && kde_default_bindirs="$KDEDIR/bin $kde_default_bindirs" + if test -n "$KDEDIRS"; then + kde_save_IFS=$IFS + IFS=: + for dir in $KDEDIRS; do + kde_default_bindirs="$dir/bin $kde_default_bindirs " + done + IFS=$kde_save_IFS + fi +]) + +AC_DEFUN([KDE_SUBST_PROGRAMS], +[ + AC_ARG_WITH(arts, + AC_HELP_STRING([--without-arts],[build without aRts [default=no]]), + [build_arts=$withval], + [build_arts=yes] + ) + AM_CONDITIONAL(include_ARTS, test "$build_arts" '!=' "no") + if test "$build_arts" = "no"; then + AC_DEFINE(WITHOUT_ARTS, 1, [Defined if compiling without arts]) + fi + + KDE_SET_DEFAULT_BINDIRS + kde_default_bindirs="$exec_prefix/bin $prefix/bin $kde_libs_prefix/bin $kde_default_bindirs" + KDE_FIND_PATH(dcopidl, DCOPIDL, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(dcopidl)]) + KDE_FIND_PATH(dcopidl2cpp, DCOPIDL2CPP, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(dcopidl2cpp)]) + if test "$build_arts" '!=' "no"; then + KDE_FIND_PATH(mcopidl, MCOPIDL, [$kde_default_bindirs], [KDE_MISSING_ARTS_ERROR(mcopidl)]) + KDE_FIND_PATH(artsc-config, ARTSCCONFIG, [$kde_default_bindirs], [KDE_MISSING_ARTS_ERROR(artsc-config)]) + fi + KDE_FIND_PATH(meinproc, MEINPROC, [$kde_default_bindirs]) + + kde32ornewer=1 + kde33ornewer=1 + if test -n "$kde_qtver" && test "$kde_qtver" -lt 3; then + kde32ornewer= + kde33ornewer= + else + if test "$kde_qtver" = "3"; then + if test "$kde_qtsubver" -le 1; then + kde32ornewer= + fi + if test "$kde_qtsubver" -le 2; then + kde33ornewer= + fi + fi + fi + + if test -n "$kde32ornewer"; then + KDE_FIND_PATH(kconfig_compiler, KCONFIG_COMPILER, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(kconfig_compiler)]) + KDE_FIND_PATH(dcopidlng, DCOPIDLNG, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(dcopidlng)]) + fi + if test -n "$kde33ornewer"; then + KDE_FIND_PATH(makekdewidgets, MAKEKDEWIDGETS, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(makekdewidgets)]) + AC_SUBST(MAKEKDEWIDGETS) + fi + KDE_FIND_PATH(xmllint, XMLLINT, [${prefix}/bin ${exec_prefix}/bin], [XMLLINT=""]) + + if test -n "$MEINPROC" && test ! "$MEINPROC" = "compiled"; then + kde_sharedirs="/usr/share/kde /usr/local/share /usr/share /opt/kde3/share /opt/kde/share $prefix/share" + test -n "$KDEDIR" && kde_sharedirs="$KDEDIR/share $kde_sharedirs" + AC_FIND_FILE(apps/ksgmltools2/customization/kde-chunk.xsl, $kde_sharedirs, KDE_XSL_STYLESHEET) + if test "$KDE_XSL_STYLESHEET" = "NO"; then + KDE_XSL_STYLESHEET="" + else + KDE_XSL_STYLESHEET="$KDE_XSL_STYLESHEET/apps/ksgmltools2/customization/kde-chunk.xsl" + fi + fi + + DCOP_DEPENDENCIES='$(DCOPIDL)' + if test -n "$kde32ornewer"; then + KCFG_DEPENDENCIES='$(KCONFIG_COMPILER)' + DCOP_DEPENDENCIES='$(DCOPIDL) $(DCOPIDLNG)' + AC_SUBST(KCONFIG_COMPILER) + AC_SUBST(KCFG_DEPENDENCIES) + AC_SUBST(DCOPIDLNG) + fi + AC_SUBST(DCOPIDL) + AC_SUBST(DCOPIDL2CPP) + AC_SUBST(DCOP_DEPENDENCIES) + AC_SUBST(MCOPIDL) + AC_SUBST(ARTSCCONFIG) + AC_SUBST(MEINPROC) + AC_SUBST(KDE_XSL_STYLESHEET) + AC_SUBST(XMLLINT) +])dnl + +AC_DEFUN([AC_CREATE_KFSSTND], +[ +AC_REQUIRE([AC_CHECK_RPATH]) + +AC_MSG_CHECKING([for KDE paths]) +kde_result="" +kde_cached_paths=yes +AC_CACHE_VAL(kde_cv_all_paths, +[ + KDE_SET_DEFAULT_PATHS($1) + kde_cached_paths=no +]) +eval "$kde_cv_all_paths" +KDE_CHECK_PATHS_FOR_COMPLETENESS +if test "$kde_have_all_paths" = "no" && test "$kde_cached_paths" = "yes"; then + # wrong values were cached, may be, we can set better ones + kde_result= + kde_htmldir= kde_appsdir= kde_icondir= kde_sounddir= + kde_datadir= kde_locale= kde_cgidir= kde_confdir= kde_kcfgdir= + kde_mimedir= kde_toolbardir= kde_wallpaperdir= kde_templatesdir= + kde_bindir= kde_servicesdir= kde_servicetypesdir= kde_moduledir= + kde_have_all_paths= + kde_styledir= + kde_widgetdir= + xdg_appsdir = xdg_menudir= xdg_directorydir= + KDE_SET_DEFAULT_PATHS($1) + eval "$kde_cv_all_paths" + KDE_CHECK_PATHS_FOR_COMPLETENESS + kde_result="$kde_result (cache overridden)" +fi +if test "$kde_have_all_paths" = "no"; then + AC_MSG_ERROR([configure could not run a little KDE program to test the environment. +Since it had compiled and linked before, it must be a strange problem on your system. +Look at config.log for details. If you are not able to fix this, look at +http://www.kde.org/faq/installation.html or any www.kde.org mirror. +(If you're using an egcs version on Linux, you may update binutils!) +]) +else + rm -f conftest* + AC_MSG_RESULT($kde_result) +fi + +bindir=$kde_bindir + +KDE_SUBST_PROGRAMS + +]) + +AC_DEFUN([AC_SUBST_KFSSTND], +[ +AC_SUBST(kde_htmldir) +AC_SUBST(kde_appsdir) +AC_SUBST(kde_icondir) +AC_SUBST(kde_sounddir) +AC_SUBST(kde_datadir) +AC_SUBST(kde_locale) +AC_SUBST(kde_confdir) +AC_SUBST(kde_kcfgdir) +AC_SUBST(kde_mimedir) +AC_SUBST(kde_wallpaperdir) +AC_SUBST(kde_bindir) +dnl X Desktop Group standards +AC_SUBST(xdg_appsdir) +AC_SUBST(xdg_menudir) +AC_SUBST(xdg_directorydir) +dnl for KDE 2 +AC_SUBST(kde_templatesdir) +AC_SUBST(kde_servicesdir) +AC_SUBST(kde_servicetypesdir) +AC_SUBST(kde_moduledir) +AC_SUBST(kdeinitdir, '$(kde_moduledir)') +AC_SUBST(kde_styledir) +AC_SUBST(kde_widgetdir) +if test "$kde_qtver" = 1; then + kde_minidir="$kde_icondir/mini" +else +# for KDE 1 - this breaks KDE2 apps using minidir, but +# that's the plan ;-/ + kde_minidir="/dev/null" +fi +dnl AC_SUBST(kde_minidir) +dnl AC_SUBST(kde_cgidir) +dnl AC_SUBST(kde_toolbardir) +]) + +AC_DEFUN([KDE_MISC_TESTS], +[ + dnl Checks for libraries. + AC_CHECK_LIB(util, main, [LIBUTIL="-lutil"]) dnl for *BSD + AC_SUBST(LIBUTIL) + AC_CHECK_LIB(compat, main, [LIBCOMPAT="-lcompat"]) dnl for *BSD + AC_SUBST(LIBCOMPAT) + kde_have_crypt= + AC_CHECK_LIB(crypt, crypt, [LIBCRYPT="-lcrypt"; kde_have_crypt=yes], + AC_CHECK_LIB(c, crypt, [kde_have_crypt=yes], [ + AC_MSG_WARN([you have no crypt in either libcrypt or libc. +You should install libcrypt from another source or configure with PAM +support]) + kde_have_crypt=no + ])) + AC_SUBST(LIBCRYPT) + if test $kde_have_crypt = yes; then + AC_DEFINE_UNQUOTED(HAVE_CRYPT, 1, [Defines if your system has the crypt function]) + fi + AC_CHECK_SOCKLEN_T + AC_CHECK_LIB(dnet, dnet_ntoa, [X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet"]) + if test $ac_cv_lib_dnet_dnet_ntoa = no; then + AC_CHECK_LIB(dnet_stub, dnet_ntoa, + [X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub"]) + fi + AC_CHECK_FUNC(inet_ntoa) + if test $ac_cv_func_inet_ntoa = no; then + AC_CHECK_LIB(nsl, inet_ntoa, X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl") + fi + AC_CHECK_FUNC(connect) + if test $ac_cv_func_connect = no; then + AC_CHECK_LIB(socket, connect, X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS", , + $X_EXTRA_LIBS) + fi + + AC_CHECK_FUNC(remove) + if test $ac_cv_func_remove = no; then + AC_CHECK_LIB(posix, remove, X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix") + fi + + # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. + AC_CHECK_FUNC(shmat, , + AC_CHECK_LIB(ipc, shmat, X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc")) + + # more headers that need to be explicitly included on darwin + AC_CHECK_HEADERS(sys/types.h stdint.h) + + # sys/bitypes.h is needed for uint32_t and friends on Tru64 + AC_CHECK_HEADERS(sys/bitypes.h) + + # darwin requires a poll emulation library + AC_CHECK_LIB(poll, poll, LIB_POLL="-lpoll") + + # for some image handling on Mac OS X + AC_CHECK_HEADERS(Carbon/Carbon.h) + + # CoreAudio framework + AC_CHECK_HEADER(CoreAudio/CoreAudio.h, [ + AC_DEFINE(HAVE_COREAUDIO, 1, [Define if you have the CoreAudio API]) + FRAMEWORK_COREAUDIO="-Xlinker -framework -Xlinker CoreAudio" + ]) + + AC_CHECK_RES_INIT + AC_SUBST(LIB_POLL) + AC_SUBST(FRAMEWORK_COREAUDIO) + LIBSOCKET="$X_EXTRA_LIBS" + AC_SUBST(LIBSOCKET) + AC_SUBST(X_EXTRA_LIBS) + AC_CHECK_LIB(ucb, killpg, [LIBUCB="-lucb"]) dnl for Solaris2.4 + AC_SUBST(LIBUCB) + + case $host in dnl this *is* LynxOS specific + *-*-lynxos* ) + AC_MSG_CHECKING([LynxOS header file wrappers]) + [CFLAGS="$CFLAGS -D__NO_INCLUDE_WARN__"] + AC_MSG_RESULT(disabled) + AC_CHECK_LIB(bsd, gethostbyname, [LIBSOCKET="-lbsd"]) dnl for LynxOS + ;; + esac + + KDE_CHECK_TYPES + KDE_CHECK_LIBDL + KDE_CHECK_STRLCPY + +# darwin needs this to initialize the environment +AC_CHECK_HEADERS(crt_externs.h) +AC_CHECK_FUNC(_NSGetEnviron, [AC_DEFINE(HAVE_NSGETENVIRON, 1, [Define if your system needs _NSGetEnviron to set up the environment])]) + +AH_VERBATIM(_DARWIN_ENVIRON, +[ +#if defined(HAVE_NSGETENVIRON) && defined(HAVE_CRT_EXTERNS_H) +# include +# include +# define environ (*_NSGetEnviron()) +#endif +]) + +AH_VERBATIM(_AIX_STRINGS_H_BZERO, +[ +/* + * AIX defines FD_SET in terms of bzero, but fails to include + * that defines bzero. + */ + +#if defined(_AIX) +#include +#endif +]) + +AC_CHECK_FUNCS([vsnprintf snprintf]) + +AH_VERBATIM(_TRU64,[ +/* + * On HP-UX, the declaration of vsnprintf() is needed every time ! + */ + +#if !defined(HAVE_VSNPRINTF) || defined(hpux) +#if __STDC__ +#include +#include +#else +#include +#endif +#ifdef __cplusplus +extern "C" +#endif +int vsnprintf(char *str, size_t n, char const *fmt, va_list ap); +#ifdef __cplusplus +extern "C" +#endif +int snprintf(char *str, size_t n, char const *fmt, ...); +#endif +]) + +]) + +dnl ------------------------------------------------------------------------ +dnl Find the header files and libraries for X-Windows. Extended the +dnl macro AC_PATH_X +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([K_PATH_X], +[ +AC_REQUIRE([KDE_MISC_TESTS])dnl +AC_REQUIRE([KDE_CHECK_LIB64]) + +AC_ARG_ENABLE( + embedded, + AC_HELP_STRING([--enable-embedded],[link to Qt-embedded, don't use X]), + kde_use_qt_emb=$enableval, + kde_use_qt_emb=no +) + +AC_ARG_ENABLE( + qtopia, + AC_HELP_STRING([--enable-qtopia],[link to Qt-embedded, link to the Qtopia Environment]), + kde_use_qt_emb_palm=$enableval, + kde_use_qt_emb_palm=no +) + +AC_ARG_ENABLE( + mac, + AC_HELP_STRING([--enable-mac],[link to Qt/Mac (don't use X)]), + kde_use_qt_mac=$enableval, + kde_use_qt_mac=no +) + +# used to disable x11-specific stuff on special platforms +AM_CONDITIONAL(include_x11, test "$kde_use_qt_emb" = "no" && test "$kde_use_qt_mac" = "no") + +if test "$kde_use_qt_emb" = "no" && test "$kde_use_qt_mac" = "no"; then + +AC_MSG_CHECKING(for X) + +AC_CACHE_VAL(kde_cv_have_x, +[# One or both of the vars are not set, and there is no cached value. +if test "{$x_includes+set}" = set || test "$x_includes" = NONE; then + kde_x_includes=NO +else + kde_x_includes=$x_includes +fi +if test "{$x_libraries+set}" = set || test "$x_libraries" = NONE; then + kde_x_libraries=NO +else + kde_x_libraries=$x_libraries +fi + +# below we use the standard autoconf calls +ac_x_libraries=$kde_x_libraries +ac_x_includes=$kde_x_includes + +KDE_PATH_X_DIRECT +dnl AC_PATH_X_XMKMF picks /usr/lib as the path for the X libraries. +dnl Unfortunately, if compiling with the N32 ABI, this is not the correct +dnl location. The correct location is /usr/lib32 or an undefined value +dnl (the linker is smart enough to pick the correct default library). +dnl Things work just fine if you use just AC_PATH_X_DIRECT. +dnl Solaris has a similar problem. AC_PATH_X_XMKMF forces x_includes to +dnl /usr/openwin/include, which doesn't work. /usr/include does work, so +dnl x_includes should be left alone. +case "$host" in +mips-sgi-irix6*) + ;; +*-*-solaris*) + ;; +*) + _AC_PATH_X_XMKMF + if test -z "$ac_x_includes"; then + ac_x_includes="." + fi + if test -z "$ac_x_libraries"; then + ac_x_libraries="/usr/lib${kdelibsuff}" + fi +esac +#from now on we use our own again + +# when the user already gave --x-includes, we ignore +# what the standard autoconf macros told us. +if test "$kde_x_includes" = NO; then + kde_x_includes=$ac_x_includes +fi + +# for --x-libraries too +if test "$kde_x_libraries" = NO; then + kde_x_libraries=$ac_x_libraries +fi + +if test "$kde_x_includes" = NO; then + AC_MSG_ERROR([Can't find X includes. Please check your installation and add the correct paths!]) +fi + +if test "$kde_x_libraries" = NO; then + AC_MSG_ERROR([Can't find X libraries. Please check your installation and add the correct paths!]) +fi + +# Record where we found X for the cache. +kde_cv_have_x="have_x=yes \ + kde_x_includes=$kde_x_includes kde_x_libraries=$kde_x_libraries" +])dnl + +eval "$kde_cv_have_x" + +if test "$have_x" != yes; then + AC_MSG_RESULT($have_x) + no_x=yes +else + AC_MSG_RESULT([libraries $kde_x_libraries, headers $kde_x_includes]) +fi + +if test -z "$kde_x_includes" || test "x$kde_x_includes" = xNONE; then + X_INCLUDES="" + x_includes="."; dnl better than nothing :- + else + x_includes=$kde_x_includes + X_INCLUDES="-I$x_includes" +fi + +if test -z "$kde_x_libraries" || test "x$kde_x_libraries" = xNONE; then + X_LDFLAGS="" + x_libraries="/usr/lib"; dnl better than nothing :- + else + x_libraries=$kde_x_libraries + X_LDFLAGS="-L$x_libraries" +fi +all_includes="$X_INCLUDES" +all_libraries="$X_LDFLAGS $LDFLAGS_AS_NEEDED $LDFLAGS_NEW_DTAGS" + +# Check for libraries that X11R6 Xt/Xaw programs need. +ac_save_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS $X_LDFLAGS" +# SM needs ICE to (dynamically) link under SunOS 4.x (so we have to +# check for ICE first), but we must link in the order -lSM -lICE or +# we get undefined symbols. So assume we have SM if we have ICE. +# These have to be linked with before -lX11, unlike the other +# libraries we check for below, so use a different variable. +# --interran@uluru.Stanford.EDU, kb@cs.umb.edu. +AC_CHECK_LIB(ICE, IceConnectionNumber, + [LIBSM="-lSM -lICE"], , $X_EXTRA_LIBS) +LDFLAGS="$ac_save_LDFLAGS" + +LIB_X11='-lX11 $(LIBSOCKET)' + +AC_MSG_CHECKING(for libXext) +AC_CACHE_VAL(kde_cv_have_libXext, +[ +kde_ldflags_safe="$LDFLAGS" +kde_libs_safe="$LIBS" + +LDFLAGS="$LDFLAGS $X_LDFLAGS $USER_LDFLAGS" +LIBS="-lXext -lX11 $LIBSOCKET" + +AC_TRY_LINK([ +#include +#ifdef STDC_HEADERS +# include +#endif +], +[ +printf("hello Xext\n"); +], +kde_cv_have_libXext=yes, +kde_cv_have_libXext=no +) + +LDFLAGS=$kde_ldflags_safe +LIBS=$kde_libs_safe +]) + +AC_MSG_RESULT($kde_cv_have_libXext) + +if test "$kde_cv_have_libXext" = "no"; then + AC_MSG_ERROR([We need a working libXext to proceed. Since configure +can't find it itself, we stop here assuming that make wouldn't find +them either.]) +fi + +LIB_XEXT="-lXext" +QTE_NORTTI="" + +elif test "$kde_use_qt_emb" = "yes"; then + dnl We're using QT Embedded + CPPFLAGS=-DQWS + CXXFLAGS="$CXXFLAGS -fno-rtti" + QTE_NORTTI="-fno-rtti -DQWS" + X_PRE_LIBS="" + LIB_X11="" + LIB_XEXT="" + LIB_XRENDER="" + LIBSM="" + X_INCLUDES="" + X_LDFLAGS="" + x_includes="" + x_libraries="" +elif test "$kde_use_qt_mac" = "yes"; then + dnl We're using QT/Mac (I use QT_MAC so that qglobal.h doesn't *have* to + dnl be included to get the information) --Sam + CXXFLAGS="$CXXFLAGS -DQT_MAC -no-cpp-precomp" + CFLAGS="$CFLAGS -DQT_MAC -no-cpp-precomp" + X_PRE_LIBS="" + LIB_X11="" + LIB_XEXT="" + LIB_XRENDER="" + LIBSM="" + X_INCLUDES="" + X_LDFLAGS="" + x_includes="" + x_libraries="" +fi +AC_SUBST(X_PRE_LIBS) +AC_SUBST(LIB_X11) +AC_SUBST(LIB_XRENDER) +AC_SUBST(LIBSM) +AC_SUBST(X_INCLUDES) +AC_SUBST(X_LDFLAGS) +AC_SUBST(x_includes) +AC_SUBST(x_libraries) +AC_SUBST(QTE_NORTTI) +AC_SUBST(LIB_XEXT) + +]) + +AC_DEFUN([KDE_PRINT_QT_PROGRAM], +[ +AC_REQUIRE([KDE_USE_QT]) +cat > conftest.$ac_ext < +#include +EOF +if test "$kde_qtver" = "2"; then +cat >> conftest.$ac_ext < +#include +#include +EOF + +if test $kde_qtsubver -gt 0; then +cat >> conftest.$ac_ext <> conftest.$ac_ext < +#include +#include +EOF +fi + +echo "#if ! ($kde_qt_verstring)" >> conftest.$ac_ext +cat >> conftest.$ac_ext <> conftest.$ac_ext <> conftest.$ac_ext <> conftest.$ac_ext <> conftest.$ac_ext <&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC +fi + +rm -f conftest* +CXXFLAGS="$ac_cxxflags_safe" +LDFLAGS="$ac_ldflags_safe" +LIBS="$ac_libs_safe" + +LD_LIBRARY_PATH="$ac_LD_LIBRARY_PATH_safe" +export LD_LIBRARY_PATH +LIBRARY_PATH="$ac_LIBRARY_PATH" +export LIBRARY_PATH +AC_LANG_RESTORE +]) + +if test "$kde_cv_qt_direct" = "yes"; then + AC_MSG_RESULT(yes) + $1 +else + AC_MSG_RESULT(no) + $2 +fi +]) + +dnl ------------------------------------------------------------------------ +dnl Try to find the Qt headers and libraries. +dnl $(QT_LDFLAGS) will be -Lqtliblocation (if needed) +dnl and $(QT_INCLUDES) will be -Iqthdrlocation (if needed) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_PATH_QT_1_3], +[ +AC_REQUIRE([K_PATH_X]) +AC_REQUIRE([KDE_USE_QT]) +AC_REQUIRE([KDE_CHECK_LIB64]) + +dnl ------------------------------------------------------------------------ +dnl Add configure flag to enable linking to MT version of Qt library. +dnl ------------------------------------------------------------------------ + +AC_ARG_ENABLE( + mt, + AC_HELP_STRING([--disable-mt],[link to non-threaded Qt (deprecated)]), + kde_use_qt_mt=$enableval, + [ + if test $kde_qtver = 3; then + kde_use_qt_mt=yes + else + kde_use_qt_mt=no + fi + ] +) + +USING_QT_MT="" + +dnl ------------------------------------------------------------------------ +dnl If we not get --disable-qt-mt then adjust some vars for the host. +dnl ------------------------------------------------------------------------ + +KDE_MT_LDFLAGS= +KDE_MT_LIBS= +if test "x$kde_use_qt_mt" = "xyes"; then + KDE_CHECK_THREADING + if test "x$kde_use_threading" = "xyes"; then + CPPFLAGS="$USE_THREADS -DQT_THREAD_SUPPORT $CPPFLAGS" + KDE_MT_LDFLAGS="$USE_THREADS" + KDE_MT_LIBS="$LIBPTHREAD" + else + kde_use_qt_mt=no + fi +fi +AC_SUBST(KDE_MT_LDFLAGS) +AC_SUBST(KDE_MT_LIBS) + +kde_qt_was_given=yes + +dnl ------------------------------------------------------------------------ +dnl If we haven't been told how to link to Qt, we work it out for ourselves. +dnl ------------------------------------------------------------------------ +if test -z "$LIBQT_GLOB"; then + if test "x$kde_use_qt_emb" = "xyes"; then + LIBQT_GLOB="libqte.*" + else + LIBQT_GLOB="libqt.*" + fi +fi + +if test -z "$LIBQT"; then +dnl ------------------------------------------------------------ +dnl If we got --enable-embedded then adjust the Qt library name. +dnl ------------------------------------------------------------ + if test "x$kde_use_qt_emb" = "xyes"; then + qtlib="qte" + else + qtlib="qt" + fi + + kde_int_qt="-l$qtlib" +else + kde_int_qt="$LIBQT" + kde_lib_qt_set=yes +fi + +if test -z "$LIBQPE"; then +dnl ------------------------------------------------------------ +dnl If we got --enable-palmtop then add -lqpe to the link line +dnl ------------------------------------------------------------ + if test "x$kde_use_qt_emb" = "xyes"; then + if test "x$kde_use_qt_emb_palm" = "xyes"; then + LIB_QPE="-lqpe" + else + LIB_QPE="" + fi + else + LIB_QPE="" + fi +fi + +dnl ------------------------------------------------------------------------ +dnl If we got --enable-qt-mt then adjust the Qt library name for the host. +dnl ------------------------------------------------------------------------ + +if test "x$kde_use_qt_mt" = "xyes"; then + if test -z "$LIBQT"; then + LIBQT="-l$qtlib-mt" + kde_int_qt="-l$qtlib-mt" + else + LIBQT="$qtlib-mt" + kde_int_qt="$qtlib-mt" + fi + LIBQT_GLOB="lib$qtlib-mt.*" + USING_QT_MT="using -mt" +else + LIBQT="-l$qtlib" +fi + +if test $kde_qtver != 1; then + + AC_REQUIRE([AC_FIND_PNG]) + AC_REQUIRE([AC_FIND_JPEG]) + LIBQT="$LIBQT $LIBPNG $LIBJPEG" +fi + +if test $kde_qtver = 3; then + AC_REQUIRE([KDE_CHECK_LIBDL]) + LIBQT="$LIBQT $LIBDL" +fi + +AC_MSG_CHECKING([for Qt]) + +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBQT="$LIBQT $X_PRE_LIBS -lXext -lX11 $LIBSM $LIBSOCKET" +fi +ac_qt_includes=NO ac_qt_libraries=NO ac_qt_bindir=NO +qt_libraries="" +qt_includes="" +AC_ARG_WITH(qt-dir, + AC_HELP_STRING([--with-qt-dir=DIR],[where the root of Qt is installed ]), + [ ac_qt_includes="$withval"/include + ac_qt_libraries="$withval"/lib${kdelibsuff} + ac_qt_bindir="$withval"/bin + ]) + +AC_ARG_WITH(qt-includes, + AC_HELP_STRING([--with-qt-includes=DIR],[where the Qt includes are. ]), + [ + ac_qt_includes="$withval" + ]) + +kde_qt_libs_given=no + +AC_ARG_WITH(qt-libraries, + AC_HELP_STRING([--with-qt-libraries=DIR],[where the Qt library is installed.]), + [ ac_qt_libraries="$withval" + kde_qt_libs_given=yes + ]) + +AC_CACHE_VAL(ac_cv_have_qt, +[#try to guess Qt locations + +qt_incdirs="" +for dir in $kde_qt_dirs; do + qt_incdirs="$qt_incdirs $dir/include $dir" +done +qt_incdirs="$QTINC $qt_incdirs /usr/local/qt/include /usr/include/qt /usr/include /usr/X11R6/include/X11/qt /usr/X11R6/include/qt /usr/X11R6/include/qt2 /usr/include/qt3 $x_includes" +if test ! "$ac_qt_includes" = "NO"; then + qt_incdirs="$ac_qt_includes $qt_incdirs" +fi + +if test "$kde_qtver" != "1"; then + kde_qt_header=qstyle.h +else + kde_qt_header=qglobal.h +fi + +AC_FIND_FILE($kde_qt_header, $qt_incdirs, qt_incdir) +ac_qt_includes="$qt_incdir" + +qt_libdirs="" +for dir in $kde_qt_dirs; do + qt_libdirs="$qt_libdirs $dir/lib${kdelibsuff} $dir" +done +qt_libdirs="$QTLIB $qt_libdirs /usr/X11R6/lib /usr/lib /usr/local/qt/lib $x_libraries" +if test ! "$ac_qt_libraries" = "NO"; then + qt_libdir=$ac_qt_libraries +else + qt_libdirs="$ac_qt_libraries $qt_libdirs" + # if the Qt was given, the chance is too big that libqt.* doesn't exist + qt_libdir=NONE + for dir in $qt_libdirs; do + try="ls -1 $dir/${LIBQT_GLOB}" + if test -n "`$try 2> /dev/null`"; then qt_libdir=$dir; break; else echo "tried $dir" >&AC_FD_CC ; fi + done +fi +for a in $qt_libdir/lib`echo ${kde_int_qt} | sed 's,^-l,,'`_incremental.*; do + if test -e "$a"; then + LIBQT="$LIBQT ${kde_int_qt}_incremental" + break + fi +done + +ac_qt_libraries="$qt_libdir" + +AC_LANG_SAVE +AC_LANG_CPLUSPLUS + +ac_cxxflags_safe="$CXXFLAGS" +ac_ldflags_safe="$LDFLAGS" +ac_libs_safe="$LIBS" + +CXXFLAGS="$CXXFLAGS -I$qt_incdir $all_includes" +LDFLAGS="$LDFLAGS -L$qt_libdir $all_libraries $USER_LDFLAGS $KDE_MT_LDFLAGS" +LIBS="$LIBS $LIBQT $KDE_MT_LIBS" + +KDE_PRINT_QT_PROGRAM + +if AC_TRY_EVAL(ac_link) && test -s conftest; then + rm -f conftest* +else + echo "configure: failed program was:" >&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC + ac_qt_libraries="NO" +fi +rm -f conftest* +CXXFLAGS="$ac_cxxflags_safe" +LDFLAGS="$ac_ldflags_safe" +LIBS="$ac_libs_safe" + +AC_LANG_RESTORE +if test "$ac_qt_includes" = NO || test "$ac_qt_libraries" = NO; then + ac_cv_have_qt="have_qt=no" + ac_qt_notfound="" + missing_qt_mt="" + if test "$ac_qt_includes" = NO; then + if test "$ac_qt_libraries" = NO; then + ac_qt_notfound="(headers and libraries)"; + else + ac_qt_notfound="(headers)"; + fi + else + if test "x$kde_use_qt_mt" = "xyes"; then + missing_qt_mt=" +Make sure that you have compiled Qt with thread support!" + ac_qt_notfound="(library $qtlib-mt)"; + else + ac_qt_notfound="(library $qtlib)"; + fi + fi + + AC_MSG_ERROR([Qt ($kde_qt_minversion) $ac_qt_notfound not found. Please check your installation! +For more details about this problem, look at the end of config.log.$missing_qt_mt]) +else + have_qt="yes" +fi +]) + +eval "$ac_cv_have_qt" + +if test "$have_qt" != yes; then + AC_MSG_RESULT([$have_qt]); +else + ac_cv_have_qt="have_qt=yes \ + ac_qt_includes=$ac_qt_includes ac_qt_libraries=$ac_qt_libraries" + AC_MSG_RESULT([libraries $ac_qt_libraries, headers $ac_qt_includes $USING_QT_MT]) + + qt_libraries="$ac_qt_libraries" + qt_includes="$ac_qt_includes" +fi + +if test ! "$kde_qt_libs_given" = "yes" && test ! "$kde_qtver" = 3; then + KDE_CHECK_QT_DIRECT(qt_libraries= ,[]) +fi + +AC_SUBST(qt_libraries) +AC_SUBST(qt_includes) + +if test "$qt_includes" = "$x_includes" || test -z "$qt_includes"; then + QT_INCLUDES="" +else + QT_INCLUDES="-I$qt_includes" + all_includes="$QT_INCLUDES $all_includes" +fi + +if test "$qt_libraries" = "$x_libraries" || test -z "$qt_libraries"; then + QT_LDFLAGS="" +else + QT_LDFLAGS="-L$qt_libraries" + all_libraries="$QT_LDFLAGS $all_libraries" +fi +test -z "$KDE_MT_LDFLAGS" || all_libraries="$all_libraries $KDE_MT_LDFLAGS" + +AC_SUBST(QT_INCLUDES) +AC_SUBST(QT_LDFLAGS) +AC_PATH_QT_MOC_UIC + +KDE_CHECK_QT_JPEG + +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIB_QT="$kde_int_qt $LIBJPEG_QT "'$(LIBZ) $(LIBPNG) -lXext $(LIB_X11) $(LIBSM)' +else +LIB_QT="$kde_int_qt $LIBJPEG_QT "'$(LIBZ) $(LIBPNG)' +fi +test -z "$KDE_MT_LIBS" || LIB_QT="$LIB_QT $KDE_MT_LIBS" +for a in $qt_libdir/lib`echo ${kde_int_qt} | sed 's,^-l,,'`_incremental.*; do + if test -e "$a"; then + LIB_QT="$LIB_QT ${kde_int_qt}_incremental" + break + fi +done + +AC_SUBST(LIB_QT) +AC_SUBST(LIB_QPE) + +AC_SUBST(kde_qtver) +]) + +AC_DEFUN([AC_PATH_QT], +[ +AC_PATH_QT_1_3 +]) + +AC_DEFUN([KDE_CHECK_UIC_PLUGINS], +[ +AC_REQUIRE([AC_PATH_QT_MOC_UIC]) + +if test x$ac_uic_supports_libpath = xyes; then + +AC_MSG_CHECKING([if UIC has KDE plugins available]) +AC_CACHE_VAL(kde_cv_uic_plugins, +[ +cat > actest.ui << EOF + +NewConnectionDialog + + + + testInput + + + + +EOF + + + +kde_cv_uic_plugins=no +kde_line="$UIC_PATH -L $kde_widgetdir" +if test x$ac_uic_supports_nounload = xyes; then + kde_line="$kde_line -nounload" +fi +kde_line="$kde_line -impl actest.h actest.ui > actest.cpp" +if AC_TRY_EVAL(kde_line); then + # if you're trying to debug this check and think it's incorrect, + # better check your installation. The check _is_ correct - your + # installation is not. + if test -f actest.cpp && grep klineedit actest.cpp > /dev/null; then + kde_cv_uic_plugins=yes + fi +fi +rm -f actest.ui actest.cpp +]) + +AC_MSG_RESULT([$kde_cv_uic_plugins]) +if test "$kde_cv_uic_plugins" != yes; then + AC_MSG_ERROR([you need to install kdelibs first.]) +fi +fi +]) + +AC_DEFUN([KDE_CHECK_FINAL], +[ + AC_ARG_ENABLE(final, + AC_HELP_STRING([--enable-final], + [build size optimized apps (experimental - needs lots of memory)]), + kde_use_final=$enableval, kde_use_final=no) + + if test "x$kde_use_final" = "xyes"; then + KDE_USE_FINAL_TRUE="" + KDE_USE_FINAL_FALSE="#" + else + KDE_USE_FINAL_TRUE="#" + KDE_USE_FINAL_FALSE="" + fi + AC_SUBST(KDE_USE_FINAL_TRUE) + AC_SUBST(KDE_USE_FINAL_FALSE) +]) + +AC_DEFUN([KDE_CHECK_CLOSURE], +[ + AC_ARG_ENABLE(closure, + AC_HELP_STRING([--enable-closure],[delay template instantiation]), + kde_use_closure=$enableval, kde_use_closure=no) + + KDE_NO_UNDEFINED="" + if test "x$kde_use_closure" = "xyes"; then + KDE_USE_CLOSURE_TRUE="" + KDE_USE_CLOSURE_FALSE="#" +# CXXFLAGS="$CXXFLAGS $REPO" + else + KDE_USE_CLOSURE_TRUE="#" + KDE_USE_CLOSURE_FALSE="" + KDE_NO_UNDEFINED="" + case $host in + *-*-linux-gnu) + KDE_CHECK_COMPILER_FLAG([Wl,--no-undefined], + [KDE_CHECK_COMPILER_FLAG([Wl,--allow-shlib-undefined], + [KDE_NO_UNDEFINED="-Wl,--no-undefined -Wl,--allow-shlib-undefined"], + [KDE_NO_UNDEFINED=""])], + [KDE_NO_UNDEFINED=""]) + ;; + esac + fi + AC_SUBST(KDE_USE_CLOSURE_TRUE) + AC_SUBST(KDE_USE_CLOSURE_FALSE) + AC_SUBST(KDE_NO_UNDEFINED) +]) + +dnl Check if the linker supports --enable-new-dtags and --as-needed +AC_DEFUN([KDE_CHECK_NEW_LDFLAGS], +[ + AC_ARG_ENABLE(new_ldflags, + AC_HELP_STRING([--enable-new-ldflags], + [enable the new linker flags]), + kde_use_new_ldflags=$enableval, + kde_use_new_ldflags=no) + + LDFLAGS_AS_NEEDED="" + LDFLAGS_NEW_DTAGS="" + if test "x$kde_use_new_ldflags" = "xyes"; then + LDFLAGS_NEW_DTAGS="" + KDE_CHECK_COMPILER_FLAG([Wl,--enable-new-dtags], + [LDFLAGS_NEW_DTAGS="-Wl,--enable-new-dtags"],) + + KDE_CHECK_COMPILER_FLAG([Wl,--as-needed], + [LDFLAGS_AS_NEEDED="-Wl,--as-needed"],) + fi + AC_SUBST(LDFLAGS_AS_NEEDED) + AC_SUBST(LDFLAGS_NEW_DTAGS) +]) + +AC_DEFUN([KDE_CHECK_NMCHECK], +[ + AC_ARG_ENABLE(nmcheck,AC_HELP_STRING([--enable-nmcheck],[enable automatic namespace cleanness check]), + kde_use_nmcheck=$enableval, kde_use_nmcheck=no) + + if test "$kde_use_nmcheck" = "yes"; then + KDE_USE_NMCHECK_TRUE="" + KDE_USE_NMCHECK_FALSE="#" + else + KDE_USE_NMCHECK_TRUE="#" + KDE_USE_NMCHECK_FALSE="" + fi + AC_SUBST(KDE_USE_NMCHECK_TRUE) + AC_SUBST(KDE_USE_NMCHECK_FALSE) +]) + +AC_DEFUN([KDE_EXPAND_MAKEVAR], [ +savex=$exec_prefix +test "x$exec_prefix" = xNONE && exec_prefix=$prefix +tmp=$$2 +while $1=`eval echo "$tmp"`; test "x$$1" != "x$tmp"; do tmp=$$1; done +exec_prefix=$savex +]) + +dnl ------------------------------------------------------------------------ +dnl Now, the same with KDE +dnl $(KDE_LDFLAGS) will be the kdeliblocation (if needed) +dnl and $(kde_includes) will be the kdehdrlocation (if needed) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_BASE_PATH_KDE], +[ +AC_REQUIRE([KDE_CHECK_STL]) +AC_REQUIRE([AC_PATH_QT])dnl +AC_REQUIRE([KDE_CHECK_LIB64]) + +AC_CHECK_RPATH +AC_MSG_CHECKING([for KDE]) + +if test "${prefix}" != NONE; then + kde_includes=${includedir} + KDE_EXPAND_MAKEVAR(ac_kde_includes, includedir) + + kde_libraries=${libdir} + KDE_EXPAND_MAKEVAR(ac_kde_libraries, libdir) + +else + ac_kde_includes= + ac_kde_libraries= + kde_libraries="" + kde_includes="" +fi + +AC_CACHE_VAL(ac_cv_have_kde, +[#try to guess kde locations + +if test "$kde_qtver" = 1; then + kde_check_header="ksock.h" + kde_check_lib="libkdecore.la" +else + kde_check_header="ksharedptr.h" + kde_check_lib="libkio.la" +fi + +if test -z "$1"; then + +kde_incdirs="$kde_libs_prefix/include /opt/kde3/include/kde /usr/lib/kde/include /usr/local/kde/include /usr/local/include /usr/kde/include /usr/include/kde /usr/include /opt/kde3/include /opt/kde/include $x_includes $qt_includes" +test -n "$KDEDIR" && kde_incdirs="$KDEDIR/include $KDEDIR/include/kde $KDEDIR $kde_incdirs" +kde_incdirs="$ac_kde_includes $kde_incdirs" +AC_FIND_FILE($kde_check_header, $kde_incdirs, kde_incdir) +ac_kde_includes="$kde_incdir" + +if test -n "$ac_kde_includes" && test ! -r "$ac_kde_includes/$kde_check_header"; then + AC_MSG_ERROR([ +in the prefix, you've chosen, are no KDE headers installed. This will fail. +So, check this please and use another prefix!]) +fi + +kde_libdirs="$kde_libs_prefix/lib${kdelibsuff} /usr/lib/kde/lib${kdelibsuff} /usr/local/kde/lib${kdelibsuff} /usr/kde/lib${kdelibsuff} /usr/lib${kdelibsuff}/kde /usr/lib${kdelibsuff}/kde3 /usr/lib${kdelibsuff} /usr/X11R6/lib${kdelibsuff} /usr/local/lib${kdelibsuff} /opt/kde3/lib${kdelibsuff} /opt/kde/lib${kdelibsuff} /usr/X11R6/kde/lib${kdelibsuff}" +test -n "$KDEDIR" && kde_libdirs="$KDEDIR/lib${kdelibsuff} $KDEDIR $kde_libdirs" +kde_libdirs="$ac_kde_libraries $libdir $kde_libdirs" +AC_FIND_FILE($kde_check_lib, $kde_libdirs, kde_libdir) +ac_kde_libraries="$kde_libdir" + +kde_widgetdir=NO +dnl this might be somewhere else +AC_FIND_FILE("kde3/plugins/designer/kdewidgets.la", $kde_libdirs, kde_widgetdir) + +if test -n "$ac_kde_libraries" && test ! -r "$ac_kde_libraries/$kde_check_lib"; then +AC_MSG_ERROR([ +in the prefix, you've chosen, are no KDE libraries installed. This will fail. +So, check this please and use another prefix!]) +fi + +if test -n "$kde_widgetdir" && test ! -r "$kde_widgetdir/kde3/plugins/designer/kdewidgets.la"; then +AC_MSG_ERROR([ +I can't find the designer plugins. These are required and should have been installed +by kdelibs]) +fi + +if test -n "$kde_widgetdir"; then + kde_widgetdir="$kde_widgetdir/kde3/plugins/designer" +fi + + +if test "$ac_kde_includes" = NO || test "$ac_kde_libraries" = NO || test "$kde_widgetdir" = NO; then + ac_cv_have_kde="have_kde=no" +else + ac_cv_have_kde="have_kde=yes \ + ac_kde_includes=$ac_kde_includes ac_kde_libraries=$ac_kde_libraries" +fi + +else dnl test -z $1, e.g. from kdelibs + + ac_cv_have_kde="have_kde=no" + +fi +])dnl + +eval "$ac_cv_have_kde" + +if test "$have_kde" != "yes"; then + if test "${prefix}" = NONE; then + ac_kde_prefix="$ac_default_prefix" + else + ac_kde_prefix="$prefix" + fi + if test "$exec_prefix" = NONE; then + ac_kde_exec_prefix="$ac_kde_prefix" + AC_MSG_RESULT([will be installed in $ac_kde_prefix]) + else + ac_kde_exec_prefix="$exec_prefix" + AC_MSG_RESULT([will be installed in $ac_kde_prefix and $ac_kde_exec_prefix]) + fi + + kde_libraries="${libdir}" + kde_includes="${includedir}" + +else + ac_cv_have_kde="have_kde=yes \ + ac_kde_includes=$ac_kde_includes ac_kde_libraries=$ac_kde_libraries" + AC_MSG_RESULT([libraries $ac_kde_libraries, headers $ac_kde_includes]) + + kde_libraries="$ac_kde_libraries" + kde_includes="$ac_kde_includes" +fi +AC_SUBST(kde_libraries) +AC_SUBST(kde_includes) + +if test "$kde_includes" = "$x_includes" || test "$kde_includes" = "$qt_includes" || test "$kde_includes" = "/usr/include"; then + KDE_INCLUDES="" +else + KDE_INCLUDES="-I$kde_includes" + all_includes="$KDE_INCLUDES $all_includes" +fi + +KDE_DEFAULT_CXXFLAGS="-DQT_CLEAN_NAMESPACE -DQT_NO_ASCII_CAST -DQT_NO_STL -DQT_NO_COMPAT -DQT_NO_TRANSLATION" + +KDE_LDFLAGS="-L$kde_libraries" +if test ! "$kde_libraries" = "$x_libraries" && test ! "$kde_libraries" = "$qt_libraries" ; then + all_libraries="$KDE_LDFLAGS $all_libraries" +fi + +AC_SUBST(KDE_LDFLAGS) +AC_SUBST(KDE_INCLUDES) + +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + +all_libraries="$all_libraries $USER_LDFLAGS" +all_includes="$all_includes $USER_INCLUDES" +AC_SUBST(all_includes) +AC_SUBST(all_libraries) + +if test -z "$1"; then +KDE_CHECK_UIC_PLUGINS +fi + +ac_kde_libraries="$kde_libdir" + +AC_SUBST(AUTODIRS) + + +]) + +AC_DEFUN([KDE_CHECK_EXTRA_LIBS], +[ +AC_MSG_CHECKING(for extra includes) +AC_ARG_WITH(extra-includes,AC_HELP_STRING([--with-extra-includes=DIR],[adds non standard include paths]), + kde_use_extra_includes="$withval", + kde_use_extra_includes=NONE +) +kde_extra_includes= +if test -n "$kde_use_extra_includes" && \ + test "$kde_use_extra_includes" != "NONE"; then + + ac_save_ifs=$IFS + IFS=':' + for dir in $kde_use_extra_includes; do + kde_extra_includes="$kde_extra_includes $dir" + USER_INCLUDES="$USER_INCLUDES -I$dir" + done + IFS=$ac_save_ifs + kde_use_extra_includes="added" +else + kde_use_extra_includes="no" +fi +AC_SUBST(USER_INCLUDES) + +AC_MSG_RESULT($kde_use_extra_includes) + +kde_extra_libs= +AC_MSG_CHECKING(for extra libs) +AC_ARG_WITH(extra-libs,AC_HELP_STRING([--with-extra-libs=DIR],[adds non standard library paths]), + kde_use_extra_libs=$withval, + kde_use_extra_libs=NONE +) +if test -n "$kde_use_extra_libs" && \ + test "$kde_use_extra_libs" != "NONE"; then + + ac_save_ifs=$IFS + IFS=':' + for dir in $kde_use_extra_libs; do + kde_extra_libs="$kde_extra_libs $dir" + KDE_EXTRA_RPATH="$KDE_EXTRA_RPATH -R $dir" + USER_LDFLAGS="$USER_LDFLAGS -L$dir" + done + IFS=$ac_save_ifs + kde_use_extra_libs="added" +else + kde_use_extra_libs="no" +fi + +AC_SUBST(USER_LDFLAGS) + +AC_MSG_RESULT($kde_use_extra_libs) + +]) + +AC_DEFUN([KDE_1_CHECK_PATH_HEADERS], +[ + AC_MSG_CHECKING([for KDE headers installed]) + AC_LANG_SAVE + AC_LANG_CPLUSPLUS +cat > conftest.$ac_ext < +#endif +#include +#include "confdefs.h" +#include + +int main() { + printf("kde_htmldir=\\"%s\\"\n", KApplication::kde_htmldir().data()); + printf("kde_appsdir=\\"%s\\"\n", KApplication::kde_appsdir().data()); + printf("kde_icondir=\\"%s\\"\n", KApplication::kde_icondir().data()); + printf("kde_sounddir=\\"%s\\"\n", KApplication::kde_sounddir().data()); + printf("kde_datadir=\\"%s\\"\n", KApplication::kde_datadir().data()); + printf("kde_locale=\\"%s\\"\n", KApplication::kde_localedir().data()); + printf("kde_cgidir=\\"%s\\"\n", KApplication::kde_cgidir().data()); + printf("kde_confdir=\\"%s\\"\n", KApplication::kde_configdir().data()); + printf("kde_mimedir=\\"%s\\"\n", KApplication::kde_mimedir().data()); + printf("kde_toolbardir=\\"%s\\"\n", KApplication::kde_toolbardir().data()); + printf("kde_wallpaperdir=\\"%s\\"\n", + KApplication::kde_wallpaperdir().data()); + printf("kde_bindir=\\"%s\\"\n", KApplication::kde_bindir().data()); + printf("kde_partsdir=\\"%s\\"\n", KApplication::kde_partsdir().data()); + printf("kde_servicesdir=\\"/tmp/dummy\\"\n"); + printf("kde_servicetypesdir=\\"/tmp/dummy\\"\n"); + printf("kde_moduledir=\\"/tmp/dummy\\"\n"); + printf("kde_styledir=\\"/tmp/dummy\\"\n"); + printf("kde_widgetdir=\\"/tmp/dummy\\"\n"); + printf("xdg_appsdir=\\"/tmp/dummy\\"\n"); + printf("xdg_menudir=\\"/tmp/dummy\\"\n"); + printf("xdg_directorydir=\\"/tmp/dummy\\"\n"); + printf("kde_kcfgdir=\\"/tmp/dummy\\"\n"); + return 0; + } +EOF + + ac_save_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$all_includes $CPPFLAGS" + if AC_TRY_EVAL(ac_compile); then + AC_MSG_RESULT(yes) + else + AC_MSG_ERROR([your system is not able to compile a small KDE application! +Check, if you installed the KDE header files correctly. +For more details about this problem, look at the end of config.log.]) + fi + CPPFLAGS=$ac_save_CPPFLAGS + + AC_LANG_RESTORE +]) + +AC_DEFUN([KDE_CHECK_KDEQTADDON], +[ +AC_MSG_CHECKING(for kde-qt-addon) +AC_CACHE_VAL(kde_cv_have_kdeqtaddon, +[ + kde_ldflags_safe="$LDFLAGS" + kde_libs_safe="$LIBS" + kde_cxxflags_safe="$CXXFLAGS" + + LIBS="-lkde-qt-addon $LIBQT $LIBS" + CXXFLAGS="$CXXFLAGS -I$prefix/include -I$prefix/include/kde $all_includes" + LDFLAGS="$LDFLAGS $all_libraries $USER_LDFLAGS" + + AC_TRY_LINK([ + #include + ], + [ + QDomDocument doc; + ], + kde_cv_have_kdeqtaddon=yes, + kde_cv_have_kdeqtaddon=no + ) + + LDFLAGS=$kde_ldflags_safe + LIBS=$kde_libs_safe + CXXFLAGS=$kde_cxxflags_safe +]) + +AC_MSG_RESULT($kde_cv_have_kdeqtaddon) + +if test "$kde_cv_have_kdeqtaddon" = "no"; then + AC_MSG_ERROR([Can't find libkde-qt-addon. You need to install it first. +It is a separate package (and CVS module) named kde-qt-addon.]) +fi +]) + +AC_DEFUN([KDE_CREATE_LIBS_ALIASES], +[ + AC_REQUIRE([KDE_MISC_TESTS]) + AC_REQUIRE([KDE_CHECK_LIBDL]) + AC_REQUIRE([K_PATH_X]) + +if test $kde_qtver = 3; then + AC_SUBST(LIB_KDECORE, "-lkdecore") + AC_SUBST(LIB_KDEUI, "-lkdeui") + AC_SUBST(LIB_KIO, "-lkio") + AC_SUBST(LIB_KJS, "-lkjs") + AC_SUBST(LIB_SMB, "-lsmb") + AC_SUBST(LIB_KAB, "-lkab") + AC_SUBST(LIB_KABC, "-lkabc") + AC_SUBST(LIB_KHTML, "-lkhtml") + AC_SUBST(LIB_KSPELL, "-lkspell") + AC_SUBST(LIB_KPARTS, "-lkparts") + AC_SUBST(LIB_KDEPRINT, "-lkdeprint") + AC_SUBST(LIB_KUTILS, "-lkutils") + AC_SUBST(LIB_KDEPIM, "-lkdepim") + AC_SUBST(LIB_KIMPROXY, "-lkimproxy") + AC_SUBST(LIB_KNEWSTUFF, "-lknewstuff") + AC_SUBST(LIB_KDNSSD, "-lkdnssd") +# these are for backward compatibility + AC_SUBST(LIB_KSYCOCA, "-lkio") + AC_SUBST(LIB_KFILE, "-lkio") +elif test $kde_qtver = 2; then + AC_SUBST(LIB_KDECORE, "-lkdecore") + AC_SUBST(LIB_KDEUI, "-lkdeui") + AC_SUBST(LIB_KIO, "-lkio") + AC_SUBST(LIB_KSYCOCA, "-lksycoca") + AC_SUBST(LIB_SMB, "-lsmb") + AC_SUBST(LIB_KFILE, "-lkfile") + AC_SUBST(LIB_KAB, "-lkab") + AC_SUBST(LIB_KHTML, "-lkhtml") + AC_SUBST(LIB_KSPELL, "-lkspell") + AC_SUBST(LIB_KPARTS, "-lkparts") + AC_SUBST(LIB_KDEPRINT, "-lkdeprint") +else + AC_SUBST(LIB_KDECORE, "-lkdecore -lXext $(LIB_QT)") + AC_SUBST(LIB_KDEUI, "-lkdeui $(LIB_KDECORE)") + AC_SUBST(LIB_KFM, "-lkfm $(LIB_KDECORE)") + AC_SUBST(LIB_KFILE, "-lkfile $(LIB_KFM) $(LIB_KDEUI)") + AC_SUBST(LIB_KAB, "-lkab $(LIB_KIMGIO) $(LIB_KDECORE)") +fi +]) + +AC_DEFUN([AC_PATH_KDE], +[ + AC_BASE_PATH_KDE + AC_ARG_ENABLE(path-check,AC_HELP_STRING([--disable-path-check],[don't try to find out, where to install]), + [ + if test "$enableval" = "no"; + then ac_use_path_checking="default" + else ac_use_path_checking="" + fi + ], + [ + if test "$kde_qtver" = 1; + then ac_use_path_checking="" + else ac_use_path_checking="default" + fi + ] + ) + + AC_CREATE_KFSSTND($ac_use_path_checking) + + AC_SUBST_KFSSTND + KDE_CREATE_LIBS_ALIASES +]) + +dnl KDE_CHECK_FUNC_EXT(, [headers], [sample-use], [C prototype], [autoheader define], [call if found]) +AC_DEFUN([KDE_CHECK_FUNC_EXT], +[ +AC_MSG_CHECKING(for $1) +AC_CACHE_VAL(kde_cv_func_$1, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +save_CXXFLAGS="$CXXFLAGS" +kde_safe_LIBS="$LIBS" +LIBS="$LIBS $X_EXTRA_LIBS" +if test "$GXX" = "yes"; then +CXXFLAGS="$CXXFLAGS -pedantic-errors" +fi +AC_TRY_COMPILE([ +$2 +], +[ +$3 +], +kde_cv_func_$1=yes, +kde_cv_func_$1=no) +CXXFLAGS="$save_CXXFLAGS" +LIBS="$kde_safe_LIBS" +AC_LANG_RESTORE +]) + +AC_MSG_RESULT($kde_cv_func_$1) + +AC_MSG_CHECKING([if $1 needs custom prototype]) +AC_CACHE_VAL(kde_cv_proto_$1, +[ +if test "x$kde_cv_func_$1" = xyes; then + kde_cv_proto_$1=no +else + case "$1" in + setenv|unsetenv|usleep|random|srandom|seteuid|mkstemps|mkstemp|revoke|vsnprintf|strlcpy|strlcat) + kde_cv_proto_$1="yes - in libkdefakes" + ;; + *) + kde_cv_proto_$1=unknown + ;; + esac +fi + +if test "x$kde_cv_proto_$1" = xunknown; then + +AC_LANG_SAVE +AC_LANG_CPLUSPLUS + kde_safe_libs=$LIBS + LIBS="$LIBS $X_EXTRA_LIBS" + AC_TRY_LINK([ +$2 + +extern "C" $4; +], +[ +$3 +], +[ kde_cv_func_$1=yes + kde_cv_proto_$1=yes ], + [kde_cv_proto_$1="$1 unavailable"] +) +LIBS=$kde_safe_libs +AC_LANG_RESTORE +fi +]) +AC_MSG_RESULT($kde_cv_proto_$1) + +if test "x$kde_cv_func_$1" = xyes; then + AC_DEFINE(HAVE_$5, 1, [Define if you have $1]) + $6 +fi +if test "x$kde_cv_proto_$1" = xno; then + AC_DEFINE(HAVE_$5_PROTO, 1, + [Define if you have the $1 prototype]) +fi + +AH_VERBATIM([_HAVE_$5_PROTO], +[ +#if !defined(HAVE_$5_PROTO) +#ifdef __cplusplus +extern "C" { +#endif +$4; +#ifdef __cplusplus +} +#endif +#endif +]) +]) + +AC_DEFUN([AC_CHECK_SETENV], +[ + KDE_CHECK_FUNC_EXT(setenv, [ +#include +], + [setenv("VAR", "VALUE", 1);], + [int setenv (const char *, const char *, int)], + [SETENV]) +]) + +AC_DEFUN([AC_CHECK_UNSETENV], +[ + KDE_CHECK_FUNC_EXT(unsetenv, [ +#include +], + [unsetenv("VAR");], + [void unsetenv (const char *)], + [UNSETENV]) +]) + +AC_DEFUN([AC_CHECK_GETDOMAINNAME], +[ + KDE_CHECK_FUNC_EXT(getdomainname, [ +#include +#include +#include +], + [ +char buffer[200]; +getdomainname(buffer, 200); +], + [#include + int getdomainname (char *, size_t)], + [GETDOMAINNAME]) +]) + +AC_DEFUN([AC_CHECK_GETHOSTNAME], +[ + KDE_CHECK_FUNC_EXT(gethostname, [ +#include +#include +], + [ +char buffer[200]; +gethostname(buffer, 200); +], + [int gethostname (char *, unsigned int)], + [GETHOSTNAME]) +]) + +AC_DEFUN([AC_CHECK_USLEEP], +[ + KDE_CHECK_FUNC_EXT(usleep, [ +#include +], + [ +usleep(200); +], + [int usleep (unsigned int)], + [USLEEP]) +]) + + +AC_DEFUN([AC_CHECK_RANDOM], +[ + KDE_CHECK_FUNC_EXT(random, [ +#include +], + [ +random(); +], + [long int random(void)], + [RANDOM]) + + KDE_CHECK_FUNC_EXT(srandom, [ +#include +], + [ +srandom(27); +], + [void srandom(unsigned int)], + [SRANDOM]) + +]) + +AC_DEFUN([AC_CHECK_INITGROUPS], +[ + KDE_CHECK_FUNC_EXT(initgroups, [ +#include +#include +#include +], + [ +char buffer[200]; +initgroups(buffer, 27); +], + [int initgroups(const char *, gid_t)], + [INITGROUPS]) +]) + +AC_DEFUN([AC_CHECK_MKSTEMPS], +[ + KDE_CHECK_FUNC_EXT(mkstemps, [ +#include +#include +], + [ +mkstemps("/tmp/aaaXXXXXX", 6); +], + [int mkstemps(char *, int)], + [MKSTEMPS]) +]) + +AC_DEFUN([AC_CHECK_MKSTEMP], +[ + KDE_CHECK_FUNC_EXT(mkstemp, [ +#include +#include +], + [ +mkstemp("/tmp/aaaXXXXXX"); +], + [int mkstemp(char *)], + [MKSTEMP]) +]) + +AC_DEFUN([AC_CHECK_MKDTEMP], +[ + KDE_CHECK_FUNC_EXT(mkdtemp, [ +#include +#include +], + [ +mkdtemp("/tmp/aaaXXXXXX"); +], + [char *mkdtemp(char *)], + [MKDTEMP]) +]) + + +AC_DEFUN([AC_CHECK_RES_INIT], +[ + AC_MSG_CHECKING([if res_init needs -lresolv]) + kde_libs_safe="$LIBS" + LIBS="$LIBS $X_EXTRA_LIBS -lresolv" + AC_TRY_LINK( + [ +#include +#include +#include +#include + ], + [ + res_init(); + ], + [ + LIBRESOLV="-lresolv" + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_RES_INIT, 1, [Define if you have the res_init function]) + ], + [ AC_MSG_RESULT(no) ] + ) + LIBS=$kde_libs_safe + AC_SUBST(LIBRESOLV) + + KDE_CHECK_FUNC_EXT(res_init, + [ +#include +#include +#include +#include + ], + [res_init()], + [int res_init(void)], + [RES_INIT]) +]) + +AC_DEFUN([AC_CHECK_STRLCPY], +[ + KDE_CHECK_FUNC_EXT(strlcpy, [ +#include +], +[ char buf[20]; + strlcpy(buf, "KDE function test", sizeof(buf)); +], + [unsigned long strlcpy(char*, const char*, unsigned long)], + [STRLCPY]) +]) + +AC_DEFUN([AC_CHECK_STRLCAT], +[ + KDE_CHECK_FUNC_EXT(strlcat, [ +#include +], +[ char buf[20]; + buf[0]='\0'; + strlcat(buf, "KDE function test", sizeof(buf)); +], + [unsigned long strlcat(char*, const char*, unsigned long)], + [STRLCAT]) +]) + +AC_DEFUN([AC_CHECK_RES_QUERY], +[ + KDE_CHECK_FUNC_EXT(res_query, [ +#include +#include +#include +#include +#include +], +[ +res_query(NULL, 0, 0, NULL, 0); +], + [int res_query(const char *, int, int, unsigned char *, int)], + [RES_QUERY]) +]) + +AC_DEFUN([AC_CHECK_DN_SKIPNAME], +[ + KDE_CHECK_FUNC_EXT(dn_skipname, [ +#include +#include +#include +#include +], +[ +dn_skipname (NULL, NULL); +], + [int dn_skipname (unsigned char *, unsigned char *)], + [DN_SKIPNAME]) +]) + + +AC_DEFUN([AC_FIND_GIF], + [AC_MSG_CHECKING([for giflib]) +AC_CACHE_VAL(ac_cv_lib_gif, +[ac_save_LIBS="$LIBS" +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBS="$all_libraries -lgif -lX11 $LIBSOCKET" +else +LIBS="$all_libraries -lgif" +fi +AC_TRY_LINK(dnl +[ +#ifdef __cplusplus +extern "C" { +#endif +int GifLastError(void); +#ifdef __cplusplus +} +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +], + [return GifLastError();], + eval "ac_cv_lib_gif=yes", + eval "ac_cv_lib_gif=no") +LIBS="$ac_save_LIBS" +])dnl +if eval "test \"`echo $ac_cv_lib_gif`\" = yes"; then + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_LIBGIF, 1, [Define if you have libgif]) +else + AC_MSG_ERROR(You need giflib30. Please install the kdesupport package) +fi +]) + +AC_DEFUN([KDE_FIND_JPEG_HELPER], +[ +AC_MSG_CHECKING([for libjpeg$2]) +AC_CACHE_VAL(ac_cv_lib_jpeg_$1, +[ +ac_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS -ljpeg$2 -lm" +ac_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK( +[/* Override any gcc2 internal prototype to avoid an error. */ +struct jpeg_decompress_struct; +typedef struct jpeg_decompress_struct * j_decompress_ptr; +typedef int size_t; +#ifdef __cplusplus +extern "C" { +#endif + void jpeg_CreateDecompress(j_decompress_ptr cinfo, + int version, size_t structsize); +#ifdef __cplusplus +} +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +], + [jpeg_CreateDecompress(0L, 0, 0);], + eval "ac_cv_lib_jpeg_$1=-ljpeg$2", + eval "ac_cv_lib_jpeg_$1=no") +LIBS="$ac_save_LIBS" +CFLAGS="$ac_save_CFLAGS" +]) + +if eval "test ! \"`echo $ac_cv_lib_jpeg_$1`\" = no"; then + LIBJPEG="$ac_cv_lib_jpeg_$1" + AC_MSG_RESULT($ac_cv_lib_jpeg_$1) +else + AC_MSG_RESULT(no) + $3 +fi + +]) + +AC_DEFUN([AC_FIND_JPEG], +[ +dnl first look for libraries +KDE_FIND_JPEG_HELPER(6b, 6b, + KDE_FIND_JPEG_HELPER(normal, [], + [ + LIBJPEG= + ] + ) +) + +dnl then search the headers (can't use simply AC_TRY_xxx, as jpeglib.h +dnl requires system dependent includes loaded before it) +jpeg_incdirs="$includedir /usr/include /usr/local/include $kde_extra_includes" +AC_FIND_FILE(jpeglib.h, $jpeg_incdirs, jpeg_incdir) +test "x$jpeg_incdir" = xNO && jpeg_incdir= + +dnl if headers _and_ libraries are missing, this is no error, and we +dnl continue with a warning (the user will get no jpeg support in khtml) +dnl if only one is missing, it means a configuration error, but we still +dnl only warn +if test -n "$jpeg_incdir" && test -n "$LIBJPEG" ; then + AC_DEFINE_UNQUOTED(HAVE_LIBJPEG, 1, [Define if you have libjpeg]) +else + if test -n "$jpeg_incdir" || test -n "$LIBJPEG" ; then + AC_MSG_WARN([ +There is an installation error in jpeg support. You seem to have only one +of either the headers _or_ the libraries installed. You may need to either +provide correct --with-extra-... options, or the development package of +libjpeg6b. You can get a source package of libjpeg from http://www.ijg.org/ +Disabling JPEG support. +]) + else + AC_MSG_WARN([libjpeg not found. disable JPEG support.]) + fi + jpeg_incdir= + LIBJPEG= +fi + +AC_SUBST(LIBJPEG) +AH_VERBATIM(_AC_CHECK_JPEG, +[/* + * jpeg.h needs HAVE_BOOLEAN, when the system uses boolean in system + * headers and I'm too lazy to write a configure test as long as only + * unixware is related + */ +#ifdef _UNIXWARE +#define HAVE_BOOLEAN +#endif +]) +]) + +AC_DEFUN([KDE_CHECK_QT_JPEG], +[ +if test -n "$LIBJPEG"; then +AC_MSG_CHECKING([if Qt needs $LIBJPEG]) +AC_CACHE_VAL(kde_cv_qt_jpeg, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +ac_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS $LIBQT" +LIBS=`echo $LIBS | sed "s/$LIBJPEG//"` +ac_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK( +[#include ], + [ + int argc; + char** argv; + QApplication app(argc, argv);], + eval "kde_cv_qt_jpeg=no", + eval "kde_cv_qt_jpeg=yes") +LIBS="$ac_save_LIBS" +CXXFLAGS="$ac_save_CXXFLAGS" +AC_LANG_RESTORE +fi +]) + +if eval "test ! \"`echo $kde_cv_qt_jpeg`\" = no"; then + AC_MSG_RESULT(yes) + LIBJPEG_QT='$(LIBJPEG)' +else + AC_MSG_RESULT(no) + LIBJPEG_QT= +fi + +]) + +AC_DEFUN([AC_FIND_ZLIB], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_MSG_CHECKING([for libz]) +AC_CACHE_VAL(ac_cv_lib_z, +[ +kde_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS -lz $LIBSOCKET" +kde_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK(dnl +[ +#include +], +[ + char buf[42]; + gzFile f = (gzFile) 0; + /* this would segfault.. but we only link, don't run */ + (void) gzgets(f, buf, sizeof(buf)); + + return (zlibVersion() == ZLIB_VERSION); +], + eval "ac_cv_lib_z='-lz'", + eval "ac_cv_lib_z=no") +LIBS="$kde_save_LIBS" +CFLAGS="$kde_save_CFLAGS" +])dnl +if test ! "$ac_cv_lib_z" = no; then + AC_DEFINE_UNQUOTED(HAVE_LIBZ, 1, [Define if you have libz]) + LIBZ="$ac_cv_lib_z" + AC_MSG_RESULT($ac_cv_lib_z) +else + AC_MSG_ERROR(not found. + Possibly configure picks up an outdated version + installed by XFree86. Remove it from your system. + + Check your installation and look into config.log) + LIBZ="" +fi +AC_SUBST(LIBZ) +]) + +AC_DEFUN([KDE_TRY_TIFFLIB], +[ +AC_MSG_CHECKING([for libtiff $1]) + +AC_CACHE_VAL(kde_cv_libtiff_$1, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +kde_save_LIBS="$LIBS" +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBS="$all_libraries $USER_LDFLAGS -l$1 $LIBJPEG $LIBZ -lX11 $LIBSOCKET -lm" +else +LIBS="$all_libraries $USER_LDFLAGS -l$1 $LIBJPEG $LIBZ -lm" +fi +kde_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES" + +AC_TRY_LINK(dnl +[ +#include +], + [return (TIFFOpen( "", "r") == 0); ], +[ + kde_cv_libtiff_$1="-l$1 $LIBJPEG $LIBZ" +], [ + kde_cv_libtiff_$1=no +]) + +LIBS="$kde_save_LIBS" +CXXFLAGS="$kde_save_CXXFLAGS" +AC_LANG_RESTORE +]) + +if test "$kde_cv_libtiff_$1" = "no"; then + AC_MSG_RESULT(no) + LIBTIFF="" + $3 +else + LIBTIFF="$kde_cv_libtiff_$1" + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_LIBTIFF, 1, [Define if you have libtiff]) + $2 +fi + +]) + +AC_DEFUN([AC_FIND_TIFF], +[ +AC_REQUIRE([K_PATH_X]) +AC_REQUIRE([AC_FIND_ZLIB]) +AC_REQUIRE([AC_FIND_JPEG]) +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + +KDE_TRY_TIFFLIB(tiff, [], + KDE_TRY_TIFFLIB(tiff34)) + +AC_SUBST(LIBTIFF) +]) + + +AC_DEFUN([AC_FIND_PNG], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_REQUIRE([AC_FIND_ZLIB]) +AC_MSG_CHECKING([for libpng]) +AC_CACHE_VAL(ac_cv_lib_png, +[ +kde_save_LIBS="$LIBS" +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBS="$LIBS $all_libraries $USER_LDFLAGS -lpng $LIBZ -lm -lX11 $LIBSOCKET" +else +LIBS="$LIBS $all_libraries $USER_LDFLAGS -lpng $LIBZ -lm" +fi +kde_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" + +AC_TRY_LINK(dnl + [ + #include + ], + [ + png_structp png_ptr = png_create_read_struct( /* image ptr */ + PNG_LIBPNG_VER_STRING, 0, 0, 0 ); + return( png_ptr != 0 ); + ], + eval "ac_cv_lib_png='-lpng $LIBZ -lm'", + eval "ac_cv_lib_png=no" +) +LIBS="$kde_save_LIBS" +CFLAGS="$kde_save_CFLAGS" +])dnl +if eval "test ! \"`echo $ac_cv_lib_png`\" = no"; then + AC_DEFINE_UNQUOTED(HAVE_LIBPNG, 1, [Define if you have libpng]) + LIBPNG="$ac_cv_lib_png" + AC_SUBST(LIBPNG) + AC_MSG_RESULT($ac_cv_lib_png) +else + AC_MSG_RESULT(no) + LIBPNG="" + AC_SUBST(LIBPNG) +fi +]) + + +AC_DEFUN([AC_FIND_JASPER], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_REQUIRE([AC_FIND_JPEG]) +AC_MSG_CHECKING([for jasper]) +AC_CACHE_VAL(ac_cv_jasper, +[ +kde_save_LIBS="$LIBS" +LIBS="$LIBS $all_libraries $USER_LDFLAGS -ljasper $LIBJPEG -lm" +kde_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" + +AC_TRY_LINK(dnl + [ + #include + ], + [ + return( jas_init() ); + ], + eval "ac_cv_jasper='-ljasper $LIBJPEG -lm'", + eval "ac_cv_jasper=no" +) +LIBS="$kde_save_LIBS" +CFLAGS="$kde_save_CFLAGS" +])dnl +if eval "test ! \"`echo $ac_cv_jasper`\" = no"; then + AC_DEFINE_UNQUOTED(HAVE_JASPER, 1, [Define if you have jasper]) + LIB_JASPER="$ac_cv_jasper" + AC_MSG_RESULT($ac_cv_jasper) +else + AC_MSG_RESULT(no) + LIB_JASPER="" +fi +AC_SUBST(LIB_JASPER) +]) + +AC_DEFUN([AC_CHECK_BOOL], +[ + AC_DEFINE_UNQUOTED(HAVE_BOOL, 1, [You _must_ have bool]) +]) + +AC_DEFUN([AC_CHECK_GNU_EXTENSIONS], +[ +AC_MSG_CHECKING(if you need GNU extensions) +AC_CACHE_VAL(ac_cv_gnu_extensions, +[ +cat > conftest.c << EOF +#include + +#ifdef __GNU_LIBRARY__ +yes +#endif +EOF + +if (eval "$ac_cpp conftest.c") 2>&5 | + egrep "yes" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_gnu_extensions=yes +else + ac_cv_gnu_extensions=no +fi +]) + +AC_MSG_RESULT($ac_cv_gnu_extensions) +if test "$ac_cv_gnu_extensions" = "yes"; then + AC_DEFINE_UNQUOTED(_GNU_SOURCE, 1, [Define if you need to use the GNU extensions]) +fi +]) + +AC_DEFUN([KDE_CHECK_COMPILER_FLAG], +[ +AC_MSG_CHECKING([whether $CXX supports -$1]) +kde_cache=`echo $1 | sed 'y% .=/+-,%____p__%'` +AC_CACHE_VAL(kde_cv_prog_cxx_$kde_cache, +[ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -$1" + AC_TRY_LINK([],[ return 0; ], [eval "kde_cv_prog_cxx_$kde_cache=yes"], []) + CXXFLAGS="$save_CXXFLAGS" + AC_LANG_RESTORE +]) +if eval "test \"`echo '$kde_cv_prog_cxx_'$kde_cache`\" = yes"; then + AC_MSG_RESULT(yes) + : + $2 +else + AC_MSG_RESULT(no) + : + $3 +fi +]) + +AC_DEFUN([KDE_CHECK_C_COMPILER_FLAG], +[ +AC_MSG_CHECKING([whether $CC supports -$1]) +kde_cache=`echo $1 | sed 'y% .=/+-,%____p__%'` +AC_CACHE_VAL(kde_cv_prog_cc_$kde_cache, +[ + AC_LANG_SAVE + AC_LANG_C + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -$1" + AC_TRY_LINK([],[ return 0; ], [eval "kde_cv_prog_cc_$kde_cache=yes"], []) + CFLAGS="$save_CFLAGS" + AC_LANG_RESTORE +]) +if eval "test \"`echo '$kde_cv_prog_cc_'$kde_cache`\" = yes"; then + AC_MSG_RESULT(yes) + : + $2 +else + AC_MSG_RESULT(no) + : + $3 +fi +]) + + +dnl AC_REMOVE_FORBIDDEN removes forbidden arguments from variables +dnl use: AC_REMOVE_FORBIDDEN(CC, [-forbid -bad-option whatever]) +dnl it's all white-space separated +AC_DEFUN([AC_REMOVE_FORBIDDEN], +[ __val=$$1 + __forbid=" $2 " + if test -n "$__val"; then + __new="" + ac_save_IFS=$IFS + IFS=" " + for i in $__val; do + case "$__forbid" in + *" $i "*) AC_MSG_WARN([found forbidden $i in $1, removing it]) ;; + *) # Careful to not add spaces, where there were none, because otherwise + # libtool gets confused, if we change e.g. CXX + if test -z "$__new" ; then __new=$i ; else __new="$__new $i" ; fi ;; + esac + done + IFS=$ac_save_IFS + $1=$__new + fi +]) + +dnl AC_VALIDIFY_CXXFLAGS checks for forbidden flags the user may have given +AC_DEFUN([AC_VALIDIFY_CXXFLAGS], +[dnl +if test "x$kde_use_qt_emb" != "xyes"; then + AC_REMOVE_FORBIDDEN(CXX, [-fno-rtti -rpath]) + AC_REMOVE_FORBIDDEN(CXXFLAGS, [-fno-rtti -rpath]) +else + AC_REMOVE_FORBIDDEN(CXX, [-rpath]) + AC_REMOVE_FORBIDDEN(CXXFLAGS, [-rpath]) +fi +]) + +AC_DEFUN([AC_CHECK_COMPILERS], +[ + AC_ARG_ENABLE(debug, + AC_HELP_STRING([--enable-debug=ARG],[enables debug symbols (yes|no|full) [default=no]]), + [ + case $enableval in + yes) + kde_use_debug_code="yes" + kde_use_debug_define=no + ;; + full) + kde_use_debug_code="full" + kde_use_debug_define=no + ;; + *) + kde_use_debug_code="no" + kde_use_debug_define=yes + ;; + esac + ], + [kde_use_debug_code="no" + kde_use_debug_define=no + ]) + + dnl Just for configure --help + AC_ARG_ENABLE(dummyoption, + AC_HELP_STRING([--disable-debug], + [disables debug output and debug symbols [default=no]]), + [],[]) + + AC_ARG_ENABLE(strict, + AC_HELP_STRING([--enable-strict], + [compiles with strict compiler options (may not work!)]), + [ + if test $enableval = "no"; then + kde_use_strict_options="no" + else + kde_use_strict_options="yes" + fi + ], [kde_use_strict_options="no"]) + + AC_ARG_ENABLE(warnings,AC_HELP_STRING([--disable-warnings],[disables compilation with -Wall and similar]), + [ + if test $enableval = "no"; then + kde_use_warnings="no" + else + kde_use_warnings="yes" + fi + ], [kde_use_warnings="yes"]) + + dnl enable warnings for debug build + if test "$kde_use_debug_code" != "no"; then + kde_use_warnings=yes + fi + + AC_ARG_ENABLE(profile,AC_HELP_STRING([--enable-profile],[creates profiling infos [default=no]]), + [kde_use_profiling=$enableval], + [kde_use_profiling="no"] + ) + + dnl this prevents stupid AC_PROG_CC to add "-g" to the default CFLAGS + CFLAGS=" $CFLAGS" + + AC_PROG_CC + + AC_PROG_CPP + + if test "$GCC" = "yes"; then + if test "$kde_use_debug_code" != "no"; then + if test $kde_use_debug_code = "full"; then + CFLAGS="-g3 -fno-inline $CFLAGS" + else + CFLAGS="-g -O2 $CFLAGS" + fi + else + CFLAGS="-O2 $CFLAGS" + fi + fi + + if test "$kde_use_debug_define" = "yes"; then + CFLAGS="-DNDEBUG $CFLAGS" + fi + + + case "$host" in + *-*-sysv4.2uw*) CFLAGS="-D_UNIXWARE $CFLAGS";; + *-*-sysv5uw7*) CFLAGS="-D_UNIXWARE7 $CFLAGS";; + esac + + if test -z "$LDFLAGS" && test "$kde_use_debug_code" = "no" && test "$GCC" = "yes"; then + LDFLAGS="" + fi + + CXXFLAGS=" $CXXFLAGS" + + AC_PROG_CXX + + if test "$GXX" = "yes" || test "$CXX" = "KCC"; then + if test "$kde_use_debug_code" != "no"; then + if test "$CXX" = "KCC"; then + CXXFLAGS="+K0 -Wall -pedantic -W -Wpointer-arith -Wwrite-strings $CXXFLAGS" + else + if test "$kde_use_debug_code" = "full"; then + CXXFLAGS="-g3 -fno-inline $CXXFLAGS" + else + CXXFLAGS="-g -O2 $CXXFLAGS" + fi + fi + KDE_CHECK_COMPILER_FLAG(fno-builtin,[CXXFLAGS="-fno-builtin $CXXFLAGS"]) + + dnl convenience compiler flags + KDE_CHECK_COMPILER_FLAG(Woverloaded-virtual, [WOVERLOADED_VIRTUAL="-Woverloaded-virtual"], [WOVERLOADED_VRITUAL=""]) + AC_SUBST(WOVERLOADED_VIRTUAL) + else + if test "$CXX" = "KCC"; then + CXXFLAGS="+K3 $CXXFLAGS" + else + CXXFLAGS="-O2 $CXXFLAGS" + fi + fi + fi + + if test "$kde_use_debug_define" = "yes"; then + CXXFLAGS="-DNDEBUG -DNO_DEBUG $CXXFLAGS" + fi + + if test "$kde_use_profiling" = "yes"; then + KDE_CHECK_COMPILER_FLAG(pg, + [ + CFLAGS="-pg $CFLAGS" + CXXFLAGS="-pg $CXXFLAGS" + ]) + fi + + if test "$kde_use_warnings" = "yes"; then + if test "$GCC" = "yes"; then + CXXFLAGS="-Wall -W -Wpointer-arith -Wwrite-strings $CXXFLAGS" + case $host in + *-*-linux-gnu) + CFLAGS="-std=iso9899:1990 -W -Wall -Wchar-subscripts -Wshadow -Wpointer-arith -Wmissing-prototypes -Wwrite-strings -D_XOPEN_SOURCE=500 -D_BSD_SOURCE $CFLAGS" + CXXFLAGS="-ansi -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wcast-align -Wconversion -Wchar-subscripts $CXXFLAGS" + KDE_CHECK_COMPILER_FLAG(Wmissing-format-attribute, [CXXFLAGS="$CXXFLAGS -Wformat-security -Wmissing-format-attribute"]) + KDE_CHECK_C_COMPILER_FLAG(Wmissing-format-attribute, [CFLAGS="$CFLAGS -Wformat-security -Wmissing-format-attribute"]) + ;; + esac + KDE_CHECK_COMPILER_FLAG(Wundef,[CXXFLAGS="-Wundef $CXXFLAGS"]) + KDE_CHECK_COMPILER_FLAG(Wno-long-long,[CXXFLAGS="-Wno-long-long $CXXFLAGS"]) + KDE_CHECK_COMPILER_FLAG(Wnon-virtual-dtor,[CXXFLAGS="-Wnon-virtual-dtor $CXXFLAGS"]) + fi + fi + + if test "$GXX" = "yes" && test "$kde_use_strict_options" = "yes"; then + CXXFLAGS="-Wcast-qual -Wshadow -Wcast-align $CXXFLAGS" + fi + + AC_ARG_ENABLE(pch, + AC_HELP_STRING([--enable-pch], + [enables precompiled header support (currently only KCC or gcc >=3.4+unsermake) [default=no]]), + [ kde_use_pch=$enableval ],[ kde_use_pch=no ]) + + HAVE_GCC_VISIBILITY=0 + AC_SUBST([HAVE_GCC_VISIBILITY]) + + if test "$GXX" = "yes"; then + KDE_CHECK_COMPILER_FLAG(fno-exceptions,[CXXFLAGS="$CXXFLAGS -fno-exceptions"]) + KDE_CHECK_COMPILER_FLAG(fno-check-new, [CXXFLAGS="$CXXFLAGS -fno-check-new"]) + KDE_CHECK_COMPILER_FLAG(fno-common, [CXXFLAGS="$CXXFLAGS -fno-common"]) + KDE_CHECK_COMPILER_FLAG(fexceptions, [USE_EXCEPTIONS="-fexceptions"], USE_EXCEPTIONS= ) + ENABLE_PERMISSIVE_FLAG="-fpermissive" + + if test "$kde_use_pch" = "yes"; then + AC_MSG_CHECKING(whether gcc supports precompiling c header files) + echo >conftest.h + if $CC -x c-header conftest.h >/dev/null 2>/dev/null; then + kde_gcc_supports_pch=yes + AC_MSG_RESULT(yes) + else + kde_gcc_supports_pch=no + AC_MSG_RESULT(no) + fi + if test "$kde_gcc_supports_pch" = "yes"; then + AC_MSG_CHECKING(whether gcc supports precompiling c++ header files) + if $CXX -x c++-header conftest.h >/dev/null 2>/dev/null; then + kde_gcc_supports_pch=yes + AC_MSG_RESULT(yes) + else + kde_gcc_supports_pch=no + AC_MSG_RESULT(no) + fi + fi + rm -f conftest.h conftest.h.gch + fi + AM_CONDITIONAL(unsermake_enable_pch, test "$kde_use_pch" = "yes" && test "$kde_gcc_supports_pch" = "yes") + fi + if test "$CXX" = "KCC"; then + dnl unfortunately we currently cannot disable exception support in KCC + dnl because doing so is binary incompatible and Qt by default links with exceptions :-( + dnl KDE_CHECK_COMPILER_FLAG(-no_exceptions,[CXXFLAGS="$CXXFLAGS --no_exceptions"]) + dnl KDE_CHECK_COMPILER_FLAG(-exceptions, [USE_EXCEPTIONS="--exceptions"], USE_EXCEPTIONS= ) + + if test "$kde_use_pch" = "yes"; then + dnl TODO: support --pch-dir! + KDE_CHECK_COMPILER_FLAG(-pch,[CXXFLAGS="$CXXFLAGS --pch"]) + dnl the below works (but the dir must exist), but it's + dnl useless for a whole package. + dnl The are precompiled headers for each source file, so when compiling + dnl from scratch, it doesn't make a difference, and they take up + dnl around ~5Mb _per_ sourcefile. + dnl KDE_CHECK_COMPILER_FLAG(-pch_dir /tmp, + dnl [CXXFLAGS="$CXXFLAGS --pch_dir `pwd`/pcheaders"]) + fi + dnl this flag controls inlining. by default KCC inlines in optimisation mode + dnl all implementations that are defined inside the class {} declaration. + dnl because of templates-compatibility with broken gcc compilers, this + dnl can cause excessive inlining. This flag limits it to a sane level + KDE_CHECK_COMPILER_FLAG(-inline_keyword_space_time=6,[CXXFLAGS="$CXXFLAGS --inline_keyword_space_time=6"]) + KDE_CHECK_COMPILER_FLAG(-inline_auto_space_time=2,[CXXFLAGS="$CXXFLAGS --inline_auto_space_time=2"]) + KDE_CHECK_COMPILER_FLAG(-inline_implicit_space_time=2.0,[CXXFLAGS="$CXXFLAGS --inline_implicit_space_time=2.0"]) + KDE_CHECK_COMPILER_FLAG(-inline_generated_space_time=2.0,[CXXFLAGS="$CXXFLAGS --inline_generated_space_time=2.0"]) + dnl Some source files are shared between multiple executables + dnl (or libraries) and some of those need template instantiations. + dnl In that case KCC needs to compile those sources with + dnl --one_instantiation_per_object. To make it easy for us we compile + dnl _all_ objects with that flag (--one_per is a shorthand). + KDE_CHECK_COMPILER_FLAG(-one_per, [CXXFLAGS="$CXXFLAGS --one_per"]) + fi + AC_SUBST(USE_EXCEPTIONS) + dnl obsolete macro - provided to keep things going + USE_RTTI= + AC_SUBST(USE_RTTI) + + case "$host" in + *-*-irix*) test "$GXX" = yes && CXXFLAGS="-D_LANGUAGE_C_PLUS_PLUS -D__LANGUAGE_C_PLUS_PLUS $CXXFLAGS" ;; + *-*-sysv4.2uw*) CXXFLAGS="-D_UNIXWARE $CXXFLAGS";; + *-*-sysv5uw7*) CXXFLAGS="-D_UNIXWARE7 $CXXFLAGS";; + *-*-solaris*) + if test "$GXX" = yes; then + libstdcpp=`$CXX -print-file-name=libstdc++.so` + if test ! -f $libstdcpp; then + AC_MSG_ERROR([You've compiled gcc without --enable-shared. This doesn't work with KDE. Please recompile gcc with --enable-shared to receive a libstdc++.so]) + fi + fi + ;; + esac + + AC_VALIDIFY_CXXFLAGS + + AC_PROG_CXXCPP + + if test "$GCC" = yes; then + NOOPT_CFLAGS=-O0 + fi + KDE_CHECK_COMPILER_FLAG(O0,[NOOPT_CXXFLAGS=-O0]) + + AC_ARG_ENABLE(coverage, + AC_HELP_STRING([--enable-coverage],[use gcc coverage testing]), [ + if test "$am_cv_CC_dependencies_compiler_type" = "gcc3"; then + ac_coverage_compiler="-fprofile-arcs -ftest-coverage" + ac_coverage_linker="-lgcc" + elif test "$am_cv_CC_dependencies_compiler_type" = "gcc"; then + ac_coverage_compiler="-fprofile-arcs -ftest-coverage" + ac_coverage_linker="" + else + AC_MSG_ERROR([coverage with your compiler is not supported]) + fi + CFLAGS="$CFLAGS $ac_coverage_compiler" + CXXFLAGS="$CXXFLAGS $ac_coverage_compiler" + LDFLAGS="$LDFLAGS $ac_coverage_linker" + ]) + + AC_SUBST(NOOPT_CXXFLAGS) + AC_SUBST(NOOPT_CFLAGS) + AC_SUBST(ENABLE_PERMISSIVE_FLAG) + + KDE_CHECK_NEW_LDFLAGS + KDE_CHECK_FINAL + KDE_CHECK_CLOSURE + KDE_CHECK_NMCHECK + + ifdef([AM_DEPENDENCIES], AC_REQUIRE([KDE_ADD_DEPENDENCIES]), []) +]) + +AC_DEFUN([KDE_CHECK_VISIBILITY_GCC_BUG], + [ + AC_CACHE_CHECK([for gcc -fvisibility-inlines-hidden bug], kde_cv_val_gcc_visibility_bug, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + + safe_CXXFLAGS=$CXXFLAGS + safe_LDFLAGS=$LDFLAGS + CXXFLAGS="$CXXFLAGS -fPIC -fvisibility-inlines-hidden -O0" + LDFLAGS="$LDFLAGS -shared -fPIC" + + AC_TRY_LINK( + [ + /* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19664 */ + template + struct VisTest + { + inline VisTest (); + }; + template + inline VisTest::VisTest() + {} + extern template class VisTest; // It works if we drop that line + int some_function( int do_something ) __attribute__ ((visibility("default"))); + int some_function( int ) + { + VisTest a; + return 0; + } + ], [/* elvis is alive */], + kde_cv_val_gcc_visibility_bug=no, kde_cv_val_gcc_visibility_bug=yes) + + CXXFLAGS=$safe_CXXFLAGS + LDFLAGS=$safe_LDFLAGS + AC_LANG_RESTORE + ] + ) + + if test x$kde_cv_val_gcc_visibility_bug = xno; then + CXXFLAGS="$CXXFLAGS -fvisibility-inlines-hidden" + fi + ] +) + +AC_DEFUN([KDE_CHECK_AND_ADD_HIDDEN_VISIBILITY], +[ + if test "$GXX" = "yes"; then + KDE_CHECK_COMPILER_FLAG(fno-exceptions,[CXXFLAGS="$CXXFLAGS -fno-exceptions"]) + KDE_CHECK_COMPILER_FLAG(fno-check-new, [CXXFLAGS="$CXXFLAGS -fno-check-new"]) + KDE_CHECK_COMPILER_FLAG(fno-common, [CXXFLAGS="$CXXFLAGS -fno-common"]) + KDE_CHECK_COMPILER_FLAG(fvisibility=hidden, + [ + CXXFLAGS="$CXXFLAGS -fvisibility=hidden" + KDE_CHECK_VISIBILITY_GCC_BUG + + HAVE_GCC_VISIBILITY=1 + AC_DEFINE_UNQUOTED(__KDE_HAVE_GCC_VISIBILITY, "$HAVE_GCC_VISIBILITY", [define to 1 if -fvisibility is supported]) + ]) + fi +]) + +AC_DEFUN([KDE_ENABLE_HIDDEN_VISIBILITY], +[ + AC_REQUIRE([KDE_CHECK_AND_ADD_HIDDEN_VISIBILITY]) +]) + +AC_DEFUN([KDE_ADD_DEPENDENCIES], +[ + [A]M_DEPENDENCIES(CC) + [A]M_DEPENDENCIES(CXX) +]) + +dnl just a wrapper to clean up configure.in +AC_DEFUN([KDE_PROG_LIBTOOL], +[ +AC_REQUIRE([AC_CHECK_COMPILERS]) +AC_REQUIRE([AC_ENABLE_SHARED]) +AC_REQUIRE([AC_ENABLE_STATIC]) + +AC_REQUIRE([AC_LIBTOOL_DLOPEN]) +AC_REQUIRE([KDE_CHECK_LIB64]) + +AC_OBJEXT +AC_EXEEXT + +AM_PROG_LIBTOOL +AC_LIBTOOL_CXX + +LIBTOOL_SHELL="/bin/sh ./libtool" +# LIBTOOL="$LIBTOOL --silent" +KDE_PLUGIN="-avoid-version -module -no-undefined \$(KDE_NO_UNDEFINED) \$(KDE_RPATH) \$(KDE_MT_LDFLAGS)" +AC_SUBST(KDE_PLUGIN) + +# we patch configure quite some so we better keep that consistent for incremental runs +AC_SUBST(AUTOCONF,'$(SHELL) $(top_srcdir)/admin/cvs.sh configure || touch configure') +]) + +AC_DEFUN([KDE_CHECK_LIB64], +[ + kdelibsuff="$kde_libs_suffix" + if test -z "$kdelibsuff"; then + kdelibsuff=no + fi + AC_ARG_ENABLE(libsuffix, + AC_HELP_STRING([--enable-libsuffix], + [/lib directory suffix (64,32,none[=default])]), + kdelibsuff=$enableval) + # TODO: add an auto case that compiles a little C app to check + # where the glibc is + if test "$kdelibsuff" = "no"; then + kdelibsuff= + fi + if test -z "$kdelibsuff"; then + AC_MSG_RESULT([not using lib directory suffix]) + AC_DEFINE(KDELIBSUFF, [""], Suffix for lib directories) + else + if test "$libdir" = '${exec_prefix}/lib'; then + libdir="$libdir${kdelibsuff}" + AC_SUBST([libdir], ["$libdir"]) dnl ugly hack for lib64 platforms + fi + AC_DEFINE_UNQUOTED(KDELIBSUFF, ["${kdelibsuff}"], Suffix for lib directories) + AC_MSG_RESULT([using lib directory suffix $kdelibsuff]) + fi +]) + +AC_DEFUN([KDE_CHECK_TYPES], +[ AC_CHECK_SIZEOF(int, 4)dnl + AC_CHECK_SIZEOF(short)dnl + AC_CHECK_SIZEOF(long, 4)dnl + AC_CHECK_SIZEOF(char *, 4)dnl +])dnl + +dnl Not used - kept for compat only? +AC_DEFUN([KDE_DO_IT_ALL], +[ +AC_CANONICAL_SYSTEM +AC_ARG_PROGRAM +AM_INIT_AUTOMAKE($1, $2) +AM_DISABLE_LIBRARIES +AC_PREFIX_DEFAULT(${KDEDIR:-/usr/local/kde}) +AC_CHECK_COMPILERS +KDE_PROG_LIBTOOL +AM_KDE_WITH_NLS +AC_PATH_KDE +]) + +AC_DEFUN([AC_CHECK_RPATH], +[ +AC_MSG_CHECKING(for rpath) +AC_ARG_ENABLE(rpath, + AC_HELP_STRING([--disable-rpath],[do not use the rpath feature of ld]), + USE_RPATH=$enableval, USE_RPATH=yes) + +if test -z "$KDE_RPATH" && test "$USE_RPATH" = "yes"; then + + KDE_RPATH="-R \$(libdir)" + + if test "$kde_libraries" != "$libdir"; then + KDE_RPATH="$KDE_RPATH -R \$(kde_libraries)" + fi + + if test -n "$qt_libraries"; then + KDE_RPATH="$KDE_RPATH -R \$(qt_libraries)" + fi + dnl $x_libraries is set to /usr/lib in case + if test -n "$X_LDFLAGS"; then + X_RPATH="-R \$(x_libraries)" + KDE_RPATH="$KDE_RPATH $X_RPATH" + fi + if test -n "$KDE_EXTRA_RPATH"; then + KDE_RPATH="$KDE_RPATH \$(KDE_EXTRA_RPATH)" + fi +fi +AC_SUBST(KDE_EXTRA_RPATH) +AC_SUBST(KDE_RPATH) +AC_SUBST(X_RPATH) +AC_MSG_RESULT($USE_RPATH) +]) + +dnl Check for the type of the third argument of getsockname +AC_DEFUN([AC_CHECK_SOCKLEN_T], +[ + AC_MSG_CHECKING(for socklen_t) + AC_CACHE_VAL(kde_cv_socklen_t, + [ + AC_LANG_PUSH(C++) + kde_cv_socklen_t=no + AC_TRY_COMPILE([ + #include + #include + ], + [ + socklen_t len; + getpeername(0,0,&len); + ], + [ + kde_cv_socklen_t=yes + kde_cv_socklen_t_equiv=socklen_t + ]) + AC_LANG_POP(C++) + ]) + AC_MSG_RESULT($kde_cv_socklen_t) + if test $kde_cv_socklen_t = no; then + AC_MSG_CHECKING([for socklen_t equivalent for socket functions]) + AC_CACHE_VAL(kde_cv_socklen_t_equiv, + [ + kde_cv_socklen_t_equiv=int + AC_LANG_PUSH(C++) + for t in int size_t unsigned long "unsigned long"; do + AC_TRY_COMPILE([ + #include + #include + ], + [ + $t len; + getpeername(0,0,&len); + ], + [ + kde_cv_socklen_t_equiv="$t" + break + ]) + done + AC_LANG_POP(C++) + ]) + AC_MSG_RESULT($kde_cv_socklen_t_equiv) + fi + AC_DEFINE_UNQUOTED(kde_socklen_t, $kde_cv_socklen_t_equiv, + [type to use in place of socklen_t if not defined]) + AC_DEFINE_UNQUOTED(ksize_t, $kde_cv_socklen_t_equiv, + [type to use in place of socklen_t if not defined (deprecated, use kde_socklen_t)]) +]) + +dnl This is a merge of some macros out of the gettext aclocal.m4 +dnl since we don't need anything, I took the things we need +dnl the copyright for them is: +dnl > +dnl Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +dnl This Makefile.in is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. +dnl > +dnl for this file it is relicensed under LGPL + +AC_DEFUN([AM_KDE_WITH_NLS], + [ + dnl If we use NLS figure out what method + + AM_PATH_PROG_WITH_TEST_KDE(MSGFMT, msgfmt, + [test -n "`$ac_dir/$ac_word --version 2>&1 | grep 'GNU gettext'`"], msgfmt) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + + if test -z "`$GMSGFMT --version 2>&1 | grep 'GNU gettext'`"; then + AC_MSG_RESULT([found msgfmt program is not GNU msgfmt; ignore it]) + GMSGFMT=":" + fi + MSGFMT=$GMSGFMT + AC_SUBST(GMSGFMT) + AC_SUBST(MSGFMT) + + AM_PATH_PROG_WITH_TEST_KDE(XGETTEXT, xgettext, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) + + dnl Test whether we really found GNU xgettext. + if test "$XGETTEXT" != ":"; then + dnl If it is no GNU xgettext we define it as : so that the + dnl Makefiles still can work. + if $XGETTEXT --omit-header /dev/null 2> /dev/null; then + : ; + else + AC_MSG_RESULT( + [found xgettext programs is not GNU xgettext; ignore it]) + XGETTEXT=":" + fi + fi + AC_SUBST(XGETTEXT) + + ]) + +# Search path for a program which passes the given test. +# Ulrich Drepper , 1996. + +# serial 1 +# Stephan Kulow: I appended a _KDE against name conflicts + +dnl AM_PATH_PROG_WITH_TEST_KDE(VARIABLE, PROG-TO-CHECK-FOR, +dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN([AM_PATH_PROG_WITH_TEST_KDE], +[# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_path_$1, +[case "[$]$1" in + /*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in ifelse([$5], , $PATH, [$5]); do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if [$3]; then + ac_cv_path_$1="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test -n "[$]$1"; then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) + + +# Check whether LC_MESSAGES is available in . +# Ulrich Drepper , 1995. + +# serial 1 + +AC_DEFUN([AM_LC_MESSAGES], + [if test $ac_cv_header_locale_h = yes; then + AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, + [AC_TRY_LINK([#include ], [return LC_MESSAGES], + am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) + if test $am_cv_val_LC_MESSAGES = yes; then + AC_DEFINE(HAVE_LC_MESSAGES, 1, [Define if your locale.h file contains LC_MESSAGES]) + fi + fi]) + +dnl From Jim Meyering. +dnl FIXME: migrate into libit. + +AC_DEFUN([AM_FUNC_OBSTACK], +[AC_CACHE_CHECK([for obstacks], am_cv_func_obstack, + [AC_TRY_LINK([#include "obstack.h"], + [struct obstack *mem;obstack_free(mem,(char *) 0)], + am_cv_func_obstack=yes, + am_cv_func_obstack=no)]) + if test $am_cv_func_obstack = yes; then + AC_DEFINE(HAVE_OBSTACK) + else + LIBOBJS="$LIBOBJS obstack.o" + fi +]) + +dnl From Jim Meyering. Use this if you use the GNU error.[ch]. +dnl FIXME: Migrate into libit + +AC_DEFUN([AM_FUNC_ERROR_AT_LINE], +[AC_CACHE_CHECK([for error_at_line], am_cv_lib_error_at_line, + [AC_TRY_LINK([],[error_at_line(0, 0, "", 0, "");], + am_cv_lib_error_at_line=yes, + am_cv_lib_error_at_line=no)]) + if test $am_cv_lib_error_at_line = no; then + LIBOBJS="$LIBOBJS error.o" + fi + AC_SUBST(LIBOBJS)dnl +]) + +# Macro to add for using GNU gettext. +# Ulrich Drepper , 1995. + +# serial 1 +# Stephan Kulow: I put a KDE in it to avoid name conflicts + +AC_DEFUN([AM_KDE_GNU_GETTEXT], + [AC_REQUIRE([AC_PROG_MAKE_SET])dnl + AC_REQUIRE([AC_PROG_RANLIB])dnl + AC_REQUIRE([AC_HEADER_STDC])dnl + AC_REQUIRE([AC_TYPE_OFF_T])dnl + AC_REQUIRE([AC_TYPE_SIZE_T])dnl + AC_REQUIRE([AC_FUNC_ALLOCA])dnl + AC_REQUIRE([AC_FUNC_MMAP])dnl + AC_REQUIRE([AM_KDE_WITH_NLS])dnl + AC_CHECK_HEADERS([limits.h locale.h nl_types.h string.h values.h alloca.h]) + AC_CHECK_FUNCS([getcwd munmap putenv setlocale strchr strcasecmp \ +__argz_count __argz_stringify __argz_next]) + + AC_MSG_CHECKING(for stpcpy) + AC_CACHE_VAL(kde_cv_func_stpcpy, + [ + kde_safe_cxxflags=$CXXFLAGS + CXXFLAGS="-Werror" + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_COMPILE([ + #include + ], + [ + char buffer[200]; + stpcpy(buffer, buffer); + ], + kde_cv_func_stpcpy=yes, + kde_cv_func_stpcpy=no) + AC_LANG_RESTORE + CXXFLAGS=$kde_safe_cxxflags + ]) + AC_MSG_RESULT($kde_cv_func_stpcpy) + if eval "test \"`echo $kde_cv_func_stpcpy`\" = yes"; then + AC_DEFINE(HAVE_STPCPY, 1, [Define if you have stpcpy]) + fi + + AM_LC_MESSAGES + + if test "x$CATOBJEXT" != "x"; then + if test "x$ALL_LINGUAS" = "x"; then + LINGUAS= + else + AC_MSG_CHECKING(for catalogs to be installed) + NEW_LINGUAS= + for lang in ${LINGUAS=$ALL_LINGUAS}; do + case "$ALL_LINGUAS" in + *$lang*) NEW_LINGUAS="$NEW_LINGUAS $lang" ;; + esac + done + LINGUAS=$NEW_LINGUAS + AC_MSG_RESULT($LINGUAS) + fi + + dnl Construct list of names of catalog files to be constructed. + if test -n "$LINGUAS"; then + for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done + fi + fi + + ]) + +AC_DEFUN([AC_HAVE_XPM], + [AC_REQUIRE_CPP()dnl + AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + + test -z "$XPM_LDFLAGS" && XPM_LDFLAGS= + test -z "$XPM_INCLUDE" && XPM_INCLUDE= + + AC_ARG_WITH(xpm,AC_HELP_STRING([--without-xpm],[disable color pixmap XPM tests]), + xpm_test=$withval, xpm_test="yes") + if test "x$xpm_test" = xno; then + ac_cv_have_xpm=no + else + AC_MSG_CHECKING(for XPM) + AC_CACHE_VAL(ac_cv_have_xpm, + [ + ac_save_ldflags="$LDFLAGS" + ac_save_cflags="$CFLAGS" + if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then + LDFLAGS="$LDFLAGS $X_LDFLAGS $USER_LDFLAGS $LDFLAGS $XPM_LDFLAGS $all_libraries -lXpm -lX11 -lXext $LIBZ $LIBSOCKET" + else + LDFLAGS="$LDFLAGS $X_LDFLAGS $USER_LDFLAGS $LDFLAGS $XPM_LDFLAGS $all_libraries -lXpm $LIBZ $LIBSOCKET" + fi + CFLAGS="$CFLAGS $X_INCLUDES $USER_INCLUDES" + test -n "$XPM_INCLUDE" && CFLAGS="-I$XPM_INCLUDE $CFLAGS" + AC_TRY_LINK([#include ],[], + ac_cv_have_xpm="yes",ac_cv_have_xpm="no") + LDFLAGS="$ac_save_ldflags" + CFLAGS="$ac_save_cflags" + ])dnl + + if test "$ac_cv_have_xpm" = no; then + AC_MSG_RESULT(no) + XPM_LDFLAGS="" + XPMINC="" + $2 + else + AC_DEFINE(HAVE_XPM, 1, [Define if you have XPM support]) + if test "$XPM_LDFLAGS" = ""; then + XPMLIB='-lXpm $(LIB_X11)' + else + XPMLIB="-L$XPM_LDFLAGS -lXpm "'$(LIB_X11)' + fi + if test "$XPM_INCLUDE" = ""; then + XPMINC="" + else + XPMINC="-I$XPM_INCLUDE" + fi + AC_MSG_RESULT(yes) + $1 + fi + fi + AC_SUBST(XPMINC) + AC_SUBST(XPMLIB) +]) + +AC_DEFUN([AC_HAVE_DPMS], + [AC_REQUIRE_CPP()dnl + AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + + test -z "$DPMS_LDFLAGS" && DPMS_LDFLAGS= + test -z "$DPMS_INCLUDE" && DPMS_INCLUDE= + DPMS_LIB= + + AC_ARG_WITH(dpms,AC_HELP_STRING([--without-dpms],[disable DPMS power saving]), + dpms_test=$withval, dpms_test="yes") + if test "x$dpms_test" = xno; then + ac_cv_have_dpms=no + else + AC_MSG_CHECKING(for DPMS) + dnl Note: ac_cv_have_dpms can be no, yes, or -lXdpms. + dnl 'yes' means DPMS_LIB="", '-lXdpms' means DPMS_LIB="-lXdpms". + AC_CACHE_VAL(ac_cv_have_dpms, + [ + if test "x$kde_use_qt_emb" = "xyes" || test "x$kde_use_qt_mac" = "xyes"; then + AC_MSG_RESULT(no) + ac_cv_have_dpms="no" + else + ac_save_ldflags="$LDFLAGS" + ac_save_cflags="$CFLAGS" + ac_save_libs="$LIBS" + LDFLAGS="$LDFLAGS $DPMS_LDFLAGS $all_libraries -lX11 -lXext $LIBSOCKET" + CFLAGS="$CFLAGS $X_INCLUDES" + test -n "$DPMS_INCLUDE" && CFLAGS="-I$DPMS_INCLUDE $CFLAGS" + AC_TRY_LINK([ + #include + #include + #include + #include + int foo_test_dpms() + { return DPMSSetTimeouts( 0, 0, 0, 0 ); }],[], + ac_cv_have_dpms="yes", [ + LDFLAGS="$ac_save_ldflags" + CFLAGS="$ac_save_cflags" + LDFLAGS="$LDFLAGS $DPMS_LDFLAGS $all_libraries -lX11 -lXext $LIBSOCKET" + LIBS="$LIBS -lXdpms" + CFLAGS="$CFLAGS $X_INCLUDES" + test -n "$DPMS_INCLUDE" && CFLAGS="-I$DPMS_INCLUDE $CFLAGS" + AC_TRY_LINK([ + #include + #include + #include + #include + int foo_test_dpms() + { return DPMSSetTimeouts( 0, 0, 0, 0 ); }],[], + [ + ac_cv_have_dpms="-lXdpms" + ],ac_cv_have_dpms="no") + ]) + LDFLAGS="$ac_save_ldflags" + CFLAGS="$ac_save_cflags" + LIBS="$ac_save_libs" + fi + ])dnl + + if test "$ac_cv_have_dpms" = no; then + AC_MSG_RESULT(no) + DPMS_LDFLAGS="" + DPMSINC="" + $2 + else + AC_DEFINE(HAVE_DPMS, 1, [Define if you have DPMS support]) + if test "$ac_cv_have_dpms" = "-lXdpms"; then + DPMS_LIB="-lXdpms" + fi + if test "$DPMS_LDFLAGS" = ""; then + DPMSLIB="$DPMS_LIB "'$(LIB_X11)' + else + DPMSLIB="$DPMS_LDFLAGS $DPMS_LIB "'$(LIB_X11)' + fi + if test "$DPMS_INCLUDE" = ""; then + DPMSINC="" + else + DPMSINC="-I$DPMS_INCLUDE" + fi + AC_MSG_RESULT(yes) + $1 + fi + fi + ac_save_cflags="$CFLAGS" + CFLAGS="$CFLAGS $X_INCLUDES" + test -n "$DPMS_INCLUDE" && CFLAGS="-I$DPMS_INCLUDE $CFLAGS" + AH_TEMPLATE(HAVE_DPMSCAPABLE_PROTO, + [Define if you have the DPMSCapable prototype in ]) + AC_CHECK_DECL(DPMSCapable, + AC_DEFINE(HAVE_DPMSCAPABLE_PROTO),, + [#include ]) + AH_TEMPLATE(HAVE_DPMSINFO_PROTO, + [Define if you have the DPMSInfo prototype in ]) + AC_CHECK_DECL(DPMSInfo, + AC_DEFINE(HAVE_DPMSINFO_PROTO),, + [#include ]) + CFLAGS="$ac_save_cflags" + AC_SUBST(DPMSINC) + AC_SUBST(DPMSLIB) +]) + +AC_DEFUN([AC_HAVE_GL], + [AC_REQUIRE_CPP()dnl + AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + + test -z "$GL_LDFLAGS" && GL_LDFLAGS= + test -z "$GL_INCLUDE" && GL_INCLUDE= + + AC_ARG_WITH(gl,AC_HELP_STRING([--without-gl],[disable 3D GL modes]), + gl_test=$withval, gl_test="yes") + if test "x$kde_use_qt_emb" = "xyes"; then + # GL and Qt Embedded is a no-go for now. + ac_cv_have_gl=no + elif test "x$gl_test" = xno; then + ac_cv_have_gl=no + else + AC_MSG_CHECKING(for GL) + AC_CACHE_VAL(ac_cv_have_gl, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_ldflags="$LDFLAGS" + ac_save_cxxflags="$CXXFLAGS" + LDFLAGS="$LDFLAGS $GL_LDFLAGS $X_LDFLAGS $all_libraries -lGL -lGLU" + test "x$kde_use_qt_mac" != xyes && test "x$kde_use_qt_emb" != xyes && LDFLAGS="$LDFLAGS -lX11" + LDFLAGS="$LDFLAGS $LIB_XEXT -lm $LIBSOCKET" + CXXFLAGS="$CFLAGS $X_INCLUDES" + test -n "$GL_INCLUDE" && CFLAGS="-I$GL_INCLUDE $CFLAGS" + AC_TRY_LINK([#include +#include +], [], + ac_cv_have_gl="yes", ac_cv_have_gl="no") + AC_LANG_RESTORE + LDFLAGS="$ac_save_ldflags" + CXXFLAGS="$ac_save_cxxflags" + ])dnl + + if test "$ac_cv_have_gl" = "no"; then + AC_MSG_RESULT(no) + GL_LDFLAGS="" + GLINC="" + $2 + else + AC_DEFINE(HAVE_GL, 1, [Defines if you have GL (Mesa, OpenGL, ...)]) + if test "$GL_LDFLAGS" = ""; then + GLLIB='-lGLU -lGL $(LIB_X11)' + else + GLLIB="$GL_LDFLAGS -lGLU -lGL "'$(LIB_X11)' + fi + if test "$GL_INCLUDE" = ""; then + GLINC="" + else + GLINC="-I$GL_INCLUDE" + fi + AC_MSG_RESULT($ac_cv_have_gl) + $1 + fi + fi + AC_SUBST(GLINC) + AC_SUBST(GLLIB) +]) + + + dnl shadow password and PAM magic - maintained by ossi@kde.org + +AC_DEFUN([KDE_PAM], [ + AC_REQUIRE([KDE_CHECK_LIBDL]) + + want_pam= + AC_ARG_WITH(pam, + AC_HELP_STRING([--with-pam[=ARG]],[enable support for PAM: ARG=[yes|no|service name]]), + [ if test "x$withval" = "xyes"; then + want_pam=yes + pam_service=kde + elif test "x$withval" = "xno"; then + want_pam=no + else + want_pam=yes + pam_service=$withval + fi + ], [ pam_service=kde ]) + + use_pam= + PAMLIBS= + if test "x$want_pam" != xno; then + AC_CHECK_LIB(pam, pam_start, [ + AC_CHECK_HEADER(security/pam_appl.h, + [ pam_header=security/pam_appl.h ], + [ AC_CHECK_HEADER(pam/pam_appl.h, + [ pam_header=pam/pam_appl.h ], + [ + AC_MSG_WARN([PAM detected, but no headers found! +Make sure you have the necessary development packages installed.]) + ] + ) + ] + ) + ], , $LIBDL) + if test -z "$pam_header"; then + if test "x$want_pam" = xyes; then + AC_MSG_ERROR([--with-pam was specified, but cannot compile with PAM!]) + fi + else + AC_DEFINE(HAVE_PAM, 1, [Defines if you have PAM (Pluggable Authentication Modules)]) + PAMLIBS="$PAM_MISC_LIB -lpam $LIBDL" + use_pam=yes + + dnl darwin claims to be something special + if test "$pam_header" = "pam/pam_appl.h"; then + AC_DEFINE(HAVE_PAM_PAM_APPL_H, 1, [Define if your PAM headers are in pam/ instead of security/]) + fi + + dnl test whether struct pam_message is const (Linux) or not (Sun) + AC_MSG_CHECKING(for const pam_message) + AC_EGREP_HEADER([struct pam_message], $pam_header, + [ AC_EGREP_HEADER([const struct pam_message], $pam_header, + [AC_MSG_RESULT([const: Linux-type PAM])], + [AC_MSG_RESULT([nonconst: Sun-type PAM]) + AC_DEFINE(PAM_MESSAGE_NONCONST, 1, [Define if your PAM support takes non-const arguments (Solaris)])] + )], + [AC_MSG_RESULT([not found - assume const, Linux-type PAM])]) + fi + fi + + AC_SUBST(PAMLIBS) +]) + +dnl DEF_PAM_SERVICE(arg name, full name, define name) +AC_DEFUN([DEF_PAM_SERVICE], [ + AC_ARG_WITH($1-pam, + AC_HELP_STRING([--with-$1-pam=[val]],[override PAM service from --with-pam for $2]), + [ if test "x$use_pam" = xyes; then + $3_PAM_SERVICE=$withval + else + AC_MSG_ERROR([Cannot use use --with-$1-pam, as no PAM was detected. +You may want to enforce it by using --with-pam.]) + fi + ], + [ if test "x$use_pam" = xyes; then + $3_PAM_SERVICE="$pam_service" + fi + ]) + if test -n "$$3_PAM_SERVICE"; then + AC_MSG_RESULT([The PAM service used by $2 will be $$3_PAM_SERVICE]) + AC_DEFINE_UNQUOTED($3_PAM_SERVICE, "$$3_PAM_SERVICE", [The PAM service to be used by $2]) + fi + AC_SUBST($3_PAM_SERVICE) +]) + +AC_DEFUN([KDE_SHADOWPASSWD], [ + AC_REQUIRE([KDE_PAM]) + + AC_CHECK_LIB(shadow, getspent, + [ LIBSHADOW="-lshadow" + ac_use_shadow=yes + ], + [ dnl for UnixWare + AC_CHECK_LIB(gen, getspent, + [ LIBGEN="-lgen" + ac_use_shadow=yes + ], + [ AC_CHECK_FUNC(getspent, + [ ac_use_shadow=yes ], + [ ac_use_shadow=no ]) + ]) + ]) + AC_SUBST(LIBSHADOW) + AC_SUBST(LIBGEN) + + AC_MSG_CHECKING([for shadow passwords]) + + AC_ARG_WITH(shadow, + AC_HELP_STRING([--with-shadow],[If you want shadow password support]), + [ if test "x$withval" != "xno"; then + use_shadow=yes + else + use_shadow=no + fi + ], [ + use_shadow="$ac_use_shadow" + ]) + + if test "x$use_shadow" = xyes; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SHADOW, 1, [Define if you use shadow passwords]) + else + AC_MSG_RESULT(no) + LIBSHADOW= + LIBGEN= + fi + + dnl finally make the relevant binaries setuid root, if we have shadow passwds. + dnl this still applies, if we could use it indirectly through pam. + if test "x$use_shadow" = xyes || + ( test "x$use_pam" = xyes && test "x$ac_use_shadow" = xyes ); then + case $host in + *-*-freebsd* | *-*-netbsd* | *-*-openbsd*) + SETUIDFLAGS="-m 4755 -o root";; + *) + SETUIDFLAGS="-m 4755";; + esac + fi + AC_SUBST(SETUIDFLAGS) + +]) + +AC_DEFUN([KDE_PASSWDLIBS], [ + AC_REQUIRE([KDE_MISC_TESTS]) dnl for LIBCRYPT + AC_REQUIRE([KDE_PAM]) + AC_REQUIRE([KDE_SHADOWPASSWD]) + + if test "x$use_pam" = "xyes"; then + PASSWDLIBS="$PAMLIBS" + else + PASSWDLIBS="$LIBCRYPT $LIBSHADOW $LIBGEN" + fi + + dnl FreeBSD uses a shadow-like setup, where /etc/passwd holds the users, but + dnl /etc/master.passwd holds the actual passwords. /etc/master.passwd requires + dnl root to read, so kcheckpass needs to be root (even when using pam, since pam + dnl may need to read /etc/master.passwd). + case $host in + *-*-freebsd*) + SETUIDFLAGS="-m 4755 -o root" + ;; + *) + ;; + esac + + AC_SUBST(PASSWDLIBS) +]) + +AC_DEFUN([KDE_CHECK_LIBDL], +[ +AC_CHECK_LIB(dl, dlopen, [ +LIBDL="-ldl" +ac_cv_have_dlfcn=yes +]) + +AC_CHECK_LIB(dld, shl_unload, [ +LIBDL="-ldld" +ac_cv_have_shload=yes +]) + +AC_SUBST(LIBDL) +]) + +AC_DEFUN([KDE_CHECK_DLOPEN], +[ +KDE_CHECK_LIBDL +AC_CHECK_HEADERS(dlfcn.h dl.h) +if test "$ac_cv_header_dlfcn_h" = "no"; then + ac_cv_have_dlfcn=no +fi + +if test "$ac_cv_header_dl_h" = "no"; then + ac_cv_have_shload=no +fi + +dnl XXX why change enable_dlopen? its already set by autoconf's AC_ARG_ENABLE +dnl (MM) +AC_ARG_ENABLE(dlopen, +AC_HELP_STRING([--disable-dlopen],[link statically [default=no]]), +enable_dlopen=$enableval, +enable_dlopen=yes) + +# override the user's opinion, if we know it better ;) +if test "$ac_cv_have_dlfcn" = "no" && test "$ac_cv_have_shload" = "no"; then + enable_dlopen=no +fi + +if test "$ac_cv_have_dlfcn" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_DLFCN, 1, [Define if you have dlfcn]) +fi + +if test "$ac_cv_have_shload" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_SHLOAD, 1, [Define if you have shload]) +fi + +if test "$enable_dlopen" = no ; then + test -n "$1" && eval $1 +else + test -n "$2" && eval $2 +fi + +]) + +AC_DEFUN([KDE_CHECK_DYNAMIC_LOADING], +[ +KDE_CHECK_DLOPEN(libtool_enable_shared=yes, libtool_enable_static=no) +KDE_PROG_LIBTOOL +AC_MSG_CHECKING([dynamic loading]) +eval "`egrep '^build_libtool_libs=' libtool`" +if test "$build_libtool_libs" = "yes" && test "$enable_dlopen" = "yes"; then + dynamic_loading=yes + AC_DEFINE_UNQUOTED(HAVE_DYNAMIC_LOADING) +else + dynamic_loading=no +fi +AC_MSG_RESULT($dynamic_loading) +if test "$dynamic_loading" = "yes"; then + $1 +else + $2 +fi +]) + +AC_DEFUN([KDE_ADD_INCLUDES], +[ +if test -z "$1"; then + test_include="Pix.h" +else + test_include="$1" +fi + +AC_MSG_CHECKING([for libg++ ($test_include)]) + +AC_CACHE_VAL(kde_cv_libgpp_includes, +[ +kde_cv_libgpp_includes=no + + for ac_dir in \ + \ + /usr/include/g++ \ + /usr/include \ + /usr/unsupported/include \ + /opt/include \ + $extra_include \ + ; \ + do + if test -r "$ac_dir/$test_include"; then + kde_cv_libgpp_includes=$ac_dir + break + fi + done +]) + +AC_MSG_RESULT($kde_cv_libgpp_includes) +if test "$kde_cv_libgpp_includes" != "no"; then + all_includes="-I$kde_cv_libgpp_includes $all_includes $USER_INCLUDES" +fi +]) +]) + +AC_DEFUN([KDE_CHECK_LIBPTHREAD], +[ + dnl This code is here specifically to handle the + dnl various flavors of threading library on FreeBSD + dnl 4-, 5-, and 6-, and the (weird) rules around it. + dnl There may be an environment PTHREAD_LIBS that + dnl specifies what to use; otherwise, search for it. + dnl -pthread is special cased and unsets LIBPTHREAD + dnl below if found. + LIBPTHREAD="" + + if test -n "$PTHREAD_LIBS"; then + if test "x$PTHREAD_LIBS" = "x-pthread" ; then + LIBPTHREAD="PTHREAD" + else + PTHREAD_LIBS_save="$PTHREAD_LIBS" + PTHREAD_LIBS=`echo "$PTHREAD_LIBS_save" | sed -e 's,^-l,,g'` + AC_MSG_CHECKING([for pthread_create in $PTHREAD_LIBS]) + KDE_CHECK_LIB($PTHREAD_LIBS, pthread_create, [ + LIBPTHREAD="$PTHREAD_LIBS_save"]) + PTHREAD_LIBS="$PTHREAD_LIBS_save" + fi + fi + + dnl Is this test really needed, in the face of the Tru64 test below? + if test -z "$LIBPTHREAD"; then + AC_CHECK_LIB(pthread, pthread_create, [LIBPTHREAD="-lpthread"]) + fi + + dnl This is a special Tru64 check, see BR 76171 issue #18. + if test -z "$LIBPTHREAD" ; then + AC_MSG_CHECKING([for pthread_create in -lpthread]) + kde_safe_libs=$LIBS + LIBS="$LIBS -lpthread" + AC_TRY_LINK([#include ],[(void)pthread_create(0,0,0,0);],[ + AC_MSG_RESULT(yes) + LIBPTHREAD="-lpthread"],[ + AC_MSG_RESULT(no)]) + LIBS=$kde_safe_libs + fi + + dnl Un-special-case for FreeBSD. + if test "x$LIBPTHREAD" = "xPTHREAD" ; then + LIBPTHREAD="" + fi + + AC_SUBST(LIBPTHREAD) +]) + +AC_DEFUN([KDE_CHECK_PTHREAD_OPTION], +[ + USE_THREADS="" + if test -z "$LIBPTHREAD"; then + KDE_CHECK_COMPILER_FLAG(pthread, [USE_THREADS="-D_THREAD_SAFE -pthread"]) + fi + + AH_VERBATIM(__svr_define, [ +#if defined(__SVR4) && !defined(__svr4__) +#define __svr4__ 1 +#endif +]) + case $host_os in + solaris*) + KDE_CHECK_COMPILER_FLAG(mt, [USE_THREADS="-mt"]) + CPPFLAGS="$CPPFLAGS -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -DUSE_SOLARIS -DSVR4" + ;; + freebsd*) + CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE $PTHREAD_CFLAGS" + ;; + aix*) + CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE" + LIBPTHREAD="$LIBPTHREAD -lc_r" + ;; + linux*) CPPFLAGS="$CPPFLAGS -D_REENTRANT" + if test "$CXX" = "KCC"; then + CXXFLAGS="$CXXFLAGS --thread_safe" + NOOPT_CXXFLAGS="$NOOPT_CXXFLAGS --thread_safe" + fi + ;; + *) + ;; + esac + AC_SUBST(USE_THREADS) + AC_SUBST(LIBPTHREAD) +]) + +AC_DEFUN([KDE_CHECK_THREADING], +[ + AC_REQUIRE([KDE_CHECK_LIBPTHREAD]) + AC_REQUIRE([KDE_CHECK_PTHREAD_OPTION]) + dnl default is yes if libpthread is found and no if no libpthread is available + if test -z "$LIBPTHREAD"; then + if test -z "$USE_THREADS"; then + kde_check_threading_default=no + else + kde_check_threading_default=yes + fi + else + kde_check_threading_default=yes + fi + AC_ARG_ENABLE(threading,AC_HELP_STRING([--disable-threading],[disables threading even if libpthread found]), + kde_use_threading=$enableval, kde_use_threading=$kde_check_threading_default) + if test "x$kde_use_threading" = "xyes"; then + AC_DEFINE(HAVE_LIBPTHREAD, 1, [Define if you have a working libpthread (will enable threaded code)]) + fi +]) + +AC_DEFUN([KDE_TRY_LINK_PYTHON], +[ +if test "$kde_python_link_found" = no; then + +if test "$1" = normal; then + AC_MSG_CHECKING(if a Python application links) +else + AC_MSG_CHECKING(if Python depends on $2) +fi + +AC_CACHE_VAL(kde_cv_try_link_python_$1, +[ +kde_save_cflags="$CFLAGS" +CFLAGS="$CFLAGS $PYTHONINC" +kde_save_libs="$LIBS" +LIBS="$LIBS $LIBPYTHON $2 $LIBDL $LIBSOCKET" +kde_save_ldflags="$LDFLAGS" +LDFLAGS="$LDFLAGS $PYTHONLIB" + +AC_TRY_LINK( +[ +#include +],[ + PySys_SetArgv(1, 0); +], + [kde_cv_try_link_python_$1=yes], + [kde_cv_try_link_python_$1=no] +) +CFLAGS="$kde_save_cflags" +LIBS="$kde_save_libs" +LDFLAGS="$kde_save_ldflags" +]) + +if test "$kde_cv_try_link_python_$1" = "yes"; then + AC_MSG_RESULT(yes) + kde_python_link_found=yes + if test ! "$1" = normal; then + LIBPYTHON="$LIBPYTHON $2" + fi + $3 +else + AC_MSG_RESULT(no) + $4 +fi + +fi + +]) + +AC_DEFUN([KDE_CHECK_PYTHON_DIR], +[ +AC_MSG_CHECKING([for Python directory]) + +AC_CACHE_VAL(kde_cv_pythondir, +[ + if test -z "$PYTHONDIR"; then + kde_cv_pythondir=/usr/local + else + kde_cv_pythondir="$PYTHONDIR" + fi +]) + +AC_ARG_WITH(pythondir, +AC_HELP_STRING([--with-pythondir=pythondir],[use python installed in pythondir]), +[ + ac_python_dir=$withval +], ac_python_dir=$kde_cv_pythondir +) + +AC_MSG_RESULT($ac_python_dir) +]) + +AC_DEFUN([KDE_CHECK_PYTHON_INTERN], +[ +AC_REQUIRE([KDE_CHECK_LIBDL]) +AC_REQUIRE([KDE_CHECK_LIBPTHREAD]) +AC_REQUIRE([KDE_CHECK_PYTHON_DIR]) + +if test -z "$1"; then + version="1.5" +else + version="$1" +fi + +AC_MSG_CHECKING([for Python$version]) + +python_incdirs="$ac_python_dir/include /usr/include /usr/local/include/ $kde_extra_includes" +AC_FIND_FILE(Python.h, $python_incdirs, python_incdir) +if test ! -r $python_incdir/Python.h; then + AC_FIND_FILE(python$version/Python.h, $python_incdirs, python_incdir) + python_incdir=$python_incdir/python$version + if test ! -r $python_incdir/Python.h; then + python_incdir=no + fi +fi + +PYTHONINC=-I$python_incdir + +python_libdirs="$ac_python_dir/lib$kdelibsuff /usr/lib$kdelibsuff /usr/local /usr/lib$kdelibsuff $kde_extra_libs" +AC_FIND_FILE(libpython$version.so, $python_libdirs, python_libdir) +if test ! -r $python_libdir/libpython$version.so; then + AC_FIND_FILE(libpython$version.a, $python_libdirs, python_libdir) + if test ! -r $python_libdir/libpython$version.a; then + AC_FIND_FILE(python$version/config/libpython$version.a, $python_libdirs, python_libdir) + python_libdir=$python_libdir/python$version/config + if test ! -r $python_libdir/libpython$version.a; then + python_libdir=no + fi + fi +fi + +PYTHONLIB=-L$python_libdir +kde_orig_LIBPYTHON=$LIBPYTHON +if test -z "$LIBPYTHON"; then + LIBPYTHON=-lpython$version +fi + +AC_FIND_FILE(python$version/copy.py, $python_libdirs, python_moddir) +python_moddir=$python_moddir/python$version +if test ! -r $python_moddir/copy.py; then + python_moddir=no +fi + +PYTHONMODDIR=$python_moddir + +AC_MSG_RESULT(header $python_incdir library $python_libdir modules $python_moddir) + +if test x$python_incdir = xno || test x$python_libdir = xno || test x$python_moddir = xno; then + LIBPYTHON=$kde_orig_LIBPYTHON + test "x$PYTHONLIB" = "x-Lno" && PYTHONLIB="" + test "x$PYTHONINC" = "x-Ino" && PYTHONINC="" + $2 +else + dnl Note: this test is very weak + kde_python_link_found=no + KDE_TRY_LINK_PYTHON(normal) + KDE_TRY_LINK_PYTHON(m, -lm) + KDE_TRY_LINK_PYTHON(pthread, $LIBPTHREAD) + KDE_TRY_LINK_PYTHON(tcl, -ltcl) + KDE_TRY_LINK_PYTHON(db2, -ldb2) + KDE_TRY_LINK_PYTHON(m_and_thread, [$LIBPTHREAD -lm]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_util, [$LIBPTHREAD -lm -lutil]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_db3, [$LIBPTHREAD -lm -ldb-3 -lutil]) + KDE_TRY_LINK_PYTHON(pthread_and_db3, [$LIBPTHREAD -ldb-3]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_db, [$LIBPTHREAD -lm -ldb -ltermcap -lutil]) + KDE_TRY_LINK_PYTHON(pthread_and_dl, [$LIBPTHREAD $LIBDL -lutil -lreadline -lncurses -lm]) + KDE_TRY_LINK_PYTHON(pthread_and_panel_curses, [$LIBPTHREAD $LIBDL -lm -lpanel -lcurses]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_db_special, [$LIBPTHREAD -lm -ldb -lutil], [], + [AC_MSG_WARN([it seems, Python depends on another library. + Please set LIBPYTHON to '-lpython$version -lotherlib' before calling configure to fix this + and contact the authors to let them know about this problem]) + ]) + + LIBPYTHON="$LIBPYTHON $LIBDL $LIBSOCKET" + AC_SUBST(PYTHONINC) + AC_SUBST(PYTHONLIB) + AC_SUBST(LIBPYTHON) + AC_SUBST(PYTHONMODDIR) + AC_DEFINE(HAVE_PYTHON, 1, [Define if you have the development files for python]) +fi + +]) + + +AC_DEFUN([KDE_CHECK_PYTHON], +[ + KDE_CHECK_PYTHON_INTERN("2.4", + [KDE_CHECK_PYTHON_INTERN("2.3", + [KDE_CHECK_PYTHON_INTERN("2.2", + [KDE_CHECK_PYTHON_INTERN("2.1", + [KDE_CHECK_PYTHON_INTERN("2.0", + [KDE_CHECK_PYTHON_INTERN($1, $2) ]) + ]) + ]) + ]) + ]) +]) + +AC_DEFUN([KDE_CHECK_STL], +[ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="`echo $CXXFLAGS | sed s/-fno-exceptions//`" + + AC_MSG_CHECKING([if C++ programs can be compiled]) + AC_CACHE_VAL(kde_cv_stl_works, + [ + AC_TRY_COMPILE([ +#include +using namespace std; +],[ + string astring="Hallo Welt."; + astring.erase(0, 6); // now astring is "Welt" + return 0; +], kde_cv_stl_works=yes, + kde_cv_stl_works=no) +]) + + AC_MSG_RESULT($kde_cv_stl_works) + + if test "$kde_cv_stl_works" = "yes"; then + # back compatible + AC_DEFINE_UNQUOTED(HAVE_SGI_STL, 1, [Define if you have a STL implementation by SGI]) + else + AC_MSG_ERROR([Your Installation isn't able to compile simple C++ programs. +Check config.log for details - if you're using a Linux distribution you might miss +a package named similar to libstdc++-dev.]) + fi + + CXXFLAGS="$ac_save_CXXFLAGS" + AC_LANG_RESTORE +]) + +AC_DEFUN([AC_FIND_QIMGIO], + [AC_REQUIRE([AC_FIND_JPEG]) +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_MSG_CHECKING([for qimgio]) +AC_CACHE_VAL(ac_cv_lib_qimgio, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +ac_save_LIBS="$LIBS" +ac_save_CXXFLAGS="$CXXFLAGS" +LIBS="$all_libraries -lqimgio -lpng -lz $LIBJPEG $LIBQT" +CXXFLAGS="$CXXFLAGS -I$qt_incdir $all_includes" +AC_TRY_RUN(dnl +[ +#include +#include +int main() { + QString t = "hallo"; + t.fill('t'); + qInitImageIO(); +} +], + ac_cv_lib_qimgio=yes, + ac_cv_lib_qimgio=no, + ac_cv_lib_qimgio=no) +LIBS="$ac_save_LIBS" +CXXFLAGS="$ac_save_CXXFLAGS" +AC_LANG_RESTORE +])dnl +if eval "test \"`echo $ac_cv_lib_qimgio`\" = yes"; then + LIBQIMGIO="-lqimgio -lpng -lz $LIBJPEG" + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_QIMGIO, 1, [Define if you have the Qt extension qimgio available]) + AC_SUBST(LIBQIMGIO) +else + AC_MSG_RESULT(not found) +fi +]) + +AC_DEFUN([AM_DISABLE_LIBRARIES], +[ + AC_PROVIDE([AM_ENABLE_STATIC]) + AC_PROVIDE([AM_ENABLE_SHARED]) + enable_static=no + enable_shared=yes +]) + + +AC_DEFUN([AC_CHECK_UTMP_FILE], +[ + AC_MSG_CHECKING([for utmp file]) + + AC_CACHE_VAL(kde_cv_utmp_file, + [ + kde_cv_utmp_file=no + + for ac_file in \ + \ + /var/run/utmp \ + /var/adm/utmp \ + /etc/utmp \ + ; \ + do + if test -r "$ac_file"; then + kde_cv_utmp_file=$ac_file + break + fi + done + ]) + + if test "$kde_cv_utmp_file" != "no"; then + AC_DEFINE_UNQUOTED(UTMP, "$kde_cv_utmp_file", [Define the file for utmp entries]) + $1 + AC_MSG_RESULT($kde_cv_utmp_file) + else + $2 + AC_MSG_RESULT([non found]) + fi +]) + + +AC_DEFUN([KDE_CREATE_SUBDIRSLIST], +[ + +DO_NOT_COMPILE="$DO_NOT_COMPILE CVS debian bsd-port admin" +TOPSUBDIRS="" + +if test ! -s $srcdir/subdirs; then + dnl Note: Makefile.common creates subdirs, so this is just a fallback + files=`cd $srcdir && ls -1` + dirs=`for i in $files; do if test -d $i; then echo $i; fi; done` + for i in $dirs; do + echo $i >> $srcdir/subdirs + done +fi + +ac_topsubdirs= +if test -s $srcdir/inst-apps; then + ac_topsubdirs="`cat $srcdir/inst-apps`" +elif test -s $srcdir/subdirs; then + ac_topsubdirs="`cat $srcdir/subdirs`" +fi + +for i in $ac_topsubdirs; do + AC_MSG_CHECKING([if $i should be compiled]) + if test -d $srcdir/$i; then + install_it="yes" + for j in $DO_NOT_COMPILE; do + if test $i = $j; then + install_it="no" + fi + done + else + install_it="no" + fi + AC_MSG_RESULT($install_it) + vari=`echo $i | sed -e 's,[[-+.@]],_,g'` + if test $install_it = "yes"; then + TOPSUBDIRS="$TOPSUBDIRS $i" + eval "$vari""_SUBDIR_included=yes" + else + eval "$vari""_SUBDIR_included=no" + fi +done + +AC_SUBST(TOPSUBDIRS) +]) + +AC_DEFUN([KDE_CHECK_NAMESPACES], +[ +AC_MSG_CHECKING(whether C++ compiler supports namespaces) +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +AC_TRY_COMPILE([ +], +[ +namespace Foo { + extern int i; + namespace Bar { + extern int i; + } +} + +int Foo::i = 0; +int Foo::Bar::i = 1; +],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_NAMESPACES) +], [ +AC_MSG_RESULT(no) +]) +AC_LANG_RESTORE +]) + +dnl ------------------------------------------------------------------------ +dnl Check for S_ISSOCK macro. Doesn't exist on Unix SCO. faure@kde.org +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_CHECK_S_ISSOCK], +[ +AC_MSG_CHECKING(for S_ISSOCK) +AC_CACHE_VAL(ac_cv_have_s_issock, +[ +AC_TRY_LINK( +[ +#include +], +[ +struct stat buff; +int b = S_ISSOCK( buff.st_mode ); +], +ac_cv_have_s_issock=yes, +ac_cv_have_s_issock=no) +]) +AC_MSG_RESULT($ac_cv_have_s_issock) +if test "$ac_cv_have_s_issock" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_S_ISSOCK, 1, [Define if sys/stat.h declares S_ISSOCK.]) +fi + +AH_VERBATIM(_ISSOCK, +[ +#ifndef HAVE_S_ISSOCK +#define HAVE_S_ISSOCK +#define S_ISSOCK(mode) (1==0) +#endif +]) + +]) + +dnl ------------------------------------------------------------------------ +dnl Check for MAXPATHLEN macro, defines KDEMAXPATHLEN. faure@kde.org +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_CHECK_KDEMAXPATHLEN], +[ +AC_MSG_CHECKING(for MAXPATHLEN) +AC_CACHE_VAL(ac_cv_maxpathlen, +[ +cat > conftest.$ac_ext < +#endif +#include +#include +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +KDE_HELLO MAXPATHLEN + +EOF + +ac_try="$ac_cpp conftest.$ac_ext 2>/dev/null | grep '^KDE_HELLO' >conftest.out" + +if AC_TRY_EVAL(ac_try) && test -s conftest.out; then + ac_cv_maxpathlen=`sed 's#KDE_HELLO ##' conftest.out` +else + ac_cv_maxpathlen=1024 +fi + +rm conftest.* + +]) +AC_MSG_RESULT($ac_cv_maxpathlen) +AC_DEFINE_UNQUOTED(KDEMAXPATHLEN,$ac_cv_maxpathlen, [Define a safe value for MAXPATHLEN] ) +]) + +AC_DEFUN([KDE_CHECK_HEADER], +[ + kde_safe_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $all_includes" + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_CHECK_HEADER([$1], [$2], [$3], [$4]) + AC_LANG_RESTORE + CPPFLAGS=$kde_safe_cppflags +]) + +AC_DEFUN([KDE_CHECK_HEADERS], +[ + AH_CHECK_HEADERS([$1]) + AC_LANG_SAVE + kde_safe_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $all_includes" + AC_LANG_CPLUSPLUS + AC_CHECK_HEADERS([$1], [$2], [$3], [$4]) + CPPFLAGS=$kde_safe_cppflags + AC_LANG_RESTORE +]) + +AC_DEFUN([KDE_FAST_CONFIGURE], +[ + dnl makes configure fast (needs perl) + AC_ARG_ENABLE(fast-perl, AC_HELP_STRING([--disable-fast-perl],[disable fast Makefile generation (needs perl)]), + with_fast_perl=$enableval, with_fast_perl=yes) +]) + +AC_DEFUN([KDE_CONF_FILES], +[ + val= + if test -f $srcdir/configure.files ; then + val=`sed -e 's%^%\$(top_srcdir)/%' $srcdir/configure.files` + fi + CONF_FILES= + if test -n "$val" ; then + for i in $val ; do + CONF_FILES="$CONF_FILES $i" + done + fi + AC_SUBST(CONF_FILES) +])dnl + +dnl This sets the prefix, for arts and kdelibs +dnl Do NOT use in any other module. +dnl It only looks at --prefix, KDEDIR and falls back to /usr/local/kde +AC_DEFUN([KDE_SET_PREFIX_CORE], +[ + unset CDPATH + dnl make $KDEDIR the default for the installation + AC_PREFIX_DEFAULT(${KDEDIR:-/usr/local/kde}) + + if test "x$prefix" = "xNONE"; then + prefix=$ac_default_prefix + ac_configure_args="$ac_configure_args --prefix=$prefix" + fi + # And delete superfluous '/' to make compares easier + prefix=`echo "$prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + exec_prefix=`echo "$exec_prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + + kde_libs_prefix='$(prefix)' + kde_libs_htmldir='$(kde_htmldir)' + AC_SUBST(kde_libs_prefix) + AC_SUBST(kde_libs_htmldir) + KDE_FAST_CONFIGURE + KDE_CONF_FILES +]) + + +AC_DEFUN([KDE_SET_PREFIX], +[ + unset CDPATH + dnl We can't give real code to that macro, only a value. + dnl It only matters for --help, since we set the prefix in this function anyway. + AC_PREFIX_DEFAULT(${KDEDIR:-the kde prefix}) + + KDE_SET_DEFAULT_BINDIRS + if test "x$prefix" = "xNONE"; then + dnl no prefix given: look for kde-config in the PATH and deduce the prefix from it + KDE_FIND_PATH(kde-config, KDECONFIG, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(kde-config)], [], prepend) + else + dnl prefix given: look for kde-config, preferrably in prefix, otherwise in PATH + kde_save_PATH="$PATH" + PATH="$exec_prefix/bin:$prefix/bin:$PATH" + KDE_FIND_PATH(kde-config, KDECONFIG, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(kde-config)], [], prepend) + PATH="$kde_save_PATH" + fi + + kde_libs_prefix=`$KDECONFIG --prefix` + if test -z "$kde_libs_prefix" || test ! -x "$kde_libs_prefix"; then + AC_MSG_ERROR([$KDECONFIG --prefix outputed the non existant prefix '$kde_libs_prefix' for kdelibs. + This means it has been moved since you installed it. + This won't work. Please recompile kdelibs for the new prefix. + ]) + fi + kde_libs_htmldir=`$KDECONFIG --install html --expandvars` + kde_libs_suffix=`$KDECONFIG --libsuffix` + + AC_MSG_CHECKING([where to install]) + if test "x$prefix" = "xNONE"; then + prefix=$kde_libs_prefix + AC_MSG_RESULT([$prefix (as returned by kde-config)]) + else + dnl --prefix was given. Compare prefixes and warn (in configure.in.bot.end) if different + given_prefix=$prefix + AC_MSG_RESULT([$prefix (as requested)]) + fi + + # And delete superfluous '/' to make compares easier + prefix=`echo "$prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + exec_prefix=`echo "$exec_prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + given_prefix=`echo "$given_prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + + AC_SUBST(KDECONFIG) + AC_SUBST(kde_libs_prefix) + AC_SUBST(kde_libs_htmldir) + + KDE_FAST_CONFIGURE + KDE_CONF_FILES +]) + +pushdef([AC_PROG_INSTALL], +[ + dnl our own version, testing for a -p flag + popdef([AC_PROG_INSTALL]) + dnl as AC_PROG_INSTALL works as it works we first have + dnl to save if the user didn't specify INSTALL, as the + dnl autoconf one overwrites INSTALL and we have no chance to find + dnl out afterwards + test -n "$INSTALL" && kde_save_INSTALL_given=$INSTALL + test -n "$INSTALL_PROGRAM" && kde_save_INSTALL_PROGRAM_given=$INSTALL_PROGRAM + test -n "$INSTALL_SCRIPT" && kde_save_INSTALL_SCRIPT_given=$INSTALL_SCRIPT + AC_PROG_INSTALL + + if test -z "$kde_save_INSTALL_given" ; then + # OK, user hasn't given any INSTALL, autoconf found one for us + # now we test, if it supports the -p flag + AC_MSG_CHECKING(for -p flag to install) + rm -f confinst.$$.* > /dev/null 2>&1 + echo "Testtest" > confinst.$$.orig + ac_res=no + if ${INSTALL} -p confinst.$$.orig confinst.$$.new > /dev/null 2>&1 ; then + if test -f confinst.$$.new ; then + # OK, -p seems to do no harm to install + INSTALL="${INSTALL} -p" + ac_res=yes + fi + fi + rm -f confinst.$$.* + AC_MSG_RESULT($ac_res) + fi + dnl the following tries to resolve some signs and wonders coming up + dnl with different autoconf/automake versions + dnl e.g.: + dnl *automake 1.4 install-strip sets A_M_INSTALL_PROGRAM_FLAGS to -s + dnl and has INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(A_M_INSTALL_PROGRAM_FLAGS) + dnl it header-vars.am, so there the actual INSTALL_PROGRAM gets the -s + dnl *automake 1.4a (and above) use INSTALL_STRIP_FLAG and only has + dnl INSTALL_PROGRAM = @INSTALL_PROGRAM@ there, but changes the + dnl install-@DIR@PROGRAMS targets to explicitly use that flag + dnl *autoconf 2.13 is dumb, and thinks it can use INSTALL_PROGRAM as + dnl INSTALL_SCRIPT, which breaks with automake <= 1.4 + dnl *autoconf >2.13 (since 10.Apr 1999) has not that failure + dnl *sometimes KDE does not use the install-@DIR@PROGRAM targets from + dnl automake (due to broken Makefile.am or whatever) to install programs, + dnl and so does not see the -s flag in automake > 1.4 + dnl to clean up that mess we: + dnl +set INSTALL_PROGRAM to use INSTALL_STRIP_FLAG + dnl which cleans KDE's program with automake > 1.4; + dnl +set INSTALL_SCRIPT to only use INSTALL, to clean up autoconf's problems + dnl with automake<=1.4 + dnl note that dues to this sometimes two '-s' flags are used (if KDE + dnl properly uses install-@DIR@PROGRAMS, but I don't care + dnl + dnl And to all this comes, that I even can't write in comments variable + dnl names used by automake, because it is so stupid to think I wanted to + dnl _use_ them, therefor I have written A_M_... instead of AM_ + dnl hmm, I wanted to say something ... ahh yes: Arghhh. + + if test -z "$kde_save_INSTALL_PROGRAM_given" ; then + INSTALL_PROGRAM='${INSTALL} $(INSTALL_STRIP_FLAG)' + fi + if test -z "$kde_save_INSTALL_SCRIPT_given" ; then + INSTALL_SCRIPT='${INSTALL}' + fi +])dnl + +AC_DEFUN([KDE_LANG_CPLUSPLUS], +[AC_LANG_CPLUSPLUS +ac_link='rm -rf SunWS_cache; ${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&AC_FD_CC' +pushdef([AC_LANG_CPLUSPLUS], [popdef([AC_LANG_CPLUSPLUS]) KDE_LANG_CPLUSPLUS]) +]) + +pushdef([AC_LANG_CPLUSPLUS], +[popdef([AC_LANG_CPLUSPLUS]) +KDE_LANG_CPLUSPLUS +]) + +AC_DEFUN([KDE_CHECK_LONG_LONG], +[ +AC_MSG_CHECKING(for long long) +AC_CACHE_VAL(kde_cv_c_long_long, +[ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_LINK([], [ + long long foo = 0; + foo = foo+1; + ], + kde_cv_c_long_long=yes, kde_cv_c_long_long=no) + AC_LANG_RESTORE +]) +AC_MSG_RESULT($kde_cv_c_long_long) +if test "$kde_cv_c_long_long" = yes; then + AC_DEFINE(HAVE_LONG_LONG, 1, [Define if you have long long as datatype]) +fi +]) + +AC_DEFUN([KDE_CHECK_LIB], +[ + kde_save_LDFLAGS="$LDFLAGS" + dnl AC_CHECK_LIB modifies LIBS, so save it here + kde_save_LIBS="$LIBS" + LDFLAGS="$LDFLAGS $all_libraries" + case $host_os in + aix*) LDFLAGS="-brtl $LDFLAGS" + test "$GCC" = yes && LDFLAGS="-Wl,$LDFLAGS" + ;; + esac + AC_CHECK_LIB($1, $2, $3, $4, $5) + LDFLAGS="$kde_save_LDFLAGS" + LIBS="$kde_save_LIBS" +]) + +AC_DEFUN([KDE_JAVA_PREFIX], +[ + dir=`dirname "$1"` + base=`basename "$1"` + list=`ls -1 $dir 2> /dev/null` + for entry in $list; do + if test -d $dir/$entry/bin; then + case $entry in + $base) + javadirs="$javadirs $dir/$entry/bin" + ;; + esac + elif test -d $dir/$entry/jre/bin; then + case $entry in + $base) + javadirs="$javadirs $dir/$entry/jre/bin" + ;; + esac + fi + done +]) + +dnl KDE_CHEC_JAVA_DIR(onlyjre) +AC_DEFUN([KDE_CHECK_JAVA_DIR], +[ + +AC_ARG_WITH(java, +AC_HELP_STRING([--with-java=javadir],[use java installed in javadir, --without-java disables]), +[ ac_java_dir=$withval +], ac_java_dir="" +) + +AC_MSG_CHECKING([for Java]) + +dnl at this point ac_java_dir is either a dir, 'no' to disable, or '' to say look in $PATH +if test "x$ac_java_dir" = "xno"; then + kde_java_bindir=no + kde_java_includedir=no + kde_java_libjvmdir=no + kde_java_libgcjdir=no + kde_java_libhpidir=no +else + if test "x$ac_java_dir" = "x"; then + + + dnl No option set -> collect list of candidate paths + if test -n "$JAVA_HOME"; then + KDE_JAVA_PREFIX($JAVA_HOME) + fi + KDE_JAVA_PREFIX(/usr/j2se) + KDE_JAVA_PREFIX(/usr/lib/j2se) + KDE_JAVA_PREFIX(/usr/j*dk*) + KDE_JAVA_PREFIX(/usr/lib/j*dk*) + KDE_JAVA_PREFIX(/opt/j*sdk*) + KDE_JAVA_PREFIX(/usr/lib/java*) + KDE_JAVA_PREFIX(/usr/java*) + KDE_JAVA_PREFIX(/usr/java/j*dk*) + KDE_JAVA_PREFIX(/usr/java/j*re*) + KDE_JAVA_PREFIX(/usr/lib/SunJava2*) + KDE_JAVA_PREFIX(/usr/lib/SunJava*) + KDE_JAVA_PREFIX(/usr/lib/IBMJava2*) + KDE_JAVA_PREFIX(/usr/lib/IBMJava*) + KDE_JAVA_PREFIX(/opt/java*) + + kde_cv_path="NONE" + kde_save_IFS=$IFS + IFS=':' + for dir in $PATH; do + if test -d "$dir"; then + javadirs="$javadirs $dir" + fi + done + IFS=$kde_save_IFS + jredirs= + + dnl Now javadirs contains a list of paths that exist, all ending with bin/ + for dir in $javadirs; do + dnl Check for the java executable + if test -x "$dir/java"; then + dnl And also check for a libjvm.so somewhere under there + dnl Since we have to go to the parent dir, /usr/bin is excluded, /usr is too big. + if test "$dir" != "/usr/bin"; then + libjvmdir=`find $dir/.. -name libjvm.so | sed 's,libjvm.so,,'|head -n 1` + if test ! -f $libjvmdir/libjvm.so; then continue; fi + jredirs="$jredirs $dir" + fi + fi + done + + dnl Now jredirs contains a reduced list, of paths where both java and ../**/libjvm.so was found + JAVAC= + JAVA= + kde_java_bindir=no + for dir in $jredirs; do + JAVA="$dir/java" + kde_java_bindir=$dir + if test -x "$dir/javac"; then + JAVAC="$dir/javac" + break + fi + done + + if test -n "$JAVAC"; then + dnl this substitution might not work - well, we test for jni.h below + kde_java_includedir=`echo $JAVAC | sed -e 's,bin/javac$,include/,'` + else + kde_java_includedir=no + fi + else + dnl config option set + kde_java_bindir=$ac_java_dir/bin + if test -x $ac_java_dir/bin/java && test ! -x $ac_java_dir/bin/javac; then + kde_java_includedir=no + else + kde_java_includedir=$ac_java_dir/include + fi + fi +fi + +dnl At this point kde_java_bindir and kde_java_includedir are either set or "no" +if test "x$kde_java_bindir" != "xno"; then + + dnl Look for libjvm.so + kde_java_libjvmdir=`find $kde_java_bindir/.. -name libjvm.so | sed 's,libjvm.so,,'|head -n 1` + dnl Look for libgcj.so + kde_java_libgcjdir=`find $kde_java_bindir/.. -name libgcj.so | sed 's,libgcj.so,,'|head -n 1` + dnl Look for libhpi.so and avoid green threads + kde_java_libhpidir=`find $kde_java_bindir/.. -name libhpi.so | grep -v green | sed 's,libhpi.so,,' | head -n 1` + + dnl Now check everything's fine under there + dnl the include dir is our flag for having the JDK + if test -d "$kde_java_includedir"; then + if test ! -x "$kde_java_bindir/javac"; then + AC_MSG_ERROR([javac not found under $kde_java_bindir - it seems you passed a wrong --with-java.]) + fi + if test ! -x "$kde_java_bindir/javah"; then + AC_MSG_ERROR([javah not found under $kde_java_bindir. javac was found though! Use --with-java or --without-java.]) + fi + if test ! -x "$kde_java_bindir/jar"; then + AC_MSG_ERROR([jar not found under $kde_java_bindir. javac was found though! Use --with-java or --without-java.]) + fi + if test ! -r "$kde_java_includedir/jni.h"; then + AC_MSG_ERROR([jni.h not found under $kde_java_includedir. Use --with-java or --without-java.]) + fi + + jni_includes="-I$kde_java_includedir" + dnl Strange thing, jni.h requires jni_md.h which is under genunix here.. + dnl and under linux here.. + + dnl not needed for gcj + + if test "x$kde_java_libgcjdir" = "x"; then + test -d "$kde_java_includedir/linux" && jni_includes="$jni_includes -I$kde_java_includedir/linux" + test -d "$kde_java_includedir/solaris" && jni_includes="$jni_includes -I$kde_java_includedir/solaris" + test -d "$kde_java_includedir/genunix" && jni_includes="$jni_includes -I$kde_java_includedir/genunix" + fi + + else + JAVAC= + jni_includes= + fi + + if test "x$kde_java_libgcjdir" = "x"; then + if test ! -r "$kde_java_libjvmdir/libjvm.so"; then + AC_MSG_ERROR([libjvm.so not found under $kde_java_libjvmdir. Use --without-java.]) + fi + else + if test ! -r "$kde_java_libgcjdir/libgcj.so"; then + AC_MSG_ERROR([libgcj.so not found under $kde_java_libgcjdir. Use --without-java.]) + fi + fi + + if test ! -x "$kde_java_bindir/java"; then + AC_MSG_ERROR([java not found under $kde_java_bindir. javac was found though! Use --with-java or --without-java.]) + fi + + dnl not needed for gcj compile + + if test "x$kde_java_libgcjdir" = "x"; then + if test ! -r "$kde_java_libhpidir/libhpi.so"; then + AC_MSG_ERROR([libhpi.so not found under $kde_java_libhpidir. Use --without-java.]) + fi + fi + + if test -n "$jni_includes"; then + dnl Check for JNI version + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_cxxflags_safe="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $all_includes $jni_includes" + + AC_TRY_COMPILE([ + #include + ], + [ + #ifndef JNI_VERSION_1_2 + Syntax Error + #endif + ],[ kde_jni_works=yes ], + [ kde_jni_works=no ]) + + if test $kde_jni_works = no; then + AC_MSG_ERROR([Incorrect version of $kde_java_includedir/jni.h. + You need to have Java Development Kit (JDK) version 1.2. + + Use --with-java to specify another location. + Use --without-java to configure without java support. + Or download a newer JDK and try again. + See e.g. http://java.sun.com/products/jdk/1.2 ]) + fi + + CXXFLAGS="$ac_cxxflags_safe" + AC_LANG_RESTORE + + dnl All tests ok, inform and subst the variables + + JAVAC=$kde_java_bindir/javac + JAVAH=$kde_java_bindir/javah + JAR=$kde_java_bindir/jar + AC_DEFINE_UNQUOTED(PATH_JAVA, "$kde_java_bindir/java", [Define where your java executable is]) + if test "x$kde_java_libgcjdir" = "x"; then + JVMLIBS="-L$kde_java_libjvmdir -ljvm -L$kde_java_libhpidir -lhpi" + else + JVMLIBS="-L$kde_java_libgcjdir -lgcj" + fi + AC_MSG_RESULT([java JDK in $kde_java_bindir]) + + else + AC_DEFINE_UNQUOTED(PATH_JAVA, "$kde_java_bindir/java", [Define where your java executable is]) + AC_MSG_RESULT([java JRE in $kde_java_bindir]) + fi +elif test -d "/Library/Java/Home"; then + kde_java_bindir="/Library/Java/Home/bin" + jni_includes="-I/Library/Java/Home/include" + + JAVAC=$kde_java_bindir/javac + JAVAH=$kde_java_bindir/javah + JAR=$kde_java_bindir/jar + JVMLIBS="-Xlinker -framework -Xlinker JavaVM" + + AC_DEFINE_UNQUOTED(PATH_JAVA, "$kde_java_bindir/java", [Define where your java executable is]) + AC_MSG_RESULT([Apple Java Framework]) +else + AC_MSG_RESULT([none found]) +fi + +AC_SUBST(JAVAC) +AC_SUBST(JAVAH) +AC_SUBST(JAR) +AC_SUBST(JVMLIBS) +AC_SUBST(jni_includes) + +# for backward compat +kde_cv_java_includedir=$kde_java_includedir +kde_cv_java_bindir=$kde_java_bindir +]) + +dnl this is a redefinition of autoconf 2.5x's AC_FOREACH. +dnl When the argument list becomes big, as in KDE for AC_OUTPUT in +dnl big packages, m4_foreach is dog-slow. So use our own version of +dnl it. (matz@kde.org) +m4_define([mm_foreach], +[m4_pushdef([$1])_mm_foreach($@)m4_popdef([$1])]) +m4_define([mm_car], [[$1]]) +m4_define([mm_car2], [[$@]]) +m4_define([_mm_foreach], +[m4_if(m4_quote($2), [], [], + [m4_define([$1], mm_car($2))$3[]_mm_foreach([$1], + mm_car2(m4_shift($2)), + [$3])])]) +m4_define([AC_FOREACH], +[mm_foreach([$1], m4_split(m4_normalize([$2])), [$3])]) + +AC_DEFUN([KDE_NEED_FLEX], +[ +kde_libs_safe=$LIBS +LIBS="$LIBS $USER_LDFLAGS" +AM_PROG_LEX +LIBS=$kde_libs_safe +if test -z "$LEXLIB"; then + AC_MSG_ERROR([You need to have flex installed.]) +fi +AC_SUBST(LEXLIB) +]) + +AC_DEFUN([AC_PATH_QTOPIA], +[ + dnl TODO: use AC_CACHE_VAL + + if test -z "$1"; then + qtopia_minver_maj=1 + qtopia_minver_min=5 + qtopia_minver_pat=0 + else + qtopia_minver_maj=`echo "$1" | sed -e "s/^\(.*\)\..*\..*$/\1/"` + qtopia_minver_min=`echo "$1" | sed -e "s/^.*\.\(.*\)\..*$/\1/"` + qtopia_minver_pat=`echo "$1" | sed -e "s/^.*\..*\.\(.*\)$/\1/"` + fi + + qtopia_minver="$qtopia_minver_maj$qtopia_minver_min$qtopia_minver_pat" + qtopia_minverstr="$qtopia_minver_maj.$qtopia_minver_min.$qtopia_minver_pat" + + AC_REQUIRE([AC_PATH_QT]) + + AC_MSG_CHECKING([for Qtopia]) + + LIB_QTOPIA="-lqpe" + AC_SUBST(LIB_QTOPIA) + + kde_qtopia_dirs="$QPEDIR /opt/Qtopia" + + ac_qtopia_incdir=NO + + AC_ARG_WITH(qtopia-dir, + AC_HELP_STRING([--with-qtopia-dir=DIR],[where the root of Qtopia is installed]), + [ ac_qtopia_incdir="$withval"/include] ) + + qtopia_incdirs="" + for dir in $kde_qtopia_dirs; do + qtopia_incdirs="$qtopia_incdirs $dir/include" + done + + if test ! "$ac_qtopia_incdir" = "NO"; then + qtopia_incdirs="$ac_qtopia_incdir $qtopia_incdirs" + fi + + qtopia_incdir="" + AC_FIND_FILE(qpe/qpeapplication.h, $qtopia_incdirs, qtopia_incdir) + ac_qtopia_incdir="$qtopia_incdir" + + if test -z "$qtopia_incdir"; then + AC_MSG_ERROR([Cannot find Qtopia headers. Please check your installation.]) + fi + + qtopia_ver_maj=`cat $qtopia_incdir/qpe/version.h | sed -n -e 's,.*QPE_VERSION "\(.*\)\..*\..*".*,\1,p'`; + qtopia_ver_min=`cat $qtopia_incdir/qpe/version.h | sed -n -e 's,.*QPE_VERSION ".*\.\(.*\)\..*".*,\1,p'`; + qtopia_ver_pat=`cat $qtopia_incdir/qpe/version.h | sed -n -e 's,.*QPE_VERSION ".*\..*\.\(.*\)".*,\1,p'`; + + qtopia_ver="$qtopia_ver_maj$qtopia_ver_min$qtopia_ver_pat" + qtopia_verstr="$qtopia_ver_maj.$qtopia_ver_min.$qtopia_ver_pat" + if test "$qtopia_ver" -lt "$qtopia_minver"; then + AC_MSG_ERROR([found Qtopia version $qtopia_verstr but version $qtopia_minverstr +is required.]) + fi + + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + + ac_cxxflags_safe="$CXXFLAGS" + ac_ldflags_safe="$LDFLAGS" + ac_libs_safe="$LIBS" + + CXXFLAGS="$CXXFLAGS -I$qtopia_incdir $all_includes" + LDFLAGS="$LDFLAGS $QT_LDFLAGS $all_libraries $USER_LDFLAGS $KDE_MT_LDFLAGS" + LIBS="$LIBS $LIB_QTOPIA $LIBQT" + + cat > conftest.$ac_ext < +#include + +int main( int argc, char **argv ) +{ + QPEApplication app( argc, argv ); + return 0; +} +EOF + + if AC_TRY_EVAL(ac_link) && test -s conftest; then + rm -f conftest* + else + rm -f conftest* + AC_MSG_ERROR([Cannot link small Qtopia Application. For more details look at +the end of config.log]) + fi + + CXXFLAGS="$ac_cxxflags_safe" + LDFLAGS="$ac_ldflags_safe" + LIBS="$ac_libs_safe" + + AC_LANG_RESTORE + + QTOPIA_INCLUDES="-I$qtopia_incdir" + AC_SUBST(QTOPIA_INCLUDES) + + AC_MSG_RESULT([found version $qtopia_verstr with headers at $qtopia_incdir]) +]) + + +AC_DEFUN([KDE_INIT_DOXYGEN], +[ +AC_MSG_CHECKING([for Qt docs]) +kde_qtdir= +if test "${with_qt_dir+set}" = set; then + kde_qtdir="$with_qt_dir" +fi + +AC_FIND_FILE(qsql.html, [ $kde_qtdir/doc/html $QTDIR/doc/html /usr/share/doc/packages/qt3/html /usr/lib/qt/doc /usr/lib/qt3/doc /usr/lib/qt3/doc/html /usr/doc/qt3/html /usr/doc/qt3 /usr/share/doc/qt3-doc /usr/share/qt3/doc/html /usr/X11R6/share/doc/qt/html ], QTDOCDIR) +AC_MSG_RESULT($QTDOCDIR) + +AC_SUBST(QTDOCDIR) + +KDE_FIND_PATH(dot, DOT, [], []) +if test -n "$DOT"; then + KDE_HAVE_DOT="YES" +else + KDE_HAVE_DOT="NO" +fi +AC_SUBST(KDE_HAVE_DOT) +KDE_FIND_PATH(doxygen, DOXYGEN, [], []) +AC_SUBST(DOXYGEN) + +DOXYGEN_PROJECT_NAME="$1" +DOXYGEN_PROJECT_NUMBER="$2" +AC_SUBST(DOXYGEN_PROJECT_NAME) +AC_SUBST(DOXYGEN_PROJECT_NUMBER) + +KDE_HAS_DOXYGEN=no +if test -n "$DOXYGEN" && test -x "$DOXYGEN" && test -f $QTDOCDIR/qsql.html; then + KDE_HAS_DOXYGEN=yes +fi +AC_SUBST(KDE_HAS_DOXYGEN) + +]) + + +AC_DEFUN([AC_FIND_BZIP2], +[ +AC_MSG_CHECKING([for bzDecompress in libbz2]) +AC_CACHE_VAL(ac_cv_lib_bzip2, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +kde_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS -lbz2 $LIBSOCKET" +kde_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK(dnl +[ +#define BZ_NO_STDIO +#include +], + [ bz_stream s; (void) bzDecompress(&s); ], + eval "ac_cv_lib_bzip2='-lbz2'", + eval "ac_cv_lib_bzip2=no") +LIBS="$kde_save_LIBS" +CXXFLAGS="$kde_save_CXXFLAGS" +AC_LANG_RESTORE +])dnl +AC_MSG_RESULT($ac_cv_lib_bzip2) + +if test ! "$ac_cv_lib_bzip2" = no; then + BZIP2DIR=bzip2 + + LIBBZ2="$ac_cv_lib_bzip2" + AC_SUBST(LIBBZ2) + +else + + cxx_shared_flag= + ld_shared_flag= + KDE_CHECK_COMPILER_FLAG(shared, [ + ld_shared_flag="-shared" + ]) + KDE_CHECK_COMPILER_FLAG(fPIC, [ + cxx_shared_flag="-fPIC" + ]) + + AC_MSG_CHECKING([for BZ2_bzDecompress in (shared) libbz2]) + AC_CACHE_VAL(ac_cv_lib_bzip2_prefix, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + kde_save_LIBS="$LIBS" + LIBS="$all_libraries $USER_LDFLAGS $ld_shared_flag -lbz2 $LIBSOCKET" + kde_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CFLAGS $cxx_shared_flag $all_includes $USER_INCLUDES" + + AC_TRY_LINK(dnl + [ + #define BZ_NO_STDIO + #include + ], + [ bz_stream s; (void) BZ2_bzDecompress(&s); ], + eval "ac_cv_lib_bzip2_prefix='-lbz2'", + eval "ac_cv_lib_bzip2_prefix=no") + LIBS="$kde_save_LIBS" + CXXFLAGS="$kde_save_CXXFLAGS" + AC_LANG_RESTORE + ])dnl + + AC_MSG_RESULT($ac_cv_lib_bzip2_prefix) + + if test ! "$ac_cv_lib_bzip2_prefix" = no; then + BZIP2DIR=bzip2 + + LIBBZ2="$ac_cv_lib_bzip2_prefix" + AC_SUBST(LIBBZ2) + + AC_DEFINE(NEED_BZ2_PREFIX, 1, [Define if the libbz2 functions need the BZ2_ prefix]) + dnl else, we just ignore this + fi + +fi +AM_CONDITIONAL(include_BZIP2, test -n "$BZIP2DIR") +]) + +dnl ------------------------------------------------------------------------ +dnl Try to find the SSL headers and libraries. +dnl $(SSL_LDFLAGS) will be -Lsslliblocation (if needed) +dnl and $(SSL_INCLUDES) will be -Isslhdrlocation (if needed) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([KDE_CHECK_SSL], +[ +LIBSSL="-lssl -lcrypto" +AC_REQUIRE([KDE_CHECK_LIB64]) + +ac_ssl_includes=NO ac_ssl_libraries=NO +ssl_libraries="" +ssl_includes="" +AC_ARG_WITH(ssl-dir, + AC_HELP_STRING([--with-ssl-dir=DIR],[where the root of OpenSSL is installed]), + [ ac_ssl_includes="$withval"/include + ac_ssl_libraries="$withval"/lib$kdelibsuff + ]) + +want_ssl=yes +AC_ARG_WITH(ssl, + AC_HELP_STRING([--without-ssl],[disable SSL checks]), + [want_ssl=$withval]) + +if test $want_ssl = yes; then + +AC_MSG_CHECKING(for OpenSSL) + +AC_CACHE_VAL(ac_cv_have_ssl, +[#try to guess OpenSSL locations + + ssl_incdirs="/usr/include /usr/local/include /usr/ssl/include /usr/local/ssl/include $prefix/include $kde_extra_includes" + ssl_incdirs="$ac_ssl_includes $ssl_incdirs" + AC_FIND_FILE(openssl/ssl.h, $ssl_incdirs, ssl_incdir) + ac_ssl_includes="$ssl_incdir" + + ssl_libdirs="/usr/lib$kdelibsuff /usr/local/lib$kdelibsuff /usr/ssl/lib$kdelibsuff /usr/local/ssl/lib$kdelibsuff $libdir $prefix/lib$kdelibsuff $exec_prefix/lib$kdelibsuff $kde_extra_libs" + if test ! "$ac_ssl_libraries" = "NO"; then + ssl_libdirs="$ac_ssl_libraries $ssl_libdirs" + fi + + test=NONE + ssl_libdir=NONE + for dir in $ssl_libdirs; do + try="ls -1 $dir/libssl*" + if test=`eval $try 2> /dev/null`; then ssl_libdir=$dir; break; else echo "tried $dir" >&AC_FD_CC ; fi + done + + ac_ssl_libraries="$ssl_libdir" + + ac_ldflags_safe="$LDFLAGS" + ac_libs_safe="$LIBS" + + LDFLAGS="$LDFLAGS -L$ssl_libdir $all_libraries" + LIBS="$LIBS $LIBSSL -lRSAglue -lrsaref" + + AC_TRY_LINK(,void RSAPrivateEncrypt(void);RSAPrivateEncrypt();, + ac_ssl_rsaref="yes" + , + ac_ssl_rsaref="no" + ) + + LDFLAGS="$ac_ldflags_safe" + LIBS="$ac_libs_safe" + + if test "$ac_ssl_includes" = NO || test "$ac_ssl_libraries" = NO; then + have_ssl=no + else + have_ssl=yes; + fi + + ]) + + eval "$ac_cv_have_ssl" + + AC_MSG_RESULT([libraries $ac_ssl_libraries, headers $ac_ssl_includes]) + + AC_MSG_CHECKING([whether OpenSSL uses rsaref]) + AC_MSG_RESULT($ac_ssl_rsaref) + + AC_MSG_CHECKING([for easter eggs]) + AC_MSG_RESULT([none found]) + +else + have_ssl=no +fi + +if test "$have_ssl" = yes; then + AC_MSG_CHECKING(for OpenSSL version) + dnl Check for SSL version + AC_CACHE_VAL(ac_cv_ssl_version, + [ + + cat >conftest.$ac_ext < +#include + int main() { + +#ifndef OPENSSL_VERSION_NUMBER + printf("ssl_version=\\"error\\"\n"); +#else + if (OPENSSL_VERSION_NUMBER < 0x00906000) + printf("ssl_version=\\"old\\"\n"); + else + printf("ssl_version=\\"ok\\"\n"); +#endif + return (0); + } +EOF + + ac_save_CPPFLAGS=$CPPFLAGS + if test "$ac_ssl_includes" != "/usr/include"; then + CPPFLAGS="$CPPFLAGS -I$ac_ssl_includes" + fi + + if AC_TRY_EVAL(ac_link); then + + if eval `./conftest 2>&5`; then + if test $ssl_version = error; then + AC_MSG_ERROR([$ssl_incdir/openssl/opensslv.h doesn't define OPENSSL_VERSION_NUMBER !]) + else + if test $ssl_version = old; then + AC_MSG_WARN([OpenSSL version too old. Upgrade to 0.9.6 at least, see http://www.openssl.org. SSL support disabled.]) + have_ssl=no + fi + fi + ac_cv_ssl_version="ssl_version=$ssl_version" + else + AC_MSG_ERROR([Your system couldn't run a small SSL test program. + Check config.log, and if you can't figure it out, send a mail to + David Faure , attaching your config.log]) + fi + + else + AC_MSG_ERROR([Your system couldn't link a small SSL test program. + Check config.log, and if you can't figure it out, send a mail to + David Faure , attaching your config.log]) + fi + CPPFLAGS=$ac_save_CPPFLAGS + + ]) + + eval "$ac_cv_ssl_version" + AC_MSG_RESULT($ssl_version) +fi + +if test "$have_ssl" != yes; then + LIBSSL=""; +else + AC_DEFINE(HAVE_SSL, 1, [If we are going to use OpenSSL]) + ac_cv_have_ssl="have_ssl=yes \ + ac_ssl_includes=$ac_ssl_includes ac_ssl_libraries=$ac_ssl_libraries ac_ssl_rsaref=$ac_ssl_rsaref" + + + ssl_libraries="$ac_ssl_libraries" + ssl_includes="$ac_ssl_includes" + + if test "$ac_ssl_rsaref" = yes; then + LIBSSL="-lssl -lcrypto -lRSAglue -lrsaref" + fi + + if test $ssl_version = "old"; then + AC_DEFINE(HAVE_OLD_SSL_API, 1, [Define if you have OpenSSL < 0.9.6]) + fi +fi + +SSL_INCLUDES= + +if test "$ssl_includes" = "/usr/include"; then + if test -f /usr/kerberos/include/krb5.h; then + SSL_INCLUDES="-I/usr/kerberos/include" + fi +elif test "$ssl_includes" != "/usr/local/include" && test -n "$ssl_includes"; then + SSL_INCLUDES="-I$ssl_includes" +fi + +if test "$ssl_libraries" = "/usr/lib" || test "$ssl_libraries" = "/usr/local/lib" || test -z "$ssl_libraries" || test "$ssl_libraries" = "NONE"; then + SSL_LDFLAGS="" +else + SSL_LDFLAGS="-L$ssl_libraries -R$ssl_libraries" +fi + +AC_SUBST(SSL_INCLUDES) +AC_SUBST(SSL_LDFLAGS) +AC_SUBST(LIBSSL) +]) + +AC_DEFUN([KDE_CHECK_STRLCPY], +[ + AC_REQUIRE([AC_CHECK_STRLCAT]) + AC_REQUIRE([AC_CHECK_STRLCPY]) + AC_CHECK_SIZEOF(size_t) + AC_CHECK_SIZEOF(unsigned long) + + AC_MSG_CHECKING([sizeof size_t == sizeof unsigned long]) + AC_TRY_COMPILE(,[ + #if SIZEOF_SIZE_T != SIZEOF_UNSIGNED_LONG + choke me + #endif + ],AC_MSG_RESULT([yes]),[ + AC_MSG_RESULT(no) + AC_MSG_ERROR([ + Apparently on your system our assumption sizeof size_t == sizeof unsigned long + does not apply. Please mail kde-devel@kde.org with a description of your system! + ]) + ]) +]) + +AC_DEFUN([KDE_CHECK_BINUTILS], +[ + AC_MSG_CHECKING([if ld supports unversioned version maps]) + + kde_save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -Wl,--version-script=conftest.map" + echo "{ local: extern \"C++\" { foo }; };" > conftest.map + AC_TRY_LINK([int foo;], +[ +#ifdef __INTEL_COMPILER +icc apparently does not support libtools version-info and version-script +at the same time. Dunno where the bug is, but until somebody figured out, +better disable the optional version scripts. +#endif + + foo = 42; +], kde_supports_versionmaps=yes, kde_supports_versionmaps=no) + LDFLAGS="$kde_save_LDFLAGS" + rm -f conftest.map + AM_CONDITIONAL(include_VERSION_SCRIPT, + [test "$kde_supports_versionmaps" = "yes" && test "$kde_use_debug_code" = "no"]) + + AC_MSG_RESULT($kde_supports_versionmaps) +]) + +AC_DEFUN([AM_PROG_OBJC],[ +AC_CHECK_PROGS(OBJC, gcc, gcc) +test -z "$OBJC" && AC_MSG_ERROR([no acceptable objective-c gcc found in \$PATH]) +if test "x${OBJCFLAGS-unset}" = xunset; then + OBJCFLAGS="-g -O2" +fi +AC_SUBST(OBJCFLAGS) +_AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES(OBJC)]) +]) + +AC_DEFUN([KDE_CHECK_PERL], +[ + KDE_FIND_PATH(perl, PERL, [$bindir $exec_prefix/bin $prefix/bin], [ + AC_MSG_ERROR([No Perl found in your $PATH. +We need perl to generate some code.]) + ]) + AC_SUBST(PERL) +]) + +AC_DEFUN([KDE_CHECK_LARGEFILE], +[ +AC_SYS_LARGEFILE +if test "$ac_cv_sys_file_offset_bits" != no; then + CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=$ac_cv_sys_file_offset_bits" +fi + +if test "x$ac_cv_sys_large_files" != "xno"; then + CPPFLAGS="$CPPFLAGS -D_LARGE_FILES=1" +fi + +]) + +dnl A small extension to PKG_CHECK_MODULES (defined in pkg.m4.in) +dnl which allows to search for libs that get installed into the KDE prefix. +dnl +dnl Syntax: KDE_PKG_CHECK_MODULES(KSTUFF, libkexif >= 0.2 glib = 1.3.4, action-if, action-not) +dnl defines KSTUFF_LIBS, KSTUFF_CFLAGS, see pkg-config man page +dnl also defines KSTUFF_PKG_ERRORS on error +AC_DEFUN([KDE_PKG_CHECK_MODULES], [ + + PKG_CONFIG_PATH="$prefix/lib/pkgconfig:$PKG_CONFIG_PATH" + if test "$prefix" != "$kde_libs_prefix"; then + PKG_CONFIG_PATH="$kde_libs_prefix/lib/pkgconfig:$PKG_CONFIG_PATH" + fi + export PKG_CONFIG_PATH + PKG_CHECK_MODULES($1,$2,$3,$4) +]) + +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +## Copyright 1996, 1997, 1998, 1999, 2000, 2001 +## Free Software Foundation, Inc. +## Originally by Gordon Matzigkeit , 1996 +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +## +## As a special exception to the GNU General Public License, if you +## distribute this file as part of a program that contains a +## configuration script generated by Autoconf, you may include it under +## the same distribution terms that you use for the rest of that program. + +# serial 47 AC_PROG_LIBTOOL + + +# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED) +# ----------------------------------------------------------- +# If this macro is not defined by Autoconf, define it here. +m4_ifdef([AC_PROVIDE_IFELSE], + [], + [m4_define([AC_PROVIDE_IFELSE], + [m4_ifdef([AC_PROVIDE_$1], + [$2], [$3])])]) + + +# AC_PROG_LIBTOOL +# --------------- +AC_DEFUN([AC_PROG_LIBTOOL], +[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl +dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX +dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. + AC_PROVIDE_IFELSE([AC_PROG_CXX], + [AC_LIBTOOL_CXX], + [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX + ])]) +dnl And a similar setup for Fortran 77 support + AC_PROVIDE_IFELSE([AC_PROG_F77], + [AC_LIBTOOL_F77], + [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77 +])]) + +dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. +dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run +dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. + AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [ifdef([AC_PROG_GCJ], + [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([A][M_PROG_GCJ], + [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([LT_AC_PROG_GCJ], + [define([LT_AC_PROG_GCJ], + defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])]) +])])# AC_PROG_LIBTOOL + + +# _AC_PROG_LIBTOOL +# ---------------- +AC_DEFUN([_AC_PROG_LIBTOOL], +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl +AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl +AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl +AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool --silent' +AC_SUBST(LIBTOOL)dnl + +# Prevent multiple expansion +define([AC_PROG_LIBTOOL], []) +])# _AC_PROG_LIBTOOL + + +# AC_LIBTOOL_SETUP +# ---------------- +AC_DEFUN([AC_LIBTOOL_SETUP], +[AC_PREREQ(2.50)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl +AC_REQUIRE([AC_PROG_NM])dnl + +AC_REQUIRE([AC_PROG_LN_S])dnl +AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! +AC_REQUIRE([AC_OBJEXT])dnl +AC_REQUIRE([AC_EXEEXT])dnl +dnl + +AC_LIBTOOL_SYS_MAX_CMD_LEN +AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +AC_LIBTOOL_OBJDIR + +AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +_LT_AC_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e s/^X//' +[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] + +# Same as above, but do not quote variable references. +[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except M$VC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" + +AC_CHECK_TOOL(AR, ar, false) +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(STRIP, strip, :) + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$SED" && SED=sed +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds" + ;; + *) + old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + AC_PATH_MAGIC + fi + ;; +esac + +AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +enable_win32_dll=yes, enable_win32_dll=no) + +AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +AC_ARG_WITH([pic], + [AC_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) +test -z "$pic_mode" && pic_mode=default + +# Use C for the default configuration in the libtool script +tagname= +AC_LIBTOOL_LANG_C_CONFIG +_LT_AC_TAGCONFIG +])# AC_LIBTOOL_SETUP + + +# _LT_AC_SYS_COMPILER +# ------------------- +AC_DEFUN([_LT_AC_SYS_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_AC_SYS_COMPILER + + +# _LT_AC_SYS_LIBPATH_AIX +# ---------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX], +[AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_AC_SYS_LIBPATH_AIX + + +# _LT_AC_SHELL_INIT(ARG) +# ---------------------- +AC_DEFUN([_LT_AC_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_AC_SHELL_INIT + + +# _LT_AC_PROG_ECHO_BACKSLASH +# -------------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], +[_LT_AC_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +echo=${ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null && + echo_test_string="`eval $cmd`" && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(ECHO) +])])# _LT_AC_PROG_ECHO_BACKSLASH + + +# _LT_AC_LOCK +# ----------- +AC_DEFUN([_LT_AC_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case "`/usr/bin/file conftest.o`" in + *32-bit*) + LINUX_64_MODE="32" + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + LINUX_64_MODE="64" + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw* | *-*-pw32*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; + ]) +esac + +need_locks="$enable_libtool_lock" + +])# _LT_AC_LOCK + + +# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], +[AC_REQUIRE([LT_AC_PROG_SED]) +AC_CACHE_CHECK([$1], [$2], + [$2=no + ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s conftest.err; then + $2=yes + fi + fi + $rm conftest* +]) + +if test x"[$]$2" = xyes; then + ifelse([$5], , :, [$5]) +else + ifelse([$6], , :, [$6]) +fi +])# AC_LIBTOOL_COMPILER_OPTION + + +# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ------------------------------------------------------------ +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], +[AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + else + $2=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + ifelse([$4], , :, [$4]) +else + ifelse([$5], , :, [$5]) +fi +])# AC_LIBTOOL_LINKER_OPTION + + +# AC_LIBTOOL_SYS_MAX_CMD_LEN +# -------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], +[# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + testring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + *) + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while (test "X"`$CONFIG_SHELL [$]0 --fallback-echo "X$testring" 2>/dev/null` \ + = "XX$testring") >/dev/null 2>&1 && + new_result=`expr "X$testring" : ".*" 2>&1` && + lt_cv_sys_max_cmd_len=$new_result && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + testring=$testring$testring + done + testring= + # Add a significant safety factor because C++ compilers can tack on massive + # amounts of additional arguments before passing them to the linker. + # It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +])# AC_LIBTOOL_SYS_MAX_CMD_LEN + + +# _LT_AC_CHECK_DLFCN +# -------------------- +AC_DEFUN([_LT_AC_CHECK_DLFCN], +[AC_CHECK_HEADERS(dlfcn.h)dnl +])# _LT_AC_CHECK_DLFCN + + +# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ------------------------------------------------------------------ +AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +}] +EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_unknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_AC_TRY_DLOPEN_SELF + + +# AC_LIBTOOL_DLOPEN_SELF +# ------------------- +AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + LDFLAGS="$LDFLAGS $link_static_flag" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +])# AC_LIBTOOL_DLOPEN_SELF + + +# AC_LIBTOOL_PROG_CC_C_O([TAGNAME]) +# --------------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler +AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + # According to Tom Tromey, Ian Lance Taylor reported there are C compilers + # that will create temporary files in the current directory regardless of + # the output directory. Thus, making CWD read-only will cause this test + # to fail, enabling locking or at least warning the user not to do parallel + # builds. + chmod -w . + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s out/conftest.err; then + _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . + $rm conftest* out/* + rmdir out + cd .. + rmdir conftest + $rm conftest* +]) +])# AC_LIBTOOL_PROG_CC_C_O + + +# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME]) +# ----------------------------------------- +# Check to see if we can do hard links to lock some files if needed +AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], +[AC_REQUIRE([_LT_AC_LOCK])dnl + +hard_links="nottested" +if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS + + +# AC_LIBTOOL_OBJDIR +# ----------------- +AC_DEFUN([AC_LIBTOOL_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +])# AC_LIBTOOL_OBJDIR + + +# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME]) +# ---------------------------------------------- +# Check hardcoding attributes. +AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_AC_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \ + test -n "$_LT_AC_TAGVAR(runpath_var $1)" || \ + test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)"="Xyes" ; then + + # We can hardcode non-existant directories. + if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_AC_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_AC_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_AC_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH + + +# AC_LIBTOOL_SYS_LIB_STRIP +# ------------------------ +AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP], +[striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) +fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +])# AC_LIBTOOL_SYS_LIB_STRIP + + +# AC_LIBTOOL_SYS_DYNAMIC_LINKER +# ----------------------------- +# PORTME Fill in your ld.so characteristics +AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER], +[AC_MSG_CHECKING([dynamic linker characteristics]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi4*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext='$(test .$module = .yes && echo .so || echo .dylib)' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd*-gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd*) + objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + *) # from 3.2 on + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case "$host_cpu" in + ia64*) + shrext='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + libsuff= + if test "x$LINUX_64_MODE" = x64; then + # Some platforms are per default 64-bit, so there's no /lib64 + if test -d /lib64; then + libsuff=64 + fi + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff}" + sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}" + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no +])# AC_LIBTOOL_SYS_DYNAMIC_LINKER + + +# _LT_AC_TAGCONFIG +# ---------------- +AC_DEFUN([_LT_AC_TAGCONFIG], +[AC_ARG_WITH([tags], + [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@], + [include additional configurations @<:@automatic@:>@])], + [tagnames="$withval"]) + +if test -f "$ltmain" && test -n "$tagnames"; then + if test ! -f "${ofile}"; then + AC_MSG_WARN([output file `$ofile' does not exist]) + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) + else + AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) + fi + fi + + # Extract list of available tagged configurations in $ofile. + # Note that this assumes the entire list is on one line. + available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` + + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for tagname in $tagnames; do + IFS="$lt_save_ifs" + # Check whether tagname contains only valid characters + case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in + "") ;; + *) AC_MSG_ERROR([invalid tag name: $tagname]) + ;; + esac + + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null + then + AC_MSG_ERROR([tag name \"$tagname\" already exists]) + fi + + # Update the list of available tags. + if test -n "$tagname"; then + echo appending configuration tag \"$tagname\" to $ofile + + case $tagname in + CXX) + if test -n "$CXX" && test "X$CXX" != "Xno"; then + AC_LIBTOOL_LANG_CXX_CONFIG + else + tagname="" + fi + ;; + + F77) + if test -n "$F77" && test "X$F77" != "Xno"; then + AC_LIBTOOL_LANG_F77_CONFIG + else + tagname="" + fi + ;; + + GCJ) + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + AC_LIBTOOL_LANG_GCJ_CONFIG + else + tagname="" + fi + ;; + + RC) + AC_LIBTOOL_LANG_RC_CONFIG + ;; + + *) + AC_MSG_ERROR([Unsupported tag name: $tagname]) + ;; + esac + + # Append the new tag name to the list of available tags. + if test -n "$tagname" ; then + available_tags="$available_tags $tagname" + fi + fi + done + IFS="$lt_save_ifs" + + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + else + rm -f "${ofile}T" + AC_MSG_ERROR([unable to update list of available tagged configurations.]) + fi +fi +])# _LT_AC_TAGCONFIG + + +# AC_LIBTOOL_DLOPEN +# ----------------- +# enable checks for dlopen support +AC_DEFUN([AC_LIBTOOL_DLOPEN], + [AC_BEFORE([$0],[AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_DLOPEN + + +# AC_LIBTOOL_WIN32_DLL +# -------------------- +# declare package support for building win32 dll's +AC_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_BEFORE([$0], [AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_WIN32_DLL + + +# AC_ENABLE_SHARED([DEFAULT]) +# --------------------------- +# implement the --enable-shared flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_SHARED], +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([shared], + [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]AC_ENABLE_SHARED_DEFAULT) +])# AC_ENABLE_SHARED + + +# AC_DISABLE_SHARED +# ----------------- +#- set the default shared flag to --disable-shared +AC_DEFUN([AC_DISABLE_SHARED], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no) +])# AC_DISABLE_SHARED + + +# AC_ENABLE_STATIC([DEFAULT]) +# --------------------------- +# implement the --enable-static flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_STATIC], +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([static], + [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]AC_ENABLE_STATIC_DEFAULT) +])# AC_ENABLE_STATIC + + +# AC_DISABLE_STATIC +# ----------------- +# set the default static flag to --disable-static +AC_DEFUN([AC_DISABLE_STATIC], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no) +])# AC_DISABLE_STATIC + + +# AC_ENABLE_FAST_INSTALL([DEFAULT]) +# --------------------------------- +# implement the --enable-fast-install flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_FAST_INSTALL], +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([fast-install], + [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT) +])# AC_ENABLE_FAST_INSTALL + + +# AC_DISABLE_FAST_INSTALL +# ----------------------- +# set the default to --disable-fast-install +AC_DEFUN([AC_DISABLE_FAST_INSTALL], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no) +])# AC_DISABLE_FAST_INSTALL + + +# AC_LIBTOOL_PICMODE([MODE]) +# -------------------------- +# implement the --with-pic flag +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +AC_DEFUN([AC_LIBTOOL_PICMODE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +pic_mode=ifelse($#,1,$1,default) +])# AC_LIBTOOL_PICMODE + + +# AC_PROG_EGREP +# ------------- +# This is predefined starting with Autoconf 2.54, so this conditional +# definition can be removed once we require Autoconf 2.54 or later. +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP], +[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], + [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi]) + EGREP=$ac_cv_prog_egrep + AC_SUBST([EGREP]) +])]) + + +# AC_PATH_TOOL_PREFIX +# ------------------- +# find a file program which can recognise shared library +AC_DEFUN([AC_PATH_TOOL_PREFIX], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +])# AC_PATH_TOOL_PREFIX + + +# AC_PATH_MAGIC +# ------------- +# find a file program which can recognise a shared library +AC_DEFUN([AC_PATH_MAGIC], +[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# AC_PATH_MAGIC + + +# AC_PROG_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH([gnu-ld], + [AC_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no]) +AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case "$host_cpu" in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + irix5* | nonstopux*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" + ;; + *) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[[1234]] dynamic lib MIPS - version 1" + ;; + esac + lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*` + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux*) + case $host_cpu in + alpha* | hppa* | i*86 | ia64* | m68* | mips* | powerpc* | sparc* | s390* | sh* | x86_64* ) + lt_cv_deplibs_check_method=pass_all ;; + # the debian people say, arm and glibc 2.3.1 works for them with pass_all + arm* ) + lt_cv_deplibs_check_method=pass_all ;; + *) + # glibc up to 2.1.1 does not perform some relocations on ARM + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; + esac + lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +nto-qnx*) + lt_cv_deplibs_check_method=unknown + ;; + +openbsd*) + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB shared object' + else + lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library' + fi + ;; + +osf3* | osf4* | osf5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method='file_magic COFF format alpha shared library' + lt_cv_file_magic_test_file=/shlib/libc.so + lt_cv_deplibs_check_method=pass_all + ;; + +sco3.2v5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + lt_cv_file_magic_test_file=/lib/libc.so + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown +])# AC_DEPLIBS_CHECK_METHOD + + +# AC_PROG_NM +# ---------- +# find the pathname to a BSD-compatible name lister +AC_DEFUN([AC_PROG_NM], +[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/${ac_tool_prefix}nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + esac + fi + done + IFS="$lt_save_ifs" + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi]) +NM="$lt_cv_path_NM" +])# AC_PROG_NM + + +# AC_CHECK_LIBM +# ------------- +# check for math library +AC_DEFUN([AC_CHECK_LIBM], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +])# AC_CHECK_LIBM + + +# AC_LIBLTDL_CONVENIENCE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl convenience library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-convenience to the configure arguments. Note that LIBLTDL +# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If +# DIRECTORY is not provided, it is assumed to be `libltdl'. LIBLTDL will +# be prefixed with '${top_builddir}/' and LTDLINCL will be prefixed with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +AC_DEFUN([AC_LIBLTDL_CONVENIENCE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_CONVENIENCE + + +# AC_LIBLTDL_INSTALLABLE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl installable library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-install to the configure arguments. Note that LIBLTDL +# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If +# DIRECTORY is not provided and an installed libltdl is not found, it is +# assumed to be `libltdl'. LIBLTDL will be prefixed with '${top_builddir}/' +# and LTDLINCL will be prefixed with '${top_srcdir}/' (note the single +# quotes!). If your package is not flat and you're not using automake, +# define top_builddir and top_srcdir appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN([AC_LIBLTDL_INSTALLABLE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, lt_dlinit, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + LTDLINCL= + fi + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_INSTALLABLE + + +# AC_LIBTOOL_CXX +# -------------- +# enable support for C++ libraries +AC_DEFUN([AC_LIBTOOL_CXX], +[AC_REQUIRE([_LT_AC_LANG_CXX]) +])# AC_LIBTOOL_CXX + + +# _LT_AC_LANG_CXX +# --------------- +AC_DEFUN([_LT_AC_LANG_CXX], +[AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([AC_PROG_CXXCPP]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX]) +])# _LT_AC_LANG_CXX + + +# AC_LIBTOOL_F77 +# -------------- +# enable support for Fortran 77 libraries +AC_DEFUN([AC_LIBTOOL_F77], +[AC_REQUIRE([_LT_AC_LANG_F77]) +])# AC_LIBTOOL_F77 + + +# _LT_AC_LANG_F77 +# --------------- +AC_DEFUN([_LT_AC_LANG_F77], +[AC_REQUIRE([AC_PROG_F77]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77]) +])# _LT_AC_LANG_F77 + + +# AC_LIBTOOL_GCJ +# -------------- +# enable support for GCJ libraries +AC_DEFUN([AC_LIBTOOL_GCJ], +[AC_REQUIRE([_LT_AC_LANG_GCJ]) +])# AC_LIBTOOL_GCJ + + +# _LT_AC_LANG_GCJ +# --------------- +AC_DEFUN([_LT_AC_LANG_GCJ], +[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], + [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], + [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], + [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ]) +])# _LT_AC_LANG_GCJ + + +# AC_LIBTOOL_RC +# -------------- +# enable support for Windows resource files +AC_DEFUN([AC_LIBTOOL_RC], +[AC_REQUIRE([LT_AC_PROG_RC]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC]) +])# AC_LIBTOOL_RC + + +# AC_LIBTOOL_LANG_C_CONFIG +# ------------------------ +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG]) +AC_DEFUN([_LT_AC_LANG_C_CONFIG], +[lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}\n' + +_LT_AC_SYS_COMPILER + +# +# Check for any special shared library compilation flags. +# +_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)= +if test "$GCC" = no; then + case $host_os in + sco3.2v5*) + _LT_AC_TAGVAR(lt_prog_cc_shlib, $1)='-belf' + ;; + esac +fi +if test -n "$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)"; then + AC_MSG_WARN([`$CC' requires `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to build shared libraries]) + if echo "$old_CC $old_CFLAGS " | grep "[[ ]]$]_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)[[[ ]]" >/dev/null; then : + else + AC_MSG_WARN([add `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to the CC or CFLAGS env variable and reconfigure]) + _LT_AC_TAGVAR(lt_cv_prog_cc_can_build_shared, $1)=no + fi +fi + + +# +# Check to make sure the static flag actually works. +# +AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $_LT_AC_TAGVAR(lt_prog_compiler_static, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1), + $_LT_AC_TAGVAR(lt_prog_compiler_static, $1), + [], + [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=]) + + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_DLOPEN_SELF($1) + +# Report which librarie types wil actually be built +AC_MSG_CHECKING([if libtool supports shared libraries]) +AC_MSG_RESULT([$can_build_shared]) + +AC_MSG_CHECKING([whether to build shared libraries]) +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + darwin* | rhapsody*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case "$host_os" in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress' + ;; + *) # Darwin 1.3 on + test -z ${LD_TWOLEVEL_NAMESPACE} && _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' + ;; + esac + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; +esac +AC_MSG_RESULT([$enable_shared]) + +AC_MSG_CHECKING([whether to build static libraries]) +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +AC_MSG_RESULT([$enable_static]) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_C_CONFIG + + +# AC_LIBTOOL_LANG_CXX_CONFIG +# -------------------------- +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)]) +AC_DEFUN([_LT_AC_LANG_CXX_CONFIG], +[AC_LANG_PUSH(C++) +AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([AC_PROG_CXXCPP]) + +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_AC_TAGVAR(allow_undefined_flag, $1)= +_LT_AC_TAGVAR(always_export_symbols, $1)=no +_LT_AC_TAGVAR(archive_expsym_cmds, $1)= +_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_direct, $1)=no +_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_AC_TAGVAR(hardcode_libdir_separator, $1)= +_LT_AC_TAGVAR(hardcode_minus_L, $1)=no +_LT_AC_TAGVAR(hardcode_automatic, $1)=no +_LT_AC_TAGVAR(module_cmds, $1)= +_LT_AC_TAGVAR(module_expsym_cmds, $1)= +_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown +_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_AC_TAGVAR(no_undefined_flag, $1)= +_LT_AC_TAGVAR(whole_archive_flag_spec, $1)= +_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Dependencies to place before and after the object being linked: +_LT_AC_TAGVAR(predep_objects, $1)= +_LT_AC_TAGVAR(postdep_objects, $1)= +_LT_AC_TAGVAR(predeps, $1)= +_LT_AC_TAGVAR(postdeps, $1)= +_LT_AC_TAGVAR(compiler_lib_search_path, $1)= + +# Source file extension for C++ test sources. +ac_ext=cc + +# Object file extension for compiled C++ test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(int, char *[]) { return(0); }\n' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_LD=$LD +lt_save_GCC=$GCC +GCC=$GXX +lt_save_with_gnu_ld=$with_gnu_ld +lt_save_path_LD=$lt_cv_path_LD +if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx +else + unset lt_cv_prog_gnu_ld +fi +if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX +else + unset lt_cv_path_LD +fi +test -z "${LDCXX+set}" || LD=$LDCXX +CC=${CXX-"c++"} +compiler=$CC +_LT_AC_TAGVAR(compiler, $1)=$CC +cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'` + +# We don't want -fno-exception wen compiling C++ code, so set the +# no_builtin_flag separately +if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' +else + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= +fi + +if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + AC_PROG_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ + grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + +else + GXX=no + with_gnu_ld=no + wlarc= +fi + +# PORTME: fill in a description of your system's C++ link characteristics +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +_LT_AC_TAGVAR(ld_shlibs, $1)=yes +case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # KDE requires run time linking. Make it the default. + aix_use_runtimelinking=yes + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='-qmkshrobj ${wl}-G' + else + shared_flag='-qmkshrobj' + fi + fi + fi + + # Let the compiler handle the export list. + _LT_AC_TAGVAR(always_export_symbols, $1)=no + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_AC_TAGVAR(archive_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '" $shared_flag" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # -bexpall does not export symbols beginning with underscore (_) + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds it's shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + darwin* | rhapsody*) + if test "$GXX" = yes; then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case "$host_os" in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress' + ;; + *) # Darwin 1.3 on + test -z ${LD_TWOLEVEL_NAMESPACE} && _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' + ;; + esac + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + fi + _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + dgux*) + case $cc_basename in + ec++) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + freebsd[12]*) + # C++ shared libraries reported to be fairly broken before switch to ELF + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + freebsd-elf*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + freebsd*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + ;; + gnu*) + ;; + hpux9*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | egrep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + case "$host_cpu" in + hppa*64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + ;; + *) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case "$host_cpu" in + hppa*64*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + ia64*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC) + case "$host_cpu" in + hppa*64*|ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case "$host_cpu" in + ia64*|hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + irix5* | irix6*) + case $cc_basename in + CC) + # SGI C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' + fi + fi + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + linux*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc) + # Intel C++ + with_gnu_ld=yes + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + cxx) + # Compaq C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + esac + ;; + lynxos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + m88k*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + mvs*) + case $cc_basename in + cxx) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + osf3*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + + ;; + RCC) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + osf4* | osf5*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' + ;; + RCC) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry $objdir/so_locations -o $lib~ + $rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + psos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + sco*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + lcc) + # Lucid + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + solaris*) + case $cc_basename in + CC) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The C++ compiler is used as linker so we must use $wl + # flag to pass the commands to the underlying system + # linker. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[[LR]]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | grep -v '^2\.7' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + fi + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + fi + ;; + esac + ;; + sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + tandem*) + case $cc_basename in + NCC) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + vxworks*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; +esac +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_AC_TAGVAR(GCC, $1)="$GXX" +_LT_AC_TAGVAR(LD, $1)="$LD" + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +AC_LIBTOOL_POSTDEP_PREDEP($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_DLOPEN_SELF($1) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC=$lt_save_CC +LDCXX=$LD +LD=$lt_save_LD +GCC=$lt_save_GCC +with_gnu_ldcxx=$with_gnu_ld +with_gnu_ld=$lt_save_with_gnu_ld +lt_cv_path_LDCXX=$lt_cv_path_LD +lt_cv_path_LD=$lt_save_path_LD +lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld +lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +])# AC_LIBTOOL_LANG_CXX_CONFIG + +# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME]) +# ------------------------ +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[ +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +ifelse([$1],[],[cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext <> "$cfgfile" +ifelse([$1], [], +[#! $SHELL + +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="$SED -e s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +# The names of the tagged configurations supported by this script. +available_tags= + +# ### BEGIN LIBTOOL CONFIG], +[# ### BEGIN LIBTOOL TAG CONFIG: $tagname]) + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1) + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# A language-specific compiler. +CC=$lt_[]_LT_AC_TAGVAR(compiler, $1) + +# Is the compiler the GNU C compiler? +with_gcc=$_LT_AC_TAGVAR(GCC, $1) + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_[]_LT_AC_TAGVAR(LD, $1) + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext='$shrext' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) + +# Must we lock files when doing compilation ? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1) + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1) + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1) + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1) + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1) +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1) + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) + +# Commands used to build and install a shared archive. +archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1) +archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1) +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1) +module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1) + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1) + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1) + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1) + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1) + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1) + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1) + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1) + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1) + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1) + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1) + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1) + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1) + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)" + +# Set to yes if exported symbols are required. +always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1) + +# The commands to list exported symbols. +export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1) + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1) + +# Symbols that must always be exported. +include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1) + +ifelse([$1],[], +[# ### END LIBTOOL CONFIG], +[# ### END LIBTOOL TAG CONFIG: $tagname]) + +__EOF__ + +ifelse([$1],[], [ + case $host_os in + aix3*) + cat <<\EOF >> "$cfgfile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || \ + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +]) +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + test -f Makefile && make "$ltmain" +fi +])# AC_LIBTOOL_CONFIG + + +# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl + +_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI + + +# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +# --------------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_NM]) +AC_REQUIRE([AC_OBJEXT]) +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Transform the above into a raw symbol and a C symbol. +symxfrm='\1 \2\3 \3' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) # Its linker distinguishes data from code symbols + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris* | sysv5*) + symcode='[[BDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGISTW]]' ;; +esac + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Write the raw and C identifiers. + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if grep ' nm_test_var$' "$nlist" >/dev/null; then + if grep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[[]] = +{ +EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi +]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE + + +# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME]) +# --------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC], +[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) + ifelse([$1],[CXX],[ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | os2* | pw32*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix4* | aix5*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68) + # Green Hills C++ Compiler + # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux*) + case $cc_basename in + KCC) + # KAI C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + icpc) + # Intel C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + cxx) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC) + # Rational C++ 2.4.1 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx) + # Digital/Compaq C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + sco*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + *) + ;; + esac + ;; + solaris*) + case $cc_basename in + CC) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC) + # Sun C++ 4.x + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc) + # Lucid + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC) + # NonStop-UX NCC 3.20 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + unixware*) + ;; + vxworks*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + newsos6) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + linux*) + case $CC in + icc* | ecc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + ccc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + sco3.2v5*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-dn' + ;; + + solaris*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sunos4*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + uts4*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then + AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1), + [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +case "$host_os" in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])" + ;; +esac +]) + + +# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME]) +# ------------------------------------ +# See if the linker supports building shared libraries. +AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS], +[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +ifelse([$1],[CXX],[ + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix4* | aix5*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + ;; + *) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +],[ + runpath_var= + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)= + _LT_AC_TAGVAR(archive_expsym_cmds, $1)= + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)= + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + _LT_AC_TAGVAR(thread_safe_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown + _LT_AC_TAGVAR(hardcode_automatic, $1)=no + _LT_AC_TAGVAR(module_cmds, $1)= + _LT_AC_TAGVAR(module_expsym_cmds, $1)= + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_AC_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + else + ld_shlibs=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris* | sysv5*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sunos4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = yes; then + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + + # KDE requires run time linking. Make it the default. + aix_use_runtimelinking=yes + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='-qmkshrobj ${wl}-G' + else + shared_flag='-qmkshrobj' + fi + fi + fi + + # Let the compiler handle the export list. + _LT_AC_TAGVAR(always_export_symbols, $1)=no + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_AC_TAGVAR(archive_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '" $shared_flag" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # -bexpall does not export symbols beginning with underscore (_) + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds it's shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + # see comment about different semantics on the GNU ld section + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + bsdi4*) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + if test "$GXX" = yes ; then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case "$host_os" in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress' + ;; + *) # Darwin 1.3 on + test -z ${LD_TWOLEVEL_NAMESPACE} && _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' + ;; + esac + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + fi + _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + dgux*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10* | hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case "$host_cpu" in + hppa*64*|ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case "$host_cpu" in + hppa*64*|ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + case "$host_cpu" in + hppa*64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + ;; + *) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + openbsd*) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + sco3.2v5*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ;; + + solaris*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4.2uw2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + hardcode_runpath_var=yes + runpath_var=LD_RUN_PATH + ;; + + sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z ${wl}text' + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv5*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + ;; + + uts4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +# +# Do we need to explicitly link libc? +# +case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_AC_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1) + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) + then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac +])# AC_LIBTOOL_PROG_LD_SHLIBS + + +# _LT_AC_FILE_LTDLL_C +# ------------------- +# Be careful that the start marker always follows a newline. +AC_DEFUN([_LT_AC_FILE_LTDLL_C], [ +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include +# #undef WIN32_LEAN_AND_MEAN +# #include +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ +])# _LT_AC_FILE_LTDLL_C + + +# _LT_AC_TAGVAR(VARNAME, [TAGNAME]) +# --------------------------------- +AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])]) + + +# old names +AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) +AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) +AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) +AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) +AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) + +# This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL]) + +AC_DEFUN([LT_AC_PROG_GCJ], +[AC_CHECK_TOOL(GCJ, gcj, no) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS) +]) + +AC_DEFUN([LT_AC_PROG_RC], +[AC_CHECK_TOOL(RC, windres, no) +]) + +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ +# LT_AC_PROG_SED +# -------------- +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +AC_DEFUN([LT_AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && break + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_MSG_RESULT([$SED]) +]) + +dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not) +dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page +dnl also defines GSTUFF_PKG_ERRORS on error +AC_DEFUN([PKG_CHECK_MODULES], [ + succeeded=no + + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + + if test "$PKG_CONFIG" = "no" ; then + echo "*** The pkg-config script could not be found. Make sure it is" + echo "*** in your path, or set the PKG_CONFIG environment variable" + echo "*** to the full path to pkg-config." + echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." + else + PKG_CONFIG_MIN_VERSION=0.9.0 + if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then + AC_MSG_CHECKING(for $2) + + if $PKG_CONFIG --exists "$2" ; then + AC_MSG_RESULT(yes) + succeeded=yes + + AC_MSG_CHECKING($1_CFLAGS) + $1_CFLAGS=`$PKG_CONFIG --cflags "$2"` + AC_MSG_RESULT($$1_CFLAGS) + + AC_MSG_CHECKING($1_LIBS) + $1_LIBS=`$PKG_CONFIG --libs "$2"` + AC_MSG_RESULT($$1_LIBS) + else + $1_CFLAGS="" + $1_LIBS="" + ## If we have a custom action on failure, don't print errors, but + ## do set a variable so people can do so. + $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` + ifelse([$4], ,echo $$1_PKG_ERRORS,) + fi + + AC_SUBST($1_CFLAGS) + AC_SUBST($1_LIBS) + else + echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer." + echo "*** See http://www.freedesktop.org/software/pkgconfig" + fi + fi + + if test $succeeded = yes; then + ifelse([$3], , :, [$3]) + else + ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4]) + fi +]) + + diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..f7915e1 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,12463 @@ +# aclocal.m4 generated automatically by aclocal 1.6.3 -*- Autoconf -*- + +# Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +dnl This file is part of the KDE libraries/packages +dnl Copyright (C) 1997 Janos Farkas (chexum@shadow.banki.hu) +dnl (C) 1997,98,99 Stephan Kulow (coolo@kde.org) + +dnl This file is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Library General Public +dnl License as published by the Free Software Foundation; either +dnl version 2 of the License, or (at your option) any later version. + +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Library General Public License for more details. + +dnl You should have received a copy of the GNU Library General Public License +dnl along with this library; see the file COPYING.LIB. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +dnl Boston, MA 02110-1301, USA. + +dnl IMPORTANT NOTE: +dnl Please do not modify this file unless you expect your modifications to be +dnl carried into every other module in the repository. +dnl +dnl Single-module modifications are best placed in configure.in for kdelibs +dnl and kdebase or configure.in.in if present. + +# KDE_PATH_X_DIRECT +dnl Internal subroutine of AC_PATH_X. +dnl Set ac_x_includes and/or ac_x_libraries. +AC_DEFUN([KDE_PATH_X_DIRECT], +[ +AC_REQUIRE([KDE_CHECK_LIB64]) + +if test "$ac_x_includes" = NO; then + # Guess where to find include files, by looking for this one X11 .h file. + test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h + + # First, try using that file with no special directory specified. +AC_TRY_CPP([#include <$x_direct_test_include>], +[# We can compile using X headers with no special include directory. +ac_x_includes=], +[# Look for the header file in a standard set of common directories. +# Check X11 before X11Rn because it is often a symlink to the current release. + for ac_dir in \ + /usr/X11/include \ + /usr/X11R6/include \ + /usr/X11R5/include \ + /usr/X11R4/include \ + \ + /usr/include/X11 \ + /usr/include/X11R6 \ + /usr/include/X11R5 \ + /usr/include/X11R4 \ + \ + /usr/local/X11/include \ + /usr/local/X11R6/include \ + /usr/local/X11R5/include \ + /usr/local/X11R4/include \ + \ + /usr/local/include/X11 \ + /usr/local/include/X11R6 \ + /usr/local/include/X11R5 \ + /usr/local/include/X11R4 \ + \ + /usr/X386/include \ + /usr/x386/include \ + /usr/XFree86/include/X11 \ + \ + /usr/include \ + /usr/local/include \ + /usr/unsupported/include \ + /usr/athena/include \ + /usr/local/x11r5/include \ + /usr/lpp/Xamples/include \ + \ + /usr/openwin/include \ + /usr/openwin/share/include \ + ; \ + do + if test -r "$ac_dir/$x_direct_test_include"; then + ac_x_includes=$ac_dir + break + fi + done]) +fi # $ac_x_includes = NO + +if test "$ac_x_libraries" = NO; then + # Check for the libraries. + + test -z "$x_direct_test_library" && x_direct_test_library=Xt + test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc + + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS="$LIBS" + LIBS="-l$x_direct_test_library $LIBS" +AC_TRY_LINK([#include ], [${x_direct_test_function}(1)], +[LIBS="$ac_save_LIBS" +# We can link X programs with no special library path. +ac_x_libraries=], +[LIBS="$ac_save_LIBS" +# First see if replacing the include by lib works. +# Check X11 before X11Rn because it is often a symlink to the current release. +for ac_dir in `echo "$ac_x_includes" | sed s/include/lib${kdelibsuff}/` \ + /usr/X11/lib${kdelibsuff} \ + /usr/X11R6/lib${kdelibsuff} \ + /usr/X11R5/lib${kdelibsuff} \ + /usr/X11R4/lib${kdelibsuff} \ + \ + /usr/lib${kdelibsuff}/X11 \ + /usr/lib${kdelibsuff}/X11R6 \ + /usr/lib${kdelibsuff}/X11R5 \ + /usr/lib${kdelibsuff}/X11R4 \ + \ + /usr/local/X11/lib${kdelibsuff} \ + /usr/local/X11R6/lib${kdelibsuff} \ + /usr/local/X11R5/lib${kdelibsuff} \ + /usr/local/X11R4/lib${kdelibsuff} \ + \ + /usr/local/lib${kdelibsuff}/X11 \ + /usr/local/lib${kdelibsuff}/X11R6 \ + /usr/local/lib${kdelibsuff}/X11R5 \ + /usr/local/lib${kdelibsuff}/X11R4 \ + \ + /usr/X386/lib${kdelibsuff} \ + /usr/x386/lib${kdelibsuff} \ + /usr/XFree86/lib${kdelibsuff}/X11 \ + \ + /usr/lib${kdelibsuff} \ + /usr/local/lib${kdelibsuff} \ + /usr/unsupported/lib${kdelibsuff} \ + /usr/athena/lib${kdelibsuff} \ + /usr/local/x11r5/lib${kdelibsuff} \ + /usr/lpp/Xamples/lib${kdelibsuff} \ + /lib/usr/lib${kdelibsuff}/X11 \ + \ + /usr/openwin/lib${kdelibsuff} \ + /usr/openwin/share/lib${kdelibsuff} \ + ; \ +do +dnl Don't even attempt the hair of trying to link an X program! + for ac_extension in a so sl; do + if test -r $ac_dir/lib${x_direct_test_library}.$ac_extension; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done]) +fi # $ac_x_libraries = NO +]) + + +dnl ------------------------------------------------------------------------ +dnl Find a file (or one of more files in a list of dirs) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_FIND_FILE], +[ +$3=NO +for i in $2; +do + for j in $1; + do + echo "configure: __oline__: $i/$j" >&AC_FD_CC + if test -r "$i/$j"; then + echo "taking that" >&AC_FD_CC + $3=$i + break 2 + fi + done +done +]) + +dnl KDE_FIND_PATH(program-name, variable-name, list-of-dirs, +dnl if-not-found, test-parameter, prepend-path) +dnl +dnl Look for program-name in list-of-dirs+$PATH. +dnl If prepend-path is set, look in $PATH+list-of-dirs instead. +dnl If found, $variable-name is set. If not, if-not-found is evaluated. +dnl test-parameter: if set, the program is executed with this arg, +dnl and only a successful exit code is required. +AC_DEFUN([KDE_FIND_PATH], +[ + AC_MSG_CHECKING([for $1]) + if test -n "$$2"; then + kde_cv_path="$$2"; + else + kde_cache=`echo $1 | sed 'y%./+-%__p_%'` + + AC_CACHE_VAL(kde_cv_path_$kde_cache, + [ + kde_cv_path="NONE" + kde_save_IFS=$IFS + IFS=':' + dirs="" + for dir in $PATH; do + dirs="$dirs $dir" + done + if test -z "$6"; then dnl Append dirs in PATH (default) + dirs="$3 $dirs" + else dnl Prepend dirs in PATH (if 6th arg is set) + dirs="$dirs $3" + fi + IFS=$kde_save_IFS + + for dir in $dirs; do + if test -x "$dir/$1"; then + if test -n "$5" + then + evalstr="$dir/$1 $5 2>&1 " + if eval $evalstr; then + kde_cv_path="$dir/$1" + break + fi + else + kde_cv_path="$dir/$1" + break + fi + fi + done + + eval "kde_cv_path_$kde_cache=$kde_cv_path" + + ]) + + eval "kde_cv_path=\"`echo '$kde_cv_path_'$kde_cache`\"" + + fi + + if test -z "$kde_cv_path" || test "$kde_cv_path" = NONE; then + AC_MSG_RESULT(not found) + $4 + else + AC_MSG_RESULT($kde_cv_path) + $2=$kde_cv_path + + fi +]) + +AC_DEFUN([KDE_MOC_ERROR_MESSAGE], +[ + AC_MSG_ERROR([No Qt meta object compiler (moc) found! +Please check whether you installed Qt correctly. +You need to have a running moc binary. +configure tried to run $ac_cv_path_moc and the test didn't +succeed. If configure shouldn't have tried this one, set +the environment variable MOC to the right one before running +configure. +]) +]) + +AC_DEFUN([KDE_UIC_ERROR_MESSAGE], +[ + AC_MSG_WARN([No Qt ui compiler (uic) found! +Please check whether you installed Qt correctly. +You need to have a running uic binary. +configure tried to run $ac_cv_path_uic and the test didn't +succeed. If configure shouldn't have tried this one, set +the environment variable UIC to the right one before running +configure. +]) +]) + + +AC_DEFUN([KDE_CHECK_UIC_FLAG], +[ + AC_MSG_CHECKING([whether uic supports -$1 ]) + kde_cache=`echo $1 | sed 'y% .=/+-%____p_%'` + AC_CACHE_VAL(kde_cv_prog_uic_$kde_cache, + [ + cat >conftest.ui < +EOT + ac_uic_testrun="$UIC_PATH -$1 $2 conftest.ui >/dev/null" + if AC_TRY_EVAL(ac_uic_testrun); then + eval "kde_cv_prog_uic_$kde_cache=yes" + else + eval "kde_cv_prog_uic_$kde_cache=no" + fi + rm -f conftest* + ]) + + if eval "test \"`echo '$kde_cv_prog_uic_'$kde_cache`\" = yes"; then + AC_MSG_RESULT([yes]) + : + $3 + else + AC_MSG_RESULT([no]) + : + $4 + fi +]) + + +dnl ------------------------------------------------------------------------ +dnl Find the meta object compiler and the ui compiler in the PATH, +dnl in $QTDIR/bin, and some more usual places +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_PATH_QT_MOC_UIC], +[ + AC_REQUIRE([KDE_CHECK_PERL]) + qt_bindirs="" + for dir in $kde_qt_dirs; do + qt_bindirs="$qt_bindirs $dir/bin $dir/src/moc" + done + qt_bindirs="$qt_bindirs /usr/bin /usr/X11R6/bin /usr/local/qt/bin" + if test ! "$ac_qt_bindir" = "NO"; then + qt_bindirs="$ac_qt_bindir $qt_bindirs" + fi + + KDE_FIND_PATH(moc, MOC, [$qt_bindirs], [KDE_MOC_ERROR_MESSAGE]) + if test -z "$UIC_NOT_NEEDED"; then + KDE_FIND_PATH(uic, UIC_PATH, [$qt_bindirs], [UIC_PATH=""]) + if test -z "$UIC_PATH" ; then + KDE_UIC_ERROR_MESSAGE + exit 1 + else + UIC=$UIC_PATH + + if test $kde_qtver = 3; then + KDE_CHECK_UIC_FLAG(L,[/nonexistent],ac_uic_supports_libpath=yes,ac_uic_supports_libpath=no) + KDE_CHECK_UIC_FLAG(nounload,,ac_uic_supports_nounload=yes,ac_uic_supports_nounload=no) + + if test x$ac_uic_supports_libpath = xyes; then + UIC="$UIC -L \$(kde_widgetdir)" + fi + if test x$ac_uic_supports_nounload = xyes; then + UIC="$UIC -nounload" + fi + fi + fi + else + UIC="echo uic not available: " + fi + + AC_SUBST(MOC) + AC_SUBST(UIC) + + UIC_TR="i18n" + if test $kde_qtver = 3; then + UIC_TR="tr2i18n" + fi + + AC_SUBST(UIC_TR) +]) + +AC_DEFUN([KDE_1_CHECK_PATHS], +[ + KDE_1_CHECK_PATH_HEADERS + + KDE_TEST_RPATH= + + if test -n "$USE_RPATH"; then + + if test -n "$kde_libraries"; then + KDE_TEST_RPATH="-R $kde_libraries" + fi + + if test -n "$qt_libraries"; then + KDE_TEST_RPATH="$KDE_TEST_RPATH -R $qt_libraries" + fi + + if test -n "$x_libraries"; then + KDE_TEST_RPATH="$KDE_TEST_RPATH -R $x_libraries" + fi + + KDE_TEST_RPATH="$KDE_TEST_RPATH $KDE_EXTRA_RPATH" + fi + +AC_MSG_CHECKING([for KDE libraries installed]) +ac_link='$LIBTOOL_SHELL --silent --mode=link ${CXX-g++} -o conftest $CXXFLAGS $all_includes $CPPFLAGS $LDFLAGS $all_libraries conftest.$ac_ext $LIBS -lkdecore $LIBQT $KDE_TEST_RPATH 1>&5' + +if AC_TRY_EVAL(ac_link) && test -s conftest; then + AC_MSG_RESULT(yes) +else + AC_MSG_ERROR([your system fails at linking a small KDE application! +Check, if your compiler is installed correctly and if you have used the +same compiler to compile Qt and kdelibs as you did use now. +For more details about this problem, look at the end of config.log.]) +fi + +if eval `KDEDIR= ./conftest 2>&5`; then + kde_result=done +else + kde_result=problems +fi + +KDEDIR= ./conftest 2> /dev/null >&5 # make an echo for config.log +kde_have_all_paths=yes + +KDE_SET_PATHS($kde_result) + +]) + +AC_DEFUN([KDE_SET_PATHS], +[ + kde_cv_all_paths="kde_have_all_paths=\"yes\" \ + kde_htmldir=\"$kde_htmldir\" \ + kde_appsdir=\"$kde_appsdir\" \ + kde_icondir=\"$kde_icondir\" \ + kde_sounddir=\"$kde_sounddir\" \ + kde_datadir=\"$kde_datadir\" \ + kde_locale=\"$kde_locale\" \ + kde_cgidir=\"$kde_cgidir\" \ + kde_confdir=\"$kde_confdir\" \ + kde_kcfgdir=\"$kde_kcfgdir\" \ + kde_mimedir=\"$kde_mimedir\" \ + kde_toolbardir=\"$kde_toolbardir\" \ + kde_wallpaperdir=\"$kde_wallpaperdir\" \ + kde_templatesdir=\"$kde_templatesdir\" \ + kde_bindir=\"$kde_bindir\" \ + kde_servicesdir=\"$kde_servicesdir\" \ + kde_servicetypesdir=\"$kde_servicetypesdir\" \ + kde_moduledir=\"$kde_moduledir\" \ + kde_styledir=\"$kde_styledir\" \ + kde_widgetdir=\"$kde_widgetdir\" \ + xdg_appsdir=\"$xdg_appsdir\" \ + xdg_menudir=\"$xdg_menudir\" \ + xdg_directorydir=\"$xdg_directorydir\" \ + kde_result=$1" +]) + +AC_DEFUN([KDE_SET_DEFAULT_PATHS], +[ +if test "$1" = "default"; then + + if test -z "$kde_htmldir"; then + if test -f /etc/debian_version; then + if dpkg -s kdelibs4 | grep Status | grep not-installed 2>&1 >/dev/null; then + kde_htmldir='\${prefix}/share/doc/HTML'; + else + kde_htmldir='\${prefix}/share/doc/kde/HTML' + fi + else + kde_htmldir='\${prefix}/share/doc/HTML' + fi + fi + + if test -z "$kde_appsdir"; then + kde_appsdir='\${datadir}/applnk' + fi + if test -z "$kde_icondir"; then + kde_icondir='\${datadir}/icons' + fi + if test -z "$kde_sounddir"; then + kde_sounddir='\${datadir}/sounds' + fi + if test -z "$kde_datadir"; then + kde_datadir='\${datadir}/apps' + fi + if test -z "$kde_locale"; then + kde_locale='\${datadir}/locale' + fi + if test -z "$kde_cgidir"; then + kde_cgidir='\${exec_prefix}/cgi-bin' + fi + if test -z "$kde_confdir"; then + kde_confdir='\${datadir}/config' + fi + if test -z "$kde_kcfgdir"; then + kde_kcfgdir='\${datadir}/config.kcfg' + fi + if test -z "$kde_mimedir"; then + kde_mimedir='\${datadir}/mimelnk' + fi + if test -z "$kde_toolbardir"; then + kde_toolbardir='\${datadir}/toolbar' + fi + if test -z "$kde_wallpaperdir"; then + kde_wallpaperdir='\${datadir}/wallpapers' + fi + if test -z "$kde_templatesdir"; then + kde_templatesdir='\${datadir}/templates' + fi + if test -z "$kde_bindir"; then + kde_bindir='\${exec_prefix}/bin' + fi + if test -z "$kde_servicesdir"; then + kde_servicesdir='\${datadir}/services' + fi + if test -z "$kde_servicetypesdir"; then + kde_servicetypesdir='\${datadir}/servicetypes' + fi + if test -z "$kde_moduledir"; then + if test "$kde_qtver" = "2"; then + kde_moduledir='\${libdir}/kde2' + else + kde_moduledir='\${libdir}/kde3' + fi + fi + if test -z "$kde_styledir"; then + kde_styledir='\${libdir}/kde3/plugins/styles' + fi + if test -z "$kde_widgetdir"; then + kde_widgetdir='\${libdir}/kde3/plugins/designer' + fi + if test -z "$xdg_appsdir"; then + xdg_appsdir='\${datadir}/applications/kde' + fi + if test -z "$xdg_menudir"; then + xdg_menudir='\${sysconfdir}/xdg/menus' + fi + if test -z "$xdg_directorydir"; then + xdg_directorydir='\${datadir}/desktop-directories' + fi + + KDE_SET_PATHS(defaults) + +else + + if test $kde_qtver = 1; then + AC_MSG_RESULT([compiling]) + KDE_1_CHECK_PATHS + else + AC_MSG_ERROR([path checking not yet supported for KDE 2]) + fi + +fi +]) + +AC_DEFUN([KDE_CHECK_PATHS_FOR_COMPLETENESS], +[ if test -z "$kde_htmldir" || test -z "$kde_appsdir" || + test -z "$kde_icondir" || test -z "$kde_sounddir" || + test -z "$kde_datadir" || test -z "$kde_locale" || + test -z "$kde_cgidir" || test -z "$kde_confdir" || + test -z "$kde_kcfgdir" || + test -z "$kde_mimedir" || test -z "$kde_toolbardir" || + test -z "$kde_wallpaperdir" || test -z "$kde_templatesdir" || + test -z "$kde_bindir" || test -z "$kde_servicesdir" || + test -z "$kde_servicetypesdir" || test -z "$kde_moduledir" || + test -z "$kde_styledir" || test -z "kde_widgetdir" || + test -z "$xdg_appsdir" || test -z "$xdg_menudir" || test -z "$xdg_directorydir" || + test "x$kde_have_all_paths" != "xyes"; then + kde_have_all_paths=no + fi +]) + +AC_DEFUN([KDE_MISSING_PROG_ERROR], +[ + AC_MSG_ERROR([The important program $1 was not found! +Please check whether you installed KDE correctly. +]) +]) + +AC_DEFUN([KDE_MISSING_ARTS_ERROR], +[ + AC_MSG_ERROR([The important program $1 was not found! +Please check whether you installed aRts correctly or use +--without-arts to compile without aRts support (this will remove functionality). +]) +]) + +AC_DEFUN([KDE_SET_DEFAULT_BINDIRS], +[ + kde_default_bindirs="/usr/bin /usr/local/bin /opt/local/bin /usr/X11R6/bin /opt/kde/bin /opt/kde3/bin /usr/kde/bin /usr/local/kde/bin" + test -n "$KDEDIR" && kde_default_bindirs="$KDEDIR/bin $kde_default_bindirs" + if test -n "$KDEDIRS"; then + kde_save_IFS=$IFS + IFS=: + for dir in $KDEDIRS; do + kde_default_bindirs="$dir/bin $kde_default_bindirs " + done + IFS=$kde_save_IFS + fi +]) + +AC_DEFUN([KDE_SUBST_PROGRAMS], +[ + AC_ARG_WITH(arts, + AC_HELP_STRING([--without-arts],[build without aRts [default=no]]), + [build_arts=$withval], + [build_arts=yes] + ) + AM_CONDITIONAL(include_ARTS, test "$build_arts" '!=' "no") + if test "$build_arts" = "no"; then + AC_DEFINE(WITHOUT_ARTS, 1, [Defined if compiling without arts]) + fi + + KDE_SET_DEFAULT_BINDIRS + kde_default_bindirs="$exec_prefix/bin $prefix/bin $kde_libs_prefix/bin $kde_default_bindirs" + KDE_FIND_PATH(dcopidl, DCOPIDL, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(dcopidl)]) + KDE_FIND_PATH(dcopidl2cpp, DCOPIDL2CPP, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(dcopidl2cpp)]) + if test "$build_arts" '!=' "no"; then + KDE_FIND_PATH(mcopidl, MCOPIDL, [$kde_default_bindirs], [KDE_MISSING_ARTS_ERROR(mcopidl)]) + KDE_FIND_PATH(artsc-config, ARTSCCONFIG, [$kde_default_bindirs], [KDE_MISSING_ARTS_ERROR(artsc-config)]) + fi + KDE_FIND_PATH(meinproc, MEINPROC, [$kde_default_bindirs]) + + kde32ornewer=1 + kde33ornewer=1 + if test -n "$kde_qtver" && test "$kde_qtver" -lt 3; then + kde32ornewer= + kde33ornewer= + else + if test "$kde_qtver" = "3"; then + if test "$kde_qtsubver" -le 1; then + kde32ornewer= + fi + if test "$kde_qtsubver" -le 2; then + kde33ornewer= + fi + fi + fi + + if test -n "$kde32ornewer"; then + KDE_FIND_PATH(kconfig_compiler, KCONFIG_COMPILER, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(kconfig_compiler)]) + KDE_FIND_PATH(dcopidlng, DCOPIDLNG, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(dcopidlng)]) + fi + if test -n "$kde33ornewer"; then + KDE_FIND_PATH(makekdewidgets, MAKEKDEWIDGETS, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(makekdewidgets)]) + AC_SUBST(MAKEKDEWIDGETS) + fi + KDE_FIND_PATH(xmllint, XMLLINT, [${prefix}/bin ${exec_prefix}/bin], [XMLLINT=""]) + + if test -n "$MEINPROC" && test ! "$MEINPROC" = "compiled"; then + kde_sharedirs="/usr/share/kde /usr/local/share /usr/share /opt/kde3/share /opt/kde/share $prefix/share" + test -n "$KDEDIR" && kde_sharedirs="$KDEDIR/share $kde_sharedirs" + AC_FIND_FILE(apps/ksgmltools2/customization/kde-chunk.xsl, $kde_sharedirs, KDE_XSL_STYLESHEET) + if test "$KDE_XSL_STYLESHEET" = "NO"; then + KDE_XSL_STYLESHEET="" + else + KDE_XSL_STYLESHEET="$KDE_XSL_STYLESHEET/apps/ksgmltools2/customization/kde-chunk.xsl" + fi + fi + + DCOP_DEPENDENCIES='$(DCOPIDL)' + if test -n "$kde32ornewer"; then + KCFG_DEPENDENCIES='$(KCONFIG_COMPILER)' + DCOP_DEPENDENCIES='$(DCOPIDL) $(DCOPIDLNG)' + AC_SUBST(KCONFIG_COMPILER) + AC_SUBST(KCFG_DEPENDENCIES) + AC_SUBST(DCOPIDLNG) + fi + AC_SUBST(DCOPIDL) + AC_SUBST(DCOPIDL2CPP) + AC_SUBST(DCOP_DEPENDENCIES) + AC_SUBST(MCOPIDL) + AC_SUBST(ARTSCCONFIG) + AC_SUBST(MEINPROC) + AC_SUBST(KDE_XSL_STYLESHEET) + AC_SUBST(XMLLINT) +])dnl + +AC_DEFUN([AC_CREATE_KFSSTND], +[ +AC_REQUIRE([AC_CHECK_RPATH]) + +AC_MSG_CHECKING([for KDE paths]) +kde_result="" +kde_cached_paths=yes +AC_CACHE_VAL(kde_cv_all_paths, +[ + KDE_SET_DEFAULT_PATHS($1) + kde_cached_paths=no +]) +eval "$kde_cv_all_paths" +KDE_CHECK_PATHS_FOR_COMPLETENESS +if test "$kde_have_all_paths" = "no" && test "$kde_cached_paths" = "yes"; then + # wrong values were cached, may be, we can set better ones + kde_result= + kde_htmldir= kde_appsdir= kde_icondir= kde_sounddir= + kde_datadir= kde_locale= kde_cgidir= kde_confdir= kde_kcfgdir= + kde_mimedir= kde_toolbardir= kde_wallpaperdir= kde_templatesdir= + kde_bindir= kde_servicesdir= kde_servicetypesdir= kde_moduledir= + kde_have_all_paths= + kde_styledir= + kde_widgetdir= + xdg_appsdir = xdg_menudir= xdg_directorydir= + KDE_SET_DEFAULT_PATHS($1) + eval "$kde_cv_all_paths" + KDE_CHECK_PATHS_FOR_COMPLETENESS + kde_result="$kde_result (cache overridden)" +fi +if test "$kde_have_all_paths" = "no"; then + AC_MSG_ERROR([configure could not run a little KDE program to test the environment. +Since it had compiled and linked before, it must be a strange problem on your system. +Look at config.log for details. If you are not able to fix this, look at +http://www.kde.org/faq/installation.html or any www.kde.org mirror. +(If you're using an egcs version on Linux, you may update binutils!) +]) +else + rm -f conftest* + AC_MSG_RESULT($kde_result) +fi + +bindir=$kde_bindir + +KDE_SUBST_PROGRAMS + +]) + +AC_DEFUN([AC_SUBST_KFSSTND], +[ +AC_SUBST(kde_htmldir) +AC_SUBST(kde_appsdir) +AC_SUBST(kde_icondir) +AC_SUBST(kde_sounddir) +AC_SUBST(kde_datadir) +AC_SUBST(kde_locale) +AC_SUBST(kde_confdir) +AC_SUBST(kde_kcfgdir) +AC_SUBST(kde_mimedir) +AC_SUBST(kde_wallpaperdir) +AC_SUBST(kde_bindir) +dnl X Desktop Group standards +AC_SUBST(xdg_appsdir) +AC_SUBST(xdg_menudir) +AC_SUBST(xdg_directorydir) +dnl for KDE 2 +AC_SUBST(kde_templatesdir) +AC_SUBST(kde_servicesdir) +AC_SUBST(kde_servicetypesdir) +AC_SUBST(kde_moduledir) +AC_SUBST(kdeinitdir, '$(kde_moduledir)') +AC_SUBST(kde_styledir) +AC_SUBST(kde_widgetdir) +if test "$kde_qtver" = 1; then + kde_minidir="$kde_icondir/mini" +else +# for KDE 1 - this breaks KDE2 apps using minidir, but +# that's the plan ;-/ + kde_minidir="/dev/null" +fi +dnl AC_SUBST(kde_minidir) +dnl AC_SUBST(kde_cgidir) +dnl AC_SUBST(kde_toolbardir) +]) + +AC_DEFUN([KDE_MISC_TESTS], +[ + dnl Checks for libraries. + AC_CHECK_LIB(util, main, [LIBUTIL="-lutil"]) dnl for *BSD + AC_SUBST(LIBUTIL) + AC_CHECK_LIB(compat, main, [LIBCOMPAT="-lcompat"]) dnl for *BSD + AC_SUBST(LIBCOMPAT) + kde_have_crypt= + AC_CHECK_LIB(crypt, crypt, [LIBCRYPT="-lcrypt"; kde_have_crypt=yes], + AC_CHECK_LIB(c, crypt, [kde_have_crypt=yes], [ + AC_MSG_WARN([you have no crypt in either libcrypt or libc. +You should install libcrypt from another source or configure with PAM +support]) + kde_have_crypt=no + ])) + AC_SUBST(LIBCRYPT) + if test $kde_have_crypt = yes; then + AC_DEFINE_UNQUOTED(HAVE_CRYPT, 1, [Defines if your system has the crypt function]) + fi + AC_CHECK_SOCKLEN_T + AC_CHECK_LIB(dnet, dnet_ntoa, [X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet"]) + if test $ac_cv_lib_dnet_dnet_ntoa = no; then + AC_CHECK_LIB(dnet_stub, dnet_ntoa, + [X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub"]) + fi + AC_CHECK_FUNC(inet_ntoa) + if test $ac_cv_func_inet_ntoa = no; then + AC_CHECK_LIB(nsl, inet_ntoa, X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl") + fi + AC_CHECK_FUNC(connect) + if test $ac_cv_func_connect = no; then + AC_CHECK_LIB(socket, connect, X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS", , + $X_EXTRA_LIBS) + fi + + AC_CHECK_FUNC(remove) + if test $ac_cv_func_remove = no; then + AC_CHECK_LIB(posix, remove, X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix") + fi + + # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. + AC_CHECK_FUNC(shmat, , + AC_CHECK_LIB(ipc, shmat, X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc")) + + # more headers that need to be explicitly included on darwin + AC_CHECK_HEADERS(sys/types.h stdint.h) + + # sys/bitypes.h is needed for uint32_t and friends on Tru64 + AC_CHECK_HEADERS(sys/bitypes.h) + + # darwin requires a poll emulation library + AC_CHECK_LIB(poll, poll, LIB_POLL="-lpoll") + + # for some image handling on Mac OS X + AC_CHECK_HEADERS(Carbon/Carbon.h) + + # CoreAudio framework + AC_CHECK_HEADER(CoreAudio/CoreAudio.h, [ + AC_DEFINE(HAVE_COREAUDIO, 1, [Define if you have the CoreAudio API]) + FRAMEWORK_COREAUDIO="-Xlinker -framework -Xlinker CoreAudio" + ]) + + AC_CHECK_RES_INIT + AC_SUBST(LIB_POLL) + AC_SUBST(FRAMEWORK_COREAUDIO) + LIBSOCKET="$X_EXTRA_LIBS" + AC_SUBST(LIBSOCKET) + AC_SUBST(X_EXTRA_LIBS) + AC_CHECK_LIB(ucb, killpg, [LIBUCB="-lucb"]) dnl for Solaris2.4 + AC_SUBST(LIBUCB) + + case $host in dnl this *is* LynxOS specific + *-*-lynxos* ) + AC_MSG_CHECKING([LynxOS header file wrappers]) + [CFLAGS="$CFLAGS -D__NO_INCLUDE_WARN__"] + AC_MSG_RESULT(disabled) + AC_CHECK_LIB(bsd, gethostbyname, [LIBSOCKET="-lbsd"]) dnl for LynxOS + ;; + esac + + KDE_CHECK_TYPES + KDE_CHECK_LIBDL + KDE_CHECK_STRLCPY + +# darwin needs this to initialize the environment +AC_CHECK_HEADERS(crt_externs.h) +AC_CHECK_FUNC(_NSGetEnviron, [AC_DEFINE(HAVE_NSGETENVIRON, 1, [Define if your system needs _NSGetEnviron to set up the environment])]) + +AH_VERBATIM(_DARWIN_ENVIRON, +[ +#if defined(HAVE_NSGETENVIRON) && defined(HAVE_CRT_EXTERNS_H) +# include +# include +# define environ (*_NSGetEnviron()) +#endif +]) + +AH_VERBATIM(_AIX_STRINGS_H_BZERO, +[ +/* + * AIX defines FD_SET in terms of bzero, but fails to include + * that defines bzero. + */ + +#if defined(_AIX) +#include +#endif +]) + +AC_CHECK_FUNCS([vsnprintf snprintf]) + +AH_VERBATIM(_TRU64,[ +/* + * On HP-UX, the declaration of vsnprintf() is needed every time ! + */ + +#if !defined(HAVE_VSNPRINTF) || defined(hpux) +#if __STDC__ +#include +#include +#else +#include +#endif +#ifdef __cplusplus +extern "C" +#endif +int vsnprintf(char *str, size_t n, char const *fmt, va_list ap); +#ifdef __cplusplus +extern "C" +#endif +int snprintf(char *str, size_t n, char const *fmt, ...); +#endif +]) + +]) + +dnl ------------------------------------------------------------------------ +dnl Find the header files and libraries for X-Windows. Extended the +dnl macro AC_PATH_X +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([K_PATH_X], +[ +AC_REQUIRE([KDE_MISC_TESTS])dnl +AC_REQUIRE([KDE_CHECK_LIB64]) + +AC_ARG_ENABLE( + embedded, + AC_HELP_STRING([--enable-embedded],[link to Qt-embedded, don't use X]), + kde_use_qt_emb=$enableval, + kde_use_qt_emb=no +) + +AC_ARG_ENABLE( + qtopia, + AC_HELP_STRING([--enable-qtopia],[link to Qt-embedded, link to the Qtopia Environment]), + kde_use_qt_emb_palm=$enableval, + kde_use_qt_emb_palm=no +) + +AC_ARG_ENABLE( + mac, + AC_HELP_STRING([--enable-mac],[link to Qt/Mac (don't use X)]), + kde_use_qt_mac=$enableval, + kde_use_qt_mac=no +) + +# used to disable x11-specific stuff on special platforms +AM_CONDITIONAL(include_x11, test "$kde_use_qt_emb" = "no" && test "$kde_use_qt_mac" = "no") + +if test "$kde_use_qt_emb" = "no" && test "$kde_use_qt_mac" = "no"; then + +AC_MSG_CHECKING(for X) + +AC_CACHE_VAL(kde_cv_have_x, +[# One or both of the vars are not set, and there is no cached value. +if test "{$x_includes+set}" = set || test "$x_includes" = NONE; then + kde_x_includes=NO +else + kde_x_includes=$x_includes +fi +if test "{$x_libraries+set}" = set || test "$x_libraries" = NONE; then + kde_x_libraries=NO +else + kde_x_libraries=$x_libraries +fi + +# below we use the standard autoconf calls +ac_x_libraries=$kde_x_libraries +ac_x_includes=$kde_x_includes + +KDE_PATH_X_DIRECT +dnl AC_PATH_X_XMKMF picks /usr/lib as the path for the X libraries. +dnl Unfortunately, if compiling with the N32 ABI, this is not the correct +dnl location. The correct location is /usr/lib32 or an undefined value +dnl (the linker is smart enough to pick the correct default library). +dnl Things work just fine if you use just AC_PATH_X_DIRECT. +dnl Solaris has a similar problem. AC_PATH_X_XMKMF forces x_includes to +dnl /usr/openwin/include, which doesn't work. /usr/include does work, so +dnl x_includes should be left alone. +case "$host" in +mips-sgi-irix6*) + ;; +*-*-solaris*) + ;; +*) + _AC_PATH_X_XMKMF + if test -z "$ac_x_includes"; then + ac_x_includes="." + fi + if test -z "$ac_x_libraries"; then + ac_x_libraries="/usr/lib${kdelibsuff}" + fi +esac +#from now on we use our own again + +# when the user already gave --x-includes, we ignore +# what the standard autoconf macros told us. +if test "$kde_x_includes" = NO; then + kde_x_includes=$ac_x_includes +fi + +# for --x-libraries too +if test "$kde_x_libraries" = NO; then + kde_x_libraries=$ac_x_libraries +fi + +if test "$kde_x_includes" = NO; then + AC_MSG_ERROR([Can't find X includes. Please check your installation and add the correct paths!]) +fi + +if test "$kde_x_libraries" = NO; then + AC_MSG_ERROR([Can't find X libraries. Please check your installation and add the correct paths!]) +fi + +# Record where we found X for the cache. +kde_cv_have_x="have_x=yes \ + kde_x_includes=$kde_x_includes kde_x_libraries=$kde_x_libraries" +])dnl + +eval "$kde_cv_have_x" + +if test "$have_x" != yes; then + AC_MSG_RESULT($have_x) + no_x=yes +else + AC_MSG_RESULT([libraries $kde_x_libraries, headers $kde_x_includes]) +fi + +if test -z "$kde_x_includes" || test "x$kde_x_includes" = xNONE; then + X_INCLUDES="" + x_includes="."; dnl better than nothing :- + else + x_includes=$kde_x_includes + X_INCLUDES="-I$x_includes" +fi + +if test -z "$kde_x_libraries" || test "x$kde_x_libraries" = xNONE; then + X_LDFLAGS="" + x_libraries="/usr/lib"; dnl better than nothing :- + else + x_libraries=$kde_x_libraries + X_LDFLAGS="-L$x_libraries" +fi +all_includes="$X_INCLUDES" +all_libraries="$X_LDFLAGS $LDFLAGS_AS_NEEDED $LDFLAGS_NEW_DTAGS" + +# Check for libraries that X11R6 Xt/Xaw programs need. +ac_save_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS $X_LDFLAGS" +# SM needs ICE to (dynamically) link under SunOS 4.x (so we have to +# check for ICE first), but we must link in the order -lSM -lICE or +# we get undefined symbols. So assume we have SM if we have ICE. +# These have to be linked with before -lX11, unlike the other +# libraries we check for below, so use a different variable. +# --interran@uluru.Stanford.EDU, kb@cs.umb.edu. +AC_CHECK_LIB(ICE, IceConnectionNumber, + [LIBSM="-lSM -lICE"], , $X_EXTRA_LIBS) +LDFLAGS="$ac_save_LDFLAGS" + +LIB_X11='-lX11 $(LIBSOCKET)' + +AC_MSG_CHECKING(for libXext) +AC_CACHE_VAL(kde_cv_have_libXext, +[ +kde_ldflags_safe="$LDFLAGS" +kde_libs_safe="$LIBS" + +LDFLAGS="$LDFLAGS $X_LDFLAGS $USER_LDFLAGS" +LIBS="-lXext -lX11 $LIBSOCKET" + +AC_TRY_LINK([ +#include +#ifdef STDC_HEADERS +# include +#endif +], +[ +printf("hello Xext\n"); +], +kde_cv_have_libXext=yes, +kde_cv_have_libXext=no +) + +LDFLAGS=$kde_ldflags_safe +LIBS=$kde_libs_safe +]) + +AC_MSG_RESULT($kde_cv_have_libXext) + +if test "$kde_cv_have_libXext" = "no"; then + AC_MSG_ERROR([We need a working libXext to proceed. Since configure +can't find it itself, we stop here assuming that make wouldn't find +them either.]) +fi + +LIB_XEXT="-lXext" +QTE_NORTTI="" + +elif test "$kde_use_qt_emb" = "yes"; then + dnl We're using QT Embedded + CPPFLAGS=-DQWS + CXXFLAGS="$CXXFLAGS -fno-rtti" + QTE_NORTTI="-fno-rtti -DQWS" + X_PRE_LIBS="" + LIB_X11="" + LIB_XEXT="" + LIB_XRENDER="" + LIBSM="" + X_INCLUDES="" + X_LDFLAGS="" + x_includes="" + x_libraries="" +elif test "$kde_use_qt_mac" = "yes"; then + dnl We're using QT/Mac (I use QT_MAC so that qglobal.h doesn't *have* to + dnl be included to get the information) --Sam + CXXFLAGS="$CXXFLAGS -DQT_MAC -no-cpp-precomp" + CFLAGS="$CFLAGS -DQT_MAC -no-cpp-precomp" + X_PRE_LIBS="" + LIB_X11="" + LIB_XEXT="" + LIB_XRENDER="" + LIBSM="" + X_INCLUDES="" + X_LDFLAGS="" + x_includes="" + x_libraries="" +fi +AC_SUBST(X_PRE_LIBS) +AC_SUBST(LIB_X11) +AC_SUBST(LIB_XRENDER) +AC_SUBST(LIBSM) +AC_SUBST(X_INCLUDES) +AC_SUBST(X_LDFLAGS) +AC_SUBST(x_includes) +AC_SUBST(x_libraries) +AC_SUBST(QTE_NORTTI) +AC_SUBST(LIB_XEXT) + +]) + +AC_DEFUN([KDE_PRINT_QT_PROGRAM], +[ +AC_REQUIRE([KDE_USE_QT]) +cat > conftest.$ac_ext < +#include +EOF +if test "$kde_qtver" = "2"; then +cat >> conftest.$ac_ext < +#include +#include +EOF + +if test $kde_qtsubver -gt 0; then +cat >> conftest.$ac_ext <> conftest.$ac_ext < +#include +#include +EOF +fi + +echo "#if ! ($kde_qt_verstring)" >> conftest.$ac_ext +cat >> conftest.$ac_ext <> conftest.$ac_ext <> conftest.$ac_ext <> conftest.$ac_ext <> conftest.$ac_ext <&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC +fi + +rm -f conftest* +CXXFLAGS="$ac_cxxflags_safe" +LDFLAGS="$ac_ldflags_safe" +LIBS="$ac_libs_safe" + +LD_LIBRARY_PATH="$ac_LD_LIBRARY_PATH_safe" +export LD_LIBRARY_PATH +LIBRARY_PATH="$ac_LIBRARY_PATH" +export LIBRARY_PATH +AC_LANG_RESTORE +]) + +if test "$kde_cv_qt_direct" = "yes"; then + AC_MSG_RESULT(yes) + $1 +else + AC_MSG_RESULT(no) + $2 +fi +]) + +dnl ------------------------------------------------------------------------ +dnl Try to find the Qt headers and libraries. +dnl $(QT_LDFLAGS) will be -Lqtliblocation (if needed) +dnl and $(QT_INCLUDES) will be -Iqthdrlocation (if needed) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_PATH_QT_1_3], +[ +AC_REQUIRE([K_PATH_X]) +AC_REQUIRE([KDE_USE_QT]) +AC_REQUIRE([KDE_CHECK_LIB64]) + +dnl ------------------------------------------------------------------------ +dnl Add configure flag to enable linking to MT version of Qt library. +dnl ------------------------------------------------------------------------ + +AC_ARG_ENABLE( + mt, + AC_HELP_STRING([--disable-mt],[link to non-threaded Qt (deprecated)]), + kde_use_qt_mt=$enableval, + [ + if test $kde_qtver = 3; then + kde_use_qt_mt=yes + else + kde_use_qt_mt=no + fi + ] +) + +USING_QT_MT="" + +dnl ------------------------------------------------------------------------ +dnl If we not get --disable-qt-mt then adjust some vars for the host. +dnl ------------------------------------------------------------------------ + +KDE_MT_LDFLAGS= +KDE_MT_LIBS= +if test "x$kde_use_qt_mt" = "xyes"; then + KDE_CHECK_THREADING + if test "x$kde_use_threading" = "xyes"; then + CPPFLAGS="$USE_THREADS -DQT_THREAD_SUPPORT $CPPFLAGS" + KDE_MT_LDFLAGS="$USE_THREADS" + KDE_MT_LIBS="$LIBPTHREAD" + else + kde_use_qt_mt=no + fi +fi +AC_SUBST(KDE_MT_LDFLAGS) +AC_SUBST(KDE_MT_LIBS) + +kde_qt_was_given=yes + +dnl ------------------------------------------------------------------------ +dnl If we haven't been told how to link to Qt, we work it out for ourselves. +dnl ------------------------------------------------------------------------ +if test -z "$LIBQT_GLOB"; then + if test "x$kde_use_qt_emb" = "xyes"; then + LIBQT_GLOB="libqte.*" + else + LIBQT_GLOB="libqt.*" + fi +fi + +if test -z "$LIBQT"; then +dnl ------------------------------------------------------------ +dnl If we got --enable-embedded then adjust the Qt library name. +dnl ------------------------------------------------------------ + if test "x$kde_use_qt_emb" = "xyes"; then + qtlib="qte" + else + qtlib="qt" + fi + + kde_int_qt="-l$qtlib" +else + kde_int_qt="$LIBQT" + kde_lib_qt_set=yes +fi + +if test -z "$LIBQPE"; then +dnl ------------------------------------------------------------ +dnl If we got --enable-palmtop then add -lqpe to the link line +dnl ------------------------------------------------------------ + if test "x$kde_use_qt_emb" = "xyes"; then + if test "x$kde_use_qt_emb_palm" = "xyes"; then + LIB_QPE="-lqpe" + else + LIB_QPE="" + fi + else + LIB_QPE="" + fi +fi + +dnl ------------------------------------------------------------------------ +dnl If we got --enable-qt-mt then adjust the Qt library name for the host. +dnl ------------------------------------------------------------------------ + +if test "x$kde_use_qt_mt" = "xyes"; then + if test -z "$LIBQT"; then + LIBQT="-l$qtlib-mt" + kde_int_qt="-l$qtlib-mt" + else + LIBQT="$qtlib-mt" + kde_int_qt="$qtlib-mt" + fi + LIBQT_GLOB="lib$qtlib-mt.*" + USING_QT_MT="using -mt" +else + LIBQT="-l$qtlib" +fi + +if test $kde_qtver != 1; then + + AC_REQUIRE([AC_FIND_PNG]) + AC_REQUIRE([AC_FIND_JPEG]) + LIBQT="$LIBQT $LIBPNG $LIBJPEG" +fi + +if test $kde_qtver = 3; then + AC_REQUIRE([KDE_CHECK_LIBDL]) + LIBQT="$LIBQT $LIBDL" +fi + +AC_MSG_CHECKING([for Qt]) + +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBQT="$LIBQT $X_PRE_LIBS -lXext -lX11 $LIBSM $LIBSOCKET" +fi +ac_qt_includes=NO ac_qt_libraries=NO ac_qt_bindir=NO +qt_libraries="" +qt_includes="" +AC_ARG_WITH(qt-dir, + AC_HELP_STRING([--with-qt-dir=DIR],[where the root of Qt is installed ]), + [ ac_qt_includes="$withval"/include + ac_qt_libraries="$withval"/lib${kdelibsuff} + ac_qt_bindir="$withval"/bin + ]) + +AC_ARG_WITH(qt-includes, + AC_HELP_STRING([--with-qt-includes=DIR],[where the Qt includes are. ]), + [ + ac_qt_includes="$withval" + ]) + +kde_qt_libs_given=no + +AC_ARG_WITH(qt-libraries, + AC_HELP_STRING([--with-qt-libraries=DIR],[where the Qt library is installed.]), + [ ac_qt_libraries="$withval" + kde_qt_libs_given=yes + ]) + +AC_CACHE_VAL(ac_cv_have_qt, +[#try to guess Qt locations + +qt_incdirs="" +for dir in $kde_qt_dirs; do + qt_incdirs="$qt_incdirs $dir/include $dir" +done +qt_incdirs="$QTINC $qt_incdirs /usr/local/qt/include /usr/include/qt /usr/include /usr/X11R6/include/X11/qt /usr/X11R6/include/qt /usr/X11R6/include/qt2 /usr/include/qt3 $x_includes" +if test ! "$ac_qt_includes" = "NO"; then + qt_incdirs="$ac_qt_includes $qt_incdirs" +fi + +if test "$kde_qtver" != "1"; then + kde_qt_header=qstyle.h +else + kde_qt_header=qglobal.h +fi + +AC_FIND_FILE($kde_qt_header, $qt_incdirs, qt_incdir) +ac_qt_includes="$qt_incdir" + +qt_libdirs="" +for dir in $kde_qt_dirs; do + qt_libdirs="$qt_libdirs $dir/lib${kdelibsuff} $dir" +done +qt_libdirs="$QTLIB $qt_libdirs /usr/X11R6/lib /usr/lib /usr/local/qt/lib $x_libraries" +if test ! "$ac_qt_libraries" = "NO"; then + qt_libdir=$ac_qt_libraries +else + qt_libdirs="$ac_qt_libraries $qt_libdirs" + # if the Qt was given, the chance is too big that libqt.* doesn't exist + qt_libdir=NONE + for dir in $qt_libdirs; do + try="ls -1 $dir/${LIBQT_GLOB}" + if test -n "`$try 2> /dev/null`"; then qt_libdir=$dir; break; else echo "tried $dir" >&AC_FD_CC ; fi + done +fi +for a in $qt_libdir/lib`echo ${kde_int_qt} | sed 's,^-l,,'`_incremental.*; do + if test -e "$a"; then + LIBQT="$LIBQT ${kde_int_qt}_incremental" + break + fi +done + +ac_qt_libraries="$qt_libdir" + +AC_LANG_SAVE +AC_LANG_CPLUSPLUS + +ac_cxxflags_safe="$CXXFLAGS" +ac_ldflags_safe="$LDFLAGS" +ac_libs_safe="$LIBS" + +CXXFLAGS="$CXXFLAGS -I$qt_incdir $all_includes" +LDFLAGS="$LDFLAGS -L$qt_libdir $all_libraries $USER_LDFLAGS $KDE_MT_LDFLAGS" +LIBS="$LIBS $LIBQT $KDE_MT_LIBS" + +KDE_PRINT_QT_PROGRAM + +if AC_TRY_EVAL(ac_link) && test -s conftest; then + rm -f conftest* +else + echo "configure: failed program was:" >&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC + ac_qt_libraries="NO" +fi +rm -f conftest* +CXXFLAGS="$ac_cxxflags_safe" +LDFLAGS="$ac_ldflags_safe" +LIBS="$ac_libs_safe" + +AC_LANG_RESTORE +if test "$ac_qt_includes" = NO || test "$ac_qt_libraries" = NO; then + ac_cv_have_qt="have_qt=no" + ac_qt_notfound="" + missing_qt_mt="" + if test "$ac_qt_includes" = NO; then + if test "$ac_qt_libraries" = NO; then + ac_qt_notfound="(headers and libraries)"; + else + ac_qt_notfound="(headers)"; + fi + else + if test "x$kde_use_qt_mt" = "xyes"; then + missing_qt_mt=" +Make sure that you have compiled Qt with thread support!" + ac_qt_notfound="(library $qtlib-mt)"; + else + ac_qt_notfound="(library $qtlib)"; + fi + fi + + AC_MSG_ERROR([Qt ($kde_qt_minversion) $ac_qt_notfound not found. Please check your installation! +For more details about this problem, look at the end of config.log.$missing_qt_mt]) +else + have_qt="yes" +fi +]) + +eval "$ac_cv_have_qt" + +if test "$have_qt" != yes; then + AC_MSG_RESULT([$have_qt]); +else + ac_cv_have_qt="have_qt=yes \ + ac_qt_includes=$ac_qt_includes ac_qt_libraries=$ac_qt_libraries" + AC_MSG_RESULT([libraries $ac_qt_libraries, headers $ac_qt_includes $USING_QT_MT]) + + qt_libraries="$ac_qt_libraries" + qt_includes="$ac_qt_includes" +fi + +if test ! "$kde_qt_libs_given" = "yes" && test ! "$kde_qtver" = 3; then + KDE_CHECK_QT_DIRECT(qt_libraries= ,[]) +fi + +AC_SUBST(qt_libraries) +AC_SUBST(qt_includes) + +if test "$qt_includes" = "$x_includes" || test -z "$qt_includes"; then + QT_INCLUDES="" +else + QT_INCLUDES="-I$qt_includes" + all_includes="$QT_INCLUDES $all_includes" +fi + +if test "$qt_libraries" = "$x_libraries" || test -z "$qt_libraries"; then + QT_LDFLAGS="" +else + QT_LDFLAGS="-L$qt_libraries" + all_libraries="$QT_LDFLAGS $all_libraries" +fi +test -z "$KDE_MT_LDFLAGS" || all_libraries="$all_libraries $KDE_MT_LDFLAGS" + +AC_SUBST(QT_INCLUDES) +AC_SUBST(QT_LDFLAGS) +AC_PATH_QT_MOC_UIC + +KDE_CHECK_QT_JPEG + +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIB_QT="$kde_int_qt $LIBJPEG_QT "'$(LIBZ) $(LIBPNG) -lXext $(LIB_X11) $(LIBSM)' +else +LIB_QT="$kde_int_qt $LIBJPEG_QT "'$(LIBZ) $(LIBPNG)' +fi +test -z "$KDE_MT_LIBS" || LIB_QT="$LIB_QT $KDE_MT_LIBS" +for a in $qt_libdir/lib`echo ${kde_int_qt} | sed 's,^-l,,'`_incremental.*; do + if test -e "$a"; then + LIB_QT="$LIB_QT ${kde_int_qt}_incremental" + break + fi +done + +AC_SUBST(LIB_QT) +AC_SUBST(LIB_QPE) + +AC_SUBST(kde_qtver) +]) + +AC_DEFUN([AC_PATH_QT], +[ +AC_PATH_QT_1_3 +]) + +AC_DEFUN([KDE_CHECK_UIC_PLUGINS], +[ +AC_REQUIRE([AC_PATH_QT_MOC_UIC]) + +if test x$ac_uic_supports_libpath = xyes; then + +AC_MSG_CHECKING([if UIC has KDE plugins available]) +AC_CACHE_VAL(kde_cv_uic_plugins, +[ +cat > actest.ui << EOF + +NewConnectionDialog + + + + testInput + + + + +EOF + + + +kde_cv_uic_plugins=no +kde_line="$UIC_PATH -L $kde_widgetdir" +if test x$ac_uic_supports_nounload = xyes; then + kde_line="$kde_line -nounload" +fi +kde_line="$kde_line -impl actest.h actest.ui > actest.cpp" +if AC_TRY_EVAL(kde_line); then + # if you're trying to debug this check and think it's incorrect, + # better check your installation. The check _is_ correct - your + # installation is not. + if test -f actest.cpp && grep klineedit actest.cpp > /dev/null; then + kde_cv_uic_plugins=yes + fi +fi +rm -f actest.ui actest.cpp +]) + +AC_MSG_RESULT([$kde_cv_uic_plugins]) +if test "$kde_cv_uic_plugins" != yes; then + AC_MSG_ERROR([you need to install kdelibs first.]) +fi +fi +]) + +AC_DEFUN([KDE_CHECK_FINAL], +[ + AC_ARG_ENABLE(final, + AC_HELP_STRING([--enable-final], + [build size optimized apps (experimental - needs lots of memory)]), + kde_use_final=$enableval, kde_use_final=no) + + if test "x$kde_use_final" = "xyes"; then + KDE_USE_FINAL_TRUE="" + KDE_USE_FINAL_FALSE="#" + else + KDE_USE_FINAL_TRUE="#" + KDE_USE_FINAL_FALSE="" + fi + AC_SUBST(KDE_USE_FINAL_TRUE) + AC_SUBST(KDE_USE_FINAL_FALSE) +]) + +AC_DEFUN([KDE_CHECK_CLOSURE], +[ + AC_ARG_ENABLE(closure, + AC_HELP_STRING([--enable-closure],[delay template instantiation]), + kde_use_closure=$enableval, kde_use_closure=no) + + KDE_NO_UNDEFINED="" + if test "x$kde_use_closure" = "xyes"; then + KDE_USE_CLOSURE_TRUE="" + KDE_USE_CLOSURE_FALSE="#" +# CXXFLAGS="$CXXFLAGS $REPO" + else + KDE_USE_CLOSURE_TRUE="#" + KDE_USE_CLOSURE_FALSE="" + KDE_NO_UNDEFINED="" + case $host in + *-*-linux-gnu) + KDE_CHECK_COMPILER_FLAG([Wl,--no-undefined], + [KDE_CHECK_COMPILER_FLAG([Wl,--allow-shlib-undefined], + [KDE_NO_UNDEFINED="-Wl,--no-undefined -Wl,--allow-shlib-undefined"], + [KDE_NO_UNDEFINED=""])], + [KDE_NO_UNDEFINED=""]) + ;; + esac + fi + AC_SUBST(KDE_USE_CLOSURE_TRUE) + AC_SUBST(KDE_USE_CLOSURE_FALSE) + AC_SUBST(KDE_NO_UNDEFINED) +]) + +dnl Check if the linker supports --enable-new-dtags and --as-needed +AC_DEFUN([KDE_CHECK_NEW_LDFLAGS], +[ + AC_ARG_ENABLE(new_ldflags, + AC_HELP_STRING([--enable-new-ldflags], + [enable the new linker flags]), + kde_use_new_ldflags=$enableval, + kde_use_new_ldflags=no) + + LDFLAGS_AS_NEEDED="" + LDFLAGS_NEW_DTAGS="" + if test "x$kde_use_new_ldflags" = "xyes"; then + LDFLAGS_NEW_DTAGS="" + KDE_CHECK_COMPILER_FLAG([Wl,--enable-new-dtags], + [LDFLAGS_NEW_DTAGS="-Wl,--enable-new-dtags"],) + + KDE_CHECK_COMPILER_FLAG([Wl,--as-needed], + [LDFLAGS_AS_NEEDED="-Wl,--as-needed"],) + fi + AC_SUBST(LDFLAGS_AS_NEEDED) + AC_SUBST(LDFLAGS_NEW_DTAGS) +]) + +AC_DEFUN([KDE_CHECK_NMCHECK], +[ + AC_ARG_ENABLE(nmcheck,AC_HELP_STRING([--enable-nmcheck],[enable automatic namespace cleanness check]), + kde_use_nmcheck=$enableval, kde_use_nmcheck=no) + + if test "$kde_use_nmcheck" = "yes"; then + KDE_USE_NMCHECK_TRUE="" + KDE_USE_NMCHECK_FALSE="#" + else + KDE_USE_NMCHECK_TRUE="#" + KDE_USE_NMCHECK_FALSE="" + fi + AC_SUBST(KDE_USE_NMCHECK_TRUE) + AC_SUBST(KDE_USE_NMCHECK_FALSE) +]) + +AC_DEFUN([KDE_EXPAND_MAKEVAR], [ +savex=$exec_prefix +test "x$exec_prefix" = xNONE && exec_prefix=$prefix +tmp=$$2 +while $1=`eval echo "$tmp"`; test "x$$1" != "x$tmp"; do tmp=$$1; done +exec_prefix=$savex +]) + +dnl ------------------------------------------------------------------------ +dnl Now, the same with KDE +dnl $(KDE_LDFLAGS) will be the kdeliblocation (if needed) +dnl and $(kde_includes) will be the kdehdrlocation (if needed) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_BASE_PATH_KDE], +[ +AC_REQUIRE([KDE_CHECK_STL]) +AC_REQUIRE([AC_PATH_QT])dnl +AC_REQUIRE([KDE_CHECK_LIB64]) + +AC_CHECK_RPATH +AC_MSG_CHECKING([for KDE]) + +if test "${prefix}" != NONE; then + kde_includes=${includedir} + KDE_EXPAND_MAKEVAR(ac_kde_includes, includedir) + + kde_libraries=${libdir} + KDE_EXPAND_MAKEVAR(ac_kde_libraries, libdir) + +else + ac_kde_includes= + ac_kde_libraries= + kde_libraries="" + kde_includes="" +fi + +AC_CACHE_VAL(ac_cv_have_kde, +[#try to guess kde locations + +if test "$kde_qtver" = 1; then + kde_check_header="ksock.h" + kde_check_lib="libkdecore.la" +else + kde_check_header="ksharedptr.h" + kde_check_lib="libkio.la" +fi + +if test -z "$1"; then + +kde_incdirs="$kde_libs_prefix/include /usr/lib/kde/include /usr/local/kde/include /usr/local/include /usr/kde/include /usr/include/kde /usr/include /opt/kde3/include /opt/kde/include $x_includes $qt_includes" +test -n "$KDEDIR" && kde_incdirs="$KDEDIR/include $KDEDIR/include/kde $KDEDIR $kde_incdirs" +kde_incdirs="$ac_kde_includes $kde_incdirs" +AC_FIND_FILE($kde_check_header, $kde_incdirs, kde_incdir) +ac_kde_includes="$kde_incdir" + +if test -n "$ac_kde_includes" && test ! -r "$ac_kde_includes/$kde_check_header"; then + AC_MSG_ERROR([ +in the prefix, you've chosen, are no KDE headers installed. This will fail. +So, check this please and use another prefix!]) +fi + +kde_libdirs="$kde_libs_prefix/lib${kdelibsuff} /usr/lib/kde/lib${kdelibsuff} /usr/local/kde/lib${kdelibsuff} /usr/kde/lib${kdelibsuff} /usr/lib${kdelibsuff}/kde /usr/lib${kdelibsuff}/kde3 /usr/lib${kdelibsuff} /usr/X11R6/lib${kdelibsuff} /usr/local/lib${kdelibsuff} /opt/kde3/lib${kdelibsuff} /opt/kde/lib${kdelibsuff} /usr/X11R6/kde/lib${kdelibsuff}" +test -n "$KDEDIR" && kde_libdirs="$KDEDIR/lib${kdelibsuff} $KDEDIR $kde_libdirs" +kde_libdirs="$ac_kde_libraries $libdir $kde_libdirs" +AC_FIND_FILE($kde_check_lib, $kde_libdirs, kde_libdir) +ac_kde_libraries="$kde_libdir" + +kde_widgetdir=NO +dnl this might be somewhere else +AC_FIND_FILE("kde3/plugins/designer/kdewidgets.la", $kde_libdirs, kde_widgetdir) + +if test -n "$ac_kde_libraries" && test ! -r "$ac_kde_libraries/$kde_check_lib"; then +AC_MSG_ERROR([ +in the prefix, you've chosen, are no KDE libraries installed. This will fail. +So, check this please and use another prefix!]) +fi + +if test -n "$kde_widgetdir" && test ! -r "$kde_widgetdir/kde3/plugins/designer/kdewidgets.la"; then +AC_MSG_ERROR([ +I can't find the designer plugins. These are required and should have been installed +by kdelibs]) +fi + +if test -n "$kde_widgetdir"; then + kde_widgetdir="$kde_widgetdir/kde3/plugins/designer" +fi + + +if test "$ac_kde_includes" = NO || test "$ac_kde_libraries" = NO || test "$kde_widgetdir" = NO; then + ac_cv_have_kde="have_kde=no" +else + ac_cv_have_kde="have_kde=yes \ + ac_kde_includes=$ac_kde_includes ac_kde_libraries=$ac_kde_libraries" +fi + +else dnl test -z $1, e.g. from kdelibs + + ac_cv_have_kde="have_kde=no" + +fi +])dnl + +eval "$ac_cv_have_kde" + +if test "$have_kde" != "yes"; then + if test "${prefix}" = NONE; then + ac_kde_prefix="$ac_default_prefix" + else + ac_kde_prefix="$prefix" + fi + if test "$exec_prefix" = NONE; then + ac_kde_exec_prefix="$ac_kde_prefix" + AC_MSG_RESULT([will be installed in $ac_kde_prefix]) + else + ac_kde_exec_prefix="$exec_prefix" + AC_MSG_RESULT([will be installed in $ac_kde_prefix and $ac_kde_exec_prefix]) + fi + + kde_libraries="${libdir}" + kde_includes="${includedir}" + +else + ac_cv_have_kde="have_kde=yes \ + ac_kde_includes=$ac_kde_includes ac_kde_libraries=$ac_kde_libraries" + AC_MSG_RESULT([libraries $ac_kde_libraries, headers $ac_kde_includes]) + + kde_libraries="$ac_kde_libraries" + kde_includes="$ac_kde_includes" +fi +AC_SUBST(kde_libraries) +AC_SUBST(kde_includes) + +if test "$kde_includes" = "$x_includes" || test "$kde_includes" = "$qt_includes" || test "$kde_includes" = "/usr/include"; then + KDE_INCLUDES="" +else + KDE_INCLUDES="-I$kde_includes" + all_includes="$KDE_INCLUDES $all_includes" +fi + +KDE_DEFAULT_CXXFLAGS="-DQT_CLEAN_NAMESPACE -DQT_NO_ASCII_CAST -DQT_NO_STL -DQT_NO_COMPAT -DQT_NO_TRANSLATION" + +KDE_LDFLAGS="-L$kde_libraries" +if test ! "$kde_libraries" = "$x_libraries" && test ! "$kde_libraries" = "$qt_libraries" ; then + all_libraries="$KDE_LDFLAGS $all_libraries" +fi + +AC_SUBST(KDE_LDFLAGS) +AC_SUBST(KDE_INCLUDES) + +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + +all_libraries="$all_libraries $USER_LDFLAGS" +all_includes="$all_includes $USER_INCLUDES" +AC_SUBST(all_includes) +AC_SUBST(all_libraries) + +if test -z "$1"; then +KDE_CHECK_UIC_PLUGINS +fi + +ac_kde_libraries="$kde_libdir" + +AC_SUBST(AUTODIRS) + + +]) + +AC_DEFUN([KDE_CHECK_EXTRA_LIBS], +[ +AC_MSG_CHECKING(for extra includes) +AC_ARG_WITH(extra-includes,AC_HELP_STRING([--with-extra-includes=DIR],[adds non standard include paths]), + kde_use_extra_includes="$withval", + kde_use_extra_includes=NONE +) +kde_extra_includes= +if test -n "$kde_use_extra_includes" && \ + test "$kde_use_extra_includes" != "NONE"; then + + ac_save_ifs=$IFS + IFS=':' + for dir in $kde_use_extra_includes; do + kde_extra_includes="$kde_extra_includes $dir" + USER_INCLUDES="$USER_INCLUDES -I$dir" + done + IFS=$ac_save_ifs + kde_use_extra_includes="added" +else + kde_use_extra_includes="no" +fi +AC_SUBST(USER_INCLUDES) + +AC_MSG_RESULT($kde_use_extra_includes) + +kde_extra_libs= +AC_MSG_CHECKING(for extra libs) +AC_ARG_WITH(extra-libs,AC_HELP_STRING([--with-extra-libs=DIR],[adds non standard library paths]), + kde_use_extra_libs=$withval, + kde_use_extra_libs=NONE +) +if test -n "$kde_use_extra_libs" && \ + test "$kde_use_extra_libs" != "NONE"; then + + ac_save_ifs=$IFS + IFS=':' + for dir in $kde_use_extra_libs; do + kde_extra_libs="$kde_extra_libs $dir" + KDE_EXTRA_RPATH="$KDE_EXTRA_RPATH -R $dir" + USER_LDFLAGS="$USER_LDFLAGS -L$dir" + done + IFS=$ac_save_ifs + kde_use_extra_libs="added" +else + kde_use_extra_libs="no" +fi + +AC_SUBST(USER_LDFLAGS) + +AC_MSG_RESULT($kde_use_extra_libs) + +]) + +AC_DEFUN([KDE_1_CHECK_PATH_HEADERS], +[ + AC_MSG_CHECKING([for KDE headers installed]) + AC_LANG_SAVE + AC_LANG_CPLUSPLUS +cat > conftest.$ac_ext < +#endif +#include +#include "confdefs.h" +#include + +int main() { + printf("kde_htmldir=\\"%s\\"\n", KApplication::kde_htmldir().data()); + printf("kde_appsdir=\\"%s\\"\n", KApplication::kde_appsdir().data()); + printf("kde_icondir=\\"%s\\"\n", KApplication::kde_icondir().data()); + printf("kde_sounddir=\\"%s\\"\n", KApplication::kde_sounddir().data()); + printf("kde_datadir=\\"%s\\"\n", KApplication::kde_datadir().data()); + printf("kde_locale=\\"%s\\"\n", KApplication::kde_localedir().data()); + printf("kde_cgidir=\\"%s\\"\n", KApplication::kde_cgidir().data()); + printf("kde_confdir=\\"%s\\"\n", KApplication::kde_configdir().data()); + printf("kde_mimedir=\\"%s\\"\n", KApplication::kde_mimedir().data()); + printf("kde_toolbardir=\\"%s\\"\n", KApplication::kde_toolbardir().data()); + printf("kde_wallpaperdir=\\"%s\\"\n", + KApplication::kde_wallpaperdir().data()); + printf("kde_bindir=\\"%s\\"\n", KApplication::kde_bindir().data()); + printf("kde_partsdir=\\"%s\\"\n", KApplication::kde_partsdir().data()); + printf("kde_servicesdir=\\"/tmp/dummy\\"\n"); + printf("kde_servicetypesdir=\\"/tmp/dummy\\"\n"); + printf("kde_moduledir=\\"/tmp/dummy\\"\n"); + printf("kde_styledir=\\"/tmp/dummy\\"\n"); + printf("kde_widgetdir=\\"/tmp/dummy\\"\n"); + printf("xdg_appsdir=\\"/tmp/dummy\\"\n"); + printf("xdg_menudir=\\"/tmp/dummy\\"\n"); + printf("xdg_directorydir=\\"/tmp/dummy\\"\n"); + printf("kde_kcfgdir=\\"/tmp/dummy\\"\n"); + return 0; + } +EOF + + ac_save_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$all_includes $CPPFLAGS" + if AC_TRY_EVAL(ac_compile); then + AC_MSG_RESULT(yes) + else + AC_MSG_ERROR([your system is not able to compile a small KDE application! +Check, if you installed the KDE header files correctly. +For more details about this problem, look at the end of config.log.]) + fi + CPPFLAGS=$ac_save_CPPFLAGS + + AC_LANG_RESTORE +]) + +AC_DEFUN([KDE_CHECK_KDEQTADDON], +[ +AC_MSG_CHECKING(for kde-qt-addon) +AC_CACHE_VAL(kde_cv_have_kdeqtaddon, +[ + kde_ldflags_safe="$LDFLAGS" + kde_libs_safe="$LIBS" + kde_cxxflags_safe="$CXXFLAGS" + + LIBS="-lkde-qt-addon $LIBQT $LIBS" + CXXFLAGS="$CXXFLAGS -I$prefix/include -I$prefix/include/kde $all_includes" + LDFLAGS="$LDFLAGS $all_libraries $USER_LDFLAGS" + + AC_TRY_LINK([ + #include + ], + [ + QDomDocument doc; + ], + kde_cv_have_kdeqtaddon=yes, + kde_cv_have_kdeqtaddon=no + ) + + LDFLAGS=$kde_ldflags_safe + LIBS=$kde_libs_safe + CXXFLAGS=$kde_cxxflags_safe +]) + +AC_MSG_RESULT($kde_cv_have_kdeqtaddon) + +if test "$kde_cv_have_kdeqtaddon" = "no"; then + AC_MSG_ERROR([Can't find libkde-qt-addon. You need to install it first. +It is a separate package (and CVS module) named kde-qt-addon.]) +fi +]) + +AC_DEFUN([KDE_CREATE_LIBS_ALIASES], +[ + AC_REQUIRE([KDE_MISC_TESTS]) + AC_REQUIRE([KDE_CHECK_LIBDL]) + AC_REQUIRE([K_PATH_X]) + +if test $kde_qtver = 3; then + AC_SUBST(LIB_KDECORE, "-lkdecore") + AC_SUBST(LIB_KDEUI, "-lkdeui") + AC_SUBST(LIB_KIO, "-lkio") + AC_SUBST(LIB_KJS, "-lkjs") + AC_SUBST(LIB_SMB, "-lsmb") + AC_SUBST(LIB_KAB, "-lkab") + AC_SUBST(LIB_KABC, "-lkabc") + AC_SUBST(LIB_KHTML, "-lkhtml") + AC_SUBST(LIB_KSPELL, "-lkspell") + AC_SUBST(LIB_KPARTS, "-lkparts") + AC_SUBST(LIB_KDEPRINT, "-lkdeprint") + AC_SUBST(LIB_KUTILS, "-lkutils") + AC_SUBST(LIB_KDEPIM, "-lkdepim") + AC_SUBST(LIB_KIMPROXY, "-lkimproxy") + AC_SUBST(LIB_KNEWSTUFF, "-lknewstuff") + AC_SUBST(LIB_KDNSSD, "-lkdnssd") +# these are for backward compatibility + AC_SUBST(LIB_KSYCOCA, "-lkio") + AC_SUBST(LIB_KFILE, "-lkio") +elif test $kde_qtver = 2; then + AC_SUBST(LIB_KDECORE, "-lkdecore") + AC_SUBST(LIB_KDEUI, "-lkdeui") + AC_SUBST(LIB_KIO, "-lkio") + AC_SUBST(LIB_KSYCOCA, "-lksycoca") + AC_SUBST(LIB_SMB, "-lsmb") + AC_SUBST(LIB_KFILE, "-lkfile") + AC_SUBST(LIB_KAB, "-lkab") + AC_SUBST(LIB_KHTML, "-lkhtml") + AC_SUBST(LIB_KSPELL, "-lkspell") + AC_SUBST(LIB_KPARTS, "-lkparts") + AC_SUBST(LIB_KDEPRINT, "-lkdeprint") +else + AC_SUBST(LIB_KDECORE, "-lkdecore -lXext $(LIB_QT)") + AC_SUBST(LIB_KDEUI, "-lkdeui $(LIB_KDECORE)") + AC_SUBST(LIB_KFM, "-lkfm $(LIB_KDECORE)") + AC_SUBST(LIB_KFILE, "-lkfile $(LIB_KFM) $(LIB_KDEUI)") + AC_SUBST(LIB_KAB, "-lkab $(LIB_KIMGIO) $(LIB_KDECORE)") +fi +]) + +AC_DEFUN([AC_PATH_KDE], +[ + AC_BASE_PATH_KDE + AC_ARG_ENABLE(path-check,AC_HELP_STRING([--disable-path-check],[don't try to find out, where to install]), + [ + if test "$enableval" = "no"; + then ac_use_path_checking="default" + else ac_use_path_checking="" + fi + ], + [ + if test "$kde_qtver" = 1; + then ac_use_path_checking="" + else ac_use_path_checking="default" + fi + ] + ) + + AC_CREATE_KFSSTND($ac_use_path_checking) + + AC_SUBST_KFSSTND + KDE_CREATE_LIBS_ALIASES +]) + +dnl KDE_CHECK_FUNC_EXT(, [headers], [sample-use], [C prototype], [autoheader define], [call if found]) +AC_DEFUN([KDE_CHECK_FUNC_EXT], +[ +AC_MSG_CHECKING(for $1) +AC_CACHE_VAL(kde_cv_func_$1, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +save_CXXFLAGS="$CXXFLAGS" +kde_safe_LIBS="$LIBS" +LIBS="$LIBS $X_EXTRA_LIBS" +if test "$GXX" = "yes"; then +CXXFLAGS="$CXXFLAGS -pedantic-errors" +fi +AC_TRY_COMPILE([ +$2 +], +[ +$3 +], +kde_cv_func_$1=yes, +kde_cv_func_$1=no) +CXXFLAGS="$save_CXXFLAGS" +LIBS="$kde_safe_LIBS" +AC_LANG_RESTORE +]) + +AC_MSG_RESULT($kde_cv_func_$1) + +AC_MSG_CHECKING([if $1 needs custom prototype]) +AC_CACHE_VAL(kde_cv_proto_$1, +[ +if test "x$kde_cv_func_$1" = xyes; then + kde_cv_proto_$1=no +else + case "$1" in + setenv|unsetenv|usleep|random|srandom|seteuid|mkstemps|mkstemp|revoke|vsnprintf|strlcpy|strlcat) + kde_cv_proto_$1="yes - in libkdefakes" + ;; + *) + kde_cv_proto_$1=unknown + ;; + esac +fi + +if test "x$kde_cv_proto_$1" = xunknown; then + +AC_LANG_SAVE +AC_LANG_CPLUSPLUS + kde_safe_libs=$LIBS + LIBS="$LIBS $X_EXTRA_LIBS" + AC_TRY_LINK([ +$2 + +extern "C" $4; +], +[ +$3 +], +[ kde_cv_func_$1=yes + kde_cv_proto_$1=yes ], + [kde_cv_proto_$1="$1 unavailable"] +) +LIBS=$kde_safe_libs +AC_LANG_RESTORE +fi +]) +AC_MSG_RESULT($kde_cv_proto_$1) + +if test "x$kde_cv_func_$1" = xyes; then + AC_DEFINE(HAVE_$5, 1, [Define if you have $1]) + $6 +fi +if test "x$kde_cv_proto_$1" = xno; then + AC_DEFINE(HAVE_$5_PROTO, 1, + [Define if you have the $1 prototype]) +fi + +AH_VERBATIM([_HAVE_$5_PROTO], +[ +#if !defined(HAVE_$5_PROTO) +#ifdef __cplusplus +extern "C" { +#endif +$4; +#ifdef __cplusplus +} +#endif +#endif +]) +]) + +AC_DEFUN([AC_CHECK_SETENV], +[ + KDE_CHECK_FUNC_EXT(setenv, [ +#include +], + [setenv("VAR", "VALUE", 1);], + [int setenv (const char *, const char *, int)], + [SETENV]) +]) + +AC_DEFUN([AC_CHECK_UNSETENV], +[ + KDE_CHECK_FUNC_EXT(unsetenv, [ +#include +], + [unsetenv("VAR");], + [void unsetenv (const char *)], + [UNSETENV]) +]) + +AC_DEFUN([AC_CHECK_GETDOMAINNAME], +[ + KDE_CHECK_FUNC_EXT(getdomainname, [ +#include +#include +#include +], + [ +char buffer[200]; +getdomainname(buffer, 200); +], + [#include + int getdomainname (char *, size_t)], + [GETDOMAINNAME]) +]) + +AC_DEFUN([AC_CHECK_GETHOSTNAME], +[ + KDE_CHECK_FUNC_EXT(gethostname, [ +#include +#include +], + [ +char buffer[200]; +gethostname(buffer, 200); +], + [int gethostname (char *, unsigned int)], + [GETHOSTNAME]) +]) + +AC_DEFUN([AC_CHECK_USLEEP], +[ + KDE_CHECK_FUNC_EXT(usleep, [ +#include +], + [ +usleep(200); +], + [int usleep (unsigned int)], + [USLEEP]) +]) + + +AC_DEFUN([AC_CHECK_RANDOM], +[ + KDE_CHECK_FUNC_EXT(random, [ +#include +], + [ +random(); +], + [long int random(void)], + [RANDOM]) + + KDE_CHECK_FUNC_EXT(srandom, [ +#include +], + [ +srandom(27); +], + [void srandom(unsigned int)], + [SRANDOM]) + +]) + +AC_DEFUN([AC_CHECK_INITGROUPS], +[ + KDE_CHECK_FUNC_EXT(initgroups, [ +#include +#include +#include +], + [ +char buffer[200]; +initgroups(buffer, 27); +], + [int initgroups(const char *, gid_t)], + [INITGROUPS]) +]) + +AC_DEFUN([AC_CHECK_MKSTEMPS], +[ + KDE_CHECK_FUNC_EXT(mkstemps, [ +#include +#include +], + [ +mkstemps("/tmp/aaaXXXXXX", 6); +], + [int mkstemps(char *, int)], + [MKSTEMPS]) +]) + +AC_DEFUN([AC_CHECK_MKSTEMP], +[ + KDE_CHECK_FUNC_EXT(mkstemp, [ +#include +#include +], + [ +mkstemp("/tmp/aaaXXXXXX"); +], + [int mkstemp(char *)], + [MKSTEMP]) +]) + +AC_DEFUN([AC_CHECK_MKDTEMP], +[ + KDE_CHECK_FUNC_EXT(mkdtemp, [ +#include +#include +], + [ +mkdtemp("/tmp/aaaXXXXXX"); +], + [char *mkdtemp(char *)], + [MKDTEMP]) +]) + + +AC_DEFUN([AC_CHECK_RES_INIT], +[ + AC_MSG_CHECKING([if res_init needs -lresolv]) + kde_libs_safe="$LIBS" + LIBS="$LIBS $X_EXTRA_LIBS -lresolv" + AC_TRY_LINK( + [ +#include +#include +#include +#include + ], + [ + res_init(); + ], + [ + LIBRESOLV="-lresolv" + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_RES_INIT, 1, [Define if you have the res_init function]) + ], + [ AC_MSG_RESULT(no) ] + ) + LIBS=$kde_libs_safe + AC_SUBST(LIBRESOLV) + + KDE_CHECK_FUNC_EXT(res_init, + [ +#include +#include +#include +#include + ], + [res_init()], + [int res_init(void)], + [RES_INIT]) +]) + +AC_DEFUN([AC_CHECK_STRLCPY], +[ + KDE_CHECK_FUNC_EXT(strlcpy, [ +#include +], +[ char buf[20]; + strlcpy(buf, "KDE function test", sizeof(buf)); +], + [unsigned long strlcpy(char*, const char*, unsigned long)], + [STRLCPY]) +]) + +AC_DEFUN([AC_CHECK_STRLCAT], +[ + KDE_CHECK_FUNC_EXT(strlcat, [ +#include +], +[ char buf[20]; + buf[0]='\0'; + strlcat(buf, "KDE function test", sizeof(buf)); +], + [unsigned long strlcat(char*, const char*, unsigned long)], + [STRLCAT]) +]) + +AC_DEFUN([AC_CHECK_RES_QUERY], +[ + KDE_CHECK_FUNC_EXT(res_query, [ +#include +#include +#include +#include +#include +], +[ +res_query(NULL, 0, 0, NULL, 0); +], + [int res_query(const char *, int, int, unsigned char *, int)], + [RES_QUERY]) +]) + +AC_DEFUN([AC_CHECK_DN_SKIPNAME], +[ + KDE_CHECK_FUNC_EXT(dn_skipname, [ +#include +#include +#include +#include +], +[ +dn_skipname (NULL, NULL); +], + [int dn_skipname (unsigned char *, unsigned char *)], + [DN_SKIPNAME]) +]) + + +AC_DEFUN([AC_FIND_GIF], + [AC_MSG_CHECKING([for giflib]) +AC_CACHE_VAL(ac_cv_lib_gif, +[ac_save_LIBS="$LIBS" +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBS="$all_libraries -lgif -lX11 $LIBSOCKET" +else +LIBS="$all_libraries -lgif" +fi +AC_TRY_LINK(dnl +[ +#ifdef __cplusplus +extern "C" { +#endif +int GifLastError(void); +#ifdef __cplusplus +} +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +], + [return GifLastError();], + eval "ac_cv_lib_gif=yes", + eval "ac_cv_lib_gif=no") +LIBS="$ac_save_LIBS" +])dnl +if eval "test \"`echo $ac_cv_lib_gif`\" = yes"; then + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_LIBGIF, 1, [Define if you have libgif]) +else + AC_MSG_ERROR(You need giflib30. Please install the kdesupport package) +fi +]) + +AC_DEFUN([KDE_FIND_JPEG_HELPER], +[ +AC_MSG_CHECKING([for libjpeg$2]) +AC_CACHE_VAL(ac_cv_lib_jpeg_$1, +[ +ac_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS -ljpeg$2 -lm" +ac_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK( +[/* Override any gcc2 internal prototype to avoid an error. */ +struct jpeg_decompress_struct; +typedef struct jpeg_decompress_struct * j_decompress_ptr; +typedef int size_t; +#ifdef __cplusplus +extern "C" { +#endif + void jpeg_CreateDecompress(j_decompress_ptr cinfo, + int version, size_t structsize); +#ifdef __cplusplus +} +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +], + [jpeg_CreateDecompress(0L, 0, 0);], + eval "ac_cv_lib_jpeg_$1=-ljpeg$2", + eval "ac_cv_lib_jpeg_$1=no") +LIBS="$ac_save_LIBS" +CFLAGS="$ac_save_CFLAGS" +]) + +if eval "test ! \"`echo $ac_cv_lib_jpeg_$1`\" = no"; then + LIBJPEG="$ac_cv_lib_jpeg_$1" + AC_MSG_RESULT($ac_cv_lib_jpeg_$1) +else + AC_MSG_RESULT(no) + $3 +fi + +]) + +AC_DEFUN([AC_FIND_JPEG], +[ +dnl first look for libraries +KDE_FIND_JPEG_HELPER(6b, 6b, + KDE_FIND_JPEG_HELPER(normal, [], + [ + LIBJPEG= + ] + ) +) + +dnl then search the headers (can't use simply AC_TRY_xxx, as jpeglib.h +dnl requires system dependent includes loaded before it) +jpeg_incdirs="$includedir /usr/include /usr/local/include $kde_extra_includes" +AC_FIND_FILE(jpeglib.h, $jpeg_incdirs, jpeg_incdir) +test "x$jpeg_incdir" = xNO && jpeg_incdir= + +dnl if headers _and_ libraries are missing, this is no error, and we +dnl continue with a warning (the user will get no jpeg support in khtml) +dnl if only one is missing, it means a configuration error, but we still +dnl only warn +if test -n "$jpeg_incdir" && test -n "$LIBJPEG" ; then + AC_DEFINE_UNQUOTED(HAVE_LIBJPEG, 1, [Define if you have libjpeg]) +else + if test -n "$jpeg_incdir" || test -n "$LIBJPEG" ; then + AC_MSG_WARN([ +There is an installation error in jpeg support. You seem to have only one +of either the headers _or_ the libraries installed. You may need to either +provide correct --with-extra-... options, or the development package of +libjpeg6b. You can get a source package of libjpeg from http://www.ijg.org/ +Disabling JPEG support. +]) + else + AC_MSG_WARN([libjpeg not found. disable JPEG support.]) + fi + jpeg_incdir= + LIBJPEG= +fi + +AC_SUBST(LIBJPEG) +AH_VERBATIM(_AC_CHECK_JPEG, +[/* + * jpeg.h needs HAVE_BOOLEAN, when the system uses boolean in system + * headers and I'm too lazy to write a configure test as long as only + * unixware is related + */ +#ifdef _UNIXWARE +#define HAVE_BOOLEAN +#endif +]) +]) + +AC_DEFUN([KDE_CHECK_QT_JPEG], +[ +if test -n "$LIBJPEG"; then +AC_MSG_CHECKING([if Qt needs $LIBJPEG]) +AC_CACHE_VAL(kde_cv_qt_jpeg, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +ac_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS $LIBQT" +LIBS=`echo $LIBS | sed "s/$LIBJPEG//"` +ac_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK( +[#include ], + [ + int argc; + char** argv; + QApplication app(argc, argv);], + eval "kde_cv_qt_jpeg=no", + eval "kde_cv_qt_jpeg=yes") +LIBS="$ac_save_LIBS" +CXXFLAGS="$ac_save_CXXFLAGS" +AC_LANG_RESTORE +fi +]) + +if eval "test ! \"`echo $kde_cv_qt_jpeg`\" = no"; then + AC_MSG_RESULT(yes) + LIBJPEG_QT='$(LIBJPEG)' +else + AC_MSG_RESULT(no) + LIBJPEG_QT= +fi + +]) + +AC_DEFUN([AC_FIND_ZLIB], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_MSG_CHECKING([for libz]) +AC_CACHE_VAL(ac_cv_lib_z, +[ +kde_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS -lz $LIBSOCKET" +kde_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK(dnl +[ +#include +], +[ + char buf[42]; + gzFile f = (gzFile) 0; + /* this would segfault.. but we only link, don't run */ + (void) gzgets(f, buf, sizeof(buf)); + + return (zlibVersion() == ZLIB_VERSION); +], + eval "ac_cv_lib_z='-lz'", + eval "ac_cv_lib_z=no") +LIBS="$kde_save_LIBS" +CFLAGS="$kde_save_CFLAGS" +])dnl +if test ! "$ac_cv_lib_z" = no; then + AC_DEFINE_UNQUOTED(HAVE_LIBZ, 1, [Define if you have libz]) + LIBZ="$ac_cv_lib_z" + AC_MSG_RESULT($ac_cv_lib_z) +else + AC_MSG_ERROR(not found. + Possibly configure picks up an outdated version + installed by XFree86. Remove it from your system. + + Check your installation and look into config.log) + LIBZ="" +fi +AC_SUBST(LIBZ) +]) + +AC_DEFUN([KDE_TRY_TIFFLIB], +[ +AC_MSG_CHECKING([for libtiff $1]) + +AC_CACHE_VAL(kde_cv_libtiff_$1, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +kde_save_LIBS="$LIBS" +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBS="$all_libraries $USER_LDFLAGS -l$1 $LIBJPEG $LIBZ -lX11 $LIBSOCKET -lm" +else +LIBS="$all_libraries $USER_LDFLAGS -l$1 $LIBJPEG $LIBZ -lm" +fi +kde_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES" + +AC_TRY_LINK(dnl +[ +#include +], + [return (TIFFOpen( "", "r") == 0); ], +[ + kde_cv_libtiff_$1="-l$1 $LIBJPEG $LIBZ" +], [ + kde_cv_libtiff_$1=no +]) + +LIBS="$kde_save_LIBS" +CXXFLAGS="$kde_save_CXXFLAGS" +AC_LANG_RESTORE +]) + +if test "$kde_cv_libtiff_$1" = "no"; then + AC_MSG_RESULT(no) + LIBTIFF="" + $3 +else + LIBTIFF="$kde_cv_libtiff_$1" + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_LIBTIFF, 1, [Define if you have libtiff]) + $2 +fi + +]) + +AC_DEFUN([AC_FIND_TIFF], +[ +AC_REQUIRE([K_PATH_X]) +AC_REQUIRE([AC_FIND_ZLIB]) +AC_REQUIRE([AC_FIND_JPEG]) +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + +KDE_TRY_TIFFLIB(tiff, [], + KDE_TRY_TIFFLIB(tiff34)) + +AC_SUBST(LIBTIFF) +]) + + +AC_DEFUN([AC_FIND_PNG], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_REQUIRE([AC_FIND_ZLIB]) +AC_MSG_CHECKING([for libpng]) +AC_CACHE_VAL(ac_cv_lib_png, +[ +kde_save_LIBS="$LIBS" +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBS="$LIBS $all_libraries $USER_LDFLAGS -lpng $LIBZ -lm -lX11 $LIBSOCKET" +else +LIBS="$LIBS $all_libraries $USER_LDFLAGS -lpng $LIBZ -lm" +fi +kde_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" + +AC_TRY_LINK(dnl + [ + #include + ], + [ + png_structp png_ptr = png_create_read_struct( /* image ptr */ + PNG_LIBPNG_VER_STRING, 0, 0, 0 ); + return( png_ptr != 0 ); + ], + eval "ac_cv_lib_png='-lpng $LIBZ -lm'", + eval "ac_cv_lib_png=no" +) +LIBS="$kde_save_LIBS" +CFLAGS="$kde_save_CFLAGS" +])dnl +if eval "test ! \"`echo $ac_cv_lib_png`\" = no"; then + AC_DEFINE_UNQUOTED(HAVE_LIBPNG, 1, [Define if you have libpng]) + LIBPNG="$ac_cv_lib_png" + AC_SUBST(LIBPNG) + AC_MSG_RESULT($ac_cv_lib_png) +else + AC_MSG_RESULT(no) + LIBPNG="" + AC_SUBST(LIBPNG) +fi +]) + + +AC_DEFUN([AC_FIND_JASPER], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_REQUIRE([AC_FIND_JPEG]) +AC_MSG_CHECKING([for jasper]) +AC_CACHE_VAL(ac_cv_jasper, +[ +kde_save_LIBS="$LIBS" +LIBS="$LIBS $all_libraries $USER_LDFLAGS -ljasper $LIBJPEG -lm" +kde_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" + +AC_TRY_LINK(dnl + [ + #include + ], + [ + return( jas_init() ); + ], + eval "ac_cv_jasper='-ljasper $LIBJPEG -lm'", + eval "ac_cv_jasper=no" +) +LIBS="$kde_save_LIBS" +CFLAGS="$kde_save_CFLAGS" +])dnl +if eval "test ! \"`echo $ac_cv_jasper`\" = no"; then + AC_DEFINE_UNQUOTED(HAVE_JASPER, 1, [Define if you have jasper]) + LIB_JASPER="$ac_cv_jasper" + AC_MSG_RESULT($ac_cv_jasper) +else + AC_MSG_RESULT(no) + LIB_JASPER="" +fi +AC_SUBST(LIB_JASPER) +]) + +AC_DEFUN([AC_CHECK_BOOL], +[ + AC_DEFINE_UNQUOTED(HAVE_BOOL, 1, [You _must_ have bool]) +]) + +AC_DEFUN([AC_CHECK_GNU_EXTENSIONS], +[ +AC_MSG_CHECKING(if you need GNU extensions) +AC_CACHE_VAL(ac_cv_gnu_extensions, +[ +cat > conftest.c << EOF +#include + +#ifdef __GNU_LIBRARY__ +yes +#endif +EOF + +if (eval "$ac_cpp conftest.c") 2>&5 | + egrep "yes" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_gnu_extensions=yes +else + ac_cv_gnu_extensions=no +fi +]) + +AC_MSG_RESULT($ac_cv_gnu_extensions) +if test "$ac_cv_gnu_extensions" = "yes"; then + AC_DEFINE_UNQUOTED(_GNU_SOURCE, 1, [Define if you need to use the GNU extensions]) +fi +]) + +AC_DEFUN([KDE_CHECK_COMPILER_FLAG], +[ +AC_MSG_CHECKING([whether $CXX supports -$1]) +kde_cache=`echo $1 | sed 'y% .=/+-,%____p__%'` +AC_CACHE_VAL(kde_cv_prog_cxx_$kde_cache, +[ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -$1" + AC_TRY_LINK([],[ return 0; ], [eval "kde_cv_prog_cxx_$kde_cache=yes"], []) + CXXFLAGS="$save_CXXFLAGS" + AC_LANG_RESTORE +]) +if eval "test \"`echo '$kde_cv_prog_cxx_'$kde_cache`\" = yes"; then + AC_MSG_RESULT(yes) + : + $2 +else + AC_MSG_RESULT(no) + : + $3 +fi +]) + +AC_DEFUN([KDE_CHECK_C_COMPILER_FLAG], +[ +AC_MSG_CHECKING([whether $CC supports -$1]) +kde_cache=`echo $1 | sed 'y% .=/+-,%____p__%'` +AC_CACHE_VAL(kde_cv_prog_cc_$kde_cache, +[ + AC_LANG_SAVE + AC_LANG_C + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -$1" + AC_TRY_LINK([],[ return 0; ], [eval "kde_cv_prog_cc_$kde_cache=yes"], []) + CFLAGS="$save_CFLAGS" + AC_LANG_RESTORE +]) +if eval "test \"`echo '$kde_cv_prog_cc_'$kde_cache`\" = yes"; then + AC_MSG_RESULT(yes) + : + $2 +else + AC_MSG_RESULT(no) + : + $3 +fi +]) + + +dnl AC_REMOVE_FORBIDDEN removes forbidden arguments from variables +dnl use: AC_REMOVE_FORBIDDEN(CC, [-forbid -bad-option whatever]) +dnl it's all white-space separated +AC_DEFUN([AC_REMOVE_FORBIDDEN], +[ __val=$$1 + __forbid=" $2 " + if test -n "$__val"; then + __new="" + ac_save_IFS=$IFS + IFS=" " + for i in $__val; do + case "$__forbid" in + *" $i "*) AC_MSG_WARN([found forbidden $i in $1, removing it]) ;; + *) # Careful to not add spaces, where there were none, because otherwise + # libtool gets confused, if we change e.g. CXX + if test -z "$__new" ; then __new=$i ; else __new="$__new $i" ; fi ;; + esac + done + IFS=$ac_save_IFS + $1=$__new + fi +]) + +dnl AC_VALIDIFY_CXXFLAGS checks for forbidden flags the user may have given +AC_DEFUN([AC_VALIDIFY_CXXFLAGS], +[dnl +if test "x$kde_use_qt_emb" != "xyes"; then + AC_REMOVE_FORBIDDEN(CXX, [-fno-rtti -rpath]) + AC_REMOVE_FORBIDDEN(CXXFLAGS, [-fno-rtti -rpath]) +else + AC_REMOVE_FORBIDDEN(CXX, [-rpath]) + AC_REMOVE_FORBIDDEN(CXXFLAGS, [-rpath]) +fi +]) + +AC_DEFUN([AC_CHECK_COMPILERS], +[ + AC_ARG_ENABLE(debug, + AC_HELP_STRING([--enable-debug=ARG],[enables debug symbols (yes|no|full) [default=no]]), + [ + case $enableval in + yes) + kde_use_debug_code="yes" + kde_use_debug_define=no + ;; + full) + kde_use_debug_code="full" + kde_use_debug_define=no + ;; + *) + kde_use_debug_code="no" + kde_use_debug_define=yes + ;; + esac + ], + [kde_use_debug_code="no" + kde_use_debug_define=no + ]) + + dnl Just for configure --help + AC_ARG_ENABLE(dummyoption, + AC_HELP_STRING([--disable-debug], + [disables debug output and debug symbols [default=no]]), + [],[]) + + AC_ARG_ENABLE(strict, + AC_HELP_STRING([--enable-strict], + [compiles with strict compiler options (may not work!)]), + [ + if test $enableval = "no"; then + kde_use_strict_options="no" + else + kde_use_strict_options="yes" + fi + ], [kde_use_strict_options="no"]) + + AC_ARG_ENABLE(warnings,AC_HELP_STRING([--disable-warnings],[disables compilation with -Wall and similar]), + [ + if test $enableval = "no"; then + kde_use_warnings="no" + else + kde_use_warnings="yes" + fi + ], [kde_use_warnings="yes"]) + + dnl enable warnings for debug build + if test "$kde_use_debug_code" != "no"; then + kde_use_warnings=yes + fi + + AC_ARG_ENABLE(profile,AC_HELP_STRING([--enable-profile],[creates profiling infos [default=no]]), + [kde_use_profiling=$enableval], + [kde_use_profiling="no"] + ) + + dnl this prevents stupid AC_PROG_CC to add "-g" to the default CFLAGS + CFLAGS=" $CFLAGS" + + AC_PROG_CC + + AC_PROG_CPP + + if test "$GCC" = "yes"; then + if test "$kde_use_debug_code" != "no"; then + if test $kde_use_debug_code = "full"; then + CFLAGS="-g3 -fno-inline $CFLAGS" + else + CFLAGS="-g -O2 $CFLAGS" + fi + else + CFLAGS="-O2 $CFLAGS" + fi + fi + + if test "$kde_use_debug_define" = "yes"; then + CFLAGS="-DNDEBUG $CFLAGS" + fi + + + case "$host" in + *-*-sysv4.2uw*) CFLAGS="-D_UNIXWARE $CFLAGS";; + *-*-sysv5uw7*) CFLAGS="-D_UNIXWARE7 $CFLAGS";; + esac + + if test -z "$LDFLAGS" && test "$kde_use_debug_code" = "no" && test "$GCC" = "yes"; then + LDFLAGS="" + fi + + CXXFLAGS=" $CXXFLAGS" + + AC_PROG_CXX + + if test "$GXX" = "yes" || test "$CXX" = "KCC"; then + if test "$kde_use_debug_code" != "no"; then + if test "$CXX" = "KCC"; then + CXXFLAGS="+K0 -Wall -pedantic -W -Wpointer-arith -Wwrite-strings $CXXFLAGS" + else + if test "$kde_use_debug_code" = "full"; then + CXXFLAGS="-g3 -fno-inline $CXXFLAGS" + else + CXXFLAGS="-g -O2 $CXXFLAGS" + fi + fi + KDE_CHECK_COMPILER_FLAG(fno-builtin,[CXXFLAGS="-fno-builtin $CXXFLAGS"]) + + dnl convenience compiler flags + KDE_CHECK_COMPILER_FLAG(Woverloaded-virtual, [WOVERLOADED_VIRTUAL="-Woverloaded-virtual"], [WOVERLOADED_VRITUAL=""]) + AC_SUBST(WOVERLOADED_VIRTUAL) + else + if test "$CXX" = "KCC"; then + CXXFLAGS="+K3 $CXXFLAGS" + else + CXXFLAGS="-O2 $CXXFLAGS" + fi + fi + fi + + if test "$kde_use_debug_define" = "yes"; then + CXXFLAGS="-DNDEBUG -DNO_DEBUG $CXXFLAGS" + fi + + if test "$kde_use_profiling" = "yes"; then + KDE_CHECK_COMPILER_FLAG(pg, + [ + CFLAGS="-pg $CFLAGS" + CXXFLAGS="-pg $CXXFLAGS" + ]) + fi + + if test "$kde_use_warnings" = "yes"; then + if test "$GCC" = "yes"; then + CXXFLAGS="-Wall -W -Wpointer-arith -Wwrite-strings $CXXFLAGS" + case $host in + *-*-linux-gnu) + CFLAGS="-std=iso9899:1990 -W -Wall -Wchar-subscripts -Wshadow -Wpointer-arith -Wmissing-prototypes -Wwrite-strings -D_XOPEN_SOURCE=500 -D_BSD_SOURCE $CFLAGS" + CXXFLAGS="-ansi -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wcast-align -Wconversion -Wchar-subscripts $CXXFLAGS" + KDE_CHECK_COMPILER_FLAG(Wmissing-format-attribute, [CXXFLAGS="$CXXFLAGS -Wformat-security -Wmissing-format-attribute"]) + KDE_CHECK_C_COMPILER_FLAG(Wmissing-format-attribute, [CFLAGS="$CFLAGS -Wformat-security -Wmissing-format-attribute"]) + ;; + esac + KDE_CHECK_COMPILER_FLAG(Wundef,[CXXFLAGS="-Wundef $CXXFLAGS"]) + KDE_CHECK_COMPILER_FLAG(Wno-long-long,[CXXFLAGS="-Wno-long-long $CXXFLAGS"]) + KDE_CHECK_COMPILER_FLAG(Wnon-virtual-dtor,[CXXFLAGS="-Wnon-virtual-dtor $CXXFLAGS"]) + fi + fi + + if test "$GXX" = "yes" && test "$kde_use_strict_options" = "yes"; then + CXXFLAGS="-Wcast-qual -Wshadow -Wcast-align $CXXFLAGS" + fi + + AC_ARG_ENABLE(pch, + AC_HELP_STRING([--enable-pch], + [enables precompiled header support (currently only KCC or gcc >=3.4+unsermake) [default=no]]), + [ kde_use_pch=$enableval ],[ kde_use_pch=no ]) + + HAVE_GCC_VISIBILITY=0 + AC_SUBST([HAVE_GCC_VISIBILITY]) + + if test "$GXX" = "yes"; then + KDE_CHECK_COMPILER_FLAG(fno-exceptions,[CXXFLAGS="$CXXFLAGS -fno-exceptions"]) + KDE_CHECK_COMPILER_FLAG(fno-check-new, [CXXFLAGS="$CXXFLAGS -fno-check-new"]) + KDE_CHECK_COMPILER_FLAG(fno-common, [CXXFLAGS="$CXXFLAGS -fno-common"]) + KDE_CHECK_COMPILER_FLAG(fexceptions, [USE_EXCEPTIONS="-fexceptions"], USE_EXCEPTIONS= ) + ENABLE_PERMISSIVE_FLAG="-fpermissive" + + if test "$kde_use_pch" = "yes"; then + AC_MSG_CHECKING(whether gcc supports precompiling c header files) + echo >conftest.h + if $CC -x c-header conftest.h >/dev/null 2>/dev/null; then + kde_gcc_supports_pch=yes + AC_MSG_RESULT(yes) + else + kde_gcc_supports_pch=no + AC_MSG_RESULT(no) + fi + if test "$kde_gcc_supports_pch" = "yes"; then + AC_MSG_CHECKING(whether gcc supports precompiling c++ header files) + if $CXX -x c++-header conftest.h >/dev/null 2>/dev/null; then + kde_gcc_supports_pch=yes + AC_MSG_RESULT(yes) + else + kde_gcc_supports_pch=no + AC_MSG_RESULT(no) + fi + fi + rm -f conftest.h conftest.h.gch + fi + AM_CONDITIONAL(unsermake_enable_pch, test "$kde_use_pch" = "yes" && test "$kde_gcc_supports_pch" = "yes") + fi + if test "$CXX" = "KCC"; then + dnl unfortunately we currently cannot disable exception support in KCC + dnl because doing so is binary incompatible and Qt by default links with exceptions :-( + dnl KDE_CHECK_COMPILER_FLAG(-no_exceptions,[CXXFLAGS="$CXXFLAGS --no_exceptions"]) + dnl KDE_CHECK_COMPILER_FLAG(-exceptions, [USE_EXCEPTIONS="--exceptions"], USE_EXCEPTIONS= ) + + if test "$kde_use_pch" = "yes"; then + dnl TODO: support --pch-dir! + KDE_CHECK_COMPILER_FLAG(-pch,[CXXFLAGS="$CXXFLAGS --pch"]) + dnl the below works (but the dir must exist), but it's + dnl useless for a whole package. + dnl The are precompiled headers for each source file, so when compiling + dnl from scratch, it doesn't make a difference, and they take up + dnl around ~5Mb _per_ sourcefile. + dnl KDE_CHECK_COMPILER_FLAG(-pch_dir /tmp, + dnl [CXXFLAGS="$CXXFLAGS --pch_dir `pwd`/pcheaders"]) + fi + dnl this flag controls inlining. by default KCC inlines in optimisation mode + dnl all implementations that are defined inside the class {} declaration. + dnl because of templates-compatibility with broken gcc compilers, this + dnl can cause excessive inlining. This flag limits it to a sane level + KDE_CHECK_COMPILER_FLAG(-inline_keyword_space_time=6,[CXXFLAGS="$CXXFLAGS --inline_keyword_space_time=6"]) + KDE_CHECK_COMPILER_FLAG(-inline_auto_space_time=2,[CXXFLAGS="$CXXFLAGS --inline_auto_space_time=2"]) + KDE_CHECK_COMPILER_FLAG(-inline_implicit_space_time=2.0,[CXXFLAGS="$CXXFLAGS --inline_implicit_space_time=2.0"]) + KDE_CHECK_COMPILER_FLAG(-inline_generated_space_time=2.0,[CXXFLAGS="$CXXFLAGS --inline_generated_space_time=2.0"]) + dnl Some source files are shared between multiple executables + dnl (or libraries) and some of those need template instantiations. + dnl In that case KCC needs to compile those sources with + dnl --one_instantiation_per_object. To make it easy for us we compile + dnl _all_ objects with that flag (--one_per is a shorthand). + KDE_CHECK_COMPILER_FLAG(-one_per, [CXXFLAGS="$CXXFLAGS --one_per"]) + fi + AC_SUBST(USE_EXCEPTIONS) + dnl obsolete macro - provided to keep things going + USE_RTTI= + AC_SUBST(USE_RTTI) + + case "$host" in + *-*-irix*) test "$GXX" = yes && CXXFLAGS="-D_LANGUAGE_C_PLUS_PLUS -D__LANGUAGE_C_PLUS_PLUS $CXXFLAGS" ;; + *-*-sysv4.2uw*) CXXFLAGS="-D_UNIXWARE $CXXFLAGS";; + *-*-sysv5uw7*) CXXFLAGS="-D_UNIXWARE7 $CXXFLAGS";; + *-*-solaris*) + if test "$GXX" = yes; then + libstdcpp=`$CXX -print-file-name=libstdc++.so` + if test ! -f $libstdcpp; then + AC_MSG_ERROR([You've compiled gcc without --enable-shared. This doesn't work with KDE. Please recompile gcc with --enable-shared to receive a libstdc++.so]) + fi + fi + ;; + esac + + AC_VALIDIFY_CXXFLAGS + + AC_PROG_CXXCPP + + if test "$GCC" = yes; then + NOOPT_CFLAGS=-O0 + fi + KDE_CHECK_COMPILER_FLAG(O0,[NOOPT_CXXFLAGS=-O0]) + + AC_ARG_ENABLE(coverage, + AC_HELP_STRING([--enable-coverage],[use gcc coverage testing]), [ + if test "$am_cv_CC_dependencies_compiler_type" = "gcc3"; then + ac_coverage_compiler="-fprofile-arcs -ftest-coverage" + ac_coverage_linker="-lgcc" + elif test "$am_cv_CC_dependencies_compiler_type" = "gcc"; then + ac_coverage_compiler="-fprofile-arcs -ftest-coverage" + ac_coverage_linker="" + else + AC_MSG_ERROR([coverage with your compiler is not supported]) + fi + CFLAGS="$CFLAGS $ac_coverage_compiler" + CXXFLAGS="$CXXFLAGS $ac_coverage_compiler" + LDFLAGS="$LDFLAGS $ac_coverage_linker" + ]) + + AC_SUBST(NOOPT_CXXFLAGS) + AC_SUBST(NOOPT_CFLAGS) + AC_SUBST(ENABLE_PERMISSIVE_FLAG) + + KDE_CHECK_NEW_LDFLAGS + KDE_CHECK_FINAL + KDE_CHECK_CLOSURE + KDE_CHECK_NMCHECK + + ifdef([AM_DEPENDENCIES], AC_REQUIRE([KDE_ADD_DEPENDENCIES]), []) +]) + +AC_DEFUN([KDE_CHECK_VISIBILITY_GCC_BUG], + [ + AC_CACHE_CHECK([for gcc -fvisibility-inlines-hidden bug], kde_cv_val_gcc_visibility_bug, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + + safe_CXXFLAGS=$CXXFLAGS + safe_LDFLAGS=$LDFLAGS + CXXFLAGS="$CXXFLAGS -fPIC -fvisibility-inlines-hidden -O0" + LDFLAGS="$LDFLAGS -shared -fPIC" + + AC_TRY_LINK( + [ + /* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19664 */ + template + struct VisTest + { + inline VisTest (); + }; + template + inline VisTest::VisTest() + {} + extern template class VisTest; // It works if we drop that line + int some_function( int do_something ) __attribute__ ((visibility("default"))); + int some_function( int ) + { + VisTest a; + return 0; + } + ], [/* elvis is alive */], + kde_cv_val_gcc_visibility_bug=no, kde_cv_val_gcc_visibility_bug=yes) + + CXXFLAGS=$safe_CXXFLAGS + LDFLAGS=$safe_LDFLAGS + AC_LANG_RESTORE + ] + ) + + if test x$kde_cv_val_gcc_visibility_bug = xno; then + CXXFLAGS="$CXXFLAGS -fvisibility-inlines-hidden" + fi + ] +) + +AC_DEFUN([KDE_CHECK_AND_ADD_HIDDEN_VISIBILITY], +[ + if test "$GXX" = "yes"; then + KDE_CHECK_COMPILER_FLAG(fno-exceptions,[CXXFLAGS="$CXXFLAGS -fno-exceptions"]) + KDE_CHECK_COMPILER_FLAG(fno-check-new, [CXXFLAGS="$CXXFLAGS -fno-check-new"]) + KDE_CHECK_COMPILER_FLAG(fno-common, [CXXFLAGS="$CXXFLAGS -fno-common"]) + KDE_CHECK_COMPILER_FLAG(fvisibility=hidden, + [ + CXXFLAGS="$CXXFLAGS -fvisibility=hidden" + KDE_CHECK_VISIBILITY_GCC_BUG + + HAVE_GCC_VISIBILITY=1 + AC_DEFINE_UNQUOTED(__KDE_HAVE_GCC_VISIBILITY, "$HAVE_GCC_VISIBILITY", [define to 1 if -fvisibility is supported]) + ]) + fi +]) + +AC_DEFUN([KDE_ENABLE_HIDDEN_VISIBILITY], +[ + AC_REQUIRE([KDE_CHECK_AND_ADD_HIDDEN_VISIBILITY]) +]) + +AC_DEFUN([KDE_ADD_DEPENDENCIES], +[ + [A]M_DEPENDENCIES(CC) + [A]M_DEPENDENCIES(CXX) +]) + +dnl just a wrapper to clean up configure.in +AC_DEFUN([KDE_PROG_LIBTOOL], +[ +AC_REQUIRE([AC_CHECK_COMPILERS]) +AC_REQUIRE([AC_ENABLE_SHARED]) +AC_REQUIRE([AC_ENABLE_STATIC]) + +AC_REQUIRE([AC_LIBTOOL_DLOPEN]) +AC_REQUIRE([KDE_CHECK_LIB64]) + +AC_OBJEXT +AC_EXEEXT + +AM_PROG_LIBTOOL +AC_LIBTOOL_CXX + +LIBTOOL_SHELL="/bin/sh ./libtool" +# LIBTOOL="$LIBTOOL --silent" +KDE_PLUGIN="-avoid-version -module -no-undefined \$(KDE_NO_UNDEFINED) \$(KDE_RPATH) \$(KDE_MT_LDFLAGS)" +AC_SUBST(KDE_PLUGIN) + +# we patch configure quite some so we better keep that consistent for incremental runs +AC_SUBST(AUTOCONF,'$(SHELL) $(top_srcdir)/admin/cvs.sh configure || touch configure') +]) + +AC_DEFUN([KDE_CHECK_LIB64], +[ + kdelibsuff="$kde_libs_suffix" + if test -z "$kdelibsuff"; then + kdelibsuff=no + fi + AC_ARG_ENABLE(libsuffix, + AC_HELP_STRING([--enable-libsuffix], + [/lib directory suffix (64,32,none[=default])]), + kdelibsuff=$enableval) + # TODO: add an auto case that compiles a little C app to check + # where the glibc is + if test "$kdelibsuff" = "no"; then + kdelibsuff= + fi + if test -z "$kdelibsuff"; then + AC_MSG_RESULT([not using lib directory suffix]) + AC_DEFINE(KDELIBSUFF, [""], Suffix for lib directories) + else + if test "$libdir" = '${exec_prefix}/lib'; then + libdir="$libdir${kdelibsuff}" + AC_SUBST([libdir], ["$libdir"]) dnl ugly hack for lib64 platforms + fi + AC_DEFINE_UNQUOTED(KDELIBSUFF, ["${kdelibsuff}"], Suffix for lib directories) + AC_MSG_RESULT([using lib directory suffix $kdelibsuff]) + fi +]) + +AC_DEFUN([KDE_CHECK_TYPES], +[ AC_CHECK_SIZEOF(int, 4)dnl + AC_CHECK_SIZEOF(short)dnl + AC_CHECK_SIZEOF(long, 4)dnl + AC_CHECK_SIZEOF(char *, 4)dnl +])dnl + +dnl Not used - kept for compat only? +AC_DEFUN([KDE_DO_IT_ALL], +[ +AC_CANONICAL_SYSTEM +AC_ARG_PROGRAM +AM_INIT_AUTOMAKE($1, $2) +AM_DISABLE_LIBRARIES +AC_PREFIX_DEFAULT(${KDEDIR:-/usr/local/kde}) +AC_CHECK_COMPILERS +KDE_PROG_LIBTOOL +AM_KDE_WITH_NLS +AC_PATH_KDE +]) + +AC_DEFUN([AC_CHECK_RPATH], +[ +AC_MSG_CHECKING(for rpath) +AC_ARG_ENABLE(rpath, + AC_HELP_STRING([--disable-rpath],[do not use the rpath feature of ld]), + USE_RPATH=$enableval, USE_RPATH=yes) + +if test -z "$KDE_RPATH" && test "$USE_RPATH" = "yes"; then + + KDE_RPATH="-R \$(libdir)" + + if test "$kde_libraries" != "$libdir"; then + KDE_RPATH="$KDE_RPATH -R \$(kde_libraries)" + fi + + if test -n "$qt_libraries"; then + KDE_RPATH="$KDE_RPATH -R \$(qt_libraries)" + fi + dnl $x_libraries is set to /usr/lib in case + if test -n "$X_LDFLAGS"; then + X_RPATH="-R \$(x_libraries)" + KDE_RPATH="$KDE_RPATH $X_RPATH" + fi + if test -n "$KDE_EXTRA_RPATH"; then + KDE_RPATH="$KDE_RPATH \$(KDE_EXTRA_RPATH)" + fi +fi +AC_SUBST(KDE_EXTRA_RPATH) +AC_SUBST(KDE_RPATH) +AC_SUBST(X_RPATH) +AC_MSG_RESULT($USE_RPATH) +]) + +dnl Check for the type of the third argument of getsockname +AC_DEFUN([AC_CHECK_SOCKLEN_T], +[ + AC_MSG_CHECKING(for socklen_t) + AC_CACHE_VAL(kde_cv_socklen_t, + [ + AC_LANG_PUSH(C++) + kde_cv_socklen_t=no + AC_TRY_COMPILE([ + #include + #include + ], + [ + socklen_t len; + getpeername(0,0,&len); + ], + [ + kde_cv_socklen_t=yes + kde_cv_socklen_t_equiv=socklen_t + ]) + AC_LANG_POP(C++) + ]) + AC_MSG_RESULT($kde_cv_socklen_t) + if test $kde_cv_socklen_t = no; then + AC_MSG_CHECKING([for socklen_t equivalent for socket functions]) + AC_CACHE_VAL(kde_cv_socklen_t_equiv, + [ + kde_cv_socklen_t_equiv=int + AC_LANG_PUSH(C++) + for t in int size_t unsigned long "unsigned long"; do + AC_TRY_COMPILE([ + #include + #include + ], + [ + $t len; + getpeername(0,0,&len); + ], + [ + kde_cv_socklen_t_equiv="$t" + break + ]) + done + AC_LANG_POP(C++) + ]) + AC_MSG_RESULT($kde_cv_socklen_t_equiv) + fi + AC_DEFINE_UNQUOTED(kde_socklen_t, $kde_cv_socklen_t_equiv, + [type to use in place of socklen_t if not defined]) + AC_DEFINE_UNQUOTED(ksize_t, $kde_cv_socklen_t_equiv, + [type to use in place of socklen_t if not defined (deprecated, use kde_socklen_t)]) +]) + +dnl This is a merge of some macros out of the gettext aclocal.m4 +dnl since we don't need anything, I took the things we need +dnl the copyright for them is: +dnl > +dnl Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +dnl This Makefile.in is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. +dnl > +dnl for this file it is relicensed under LGPL + +AC_DEFUN([AM_KDE_WITH_NLS], + [ + dnl If we use NLS figure out what method + + AM_PATH_PROG_WITH_TEST_KDE(MSGFMT, msgfmt, + [test -n "`$ac_dir/$ac_word --version 2>&1 | grep 'GNU gettext'`"], msgfmt) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + + if test -z "`$GMSGFMT --version 2>&1 | grep 'GNU gettext'`"; then + AC_MSG_RESULT([found msgfmt program is not GNU msgfmt; ignore it]) + GMSGFMT=":" + fi + MSGFMT=$GMSGFMT + AC_SUBST(GMSGFMT) + AC_SUBST(MSGFMT) + + AM_PATH_PROG_WITH_TEST_KDE(XGETTEXT, xgettext, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) + + dnl Test whether we really found GNU xgettext. + if test "$XGETTEXT" != ":"; then + dnl If it is no GNU xgettext we define it as : so that the + dnl Makefiles still can work. + if $XGETTEXT --omit-header /dev/null 2> /dev/null; then + : ; + else + AC_MSG_RESULT( + [found xgettext programs is not GNU xgettext; ignore it]) + XGETTEXT=":" + fi + fi + AC_SUBST(XGETTEXT) + + ]) + +# Search path for a program which passes the given test. +# Ulrich Drepper , 1996. + +# serial 1 +# Stephan Kulow: I appended a _KDE against name conflicts + +dnl AM_PATH_PROG_WITH_TEST_KDE(VARIABLE, PROG-TO-CHECK-FOR, +dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN([AM_PATH_PROG_WITH_TEST_KDE], +[# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_path_$1, +[case "[$]$1" in + /*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in ifelse([$5], , $PATH, [$5]); do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if [$3]; then + ac_cv_path_$1="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test -n "[$]$1"; then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) + + +# Check whether LC_MESSAGES is available in . +# Ulrich Drepper , 1995. + +# serial 1 + +AC_DEFUN([AM_LC_MESSAGES], + [if test $ac_cv_header_locale_h = yes; then + AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, + [AC_TRY_LINK([#include ], [return LC_MESSAGES], + am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) + if test $am_cv_val_LC_MESSAGES = yes; then + AC_DEFINE(HAVE_LC_MESSAGES, 1, [Define if your locale.h file contains LC_MESSAGES]) + fi + fi]) + +dnl From Jim Meyering. +dnl FIXME: migrate into libit. + +AC_DEFUN([AM_FUNC_OBSTACK], +[AC_CACHE_CHECK([for obstacks], am_cv_func_obstack, + [AC_TRY_LINK([#include "obstack.h"], + [struct obstack *mem;obstack_free(mem,(char *) 0)], + am_cv_func_obstack=yes, + am_cv_func_obstack=no)]) + if test $am_cv_func_obstack = yes; then + AC_DEFINE(HAVE_OBSTACK) + else + LIBOBJS="$LIBOBJS obstack.o" + fi +]) + +dnl From Jim Meyering. Use this if you use the GNU error.[ch]. +dnl FIXME: Migrate into libit + +AC_DEFUN([AM_FUNC_ERROR_AT_LINE], +[AC_CACHE_CHECK([for error_at_line], am_cv_lib_error_at_line, + [AC_TRY_LINK([],[error_at_line(0, 0, "", 0, "");], + am_cv_lib_error_at_line=yes, + am_cv_lib_error_at_line=no)]) + if test $am_cv_lib_error_at_line = no; then + LIBOBJS="$LIBOBJS error.o" + fi + AC_SUBST(LIBOBJS)dnl +]) + +# Macro to add for using GNU gettext. +# Ulrich Drepper , 1995. + +# serial 1 +# Stephan Kulow: I put a KDE in it to avoid name conflicts + +AC_DEFUN([AM_KDE_GNU_GETTEXT], + [AC_REQUIRE([AC_PROG_MAKE_SET])dnl + AC_REQUIRE([AC_PROG_RANLIB])dnl + AC_REQUIRE([AC_HEADER_STDC])dnl + AC_REQUIRE([AC_TYPE_OFF_T])dnl + AC_REQUIRE([AC_TYPE_SIZE_T])dnl + AC_REQUIRE([AC_FUNC_ALLOCA])dnl + AC_REQUIRE([AC_FUNC_MMAP])dnl + AC_REQUIRE([AM_KDE_WITH_NLS])dnl + AC_CHECK_HEADERS([limits.h locale.h nl_types.h string.h values.h alloca.h]) + AC_CHECK_FUNCS([getcwd munmap putenv setlocale strchr strcasecmp \ +__argz_count __argz_stringify __argz_next]) + + AC_MSG_CHECKING(for stpcpy) + AC_CACHE_VAL(kde_cv_func_stpcpy, + [ + kde_safe_cxxflags=$CXXFLAGS + CXXFLAGS="-Werror" + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_COMPILE([ + #include + ], + [ + char buffer[200]; + stpcpy(buffer, buffer); + ], + kde_cv_func_stpcpy=yes, + kde_cv_func_stpcpy=no) + AC_LANG_RESTORE + CXXFLAGS=$kde_safe_cxxflags + ]) + AC_MSG_RESULT($kde_cv_func_stpcpy) + if eval "test \"`echo $kde_cv_func_stpcpy`\" = yes"; then + AC_DEFINE(HAVE_STPCPY, 1, [Define if you have stpcpy]) + fi + + AM_LC_MESSAGES + + if test "x$CATOBJEXT" != "x"; then + if test "x$ALL_LINGUAS" = "x"; then + LINGUAS= + else + AC_MSG_CHECKING(for catalogs to be installed) + NEW_LINGUAS= + for lang in ${LINGUAS=$ALL_LINGUAS}; do + case "$ALL_LINGUAS" in + *$lang*) NEW_LINGUAS="$NEW_LINGUAS $lang" ;; + esac + done + LINGUAS=$NEW_LINGUAS + AC_MSG_RESULT($LINGUAS) + fi + + dnl Construct list of names of catalog files to be constructed. + if test -n "$LINGUAS"; then + for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done + fi + fi + + ]) + +AC_DEFUN([AC_HAVE_XPM], + [AC_REQUIRE_CPP()dnl + AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + + test -z "$XPM_LDFLAGS" && XPM_LDFLAGS= + test -z "$XPM_INCLUDE" && XPM_INCLUDE= + + AC_ARG_WITH(xpm,AC_HELP_STRING([--without-xpm],[disable color pixmap XPM tests]), + xpm_test=$withval, xpm_test="yes") + if test "x$xpm_test" = xno; then + ac_cv_have_xpm=no + else + AC_MSG_CHECKING(for XPM) + AC_CACHE_VAL(ac_cv_have_xpm, + [ + ac_save_ldflags="$LDFLAGS" + ac_save_cflags="$CFLAGS" + if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then + LDFLAGS="$LDFLAGS $X_LDFLAGS $USER_LDFLAGS $LDFLAGS $XPM_LDFLAGS $all_libraries -lXpm -lX11 -lXext $LIBZ $LIBSOCKET" + else + LDFLAGS="$LDFLAGS $X_LDFLAGS $USER_LDFLAGS $LDFLAGS $XPM_LDFLAGS $all_libraries -lXpm $LIBZ $LIBSOCKET" + fi + CFLAGS="$CFLAGS $X_INCLUDES $USER_INCLUDES" + test -n "$XPM_INCLUDE" && CFLAGS="-I$XPM_INCLUDE $CFLAGS" + AC_TRY_LINK([#include ],[], + ac_cv_have_xpm="yes",ac_cv_have_xpm="no") + LDFLAGS="$ac_save_ldflags" + CFLAGS="$ac_save_cflags" + ])dnl + + if test "$ac_cv_have_xpm" = no; then + AC_MSG_RESULT(no) + XPM_LDFLAGS="" + XPMINC="" + $2 + else + AC_DEFINE(HAVE_XPM, 1, [Define if you have XPM support]) + if test "$XPM_LDFLAGS" = ""; then + XPMLIB='-lXpm $(LIB_X11)' + else + XPMLIB="-L$XPM_LDFLAGS -lXpm "'$(LIB_X11)' + fi + if test "$XPM_INCLUDE" = ""; then + XPMINC="" + else + XPMINC="-I$XPM_INCLUDE" + fi + AC_MSG_RESULT(yes) + $1 + fi + fi + AC_SUBST(XPMINC) + AC_SUBST(XPMLIB) +]) + +AC_DEFUN([AC_HAVE_DPMS], + [AC_REQUIRE_CPP()dnl + AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + + test -z "$DPMS_LDFLAGS" && DPMS_LDFLAGS= + test -z "$DPMS_INCLUDE" && DPMS_INCLUDE= + DPMS_LIB= + + AC_ARG_WITH(dpms,AC_HELP_STRING([--without-dpms],[disable DPMS power saving]), + dpms_test=$withval, dpms_test="yes") + if test "x$dpms_test" = xno; then + ac_cv_have_dpms=no + else + AC_MSG_CHECKING(for DPMS) + dnl Note: ac_cv_have_dpms can be no, yes, or -lXdpms. + dnl 'yes' means DPMS_LIB="", '-lXdpms' means DPMS_LIB="-lXdpms". + AC_CACHE_VAL(ac_cv_have_dpms, + [ + if test "x$kde_use_qt_emb" = "xyes" || test "x$kde_use_qt_mac" = "xyes"; then + AC_MSG_RESULT(no) + ac_cv_have_dpms="no" + else + ac_save_ldflags="$LDFLAGS" + ac_save_cflags="$CFLAGS" + ac_save_libs="$LIBS" + LDFLAGS="$LDFLAGS $DPMS_LDFLAGS $all_libraries -lX11 -lXext $LIBSOCKET" + CFLAGS="$CFLAGS $X_INCLUDES" + test -n "$DPMS_INCLUDE" && CFLAGS="-I$DPMS_INCLUDE $CFLAGS" + AC_TRY_LINK([ + #include + #include + #include + #include + int foo_test_dpms() + { return DPMSSetTimeouts( 0, 0, 0, 0 ); }],[], + ac_cv_have_dpms="yes", [ + LDFLAGS="$ac_save_ldflags" + CFLAGS="$ac_save_cflags" + LDFLAGS="$LDFLAGS $DPMS_LDFLAGS $all_libraries -lX11 -lXext $LIBSOCKET" + LIBS="$LIBS -lXdpms" + CFLAGS="$CFLAGS $X_INCLUDES" + test -n "$DPMS_INCLUDE" && CFLAGS="-I$DPMS_INCLUDE $CFLAGS" + AC_TRY_LINK([ + #include + #include + #include + #include + int foo_test_dpms() + { return DPMSSetTimeouts( 0, 0, 0, 0 ); }],[], + [ + ac_cv_have_dpms="-lXdpms" + ],ac_cv_have_dpms="no") + ]) + LDFLAGS="$ac_save_ldflags" + CFLAGS="$ac_save_cflags" + LIBS="$ac_save_libs" + fi + ])dnl + + if test "$ac_cv_have_dpms" = no; then + AC_MSG_RESULT(no) + DPMS_LDFLAGS="" + DPMSINC="" + $2 + else + AC_DEFINE(HAVE_DPMS, 1, [Define if you have DPMS support]) + if test "$ac_cv_have_dpms" = "-lXdpms"; then + DPMS_LIB="-lXdpms" + fi + if test "$DPMS_LDFLAGS" = ""; then + DPMSLIB="$DPMS_LIB "'$(LIB_X11)' + else + DPMSLIB="$DPMS_LDFLAGS $DPMS_LIB "'$(LIB_X11)' + fi + if test "$DPMS_INCLUDE" = ""; then + DPMSINC="" + else + DPMSINC="-I$DPMS_INCLUDE" + fi + AC_MSG_RESULT(yes) + $1 + fi + fi + ac_save_cflags="$CFLAGS" + CFLAGS="$CFLAGS $X_INCLUDES" + test -n "$DPMS_INCLUDE" && CFLAGS="-I$DPMS_INCLUDE $CFLAGS" + AH_TEMPLATE(HAVE_DPMSCAPABLE_PROTO, + [Define if you have the DPMSCapable prototype in ]) + AC_CHECK_DECL(DPMSCapable, + AC_DEFINE(HAVE_DPMSCAPABLE_PROTO),, + [#include ]) + AH_TEMPLATE(HAVE_DPMSINFO_PROTO, + [Define if you have the DPMSInfo prototype in ]) + AC_CHECK_DECL(DPMSInfo, + AC_DEFINE(HAVE_DPMSINFO_PROTO),, + [#include ]) + CFLAGS="$ac_save_cflags" + AC_SUBST(DPMSINC) + AC_SUBST(DPMSLIB) +]) + +AC_DEFUN([AC_HAVE_GL], + [AC_REQUIRE_CPP()dnl + AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + + test -z "$GL_LDFLAGS" && GL_LDFLAGS= + test -z "$GL_INCLUDE" && GL_INCLUDE= + + AC_ARG_WITH(gl,AC_HELP_STRING([--without-gl],[disable 3D GL modes]), + gl_test=$withval, gl_test="yes") + if test "x$kde_use_qt_emb" = "xyes"; then + # GL and Qt Embedded is a no-go for now. + ac_cv_have_gl=no + elif test "x$gl_test" = xno; then + ac_cv_have_gl=no + else + AC_MSG_CHECKING(for GL) + AC_CACHE_VAL(ac_cv_have_gl, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_ldflags="$LDFLAGS" + ac_save_cxxflags="$CXXFLAGS" + LDFLAGS="$LDFLAGS $GL_LDFLAGS $X_LDFLAGS $all_libraries -lGL -lGLU" + test "x$kde_use_qt_mac" != xyes && test "x$kde_use_qt_emb" != xyes && LDFLAGS="$LDFLAGS -lX11" + LDFLAGS="$LDFLAGS $LIB_XEXT -lm $LIBSOCKET" + CXXFLAGS="$CFLAGS $X_INCLUDES" + test -n "$GL_INCLUDE" && CFLAGS="-I$GL_INCLUDE $CFLAGS" + AC_TRY_LINK([#include +#include +], [], + ac_cv_have_gl="yes", ac_cv_have_gl="no") + AC_LANG_RESTORE + LDFLAGS="$ac_save_ldflags" + CXXFLAGS="$ac_save_cxxflags" + ])dnl + + if test "$ac_cv_have_gl" = "no"; then + AC_MSG_RESULT(no) + GL_LDFLAGS="" + GLINC="" + $2 + else + AC_DEFINE(HAVE_GL, 1, [Defines if you have GL (Mesa, OpenGL, ...)]) + if test "$GL_LDFLAGS" = ""; then + GLLIB='-lGLU -lGL $(LIB_X11)' + else + GLLIB="$GL_LDFLAGS -lGLU -lGL "'$(LIB_X11)' + fi + if test "$GL_INCLUDE" = ""; then + GLINC="" + else + GLINC="-I$GL_INCLUDE" + fi + AC_MSG_RESULT($ac_cv_have_gl) + $1 + fi + fi + AC_SUBST(GLINC) + AC_SUBST(GLLIB) +]) + + + dnl shadow password and PAM magic - maintained by ossi@kde.org + +AC_DEFUN([KDE_PAM], [ + AC_REQUIRE([KDE_CHECK_LIBDL]) + + want_pam= + AC_ARG_WITH(pam, + AC_HELP_STRING([--with-pam[=ARG]],[enable support for PAM: ARG=[yes|no|service name]]), + [ if test "x$withval" = "xyes"; then + want_pam=yes + pam_service=kde + elif test "x$withval" = "xno"; then + want_pam=no + else + want_pam=yes + pam_service=$withval + fi + ], [ pam_service=kde ]) + + use_pam= + PAMLIBS= + if test "x$want_pam" != xno; then + AC_CHECK_LIB(pam, pam_start, [ + AC_CHECK_HEADER(security/pam_appl.h, + [ pam_header=security/pam_appl.h ], + [ AC_CHECK_HEADER(pam/pam_appl.h, + [ pam_header=pam/pam_appl.h ], + [ + AC_MSG_WARN([PAM detected, but no headers found! +Make sure you have the necessary development packages installed.]) + ] + ) + ] + ) + ], , $LIBDL) + if test -z "$pam_header"; then + if test "x$want_pam" = xyes; then + AC_MSG_ERROR([--with-pam was specified, but cannot compile with PAM!]) + fi + else + AC_DEFINE(HAVE_PAM, 1, [Defines if you have PAM (Pluggable Authentication Modules)]) + PAMLIBS="$PAM_MISC_LIB -lpam $LIBDL" + use_pam=yes + + dnl darwin claims to be something special + if test "$pam_header" = "pam/pam_appl.h"; then + AC_DEFINE(HAVE_PAM_PAM_APPL_H, 1, [Define if your PAM headers are in pam/ instead of security/]) + fi + + dnl test whether struct pam_message is const (Linux) or not (Sun) + AC_MSG_CHECKING(for const pam_message) + AC_EGREP_HEADER([struct pam_message], $pam_header, + [ AC_EGREP_HEADER([const struct pam_message], $pam_header, + [AC_MSG_RESULT([const: Linux-type PAM])], + [AC_MSG_RESULT([nonconst: Sun-type PAM]) + AC_DEFINE(PAM_MESSAGE_NONCONST, 1, [Define if your PAM support takes non-const arguments (Solaris)])] + )], + [AC_MSG_RESULT([not found - assume const, Linux-type PAM])]) + fi + fi + + AC_SUBST(PAMLIBS) +]) + +dnl DEF_PAM_SERVICE(arg name, full name, define name) +AC_DEFUN([DEF_PAM_SERVICE], [ + AC_ARG_WITH($1-pam, + AC_HELP_STRING([--with-$1-pam=[val]],[override PAM service from --with-pam for $2]), + [ if test "x$use_pam" = xyes; then + $3_PAM_SERVICE=$withval + else + AC_MSG_ERROR([Cannot use use --with-$1-pam, as no PAM was detected. +You may want to enforce it by using --with-pam.]) + fi + ], + [ if test "x$use_pam" = xyes; then + $3_PAM_SERVICE="$pam_service" + fi + ]) + if test -n "$$3_PAM_SERVICE"; then + AC_MSG_RESULT([The PAM service used by $2 will be $$3_PAM_SERVICE]) + AC_DEFINE_UNQUOTED($3_PAM_SERVICE, "$$3_PAM_SERVICE", [The PAM service to be used by $2]) + fi + AC_SUBST($3_PAM_SERVICE) +]) + +AC_DEFUN([KDE_SHADOWPASSWD], [ + AC_REQUIRE([KDE_PAM]) + + AC_CHECK_LIB(shadow, getspent, + [ LIBSHADOW="-lshadow" + ac_use_shadow=yes + ], + [ dnl for UnixWare + AC_CHECK_LIB(gen, getspent, + [ LIBGEN="-lgen" + ac_use_shadow=yes + ], + [ AC_CHECK_FUNC(getspent, + [ ac_use_shadow=yes ], + [ ac_use_shadow=no ]) + ]) + ]) + AC_SUBST(LIBSHADOW) + AC_SUBST(LIBGEN) + + AC_MSG_CHECKING([for shadow passwords]) + + AC_ARG_WITH(shadow, + AC_HELP_STRING([--with-shadow],[If you want shadow password support]), + [ if test "x$withval" != "xno"; then + use_shadow=yes + else + use_shadow=no + fi + ], [ + use_shadow="$ac_use_shadow" + ]) + + if test "x$use_shadow" = xyes; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SHADOW, 1, [Define if you use shadow passwords]) + else + AC_MSG_RESULT(no) + LIBSHADOW= + LIBGEN= + fi + + dnl finally make the relevant binaries setuid root, if we have shadow passwds. + dnl this still applies, if we could use it indirectly through pam. + if test "x$use_shadow" = xyes || + ( test "x$use_pam" = xyes && test "x$ac_use_shadow" = xyes ); then + case $host in + *-*-freebsd* | *-*-netbsd* | *-*-openbsd*) + SETUIDFLAGS="-m 4755 -o root";; + *) + SETUIDFLAGS="-m 4755";; + esac + fi + AC_SUBST(SETUIDFLAGS) + +]) + +AC_DEFUN([KDE_PASSWDLIBS], [ + AC_REQUIRE([KDE_MISC_TESTS]) dnl for LIBCRYPT + AC_REQUIRE([KDE_PAM]) + AC_REQUIRE([KDE_SHADOWPASSWD]) + + if test "x$use_pam" = "xyes"; then + PASSWDLIBS="$PAMLIBS" + else + PASSWDLIBS="$LIBCRYPT $LIBSHADOW $LIBGEN" + fi + + dnl FreeBSD uses a shadow-like setup, where /etc/passwd holds the users, but + dnl /etc/master.passwd holds the actual passwords. /etc/master.passwd requires + dnl root to read, so kcheckpass needs to be root (even when using pam, since pam + dnl may need to read /etc/master.passwd). + case $host in + *-*-freebsd*) + SETUIDFLAGS="-m 4755 -o root" + ;; + *) + ;; + esac + + AC_SUBST(PASSWDLIBS) +]) + +AC_DEFUN([KDE_CHECK_LIBDL], +[ +AC_CHECK_LIB(dl, dlopen, [ +LIBDL="-ldl" +ac_cv_have_dlfcn=yes +]) + +AC_CHECK_LIB(dld, shl_unload, [ +LIBDL="-ldld" +ac_cv_have_shload=yes +]) + +AC_SUBST(LIBDL) +]) + +AC_DEFUN([KDE_CHECK_DLOPEN], +[ +KDE_CHECK_LIBDL +AC_CHECK_HEADERS(dlfcn.h dl.h) +if test "$ac_cv_header_dlfcn_h" = "no"; then + ac_cv_have_dlfcn=no +fi + +if test "$ac_cv_header_dl_h" = "no"; then + ac_cv_have_shload=no +fi + +dnl XXX why change enable_dlopen? its already set by autoconf's AC_ARG_ENABLE +dnl (MM) +AC_ARG_ENABLE(dlopen, +AC_HELP_STRING([--disable-dlopen],[link statically [default=no]]), +enable_dlopen=$enableval, +enable_dlopen=yes) + +# override the user's opinion, if we know it better ;) +if test "$ac_cv_have_dlfcn" = "no" && test "$ac_cv_have_shload" = "no"; then + enable_dlopen=no +fi + +if test "$ac_cv_have_dlfcn" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_DLFCN, 1, [Define if you have dlfcn]) +fi + +if test "$ac_cv_have_shload" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_SHLOAD, 1, [Define if you have shload]) +fi + +if test "$enable_dlopen" = no ; then + test -n "$1" && eval $1 +else + test -n "$2" && eval $2 +fi + +]) + +AC_DEFUN([KDE_CHECK_DYNAMIC_LOADING], +[ +KDE_CHECK_DLOPEN(libtool_enable_shared=yes, libtool_enable_static=no) +KDE_PROG_LIBTOOL +AC_MSG_CHECKING([dynamic loading]) +eval "`egrep '^build_libtool_libs=' libtool`" +if test "$build_libtool_libs" = "yes" && test "$enable_dlopen" = "yes"; then + dynamic_loading=yes + AC_DEFINE_UNQUOTED(HAVE_DYNAMIC_LOADING) +else + dynamic_loading=no +fi +AC_MSG_RESULT($dynamic_loading) +if test "$dynamic_loading" = "yes"; then + $1 +else + $2 +fi +]) + +AC_DEFUN([KDE_ADD_INCLUDES], +[ +if test -z "$1"; then + test_include="Pix.h" +else + test_include="$1" +fi + +AC_MSG_CHECKING([for libg++ ($test_include)]) + +AC_CACHE_VAL(kde_cv_libgpp_includes, +[ +kde_cv_libgpp_includes=no + + for ac_dir in \ + \ + /usr/include/g++ \ + /usr/include \ + /usr/unsupported/include \ + /opt/include \ + $extra_include \ + ; \ + do + if test -r "$ac_dir/$test_include"; then + kde_cv_libgpp_includes=$ac_dir + break + fi + done +]) + +AC_MSG_RESULT($kde_cv_libgpp_includes) +if test "$kde_cv_libgpp_includes" != "no"; then + all_includes="-I$kde_cv_libgpp_includes $all_includes $USER_INCLUDES" +fi +]) +]) + +AC_DEFUN([KDE_CHECK_LIBPTHREAD], +[ + dnl This code is here specifically to handle the + dnl various flavors of threading library on FreeBSD + dnl 4-, 5-, and 6-, and the (weird) rules around it. + dnl There may be an environment PTHREAD_LIBS that + dnl specifies what to use; otherwise, search for it. + dnl -pthread is special cased and unsets LIBPTHREAD + dnl below if found. + LIBPTHREAD="" + + if test -n "$PTHREAD_LIBS"; then + if test "x$PTHREAD_LIBS" = "x-pthread" ; then + LIBPTHREAD="PTHREAD" + else + PTHREAD_LIBS_save="$PTHREAD_LIBS" + PTHREAD_LIBS=`echo "$PTHREAD_LIBS_save" | sed -e 's,^-l,,g'` + AC_MSG_CHECKING([for pthread_create in $PTHREAD_LIBS]) + KDE_CHECK_LIB($PTHREAD_LIBS, pthread_create, [ + LIBPTHREAD="$PTHREAD_LIBS_save"]) + PTHREAD_LIBS="$PTHREAD_LIBS_save" + fi + fi + + dnl Is this test really needed, in the face of the Tru64 test below? + if test -z "$LIBPTHREAD"; then + AC_CHECK_LIB(pthread, pthread_create, [LIBPTHREAD="-lpthread"]) + fi + + dnl This is a special Tru64 check, see BR 76171 issue #18. + if test -z "$LIBPTHREAD" ; then + AC_MSG_CHECKING([for pthread_create in -lpthread]) + kde_safe_libs=$LIBS + LIBS="$LIBS -lpthread" + AC_TRY_LINK([#include ],[(void)pthread_create(0,0,0,0);],[ + AC_MSG_RESULT(yes) + LIBPTHREAD="-lpthread"],[ + AC_MSG_RESULT(no)]) + LIBS=$kde_safe_libs + fi + + dnl Un-special-case for FreeBSD. + if test "x$LIBPTHREAD" = "xPTHREAD" ; then + LIBPTHREAD="" + fi + + AC_SUBST(LIBPTHREAD) +]) + +AC_DEFUN([KDE_CHECK_PTHREAD_OPTION], +[ + USE_THREADS="" + if test -z "$LIBPTHREAD"; then + KDE_CHECK_COMPILER_FLAG(pthread, [USE_THREADS="-D_THREAD_SAFE -pthread"]) + fi + + AH_VERBATIM(__svr_define, [ +#if defined(__SVR4) && !defined(__svr4__) +#define __svr4__ 1 +#endif +]) + case $host_os in + solaris*) + KDE_CHECK_COMPILER_FLAG(mt, [USE_THREADS="-mt"]) + CPPFLAGS="$CPPFLAGS -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -DUSE_SOLARIS -DSVR4" + ;; + freebsd*) + CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE $PTHREAD_CFLAGS" + ;; + aix*) + CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE" + LIBPTHREAD="$LIBPTHREAD -lc_r" + ;; + linux*) CPPFLAGS="$CPPFLAGS -D_REENTRANT" + if test "$CXX" = "KCC"; then + CXXFLAGS="$CXXFLAGS --thread_safe" + NOOPT_CXXFLAGS="$NOOPT_CXXFLAGS --thread_safe" + fi + ;; + *) + ;; + esac + AC_SUBST(USE_THREADS) + AC_SUBST(LIBPTHREAD) +]) + +AC_DEFUN([KDE_CHECK_THREADING], +[ + AC_REQUIRE([KDE_CHECK_LIBPTHREAD]) + AC_REQUIRE([KDE_CHECK_PTHREAD_OPTION]) + dnl default is yes if libpthread is found and no if no libpthread is available + if test -z "$LIBPTHREAD"; then + if test -z "$USE_THREADS"; then + kde_check_threading_default=no + else + kde_check_threading_default=yes + fi + else + kde_check_threading_default=yes + fi + AC_ARG_ENABLE(threading,AC_HELP_STRING([--disable-threading],[disables threading even if libpthread found]), + kde_use_threading=$enableval, kde_use_threading=$kde_check_threading_default) + if test "x$kde_use_threading" = "xyes"; then + AC_DEFINE(HAVE_LIBPTHREAD, 1, [Define if you have a working libpthread (will enable threaded code)]) + fi +]) + +AC_DEFUN([KDE_TRY_LINK_PYTHON], +[ +if test "$kde_python_link_found" = no; then + +if test "$1" = normal; then + AC_MSG_CHECKING(if a Python application links) +else + AC_MSG_CHECKING(if Python depends on $2) +fi + +AC_CACHE_VAL(kde_cv_try_link_python_$1, +[ +kde_save_cflags="$CFLAGS" +CFLAGS="$CFLAGS $PYTHONINC" +kde_save_libs="$LIBS" +LIBS="$LIBS $LIBPYTHON $2 $LIBDL $LIBSOCKET" +kde_save_ldflags="$LDFLAGS" +LDFLAGS="$LDFLAGS $PYTHONLIB" + +AC_TRY_LINK( +[ +#include +],[ + PySys_SetArgv(1, 0); +], + [kde_cv_try_link_python_$1=yes], + [kde_cv_try_link_python_$1=no] +) +CFLAGS="$kde_save_cflags" +LIBS="$kde_save_libs" +LDFLAGS="$kde_save_ldflags" +]) + +if test "$kde_cv_try_link_python_$1" = "yes"; then + AC_MSG_RESULT(yes) + kde_python_link_found=yes + if test ! "$1" = normal; then + LIBPYTHON="$LIBPYTHON $2" + fi + $3 +else + AC_MSG_RESULT(no) + $4 +fi + +fi + +]) + +AC_DEFUN([KDE_CHECK_PYTHON_DIR], +[ +AC_MSG_CHECKING([for Python directory]) + +AC_CACHE_VAL(kde_cv_pythondir, +[ + if test -z "$PYTHONDIR"; then + kde_cv_pythondir=/usr/local + else + kde_cv_pythondir="$PYTHONDIR" + fi +]) + +AC_ARG_WITH(pythondir, +AC_HELP_STRING([--with-pythondir=pythondir],[use python installed in pythondir]), +[ + ac_python_dir=$withval +], ac_python_dir=$kde_cv_pythondir +) + +AC_MSG_RESULT($ac_python_dir) +]) + +AC_DEFUN([KDE_CHECK_PYTHON_INTERN], +[ +AC_REQUIRE([KDE_CHECK_LIBDL]) +AC_REQUIRE([KDE_CHECK_LIBPTHREAD]) +AC_REQUIRE([KDE_CHECK_PYTHON_DIR]) + +if test -z "$1"; then + version="1.5" +else + version="$1" +fi + +AC_MSG_CHECKING([for Python$version]) + +python_incdirs="$ac_python_dir/include /usr/include /usr/local/include/ $kde_extra_includes" +AC_FIND_FILE(Python.h, $python_incdirs, python_incdir) +if test ! -r $python_incdir/Python.h; then + AC_FIND_FILE(python$version/Python.h, $python_incdirs, python_incdir) + python_incdir=$python_incdir/python$version + if test ! -r $python_incdir/Python.h; then + python_incdir=no + fi +fi + +PYTHONINC=-I$python_incdir + +python_libdirs="$ac_python_dir/lib$kdelibsuff /usr/lib$kdelibsuff /usr/local /usr/lib$kdelibsuff $kde_extra_libs" +AC_FIND_FILE(libpython$version.so, $python_libdirs, python_libdir) +if test ! -r $python_libdir/libpython$version.so; then + AC_FIND_FILE(libpython$version.a, $python_libdirs, python_libdir) + if test ! -r $python_libdir/libpython$version.a; then + AC_FIND_FILE(python$version/config/libpython$version.a, $python_libdirs, python_libdir) + python_libdir=$python_libdir/python$version/config + if test ! -r $python_libdir/libpython$version.a; then + python_libdir=no + fi + fi +fi + +PYTHONLIB=-L$python_libdir +kde_orig_LIBPYTHON=$LIBPYTHON +if test -z "$LIBPYTHON"; then + LIBPYTHON=-lpython$version +fi + +AC_FIND_FILE(python$version/copy.py, $python_libdirs, python_moddir) +python_moddir=$python_moddir/python$version +if test ! -r $python_moddir/copy.py; then + python_moddir=no +fi + +PYTHONMODDIR=$python_moddir + +AC_MSG_RESULT(header $python_incdir library $python_libdir modules $python_moddir) + +if test x$python_incdir = xno || test x$python_libdir = xno || test x$python_moddir = xno; then + LIBPYTHON=$kde_orig_LIBPYTHON + test "x$PYTHONLIB" = "x-Lno" && PYTHONLIB="" + test "x$PYTHONINC" = "x-Ino" && PYTHONINC="" + $2 +else + dnl Note: this test is very weak + kde_python_link_found=no + KDE_TRY_LINK_PYTHON(normal) + KDE_TRY_LINK_PYTHON(m, -lm) + KDE_TRY_LINK_PYTHON(pthread, $LIBPTHREAD) + KDE_TRY_LINK_PYTHON(tcl, -ltcl) + KDE_TRY_LINK_PYTHON(db2, -ldb2) + KDE_TRY_LINK_PYTHON(m_and_thread, [$LIBPTHREAD -lm]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_util, [$LIBPTHREAD -lm -lutil]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_db3, [$LIBPTHREAD -lm -ldb-3 -lutil]) + KDE_TRY_LINK_PYTHON(pthread_and_db3, [$LIBPTHREAD -ldb-3]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_db, [$LIBPTHREAD -lm -ldb -ltermcap -lutil]) + KDE_TRY_LINK_PYTHON(pthread_and_dl, [$LIBPTHREAD $LIBDL -lutil -lreadline -lncurses -lm]) + KDE_TRY_LINK_PYTHON(pthread_and_panel_curses, [$LIBPTHREAD $LIBDL -lm -lpanel -lcurses]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_db_special, [$LIBPTHREAD -lm -ldb -lutil], [], + [AC_MSG_WARN([it seems, Python depends on another library. + Please set LIBPYTHON to '-lpython$version -lotherlib' before calling configure to fix this + and contact the authors to let them know about this problem]) + ]) + + LIBPYTHON="$LIBPYTHON $LIBDL $LIBSOCKET" + AC_SUBST(PYTHONINC) + AC_SUBST(PYTHONLIB) + AC_SUBST(LIBPYTHON) + AC_SUBST(PYTHONMODDIR) + AC_DEFINE(HAVE_PYTHON, 1, [Define if you have the development files for python]) +fi + +]) + + +AC_DEFUN([KDE_CHECK_PYTHON], +[ + KDE_CHECK_PYTHON_INTERN("2.4", + [KDE_CHECK_PYTHON_INTERN("2.3", + [KDE_CHECK_PYTHON_INTERN("2.2", + [KDE_CHECK_PYTHON_INTERN("2.1", + [KDE_CHECK_PYTHON_INTERN("2.0", + [KDE_CHECK_PYTHON_INTERN($1, $2) ]) + ]) + ]) + ]) + ]) +]) + +AC_DEFUN([KDE_CHECK_STL], +[ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="`echo $CXXFLAGS | sed s/-fno-exceptions//`" + + AC_MSG_CHECKING([if C++ programs can be compiled]) + AC_CACHE_VAL(kde_cv_stl_works, + [ + AC_TRY_COMPILE([ +#include +using namespace std; +],[ + string astring="Hallo Welt."; + astring.erase(0, 6); // now astring is "Welt" + return 0; +], kde_cv_stl_works=yes, + kde_cv_stl_works=no) +]) + + AC_MSG_RESULT($kde_cv_stl_works) + + if test "$kde_cv_stl_works" = "yes"; then + # back compatible + AC_DEFINE_UNQUOTED(HAVE_SGI_STL, 1, [Define if you have a STL implementation by SGI]) + else + AC_MSG_ERROR([Your Installation isn't able to compile simple C++ programs. +Check config.log for details - if you're using a Linux distribution you might miss +a package named similar to libstdc++-dev.]) + fi + + CXXFLAGS="$ac_save_CXXFLAGS" + AC_LANG_RESTORE +]) + +AC_DEFUN([AC_FIND_QIMGIO], + [AC_REQUIRE([AC_FIND_JPEG]) +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_MSG_CHECKING([for qimgio]) +AC_CACHE_VAL(ac_cv_lib_qimgio, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +ac_save_LIBS="$LIBS" +ac_save_CXXFLAGS="$CXXFLAGS" +LIBS="$all_libraries -lqimgio -lpng -lz $LIBJPEG $LIBQT" +CXXFLAGS="$CXXFLAGS -I$qt_incdir $all_includes" +AC_TRY_RUN(dnl +[ +#include +#include +int main() { + QString t = "hallo"; + t.fill('t'); + qInitImageIO(); +} +], + ac_cv_lib_qimgio=yes, + ac_cv_lib_qimgio=no, + ac_cv_lib_qimgio=no) +LIBS="$ac_save_LIBS" +CXXFLAGS="$ac_save_CXXFLAGS" +AC_LANG_RESTORE +])dnl +if eval "test \"`echo $ac_cv_lib_qimgio`\" = yes"; then + LIBQIMGIO="-lqimgio -lpng -lz $LIBJPEG" + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_QIMGIO, 1, [Define if you have the Qt extension qimgio available]) + AC_SUBST(LIBQIMGIO) +else + AC_MSG_RESULT(not found) +fi +]) + +AC_DEFUN([AM_DISABLE_LIBRARIES], +[ + AC_PROVIDE([AM_ENABLE_STATIC]) + AC_PROVIDE([AM_ENABLE_SHARED]) + enable_static=no + enable_shared=yes +]) + + +AC_DEFUN([AC_CHECK_UTMP_FILE], +[ + AC_MSG_CHECKING([for utmp file]) + + AC_CACHE_VAL(kde_cv_utmp_file, + [ + kde_cv_utmp_file=no + + for ac_file in \ + \ + /var/run/utmp \ + /var/adm/utmp \ + /etc/utmp \ + ; \ + do + if test -r "$ac_file"; then + kde_cv_utmp_file=$ac_file + break + fi + done + ]) + + if test "$kde_cv_utmp_file" != "no"; then + AC_DEFINE_UNQUOTED(UTMP, "$kde_cv_utmp_file", [Define the file for utmp entries]) + $1 + AC_MSG_RESULT($kde_cv_utmp_file) + else + $2 + AC_MSG_RESULT([non found]) + fi +]) + + +AC_DEFUN([KDE_CREATE_SUBDIRSLIST], +[ + +DO_NOT_COMPILE="$DO_NOT_COMPILE CVS debian bsd-port admin" +TOPSUBDIRS="" + +if test ! -s $srcdir/subdirs; then + dnl Note: Makefile.common creates subdirs, so this is just a fallback + files=`cd $srcdir && ls -1` + dirs=`for i in $files; do if test -d $i; then echo $i; fi; done` + for i in $dirs; do + echo $i >> $srcdir/subdirs + done +fi + +ac_topsubdirs= +if test -s $srcdir/inst-apps; then + ac_topsubdirs="`cat $srcdir/inst-apps`" +elif test -s $srcdir/subdirs; then + ac_topsubdirs="`cat $srcdir/subdirs`" +fi + +for i in $ac_topsubdirs; do + AC_MSG_CHECKING([if $i should be compiled]) + if test -d $srcdir/$i; then + install_it="yes" + for j in $DO_NOT_COMPILE; do + if test $i = $j; then + install_it="no" + fi + done + else + install_it="no" + fi + AC_MSG_RESULT($install_it) + vari=`echo $i | sed -e 's,[[-+.@]],_,g'` + if test $install_it = "yes"; then + TOPSUBDIRS="$TOPSUBDIRS $i" + eval "$vari""_SUBDIR_included=yes" + else + eval "$vari""_SUBDIR_included=no" + fi +done + +AC_SUBST(TOPSUBDIRS) +]) + +AC_DEFUN([KDE_CHECK_NAMESPACES], +[ +AC_MSG_CHECKING(whether C++ compiler supports namespaces) +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +AC_TRY_COMPILE([ +], +[ +namespace Foo { + extern int i; + namespace Bar { + extern int i; + } +} + +int Foo::i = 0; +int Foo::Bar::i = 1; +],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_NAMESPACES) +], [ +AC_MSG_RESULT(no) +]) +AC_LANG_RESTORE +]) + +dnl ------------------------------------------------------------------------ +dnl Check for S_ISSOCK macro. Doesn't exist on Unix SCO. faure@kde.org +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_CHECK_S_ISSOCK], +[ +AC_MSG_CHECKING(for S_ISSOCK) +AC_CACHE_VAL(ac_cv_have_s_issock, +[ +AC_TRY_LINK( +[ +#include +], +[ +struct stat buff; +int b = S_ISSOCK( buff.st_mode ); +], +ac_cv_have_s_issock=yes, +ac_cv_have_s_issock=no) +]) +AC_MSG_RESULT($ac_cv_have_s_issock) +if test "$ac_cv_have_s_issock" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_S_ISSOCK, 1, [Define if sys/stat.h declares S_ISSOCK.]) +fi + +AH_VERBATIM(_ISSOCK, +[ +#ifndef HAVE_S_ISSOCK +#define HAVE_S_ISSOCK +#define S_ISSOCK(mode) (1==0) +#endif +]) + +]) + +dnl ------------------------------------------------------------------------ +dnl Check for MAXPATHLEN macro, defines KDEMAXPATHLEN. faure@kde.org +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_CHECK_KDEMAXPATHLEN], +[ +AC_MSG_CHECKING(for MAXPATHLEN) +AC_CACHE_VAL(ac_cv_maxpathlen, +[ +cat > conftest.$ac_ext < +#endif +#include +#include +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +KDE_HELLO MAXPATHLEN + +EOF + +ac_try="$ac_cpp conftest.$ac_ext 2>/dev/null | grep '^KDE_HELLO' >conftest.out" + +if AC_TRY_EVAL(ac_try) && test -s conftest.out; then + ac_cv_maxpathlen=`sed 's#KDE_HELLO ##' conftest.out` +else + ac_cv_maxpathlen=1024 +fi + +rm conftest.* + +]) +AC_MSG_RESULT($ac_cv_maxpathlen) +AC_DEFINE_UNQUOTED(KDEMAXPATHLEN,$ac_cv_maxpathlen, [Define a safe value for MAXPATHLEN] ) +]) + +AC_DEFUN([KDE_CHECK_HEADER], +[ + kde_safe_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $all_includes" + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_CHECK_HEADER([$1], [$2], [$3], [$4]) + AC_LANG_RESTORE + CPPFLAGS=$kde_safe_cppflags +]) + +AC_DEFUN([KDE_CHECK_HEADERS], +[ + AH_CHECK_HEADERS([$1]) + AC_LANG_SAVE + kde_safe_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $all_includes" + AC_LANG_CPLUSPLUS + AC_CHECK_HEADERS([$1], [$2], [$3], [$4]) + CPPFLAGS=$kde_safe_cppflags + AC_LANG_RESTORE +]) + +AC_DEFUN([KDE_FAST_CONFIGURE], +[ + dnl makes configure fast (needs perl) + AC_ARG_ENABLE(fast-perl, AC_HELP_STRING([--disable-fast-perl],[disable fast Makefile generation (needs perl)]), + with_fast_perl=$enableval, with_fast_perl=yes) +]) + +AC_DEFUN([KDE_CONF_FILES], +[ + val= + if test -f $srcdir/configure.files ; then + val=`sed -e 's%^%\$(top_srcdir)/%' $srcdir/configure.files` + fi + CONF_FILES= + if test -n "$val" ; then + for i in $val ; do + CONF_FILES="$CONF_FILES $i" + done + fi + AC_SUBST(CONF_FILES) +])dnl + +dnl This sets the prefix, for arts and kdelibs +dnl Do NOT use in any other module. +dnl It only looks at --prefix, KDEDIR and falls back to /usr/local/kde +AC_DEFUN([KDE_SET_PREFIX_CORE], +[ + unset CDPATH + dnl make $KDEDIR the default for the installation + AC_PREFIX_DEFAULT(${KDEDIR:-/usr/local/kde}) + + if test "x$prefix" = "xNONE"; then + prefix=$ac_default_prefix + ac_configure_args="$ac_configure_args --prefix=$prefix" + fi + # And delete superfluous '/' to make compares easier + prefix=`echo "$prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + exec_prefix=`echo "$exec_prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + + kde_libs_prefix='$(prefix)' + kde_libs_htmldir='$(kde_htmldir)' + AC_SUBST(kde_libs_prefix) + AC_SUBST(kde_libs_htmldir) + KDE_FAST_CONFIGURE + KDE_CONF_FILES +]) + + +AC_DEFUN([KDE_SET_PREFIX], +[ + unset CDPATH + dnl We can't give real code to that macro, only a value. + dnl It only matters for --help, since we set the prefix in this function anyway. + AC_PREFIX_DEFAULT(${KDEDIR:-the kde prefix}) + + KDE_SET_DEFAULT_BINDIRS + if test "x$prefix" = "xNONE"; then + dnl no prefix given: look for kde-config in the PATH and deduce the prefix from it + KDE_FIND_PATH(kde-config, KDECONFIG, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(kde-config)], [], prepend) + else + dnl prefix given: look for kde-config, preferrably in prefix, otherwise in PATH + kde_save_PATH="$PATH" + PATH="$exec_prefix/bin:$prefix/bin:$PATH" + KDE_FIND_PATH(kde-config, KDECONFIG, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(kde-config)], [], prepend) + PATH="$kde_save_PATH" + fi + + kde_libs_prefix=`$KDECONFIG --prefix` + if test -z "$kde_libs_prefix" || test ! -x "$kde_libs_prefix"; then + AC_MSG_ERROR([$KDECONFIG --prefix outputed the non existant prefix '$kde_libs_prefix' for kdelibs. + This means it has been moved since you installed it. + This won't work. Please recompile kdelibs for the new prefix. + ]) + fi + kde_libs_htmldir=`$KDECONFIG --install html --expandvars` + kde_libs_suffix=`$KDECONFIG --libsuffix` + + AC_MSG_CHECKING([where to install]) + if test "x$prefix" = "xNONE"; then + prefix=$kde_libs_prefix + AC_MSG_RESULT([$prefix (as returned by kde-config)]) + else + dnl --prefix was given. Compare prefixes and warn (in configure.in.bot.end) if different + given_prefix=$prefix + AC_MSG_RESULT([$prefix (as requested)]) + fi + + # And delete superfluous '/' to make compares easier + prefix=`echo "$prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + exec_prefix=`echo "$exec_prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + given_prefix=`echo "$given_prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + + AC_SUBST(KDECONFIG) + AC_SUBST(kde_libs_prefix) + AC_SUBST(kde_libs_htmldir) + + KDE_FAST_CONFIGURE + KDE_CONF_FILES +]) + +pushdef([AC_PROG_INSTALL], +[ + dnl our own version, testing for a -p flag + popdef([AC_PROG_INSTALL]) + dnl as AC_PROG_INSTALL works as it works we first have + dnl to save if the user didn't specify INSTALL, as the + dnl autoconf one overwrites INSTALL and we have no chance to find + dnl out afterwards + test -n "$INSTALL" && kde_save_INSTALL_given=$INSTALL + test -n "$INSTALL_PROGRAM" && kde_save_INSTALL_PROGRAM_given=$INSTALL_PROGRAM + test -n "$INSTALL_SCRIPT" && kde_save_INSTALL_SCRIPT_given=$INSTALL_SCRIPT + AC_PROG_INSTALL + + if test -z "$kde_save_INSTALL_given" ; then + # OK, user hasn't given any INSTALL, autoconf found one for us + # now we test, if it supports the -p flag + AC_MSG_CHECKING(for -p flag to install) + rm -f confinst.$$.* > /dev/null 2>&1 + echo "Testtest" > confinst.$$.orig + ac_res=no + if ${INSTALL} -p confinst.$$.orig confinst.$$.new > /dev/null 2>&1 ; then + if test -f confinst.$$.new ; then + # OK, -p seems to do no harm to install + INSTALL="${INSTALL} -p" + ac_res=yes + fi + fi + rm -f confinst.$$.* + AC_MSG_RESULT($ac_res) + fi + dnl the following tries to resolve some signs and wonders coming up + dnl with different autoconf/automake versions + dnl e.g.: + dnl *automake 1.4 install-strip sets A_M_INSTALL_PROGRAM_FLAGS to -s + dnl and has INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(A_M_INSTALL_PROGRAM_FLAGS) + dnl it header-vars.am, so there the actual INSTALL_PROGRAM gets the -s + dnl *automake 1.4a (and above) use INSTALL_STRIP_FLAG and only has + dnl INSTALL_PROGRAM = @INSTALL_PROGRAM@ there, but changes the + dnl install-@DIR@PROGRAMS targets to explicitly use that flag + dnl *autoconf 2.13 is dumb, and thinks it can use INSTALL_PROGRAM as + dnl INSTALL_SCRIPT, which breaks with automake <= 1.4 + dnl *autoconf >2.13 (since 10.Apr 1999) has not that failure + dnl *sometimes KDE does not use the install-@DIR@PROGRAM targets from + dnl automake (due to broken Makefile.am or whatever) to install programs, + dnl and so does not see the -s flag in automake > 1.4 + dnl to clean up that mess we: + dnl +set INSTALL_PROGRAM to use INSTALL_STRIP_FLAG + dnl which cleans KDE's program with automake > 1.4; + dnl +set INSTALL_SCRIPT to only use INSTALL, to clean up autoconf's problems + dnl with automake<=1.4 + dnl note that dues to this sometimes two '-s' flags are used (if KDE + dnl properly uses install-@DIR@PROGRAMS, but I don't care + dnl + dnl And to all this comes, that I even can't write in comments variable + dnl names used by automake, because it is so stupid to think I wanted to + dnl _use_ them, therefor I have written A_M_... instead of AM_ + dnl hmm, I wanted to say something ... ahh yes: Arghhh. + + if test -z "$kde_save_INSTALL_PROGRAM_given" ; then + INSTALL_PROGRAM='${INSTALL} $(INSTALL_STRIP_FLAG)' + fi + if test -z "$kde_save_INSTALL_SCRIPT_given" ; then + INSTALL_SCRIPT='${INSTALL}' + fi +])dnl + +AC_DEFUN([KDE_LANG_CPLUSPLUS], +[AC_LANG_CPLUSPLUS +ac_link='rm -rf SunWS_cache; ${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&AC_FD_CC' +pushdef([AC_LANG_CPLUSPLUS], [popdef([AC_LANG_CPLUSPLUS]) KDE_LANG_CPLUSPLUS]) +]) + +pushdef([AC_LANG_CPLUSPLUS], +[popdef([AC_LANG_CPLUSPLUS]) +KDE_LANG_CPLUSPLUS +]) + +AC_DEFUN([KDE_CHECK_LONG_LONG], +[ +AC_MSG_CHECKING(for long long) +AC_CACHE_VAL(kde_cv_c_long_long, +[ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_LINK([], [ + long long foo = 0; + foo = foo+1; + ], + kde_cv_c_long_long=yes, kde_cv_c_long_long=no) + AC_LANG_RESTORE +]) +AC_MSG_RESULT($kde_cv_c_long_long) +if test "$kde_cv_c_long_long" = yes; then + AC_DEFINE(HAVE_LONG_LONG, 1, [Define if you have long long as datatype]) +fi +]) + +AC_DEFUN([KDE_CHECK_LIB], +[ + kde_save_LDFLAGS="$LDFLAGS" + dnl AC_CHECK_LIB modifies LIBS, so save it here + kde_save_LIBS="$LIBS" + LDFLAGS="$LDFLAGS $all_libraries" + case $host_os in + aix*) LDFLAGS="-brtl $LDFLAGS" + test "$GCC" = yes && LDFLAGS="-Wl,$LDFLAGS" + ;; + esac + AC_CHECK_LIB($1, $2, $3, $4, $5) + LDFLAGS="$kde_save_LDFLAGS" + LIBS="$kde_save_LIBS" +]) + +AC_DEFUN([KDE_JAVA_PREFIX], +[ + dir=`dirname "$1"` + base=`basename "$1"` + list=`ls -1 $dir 2> /dev/null` + for entry in $list; do + if test -d $dir/$entry/bin; then + case $entry in + $base) + javadirs="$javadirs $dir/$entry/bin" + ;; + esac + elif test -d $dir/$entry/jre/bin; then + case $entry in + $base) + javadirs="$javadirs $dir/$entry/jre/bin" + ;; + esac + fi + done +]) + +dnl KDE_CHEC_JAVA_DIR(onlyjre) +AC_DEFUN([KDE_CHECK_JAVA_DIR], +[ + +AC_ARG_WITH(java, +AC_HELP_STRING([--with-java=javadir],[use java installed in javadir, --without-java disables]), +[ ac_java_dir=$withval +], ac_java_dir="" +) + +AC_MSG_CHECKING([for Java]) + +dnl at this point ac_java_dir is either a dir, 'no' to disable, or '' to say look in $PATH +if test "x$ac_java_dir" = "xno"; then + kde_java_bindir=no + kde_java_includedir=no + kde_java_libjvmdir=no + kde_java_libgcjdir=no + kde_java_libhpidir=no +else + if test "x$ac_java_dir" = "x"; then + + + dnl No option set -> collect list of candidate paths + if test -n "$JAVA_HOME"; then + KDE_JAVA_PREFIX($JAVA_HOME) + fi + KDE_JAVA_PREFIX(/usr/j2se) + KDE_JAVA_PREFIX(/usr/lib/j2se) + KDE_JAVA_PREFIX(/usr/j*dk*) + KDE_JAVA_PREFIX(/usr/lib/j*dk*) + KDE_JAVA_PREFIX(/opt/j*sdk*) + KDE_JAVA_PREFIX(/usr/lib/java*) + KDE_JAVA_PREFIX(/usr/java*) + KDE_JAVA_PREFIX(/usr/java/j*dk*) + KDE_JAVA_PREFIX(/usr/java/j*re*) + KDE_JAVA_PREFIX(/usr/lib/SunJava2*) + KDE_JAVA_PREFIX(/usr/lib/SunJava*) + KDE_JAVA_PREFIX(/usr/lib/IBMJava2*) + KDE_JAVA_PREFIX(/usr/lib/IBMJava*) + KDE_JAVA_PREFIX(/opt/java*) + + kde_cv_path="NONE" + kde_save_IFS=$IFS + IFS=':' + for dir in $PATH; do + if test -d "$dir"; then + javadirs="$javadirs $dir" + fi + done + IFS=$kde_save_IFS + jredirs= + + dnl Now javadirs contains a list of paths that exist, all ending with bin/ + for dir in $javadirs; do + dnl Check for the java executable + if test -x "$dir/java"; then + dnl And also check for a libjvm.so somewhere under there + dnl Since we have to go to the parent dir, /usr/bin is excluded, /usr is too big. + if test "$dir" != "/usr/bin"; then + libjvmdir=`find $dir/.. -name libjvm.so | sed 's,libjvm.so,,'|head -n 1` + if test ! -f $libjvmdir/libjvm.so; then continue; fi + jredirs="$jredirs $dir" + fi + fi + done + + dnl Now jredirs contains a reduced list, of paths where both java and ../**/libjvm.so was found + JAVAC= + JAVA= + kde_java_bindir=no + for dir in $jredirs; do + JAVA="$dir/java" + kde_java_bindir=$dir + if test -x "$dir/javac"; then + JAVAC="$dir/javac" + break + fi + done + + if test -n "$JAVAC"; then + dnl this substitution might not work - well, we test for jni.h below + kde_java_includedir=`echo $JAVAC | sed -e 's,bin/javac$,include/,'` + else + kde_java_includedir=no + fi + else + dnl config option set + kde_java_bindir=$ac_java_dir/bin + if test -x $ac_java_dir/bin/java && test ! -x $ac_java_dir/bin/javac; then + kde_java_includedir=no + else + kde_java_includedir=$ac_java_dir/include + fi + fi +fi + +dnl At this point kde_java_bindir and kde_java_includedir are either set or "no" +if test "x$kde_java_bindir" != "xno"; then + + dnl Look for libjvm.so + kde_java_libjvmdir=`find $kde_java_bindir/.. -name libjvm.so | sed 's,libjvm.so,,'|head -n 1` + dnl Look for libgcj.so + kde_java_libgcjdir=`find $kde_java_bindir/.. -name libgcj.so | sed 's,libgcj.so,,'|head -n 1` + dnl Look for libhpi.so and avoid green threads + kde_java_libhpidir=`find $kde_java_bindir/.. -name libhpi.so | grep -v green | sed 's,libhpi.so,,' | head -n 1` + + dnl Now check everything's fine under there + dnl the include dir is our flag for having the JDK + if test -d "$kde_java_includedir"; then + if test ! -x "$kde_java_bindir/javac"; then + AC_MSG_ERROR([javac not found under $kde_java_bindir - it seems you passed a wrong --with-java.]) + fi + if test ! -x "$kde_java_bindir/javah"; then + AC_MSG_ERROR([javah not found under $kde_java_bindir. javac was found though! Use --with-java or --without-java.]) + fi + if test ! -x "$kde_java_bindir/jar"; then + AC_MSG_ERROR([jar not found under $kde_java_bindir. javac was found though! Use --with-java or --without-java.]) + fi + if test ! -r "$kde_java_includedir/jni.h"; then + AC_MSG_ERROR([jni.h not found under $kde_java_includedir. Use --with-java or --without-java.]) + fi + + jni_includes="-I$kde_java_includedir" + dnl Strange thing, jni.h requires jni_md.h which is under genunix here.. + dnl and under linux here.. + + dnl not needed for gcj + + if test "x$kde_java_libgcjdir" = "x"; then + test -d "$kde_java_includedir/linux" && jni_includes="$jni_includes -I$kde_java_includedir/linux" + test -d "$kde_java_includedir/solaris" && jni_includes="$jni_includes -I$kde_java_includedir/solaris" + test -d "$kde_java_includedir/genunix" && jni_includes="$jni_includes -I$kde_java_includedir/genunix" + fi + + else + JAVAC= + jni_includes= + fi + + if test "x$kde_java_libgcjdir" = "x"; then + if test ! -r "$kde_java_libjvmdir/libjvm.so"; then + AC_MSG_ERROR([libjvm.so not found under $kde_java_libjvmdir. Use --without-java.]) + fi + else + if test ! -r "$kde_java_libgcjdir/libgcj.so"; then + AC_MSG_ERROR([libgcj.so not found under $kde_java_libgcjdir. Use --without-java.]) + fi + fi + + if test ! -x "$kde_java_bindir/java"; then + AC_MSG_ERROR([java not found under $kde_java_bindir. javac was found though! Use --with-java or --without-java.]) + fi + + dnl not needed for gcj compile + + if test "x$kde_java_libgcjdir" = "x"; then + if test ! -r "$kde_java_libhpidir/libhpi.so"; then + AC_MSG_ERROR([libhpi.so not found under $kde_java_libhpidir. Use --without-java.]) + fi + fi + + if test -n "$jni_includes"; then + dnl Check for JNI version + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_cxxflags_safe="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $all_includes $jni_includes" + + AC_TRY_COMPILE([ + #include + ], + [ + #ifndef JNI_VERSION_1_2 + Syntax Error + #endif + ],[ kde_jni_works=yes ], + [ kde_jni_works=no ]) + + if test $kde_jni_works = no; then + AC_MSG_ERROR([Incorrect version of $kde_java_includedir/jni.h. + You need to have Java Development Kit (JDK) version 1.2. + + Use --with-java to specify another location. + Use --without-java to configure without java support. + Or download a newer JDK and try again. + See e.g. http://java.sun.com/products/jdk/1.2 ]) + fi + + CXXFLAGS="$ac_cxxflags_safe" + AC_LANG_RESTORE + + dnl All tests ok, inform and subst the variables + + JAVAC=$kde_java_bindir/javac + JAVAH=$kde_java_bindir/javah + JAR=$kde_java_bindir/jar + AC_DEFINE_UNQUOTED(PATH_JAVA, "$kde_java_bindir/java", [Define where your java executable is]) + if test "x$kde_java_libgcjdir" = "x"; then + JVMLIBS="-L$kde_java_libjvmdir -ljvm -L$kde_java_libhpidir -lhpi" + else + JVMLIBS="-L$kde_java_libgcjdir -lgcj" + fi + AC_MSG_RESULT([java JDK in $kde_java_bindir]) + + else + AC_DEFINE_UNQUOTED(PATH_JAVA, "$kde_java_bindir/java", [Define where your java executable is]) + AC_MSG_RESULT([java JRE in $kde_java_bindir]) + fi +elif test -d "/Library/Java/Home"; then + kde_java_bindir="/Library/Java/Home/bin" + jni_includes="-I/Library/Java/Home/include" + + JAVAC=$kde_java_bindir/javac + JAVAH=$kde_java_bindir/javah + JAR=$kde_java_bindir/jar + JVMLIBS="-Xlinker -framework -Xlinker JavaVM" + + AC_DEFINE_UNQUOTED(PATH_JAVA, "$kde_java_bindir/java", [Define where your java executable is]) + AC_MSG_RESULT([Apple Java Framework]) +else + AC_MSG_RESULT([none found]) +fi + +AC_SUBST(JAVAC) +AC_SUBST(JAVAH) +AC_SUBST(JAR) +AC_SUBST(JVMLIBS) +AC_SUBST(jni_includes) + +# for backward compat +kde_cv_java_includedir=$kde_java_includedir +kde_cv_java_bindir=$kde_java_bindir +]) + +dnl this is a redefinition of autoconf 2.5x's AC_FOREACH. +dnl When the argument list becomes big, as in KDE for AC_OUTPUT in +dnl big packages, m4_foreach is dog-slow. So use our own version of +dnl it. (matz@kde.org) +m4_define([mm_foreach], +[m4_pushdef([$1])_mm_foreach($@)m4_popdef([$1])]) +m4_define([mm_car], [[$1]]) +m4_define([mm_car2], [[$@]]) +m4_define([_mm_foreach], +[m4_if(m4_quote($2), [], [], + [m4_define([$1], mm_car($2))$3[]_mm_foreach([$1], + mm_car2(m4_shift($2)), + [$3])])]) +m4_define([AC_FOREACH], +[mm_foreach([$1], m4_split(m4_normalize([$2])), [$3])]) + +AC_DEFUN([KDE_NEED_FLEX], +[ +kde_libs_safe=$LIBS +LIBS="$LIBS $USER_LDFLAGS" +AM_PROG_LEX +LIBS=$kde_libs_safe +if test -z "$LEXLIB"; then + AC_MSG_ERROR([You need to have flex installed.]) +fi +AC_SUBST(LEXLIB) +]) + +AC_DEFUN([AC_PATH_QTOPIA], +[ + dnl TODO: use AC_CACHE_VAL + + if test -z "$1"; then + qtopia_minver_maj=1 + qtopia_minver_min=5 + qtopia_minver_pat=0 + else + qtopia_minver_maj=`echo "$1" | sed -e "s/^\(.*\)\..*\..*$/\1/"` + qtopia_minver_min=`echo "$1" | sed -e "s/^.*\.\(.*\)\..*$/\1/"` + qtopia_minver_pat=`echo "$1" | sed -e "s/^.*\..*\.\(.*\)$/\1/"` + fi + + qtopia_minver="$qtopia_minver_maj$qtopia_minver_min$qtopia_minver_pat" + qtopia_minverstr="$qtopia_minver_maj.$qtopia_minver_min.$qtopia_minver_pat" + + AC_REQUIRE([AC_PATH_QT]) + + AC_MSG_CHECKING([for Qtopia]) + + LIB_QTOPIA="-lqpe" + AC_SUBST(LIB_QTOPIA) + + kde_qtopia_dirs="$QPEDIR /opt/Qtopia" + + ac_qtopia_incdir=NO + + AC_ARG_WITH(qtopia-dir, + AC_HELP_STRING([--with-qtopia-dir=DIR],[where the root of Qtopia is installed]), + [ ac_qtopia_incdir="$withval"/include] ) + + qtopia_incdirs="" + for dir in $kde_qtopia_dirs; do + qtopia_incdirs="$qtopia_incdirs $dir/include" + done + + if test ! "$ac_qtopia_incdir" = "NO"; then + qtopia_incdirs="$ac_qtopia_incdir $qtopia_incdirs" + fi + + qtopia_incdir="" + AC_FIND_FILE(qpe/qpeapplication.h, $qtopia_incdirs, qtopia_incdir) + ac_qtopia_incdir="$qtopia_incdir" + + if test -z "$qtopia_incdir"; then + AC_MSG_ERROR([Cannot find Qtopia headers. Please check your installation.]) + fi + + qtopia_ver_maj=`cat $qtopia_incdir/qpe/version.h | sed -n -e 's,.*QPE_VERSION "\(.*\)\..*\..*".*,\1,p'`; + qtopia_ver_min=`cat $qtopia_incdir/qpe/version.h | sed -n -e 's,.*QPE_VERSION ".*\.\(.*\)\..*".*,\1,p'`; + qtopia_ver_pat=`cat $qtopia_incdir/qpe/version.h | sed -n -e 's,.*QPE_VERSION ".*\..*\.\(.*\)".*,\1,p'`; + + qtopia_ver="$qtopia_ver_maj$qtopia_ver_min$qtopia_ver_pat" + qtopia_verstr="$qtopia_ver_maj.$qtopia_ver_min.$qtopia_ver_pat" + if test "$qtopia_ver" -lt "$qtopia_minver"; then + AC_MSG_ERROR([found Qtopia version $qtopia_verstr but version $qtopia_minverstr +is required.]) + fi + + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + + ac_cxxflags_safe="$CXXFLAGS" + ac_ldflags_safe="$LDFLAGS" + ac_libs_safe="$LIBS" + + CXXFLAGS="$CXXFLAGS -I$qtopia_incdir $all_includes" + LDFLAGS="$LDFLAGS $QT_LDFLAGS $all_libraries $USER_LDFLAGS $KDE_MT_LDFLAGS" + LIBS="$LIBS $LIB_QTOPIA $LIBQT" + + cat > conftest.$ac_ext < +#include + +int main( int argc, char **argv ) +{ + QPEApplication app( argc, argv ); + return 0; +} +EOF + + if AC_TRY_EVAL(ac_link) && test -s conftest; then + rm -f conftest* + else + rm -f conftest* + AC_MSG_ERROR([Cannot link small Qtopia Application. For more details look at +the end of config.log]) + fi + + CXXFLAGS="$ac_cxxflags_safe" + LDFLAGS="$ac_ldflags_safe" + LIBS="$ac_libs_safe" + + AC_LANG_RESTORE + + QTOPIA_INCLUDES="-I$qtopia_incdir" + AC_SUBST(QTOPIA_INCLUDES) + + AC_MSG_RESULT([found version $qtopia_verstr with headers at $qtopia_incdir]) +]) + + +AC_DEFUN([KDE_INIT_DOXYGEN], +[ +AC_MSG_CHECKING([for Qt docs]) +kde_qtdir= +if test "${with_qt_dir+set}" = set; then + kde_qtdir="$with_qt_dir" +fi + +AC_FIND_FILE(qsql.html, [ $kde_qtdir/doc/html $QTDIR/doc/html /usr/share/doc/packages/qt3/html /usr/lib/qt/doc /usr/lib/qt3/doc /usr/lib/qt3/doc/html /usr/doc/qt3/html /usr/doc/qt3 /usr/share/doc/qt3-doc /usr/share/qt3/doc/html /usr/X11R6/share/doc/qt/html ], QTDOCDIR) +AC_MSG_RESULT($QTDOCDIR) + +AC_SUBST(QTDOCDIR) + +KDE_FIND_PATH(dot, DOT, [], []) +if test -n "$DOT"; then + KDE_HAVE_DOT="YES" +else + KDE_HAVE_DOT="NO" +fi +AC_SUBST(KDE_HAVE_DOT) +KDE_FIND_PATH(doxygen, DOXYGEN, [], []) +AC_SUBST(DOXYGEN) + +DOXYGEN_PROJECT_NAME="$1" +DOXYGEN_PROJECT_NUMBER="$2" +AC_SUBST(DOXYGEN_PROJECT_NAME) +AC_SUBST(DOXYGEN_PROJECT_NUMBER) + +KDE_HAS_DOXYGEN=no +if test -n "$DOXYGEN" && test -x "$DOXYGEN" && test -f $QTDOCDIR/qsql.html; then + KDE_HAS_DOXYGEN=yes +fi +AC_SUBST(KDE_HAS_DOXYGEN) + +]) + + +AC_DEFUN([AC_FIND_BZIP2], +[ +AC_MSG_CHECKING([for bzDecompress in libbz2]) +AC_CACHE_VAL(ac_cv_lib_bzip2, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +kde_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS -lbz2 $LIBSOCKET" +kde_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK(dnl +[ +#define BZ_NO_STDIO +#include +], + [ bz_stream s; (void) bzDecompress(&s); ], + eval "ac_cv_lib_bzip2='-lbz2'", + eval "ac_cv_lib_bzip2=no") +LIBS="$kde_save_LIBS" +CXXFLAGS="$kde_save_CXXFLAGS" +AC_LANG_RESTORE +])dnl +AC_MSG_RESULT($ac_cv_lib_bzip2) + +if test ! "$ac_cv_lib_bzip2" = no; then + BZIP2DIR=bzip2 + + LIBBZ2="$ac_cv_lib_bzip2" + AC_SUBST(LIBBZ2) + +else + + cxx_shared_flag= + ld_shared_flag= + KDE_CHECK_COMPILER_FLAG(shared, [ + ld_shared_flag="-shared" + ]) + KDE_CHECK_COMPILER_FLAG(fPIC, [ + cxx_shared_flag="-fPIC" + ]) + + AC_MSG_CHECKING([for BZ2_bzDecompress in (shared) libbz2]) + AC_CACHE_VAL(ac_cv_lib_bzip2_prefix, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + kde_save_LIBS="$LIBS" + LIBS="$all_libraries $USER_LDFLAGS $ld_shared_flag -lbz2 $LIBSOCKET" + kde_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CFLAGS $cxx_shared_flag $all_includes $USER_INCLUDES" + + AC_TRY_LINK(dnl + [ + #define BZ_NO_STDIO + #include + ], + [ bz_stream s; (void) BZ2_bzDecompress(&s); ], + eval "ac_cv_lib_bzip2_prefix='-lbz2'", + eval "ac_cv_lib_bzip2_prefix=no") + LIBS="$kde_save_LIBS" + CXXFLAGS="$kde_save_CXXFLAGS" + AC_LANG_RESTORE + ])dnl + + AC_MSG_RESULT($ac_cv_lib_bzip2_prefix) + + if test ! "$ac_cv_lib_bzip2_prefix" = no; then + BZIP2DIR=bzip2 + + LIBBZ2="$ac_cv_lib_bzip2_prefix" + AC_SUBST(LIBBZ2) + + AC_DEFINE(NEED_BZ2_PREFIX, 1, [Define if the libbz2 functions need the BZ2_ prefix]) + dnl else, we just ignore this + fi + +fi +AM_CONDITIONAL(include_BZIP2, test -n "$BZIP2DIR") +]) + +dnl ------------------------------------------------------------------------ +dnl Try to find the SSL headers and libraries. +dnl $(SSL_LDFLAGS) will be -Lsslliblocation (if needed) +dnl and $(SSL_INCLUDES) will be -Isslhdrlocation (if needed) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([KDE_CHECK_SSL], +[ +LIBSSL="-lssl -lcrypto" +AC_REQUIRE([KDE_CHECK_LIB64]) + +ac_ssl_includes=NO ac_ssl_libraries=NO +ssl_libraries="" +ssl_includes="" +AC_ARG_WITH(ssl-dir, + AC_HELP_STRING([--with-ssl-dir=DIR],[where the root of OpenSSL is installed]), + [ ac_ssl_includes="$withval"/include + ac_ssl_libraries="$withval"/lib$kdelibsuff + ]) + +want_ssl=yes +AC_ARG_WITH(ssl, + AC_HELP_STRING([--without-ssl],[disable SSL checks]), + [want_ssl=$withval]) + +if test $want_ssl = yes; then + +AC_MSG_CHECKING(for OpenSSL) + +AC_CACHE_VAL(ac_cv_have_ssl, +[#try to guess OpenSSL locations + + ssl_incdirs="/usr/include /usr/local/include /usr/ssl/include /usr/local/ssl/include $prefix/include $kde_extra_includes" + ssl_incdirs="$ac_ssl_includes $ssl_incdirs" + AC_FIND_FILE(openssl/ssl.h, $ssl_incdirs, ssl_incdir) + ac_ssl_includes="$ssl_incdir" + + ssl_libdirs="/usr/lib$kdelibsuff /usr/local/lib$kdelibsuff /usr/ssl/lib$kdelibsuff /usr/local/ssl/lib$kdelibsuff $libdir $prefix/lib$kdelibsuff $exec_prefix/lib$kdelibsuff $kde_extra_libs" + if test ! "$ac_ssl_libraries" = "NO"; then + ssl_libdirs="$ac_ssl_libraries $ssl_libdirs" + fi + + test=NONE + ssl_libdir=NONE + for dir in $ssl_libdirs; do + try="ls -1 $dir/libssl*" + if test=`eval $try 2> /dev/null`; then ssl_libdir=$dir; break; else echo "tried $dir" >&AC_FD_CC ; fi + done + + ac_ssl_libraries="$ssl_libdir" + + ac_ldflags_safe="$LDFLAGS" + ac_libs_safe="$LIBS" + + LDFLAGS="$LDFLAGS -L$ssl_libdir $all_libraries" + LIBS="$LIBS $LIBSSL -lRSAglue -lrsaref" + + AC_TRY_LINK(,void RSAPrivateEncrypt(void);RSAPrivateEncrypt();, + ac_ssl_rsaref="yes" + , + ac_ssl_rsaref="no" + ) + + LDFLAGS="$ac_ldflags_safe" + LIBS="$ac_libs_safe" + + if test "$ac_ssl_includes" = NO || test "$ac_ssl_libraries" = NO; then + have_ssl=no + else + have_ssl=yes; + fi + + ]) + + eval "$ac_cv_have_ssl" + + AC_MSG_RESULT([libraries $ac_ssl_libraries, headers $ac_ssl_includes]) + + AC_MSG_CHECKING([whether OpenSSL uses rsaref]) + AC_MSG_RESULT($ac_ssl_rsaref) + + AC_MSG_CHECKING([for easter eggs]) + AC_MSG_RESULT([none found]) + +else + have_ssl=no +fi + +if test "$have_ssl" = yes; then + AC_MSG_CHECKING(for OpenSSL version) + dnl Check for SSL version + AC_CACHE_VAL(ac_cv_ssl_version, + [ + + cat >conftest.$ac_ext < +#include + int main() { + +#ifndef OPENSSL_VERSION_NUMBER + printf("ssl_version=\\"error\\"\n"); +#else + if (OPENSSL_VERSION_NUMBER < 0x00906000) + printf("ssl_version=\\"old\\"\n"); + else + printf("ssl_version=\\"ok\\"\n"); +#endif + return (0); + } +EOF + + ac_save_CPPFLAGS=$CPPFLAGS + if test "$ac_ssl_includes" != "/usr/include"; then + CPPFLAGS="$CPPFLAGS -I$ac_ssl_includes" + fi + + if AC_TRY_EVAL(ac_link); then + + if eval `./conftest 2>&5`; then + if test $ssl_version = error; then + AC_MSG_ERROR([$ssl_incdir/openssl/opensslv.h doesn't define OPENSSL_VERSION_NUMBER !]) + else + if test $ssl_version = old; then + AC_MSG_WARN([OpenSSL version too old. Upgrade to 0.9.6 at least, see http://www.openssl.org. SSL support disabled.]) + have_ssl=no + fi + fi + ac_cv_ssl_version="ssl_version=$ssl_version" + else + AC_MSG_ERROR([Your system couldn't run a small SSL test program. + Check config.log, and if you can't figure it out, send a mail to + David Faure , attaching your config.log]) + fi + + else + AC_MSG_ERROR([Your system couldn't link a small SSL test program. + Check config.log, and if you can't figure it out, send a mail to + David Faure , attaching your config.log]) + fi + CPPFLAGS=$ac_save_CPPFLAGS + + ]) + + eval "$ac_cv_ssl_version" + AC_MSG_RESULT($ssl_version) +fi + +if test "$have_ssl" != yes; then + LIBSSL=""; +else + AC_DEFINE(HAVE_SSL, 1, [If we are going to use OpenSSL]) + ac_cv_have_ssl="have_ssl=yes \ + ac_ssl_includes=$ac_ssl_includes ac_ssl_libraries=$ac_ssl_libraries ac_ssl_rsaref=$ac_ssl_rsaref" + + + ssl_libraries="$ac_ssl_libraries" + ssl_includes="$ac_ssl_includes" + + if test "$ac_ssl_rsaref" = yes; then + LIBSSL="-lssl -lcrypto -lRSAglue -lrsaref" + fi + + if test $ssl_version = "old"; then + AC_DEFINE(HAVE_OLD_SSL_API, 1, [Define if you have OpenSSL < 0.9.6]) + fi +fi + +SSL_INCLUDES= + +if test "$ssl_includes" = "/usr/include"; then + if test -f /usr/kerberos/include/krb5.h; then + SSL_INCLUDES="-I/usr/kerberos/include" + fi +elif test "$ssl_includes" != "/usr/local/include" && test -n "$ssl_includes"; then + SSL_INCLUDES="-I$ssl_includes" +fi + +if test "$ssl_libraries" = "/usr/lib" || test "$ssl_libraries" = "/usr/local/lib" || test -z "$ssl_libraries" || test "$ssl_libraries" = "NONE"; then + SSL_LDFLAGS="" +else + SSL_LDFLAGS="-L$ssl_libraries -R$ssl_libraries" +fi + +AC_SUBST(SSL_INCLUDES) +AC_SUBST(SSL_LDFLAGS) +AC_SUBST(LIBSSL) +]) + +AC_DEFUN([KDE_CHECK_STRLCPY], +[ + AC_REQUIRE([AC_CHECK_STRLCAT]) + AC_REQUIRE([AC_CHECK_STRLCPY]) + AC_CHECK_SIZEOF(size_t) + AC_CHECK_SIZEOF(unsigned long) + + AC_MSG_CHECKING([sizeof size_t == sizeof unsigned long]) + AC_TRY_COMPILE(,[ + #if SIZEOF_SIZE_T != SIZEOF_UNSIGNED_LONG + choke me + #endif + ],AC_MSG_RESULT([yes]),[ + AC_MSG_RESULT(no) + AC_MSG_ERROR([ + Apparently on your system our assumption sizeof size_t == sizeof unsigned long + does not apply. Please mail kde-devel@kde.org with a description of your system! + ]) + ]) +]) + +AC_DEFUN([KDE_CHECK_BINUTILS], +[ + AC_MSG_CHECKING([if ld supports unversioned version maps]) + + kde_save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -Wl,--version-script=conftest.map" + echo "{ local: extern \"C++\" { foo }; };" > conftest.map + AC_TRY_LINK([int foo;], +[ +#ifdef __INTEL_COMPILER +icc apparently does not support libtools version-info and version-script +at the same time. Dunno where the bug is, but until somebody figured out, +better disable the optional version scripts. +#endif + + foo = 42; +], kde_supports_versionmaps=yes, kde_supports_versionmaps=no) + LDFLAGS="$kde_save_LDFLAGS" + rm -f conftest.map + AM_CONDITIONAL(include_VERSION_SCRIPT, + [test "$kde_supports_versionmaps" = "yes" && test "$kde_use_debug_code" = "no"]) + + AC_MSG_RESULT($kde_supports_versionmaps) +]) + +AC_DEFUN([AM_PROG_OBJC],[ +AC_CHECK_PROGS(OBJC, gcc, gcc) +test -z "$OBJC" && AC_MSG_ERROR([no acceptable objective-c gcc found in \$PATH]) +if test "x${OBJCFLAGS-unset}" = xunset; then + OBJCFLAGS="-g -O2" +fi +AC_SUBST(OBJCFLAGS) +_AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES(OBJC)]) +]) + +AC_DEFUN([KDE_CHECK_PERL], +[ + KDE_FIND_PATH(perl, PERL, [$bindir $exec_prefix/bin $prefix/bin], [ + AC_MSG_ERROR([No Perl found in your $PATH. +We need perl to generate some code.]) + ]) + AC_SUBST(PERL) +]) + +AC_DEFUN([KDE_CHECK_LARGEFILE], +[ +AC_SYS_LARGEFILE +if test "$ac_cv_sys_file_offset_bits" != no; then + CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=$ac_cv_sys_file_offset_bits" +fi + +if test "x$ac_cv_sys_large_files" != "xno"; then + CPPFLAGS="$CPPFLAGS -D_LARGE_FILES=1" +fi + +]) + +dnl A small extension to PKG_CHECK_MODULES (defined in pkg.m4.in) +dnl which allows to search for libs that get installed into the KDE prefix. +dnl +dnl Syntax: KDE_PKG_CHECK_MODULES(KSTUFF, libkexif >= 0.2 glib = 1.3.4, action-if, action-not) +dnl defines KSTUFF_LIBS, KSTUFF_CFLAGS, see pkg-config man page +dnl also defines KSTUFF_PKG_ERRORS on error +AC_DEFUN([KDE_PKG_CHECK_MODULES], [ + + PKG_CONFIG_PATH="$prefix/lib/pkgconfig:$PKG_CONFIG_PATH" + if test "$prefix" != "$kde_libs_prefix"; then + PKG_CONFIG_PATH="$kde_libs_prefix/lib/pkgconfig:$PKG_CONFIG_PATH" + fi + export PKG_CONFIG_PATH + PKG_CHECK_MODULES($1,$2,$3,$4) +]) + +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- + +# serial 47 AC_PROG_LIBTOOL + + +# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED) +# ----------------------------------------------------------- +# If this macro is not defined by Autoconf, define it here. +m4_ifdef([AC_PROVIDE_IFELSE], + [], + [m4_define([AC_PROVIDE_IFELSE], + [m4_ifdef([AC_PROVIDE_$1], + [$2], [$3])])]) + + +# AC_PROG_LIBTOOL +# --------------- +AC_DEFUN([AC_PROG_LIBTOOL], +[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl +dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX +dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. + AC_PROVIDE_IFELSE([AC_PROG_CXX], + [AC_LIBTOOL_CXX], + [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX + ])]) +dnl And a similar setup for Fortran 77 support + AC_PROVIDE_IFELSE([AC_PROG_F77], + [AC_LIBTOOL_F77], + [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77 +])]) + +dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. +dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run +dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. + AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [ifdef([AC_PROG_GCJ], + [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([A][M_PROG_GCJ], + [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([LT_AC_PROG_GCJ], + [define([LT_AC_PROG_GCJ], + defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])]) +])])# AC_PROG_LIBTOOL + + +# _AC_PROG_LIBTOOL +# ---------------- +AC_DEFUN([_AC_PROG_LIBTOOL], +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl +AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl +AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl +AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool --silent' +AC_SUBST(LIBTOOL)dnl + +# Prevent multiple expansion +define([AC_PROG_LIBTOOL], []) +])# _AC_PROG_LIBTOOL + + +# AC_LIBTOOL_SETUP +# ---------------- +AC_DEFUN([AC_LIBTOOL_SETUP], +[AC_PREREQ(2.50)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl +AC_REQUIRE([AC_PROG_NM])dnl + +AC_REQUIRE([AC_PROG_LN_S])dnl +AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! +AC_REQUIRE([AC_OBJEXT])dnl +AC_REQUIRE([AC_EXEEXT])dnl +dnl + +AC_LIBTOOL_SYS_MAX_CMD_LEN +AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +AC_LIBTOOL_OBJDIR + +AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +_LT_AC_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e s/^X//' +[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] + +# Same as above, but do not quote variable references. +[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except M$VC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" + +AC_CHECK_TOOL(AR, ar, false) +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(STRIP, strip, :) + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$SED" && SED=sed +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds" + ;; + *) + old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + AC_PATH_MAGIC + fi + ;; +esac + +AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +enable_win32_dll=yes, enable_win32_dll=no) + +AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +AC_ARG_WITH([pic], + [AC_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) +test -z "$pic_mode" && pic_mode=default + +# Use C for the default configuration in the libtool script +tagname= +AC_LIBTOOL_LANG_C_CONFIG +_LT_AC_TAGCONFIG +])# AC_LIBTOOL_SETUP + + +# _LT_AC_SYS_COMPILER +# ------------------- +AC_DEFUN([_LT_AC_SYS_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_AC_SYS_COMPILER + + +# _LT_AC_SYS_LIBPATH_AIX +# ---------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX], +[AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_AC_SYS_LIBPATH_AIX + + +# _LT_AC_SHELL_INIT(ARG) +# ---------------------- +AC_DEFUN([_LT_AC_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_AC_SHELL_INIT + + +# _LT_AC_PROG_ECHO_BACKSLASH +# -------------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], +[_LT_AC_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +echo=${ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null && + echo_test_string="`eval $cmd`" && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(ECHO) +])])# _LT_AC_PROG_ECHO_BACKSLASH + + +# _LT_AC_LOCK +# ----------- +AC_DEFUN([_LT_AC_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case "`/usr/bin/file conftest.o`" in + *32-bit*) + LINUX_64_MODE="32" + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + LINUX_64_MODE="64" + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw* | *-*-pw32*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; + ]) +esac + +need_locks="$enable_libtool_lock" + +])# _LT_AC_LOCK + + +# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], +[AC_REQUIRE([LT_AC_PROG_SED]) +AC_CACHE_CHECK([$1], [$2], + [$2=no + ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s conftest.err; then + $2=yes + fi + fi + $rm conftest* +]) + +if test x"[$]$2" = xyes; then + ifelse([$5], , :, [$5]) +else + ifelse([$6], , :, [$6]) +fi +])# AC_LIBTOOL_COMPILER_OPTION + + +# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ------------------------------------------------------------ +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], +[AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + else + $2=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + ifelse([$4], , :, [$4]) +else + ifelse([$5], , :, [$5]) +fi +])# AC_LIBTOOL_LINKER_OPTION + + +# AC_LIBTOOL_SYS_MAX_CMD_LEN +# -------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], +[# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + testring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + *) + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while (test "X"`$CONFIG_SHELL [$]0 --fallback-echo "X$testring" 2>/dev/null` \ + = "XX$testring") >/dev/null 2>&1 && + new_result=`expr "X$testring" : ".*" 2>&1` && + lt_cv_sys_max_cmd_len=$new_result && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + testring=$testring$testring + done + testring= + # Add a significant safety factor because C++ compilers can tack on massive + # amounts of additional arguments before passing them to the linker. + # It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +])# AC_LIBTOOL_SYS_MAX_CMD_LEN + + +# _LT_AC_CHECK_DLFCN +# -------------------- +AC_DEFUN([_LT_AC_CHECK_DLFCN], +[AC_CHECK_HEADERS(dlfcn.h)dnl +])# _LT_AC_CHECK_DLFCN + + +# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ------------------------------------------------------------------ +AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +}] +EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_unknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_AC_TRY_DLOPEN_SELF + + +# AC_LIBTOOL_DLOPEN_SELF +# ------------------- +AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + LDFLAGS="$LDFLAGS $link_static_flag" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +])# AC_LIBTOOL_DLOPEN_SELF + + +# AC_LIBTOOL_PROG_CC_C_O([TAGNAME]) +# --------------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler +AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + # According to Tom Tromey, Ian Lance Taylor reported there are C compilers + # that will create temporary files in the current directory regardless of + # the output directory. Thus, making CWD read-only will cause this test + # to fail, enabling locking or at least warning the user not to do parallel + # builds. + chmod -w . + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s out/conftest.err; then + _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . + $rm conftest* out/* + rmdir out + cd .. + rmdir conftest + $rm conftest* +]) +])# AC_LIBTOOL_PROG_CC_C_O + + +# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME]) +# ----------------------------------------- +# Check to see if we can do hard links to lock some files if needed +AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], +[AC_REQUIRE([_LT_AC_LOCK])dnl + +hard_links="nottested" +if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS + + +# AC_LIBTOOL_OBJDIR +# ----------------- +AC_DEFUN([AC_LIBTOOL_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +])# AC_LIBTOOL_OBJDIR + + +# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME]) +# ---------------------------------------------- +# Check hardcoding attributes. +AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_AC_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \ + test -n "$_LT_AC_TAGVAR(runpath_var $1)" || \ + test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)"="Xyes" ; then + + # We can hardcode non-existant directories. + if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_AC_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_AC_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_AC_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH + + +# AC_LIBTOOL_SYS_LIB_STRIP +# ------------------------ +AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP], +[striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) +fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +])# AC_LIBTOOL_SYS_LIB_STRIP + + +# AC_LIBTOOL_SYS_DYNAMIC_LINKER +# ----------------------------- +# PORTME Fill in your ld.so characteristics +AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER], +[AC_MSG_CHECKING([dynamic linker characteristics]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi4*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext='$(test .$module = .yes && echo .so || echo .dylib)' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd*-gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd*) + objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + *) # from 3.2 on + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case "$host_cpu" in + ia64*) + shrext='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + libsuff= + if test "x$LINUX_64_MODE" = x64; then + # Some platforms are per default 64-bit, so there's no /lib64 + if test -d /lib64; then + libsuff=64 + fi + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff}" + sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}" + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no +])# AC_LIBTOOL_SYS_DYNAMIC_LINKER + + +# _LT_AC_TAGCONFIG +# ---------------- +AC_DEFUN([_LT_AC_TAGCONFIG], +[AC_ARG_WITH([tags], + [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@], + [include additional configurations @<:@automatic@:>@])], + [tagnames="$withval"]) + +if test -f "$ltmain" && test -n "$tagnames"; then + if test ! -f "${ofile}"; then + AC_MSG_WARN([output file `$ofile' does not exist]) + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) + else + AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) + fi + fi + + # Extract list of available tagged configurations in $ofile. + # Note that this assumes the entire list is on one line. + available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` + + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for tagname in $tagnames; do + IFS="$lt_save_ifs" + # Check whether tagname contains only valid characters + case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in + "") ;; + *) AC_MSG_ERROR([invalid tag name: $tagname]) + ;; + esac + + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null + then + AC_MSG_ERROR([tag name \"$tagname\" already exists]) + fi + + # Update the list of available tags. + if test -n "$tagname"; then + echo appending configuration tag \"$tagname\" to $ofile + + case $tagname in + CXX) + if test -n "$CXX" && test "X$CXX" != "Xno"; then + AC_LIBTOOL_LANG_CXX_CONFIG + else + tagname="" + fi + ;; + + F77) + if test -n "$F77" && test "X$F77" != "Xno"; then + AC_LIBTOOL_LANG_F77_CONFIG + else + tagname="" + fi + ;; + + GCJ) + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + AC_LIBTOOL_LANG_GCJ_CONFIG + else + tagname="" + fi + ;; + + RC) + AC_LIBTOOL_LANG_RC_CONFIG + ;; + + *) + AC_MSG_ERROR([Unsupported tag name: $tagname]) + ;; + esac + + # Append the new tag name to the list of available tags. + if test -n "$tagname" ; then + available_tags="$available_tags $tagname" + fi + fi + done + IFS="$lt_save_ifs" + + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + else + rm -f "${ofile}T" + AC_MSG_ERROR([unable to update list of available tagged configurations.]) + fi +fi +])# _LT_AC_TAGCONFIG + + +# AC_LIBTOOL_DLOPEN +# ----------------- +# enable checks for dlopen support +AC_DEFUN([AC_LIBTOOL_DLOPEN], + [AC_BEFORE([$0],[AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_DLOPEN + + +# AC_LIBTOOL_WIN32_DLL +# -------------------- +# declare package support for building win32 dll's +AC_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_BEFORE([$0], [AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_WIN32_DLL + + +# AC_ENABLE_SHARED([DEFAULT]) +# --------------------------- +# implement the --enable-shared flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_SHARED], +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([shared], + [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]AC_ENABLE_SHARED_DEFAULT) +])# AC_ENABLE_SHARED + + +# AC_DISABLE_SHARED +# ----------------- +#- set the default shared flag to --disable-shared +AC_DEFUN([AC_DISABLE_SHARED], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no) +])# AC_DISABLE_SHARED + + +# AC_ENABLE_STATIC([DEFAULT]) +# --------------------------- +# implement the --enable-static flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_STATIC], +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([static], + [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]AC_ENABLE_STATIC_DEFAULT) +])# AC_ENABLE_STATIC + + +# AC_DISABLE_STATIC +# ----------------- +# set the default static flag to --disable-static +AC_DEFUN([AC_DISABLE_STATIC], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no) +])# AC_DISABLE_STATIC + + +# AC_ENABLE_FAST_INSTALL([DEFAULT]) +# --------------------------------- +# implement the --enable-fast-install flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_FAST_INSTALL], +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([fast-install], + [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT) +])# AC_ENABLE_FAST_INSTALL + + +# AC_DISABLE_FAST_INSTALL +# ----------------------- +# set the default to --disable-fast-install +AC_DEFUN([AC_DISABLE_FAST_INSTALL], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no) +])# AC_DISABLE_FAST_INSTALL + + +# AC_LIBTOOL_PICMODE([MODE]) +# -------------------------- +# implement the --with-pic flag +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +AC_DEFUN([AC_LIBTOOL_PICMODE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +pic_mode=ifelse($#,1,$1,default) +])# AC_LIBTOOL_PICMODE + + +# AC_PROG_EGREP +# ------------- +# This is predefined starting with Autoconf 2.54, so this conditional +# definition can be removed once we require Autoconf 2.54 or later. +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP], +[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], + [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi]) + EGREP=$ac_cv_prog_egrep + AC_SUBST([EGREP]) +])]) + + +# AC_PATH_TOOL_PREFIX +# ------------------- +# find a file program which can recognise shared library +AC_DEFUN([AC_PATH_TOOL_PREFIX], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +])# AC_PATH_TOOL_PREFIX + + +# AC_PATH_MAGIC +# ------------- +# find a file program which can recognise a shared library +AC_DEFUN([AC_PATH_MAGIC], +[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# AC_PATH_MAGIC + + +# AC_PROG_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH([gnu-ld], + [AC_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no]) +AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case "$host_cpu" in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + irix5* | nonstopux*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" + ;; + *) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[[1234]] dynamic lib MIPS - version 1" + ;; + esac + lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*` + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux*) + case $host_cpu in + alpha* | hppa* | i*86 | ia64* | m68* | mips* | powerpc* | sparc* | s390* | sh* | x86_64* ) + lt_cv_deplibs_check_method=pass_all ;; + # the debian people say, arm and glibc 2.3.1 works for them with pass_all + arm* ) + lt_cv_deplibs_check_method=pass_all ;; + *) + # glibc up to 2.1.1 does not perform some relocations on ARM + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; + esac + lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +nto-qnx*) + lt_cv_deplibs_check_method=unknown + ;; + +openbsd*) + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB shared object' + else + lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library' + fi + ;; + +osf3* | osf4* | osf5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method='file_magic COFF format alpha shared library' + lt_cv_file_magic_test_file=/shlib/libc.so + lt_cv_deplibs_check_method=pass_all + ;; + +sco3.2v5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + lt_cv_file_magic_test_file=/lib/libc.so + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown +])# AC_DEPLIBS_CHECK_METHOD + + +# AC_PROG_NM +# ---------- +# find the pathname to a BSD-compatible name lister +AC_DEFUN([AC_PROG_NM], +[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/${ac_tool_prefix}nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + esac + fi + done + IFS="$lt_save_ifs" + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi]) +NM="$lt_cv_path_NM" +])# AC_PROG_NM + + +# AC_CHECK_LIBM +# ------------- +# check for math library +AC_DEFUN([AC_CHECK_LIBM], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +])# AC_CHECK_LIBM + + +# AC_LIBLTDL_CONVENIENCE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl convenience library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-convenience to the configure arguments. Note that LIBLTDL +# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If +# DIRECTORY is not provided, it is assumed to be `libltdl'. LIBLTDL will +# be prefixed with '${top_builddir}/' and LTDLINCL will be prefixed with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +AC_DEFUN([AC_LIBLTDL_CONVENIENCE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_CONVENIENCE + + +# AC_LIBLTDL_INSTALLABLE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl installable library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-install to the configure arguments. Note that LIBLTDL +# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If +# DIRECTORY is not provided and an installed libltdl is not found, it is +# assumed to be `libltdl'. LIBLTDL will be prefixed with '${top_builddir}/' +# and LTDLINCL will be prefixed with '${top_srcdir}/' (note the single +# quotes!). If your package is not flat and you're not using automake, +# define top_builddir and top_srcdir appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN([AC_LIBLTDL_INSTALLABLE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, lt_dlinit, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + LTDLINCL= + fi + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_INSTALLABLE + + +# AC_LIBTOOL_CXX +# -------------- +# enable support for C++ libraries +AC_DEFUN([AC_LIBTOOL_CXX], +[AC_REQUIRE([_LT_AC_LANG_CXX]) +])# AC_LIBTOOL_CXX + + +# _LT_AC_LANG_CXX +# --------------- +AC_DEFUN([_LT_AC_LANG_CXX], +[AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([AC_PROG_CXXCPP]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX]) +])# _LT_AC_LANG_CXX + + +# AC_LIBTOOL_F77 +# -------------- +# enable support for Fortran 77 libraries +AC_DEFUN([AC_LIBTOOL_F77], +[AC_REQUIRE([_LT_AC_LANG_F77]) +])# AC_LIBTOOL_F77 + + +# _LT_AC_LANG_F77 +# --------------- +AC_DEFUN([_LT_AC_LANG_F77], +[AC_REQUIRE([AC_PROG_F77]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77]) +])# _LT_AC_LANG_F77 + + +# AC_LIBTOOL_GCJ +# -------------- +# enable support for GCJ libraries +AC_DEFUN([AC_LIBTOOL_GCJ], +[AC_REQUIRE([_LT_AC_LANG_GCJ]) +])# AC_LIBTOOL_GCJ + + +# _LT_AC_LANG_GCJ +# --------------- +AC_DEFUN([_LT_AC_LANG_GCJ], +[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], + [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], + [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], + [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ]) +])# _LT_AC_LANG_GCJ + + +# AC_LIBTOOL_RC +# -------------- +# enable support for Windows resource files +AC_DEFUN([AC_LIBTOOL_RC], +[AC_REQUIRE([LT_AC_PROG_RC]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC]) +])# AC_LIBTOOL_RC + + +# AC_LIBTOOL_LANG_C_CONFIG +# ------------------------ +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG]) +AC_DEFUN([_LT_AC_LANG_C_CONFIG], +[lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}\n' + +_LT_AC_SYS_COMPILER + +# +# Check for any special shared library compilation flags. +# +_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)= +if test "$GCC" = no; then + case $host_os in + sco3.2v5*) + _LT_AC_TAGVAR(lt_prog_cc_shlib, $1)='-belf' + ;; + esac +fi +if test -n "$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)"; then + AC_MSG_WARN([`$CC' requires `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to build shared libraries]) + if echo "$old_CC $old_CFLAGS " | grep "[[ ]]$]_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)[[[ ]]" >/dev/null; then : + else + AC_MSG_WARN([add `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to the CC or CFLAGS env variable and reconfigure]) + _LT_AC_TAGVAR(lt_cv_prog_cc_can_build_shared, $1)=no + fi +fi + + +# +# Check to make sure the static flag actually works. +# +AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $_LT_AC_TAGVAR(lt_prog_compiler_static, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1), + $_LT_AC_TAGVAR(lt_prog_compiler_static, $1), + [], + [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=]) + + +AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_DLOPEN_SELF($1) + +# Report which librarie types wil actually be built +AC_MSG_CHECKING([if libtool supports shared libraries]) +AC_MSG_RESULT([$can_build_shared]) + +AC_MSG_CHECKING([whether to build shared libraries]) +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + darwin* | rhapsody*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case "$host_os" in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress' + ;; + *) # Darwin 1.3 on + test -z ${LD_TWOLEVEL_NAMESPACE} && _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' + ;; + esac + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; +esac +AC_MSG_RESULT([$enable_shared]) + +AC_MSG_CHECKING([whether to build static libraries]) +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +AC_MSG_RESULT([$enable_static]) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_C_CONFIG + + +# AC_LIBTOOL_LANG_CXX_CONFIG +# -------------------------- +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)]) +AC_DEFUN([_LT_AC_LANG_CXX_CONFIG], +[AC_LANG_PUSH(C++) +AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([AC_PROG_CXXCPP]) + +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_AC_TAGVAR(allow_undefined_flag, $1)= +_LT_AC_TAGVAR(always_export_symbols, $1)=no +_LT_AC_TAGVAR(archive_expsym_cmds, $1)= +_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_direct, $1)=no +_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_AC_TAGVAR(hardcode_libdir_separator, $1)= +_LT_AC_TAGVAR(hardcode_minus_L, $1)=no +_LT_AC_TAGVAR(hardcode_automatic, $1)=no +_LT_AC_TAGVAR(module_cmds, $1)= +_LT_AC_TAGVAR(module_expsym_cmds, $1)= +_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown +_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_AC_TAGVAR(no_undefined_flag, $1)= +_LT_AC_TAGVAR(whole_archive_flag_spec, $1)= +_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Dependencies to place before and after the object being linked: +_LT_AC_TAGVAR(predep_objects, $1)= +_LT_AC_TAGVAR(postdep_objects, $1)= +_LT_AC_TAGVAR(predeps, $1)= +_LT_AC_TAGVAR(postdeps, $1)= +_LT_AC_TAGVAR(compiler_lib_search_path, $1)= + +# Source file extension for C++ test sources. +ac_ext=cc + +# Object file extension for compiled C++ test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(int, char *[]) { return(0); }\n' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_LD=$LD +lt_save_GCC=$GCC +GCC=$GXX +lt_save_with_gnu_ld=$with_gnu_ld +lt_save_path_LD=$lt_cv_path_LD +if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx +else + unset lt_cv_prog_gnu_ld +fi +if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX +else + unset lt_cv_path_LD +fi +test -z "${LDCXX+set}" || LD=$LDCXX +CC=${CXX-"c++"} +compiler=$CC +_LT_AC_TAGVAR(compiler, $1)=$CC +cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'` + +# We don't want -fno-exception wen compiling C++ code, so set the +# no_builtin_flag separately +if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' +else + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= +fi + +if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + AC_PROG_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ + grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + +else + GXX=no + with_gnu_ld=no + wlarc= +fi + +# PORTME: fill in a description of your system's C++ link characteristics +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +_LT_AC_TAGVAR(ld_shlibs, $1)=yes +case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # KDE requires run time linking. Make it the default. + aix_use_runtimelinking=yes + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='-qmkshrobj ${wl}-G' + else + shared_flag='-qmkshrobj' + fi + fi + fi + + # Let the compiler handle the export list. + _LT_AC_TAGVAR(always_export_symbols, $1)=no + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_AC_TAGVAR(archive_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '" $shared_flag" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # -bexpall does not export symbols beginning with underscore (_) + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds it's shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + darwin* | rhapsody*) + if test "$GXX" = yes; then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case "$host_os" in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress' + ;; + *) # Darwin 1.3 on + test -z ${LD_TWOLEVEL_NAMESPACE} && _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' + ;; + esac + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + fi + _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + dgux*) + case $cc_basename in + ec++) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + freebsd[12]*) + # C++ shared libraries reported to be fairly broken before switch to ELF + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + freebsd-elf*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + freebsd*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + ;; + gnu*) + ;; + hpux9*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | egrep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + case "$host_cpu" in + hppa*64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + ;; + *) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case "$host_cpu" in + hppa*64*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + ia64*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC) + case "$host_cpu" in + hppa*64*|ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case "$host_cpu" in + ia64*|hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + irix5* | irix6*) + case $cc_basename in + CC) + # SGI C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' + fi + fi + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + linux*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc) + # Intel C++ + with_gnu_ld=yes + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + cxx) + # Compaq C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + esac + ;; + lynxos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + m88k*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + mvs*) + case $cc_basename in + cxx) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + osf3*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + + ;; + RCC) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + osf4* | osf5*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' + ;; + RCC) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry $objdir/so_locations -o $lib~ + $rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + psos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + sco*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + lcc) + # Lucid + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + solaris*) + case $cc_basename in + CC) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The C++ compiler is used as linker so we must use $wl + # flag to pass the commands to the underlying system + # linker. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[[LR]]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | grep -v '^2\.7' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + fi + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + fi + ;; + esac + ;; + sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + tandem*) + case $cc_basename in + NCC) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + vxworks*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; +esac +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_AC_TAGVAR(GCC, $1)="$GXX" +_LT_AC_TAGVAR(LD, $1)="$LD" + +AC_LIBTOOL_POSTDEP_PREDEP($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_DLOPEN_SELF($1) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC=$lt_save_CC +LDCXX=$LD +LD=$lt_save_LD +GCC=$lt_save_GCC +with_gnu_ldcxx=$with_gnu_ld +with_gnu_ld=$lt_save_with_gnu_ld +lt_cv_path_LDCXX=$lt_cv_path_LD +lt_cv_path_LD=$lt_save_path_LD +lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld +lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +])# AC_LIBTOOL_LANG_CXX_CONFIG + +# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME]) +# ------------------------ +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[ +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +ifelse([$1],[],[cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext <> "$cfgfile" +ifelse([$1], [], +[#! $SHELL + +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="$SED -e s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +# The names of the tagged configurations supported by this script. +available_tags= + +# ### BEGIN LIBTOOL CONFIG], +[# ### BEGIN LIBTOOL TAG CONFIG: $tagname]) + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1) + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# A language-specific compiler. +CC=$lt_[]_LT_AC_TAGVAR(compiler, $1) + +# Is the compiler the GNU C compiler? +with_gcc=$_LT_AC_TAGVAR(GCC, $1) + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_[]_LT_AC_TAGVAR(LD, $1) + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext='$shrext' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) + +# Must we lock files when doing compilation ? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1) + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1) + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1) + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1) + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1) +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1) + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) + +# Commands used to build and install a shared archive. +archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1) +archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1) +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1) +module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1) + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1) + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1) + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1) + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1) + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1) + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1) + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1) + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1) + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1) + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1) + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1) + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1) + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)" + +# Set to yes if exported symbols are required. +always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1) + +# The commands to list exported symbols. +export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1) + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1) + +# Symbols that must always be exported. +include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1) + +ifelse([$1],[], +[# ### END LIBTOOL CONFIG], +[# ### END LIBTOOL TAG CONFIG: $tagname]) + +__EOF__ + +ifelse([$1],[], [ + case $host_os in + aix3*) + cat <<\EOF >> "$cfgfile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || \ + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +]) +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + test -f Makefile && make "$ltmain" +fi +])# AC_LIBTOOL_CONFIG + + +# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl + +_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI + + +# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +# --------------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_NM]) +AC_REQUIRE([AC_OBJEXT]) +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Transform the above into a raw symbol and a C symbol. +symxfrm='\1 \2\3 \3' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) # Its linker distinguishes data from code symbols + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris* | sysv5*) + symcode='[[BDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGISTW]]' ;; +esac + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Write the raw and C identifiers. + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if grep ' nm_test_var$' "$nlist" >/dev/null; then + if grep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[[]] = +{ +EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi +]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE + + +# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME]) +# --------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC], +[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) + ifelse([$1],[CXX],[ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | os2* | pw32*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix4* | aix5*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68) + # Green Hills C++ Compiler + # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux*) + case $cc_basename in + KCC) + # KAI C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + icpc) + # Intel C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + cxx) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC) + # Rational C++ 2.4.1 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx) + # Digital/Compaq C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + sco*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + *) + ;; + esac + ;; + solaris*) + case $cc_basename in + CC) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC) + # Sun C++ 4.x + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc) + # Lucid + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC) + # NonStop-UX NCC 3.20 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + unixware*) + ;; + vxworks*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + newsos6) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + linux*) + case $CC in + icc* | ecc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + ccc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + sco3.2v5*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-dn' + ;; + + solaris*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sunos4*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + uts4*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then + AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1), + [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +case "$host_os" in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])" + ;; +esac +]) + + +# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME]) +# ------------------------------------ +# See if the linker supports building shared libraries. +AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS], +[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +ifelse([$1],[CXX],[ + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix4* | aix5*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + ;; + *) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +],[ + runpath_var= + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)= + _LT_AC_TAGVAR(archive_expsym_cmds, $1)= + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)= + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + _LT_AC_TAGVAR(thread_safe_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown + _LT_AC_TAGVAR(hardcode_automatic, $1)=no + _LT_AC_TAGVAR(module_cmds, $1)= + _LT_AC_TAGVAR(module_expsym_cmds, $1)= + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_AC_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + else + ld_shlibs=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris* | sysv5*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sunos4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = yes; then + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + + # KDE requires run time linking. Make it the default. + aix_use_runtimelinking=yes + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='-qmkshrobj ${wl}-G' + else + shared_flag='-qmkshrobj' + fi + fi + fi + + # Let the compiler handle the export list. + _LT_AC_TAGVAR(always_export_symbols, $1)=no + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_AC_TAGVAR(archive_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '" $shared_flag" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # -bexpall does not export symbols beginning with underscore (_) + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds it's shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + # see comment about different semantics on the GNU ld section + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + bsdi4*) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + if test "$GXX" = yes ; then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case "$host_os" in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress' + ;; + *) # Darwin 1.3 on + test -z ${LD_TWOLEVEL_NAMESPACE} && _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' + ;; + esac + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + fi + _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + dgux*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10* | hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case "$host_cpu" in + hppa*64*|ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case "$host_cpu" in + hppa*64*|ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + case "$host_cpu" in + hppa*64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + ;; + *) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + openbsd*) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + sco3.2v5*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ;; + + solaris*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4.2uw2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + hardcode_runpath_var=yes + runpath_var=LD_RUN_PATH + ;; + + sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z ${wl}text' + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv5*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + ;; + + uts4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +# +# Do we need to explicitly link libc? +# +case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_AC_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1) + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) + then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac +])# AC_LIBTOOL_PROG_LD_SHLIBS + + +# _LT_AC_FILE_LTDLL_C +# ------------------- +# Be careful that the start marker always follows a newline. +AC_DEFUN([_LT_AC_FILE_LTDLL_C], [ +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include +# #undef WIN32_LEAN_AND_MEAN +# #include +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ +])# _LT_AC_FILE_LTDLL_C + + +# _LT_AC_TAGVAR(VARNAME, [TAGNAME]) +# --------------------------------- +AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])]) + + +# old names +AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) +AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) +AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) +AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) +AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) + +# This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL]) + +AC_DEFUN([LT_AC_PROG_GCJ], +[AC_CHECK_TOOL(GCJ, gcj, no) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS) +]) + +AC_DEFUN([LT_AC_PROG_RC], +[AC_CHECK_TOOL(RC, windres, no) +]) + +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +# LT_AC_PROG_SED +# -------------- +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +AC_DEFUN([LT_AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && break + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_MSG_RESULT([$SED]) +]) + +dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not) +dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page +dnl also defines GSTUFF_PKG_ERRORS on error +AC_DEFUN([PKG_CHECK_MODULES], [ + succeeded=no + + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + + if test "$PKG_CONFIG" = "no" ; then + echo "*** The pkg-config script could not be found. Make sure it is" + echo "*** in your path, or set the PKG_CONFIG environment variable" + echo "*** to the full path to pkg-config." + echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." + else + PKG_CONFIG_MIN_VERSION=0.9.0 + if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then + AC_MSG_CHECKING(for $2) + + if $PKG_CONFIG --exists "$2" ; then + AC_MSG_RESULT(yes) + succeeded=yes + + AC_MSG_CHECKING($1_CFLAGS) + $1_CFLAGS=`$PKG_CONFIG --cflags "$2"` + AC_MSG_RESULT($$1_CFLAGS) + + AC_MSG_CHECKING($1_LIBS) + $1_LIBS=`$PKG_CONFIG --libs "$2"` + AC_MSG_RESULT($$1_LIBS) + else + $1_CFLAGS="" + $1_LIBS="" + ## If we have a custom action on failure, don't print errors, but + ## do set a variable so people can do so. + $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` + ifelse([$4], ,echo $$1_PKG_ERRORS,) + fi + + AC_SUBST($1_CFLAGS) + AC_SUBST($1_LIBS) + else + echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer." + echo "*** See http://www.freedesktop.org/software/pkgconfig" + fi + fi + + if test $succeeded = yes; then + ifelse([$3], , :, [$3]) + else + ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4]) + fi +]) + + + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright 1997, 2000, 2001 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# serial 5 + +AC_PREREQ(2.52) + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE]) +AC_SUBST([$1_FALSE]) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([conditional \"$1\" was never defined. +Usually this means the macro was only invoked conditionally.]) +fi])]) + +# Do all the work for Automake. -*- Autoconf -*- + +# This macro actually does too much some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# serial 8 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +AC_PREREQ([2.52]) + +# Autoconf 2.50 wants to disallow AM_ names. We explicitly allow +# the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl + AC_REQUIRE([AC_PROG_INSTALL])dnl +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl + AC_SUBST([PACKAGE], [AC_PACKAGE_TARNAME])dnl + AC_SUBST([VERSION], [AC_PACKAGE_VERSION])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_MISSING_PROG(AMTAR, tar) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl + +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_][CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_][CC], + defn([AC_PROG_][CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_][CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_][CXX], + defn([AC_PROG_][CXX])[_AM_DEPENDENCIES(CXX)])])dnl +]) +]) + +# Copyright 2002 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +AC_DEFUN([AM_AUTOMAKE_VERSION],[am__api_version="1.6"]) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION so it can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], + [AM_AUTOMAKE_VERSION([1.6.3])]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright 2001, 2002 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# serial 2 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# +# Check to make sure that the build environment is sane. +# + +# Copyright 1996, 1997, 2000, 2001 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# serial 3 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# -*- Autoconf -*- + + +# Copyright 1997, 1999, 2000, 2001 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# serial 3 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# AM_AUX_DIR_EXPAND + +# Copyright 2001 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +# Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50]) + +AC_DEFUN([AM_AUX_DIR_EXPAND], [ +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. + +# Copyright 2001 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"$am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# AM_PROG_INSTALL_STRIP + +# Copyright 2001 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# serial 4 -*- Autoconf -*- + +# Copyright 1999, 2000, 2001 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + for depmode in $am_compiler_list; do + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + echo '#include "conftest.h"' > conftest.c + echo 'int i;' > conftest.h + echo "${am__include} ${am__quote}conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=conftest.c object=conftest.o \ + depfile=conftest.Po tmpdepfile=conftest.TPo \ + $SHELL ./depcomp $depcc -c conftest.c -o conftest.o >/dev/null 2>&1 && + grep conftest.h conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[rm -f .deps 2>/dev/null +mkdir .deps 2>/dev/null +if test -d .deps; then + DEPDIR=.deps +else + # MS-DOS does not allow filenames that begin with a dot. + DEPDIR=_deps +fi +rmdir .deps 2>/dev/null +AC_SUBST([DEPDIR]) +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking Speeds up one-time builds + --enable-dependency-tracking Do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH]) +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +#serial 2 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + grep '^DEP_FILES *= *[[^ @%:@]]' < "$mf" > /dev/null || continue + # Extract the definition of DEP_FILES from the Makefile without + # running `make'. + DEPDIR=`sed -n -e '/^DEPDIR = / s///p' < "$mf"` + test -z "$DEPDIR" && continue + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n -e '/^U = / s///p' < "$mf"` + test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR" + # We invoke sed twice because it is the simplest approach to + # changing $(DEPDIR) to its actual value in the expansion. + for file in `sed -n -e ' + /^DEP_FILES = .*\\\\$/ { + s/^DEP_FILES = // + :loop + s/\\\\$// + p + n + /\\\\$/ b loop + p + } + /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Copyright 2001 Free Software Foundation, Inc. -*- Autoconf -*- + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# serial 2 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +doit: + @echo done +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | fgrep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST(am__include) +AC_SUBST(am__quote) +AC_MSG_RESULT($_am_result) +rm -f confinc confmf +]) + + +# Copyright 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# serial 3 + +AC_PREREQ(2.50) + +# AM_PROG_LEX +# ----------- +# Autoconf leaves LEX=: if lex or flex can't be found. Change that to a +# "missing" invocation, for better error output. +AC_DEFUN([AM_PROG_LEX], +[AC_REQUIRE([AM_MISSING_HAS_RUN])dnl +AC_REQUIRE([AC_PROG_LEX])dnl +if test "$LEX" = :; then + LEX=${am_missing_run}flex +fi]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. -*- Autoconf -*- + +# Copyright 1996, 1997, 2000, 2001 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +AC_PREREQ([2.52]) + +# serial 6 + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. We must strip everything past the first ":", +# and everything past the last "/". + +# _AM_DIRNAME(PATH) +# ----------------- +# Like AS_DIRNAME, only do it during macro expansion +AC_DEFUN([_AM_DIRNAME], + [m4_if(regexp([$1], [^.*[^/]//*[^/][^/]*/*$]), -1, + m4_if(regexp([$1], [^//\([^/]\|$\)]), -1, + m4_if(regexp([$1], [^/.*]), -1, + [.], + patsubst([$1], [^\(/\).*], [\1])), + patsubst([$1], [^\(//\)\([^/].*\|$\)], [\1])), + patsubst([$1], [^\(.*[^/]\)//*[^/][^/]*/*$], [\1]))[]dnl +])# _AM_DIRNAME + + +# The stamp files are numbered to have different names. +# We could number them on a directory basis, but that's additional +# complications, let's have a unique counter. +m4_define([_AM_STAMP_Count], [0]) + + +# _AM_STAMP(HEADER) +# ----------------- +# The name of the stamp file for HEADER. +AC_DEFUN([_AM_STAMP], +[m4_define([_AM_STAMP_Count], m4_incr(_AM_STAMP_Count))dnl +AS_ESCAPE(_AM_DIRNAME(patsubst([$1], + [:.*])))/stamp-h[]_AM_STAMP_Count]) + + +# _AM_CONFIG_HEADER(HEADER[:SOURCES], COMMANDS, INIT-COMMANDS) +# ------------------------------------------------------------ +# We used to try to get a real timestamp in stamp-h. But the fear is that +# that will cause unnecessary cvs conflicts. +AC_DEFUN([_AM_CONFIG_HEADER], +[# Add the stamp file to the list of files AC keeps track of, +# along with our hook. +AC_CONFIG_HEADERS([$1], + [# update the timestamp +echo 'timestamp for $1' >"_AM_STAMP([$1])" +$2], + [$3]) +])# _AM_CONFIG_HEADER + + +# AM_CONFIG_HEADER(HEADER[:SOURCES]..., COMMANDS, INIT-COMMANDS) +# -------------------------------------------------------------- +AC_DEFUN([AM_CONFIG_HEADER], +[AC_FOREACH([_AM_File], [$1], [_AM_CONFIG_HEADER(_AM_File, [$2], [$3])]) +])# AM_CONFIG_HEADER + diff --git a/config.guess b/config.guess new file mode 100755 index 0000000..da83314 --- /dev/null +++ b/config.guess @@ -0,0 +1,1561 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 +# Free Software Foundation, Inc. + +timestamp='2009-04-27' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[456]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:[3456]*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + EM64T | authenticamd | genuineintel) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^LIBC/{ + s: ::g + p + }'`" + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..6c12ac3 --- /dev/null +++ b/config.h.in @@ -0,0 +1,256 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Gpsim 0.21.11 was found */ +#undef GPSIM_0_21_11 + +/* Gpsim 0.21.12 was found */ +#undef GPSIM_0_21_12 + +/* Gpsim 0.21.4 was found */ +#undef GPSIM_0_21_4 + +/* Define to 1 if you have the header file. */ +#undef HAVE_CARBON_CARBON_H + +/* Define if you have the CoreAudio API */ +#undef HAVE_COREAUDIO + +/* Define to 1 if you have the header file. */ +#undef HAVE_CRT_EXTERNS_H + +/* Defines if your system has the crypt function */ +#undef HAVE_CRYPT + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define if you have libjpeg */ +#undef HAVE_LIBJPEG + +/* Define if you have libpng */ +#undef HAVE_LIBPNG + +/* Define if you have a working libpthread (will enable threaded code) */ +#undef HAVE_LIBPTHREAD + +/* Define if you have libz */ +#undef HAVE_LIBZ + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define if your system needs _NSGetEnviron to set up the environment */ +#undef HAVE_NSGETENVIRON + +/* Define if you have res_init */ +#undef HAVE_RES_INIT + +/* Define if you have the res_init prototype */ +#undef HAVE_RES_INIT_PROTO + +/* Define if you have a STL implementation by SGI */ +#undef HAVE_SGI_STL + +/* Define to 1 if you have the `snprintf' function. */ +#undef HAVE_SNPRINTF + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define if you have strlcat */ +#undef HAVE_STRLCAT + +/* Define if you have the strlcat prototype */ +#undef HAVE_STRLCAT_PROTO + +/* Define if you have strlcpy */ +#undef HAVE_STRLCPY + +/* Define if you have the strlcpy prototype */ +#undef HAVE_STRLCPY_PROTO + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_BITYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vsnprintf' function. */ +#undef HAVE_VSNPRINTF + +/* Suffix for lib directories */ +#undef KDELIBSUFF + +/* Define a safe value for MAXPATHLEN */ +#undef KDEMAXPATHLEN + +/* Gpsim was not found */ +#undef NO_GPSIM + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* The size of a `char *', as computed by sizeof. */ +#undef SIZEOF_CHAR_P + +/* The size of a `int', as computed by sizeof. */ +#undef SIZEOF_INT + +/* The size of a `long', as computed by sizeof. */ +#undef SIZEOF_LONG + +/* The size of a `short', as computed by sizeof. */ +#undef SIZEOF_SHORT + +/* The size of a `size_t', as computed by sizeof. */ +#undef SIZEOF_SIZE_T + +/* The size of a `unsigned long', as computed by sizeof. */ +#undef SIZEOF_UNSIGNED_LONG + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Defined if compiling without arts */ +#undef WITHOUT_ARTS + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +#undef WORDS_BIGENDIAN + +/* + * jpeg.h needs HAVE_BOOLEAN, when the system uses boolean in system + * headers and I'm too lazy to write a configure test as long as only + * unixware is related + */ +#ifdef _UNIXWARE +#define HAVE_BOOLEAN +#endif + + + +/* + * AIX defines FD_SET in terms of bzero, but fails to include + * that defines bzero. + */ + +#if defined(_AIX) +#include +#endif + + + +#if defined(HAVE_NSGETENVIRON) && defined(HAVE_CRT_EXTERNS_H) +# include +# include +# define environ (*_NSGetEnviron()) +#endif + + + +#if !defined(HAVE_RES_INIT_PROTO) +#ifdef __cplusplus +extern "C" { +#endif +int res_init(void); +#ifdef __cplusplus +} +#endif +#endif + + + +#if !defined(HAVE_STRLCAT_PROTO) +#ifdef __cplusplus +extern "C" { +#endif +unsigned long strlcat(char*, const char*, unsigned long); +#ifdef __cplusplus +} +#endif +#endif + + + +#if !defined(HAVE_STRLCPY_PROTO) +#ifdef __cplusplus +extern "C" { +#endif +unsigned long strlcpy(char*, const char*, unsigned long); +#ifdef __cplusplus +} +#endif +#endif + + + +/* + * On HP-UX, the declaration of vsnprintf() is needed every time ! + */ + +#if !defined(HAVE_VSNPRINTF) || defined(hpux) +#if __STDC__ +#include +#include +#else +#include +#endif +#ifdef __cplusplus +extern "C" +#endif +int vsnprintf(char *str, size_t n, char const *fmt, va_list ap); +#ifdef __cplusplus +extern "C" +#endif +int snprintf(char *str, size_t n, char const *fmt, ...); +#endif + + + +#if defined(__SVR4) && !defined(__svr4__) +#define __svr4__ 1 +#endif + + +/* type to use in place of socklen_t if not defined */ +#undef kde_socklen_t + +/* type to use in place of socklen_t if not defined (deprecated, use + kde_socklen_t) */ +#undef ksize_t diff --git a/config.log b/config.log new file mode 100644 index 0000000..086d124 --- /dev/null +++ b/config.log @@ -0,0 +1,341 @@ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by configure, which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ ./configure --host=x86_64-linux-gnu --build=x86_64-linux-gnu --disable-debug --disable-rpath --prefix=/opt/kde3 --libexecdir=/opt/kde3/bin --sysconfdir=/etc --libdir=/opt/kde3/lib --includedir=/opt/kde3/include/kde --with-qt-includes=/usr/include/qt3 --mandir=/opt/kde3/share/man --infodir=/opt/kde3/share/info --with-xinerama --prefix=/opt/kde3 + +## --------- ## +## Platform. ## +## --------- ## + +hostname = argus4 +uname -m = x86_64 +uname -r = 2.6.31-16-generic +uname -s = Linux +uname -v = #53-Ubuntu SMP Tue Dec 8 04:02:15 UTC 2009 + +/usr/bin/uname -p = unknown +/bin/uname -X = unknown + +/bin/arch = unknown +/usr/bin/arch -k = unknown +/usr/convex/getsysinfo = unknown +hostinfo = unknown +/bin/machine = unknown +/usr/bin/oslevel = unknown +/bin/universe = unknown + +PATH: /opt/kde3/bin +PATH: /opt/kde3/bin +PATH: /opt/kde3/games +PATH: /opt/kde3/bin +PATH: /home/eldarion/bin +PATH: /usr/local/sbin +PATH: /usr/local/bin +PATH: /usr/sbin +PATH: /usr/bin +PATH: /sbin +PATH: /bin +PATH: /usr/games + + +## ----------- ## +## Core tests. ## +## ----------- ## + +configure:1564: checking build system type +configure:1582: result: x86_64-pc-linux-gnu +configure:1590: checking host system type +configure:1604: result: x86_64-pc-linux-gnu +configure:1612: checking target system type +configure:1626: result: x86_64-pc-linux-gnu +configure:1673: checking for a BSD-compatible install +configure:1728: result: /usr/bin/install -c +configure:1743: checking for -p flag to install +configure:1756: result: yes +configure:1767: checking whether build environment is sane + +## ---------------- ## +## Cache variables. ## +## ---------------- ## + +ac_cv_build=x86_64-pc-linux-gnu +ac_cv_build_alias=x86_64-linux-gnu +ac_cv_env_CC_set= +ac_cv_env_CC_value= +ac_cv_env_CFLAGS_set=set +ac_cv_env_CFLAGS_value='-Wall -g -O2 -Wl,-z,defs' +ac_cv_env_CPPFLAGS_set=set +ac_cv_env_CPPFLAGS_value= +ac_cv_env_CPP_set= +ac_cv_env_CPP_value= +ac_cv_env_CXXCPP_set= +ac_cv_env_CXXCPP_value= +ac_cv_env_CXXFLAGS_set=set +ac_cv_env_CXXFLAGS_value='-g -O2' +ac_cv_env_CXX_set= +ac_cv_env_CXX_value= +ac_cv_env_F77_set= +ac_cv_env_F77_value= +ac_cv_env_FFLAGS_set=set +ac_cv_env_FFLAGS_value='-g -O2' +ac_cv_env_LDFLAGS_set=set +ac_cv_env_LDFLAGS_value=-Wl,-Bsymbolic-functions +ac_cv_env_build_alias_set=set +ac_cv_env_build_alias_value=x86_64-linux-gnu +ac_cv_env_host_alias_set=set +ac_cv_env_host_alias_value=x86_64-linux-gnu +ac_cv_env_target_alias_set= +ac_cv_env_target_alias_value= +ac_cv_host=x86_64-pc-linux-gnu +ac_cv_host_alias=x86_64-linux-gnu +ac_cv_path_install='/usr/bin/install -c' +ac_cv_target=x86_64-pc-linux-gnu +ac_cv_target_alias=x86_64-linux-gnu + +## ----------------- ## +## Output variables. ## +## ----------------- ## + +ACLOCAL='' +AMDEPBACKSLASH='' +AMDEP_FALSE='' +AMDEP_TRUE='' +AMTAR='' +AR='' +ARTSCCONFIG='/opt/kde3/bin/artsc-config' +AUTOCONF='' +AUTODIRS='' +AUTOHEADER='' +AUTOMAKE='' +AWK='' +CC='' +CCDEPMODE='' +CFLAGS='-Wall -g -O2 -Wl,-z,defs' +CONF_FILES='' +CPP='' +CPPFLAGS='' +CXX='' +CXXCPP='' +CXXDEPMODE='' +CXXFLAGS='-g -O2' +DCOPIDL2CPP='/opt/kde3/bin/dcopidl2cpp' +DCOPIDL='/opt/kde3/bin/dcopidl' +DCOPIDLNG='' +DCOP_DEPENDENCIES='' +DEFS='' +DEPDIR='' +ECHO='echo' +ECHO_C='' +ECHO_N='-n' +ECHO_T='' +EGREP='' +ENABLE_PERMISSIVE_FLAG='' +EXEEXT='' +F77='' +FFLAGS='-g -O2' +FRAMEWORK_COREAUDIO='' +GMSGFMT='' +HAVE_GCC_VISIBILITY='' +INSTALL_DATA='install -p -c -m 644' +INSTALL_PROGRAM='${INSTALL} $(INSTALL_STRIP_FLAG)' +INSTALL_SCRIPT='${INSTALL}' +INSTALL_STRIP_PROGRAM='' +KCFG_DEPENDENCIES='' +KCONFIG_COMPILER='' +KDECONFIG='' +KDE_EXTRA_RPATH='' +KDE_INCLUDES='' +KDE_LDFLAGS='' +KDE_MT_LDFLAGS='' +KDE_MT_LIBS='' +KDE_NO_UNDEFINED='' +KDE_PLUGIN='' +KDE_RPATH='' +KDE_USE_CLOSURE_FALSE='' +KDE_USE_CLOSURE_TRUE='' +KDE_USE_FINAL_FALSE='' +KDE_USE_FINAL_TRUE='' +KDE_USE_NMCHECK_FALSE='' +KDE_USE_NMCHECK_TRUE='' +KDE_XSL_STYLESHEET='' +LDFLAGS='-Wl,-Bsymbolic-functions' +LDFLAGS_AS_NEEDED='' +LDFLAGS_NEW_DTAGS='' +LIBCOMPAT='' +LIBCRYPT='' +LIBDL='' +LIBJPEG='' +LIBOBJS='' +LIBPNG='' +LIBPTHREAD='' +LIBRESOLV='' +LIBS='' +LIBSM='' +LIBSOCKET='' +LIBTOOL='' +LIBUCB='' +LIBUTIL='' +LIBZ='' +LIB_GPSIM='' +LIB_KAB='' +LIB_KABC='' +LIB_KDECORE='' +LIB_KDEPIM='' +LIB_KDEPRINT='' +LIB_KDEUI='' +LIB_KDNSSD='' +LIB_KFILE='' +LIB_KFM='' +LIB_KHTML='' +LIB_KIMPROXY='' +LIB_KIO='' +LIB_KJS='' +LIB_KNEWSTUFF='' +LIB_KPARTS='' +LIB_KSPELL='' +LIB_KSYCOCA='' +LIB_KUTILS='' +LIB_POLL='' +LIB_QPE='' +LIB_QT='' +LIB_SMB='' +LIB_X11='' +LIB_XEXT='' +LIB_XRENDER='' +LN_S='' +LTLIBOBJS='' +MAKEINFO='' +MAKEKDEWIDGETS='' +MCOPIDL='/opt/kde3/bin/mcopidl' +MEINPROC='' +MOC='' +MSGFMT='' +NOOPT_CFLAGS='' +NOOPT_CXXFLAGS='' +OBJEXT='' +PACKAGE='' +PACKAGE_BUGREPORT='' +PACKAGE_NAME='' +PACKAGE_STRING='' +PACKAGE_TARNAME='' +PACKAGE_VERSION='' +PATH_SEPARATOR=':' +PERL='' +QTE_NORTTI='' +QT_INCLUDES='' +QT_LDFLAGS='' +RANLIB='' +SET_MAKE='' +SHELL='/bin/bash' +STRIP='' +TOPSUBDIRS='' +UIC='' +UIC_TR='' +USER_INCLUDES='' +USER_LDFLAGS='' +USE_EXCEPTIONS='' +USE_RTTI='' +USE_THREADS='' +VERSION='' +WOVERLOADED_VIRTUAL='' +XGETTEXT='' +XMLLINT='' +X_EXTRA_LIBS='' +X_INCLUDES='' +X_LDFLAGS='' +X_PRE_LIBS='' +X_RPATH='' +ac_ct_AR='' +ac_ct_CC='' +ac_ct_CXX='' +ac_ct_F77='' +ac_ct_RANLIB='' +ac_ct_STRIP='' +all_includes='' +all_libraries='' +am__include='' +am__quote='' +bindir='${exec_prefix}/bin' +build='x86_64-pc-linux-gnu' +build_alias='x86_64-linux-gnu' +build_cpu='x86_64' +build_os='linux-gnu' +build_vendor='pc' +datadir='${prefix}/share' +exec_prefix='NONE' +glib_cflags='' +host='x86_64-pc-linux-gnu' +host_alias='x86_64-linux-gnu' +host_cpu='x86_64' +host_os='linux-gnu' +host_vendor='pc' +include_ARTS_FALSE='' +include_ARTS_TRUE='' +include_x11_FALSE='' +include_x11_TRUE='' +includedir='/opt/kde3/include/kde' +infodir='/opt/kde3/share/info' +install_sh='' +kde_appsdir='/opt/kde3/share/applnk' +kde_bindir='/opt/kde3/bin' +kde_confdir='/etc/kde3' +kde_datadir='/opt/kde3/share/apps' +kde_htmldir='/opt/kde3/share/doc/kde/HTML' +kde_icondir='/opt/kde3/share/icons' +kde_includes='' +kde_kcfgdir='' +kde_libraries='' +kde_libs_htmldir='' +kde_libs_prefix='' +kde_locale='/opt/kde3/share/locale' +kde_mimedir='/opt/kde3/share/mimelnk' +kde_moduledir='/opt/kde3/lib/kde3' +kde_qtver='' +kde_servicesdir='/opt/kde3/share/services' +kde_servicetypesdir='/opt/kde3/share/servicetypes' +kde_sounddir='/opt/kde3/share/sounds' +kde_styledir='' +kde_templatesdir='/opt/kde3/share/templates' +kde_wallpaperdir='/opt/kde3/share/wallpapers' +kde_widgetdir='' +kdeinitdir='' +libdir='/opt/kde3/lib' +libexecdir='/opt/kde3/bin' +localstatedir='${prefix}/var' +mandir='/opt/kde3/share/man' +oldincludedir='/usr/include' +prefix='/opt/kde3' +program_transform_name='s,x,x,' +qt_includes='' +qt_libraries='' +sbindir='${exec_prefix}/sbin' +sharedstatedir='${prefix}/com' +sysconfdir='/etc' +target='x86_64-pc-linux-gnu' +target_alias='' +target_cpu='x86_64' +target_os='linux-gnu' +target_vendor='pc' +unsermake_enable_pch_FALSE='' +unsermake_enable_pch_TRUE='' +x_includes='NONE' +x_libraries='NONE' +xdg_appsdir='' +xdg_directorydir='' +xdg_menudir='' + +## ----------- ## +## confdefs.h. ## +## ----------- ## + +#define PACKAGE_BUGREPORT "" +#define PACKAGE_NAME "" +#define PACKAGE_STRING "" +#define PACKAGE_TARNAME "" +#define PACKAGE_VERSION "" + +configure: caught signal 2 +configure: exit 1 diff --git a/config.sub b/config.sub new file mode 100755 index 0000000..a39437d --- /dev/null +++ b/config.sub @@ -0,0 +1,1686 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 +# Free Software Foundation, Inc. + +timestamp='2009-04-17' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tile*) + basic_machine=tile-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure.files b/configure.files new file mode 100644 index 0000000..030bce8 --- /dev/null +++ b/configure.files @@ -0,0 +1,2 @@ +./admin/configure.in.min +configure.in.in diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..5d9d430 --- /dev/null +++ b/configure.in @@ -0,0 +1,248 @@ +dnl ======================================================= +dnl FILE: ./admin/configure.in.min +dnl ======================================================= + +dnl This file is part of the KDE libraries/packages +dnl Copyright (C) 2001 Stephan Kulow (coolo@kde.org) + +dnl This file is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Library General Public +dnl License as published by the Free Software Foundation; either +dnl version 2 of the License, or (at your option) any later version. + +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Library General Public License for more details. + +dnl You should have received a copy of the GNU Library General Public License +dnl along with this library; see the file COPYING.LIB. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +dnl Boston, MA 02110-1301, USA. + +# Original Author was Kalle@kde.org +# I lifted it in some mater. (Stephan Kulow) +# I used much code from Janos Farkas + +dnl Process this file with autoconf to produce a configure script. + +AC_INIT(acinclude.m4) dnl a source file from your sub dir + +dnl This is so we can use kde-common +AC_CONFIG_AUX_DIR(admin) + +dnl This ksh/zsh feature conflicts with `cd blah ; pwd` +unset CDPATH + +dnl Checking host/target/build systems, for make, install etc. +AC_CANONICAL_SYSTEM +dnl Perform program name transformation +AC_ARG_PROGRAM + +dnl Automake doc recommends to do this only here. (Janos) +AM_INIT_AUTOMAKE(ktechlab, 0.3) dnl searches for some needed programs + +KDE_SET_PREFIX + +dnl generate the config header +AM_CONFIG_HEADER(config.h) dnl at the distribution this done + +dnl Checks for programs. +AC_CHECK_COMPILERS +AC_ENABLE_SHARED(yes) +AC_ENABLE_STATIC(no) +KDE_PROG_LIBTOOL + +dnl for NLS support. Call them in this order! +dnl WITH_NLS is for the po files +AM_KDE_WITH_NLS + +KDE_USE_QT(3.2.0) +AC_PATH_KDE +dnl ======================================================= +dnl FILE: configure.in.in +dnl ======================================================= + +#MIN_CONFIG(3.2.0) + +dnl PACKAGE set before +AC_C_BIGENDIAN +AC_CHECK_KDEMAXPATHLEN + + +################################ +## BEGIN Check for gpsim 0.21 ## +################################ + +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +ktechlab_save_CXXFLAGS="$CXXFLAGS" + +AC_ARG_WITH(glib12, [ --with-glib12 force using glib 1.2.x [default=no]]) +if test "x$with_glib12" != "xyes" ; then + glib_cflags=`pkg-config --cflags glib-2.0` +else + glib_cflags=`glib-config --cflags` +fi +AC_SUBST(glib_cflags) + +CXXFLAGS="$glib_cflags" + +AC_MSG_CHECKING([for gpsim 0.21.4 availability]) +AC_TRY_COMPILE( + [ +#include +#include +#include +#include +void func() { (void)cycles; (void)initialize_gpsim_core(); (void)load_symbol_file(0,0); } + ], + [], + AC_MSG_RESULT( yes ) + have_gpsim_0_21_4=yes, + AC_MSG_RESULT( no ) +) + +AC_MSG_CHECKING([for gpsim 0.21.11 availability]) +AC_TRY_COMPILE( + [ +#include +#include +#include +#include +#include +#include +void func() { (void)cycles; (void)initialize_gpsim_core(); } + ], + [], + AC_MSG_RESULT( yes ) + have_gpsim_0_21_11=yes, + AC_MSG_RESULT( no ) +) + +AC_MSG_CHECKING([for gpsim 0.21.12 availability]) +AC_TRY_COMPILE( + [ +#include + ], + [], + AC_MSG_RESULT( yes ) + have_gpsim_0_21_12=yes, + AC_MSG_RESULT( no ) +) + +CXXFLAGS="$ktechlab_save_CXXFLAGS" +AC_LANG_RESTORE + +############################## +## END Check for gpsim 0.21 ## +############################## + + + +################################ +## BEGIN DO_NOT_COMPILE CHECK ## +################################ + +if test x$have_gpsim_0_21_12 == xyes; then + AC_DEFINE([GPSIM_0_21_12],[],[Gpsim 0.21.12 was found]) + CXXFLAGS="$CXXFLAGS $USE_EXCEPTIONS" +else + if test x$have_gpsim_0_21_4 != xyes; then + if test x$have_gpsim_0_21_11 != xyes; then + AC_DEFINE([NO_GPSIM],[],[Gpsim was not found]) + LIB_GPSIM="" + else + AC_DEFINE([GPSIM_0_21_11],[],[Gpsim 0.21.11 was found]) + fi + else + AC_DEFINE([GPSIM_0_21_4],[],[Gpsim 0.21.4 was found]) + fi +fi + +if test x$have_gpsim_0_21_4 == xyes || test x$have_gpsim_0_21_11 == xyes || test x$have_gpsim_0_21_12 == xyes; then + wi_cv_lib_readline=no + ac_save_LIBS="$LIBS" + # Note: $LIBCURSES is permitted to be empty. + for LIBREADLINE in "-lreadline" "-lreadline $LIBCURSES" "-lreadline -ltermcap" "-lreadline -lncurses" "-lreadline -lcurses" + do + LIBS="$ac_save_LIBS $LIBREADLINE" + LIB_GPSIM="$LIBREADLINE -lgpsim -lgpsim_eXdbm -lgpsimcli" + AC_TRY_RUN([ + /* program */ + #include + #include + + main(int argc, char **argv) + { + /* Note: don't actually call readline, since it may block; + * We just want to see if it (dynamic) linked in okay. + */ + if (argc == 0) /* never true */ + readline(0); + exit(0); + } + ],[ + # action if true + wi_cv_lib_readline=yes + ],[ + # action if false + wi_cv_lib_readline=no + ],[ + # action if cross compiling + wi_cv_lib_readline=no + ]) + + if test "$wi_cv_lib_readline" = yes ; then break ; fi + done + + LIBS="$ac_save_LIBS" +fi + +AC_SUBST(LIB_GPSIM) + +############################## +## END DO_NOT_COMPILE CHECK ## +############################## + +KDE_CREATE_SUBDIRSLIST +AC_CONFIG_FILES([ Makefile ]) +AC_CONFIG_FILES([ doc/Makefile ]) +AC_CONFIG_FILES([ doc/en/Makefile ]) +AC_CONFIG_FILES([ icons/Makefile ]) +AC_CONFIG_FILES([ icons/pics/Makefile ]) +AC_CONFIG_FILES([ microbe/Makefile ]) +AC_CONFIG_FILES([ po/Makefile ]) +AC_CONFIG_FILES([ src/Makefile ]) +AC_CONFIG_FILES([ src/core/Makefile ]) +AC_CONFIG_FILES([ src/drawparts/Makefile ]) +AC_CONFIG_FILES([ src/electronics/Makefile ]) +AC_CONFIG_FILES([ src/electronics/components/Makefile ]) +AC_CONFIG_FILES([ src/electronics/simulation/Makefile ]) +AC_CONFIG_FILES([ src/flowparts/Makefile ]) +AC_CONFIG_FILES([ src/gui/Makefile ]) +AC_CONFIG_FILES([ src/languages/Makefile ]) +AC_CONFIG_FILES([ src/mechanics/Makefile ]) +AC_CONFIG_FILES([ src/micro/Makefile ]) +AC_OUTPUT +if test x$have_gpsim_0_21_4 != xyes; then + if test x$have_gpsim_0_21_11 != xyes; then + echo "" + echo "################################################################################" + echo "# WARNING: gpsim support will not be compiled as gpsim >= 0.21.4 was not found #" + echo "################################################################################" + fi +fi + +if test "$all_tests" = "bad"; then + if test ! "$cache_file" = "/dev/null"; then + echo "" + echo "Please remove the file $cache_file after changing your setup" + echo "so that configure will find the changes next time." + echo "" + fi +else + echo "" + echo "Good - your configure finished. Start make now" + echo "" +fi diff --git a/configure.in.in b/configure.in.in new file mode 100644 index 0000000..747ac83 --- /dev/null +++ b/configure.in.in @@ -0,0 +1,142 @@ +#MIN_CONFIG(3.2.0) + +AM_INIT_AUTOMAKE(ktechlab, 0.3) +AC_C_BIGENDIAN +AC_CHECK_KDEMAXPATHLEN + + +################################ +## BEGIN Check for gpsim 0.21 ## +################################ + +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +ktechlab_save_CXXFLAGS="$CXXFLAGS" + +AC_ARG_WITH(glib12, [ --with-glib12 force using glib 1.2.x [default=no]]) +if test "x$with_glib12" != "xyes" ; then + glib_cflags=`pkg-config --cflags glib-2.0` +else + glib_cflags=`glib-config --cflags` +fi +AC_SUBST(glib_cflags) + +CXXFLAGS="$glib_cflags" + +AC_MSG_CHECKING([for gpsim 0.21.4 availability]) +AC_TRY_COMPILE( + [ +#include +#include +#include +#include +void func() { (void)cycles; (void)initialize_gpsim_core(); (void)load_symbol_file(0,0); } + ], + [], + AC_MSG_RESULT( yes ) + have_gpsim_0_21_4=yes, + AC_MSG_RESULT( no ) +) + +AC_MSG_CHECKING([for gpsim 0.21.11 availability]) +AC_TRY_COMPILE( + [ +#include +#include +#include +#include +#include +#include +void func() { (void)cycles; (void)initialize_gpsim_core(); } + ], + [], + AC_MSG_RESULT( yes ) + have_gpsim_0_21_11=yes, + AC_MSG_RESULT( no ) +) + +AC_MSG_CHECKING([for gpsim 0.21.12 availability]) +AC_TRY_COMPILE( + [ +#include + ], + [], + AC_MSG_RESULT( yes ) + have_gpsim_0_21_12=yes, + AC_MSG_RESULT( no ) +) + +CXXFLAGS="$ktechlab_save_CXXFLAGS" +AC_LANG_RESTORE + +############################## +## END Check for gpsim 0.21 ## +############################## + + + +################################ +## BEGIN DO_NOT_COMPILE CHECK ## +################################ + +if test x$have_gpsim_0_21_12 == xyes; then + AC_DEFINE([GPSIM_0_21_12],[],[Gpsim 0.21.12 was found]) + CXXFLAGS="$CXXFLAGS $USE_EXCEPTIONS" +else + if test x$have_gpsim_0_21_4 != xyes; then + if test x$have_gpsim_0_21_11 != xyes; then + AC_DEFINE([NO_GPSIM],[],[Gpsim was not found]) + LIB_GPSIM="" + else + AC_DEFINE([GPSIM_0_21_11],[],[Gpsim 0.21.11 was found]) + fi + else + AC_DEFINE([GPSIM_0_21_4],[],[Gpsim 0.21.4 was found]) + fi +fi + +if test x$have_gpsim_0_21_4 == xyes || test x$have_gpsim_0_21_11 == xyes || test x$have_gpsim_0_21_12 == xyes; then + wi_cv_lib_readline=no + ac_save_LIBS="$LIBS" + # Note: $LIBCURSES is permitted to be empty. + for LIBREADLINE in "-lreadline" "-lreadline $LIBCURSES" "-lreadline -ltermcap" "-lreadline -lncurses" "-lreadline -lcurses" + do + LIBS="$ac_save_LIBS $LIBREADLINE" + LIB_GPSIM="$LIBREADLINE -lgpsim -lgpsim_eXdbm -lgpsimcli" + AC_TRY_RUN([ + /* program */ + #include + #include + + main(int argc, char **argv) + { + /* Note: don't actually call readline, since it may block; + * We just want to see if it (dynamic) linked in okay. + */ + if (argc == 0) /* never true */ + readline(0); + exit(0); + } + ],[ + # action if true + wi_cv_lib_readline=yes + ],[ + # action if false + wi_cv_lib_readline=no + ],[ + # action if cross compiling + wi_cv_lib_readline=no + ]) + + if test "$wi_cv_lib_readline" = yes ; then break ; fi + done + + LIBS="$ac_save_LIBS" +fi + +AC_SUBST(LIB_GPSIM) + +############################## +## END DO_NOT_COMPILE CHECK ## +############################## + diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..e946108 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,7 @@ +# the SUBDIRS is filled automatically by am_edit. If files are +# in this directory they are installed into the english dir + +KDE_LANG = en +KDE_DOCS = AUTO +SUBDIRS = $(AUTODIRS) + diff --git a/doc/en/Makefile.am b/doc/en/Makefile.am new file mode 100644 index 0000000..65e8484 --- /dev/null +++ b/doc/en/Makefile.am @@ -0,0 +1,7 @@ +KDE_DOCS = ktechlab +# KDE_MANS = ktechlab +KDE_LANG = en +# KDE_DOCS = AUTO + +kde_docs_KDEDOCS = debugging.docbook circuits.docbook flowcode.docbook \ + quick.docbook faq.docbook picprograms.docbook diff --git a/doc/en/circuits.docbook b/doc/en/circuits.docbook new file mode 100644 index 0000000..fb7619a --- /dev/null +++ b/doc/en/circuits.docbook @@ -0,0 +1,84 @@ + + + Circuits + + + Placing components + On the left, you'll find the Components tab. + + Dragging a component from the sidebar into the circuit will place it under the mouse cursor. Alternatively, you can double click on an item in the Components sidebar to repeatedly add it to the circuit. In this mode, a copy of the selected component will be placed repeatedly on mouse left-clicking until either Escape is pressed, or the mouse is right-clicked. + + To reposition a component, left-click and drag. You'll find it snapping to the underlying grid. If you drag the component out of the right or bottom edges of the workarea, the workarea will resize itself to accomodate. + + All components have a notion of orientation; 0, 90, 180 and 270 degrees. Those that aren't symmetrical about an axis can also be flipped. To rotate a selection of components, either right click and select from the Orientation menu, or click on the rotate buttons in the toolbar. The latter can also be accessed by pressing the "[" and "]" keys (familiar to Inkscape users). The Item sidebar (on the right) provides a powerful method of setting the orientation by providing previews of the components. Flipping components is also only possibly via the Item sidebar. + + + + Connecting Components + There are two modes for creating connections (wires): automatic, and manual. These modes are selected via the "Connection Routing Mode" pulldown menu in the toolbar. Experiment with both - automatic routing is often better for small circuits, whereas more complex circuits may need manual routing. + + In automatic mode, create a connection by dragging from either a component pin or an existing connection, and releasing the mouse over the desired pin or connection. You'll see the straight-line being drawn turn orange when a valid connection will be created on mouse release. If the line you're drawing is black, it's either because there's nothing beneath the mouse cursor, or you're attempting to connect together two items which are already connected. When flowcharting, the criteria for a valid connection are more complex - but we'll get to that later. + + The best way to get a feel for manual connection routing is by experimenting with it. Click on the starting pin or connection, and then extend the proto-connector by moving the mouse away from where you clicked. To place a corner, left-click. To cancel drawing the connection, either press escape, or right-click the mouse. + + &kappname; tries its best to maintain the routes your connections take. However, if dragging a component results in the end points of a connection moving relative to each other, &kappname; will be forced to redraw the connection using auto-routing. Before moving a component, you can see which connectors will have to be rerouted - as they will turn grey on clicking. + + To remove an existing connection, select it by drawing a small select-rectangle over part of the connector, and hit delete. + + + + Component Attributes + Most components will have editable attributes, such as the resistance for resistors. By default, you can edit simple attributes in the toolbar, when a group of the same type of components are selected. If your selection contains a mixture of different types of components (such as resistors and capacitors), then no attributes will be displayed for editing. + + Some components have more advanced attributes which are not accesible via the toolbar. These are found in the Item sidebar on the right. The diode, for example, has a variety of behavioural characteristics that you can edit here. + + If your selection of components have different values for their attributes (for example, different resistances for a selection of resistors), the Item sidebar will have the disagreeing attributes greyed-out. You can enable these by clicking the "Merge properties" button. + + The "Defaults" button will reset the component attributes to the ones it had on creation. + + There is one type of attribute that cannot be editable by either the toolbar or Item sidebar - multiline text. Double clicking on the item will bring up a dialog box where the text can be entered. + + + + Simulation + By default, the simulation will be running when you create a new circuit. The status of the simulation is displayed in the lower right of a circuit view, and can be changed via the Tools menu. Firstly - a little explanation on how the Simulator works. This should allow you to make the most out of it. + + When a circuit is created or modified, the affected areas are partitioned up into groups of pins and connections that can be considered independent. Each group is then simulated as a seperate entity (although still interacting via the components), with the simulation provided dependent on the group's complexity. Complex groups, such as those involving nonlinear components like LEDs, are slow to simulate. Groups that contain only logic pins, of which only one controls the value on those pins, are the fastest to simulate. + + The results of the simulation are provided through several graphical means. + + The pins on the components will display voltage sidebars. These are coloured orange for positive voltage, and blue for negative voltage. Their length depends on the voltage level, and their width on the amount of current flowing through the pin. These can be turned off in the Work Area tab of the Configuration dialog. + + Hovering the mouse over a pin or connection will display a small tooltip showing the voltage and current at that point in the circuit. Several components also provide graphical feedback - for example, LEDs and voltmeters or ammeters. + + Lastly, there is the oscilloscope, discussed in the next section. + + + + Oscilloscope + The oscilloscope can record logic, voltage and current data. The logic probe is optimized for storing boolean samples, and so should be used instead of the voltage probe when measuring logic. + + To collect data, create a new probe component, and attach it to an appropriate point in the circuit. You'll see the output immediately drawn in the oscilloscope. Adding more probes will squash the outputs next to each other - you can reposition these by dragging the arrows on the left of the oscilloscope view, and change their colours via the probe's attributes. + + For voltage and current probes, the range of input values can be adjusted in the "Item Editor" sidebar on the right. + + Zooming is controlled by a slider. The scaling is logarithmic; for every few pixels that the slider moves along, the zoom factor will be multipled by a constant. &kappname; simulates logic to a maximum precision of 1 microsecond, and at maximum zoom level, one microsecond is represented by 8 pixels. + + When the scrollbar is dragged to the end, it will remain there as new data is recorded. Otherwise, the position of the scrollbar remains fixed in time. The oscilloscope view can also be moved forwards and backwards by left-clicking and dragging the view. Due to limitations of the underlying widget system, scrolling will be very granular at maximum zoom. + + Right-clicking on the oscilloscope view brings up a menu where you can control the number of times the oscilloscope view is updated. This allows for either a smoother display, or reducing CPU usage. + + + + Subcircuits + Subcircuits offer a reusable and tidy way of using a circuit, when you're only interested in interacting with external connections to the circuit. The subcircuit is creating as an IC, with the pins acting as the interaction with the internal circuit. + + First, the circuit to be used in as a template for creating a subcircuit from must be constructed. The points of interaction are defined via "External Connection" components. These must be connected up, and positioned where you want the pin to be positioned on the subcircuit IC. + + Next, select the group of components and external connections to be turned into a subcircuit, and select "Create Subcircuit" from the right-click menu. You'll be offered to enter a name for the subcircuit. Once created, the name will popup in the Component selector under the Subcircuits selection. This can be treated as any normal component - with the additional option of removing it by right-clicking on the item and selecting Remove. + + + + + + diff --git a/doc/en/debugging.docbook b/doc/en/debugging.docbook new file mode 100644 index 0000000..af1a864 --- /dev/null +++ b/doc/en/debugging.docbook @@ -0,0 +1,35 @@ + + + Debugging + + + Starting the Debugger + + Debugging support is provided for Assembly, SDCC and Microbe, when they are open as a text document. From here, stepping is controlled via the Debug menu. There are two methods of starting the debugger. + + If the PIC program is already running in a circuit, then double-clicking on the PIC component will open up the program. For assembly PIC programs, the debugger for that text document will be linked into the PIC component. In this case, the debug menu cannot stop the PIC program - as this is owned by the PIC component. + + If the assembly file is already opened, then the debugger can be run via the Debug menu. After compiling the program, the debugger will be ready, with the PIC program paused at the first instruction. Note that when debugging high level languages, the current execution point will not be shown if there is no line that corresponds to the first assembly instruction to be executed. In this case, clicking next will bring the execution point to the first line in the program. + + + + Controlling the Debugger + + The debugger can be in one of two modes: running, and stepping. While running, the PIC program will be simulated in realtime. To allow stepping, the PIC program must be paused - either by clicking on Interrupt in the Debug menu, or clicking on the pause button on the PIC component. + + In stepping mode, a green arrow in the margin of the text document indicates the next line to be executed (familiar to KDevelop users). It may be useful to turn on the icon border via the View menu (it can be permanently turned on via the Editor Settings dialog). + + There are three types of stepping: + + + Step into - This executes the current instruction. The green arrow is moved onto the next line to be executed. + Step over - If the next instruction to be executed is a call, or similar, then this will "step over" the call, returning to stepping mode once the call has returned. Otherwise, stepping over an instruction behaves identically to step. To put it technically - the initial stack level is recorded, and the program execution is paused once the stack level returns to its initial level. + Step out - If the current execution is inside a call, or similar, then this will wait until the call returns. Similarly to stepping over, this is equivalent to waiting until the stack level returns to one less than the initial level, if the initial level is greater than zero. + + + Breakpoints allow the execution to be paused when the PIC program reaches a given instruction. To toggle a breakpoint on the line containing the cursor, either use the Debug menu, or click on the icon border of the text document. + + The "Symbol Viewer" sidebar on the right shows the values of the Special Function Registers. To find out the value of a variable in the General Purpose Registers, you can hover your mouse over the variable name in an instruction that operates on that register. Note that the radix selection in the Symbol Viewer also controls how the value is displayed when hovering over a variable. + + + diff --git a/doc/en/faq.docbook b/doc/en/faq.docbook new file mode 100644 index 0000000..a68e46e --- /dev/null +++ b/doc/en/faq.docbook @@ -0,0 +1,68 @@ + + +FAQ + + + + + Configure can't find gpsim + + + + Configure will attempt to compile several files to test for gpsim presence; testing for versions 0.21.4, 0.21.11 and 0.21.12. These files uses part of the gpsim API, that is also used by &kappname;, and was introduced in the respective gpsim versions. If it fails in compiling this program, it will display the warning to the user, and PIC simulation support will not be compiled into &kappname;. There are a number of possibly reasons for finding gpsim to fail: + + + gpsim >= 0.21.4 is not installed. &kappname; does not support gpsim-0.21.2 or gpsim-0.20.14 (or any earlier versions). Later versions may work; but this cannot be tested before they are released. The latest gpsim can be obtained from the gpsim website. + Gpsim is installed, but the header files could not be found. If gpsim is installed in a non-standard location, you may need to specify the location of the header files with "./configure --with-extra-includes=DIR". It is also likely you'll need to specify a library location with the configure option "--with-extra-lib" if the includes are in a non-standard location. + Gpsim is installed and the headers are somewhere where configure can find them, but there is some other glib craziness occuring. + + + Configure generates the file config.log which will contain details of exactly what went wrong. Searching for gpsim in this log should help you decide what's happened. As an example, here is part of the config.log file where one of the gpsim header files is missing: + + Possible config.log output where gpsim detection failed + +configure:30956: checking for gpsim 0.21.4 availability +configure:31009: g++ -c -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include +-DQT_THREAD_SUPPORT -O3 -march=athlon-xp -mcpu=athlon-xp -D_REENTRANT +conftest.cc >&5 +conftest.cc:48:35: gpsim/gpsim_interface.h: No such file or directory + + + If the config.log doesn't help, please contact the &kappname; developers with the relevant parts of config.log attached. + + + + + &kappname; crashes when running a PIC program + + + + Version 0.21.11 of gpsim contains a bug that may cause &kappname; to crash on the second running of a PIC program. This bug has since been fixed in gpsim-cvs. The &kappname; website provides a patched version of the stable release of gpsim that fixes this bug. + + + + + + High Level Language (HLL) debugging does not work + + + + Version 0.21.11 of gpsim contains a bug preventing HLL debugging from working. This bug has since been fixed in gpsim-cvs. The &kappname; website provides a patched version of the stable release of gpsim that fixes this bug. + + + + + + &kappname; uses lots of CPU + + + + There are several possible causes. Simulation of circuits that contain both reactive and nonlinear components (such as capacitors and transistors) take a lot of CPU time to simulate. You can pause and resume the simulation via the Tools menu. + + Drawing of the work area (in particular, redrawing lots of rapidly updating voltage bars on pins) is also CPU intensive. You can reduce the refresh rate or turn off the voltage bars via the Settings dialog. The refresh rate of the Oscilloscope can also be reduced by right clicking on its display. + + Note that the next major release of &kappname; will be a lot faster in both displaying the work area and simulating reactive and nonlinear components. + + + + diff --git a/doc/en/flowcode.docbook b/doc/en/flowcode.docbook new file mode 100644 index 0000000..d3af461 --- /dev/null +++ b/doc/en/flowcode.docbook @@ -0,0 +1,52 @@ + + + &flowcode; + + + Introduction + + &flowcode; allows for very quick and easy construction of a PIC program. After the user has constructed a flowchart from the program parts available, &kappname; can then convert the flowchart into a number of formats. To output hex, for example, the following chain of conversions takes place: + + + The &flowcode; is converted to µbe;; a high-level language whose compiler is distributed with &kappname;. + The microbe executable then compiles the µbe; file to PIC assembly. + Finally, gpasm takes the PIC assembly file, and outputs the hex for the program. + + + Of course, if you don't have gputils installed - with which gpasm is distributed - then the last step can't be performed. + + + + + Creating a Program + + Every &flowcode; program needs a unique starting point - this is the place where your program will be run from on PIC startup. To define this point, open up the FlowParts sidebar on the left, and drag across the Start part. &kappname; will only allow you to use one of these. + + You can then construct your program by using the predefined parts on the left - or insert code of your own (in assembly or µbe; format) via the Embed part. The flow of the program is controlled via the connections between the FlowParts - offers more detail on creating connections. + + &flowcode; imposes limitations in addition to those of Circuits on what can be connected. For example, each FlowPart can only have one output connection. Additional limitations are described in . + + + + PIC Settings + + When you create a new &flowcode; document, you'll notice a picture of the PIC you're using in the top-left corner of the work area. This represents the initial settings of the PIC. + + Each pin shown on the picture of the PIC shows the initial type of pin (input or output), and its initial state (high or low). You can change these by dragging the pin to set the type, and clicking on it to toggle its state. + + The Settings dialog, invoked by clicking on the Settings button, also allows you to edit the initial pin types and states - in this case, by editing the binary values written to the PORT and TRIS registers. As well as pin settings though, the dialog allows editing of the initial values of variables in the PIC program. + + At the bottom, there is a list of currently defined pin maps, as well as buttons to manipulate them. Pin maps are used to specify how a seven segment or a keypad is connected to a PIC. To use the Seven Segment or the Keypad &flowcode; parts, you will need to define a pin map here first. + + + + + Nestling &flowcode; + + Many FlowParts, such as subroutines and loops, can contain code of their own. After creating such a container, FlowParts can be added by either dragging or dropping them into the container. The container will be highlighted to indicate that it will become the new parent of the FlowPart. + + The container takes responbility for FlowParts nestled inside. If the expand button is unclicked, all contained FlowParts will be hidden - and likewise, the contents will be shown when the expand button is clicked again. Connections cannot be made between FlowParts in different containers, and the contents of a container will be moved about along with the container. + + + + diff --git a/doc/en/index.docbook b/doc/en/index.docbook new file mode 100644 index 0000000..707dd17 --- /dev/null +++ b/doc/en/index.docbook @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + +]> + + + + The KTechlab Handbook + + + David + Saxton +
david@bluehaze.org
+
+ + Daniel + Clarke + +
+ 2005-12-27 + 0.3 + + KTechlab is an IDE for microcontrollers and electronics. + + + KTechlab + KDE + Development + Electronics + Simulation + PICs + Microbe + +
+ + &ktechlab-quick; + &ktechlab-pic-programs; + &ktechlab-circuits; + &ktechlab-flowcode; + &ktechlab-microbe; + &ktechlab-debugging; + &ktechlab-faq; +
diff --git a/doc/en/microbe.docbook b/doc/en/microbe.docbook new file mode 100644 index 0000000..8f5fd13 --- /dev/null +++ b/doc/en/microbe.docbook @@ -0,0 +1,422 @@ + + +µbe; + + Introduction and General Syntax + + Microbe compiles programs written in the custom language for PICs, as a companion program to &kappname;. The syntax has been designed to suit a &flowcode; program. + + The syntax for running microbe from the commandline is: + + microbe [options] [input.microbe] [output.asm] + + where options are: + + --show-source - Puts each line of µbe; source code as a comment in the assembly output before the assembly instructions themselves for that line. + --no-optimize - Prevent optimization of the instructions generated from the source. Optimization is usually safe, and so this option is mainly used for debugging. + + + The .microbe input file must identify the target PIC by inserting the PIC name at the top of the .microbe file; e.g. the name of a PIC16F84 is "P16F84". + + Simple complete µbe; program + +P16F84 + +a = 0 +repeat +{ + PORTA = a + a = a + 1 +} +until a == 5 + +end + + + + + Naming conventions + + The following rules apply to variable names and labels: + + They can only contain alphanumerical characters [a..z][A..Z][0..9] and the underscore "_". + They are case-sensitive. + They cannot start with a number. + They should not start with "__" (double underscore), as this is reserved for use by the compiler. + + + + + + Bracing conventions + + Curly braces, {}, indicate the start and end of a code block. + + They can appear anywhere before the start and after the end of the code block. + + Examples of acceptable code blocks: + +statement1 { + some code +} + +statement2 { + other code } + + +statement3 +{ + other code +} + + +statement5 { + code block +} statement6 + + + + Commenting + + Commenting is similar to C. // comments out the rest of the line. /* and */ denote a multiline comment. + +// This is a comment +x = 2 +/* As is this +multiline comment */ + + + + + Program Structure + + The PIC id must be inserted at the top of the program. The end of the main program is denoted with "end". Subroutines must placed after "end". + + + + + Subroutines + + A subroutine can be called from anywhere in the code. Syntax: + + +sub SubName +{ + // Code... +} + The subroutine is called with "call SubName". + + + + + µbe; language reference + + if + Conditional branching. + + Syntax: + if [expression] then [statement] + or + +if [expression] then +{ + [statement block] +} + + Similarly for else: + else [statement] + or + +else +{ + [statement block] +} + + + if + +if porta.0 is high then +{ + delay 200 +} +else +{ + delay 300 +} + + + + + alias + Aliases one string to another. Syntax: + alias [from] [to] + + + + + repeat + Executes the statement block repeatedly until expression evaluates to true. + + The evaluation of the expression is performed after the statement block, so the statement block will always be executed at least once. Syntax: + +repeat +{ + [statement block] +} +until [expression] + + + + +while + + Similar to repeat, this repeatedly executes the statement block. However, the expression is evaluated before execution, not after. So if the expression evaluates to false on the first pass, then the statement block will not get executed. + + Syntax: + +while [expression] +{ + [statement block] +} + + + + + + goto + + This causes execution of the code to continue at the next statement after the label specified. + + Goto syntax: + goto [labelname] + + Label syntax: + labelname: + + It is often considered good programming practice to avoid the use of goto. Use of control statements and subroutines will result in a much more readable program. + + + goto + +goto MyLabel + +... + +[MyLabel]: +// Code will continue at this point + + + + + call + + Calls a subroutine. + + Syntax: + call [SubName] + where SubName is the name of the subroutine to be called. + + + + + delay + + This causes the code execution to stop for the given period of time. The interval is in milliseconds. + + Syntax: + delay [interval] + + At present, µbe; assumes that the PIC is operating at a frequency of 4Mhz - i.e. each instruction takes 1 microsecond to execute. If this is not the case, the interval must be adjusted proportionately. + + + + + sevenseg + This is used to define the pin mapping for a (common cathode) seven segment display connected to the PIC. Syntax: + sevenseg [name] [a] [b] [c] [d] [e] [f] [g] + + where [a]...[g] are the PIC pins to which the respective segments of the seven segment display are attached. The pins can be written either as PORTX.N or RXN. + + + To display a number on the seven segment, the pin mapping is treated as a write only variable. + + Defining and outputting to a seven segment + +sevenseg seg1 RB0 RB1 RB2 RB3 RB4 RB5 RB6 +seg1 = x + 2 + + + + + + keypad + This is used to define the pin mapping for a keypad connected to the PIC. Syntax: + keypad [name] [row 1] ... [row 4] [column 1] ... [column n] + + where [row 1] ... [row 4] and [column 1] ... [column n] are the PIC pins to which the respective rows and columns of the keypad are attached (at the moment, the number of rows is not changeable). See (above) for more information on pin mappings. + + + The columns of the keypad should be pulled down via 100k resistors to ground. The row pins must be configured as outputs and the column pins as inputs. Once the keypad has been defined, it is treated as a read only variable. + + Defining and reading from a keypad + +keypad keypad1 RB0 RB1 RB2 RB3 RB4 RB5 RB6 +x = keypad1 + + + + + By default, the values returned for a keypad are: + + The value of the number if it is a numeric key (1 to 3 along top row; hexadecimal A to D down the fourth column and continuing for each extra column). + 253 for the key in row 4, column 1. + 254 for the key in row 4, column 3. + + These values can be redefined by using the alias command, where the name of the key in row x, column y (rows and columns starting at 1), is Keypad_x_y. For example, to give the star key on a 4x3 keypad the value zero, the following alias would be used: + + Aliasing a keypad key to a value + alias Keypad_4_1 0 + + + + + + +PIC I/O + + + Port Direction + + The port direction is set by assigning a value to TRIS*, where * is the port letter. For example: + + Setting port directions + TRISB = b'01111001' + + + The above sets pins RB1, RB2 and RB7 on PORTB as outputs, and the other pins on PORTB as inputs. In this example, b'01111001' is a binary representation of the output type. The 1 on the right represents an output on RB0, and the 0 on the left represents an input on RB7. + + + + + Port I/O + + The port can be treated as a variable. For example: + + + Writing to a port + x = PORTA + + + + The above assigns the value of PORTA to the variable x. + + + + + Pin I/O + + Each pin on a port is obtained by prefixing the pin number by the port name; e.g. Pin 2 (starting from Pin 0) on PORTA is known as + PORTA.0. + + The syntax to set a pin state is: + PORTX.N = STATE + where STATE can be high or low. + + The syntax to test a pin state is: + if PORTX.N is STATE then + + Combining these examples, we have: + + Setting and testing pin state + +TRISA = 0 +TRISB = 255 +if PORTA.3 is high then +{ + PORTB.5 = low +} +else +{ + PORTB = PORTA + 15 +} + + + + + +Variables + + All variables are 8-bit unsigned integers, giving a range from 0 to 255. + + µbe; supports the typical unary operations (acting on one variable) and binary operations (acting on two variables) that are supported by the PIC. In addition, µbe; also supports division and multiplication. + + + Unary Operations + + + rotateleft x - Rotates the variable x left through carry. + rotateright x - Rotates the variable x right through carry. + increment x - Increments the variable x. If x has a value of 255, then x wraps round to 0. + decrement x - Decrements the variable x. If x has a value of 0, then x wraps round to 255. + + + + + + Arithmetic + + Supported operations: + + Addition: x + y + Subtraction: x - y + Multiplication: x * y + Division: x / y + Binary XOR: x XOR y + Binary AND: x AND y + Binary OR: x OR y + + + + + + Comparison + + Supported operations: + + Equals: x == y + Does not equal: x != y + Is greater than: x > y + Is less than: x < y + Is greater than or equal to: x >= y + Is less than or equal to: x <= y + + + For example: + + Comparison + +if PORTA >= 5 then +{ + ... +} + + + + + + diff --git a/doc/en/picprograms.docbook b/doc/en/picprograms.docbook new file mode 100644 index 0000000..e9e3306 --- /dev/null +++ b/doc/en/picprograms.docbook @@ -0,0 +1,44 @@ + + + PIC Programs + + + Manipulation + + When you create a FlowCode or a Text document, you'll notice a drop down menu in the toolbar with a rocket icon. From here, you can manipulate your PIC program; changing it to different forms. + + + Convert to µbe; - This is used only in &flowcode; documents. This is explained further in . + + Convert to Assembly - This can be used in four contexts. When a &flowcode; document is open, it will output the &flowcode; as assembly instructions. When a µbe; document is open, it will invoke the microbe program distributed with &kappname; to compile the program. Similarly, if a C program is open, it will attempt to compile it via SDCC. When a text document containing PIC hex is open, it will invoke gpdasm to disassemble the hex. + + Convert to Hex - This can also be used in four contexts. As with Convert to Assembly, this can be used with &flowcode;, µbe; and C documents. It will also be enabled when an assembly document is open to assemble it via gpasm. + + Upload to PIC - This assembles the PIC program currently being edited, and uploads it using the programmer that the user has selected. + + + None of these actions require the current document to be saved - very useful for when a quick program is required. For non-PIC targets, the Output Dialog invoked on clicking on one of these actions can either output the result (always text in the above three cases) to a fresh document, or to a file. If the output is saved to file, it also provides options to load the file after creation, and adding the newly created file to the open project (if one is open). + + Note that you can make &kappname; always use the same view for displaying the outputed content by selecting the option under General Settings. + + + + Uploading + + &kappname; uses third-party programmers to upload programs to PICs. A variety of common programmers come predefined. Others can be added via the Settings dialog. See the &kappname; website for more information. + + The list of ports is obtained from scanning for serial and parallel ports that are readable and writable. Serial ports are looked for in: + + /dev/ttyS[0..7] + /dev/tts/[0..7] + /dev/ttyUSB[0..7] + /dev/usb/tts/[0..7] + + Parallel ports are looked for in: + + /dev/usb/parport[0..7] + /dev/usb/parports/[0..7] + + + + diff --git a/doc/en/quick.docbook b/doc/en/quick.docbook new file mode 100644 index 0000000..3785ba7 --- /dev/null +++ b/doc/en/quick.docbook @@ -0,0 +1,42 @@ + + + Quick Tour + + + Introduction + + &kappname; is an IDE for electronic circuits and microcontrollers. It can perform simulation a variety of components (logic, integrated, linear, nonlinear and reactive), simulation and debugging of PIC microcontrollers via gpsim, and comes with its own closely-linked and complementary high level languages: &flowcode; and µbe;. + + It has been designed to be as easy to use and unintrusive as possible; all components and FlowParts have context sensitive help, and simulating electronics is as simple as dragging components onto the work area and creating connectors that autoroute themselves between their pins. &flowcode; allows users new to PICs to instantly create their own programs, while the electronic simulation allows stepping through a PIC's assembly program inside a circuit. + + + + Documents + To get started in &kappname;, you will need to create a new document, whose type will depend on your task: + + + &flowcode; Document - Construct a PIC program via flowcharting. + Circuit Document - Simulate electronics circuits and microcontrollers. + µbe; Document - High level language for PICs, also used by &flowcode; to generate assembly. + Assembly Document - Start writing a PIC assembly program. + + + &kappname; uses a Document-View model, in that the Document logic is completely seperate from open views of the document. This allows several views of the same file. + + On creating a new document, the view is created in a seperate tab. Each tab can support any number of views, tiled in any arbitary pattern. This allows, for example, simulating a PIC program in circuit, while stepping through the program in an assembly document in the same tab. + + The contents of tabs can be duplicated by dragging the tab to an empty area on the tab bar. They can be inserted into an existing tab by dragging it onto that tab. + + Detailed instructions on the above documents can be found in their own respective chapters. + + + + Drawing + + In Circuit and &flowcode; documents, there are several drawing tools available, including text. These are available by clicking on the paintbrush icon in the toolbar. To draw, drag the mouse to form either a shape or a line appropriate to the drawing tool in use. + + When a drawing is selected, it can be resized by dragging its handles. Holding down shift while dragging will snap the handle to the underlying grid. Each tool has basic options accessible from the toolbar, such as colours. There are also more advanced options found in the Item sidebar, such as line and cap styles. + + + + \ No newline at end of file diff --git a/icons/Makefile.am b/icons/Makefile.am new file mode 100644 index 0000000..5e7e941 --- /dev/null +++ b/icons/Makefile.am @@ -0,0 +1,6 @@ + +METASOURCES = AUTO + +KDE_ICON = AUTO + +SUBDIRS = pics diff --git a/icons/hi128-app-ktechlab.png b/icons/hi128-app-ktechlab.png new file mode 100644 index 0000000..416dcb0 Binary files /dev/null and b/icons/hi128-app-ktechlab.png differ diff --git a/icons/hi128-app-microbe.png b/icons/hi128-app-microbe.png new file mode 100644 index 0000000..a06855a Binary files /dev/null and b/icons/hi128-app-microbe.png differ diff --git a/icons/hi128-mime-ktechlab_circuit.png b/icons/hi128-mime-ktechlab_circuit.png new file mode 100644 index 0000000..349933e Binary files /dev/null and b/icons/hi128-mime-ktechlab_circuit.png differ diff --git a/icons/hi128-mime-ktechlab_flowcode.png b/icons/hi128-mime-ktechlab_flowcode.png new file mode 100644 index 0000000..1a5ccf5 Binary files /dev/null and b/icons/hi128-mime-ktechlab_flowcode.png differ diff --git a/icons/hi128-mime-ktechlab_microbe.png b/icons/hi128-mime-ktechlab_microbe.png new file mode 100644 index 0000000..cc9093f Binary files /dev/null and b/icons/hi128-mime-ktechlab_microbe.png differ diff --git a/icons/hi16-action-convert_to_assembly.png b/icons/hi16-action-convert_to_assembly.png new file mode 100644 index 0000000..7b0756a Binary files /dev/null and b/icons/hi16-action-convert_to_assembly.png differ diff --git a/icons/hi16-action-convert_to_hex.png b/icons/hi16-action-convert_to_hex.png new file mode 100644 index 0000000..1e39b3f Binary files /dev/null and b/icons/hi16-action-convert_to_hex.png differ diff --git a/icons/hi16-action-convert_to_microbe.png b/icons/hi16-action-convert_to_microbe.png new file mode 100644 index 0000000..1cc924c Binary files /dev/null and b/icons/hi16-action-convert_to_microbe.png differ diff --git a/icons/hi16-action-convert_to_pic.png b/icons/hi16-action-convert_to_pic.png new file mode 100644 index 0000000..2782aad Binary files /dev/null and b/icons/hi16-action-convert_to_pic.png differ diff --git a/icons/hi16-action-indent_asm.png b/icons/hi16-action-indent_asm.png new file mode 100644 index 0000000..d2f5ae8 Binary files /dev/null and b/icons/hi16-action-indent_asm.png differ diff --git a/icons/hi16-action-logic_or.png b/icons/hi16-action-logic_or.png new file mode 100644 index 0000000..78700a7 Binary files /dev/null and b/icons/hi16-action-logic_or.png differ diff --git a/icons/hi16-action-null.png b/icons/hi16-action-null.png new file mode 100644 index 0000000..0780739 Binary files /dev/null and b/icons/hi16-action-null.png differ diff --git a/icons/hi16-action-oscilloscope.png b/icons/hi16-action-oscilloscope.png new file mode 100644 index 0000000..1efc9a2 Binary files /dev/null and b/icons/hi16-action-oscilloscope.png differ diff --git a/icons/hi16-action-tool_arrow.png b/icons/hi16-action-tool_arrow.png new file mode 100644 index 0000000..b16ad6a Binary files /dev/null and b/icons/hi16-action-tool_arrow.png differ diff --git a/icons/hi16-action-tool_ellipse.png b/icons/hi16-action-tool_ellipse.png new file mode 100644 index 0000000..d46d7e7 Binary files /dev/null and b/icons/hi16-action-tool_ellipse.png differ diff --git a/icons/hi16-action-tool_line.png b/icons/hi16-action-tool_line.png new file mode 100644 index 0000000..e325451 Binary files /dev/null and b/icons/hi16-action-tool_line.png differ diff --git a/icons/hi16-action-tool_rectangle.png b/icons/hi16-action-tool_rectangle.png new file mode 100644 index 0000000..f3165a1 Binary files /dev/null and b/icons/hi16-action-tool_rectangle.png differ diff --git a/icons/hi16-action-tool_text.png b/icons/hi16-action-tool_text.png new file mode 100644 index 0000000..b13cc00 Binary files /dev/null and b/icons/hi16-action-tool_text.png differ diff --git a/icons/hi16-app-ktechlab.png b/icons/hi16-app-ktechlab.png new file mode 100644 index 0000000..160f81f Binary files /dev/null and b/icons/hi16-app-ktechlab.png differ diff --git a/icons/hi16-app-microbe.png b/icons/hi16-app-microbe.png new file mode 100644 index 0000000..1122d82 Binary files /dev/null and b/icons/hi16-app-microbe.png differ diff --git a/icons/hi16-mime-ktechlab_circuit.png b/icons/hi16-mime-ktechlab_circuit.png new file mode 100644 index 0000000..c0ebc2d Binary files /dev/null and b/icons/hi16-mime-ktechlab_circuit.png differ diff --git a/icons/hi16-mime-ktechlab_flowcode.png b/icons/hi16-mime-ktechlab_flowcode.png new file mode 100644 index 0000000..d6a659b Binary files /dev/null and b/icons/hi16-mime-ktechlab_flowcode.png differ diff --git a/icons/hi16-mime-ktechlab_microbe.png b/icons/hi16-mime-ktechlab_microbe.png new file mode 100644 index 0000000..e311b8c Binary files /dev/null and b/icons/hi16-mime-ktechlab_microbe.png differ diff --git a/icons/hi22-action-convert_to_assembly.png b/icons/hi22-action-convert_to_assembly.png new file mode 100644 index 0000000..c978b80 Binary files /dev/null and b/icons/hi22-action-convert_to_assembly.png differ diff --git a/icons/hi22-action-convert_to_hex.png b/icons/hi22-action-convert_to_hex.png new file mode 100644 index 0000000..8881f04 Binary files /dev/null and b/icons/hi22-action-convert_to_hex.png differ diff --git a/icons/hi22-action-convert_to_microbe.png b/icons/hi22-action-convert_to_microbe.png new file mode 100644 index 0000000..fbfbc60 Binary files /dev/null and b/icons/hi22-action-convert_to_microbe.png differ diff --git a/icons/hi22-action-convert_to_pic.png b/icons/hi22-action-convert_to_pic.png new file mode 100644 index 0000000..4effd8c Binary files /dev/null and b/icons/hi22-action-convert_to_pic.png differ diff --git a/icons/hi22-action-dbgnext.png b/icons/hi22-action-dbgnext.png new file mode 100644 index 0000000..cb512cb Binary files /dev/null and b/icons/hi22-action-dbgnext.png differ diff --git a/icons/hi22-action-dbgrun.png b/icons/hi22-action-dbgrun.png new file mode 100644 index 0000000..501550e Binary files /dev/null and b/icons/hi22-action-dbgrun.png differ diff --git a/icons/hi22-action-dbgstep.png b/icons/hi22-action-dbgstep.png new file mode 100644 index 0000000..6a09a4c Binary files /dev/null and b/icons/hi22-action-dbgstep.png differ diff --git a/icons/hi22-action-dbgstepout.png b/icons/hi22-action-dbgstepout.png new file mode 100644 index 0000000..405f9a9 Binary files /dev/null and b/icons/hi22-action-dbgstepout.png differ diff --git a/icons/hi22-action-indent_asm.png b/icons/hi22-action-indent_asm.png new file mode 100644 index 0000000..bf8b1b8 Binary files /dev/null and b/icons/hi22-action-indent_asm.png differ diff --git a/icons/hi22-action-logic_or.png b/icons/hi22-action-logic_or.png new file mode 100644 index 0000000..c3365e2 Binary files /dev/null and b/icons/hi22-action-logic_or.png differ diff --git a/icons/hi22-app-ktechlab.png b/icons/hi22-app-ktechlab.png new file mode 100644 index 0000000..dba3166 Binary files /dev/null and b/icons/hi22-app-ktechlab.png differ diff --git a/icons/hi22-app-microbe.png b/icons/hi22-app-microbe.png new file mode 100644 index 0000000..66d720e Binary files /dev/null and b/icons/hi22-app-microbe.png differ diff --git a/icons/hi22-mime-ktechlab_circuit.png b/icons/hi22-mime-ktechlab_circuit.png new file mode 100644 index 0000000..7ca5610 Binary files /dev/null and b/icons/hi22-mime-ktechlab_circuit.png differ diff --git a/icons/hi22-mime-ktechlab_flowcode.png b/icons/hi22-mime-ktechlab_flowcode.png new file mode 100644 index 0000000..816ebc7 Binary files /dev/null and b/icons/hi22-mime-ktechlab_flowcode.png differ diff --git a/icons/hi22-mime-ktechlab_microbe.png b/icons/hi22-mime-ktechlab_microbe.png new file mode 100644 index 0000000..5b99c46 Binary files /dev/null and b/icons/hi22-mime-ktechlab_microbe.png differ diff --git a/icons/hi32-action-convert_to_assembly.png b/icons/hi32-action-convert_to_assembly.png new file mode 100644 index 0000000..53aaf65 Binary files /dev/null and b/icons/hi32-action-convert_to_assembly.png differ diff --git a/icons/hi32-action-convert_to_hex.png b/icons/hi32-action-convert_to_hex.png new file mode 100644 index 0000000..2ff166b Binary files /dev/null and b/icons/hi32-action-convert_to_hex.png differ diff --git a/icons/hi32-action-convert_to_microbe.png b/icons/hi32-action-convert_to_microbe.png new file mode 100644 index 0000000..8836a5d Binary files /dev/null and b/icons/hi32-action-convert_to_microbe.png differ diff --git a/icons/hi32-action-convert_to_pic.png b/icons/hi32-action-convert_to_pic.png new file mode 100644 index 0000000..339eaf4 Binary files /dev/null and b/icons/hi32-action-convert_to_pic.png differ diff --git a/icons/hi32-action-indent_asm.png b/icons/hi32-action-indent_asm.png new file mode 100644 index 0000000..40bc3c5 Binary files /dev/null and b/icons/hi32-action-indent_asm.png differ diff --git a/icons/hi32-action-logic_or.png b/icons/hi32-action-logic_or.png new file mode 100644 index 0000000..df3d173 Binary files /dev/null and b/icons/hi32-action-logic_or.png differ diff --git a/icons/hi32-app-ktechlab.png b/icons/hi32-app-ktechlab.png new file mode 100644 index 0000000..4bcea76 Binary files /dev/null and b/icons/hi32-app-ktechlab.png differ diff --git a/icons/hi32-app-microbe.png b/icons/hi32-app-microbe.png new file mode 100644 index 0000000..d7f761e Binary files /dev/null and b/icons/hi32-app-microbe.png differ diff --git a/icons/hi32-mime-ktechlab_circuit.png b/icons/hi32-mime-ktechlab_circuit.png new file mode 100644 index 0000000..8fac6bc Binary files /dev/null and b/icons/hi32-mime-ktechlab_circuit.png differ diff --git a/icons/hi32-mime-ktechlab_flowcode.png b/icons/hi32-mime-ktechlab_flowcode.png new file mode 100644 index 0000000..8f45735 Binary files /dev/null and b/icons/hi32-mime-ktechlab_flowcode.png differ diff --git a/icons/hi32-mime-ktechlab_microbe.png b/icons/hi32-mime-ktechlab_microbe.png new file mode 100644 index 0000000..670c6d0 Binary files /dev/null and b/icons/hi32-mime-ktechlab_microbe.png differ diff --git a/icons/hi48-action-convert_to_assembly.png b/icons/hi48-action-convert_to_assembly.png new file mode 100644 index 0000000..f693907 Binary files /dev/null and b/icons/hi48-action-convert_to_assembly.png differ diff --git a/icons/hi48-action-convert_to_hex.png b/icons/hi48-action-convert_to_hex.png new file mode 100644 index 0000000..de3487b Binary files /dev/null and b/icons/hi48-action-convert_to_hex.png differ diff --git a/icons/hi48-action-convert_to_microbe.png b/icons/hi48-action-convert_to_microbe.png new file mode 100644 index 0000000..cdbdbe0 Binary files /dev/null and b/icons/hi48-action-convert_to_microbe.png differ diff --git a/icons/hi48-action-convert_to_pic.png b/icons/hi48-action-convert_to_pic.png new file mode 100644 index 0000000..5f72810 Binary files /dev/null and b/icons/hi48-action-convert_to_pic.png differ diff --git a/icons/hi48-action-indent_asm.png b/icons/hi48-action-indent_asm.png new file mode 100644 index 0000000..1a909b9 Binary files /dev/null and b/icons/hi48-action-indent_asm.png differ diff --git a/icons/hi48-action-logic_or.png b/icons/hi48-action-logic_or.png new file mode 100644 index 0000000..812283a Binary files /dev/null and b/icons/hi48-action-logic_or.png differ diff --git a/icons/hi48-app-ktechlab.png b/icons/hi48-app-ktechlab.png new file mode 100644 index 0000000..268c191 Binary files /dev/null and b/icons/hi48-app-ktechlab.png differ diff --git a/icons/hi48-app-microbe.png b/icons/hi48-app-microbe.png new file mode 100644 index 0000000..1b7b8bd Binary files /dev/null and b/icons/hi48-app-microbe.png differ diff --git a/icons/hi48-mime-ktechlab_circuit.png b/icons/hi48-mime-ktechlab_circuit.png new file mode 100644 index 0000000..4558f82 Binary files /dev/null and b/icons/hi48-mime-ktechlab_circuit.png differ diff --git a/icons/hi48-mime-ktechlab_flowcode.png b/icons/hi48-mime-ktechlab_flowcode.png new file mode 100644 index 0000000..7a1eef1 Binary files /dev/null and b/icons/hi48-mime-ktechlab_flowcode.png differ diff --git a/icons/hi48-mime-ktechlab_microbe.png b/icons/hi48-mime-ktechlab_microbe.png new file mode 100644 index 0000000..5127981 Binary files /dev/null and b/icons/hi48-mime-ktechlab_microbe.png differ diff --git a/icons/hi64-action-convert_to_assembly.png b/icons/hi64-action-convert_to_assembly.png new file mode 100644 index 0000000..3197b7d Binary files /dev/null and b/icons/hi64-action-convert_to_assembly.png differ diff --git a/icons/hi64-action-convert_to_hex.png b/icons/hi64-action-convert_to_hex.png new file mode 100644 index 0000000..dad6f90 Binary files /dev/null and b/icons/hi64-action-convert_to_hex.png differ diff --git a/icons/hi64-action-convert_to_microbe.png b/icons/hi64-action-convert_to_microbe.png new file mode 100644 index 0000000..45efe4e Binary files /dev/null and b/icons/hi64-action-convert_to_microbe.png differ diff --git a/icons/hi64-action-convert_to_pic.png b/icons/hi64-action-convert_to_pic.png new file mode 100644 index 0000000..95d3e06 Binary files /dev/null and b/icons/hi64-action-convert_to_pic.png differ diff --git a/icons/hi64-action-indent_asm.png b/icons/hi64-action-indent_asm.png new file mode 100644 index 0000000..f64c6ef Binary files /dev/null and b/icons/hi64-action-indent_asm.png differ diff --git a/icons/hi64-action-logic_or.png b/icons/hi64-action-logic_or.png new file mode 100644 index 0000000..1b1c30e Binary files /dev/null and b/icons/hi64-action-logic_or.png differ diff --git a/icons/hi64-app-ktechlab.png b/icons/hi64-app-ktechlab.png new file mode 100644 index 0000000..522bb93 Binary files /dev/null and b/icons/hi64-app-ktechlab.png differ diff --git a/icons/hi64-app-microbe.png b/icons/hi64-app-microbe.png new file mode 100644 index 0000000..2708067 Binary files /dev/null and b/icons/hi64-app-microbe.png differ diff --git a/icons/hi64-mime-ktechlab_circuit.png b/icons/hi64-mime-ktechlab_circuit.png new file mode 100644 index 0000000..e7cea04 Binary files /dev/null and b/icons/hi64-mime-ktechlab_circuit.png differ diff --git a/icons/hi64-mime-ktechlab_flowcode.png b/icons/hi64-mime-ktechlab_flowcode.png new file mode 100644 index 0000000..97d9771 Binary files /dev/null and b/icons/hi64-mime-ktechlab_flowcode.png differ diff --git a/icons/hi64-mime-ktechlab_microbe.png b/icons/hi64-mime-ktechlab_microbe.png new file mode 100644 index 0000000..479320a Binary files /dev/null and b/icons/hi64-mime-ktechlab_microbe.png differ diff --git a/icons/pics/Makefile.am b/icons/pics/Makefile.am new file mode 100644 index 0000000..7dfea88 --- /dev/null +++ b/icons/pics/Makefile.am @@ -0,0 +1,19 @@ + +METASOURCES = AUTO +ktlicon_DATA = and.png cell.png logic_input.png logic_output.png nand.png \ + nor.png not.png or.png xor.png current_source.png ground.png voltage.png \ + capacitor.png led.png resistor.png signal_lamp.png seven_segment.png ammeter.png \ + diode.png npn.png pnp.png voltmeter.png dpdt.png dpst.png ptb.png ptm.png \ + spdt.png spst.png keypad.png opamp.png xnor.png circuit.png flowcode.png \ + delay.png interrupt.png pinread.png pinwrite.png portread.png portwrite.png \ + repeat.png while.png for.png assignment.png branch.png delay.png embed.png end.png \ + for.png interrupt.png pinread.png pinwrite.png portread.png portwrite.png \ + repeat.png start.png sub.png subcall.png unary.png while.png item.png ic1.png \ + ic2.png ic3.png voltagesignal.png currentsignal.png clockinput.png cccs.png \ + ccvs.png vcvs.png vccs.png mechanics.png buffer.png external_connection.png \ + logicprobe.png potentiometer.png resistordip.png bidirled.png project_library.png \ + project_program.png bus.png floatingprobe.png inductor.png matrixdisplay.png \ + rotary.png +ktlicondir = $(kde_datadir)/ktechlab/icons + + diff --git a/icons/pics/ammeter.png b/icons/pics/ammeter.png new file mode 100644 index 0000000..2148943 Binary files /dev/null and b/icons/pics/ammeter.png differ diff --git a/icons/pics/and.png b/icons/pics/and.png new file mode 100644 index 0000000..3879e3f Binary files /dev/null and b/icons/pics/and.png differ diff --git a/icons/pics/assignment.png b/icons/pics/assignment.png new file mode 100644 index 0000000..5885b5d Binary files /dev/null and b/icons/pics/assignment.png differ diff --git a/icons/pics/bidirled.png b/icons/pics/bidirled.png new file mode 100644 index 0000000..b2c6c21 Binary files /dev/null and b/icons/pics/bidirled.png differ diff --git a/icons/pics/branch.png b/icons/pics/branch.png new file mode 100644 index 0000000..81345c2 Binary files /dev/null and b/icons/pics/branch.png differ diff --git a/icons/pics/buffer.png b/icons/pics/buffer.png new file mode 100644 index 0000000..c9acefd Binary files /dev/null and b/icons/pics/buffer.png differ diff --git a/icons/pics/bus.png b/icons/pics/bus.png new file mode 100644 index 0000000..7c973bc Binary files /dev/null and b/icons/pics/bus.png differ diff --git a/icons/pics/capacitor.png b/icons/pics/capacitor.png new file mode 100644 index 0000000..adc3826 Binary files /dev/null and b/icons/pics/capacitor.png differ diff --git a/icons/pics/cccs.png b/icons/pics/cccs.png new file mode 100644 index 0000000..8d342f8 Binary files /dev/null and b/icons/pics/cccs.png differ diff --git a/icons/pics/ccvs.png b/icons/pics/ccvs.png new file mode 100644 index 0000000..51fd467 Binary files /dev/null and b/icons/pics/ccvs.png differ diff --git a/icons/pics/cell.png b/icons/pics/cell.png new file mode 100644 index 0000000..f944ccb Binary files /dev/null and b/icons/pics/cell.png differ diff --git a/icons/pics/circuit.png b/icons/pics/circuit.png new file mode 100644 index 0000000..31e6ac9 Binary files /dev/null and b/icons/pics/circuit.png differ diff --git a/icons/pics/clockinput.png b/icons/pics/clockinput.png new file mode 100644 index 0000000..79df8c1 Binary files /dev/null and b/icons/pics/clockinput.png differ diff --git a/icons/pics/current_source.png b/icons/pics/current_source.png new file mode 100644 index 0000000..205130d Binary files /dev/null and b/icons/pics/current_source.png differ diff --git a/icons/pics/currentsignal.png b/icons/pics/currentsignal.png new file mode 100644 index 0000000..6da8d3d Binary files /dev/null and b/icons/pics/currentsignal.png differ diff --git a/icons/pics/delay.png b/icons/pics/delay.png new file mode 100644 index 0000000..1025e11 Binary files /dev/null and b/icons/pics/delay.png differ diff --git a/icons/pics/diode.png b/icons/pics/diode.png new file mode 100644 index 0000000..ada6909 Binary files /dev/null and b/icons/pics/diode.png differ diff --git a/icons/pics/dpdt.png b/icons/pics/dpdt.png new file mode 100644 index 0000000..cf45e18 Binary files /dev/null and b/icons/pics/dpdt.png differ diff --git a/icons/pics/dpst.png b/icons/pics/dpst.png new file mode 100644 index 0000000..bec0df1 Binary files /dev/null and b/icons/pics/dpst.png differ diff --git a/icons/pics/embed.png b/icons/pics/embed.png new file mode 100644 index 0000000..472bd0c Binary files /dev/null and b/icons/pics/embed.png differ diff --git a/icons/pics/end.png b/icons/pics/end.png new file mode 100644 index 0000000..5f88f0f Binary files /dev/null and b/icons/pics/end.png differ diff --git a/icons/pics/external_connection.png b/icons/pics/external_connection.png new file mode 100644 index 0000000..2841a88 Binary files /dev/null and b/icons/pics/external_connection.png differ diff --git a/icons/pics/floatingprobe.png b/icons/pics/floatingprobe.png new file mode 100644 index 0000000..1efc9a2 Binary files /dev/null and b/icons/pics/floatingprobe.png differ diff --git a/icons/pics/flowcode.png b/icons/pics/flowcode.png new file mode 100644 index 0000000..64fdc0f Binary files /dev/null and b/icons/pics/flowcode.png differ diff --git a/icons/pics/for.png b/icons/pics/for.png new file mode 100644 index 0000000..2b5ad0a Binary files /dev/null and b/icons/pics/for.png differ diff --git a/icons/pics/ground.png b/icons/pics/ground.png new file mode 100644 index 0000000..c1a4650 Binary files /dev/null and b/icons/pics/ground.png differ diff --git a/icons/pics/ic1.png b/icons/pics/ic1.png new file mode 100644 index 0000000..51e87c9 Binary files /dev/null and b/icons/pics/ic1.png differ diff --git a/icons/pics/ic2.png b/icons/pics/ic2.png new file mode 100644 index 0000000..d12bb2b Binary files /dev/null and b/icons/pics/ic2.png differ diff --git a/icons/pics/ic3.png b/icons/pics/ic3.png new file mode 100644 index 0000000..d2ebf20 Binary files /dev/null and b/icons/pics/ic3.png differ diff --git a/icons/pics/inductor.png b/icons/pics/inductor.png new file mode 100644 index 0000000..cb5653a Binary files /dev/null and b/icons/pics/inductor.png differ diff --git a/icons/pics/interrupt.png b/icons/pics/interrupt.png new file mode 100644 index 0000000..27bc0ed Binary files /dev/null and b/icons/pics/interrupt.png differ diff --git a/icons/pics/item.png b/icons/pics/item.png new file mode 100644 index 0000000..a0c8046 Binary files /dev/null and b/icons/pics/item.png differ diff --git a/icons/pics/keypad.png b/icons/pics/keypad.png new file mode 100644 index 0000000..bba7390 Binary files /dev/null and b/icons/pics/keypad.png differ diff --git a/icons/pics/led.png b/icons/pics/led.png new file mode 100644 index 0000000..e30f592 Binary files /dev/null and b/icons/pics/led.png differ diff --git a/icons/pics/logic_input.png b/icons/pics/logic_input.png new file mode 100644 index 0000000..2099712 Binary files /dev/null and b/icons/pics/logic_input.png differ diff --git a/icons/pics/logic_output.png b/icons/pics/logic_output.png new file mode 100644 index 0000000..ea11597 Binary files /dev/null and b/icons/pics/logic_output.png differ diff --git a/icons/pics/logicprobe.png b/icons/pics/logicprobe.png new file mode 100644 index 0000000..6f11b36 Binary files /dev/null and b/icons/pics/logicprobe.png differ diff --git a/icons/pics/matrixdisplay.png b/icons/pics/matrixdisplay.png new file mode 100644 index 0000000..73b90aa Binary files /dev/null and b/icons/pics/matrixdisplay.png differ diff --git a/icons/pics/mechanics.png b/icons/pics/mechanics.png new file mode 100644 index 0000000..a974ea7 Binary files /dev/null and b/icons/pics/mechanics.png differ diff --git a/icons/pics/nand.png b/icons/pics/nand.png new file mode 100644 index 0000000..6998654 Binary files /dev/null and b/icons/pics/nand.png differ diff --git a/icons/pics/nor.png b/icons/pics/nor.png new file mode 100644 index 0000000..286b048 Binary files /dev/null and b/icons/pics/nor.png differ diff --git a/icons/pics/not.png b/icons/pics/not.png new file mode 100644 index 0000000..78aa3a5 Binary files /dev/null and b/icons/pics/not.png differ diff --git a/icons/pics/npn.png b/icons/pics/npn.png new file mode 100644 index 0000000..496a1f9 Binary files /dev/null and b/icons/pics/npn.png differ diff --git a/icons/pics/opamp.png b/icons/pics/opamp.png new file mode 100644 index 0000000..abd51ee Binary files /dev/null and b/icons/pics/opamp.png differ diff --git a/icons/pics/or.png b/icons/pics/or.png new file mode 100644 index 0000000..78700a7 Binary files /dev/null and b/icons/pics/or.png differ diff --git a/icons/pics/pinread.png b/icons/pics/pinread.png new file mode 100644 index 0000000..a6cc3bb Binary files /dev/null and b/icons/pics/pinread.png differ diff --git a/icons/pics/pinwrite.png b/icons/pics/pinwrite.png new file mode 100644 index 0000000..249b4a2 Binary files /dev/null and b/icons/pics/pinwrite.png differ diff --git a/icons/pics/pnp.png b/icons/pics/pnp.png new file mode 100644 index 0000000..ce004d6 Binary files /dev/null and b/icons/pics/pnp.png differ diff --git a/icons/pics/portread.png b/icons/pics/portread.png new file mode 100644 index 0000000..cce05a8 Binary files /dev/null and b/icons/pics/portread.png differ diff --git a/icons/pics/portwrite.png b/icons/pics/portwrite.png new file mode 100644 index 0000000..911b482 Binary files /dev/null and b/icons/pics/portwrite.png differ diff --git a/icons/pics/potentiometer.png b/icons/pics/potentiometer.png new file mode 100644 index 0000000..968e771 Binary files /dev/null and b/icons/pics/potentiometer.png differ diff --git a/icons/pics/project_library.png b/icons/pics/project_library.png new file mode 100644 index 0000000..31af1bc Binary files /dev/null and b/icons/pics/project_library.png differ diff --git a/icons/pics/project_program.png b/icons/pics/project_program.png new file mode 100644 index 0000000..760ad46 Binary files /dev/null and b/icons/pics/project_program.png differ diff --git a/icons/pics/ptb.png b/icons/pics/ptb.png new file mode 100644 index 0000000..233a3b4 Binary files /dev/null and b/icons/pics/ptb.png differ diff --git a/icons/pics/ptm.png b/icons/pics/ptm.png new file mode 100644 index 0000000..f55728d Binary files /dev/null and b/icons/pics/ptm.png differ diff --git a/icons/pics/repeat.png b/icons/pics/repeat.png new file mode 100644 index 0000000..ca62e98 Binary files /dev/null and b/icons/pics/repeat.png differ diff --git a/icons/pics/resistor.png b/icons/pics/resistor.png new file mode 100644 index 0000000..9debb24 Binary files /dev/null and b/icons/pics/resistor.png differ diff --git a/icons/pics/resistordip.png b/icons/pics/resistordip.png new file mode 100644 index 0000000..de4b140 Binary files /dev/null and b/icons/pics/resistordip.png differ diff --git a/icons/pics/rotary.png b/icons/pics/rotary.png new file mode 100644 index 0000000..a2b2784 Binary files /dev/null and b/icons/pics/rotary.png differ diff --git a/icons/pics/seven_segment.png b/icons/pics/seven_segment.png new file mode 100644 index 0000000..1e8e9d3 Binary files /dev/null and b/icons/pics/seven_segment.png differ diff --git a/icons/pics/signal_lamp.png b/icons/pics/signal_lamp.png new file mode 100644 index 0000000..2422be6 Binary files /dev/null and b/icons/pics/signal_lamp.png differ diff --git a/icons/pics/spdt.png b/icons/pics/spdt.png new file mode 100644 index 0000000..ff016a3 Binary files /dev/null and b/icons/pics/spdt.png differ diff --git a/icons/pics/spst.png b/icons/pics/spst.png new file mode 100644 index 0000000..14d6381 Binary files /dev/null and b/icons/pics/spst.png differ diff --git a/icons/pics/start.png b/icons/pics/start.png new file mode 100644 index 0000000..aef06ae Binary files /dev/null and b/icons/pics/start.png differ diff --git a/icons/pics/sub.png b/icons/pics/sub.png new file mode 100644 index 0000000..3f180ce Binary files /dev/null and b/icons/pics/sub.png differ diff --git a/icons/pics/subcall.png b/icons/pics/subcall.png new file mode 100644 index 0000000..593666c Binary files /dev/null and b/icons/pics/subcall.png differ diff --git a/icons/pics/unary.png b/icons/pics/unary.png new file mode 100644 index 0000000..0238c20 Binary files /dev/null and b/icons/pics/unary.png differ diff --git a/icons/pics/vccs.png b/icons/pics/vccs.png new file mode 100644 index 0000000..cd9320d Binary files /dev/null and b/icons/pics/vccs.png differ diff --git a/icons/pics/vcvs.png b/icons/pics/vcvs.png new file mode 100644 index 0000000..d0fc37c Binary files /dev/null and b/icons/pics/vcvs.png differ diff --git a/icons/pics/voltage.png b/icons/pics/voltage.png new file mode 100644 index 0000000..622f921 Binary files /dev/null and b/icons/pics/voltage.png differ diff --git a/icons/pics/voltagesignal.png b/icons/pics/voltagesignal.png new file mode 100644 index 0000000..088e94c Binary files /dev/null and b/icons/pics/voltagesignal.png differ diff --git a/icons/pics/voltmeter.png b/icons/pics/voltmeter.png new file mode 100644 index 0000000..14f2c71 Binary files /dev/null and b/icons/pics/voltmeter.png differ diff --git a/icons/pics/while.png b/icons/pics/while.png new file mode 100644 index 0000000..d964a92 Binary files /dev/null and b/icons/pics/while.png differ diff --git a/icons/pics/xnor.png b/icons/pics/xnor.png new file mode 100644 index 0000000..33e649f Binary files /dev/null and b/icons/pics/xnor.png differ diff --git a/icons/pics/xor.png b/icons/pics/xor.png new file mode 100644 index 0000000..d039637 Binary files /dev/null and b/icons/pics/xor.png differ diff --git a/microbe/Makefile.am b/microbe/Makefile.am new file mode 100644 index 0000000..da467f9 --- /dev/null +++ b/microbe/Makefile.am @@ -0,0 +1,10 @@ +INCLUDES = $(all_includes) +METASOURCES = AUTO +bin_PROGRAMS = microbe +microbe_LDFLAGS = $(all_libraries) $(KDE_RPATH) +microbe_SOURCES = btreebase.cpp btreenode.cpp main.cpp traverser.cpp \ + expression.cpp pic14.cpp variable.cpp optimizer.cpp instruction.cpp microbe.cpp \ + parser.cpp +noinst_HEADERS = btreebase.h btreenode.h traverser.h pic14.h variable.h \ + optimizer.h microbe.h parser.h +microbe_LDADD = -lpthread $(LIB_KFILE) diff --git a/microbe/btreebase.cpp b/microbe/btreebase.cpp new file mode 100644 index 0000000..bd9e38a --- /dev/null +++ b/microbe/btreebase.cpp @@ -0,0 +1,248 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by Daniel Clarke * + * daniel.jc@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "btreebase.h" +#include "traverser.h" +#include "parser.h" +#include "pic14.h" + +BTreeBase::BTreeBase() +{ + m_root = 0L; +} + +void BTreeBase::deleteTree() +{ + if(m_root) m_root->deleteChildren(); + delete m_root; + m_root = 0L; +} + +BTreeBase::~BTreeBase() +{ + deleteTree(); +} + + +void BTreeBase::addNode(BTreeNode *parent, BTreeNode *node, bool left) +{ + // Debugging lines, remove when expression parsing has been completed. + //if(!parent) cerr<<"Null parent pointer!\n"; + //if(!node) cerr<<"Null node pointer!\n"); + + if(left) parent->setLeft(node); + else parent->setRight(node); +} + +void BTreeBase::pruneTree(BTreeNode *root, bool /*conditionalRoot*/) +{ + Traverser t(root); + + t.descendLeftwardToTerminal(); + bool done = false; + while(!done) + { + //t.descendLeftwardToTerminal(); + if( t.current()->parent() ) + { + if( t.oppositeNode()->hasChildren() ) pruneTree(t.oppositeNode()); + } + + t.moveToParent(); + if( !t.current()->hasChildren() ) + { + //if(t.current() == t.root()) done = true; + if(!t.current()->parent()) done = true; + continue; + } + + BTreeNode *l = t.current()->left(); + BTreeNode *r = t.current()->right(); + BTreeNode *n = 0; + BTreeNode *z = 0; + + + // Deal with situations where there are two constants so we want + // to evaluate at compile time + if( (l->type() == number && r->type() == number) ) // && !(t.current()==root&&conditionalRoot) ) + { + if(t.current()->childOp() == Expression::division && r->value() == "0" ) + { + t.current()->setChildOp(Expression::divbyzero); + return; + } + QString value = QString::number(Parser::doArithmetic(l->value().toInt(),r->value().toInt(),t.current()->childOp())); + t.current()->deleteChildren(); + t.current()->setChildOp(Expression::noop); + t.current()->setType(number); + t.current()->setValue(value); + } + + // Addition and subtraction + else if(t.current()->childOp() == Expression::addition || t.current()->childOp() == Expression::subtraction) + { + // See if one of the nodes is 0, and set n to the node that actually has data, + // z to the one containing zero. + bool zero = false; + if( l->value() == "0" ) + { + zero = true; + n = r; + z = l; + } + else if( r->value() == "0" ) + { + zero = true; + n = l; + z = r; + } + // Now get rid of the useless nodes + if(zero) + { + BTreeNode *p = t.current(); // save in order to delete after + + replaceNode(p,n); + t.setCurrent(n); + // Delete the old nodes + delete p; + delete z; + } + } + + // Multiplication and division + else if(t.current()->childOp() == Expression::multiplication || t.current()->childOp() == Expression::division) + { + // See if one of the nodes is 0, and set n to the node that actually has data, + // z to the one containing zero. + bool zero = false; + bool one = false; + if( l->value() == "1" ) + { + one = true; + n = r; + z = l; + } + else if( r->value() == "1" ) + { + one = true; + n = l; + z = r; + } + if( l->value() == "0" ) + { + zero = true; + n = r; + z = l; + } + else if( r->value() == "0" ) + { + + // since we can't call compileError from in this class, we have a special way of handling it: + // Leave the children as they are, and set childOp to divbyzero + if( t.current()->childOp() == Expression::division ) + { + t.current()->setChildOp(Expression::divbyzero); + return; // no point doing any more since we are going to raise a compileError later anyway. + } + zero = true; + n = l; + z = r; + } + // Now get rid of the useless nodes + if(one) + { + BTreeNode *p = t.current(); // save in order to delete after + replaceNode(p,n); + t.setCurrent(n); + // Delete the old nodes + delete p; + delete z; + } + if(zero) + { + BTreeNode *p = t.current(); + p->deleteChildren(); + p->setChildOp(Expression::noop); + p->setType(number); + p->setValue("0"); + + } + } + else if( t.current()->childOp() == Expression::bwand || t.current()->childOp() == Expression::bwor || t.current()->childOp() == Expression::bwxor ) + { + bool zero = false; + if( l->value() == "0" ) + { + zero = true; + n = r; + z = l; + } + else if( r->value() == "0" ) + { + zero = true; + n = l; + z = r; + } + // Now get rid of the useless nodes + if(zero) + { + BTreeNode *p = t.current(); + QString value; + if( p->childOp() == Expression::bwand ) + { + value = "0"; + p->deleteChildren(); + p->setChildOp(Expression::noop); + p->setType(number); + } + if( p->childOp() == Expression::bwor || p->childOp() == Expression::bwxor ) + { + value = n->value(); + BTreeNode *p = t.current(); // save in order to delete after + replaceNode(p,n); + t.setCurrent(n); + // Delete the old nodes + delete p; + delete z; + } + p->setValue(value); + } + } + + if(!t.current()->parent() || t.current() == root) done = true; + else + { + + } + } +} + +void BTreeBase::replaceNode(BTreeNode *node, BTreeNode *replacement) +{ + // (This works under the assumption that a node is not linked to two places at once). + if( !node->parent() ) + { + setRoot(replacement); + replacement->setParent(0L); + return; + } + if( node->parent()->left() == node ) node->parent()->setLeft(replacement); + if( node->parent()->right() == node ) node->parent()->setRight(replacement); +} diff --git a/microbe/btreebase.h b/microbe/btreebase.h new file mode 100644 index 0000000..d8d1040 --- /dev/null +++ b/microbe/btreebase.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by Daniel Clarke * + * daniel.jc@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef BTREEBASE_H +#define BTREEBASE_H +#include "microbe.h" +#include "btreenode.h" + +/** +@short This holds a pointer to the start of the tree, and provides the traversal code. +@author Daniel Clarke +*/ +class BTreeBase{ +public: + BTreeBase(); + ~BTreeBase(); + + /** Return a pointer to the root node of the tree */ + BTreeNode *root() const { return m_root; } + + /** Set the root node of the tree */ + void setRoot(BTreeNode *root){m_root = root; } + + /** Link the node into the tree. a.t.m all this really + does it sets the parent/child relationship pointers, + but is used in case something needs to be changed in the future + Added to the left if left == true or the right if left == false */ + void addNode(BTreeNode *parent, BTreeNode *node, bool left); + + /** Deletes all nodes in tree and zeros pointer to root node */ + void deleteTree(); + + /** Tidies the tree up; merging constants and removing redundant branches */ + void pruneTree(BTreeNode *root, bool conditionalRoot = true); + + /** Put a node in place of another, linking it correctly into the parent. */ + void replaceNode(BTreeNode *node, BTreeNode *replacement); + +protected: + BTreeNode *m_root; +}; + +#endif diff --git a/microbe/btreenode.cpp b/microbe/btreenode.cpp new file mode 100644 index 0000000..27d49cc --- /dev/null +++ b/microbe/btreenode.cpp @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by Daniel Clarke * + * daniel.jc@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "btreenode.h" +#include "pic14.h" + +BTreeNode::BTreeNode() +{ + m_parent = 0L; + m_left = 0L; + m_right = 0L; + m_type = unset; +} + +BTreeNode::BTreeNode(BTreeNode *p, BTreeNode *l, BTreeNode *r) +{ + m_parent = p; + m_left = l; + m_right = r; +} + +BTreeNode::~BTreeNode() +{ + // Must not delete children as might be unlinking!!! deleteChildren(); +} + +void BTreeNode::deleteChildren() +{ + if(m_left) + { + m_left->deleteChildren(); + delete m_left; + } + if(m_right) + { + m_right->deleteChildren(); + delete m_right; + } + + m_left = 0L; + m_right = 0L; + + return; +} + +// void BTreeNode::printTree() +// { +// +// } diff --git a/microbe/btreenode.h b/microbe/btreenode.h new file mode 100644 index 0000000..7f5fdfb --- /dev/null +++ b/microbe/btreenode.h @@ -0,0 +1,107 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by Daniel Clarke * + * daniel.jc@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef BTREENODE_H +#define BTREENODE_H + +#include "btreebase.h" +#include "expression.h" + +#include +#include + +/** +A node points to the two child nodes (left and right), and contains the binary +operation used to combine them. + +@author Daniel Clarke +@author David Saxton +*/ +class BTreeNode +{ + public: + BTreeNode(); + BTreeNode(BTreeNode *p, BTreeNode *l, BTreeNode *r); + ~BTreeNode(); + + /** + * Used for debugging purposes; prints the tree structure to stdout. + */ +// void printTree(); + /** + * Recursively delete all children of a node. + */ + void deleteChildren(); + /** + * @return the parent node. + */ + BTreeNode *parent() const { return m_parent; } + /** + * @return the left child node. + */ + BTreeNode *left() const { return m_left; } + /** + * @return the right child node. + */ + BTreeNode *right() const { return m_right; } + void setParent(BTreeNode *parent) { m_parent = parent; } + /** + * Set the child node on the left to the one give, and reparents it to + * this node. + */ + void setLeft(BTreeNode *left) { m_left = left; m_left->setParent( this ); } + /** + * Set the child node on the right to the one give, and reparents it to + * this node. + */ + void setRight(BTreeNode *right) { m_right = right; m_right->setParent( this ); } + /** + * @return true if have a left or a right child node. + */ + bool hasChildren() const { return m_left || m_right; } + + ExprType type() const {return m_type;} + void setType(ExprType type) { m_type = type; } + QString value() const {return m_value;} + void setValue( const QString & value ) { m_value = value; } + + Expression::Operation childOp() const {return m_childOp;} + void setChildOp(Expression::Operation op){ m_childOp = op;} + + void setReg( const QString & r ){ m_reg = r; } + QString reg() const {return m_reg;} + + bool needsEvaluating() const { return hasChildren(); } + + protected: + BTreeNode *m_parent; + BTreeNode *m_left; + BTreeNode *m_right; + + /** This is used to remember what working register contains the value of the node during assembly.*/ + QString m_reg; + + ExprType m_type; + QString m_value; + + Expression::Operation m_childOp; +}; + +#endif diff --git a/microbe/expression.cpp b/microbe/expression.cpp new file mode 100644 index 0000000..33fd514 --- /dev/null +++ b/microbe/expression.cpp @@ -0,0 +1,842 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by Daniel Clarke * + * daniel.jc@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "btreebase.h" +#include "btreenode.h" +#include "expression.h" +#include "traverser.h" +#include "parser.h" +#include "pic14.h" + +#include +#include +#include + +Expression::Expression( PIC14 *pic, Microbe *master, SourceLine sourceLine, bool suppressNumberTooBig ) + : m_sourceLine(sourceLine) +{ + m_pic = pic; + mb = master; + m_bSupressNumberTooBig = suppressNumberTooBig; +} + +Expression::~Expression() +{ +} + +void Expression::traverseTree( BTreeNode *root, bool conditionalRoot ) +{ + Traverser t(root); + t.start(); + + // special case: if we are starting at the root node then + // we are dealing with something of the form variable = 6 + // or variable = portb + ///TODO reimplement assignments as two branched trees? + if ( t.current() == root && + !root->hasChildren() && + t.current()->childOp() != pin && + t.current()->childOp() != notpin && + t.current()->childOp() != function && + t.current()->childOp() != read_keypad ) + { + switch(root->type()) + { + case number: m_pic->assignNum(root->value()); break; + case variable: m_pic->assignVar(root->value()); break; + default: break; // Should never get here + } + // no need to traverse the tree as there is none. + return; + } + + t.setCurrent(root); + + if(t.current()->hasChildren()) + { + // Here we work out what needs evaulating, and in which order. + // To minimize register usage, if only one branch needs traversing, + // then that branch should be done first. + bool evaluateLeft = t.current()->left()->needsEvaluating(); + + BTreeNode *evaluateFirst; + BTreeNode *evaluateSecond; + + // If both need doing, then it really doesn't matter which we do + // first (unless we are looking to do really complex optimizations... + + // Cases: + // - Both need evaluating, + // - or left needs doing first, + // in both cases we evaluate left, then right. + if( evaluateLeft ) + { + evaluateFirst = t.current()->left(); + evaluateSecond = t.current()->right(); + } + // Otherwise it is best to evaluate right first for reasons given above. + else + { + evaluateFirst = t.current()->right(); + evaluateSecond = t.current()->left(); + } + + QString dest1 = mb->dest(); + mb->incDest(); + QString dest2 = mb->dest(); + mb->decDest(); + + bool evaluated = false; + if( evaluateFirst->hasChildren() ) + { + traverseTree(evaluateFirst); + evaluated = true; + } + else if( isUnaryOp(evaluateFirst->childOp()) ) + { + doUnaryOp( evaluateFirst->childOp(), evaluateFirst ); + evaluated = true; + } + if ( evaluated ) + { + // We need to save the result if we are going tro traverse the other + // branch, or if we are performing a subtraction in which case the + // value wanted in working is not the current value. + // But as the optimizer will deal with unnecessary variables anyway, + // always save to a register + + evaluateFirst->setReg( dest1 ); + evaluateFirst->setType( variable ); + m_pic->saveToReg( dest1 ); + } + + evaluated = false; + if( evaluateSecond->hasChildren() ) + { + mb->incDest(); + mb->incDest(); + traverseTree(evaluateSecond); + evaluated = true; + mb->decDest(); + mb->decDest(); + } + else if( isUnaryOp(evaluateSecond->childOp()) ) + { + doUnaryOp( evaluateSecond->childOp(), evaluateSecond ); + evaluated = true; + } + if ( evaluated ) + { + evaluateSecond->setReg( dest2 ); + evaluateSecond->setType( variable ); + m_pic->saveToReg( dest2 ); + } + } + + if(t.current()->childOp()==divbyzero) + { + mistake( Microbe::DivisionByZero ); + } + + // If we are at the top level of something like 'if a == 3 then', then we are ready to put + // in the if code, else the expression just evaluates to 0 or 1 + if(conditionalRoot && t.current() == root) + m_pic->setConditionalCode(m_ifCode, m_elseCode); + + // Handle operations + // (functions are not actually supported) + if(isUnaryOp(t.current()->childOp())) + doUnaryOp( t.current()->childOp(), t.current() ); + else + doOp( t.current()->childOp(), t.current()->left(), t.current()->right() ); + +} + +void Expression::doOp( Operation op, BTreeNode *left, BTreeNode *right ) +{ + QString lvalue; + if(left->reg().isEmpty()) + lvalue = left->value(); + else + lvalue = left->reg(); + + QString rvalue; + if(right->reg().isEmpty()) + rvalue = right->value(); + else + rvalue = right->reg(); + + // Handle if stuff + PIC14::LocationType leftType; + switch ( left->type() ) + { + case number: + leftType = PIC14::num; + break; + + case variable: + leftType = PIC14::var; + break; + + case working: + leftType = PIC14::work; + break; + + case unset: + case extpin: + case keypad: + kdError() << k_funcinfo << "Bad left->type(): " << left->type() << endl; + }; + + PIC14::LocationType rightType; + switch ( right->type() ) + { + case number: + rightType = PIC14::num; + break; + + case variable: + rightType = PIC14::var; + break; + + case working: + rightType = PIC14::work; + break; + + case unset: + case extpin: + case keypad: + kdError() << k_funcinfo << "Bad right->type(): " << right->type() << endl; + }; + + switch(op) + { + case equals: m_pic->equal( lvalue, rvalue, leftType, rightType ); break; + case notequals: m_pic->notEqual( lvalue, rvalue, leftType, rightType ); break; + case lt: m_pic->lessThan( lvalue, rvalue, leftType, rightType ); break; + case gt: m_pic->greaterThan( lvalue, rvalue, leftType, rightType ); break; + case le: m_pic->lessOrEqual( lvalue, rvalue, leftType, rightType ); break; + case ge: m_pic->greaterOrEqual( lvalue, rvalue, leftType, rightType ); break; + + case addition: m_pic->add( lvalue, rvalue, leftType, rightType ); break; + case subtraction: m_pic->subtract( lvalue, rvalue, leftType, rightType ); break; + case multiplication: m_pic->mul( lvalue, rvalue, leftType, rightType ); break; + case division: m_pic->div( lvalue, rvalue, leftType, rightType ); break; + + case bwand: m_pic->bitwise( bwand, lvalue, rvalue, leftType, rightType ); break; + case bwor: m_pic->bitwise( bwor, lvalue, rvalue, leftType, rightType ); break; + case bwxor: m_pic->bitwise( bwxor, lvalue, rvalue, leftType, rightType ); break; + case bwnot: m_pic->bitwise( bwnot, lvalue, rvalue, leftType, rightType ); break; + + default: break; + } +} + +void Expression::buildTree( const QString & unstrippedExpression, BTreeBase *tree, BTreeNode *node, int level ) +{ + int firstEnd = 0; + int secondStart = 0; + bool unary = false; + Operation op; + QString expression = stripBrackets( unstrippedExpression ); + switch(level) + { + // ==, != + case 0: + { + int equpos = findSkipBrackets(expression, "=="); + int neqpos = findSkipBrackets(expression, "!="); + if( equpos != -1 ) + { + op = equals; + firstEnd = equpos; + secondStart = equpos + 2; + } + else if( neqpos != -1 ) + { + op = notequals; + firstEnd = neqpos; + secondStart = neqpos + 2; + } + else op = noop; + break; + } + + // <, <=, >=, > + case 1: + { + int ltpos = findSkipBrackets(expression, "<"); + int lepos = findSkipBrackets(expression, "<="); + int gepos = findSkipBrackets(expression, ">="); + int gtpos = findSkipBrackets(expression, ">"); + // Note: if (for example) "<=" is present, "<" will also be present. This + // means that we have to check for "<=" before "<", etc. + if( lepos != -1 ) + { + op = le; + firstEnd = lepos; + secondStart = lepos + 2; + } + else if( gepos != -1 ) + { + op = ge; + firstEnd = gepos; + secondStart = gepos + 2; + } + else if( ltpos != -1 ) + { + op = lt; + firstEnd = ltpos; + secondStart = ltpos + 1; + } + else if( gtpos != -1 ) + { + op = gt; + firstEnd = gtpos; + secondStart = gtpos + 1; + } + else op = noop; + break; + } + + // +,- + case 2: + { + int addpos = findSkipBrackets(expression, '+'); + int subpos = findSkipBrackets(expression, '-'); + if( subpos != -1 ) + { + op = subtraction; + firstEnd = subpos; + secondStart = subpos + 1; + } + else if( addpos != -1 ) + { + op = addition; + firstEnd = addpos; + secondStart = addpos + 1; + } + else op = noop; + break; + } + + // *,/ + case 3: + { + int mulpos = findSkipBrackets(expression, '*'); + int divpos = findSkipBrackets(expression, '/'); + if( divpos != -1 ) + { + op = division; + firstEnd = divpos; + secondStart = divpos + 1; + } + else if( mulpos != -1 ) + { + op = multiplication; + firstEnd = mulpos; + secondStart = mulpos + 1; + } + else op = noop; + break; + } + + // ^ + case 4: + { + int exppos = findSkipBrackets(expression, '^'); + if( exppos != -1 ) + { + op = exponent; + firstEnd = exppos; + secondStart = exppos + 1; + } + else op = noop; + break; + } + + // AND, OR, XOR + case 5: + { + int bwAndPos = findSkipBrackets(expression, " AND "); + int bwOrPos = findSkipBrackets(expression, " OR "); + int bwXorPos = findSkipBrackets(expression, " XOR "); + if( bwAndPos != -1 ) + { + op = bwand; + firstEnd = bwAndPos; + secondStart = bwAndPos + 5; + } + else if( bwOrPos != -1 ) + { + op = bwor; + firstEnd = bwOrPos; + secondStart = bwOrPos + 4; + } + else if( bwXorPos != -1 ) + { + op = bwxor; + firstEnd = bwXorPos; + secondStart = bwXorPos + 5; + } + else op = noop; + break; + } + + // NOT + case 6: + { + int bwNotPos = findSkipBrackets(expression, " NOT "); + if( bwNotPos != -1 ) + { + op = bwnot; + unary = true; + firstEnd = bwNotPos; // this line is not needed for unary things/ + secondStart = bwNotPos + 5; + } + else op = noop; + break; + } + } + + node->setChildOp(op); + + QString tokens[2]; + tokens[0] = expression.left(firstEnd).stripWhiteSpace(); + tokens[1] = expression.mid(secondStart).stripWhiteSpace(); + + if( op != noop ) + { + for( int j = 0; j < 2; j++ ) + { + + BTreeNode *newNode = new BTreeNode(); + tree->addNode( node, newNode, (j == 0) ); + // we need to strip any brackets from the sub-expression + + // try each token again at the same level, if they + // don't have any of this level's operators, then the function + // will go to the next level as below. + + // For unary opertaions, e.g NOT, we have no special + // code for nodes with only one child, so we leave the left + // hand child blank and put the rest in the right hand node. + if( unary && j == 0 ) + { + newNode->setValue(""); + newNode->setType(number); + } + else buildTree(tokens[j], tree, newNode, 0 ); + } + } + else + { + // if there was no relevant operation i.e. " 3*4 / 6" as opposed to " 3*4 + 6" + // then just pass the node onto the next parsing level. + // unless we are at the lowest level, in which case we have reached a final value. + if( level == 6 ) expressionValue(expression,tree,node); + else + { + buildTree(expression,tree,node,level + 1); + } + } +} + +void Expression::doUnaryOp(Operation op, BTreeNode *node) +{ + /* Note that this isn't for unary operations as such, + rather for things that are operations that have no direct children, + e.g. portx.n is high, and functionname(args)*/ + + if ( op == pin || op == notpin ) + m_pic->Spin( m_pic->toPortPin( node->value() ), (op==notpin) ); + + else if ( op == read_keypad ) + m_pic->Skeypad( mb->variable( node->value() ) ); +} + +void Expression::compileExpression( const QString & expression ) +{ + // Make a tree to put the expression in. + BTreeBase *tree = new BTreeBase(); + BTreeNode *root = new BTreeNode(); + + // parse the expression into the tree + buildTree(expression,tree,root,0); + // compile the tree into assembly code + tree->setRoot(root); + tree->pruneTree(tree->root()); + traverseTree(tree->root()); + + // Note deleting the tree deletes all nodes, so the root + // doesn't need deleting separately. + delete tree; + return; +} + +void Expression::compileConditional( const QString & expression, Code * ifCode, Code * elseCode ) +{ + if( expression.contains(QRegExp("=>|=<|=!")) ) + { + mistake( Microbe::InvalidComparison, expression ); + return; + } + if( expression.contains(QRegExp("[^=>childOp() != equals && + root->childOp() != notequals && + root->childOp() != gt && + root->childOp() != lt && + root->childOp() != ge && + root->childOp() != le && + root->childOp() != pin && + root->childOp() != notpin && + root->childOp() != read_keypad ) + { + BTreeNode *newRoot = new BTreeNode(); + + BTreeNode *oneNode = new BTreeNode(); + oneNode->setChildOp(noop); + oneNode->setType(number); + oneNode->setValue("1"); + + newRoot->setLeft(root); + newRoot->setRight(oneNode); + newRoot->setType(unset); + newRoot->setChildOp(ge); + + tree->setRoot(newRoot); + root = newRoot; + } + // compile the tree into assembly code + tree->setRoot(root); + tree->pruneTree(tree->root(),true); + + // We might have just a constant expression, in which case we can just always do if or else depending + // on whether it is true or false. + if( root->childOp() == noop ) + { + if( root->value().toInt() == 0 ) + m_pic->mergeCode( elseCode ); + else + m_pic->mergeCode( ifCode ); + return; + } + + // traverse tree with argument conditionalRoot true + // so that 3 == x gets integrated with code for if, repeat until etc... + m_ifCode = ifCode; + m_elseCode = elseCode; + traverseTree(tree->root(),true); + + // Note deleting the tree deletes all nodes, so the root + // doesn't need deleting separately. + delete tree; +} + +bool Expression::isUnaryOp(Operation op) +{ + return op == pin || op == notpin || op == function || op == read_keypad; +} + + +void Expression::mistake( Microbe::MistakeType type, const QString & context ) +{ + mb->compileError( type, context, m_sourceLine ); +} + +int Expression::findSkipBrackets( const QString & expr, char ch, int startPos) +{ + bool found = false; + int i = startPos; + int bracketLevel = 0; + while(!found) + { + if(expr[i].latin1() == '\'') + { + if( i + 2 < int(expr.length()) ) + { + if( expr[i+2].latin1() == '\'' ) + { + i = i + 2; + found = true; + } + } + } + + if(expr[i].latin1() == '(') bracketLevel++; + else if(expr[i].latin1() == ')') bracketLevel--; + + if( bracketLevel == 0 ) + { + if(expr[i].latin1() == ch) found = true; + else i++; + } + else i++; + + if( i >= int(expr.length()) ) + { + found = true; + i = -1; + } + } + return i; +} + +int Expression::findSkipBrackets( const QString & expr, QString phrase, int startPos) +{ + bool found = false; + int i = startPos; + int bracketLevel = 0; + while(!found) + { + if(expr[i].latin1() == '\'') + { + if( i + 2 < int(expr.length()) ) + { + if( expr[i+2].latin1() == '\'' ) + { + i = i + 2; + found = true; + } + } + } + + if(expr[i].latin1() == '(') bracketLevel++; + else if(expr[i].latin1() == ')') bracketLevel--; + + if( bracketLevel == 0 ) + { + if(expr.mid(i,phrase.length()) == phrase) found = true; + else i++; + } + else i++; + + if( i >= int(expr.length()) ) + { + found = true; + i = -1; + } + } + return i; +} + +QString Expression::stripBrackets( QString expression ) +{ + bool stripping = true; + int bracketLevel = 0; + int i = 0; + expression = expression.stripWhiteSpace(); + while(stripping) + { + if( expression.at(i) == '(' ) bracketLevel++; + else if( expression.at(i) == ')' ) + { + if( i == int(expression.length() - 1) && bracketLevel == 1) + { + expression = expression.mid(1,expression.length() - 2).stripWhiteSpace(); + } + bracketLevel--; + } + if( i == int(expression.length() - 1) && bracketLevel > 0 ) + { + mistake( Microbe::MismatchedBrackets, expression ); + // Stray brackets might cause the expressionession parser some problems, + // so we just avoid parsing anything altogether + expression = ""; + stripping = false; + } + i++; + if( bracketLevel == 0 ) stripping = false; + } + return expression; +} + +void Expression::expressionValue( QString expr, BTreeBase */*tree*/, BTreeNode *node) +{ + /* The "end of the line" for the expression parsing, the + expression has been broken down into the fundamental elements of expr.value()=="to"|| + variable, number, special etc... so we now just set value and type */ + + + + /* Alternatively we might have a function call + e.g. somefunction(3,potatoes,hairstyle + 6) + In which case we need to call back to parseExpr to process the arguments, + saving them on the basic stack then making the function call. + Of course we also need to mark the terminal node type as a function. + */ + expr = expr.stripWhiteSpace(); + + // My intention is so that these error checks are ordered + // so that e.g. for x = 3 it picks up the = rather than the spaces first. + + + expr = mb->alias(expr); + ExprType t = expressionType(expr); + + + // See if it is a single qouted character, e.g. 'A' + if( expr.left(1) == "\'" && expr.right(1) == "\'" ) + { + if( expr.length() == 3 ) // fall through to report as unknown variable if not of form 'x' + { + // If so, turn it into a number, and use the ASCII code as the value + t = number; + expr = QString::number(expr[1].latin1()); + } + } + + // Check for the most common mistake ever! + if(expr.contains("=")) + mistake( Microbe::InvalidEquals ); + // Check for reserved keywords + if(expr=="to"||expr=="step"||expr=="then") + mistake( Microbe::ReservedKeyword, expr ); + + // Check for empty expressions, or expressions contating spaces + // both indicating a Mistake. + if(expr.isEmpty()) + mistake( Microbe::ConsecutiveOperators ); + else if(expr.contains(QRegExp("\\s")) && t!= extpin) + mistake( Microbe::MissingOperator ); + + if( t == variable && !mb->isVariableKnown(expr) && !m_pic->isValidPort( expr ) && !m_pic->isValidTris( expr ) ) + mistake( Microbe::UnknownVariable, expr ); + + if ( mb->isVariableKnown(expr) && !mb->variable(expr).isReadable() ) + mistake( Microbe::WriteOnlyVariable, expr ); + + node->setType(t); + + // Since we currently only implement 8 bit unsigned integers, we should disallow + // anything outside the range [0-255]. + if( t == number && !m_bSupressNumberTooBig && (expr.toInt() > 255) ) + { + mistake( Microbe::NumberTooBig ); + } + + // if there was a pin, we need to decocde it. + // For now and sacrificing syntax error checking + // we just look for the word "is" then "high" or "low". + if( t == extpin ) + { + bool NOT; + int i = expr.find("is"); + if(i > 0) + { + NOT = expr.contains("low"); + if(!expr.contains("high") && !expr.contains("low")) + mistake( Microbe::HighLowExpected, expr ); + expr = expr.left(i-1); + } + else NOT = false; + node->setChildOp(NOT?notpin:pin); + } + + else if ( t == keypad ) + node->setChildOp( read_keypad ); + + node->setValue(expr); +} + +ExprType Expression::expressionType( const QString & expression ) +{ + // So we can't handle complex expressions yet anyway, + // let's just decide whether it is a variable or number. + + // Thanks to the convention that variable names must not + // begin with a number this is extremely simple to do! + + /* But now there is a catch, because there can also be + things that have a first character alpha, but are of the form + "portb.3 is high", general syntax: portx.n is + additionally, there can be things that are just porta.6, which just return the truth of that port. + In reality it is just: + portx.n is high === portx.n + portx.n is low === !(portx.n) + These types of expression can be identified by the fact + that they should be the only things that contain a '.' + */ + + /* Note that at the moment, literalToInt returns -1 if it is + not literal so isLiteral is redundant, but this may change if say + negative numbers are implemented + */ + + int value = Parser::literalToInt(expression); + if ( value != -1 ) + return number; + + if( expression.contains('.') ) + return extpin; + + if ( mb->variable( expression ).type() == Variable::keypadType ) + return keypad; + + return variable; +} + +QString Expression::processConstant( const QString & expr, bool * isConstant ) +{ + bool temp; + if (!isConstant) + isConstant = &temp; + + QString code; + + // Make a tree to put the expression in. + BTreeBase *tree = new BTreeBase(); + BTreeNode *root = new BTreeNode(); + + // parse the expression into the tree + buildTree(expr,tree,root,0); + // compile the tree into assembly code + tree->setRoot(root); + tree->pruneTree(tree->root()); + //code = traverseTree(tree->root()); + // Look to see if it is a number + if( root->type() == number ) + { + code = root->value(); + *isConstant = true; + } + else + { + code = ""; + *isConstant = false; + } + + // Note deleting the tree deletes all nodes, so the root + // doesn't need deleting separately. + delete tree; + return code; +} diff --git a/microbe/expression.h b/microbe/expression.h new file mode 100644 index 0000000..9607f16 --- /dev/null +++ b/microbe/expression.h @@ -0,0 +1,126 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by Daniel Clarke * + * daniel.jc@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef EXPRESSION_H +#define EXPRESSION_H + +#include "microbe.h" + +#include + +class PIC14; +class BTreeNode; +class Microbe; + +/** +@author Daniel Clarke +@author David Saxton +*/ +class Expression +{ + public: + enum Operation + { + noop, + addition, + subtraction, + multiplication, + division, + exponent, + equals, + notequals, + pin,//(returns the truth value obtatined by testing the pin) + notpin, //(the result of doing the pin op NOTted).] + read_keypad, //read value from keypad + function, + bwand, + bwor, + bwxor, + bwnot, + divbyzero, // used to make handling this situation easier + gt, + lt, + ge, + le + }; + + Expression(PIC14 *pic, Microbe *master, SourceLine sourceLine, bool supressNumberTooBig ); + ~Expression(); + + /** + * Generates the code needed to evaluate an expression. Firstly, a tree + * is generated from the expression string; then that tree is traversed + * to generate the assembly. + */ + void compileExpression( const QString & expression); + void compileConditional( const QString & expression, Code * ifCode, Code * elseCode ); + /** + * Returns a *number* rather than evaluating code, and sets isConstant to true + * if it the expression evaluated to a constant. + */ + QString processConstant( const QString & expr, bool * isConsant ); + + private: + PIC14 *m_pic; + Microbe *mb; + + /** Turns the operations encoded in the given tree into assembly code */ + void traverseTree( BTreeNode *root, bool conditionalRoot = false ); + + bool isUnaryOp(Operation op); + + void expressionValue( QString expression, BTreeBase *tree, BTreeNode *node ); + void doOp( Operation op, BTreeNode *left, BTreeNode *right ); + void doUnaryOp( Operation op, BTreeNode *node ); + /** + * Parses an expression, and generates a tree structure from it. + */ + void buildTree( const QString & expression, BTreeBase *tree, BTreeNode *node, int level ); + + static int findSkipBrackets( const QString & expr, char ch, int startPos = 0); + static int findSkipBrackets( const QString & expr, QString phrase, int startPos = 0); + + QString stripBrackets( QString expression ); + + void mistake( Microbe::MistakeType type, const QString & context = 0 ); + + SourceLine m_sourceLine; + + Code * m_ifCode; + Code * m_elseCode; + + /** + *Returns expression type + * 0 = directly usable number (literal) + * 1 = variable + * 2 = expression that needs evaluating + * (maybe not, see enum). + */ + ExprType expressionType( const QString & expression ); + static bool isLiteral( const QString &text ); + /** + * Normally, only allow numbers upto 255; but for some uses where the + * number is not going to be placed in a PIC register (such as when + * delaying), we can ignore numbers being too big. + */ + bool m_bSupressNumberTooBig; +}; + +#endif diff --git a/microbe/instruction.cpp b/microbe/instruction.cpp new file mode 100644 index 0000000..b2b02b4 --- /dev/null +++ b/microbe/instruction.cpp @@ -0,0 +1,2309 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by Daniel Clarke * + * 2005 by David Saxton * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "instruction.h" +#include "optimizer.h" +#include "pic14.h" + +#include +#include + +#include +#include +using namespace std; + + +//BEGIN class Register +Register::Register( Type type ) +{ + m_type = type; + + switch ( m_type ) + { + case TMR0: + m_name = "TMR0"; + break; + case OPTION_REG: + m_name = "OPTION_REG"; + break; + case PCL: + m_name = "PCL"; + break; + case STATUS: + m_name = "STATUS"; + break; + case FSR: + m_name = "FSR"; + break; + case PORTA: + m_name = "PORTA"; + break; + case TRISA: + m_name = "TRISA"; + break; + case PORTB: + m_name = "PORTB"; + break; + case TRISB: + m_name = "TRISB"; + break; + case EEDATA: + m_name = "EEDATA"; + break; + case EECON1: + m_name = "EECON1"; + break; + case EEADR: + m_name = "EEADR"; + break; + case EECON2: + m_name = "EECON2"; + break; + case PCLATH: + m_name = "PCLATH"; + break; + case INTCON: + m_name = "INTCON"; + break; + case WORKING: + m_name = ""; + break; + case GPR: + case none: + break; + } +} + + +Register::Register( const QString & name ) +{ + m_name = name.stripWhiteSpace(); + QString upper = m_name.upper(); + + if ( upper == "TMR0" ) + m_type = TMR0; + else if ( upper == "OPTION_REG" ) + m_type = OPTION_REG; + else if ( upper == "PCL" ) + m_type = PCL; + else if ( upper == "STATUS") + m_type = STATUS; + else if ( upper == "FSR") + m_type = FSR; + else if ( upper == "PORTA") + m_type = PORTA; + else if ( upper == "TRISA") + m_type = TRISA; + else if ( upper == "PORTB") + m_type = PORTB; + else if ( upper == "TRISB") + m_type = TRISB; + else if ( upper == "EEDATA") + m_type = EEDATA; + else if ( upper == "EECON1") + m_type = EECON1; + else if ( upper == "EEADR") + m_type = EEADR; + else if ( upper == "EECON2") + m_type = EECON2; + else if ( upper == "PCLATH") + m_type = PCLATH; + else if ( upper == "INTCON") + m_type = INTCON; + else + m_type = GPR; +} + + +Register::Register( const char * name ) +{ + *this = Register( QString(name) ); +} + + +bool Register::operator < ( const Register & reg ) const +{ + if ( (type() != GPR) || (reg.type() != GPR) ) + return type() < reg.type(); + + return name() < reg.name(); +} + + +bool Register::operator == ( const Register & reg ) const +{ + if ( type() != reg.type() ) + return false; + + return name() == reg.name(); +} + + +uchar Register::banks() const +{ + switch ( m_type ) + { + case TMR0: return Bank0; + case OPTION_REG: return Bank1; + case PCL: return Bank0 | Bank1; + case STATUS: return Bank0 | Bank1; + case FSR: return Bank0 | Bank1; + case PORTA: return Bank0; + case TRISA: return Bank1; + case PORTB: return Bank0; + case TRISB: return Bank1; + case EEDATA: return Bank0; + case EECON1: return Bank1; + case EEADR: return Bank0; + case EECON2: return Bank1; + case PCLATH: return Bank0 | Bank1; + case INTCON: return Bank0 | Bank1; + + case GPR: return Bank0 | Bank1; + case WORKING: return Bank0 | Bank1; + case none: return Bank0 | Bank1; + } + + return Bank0 | Bank1; // Vacously true (and useful too) - a non-existent bank can be accessed anywhere +} + + +bool Register::bankDependent() const +{ + return ( banks() != (Bank0 | Bank1) ); +} + + +bool Register::affectsExternal() const +{ + switch ( m_type ) + { + case PORTA: + case TRISA: + case PORTB: + case TRISB: + return true; + + case TMR0: + case OPTION_REG: + case PCL: + case STATUS: + case FSR: + case EEDATA: + case EECON1: + case EEADR: + case EECON2: + case PCLATH: + case INTCON: + case GPR: + case WORKING: + case none: + return false; + } + return false; +} +//END class Register + + + +//BEGIN class RegisterBit +RegisterBit::RegisterBit( uchar bitPos, Register::Type reg ) +{ + m_bitPos = bitPos; + m_registerType = reg; + + switch ( m_registerType ) + { + case Register::STATUS: + { + switch ( m_bitPos ) + { + case 0: m_name = "C"; break; + case 1: m_name = "DC"; break; + case 2: m_name = "Z"; break; + case 3: m_name = "NOT_PD"; break; + case 4: m_name = "NOT_TO"; break; + case 5: m_name = "RP0"; break; + case 6: m_name = "RP1"; break; + case 7: m_name = "IRP"; break; + } + break; + } + case Register::INTCON: + { + switch ( m_bitPos ) + { + case 0: m_name = "RBIF"; break; + case 1: m_name = "INTF"; break; + case 2: m_name = "T0IF"; break; + case 3: m_name = "RBIE"; break; + case 4: m_name = "INTE"; break; + case 5: m_name = "T0IE"; break; + case 6: m_name = "EEIE"; break; + case 7: m_name = "GIE"; break; + } + break; + } + case Register::OPTION_REG: + { + switch ( m_bitPos ) + { + case 0: m_name = "PS0"; break; + case 1: m_name = "PS1"; break; + case 2: m_name = "PS2"; break; + case 3: m_name = "PSa"; break; + case 4: m_name = "T0SE"; break; + case 5: m_name = "T0CS"; break; + case 6: m_name = "INTEDG"; break; + case 7: m_name = "NOT_RBPU"; break; + } + break; + } + case Register::EECON1: + { + switch ( m_bitPos ) + { + case 0: m_name = "RD"; break; + case 1: m_name = "WR"; break; + case 2: m_name = "WREN"; break; + case 3: m_name = "WRERR"; break; + case 4: m_name = "EEIF"; break; + } + break; + } + + case Register::TMR0: + case Register::PCL: + case Register::FSR: + case Register::PORTA: + case Register::TRISA: + case Register::PORTB: + case Register::TRISB: + case Register::EEDATA: + case Register::EEADR: + case Register::EECON2: + case Register::PCLATH: + case Register::GPR: + case Register::WORKING: + case Register::none: + { +// kdError() << k_funcinfo << "Bad register: " << reg << endl; + } + } +} + + +RegisterBit::RegisterBit( const QString & name ) +{ + m_name = name.upper().stripWhiteSpace(); + initFromName(); +} + + +RegisterBit::RegisterBit( const char * name ) +{ + m_name = QString(name).upper().stripWhiteSpace(); + initFromName(); +} + + +void RegisterBit::initFromName() +{ + bool ok; + m_bitPos = m_name.toInt( & ok, 0 ); + if ( ok ) + m_registerType = Register::none; // hmm it should be unknown - not none. + + else if ( m_name == "C" ) + { + m_registerType = Register::STATUS; + m_bitPos = 0; + } + else if ( m_name == "DC" ) + { + m_registerType = Register::STATUS; + m_bitPos = 1; + } + else if ( m_name == "Z" ) + { + m_registerType = Register::STATUS; + m_bitPos = 2; + } + else if ( m_name == "NOT_PD" ) + { + m_registerType = Register::STATUS; + m_bitPos = 3; + } + else if ( m_name == "NOT_TO" ) + { + m_registerType = Register::STATUS; + m_bitPos = 4; + } + else if ( m_name == "RP0" ) + { + m_registerType = Register::STATUS; + m_bitPos = 5; + } + else if ( m_name == "RP1" ) + { + m_registerType = Register::STATUS; + m_bitPos = 6; + } + else if ( m_name == "IRP" ) + { + m_registerType = Register::STATUS; + m_bitPos = 7; + } + else if ( m_name == "RBIF" ) + { + m_registerType = Register::INTCON; + m_bitPos = 0; + } + else if ( m_name == "INTF" ) + { + m_registerType = Register::INTCON; + m_bitPos = 1; + } + else if ( m_name == "T0IF" ) + { + m_registerType = Register::INTCON; + m_bitPos = 2; + } + else if ( m_name == "RBIE" ) + { + m_registerType = Register::INTCON; + m_bitPos = 3; + } + else if ( m_name == "INTE" ) + { + m_registerType = Register::INTCON; + m_bitPos = 4; + } + else if ( m_name == "T0IE" ) + { + m_registerType = Register::INTCON; + m_bitPos = 5; + } + else if ( m_name == "EEIE" ) + { + m_registerType = Register::INTCON; + m_bitPos = 6; + } + else if ( m_name == "GIE" ) + { + m_registerType = Register::INTCON; + m_bitPos = 7; + } + else if ( m_name == "PS0" ) + { + m_registerType = Register::OPTION_REG; + m_bitPos = 0; + } + else if ( m_name == "PS1" ) + { + m_registerType = Register::OPTION_REG; + m_bitPos = 1; + } + else if ( m_name == "PS2" ) + { + m_registerType = Register::OPTION_REG; + m_bitPos = 2; + } + else if ( m_name == "PSA" ) + { + m_registerType = Register::OPTION_REG; + m_bitPos = 3; + } + else if ( m_name == "T0SE" ) + { + m_registerType = Register::OPTION_REG; + m_bitPos = 4; + } + else if ( m_name == "T0CS" ) + { + m_registerType = Register::OPTION_REG; + m_bitPos = 5; + } + else if ( m_name == "INTEDG" ) + { + m_registerType = Register::OPTION_REG; + m_bitPos = 6; + } + else if ( m_name == "NOT_RBPU" ) + { + m_registerType = Register::OPTION_REG; + m_bitPos = 7; + } + else if ( m_name == "RD" ) + { + m_registerType = Register::EECON1; + m_bitPos = 0; + } + else if ( m_name == "WR" ) + { + m_registerType = Register::EECON1; + m_bitPos = 1; + } + else if ( m_name == "WREN" ) + { + m_registerType = Register::EECON1; + m_bitPos = 2; + } + else if ( m_name == "WRERR" ) + { + m_registerType = Register::EECON1; + m_bitPos = 3; + } + else if ( m_name == "EEIF" ) + { + m_registerType = Register::EECON1; + m_bitPos = 4; + } + else + { + m_registerType = Register::none; + m_bitPos = 0; + kdError() << k_funcinfo << "Unknown bit: " << m_name << endl; + } +} +//END class RegisterBit + + + + +//BEGIN class RegisterState +RegisterState::RegisterState() +{ + reset(); +} + + +void RegisterState::reset() +{ + known = 0x0; + value = 0x0; +} + + +void RegisterState::merge( const RegisterState & state ) +{ + known &= state.known; + known &= ~( value ^ state.value ); +} + + +bool RegisterState::operator == ( const RegisterState & state ) const +{ + return (known == state.known) && (value == state.value); +} + + +void RegisterState::print() +{ + cout << " known="<instructionList( (InstructionPosition)i ); + InstructionList::const_iterator end = list->end(); + for ( InstructionList::const_iterator it = list->begin(); it != end; ++it ) + append( *it, ( (i == Middle) ? middleInsertionPosition : (InstructionPosition)i ) ); + + // Queue any labels that the other code has queued + m_queuedLabels[i] += code->queuedLabels( (InstructionPosition)i ); + } +} + + +void Code::queueLabel( const QString & label, InstructionPosition position ) +{ +// cout << k_funcinfo << "label="<addLabels( m_queuedLabels[position] ); + m_queuedLabels[position].clear(); + } +} + + +Instruction * Code::instruction( const QString & label ) const +{ + for ( unsigned i = 0; i < PositionCount; ++i ) + { + InstructionList::const_iterator end = m_instructionLists[i].end(); + for ( InstructionList::const_iterator it = m_instructionLists[i].begin(); it != end; ++it ) + { + if ( (*it)->labels().contains( label ) ) + return *it; + } + } + return 0l; +} + + +Code::iterator Code::find( Instruction * instruction ) +{ + iterator e = end(); + iterator i = begin(); + for ( ; i != e; ++i ) + { + if ( *i == instruction ) + break; + } + return i; +} + + +void Code::postCompileConstruct() +{ + // Give any queued labels to the instructions in the subsequent code block + for ( unsigned i = 0; i < PositionCount; ++i ) + { + if ( m_queuedLabels[i].isEmpty() ) + continue; + + QStringList labels = m_queuedLabels[i]; + m_queuedLabels[i].clear(); + + // Find an instruction to dump them onto + for ( unsigned block = i+1; block < PositionCount; ++block ) + { + bool added = false; + + InstructionList::iterator end = m_instructionLists[block].end(); + for ( InstructionList::iterator it = m_instructionLists[block].begin(); it != end; ++it ) + { + if ( (*it)->type() == Instruction::Assembly ) + { + (*it)->addLabels( labels ); + added = true; + break; + } + } + + if ( added ) + break; + } + } +} + + +QString Code::generateCode( PIC14 * pic ) const +{ + QString code; + + const QStringList variables = findVariables(); + if ( !variables.isEmpty() ) + { + code += "; Variables\n"; + uchar reg = pic->gprStart(); + QStringList::const_iterator end = variables.end(); + for ( QStringList::const_iterator it = variables.begin(); it != end; ++it ) + code += QString("%1\tequ\t0x%2\n").arg( *it ).arg( QString::number( reg++, 16 ) ); + + code += "\n"; + } + + QString picString = pic->minimalTypeString(); + code += QString("list p=%1\n").arg( picString ); + code += QString("include \"p%2.inc\"\n\n").arg( picString.lower() ); + + code += "; Config options\n"; + code += " __config _WDT_OFF\n\n"; + + code += "START\n\n"; + + for ( unsigned i = 0; i < PositionCount; ++i ) + { + InstructionList::const_iterator end = m_instructionLists[i].end(); + for ( InstructionList::const_iterator it = m_instructionLists[i].begin(); it != end; ++it ) + { + const QStringList labels = (*it)->labels(); + if ( !labels.isEmpty() ) + { + code += '\n'; + QStringList::const_iterator labelsEnd = labels.end(); + for ( QStringList::const_iterator labelsIt = labels.begin(); labelsIt != labelsEnd; ++labelsIt ) + code += *labelsIt + '\n'; + } + + if ( (*it)->type() == Instruction::Assembly ) + code += '\t'; + code += (*it)->code() + '\n'; + } + } + + return code; +} + + +QStringList Code::findVariables() const +{ + QStringList variables; + + const_iterator e = end(); + for ( const_iterator i = begin(); i != e; ++i ) + { + if ( (*i)->file().type() != Register::GPR ) + continue; + + QString alias = (*i)->file().name(); + if ( !variables.contains( alias ) ) + variables << alias; + } + + return variables; +} + + +void Code::generateLinksAndStates() +{ + CodeIterator e = end(); + + for ( CodeIterator it = begin(); it != e; ++it ) + (*it)->clearLinks(); + + for ( CodeIterator it = begin(); it != e; ++it ) + (*it)->generateLinksAndStates( it ); + + // Generate return links for call instructions + // This cannot be done from the call instructions as we need to have + // generated the links first. + for ( CodeIterator it = begin(); it != e; ++it ) + { + Instr_call * ins = dynamic_cast(*it); + if ( !ins ) + continue; + + Instruction * next = *(++Code::iterator(it)); + ins->makeReturnLinks( next ); + } +} + + +void Code::setAllUnused() +{ + CodeIterator e = end(); + for ( CodeIterator it = begin(); it != e; ++it ) + { + (*it)->setUsed( false ); + (*it)->resetRegisterDepends(); + } +} + + +CodeIterator Code::begin() +{ + // Following code is very similar to the version of this function. + // Make sure any changes are applied to both (when applicable). + + for ( unsigned i = 0; i < PositionCount; ++i ) + { + if ( m_instructionLists[i].isEmpty() ) + continue; + + CodeIterator codeIterator; + codeIterator.code = this; + codeIterator.it = m_instructionLists[i].begin(); + codeIterator.pos = (Code::InstructionPosition)i; + codeIterator.list = & m_instructionLists[i]; + codeIterator.listEnd = m_instructionLists[i].end(); + + return codeIterator; + } + + return end(); +} + + +CodeIterator Code::end() +{ + // Following code is very similar to the version of this function. + // Make sure any changes are applied to both (when applicable). + + CodeIterator codeIterator; + codeIterator.code = this; + codeIterator.it = m_instructionLists[ PositionCount - 1 ].end(); + codeIterator.pos = (Code::InstructionPosition)(Code::PositionCount - 1); + codeIterator.list = & m_instructionLists[ PositionCount - 1 ]; + codeIterator.listEnd = m_instructionLists[ PositionCount - 1 ].end(); + return codeIterator; +} + + +CodeConstIterator Code::begin() const +{ + // Following code is very similar to the non-const version of this function. + // Make sure any changes are applied to both (when applicable). + + for ( unsigned i = 0; i < PositionCount; ++i ) + { + if ( m_instructionLists[i].isEmpty() ) + continue; + + CodeConstIterator codeIterator; + codeIterator.code = this; + codeIterator.it = m_instructionLists[i].begin(); + codeIterator.pos = (Code::InstructionPosition)i; + codeIterator.list = & m_instructionLists[i]; + codeIterator.listEnd = m_instructionLists[i].end(); + + return codeIterator; + } + + return end(); +} + + +CodeConstIterator Code::end() const +{ + // Following code is very similar to the non-const version of this function. + // Make sure any changes are applied to both (when applicable). + + CodeConstIterator codeIterator; + codeIterator.code = this; + codeIterator.it = m_instructionLists[ PositionCount - 1 ].end(); + codeIterator.pos = (Code::InstructionPosition)(Code::PositionCount - 1); + codeIterator.list = & m_instructionLists[ PositionCount - 1 ]; + codeIterator.listEnd = m_instructionLists[ PositionCount - 1 ].end(); + return codeIterator; +} +//END class Code + + + +//BEGIN class CodeIterator +CodeIterator & CodeIterator::operator ++ () +{ + // NOTE: This code is very similar to the const version. + // Any changes to thsi code should be applied there as well (when applicable). + + do + { + if ( ++it == listEnd && pos < (Code::PositionCount - 1) ) + { + bool found = false; + for ( pos = (Code::InstructionPosition)(pos+1); pos < Code::PositionCount; pos = (Code::InstructionPosition)(pos+1) ) + { + list = code->instructionList( pos ); + listEnd = list->end(); + if ( list->isEmpty() ) + continue; + + it = list->begin(); + found = true; + break; + } + + if ( !found ) + it = listEnd; + } + } + while ( (it != listEnd) && ((*it)->type() != Instruction::Assembly) ); + + return *this; +} + + +CodeIterator & CodeIterator::removeAndIncrement() +{ + Instruction * i = *it; + ++(*this); + code->removeInstruction( i ); + return *this; +} + + +void CodeIterator::insertBefore( Instruction * ins ) +{ + list->insert( it, ins ); +} +//END class CodeIterator + + + +//BEGIN class CodeConstIterator +CodeConstIterator & CodeConstIterator::operator ++ () +{ + // NOTE: This code is very similar to the non-const version. + // Any changes to thsi code should be applied there as well (when applicable). + + do + { + if ( ++it == listEnd && pos < (Code::PositionCount - 1) ) + { + bool found = false; + for ( pos = (Code::InstructionPosition)(pos+1); pos < Code::PositionCount; pos = (Code::InstructionPosition)(pos+1) ) + { + list = code->instructionList( pos ); + listEnd = list->end(); + if ( list->isEmpty() ) + continue; + + it = list->begin(); + found = true; + break; + } + + if ( !found ) + it = listEnd; + } + } + while ( (it != listEnd) && ((*it)->type() != Instruction::Assembly) ); + + return *this; +} +//END class CodeConstIterator + + + + +//BEGIN class Instruction +Instruction::Instruction() +{ + m_bInputStateChanged = true; + m_bPositionAffectsBranching = false; + m_bUsed = false; + m_literal = 0; + m_dest = 0; +} + + +Instruction::~ Instruction() +{ +} + + +void Instruction::addLabels( const QStringList & labels ) +{ + m_labels += labels; +} + + +void Instruction::setLabels( const QStringList & labels ) +{ + m_labels = labels; +} + + +void Instruction::generateLinksAndStates( Code::iterator current ) +{ + makeOutputLinks( current ); + m_outputState.reset(); +} + + +ProcessorBehaviour Instruction::behaviour() const +{ + return ProcessorBehaviour(); +} + + +void Instruction::makeOutputLinks( Code::iterator current, bool firstOutput, bool secondOutput ) +{ + if ( !firstOutput && !secondOutput ) + return; + + ++current; + if ( !*current ) + { + kdWarning() << k_funcinfo << "current+1 is null"<addInputLink( this ); + + if ( !secondOutput ) + return; + + ++current; + (*current)->addInputLink( this ); +} + + +void Instruction::makeLabelOutputLink( const QString & label ) +{ + Instruction * output = m_pCode->instruction( label ); + if ( output ) + output->addInputLink( this ); +} + + +void Instruction::addInputLink( Instruction * instruction ) +{ + // Don't forget that a link to ourself is valid! + if ( !instruction || m_inputLinks.contains( instruction ) ) + return; + + m_inputLinks << instruction; + instruction->addOutputLink( this ); +} + + +void Instruction::addOutputLink( Instruction * instruction ) +{ + // Don't forget that a link to ourself is valid! + if ( !instruction || m_outputLinks.contains( instruction ) ) + return; + + m_outputLinks << instruction; + instruction->addInputLink( this ); +} + + +void Instruction::removeInputLink( Instruction * instruction ) +{ + m_inputLinks.remove( instruction ); +} + + +void Instruction::removeOutputLink( Instruction * instruction ) +{ + m_outputLinks.remove( instruction ); +} + + +void Instruction::clearLinks() +{ + m_inputLinks.clear(); + m_outputLinks.clear(); +} +//END class Instruction + + + +//BEGIN Byte-Oriented File Register Operations +QString Instr_addwf::code() const +{ + return QString("addwf\t%1,%2").arg( m_file.name() ).arg( m_dest ); +} + +void Instr_addwf::generateLinksAndStates( Code::iterator current ) +{ + m_outputState = m_inputState; + + m_outputState.reg( outputReg() ).value = (m_inputState.working.value + m_inputState.reg( m_file ).value) & 0xff; + m_outputState.reg( outputReg() ).known = ((m_inputState.working.known == 0xff) && (m_inputState.reg( m_file ).known == 0xff)) ? 0xff : 0x0; + + m_outputState.status.known &= ~( (1 << RegisterBit::C) | (1 << RegisterBit::DC) | (1 << RegisterBit::Z) ); + + if ( m_file.type() != Register::PCL || m_dest == 0 ) + { + makeOutputLinks( current ); + return; + } + + ++current; // Don't have a link to ourself + + // maxInc is the greatest possibly value that we might have incremented the program counter by. + // It is generated by ORing the known bits of the working register with the greatest value + // of the unknown bits; + uchar maxInc = m_inputState.working.maxValue(); + if ( maxInc < 0xff ) + maxInc++; +// cout << "m_inputState.working.known="< m_inputState.reg( m_file ).maxValue() ) + { + m_outputState.status.value &= ~(1 << RegisterBit::C); + m_outputState.status.known |= (1 << RegisterBit::C); + } + else if ( m_inputState.working.maxValue() <= m_inputState.reg( m_file ).minValue() ) + { + m_outputState.status.value |= (1 << RegisterBit::C); + m_outputState.status.known |= (1 << RegisterBit::C); + } + + if ( (m_inputState.working.known == 0xff) && (m_inputState.reg( m_file ).known == 0xff) ) + { + bool isZero = (m_inputState.working.value == m_inputState.reg( m_file ).value); + if ( isZero ) + m_outputState.status.value |= (1 << RegisterBit::Z); + else + m_outputState.status.value &= ~(1 << RegisterBit::Z); + m_outputState.status.known |= (1 << RegisterBit::Z); + } +} + +ProcessorBehaviour Instr_subwf::behaviour() const +{ + ProcessorBehaviour behaviour; + + // Depend on W and f + behaviour.working.depends = 0xff; + behaviour.reg( m_file ).depends = 0xff; + + behaviour.status.depends = m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0; + behaviour.status.indep = (1 << RegisterBit::C) | (1 << RegisterBit::DC) | (1 << RegisterBit::Z); + return behaviour; +} + + +QString Instr_swapf::code() const +{ + return QString("swapf\t%1,%2").arg( m_file.name() ).arg( m_dest ); +} + +void Instr_swapf::generateLinksAndStates( Code::iterator current ) +{ + makeOutputLinks( current ); + + m_outputState = m_inputState; + if ( m_dest == 0 ) + { + // Writing to the working register + m_outputState.working.known = 0x0; + } +} + +ProcessorBehaviour Instr_swapf::behaviour() const +{ + ProcessorBehaviour behaviour; + behaviour.reg( m_file ).depends = 0xff; + behaviour.working.indep = ( m_dest == 0 ) ? 0xff : 0x0; + behaviour.status.depends = m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0; + return behaviour; +} + + +QString Instr_xorwf::code() const +{ + return QString("xorwf\t%1,%2").arg( m_file.name() ).arg( m_dest ); +} + +void Instr_xorwf::generateLinksAndStates( Code::iterator current ) +{ + makeOutputLinks( current ); + + m_outputState = m_inputState; + m_outputState.status.known &= ~(1 << RegisterBit::Z); + + m_outputState.reg( outputReg() ).known = 0x0; +} + +ProcessorBehaviour Instr_xorwf::behaviour() const +{ + ProcessorBehaviour behaviour; + + // Depend on W and f + behaviour.working.depends = 0xff; + behaviour.reg( m_file ).depends = 0xff; + + behaviour.status.depends = m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0; + behaviour.status.indep = (1 << RegisterBit::Z); + return behaviour; +} +//END Byte-Oriented File Register Operations + + + +//BEGIN Bit-Oriented File Register Operations +QString Instr_bcf::code() const +{ + return QString("bcf\t\t%1,%2").arg( m_file.name() ).arg( m_bit.name() ); +} + +void Instr_bcf::generateLinksAndStates( Code::iterator current ) +{ + makeOutputLinks( current ); + + m_outputState = m_inputState; + m_outputState.reg( m_file ).value &= ~uchar(1 << m_bit.bitPos()); + m_outputState.reg( m_file ).known |= uchar(1 << m_bit.bitPos()); +} + +ProcessorBehaviour Instr_bcf::behaviour() const +{ + ProcessorBehaviour behaviour; + + behaviour.status.depends = m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0; + behaviour.reg( m_file ).indep = 1 << m_bit.bitPos(); + return behaviour; +} + + +QString Instr_bsf::code() const +{ + return QString("bsf\t\t%1,%2").arg( m_file.name() ).arg( m_bit.name() ); +} + +void Instr_bsf::generateLinksAndStates( Code::iterator current ) +{ + makeOutputLinks( current ); + + m_outputState = m_inputState; + m_outputState.reg( m_file ).value |= uchar(1 << m_bit.bitPos()); + m_outputState.reg( m_file ).known |= uchar(1 << m_bit.bitPos()); +} + +ProcessorBehaviour Instr_bsf::behaviour() const +{ + ProcessorBehaviour behaviour; + behaviour.status.depends = m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0; + behaviour.reg( m_file ).indep = 1 << m_bit.bitPos(); + return behaviour; +} + + +QString Instr_btfsc::code() const +{ + return QString("btfsc\t%1,%2").arg( m_file.name() ).arg( m_bit.name() ); +} + +void Instr_btfsc::generateLinksAndStates( Code::iterator current ) +{ + m_outputState = m_inputState; + + if ( m_inputState.reg( m_file ).known & (1 << m_bit.bitPos()) ) + { + bool bit = m_inputState.reg( m_file ).value & (1 << m_bit.bitPos()); + makeOutputLinks( current, bit, !bit ); + } + else + makeOutputLinks( current, true, true ); +} + +ProcessorBehaviour Instr_btfsc::behaviour() const +{ + ProcessorBehaviour behaviour; + behaviour.reg( m_file ).depends = 1 << m_bit.bitPos(); + behaviour.status.depends = (m_file.type() == Register::STATUS) ? m_bit.bit() : 0x0; + return behaviour; +} + + +QString Instr_btfss::code() const +{ + return QString("btfss\t%1,%2").arg( m_file.name() ).arg( m_bit.name() ); +} + +void Instr_btfss::generateLinksAndStates( Code::iterator current ) +{ + m_outputState = m_inputState; + + if ( m_inputState.reg( m_file ).known & (1 << m_bit.bitPos()) ) + { + bool bit = m_inputState.reg( m_file ).value & (1 << m_bit.bitPos()); + makeOutputLinks( current, !bit, bit ); + } + else + makeOutputLinks( current, true, true ); +} + +ProcessorBehaviour Instr_btfss::behaviour() const +{ + ProcessorBehaviour behaviour; + behaviour.reg( m_file ).depends = 1 << m_bit.bitPos(); + behaviour.status.depends = (m_file.type() == Register::STATUS) ? m_bit.bit() : 0x0; + return behaviour; +} +//END Bit-Oriented File Register Operations + + + +//BEGIN Literal and Control Operations +QString Instr_addlw::code() const +{ + return QString("addlw\t%1").arg( m_literal ); +} + +void Instr_addlw::generateLinksAndStates( Code::iterator current ) +{ + makeOutputLinks( current ); + + m_outputState = m_inputState; + m_outputState.working.value = (m_inputState.working.value + m_literal) & 0xff; + m_outputState.working.known = (m_inputState.working.known == 0xff) ? 0xff : 0x0; + m_outputState.status.known &= ~( (1 << RegisterBit::C) | (1 << RegisterBit::DC) | (1 << RegisterBit::Z) ); +} + +ProcessorBehaviour Instr_addlw::behaviour() const +{ + ProcessorBehaviour behaviour; + + behaviour.working.depends = 0xff; + + behaviour.status.indep = (1 << RegisterBit::C) | (1 << RegisterBit::DC) | (1 << RegisterBit::Z); + + return behaviour; +} + + +QString Instr_andlw::code() const +{ + return QString("andlw\t%1").arg( m_literal ); +} + +void Instr_andlw::generateLinksAndStates( Code::iterator current ) +{ + makeOutputLinks( current ); + + m_outputState = m_inputState; + m_outputState.working.value = (m_inputState.working.value & m_literal) & 0xff; + m_outputState.working.known |= ~m_literal; // Now know any bits that are zero in value + m_outputState.status.known &= ~(1 << RegisterBit::Z); +} + +ProcessorBehaviour Instr_andlw::behaviour() const +{ + ProcessorBehaviour behaviour; + + behaviour.working.indep = ~m_literal; + behaviour.working.depends = m_literal; + + behaviour.status.indep = (1 << RegisterBit::Z); + return behaviour; +} + + +QString Instr_call::code() const +{ + return QString("call\t%1").arg( m_label ); +} + +void Instr_call::generateLinksAndStates( Code::iterator current ) +{ + (void)current; + makeLabelOutputLink( m_label ); + + m_outputState = m_inputState; +} + +ProcessorBehaviour Instr_call::behaviour() const +{ + ProcessorBehaviour behaviour; + return behaviour; +} + +void Instr_call::makeReturnLinks( Instruction * next ) +{ + m_pCode->setAllUnused(); + linkReturns( m_pCode->instruction( m_label ), next ); +} + + +void Instr_call::linkReturns( Instruction * current, Instruction * returnPoint ) +{ + while (true) + { + if ( !current || current->isUsed() ) + return; + + current->setUsed( true ); + if ( dynamic_cast(current) || dynamic_cast(current) ) + { +// cout << "Added return link" << endl; +// cout << " FROM: " << current->code() << endl; +// cout << " TO: " << returnPoint->code() << endl; + returnPoint->addInputLink( current ); + return; + } + if ( dynamic_cast(current) ) + { + // Jump over the call instruction to its return point, + // which will be the instruction after current. + current = *(++m_pCode->find( current )); + continue; + } + + const InstructionList outputs = current->outputLinks(); + + if ( outputs.isEmpty() ) + return; + + if ( outputs.size() == 1 ) + current = outputs.first(); + + else + { + // Can't avoid function recursion now. + InstructionList::const_iterator end = outputs.end(); + for ( InstructionList::const_iterator it = outputs.begin(); it != end; ++it ) + linkReturns( *it, returnPoint ); + return; + } + }; +} + + +//TODO CLRWDT + + +QString Instr_goto::code() const +{ + return QString("goto\t%1").arg( m_label ); +} + +void Instr_goto::generateLinksAndStates( Code::iterator current ) +{ + (void)current; + + makeLabelOutputLink( m_label ); + + m_outputState = m_inputState; +} + +ProcessorBehaviour Instr_goto::behaviour() const +{ + ProcessorBehaviour behaviour; + return behaviour; +} + + +QString Instr_iorlw::code() const +{ + return QString("iorlw\t%1").arg( m_literal ); +} + +void Instr_iorlw::generateLinksAndStates( Code::iterator current ) +{ + makeOutputLinks( current ); + + m_outputState = m_inputState; + m_outputState.working.value = (m_inputState.working.value | m_literal) & 0xff; + m_outputState.working.known |= m_literal; // Now know any bits that are one in value + m_outputState.status.known &= ~(1 << RegisterBit::Z); +} + +ProcessorBehaviour Instr_iorlw::behaviour() const +{ + ProcessorBehaviour behaviour; + + behaviour.working.indep = m_literal; + behaviour.working.depends = ~m_literal; + + behaviour.status.indep = (1 << RegisterBit::Z);; + return behaviour; +} + + +QString Instr_movlw::code() const +{ + return QString("movlw\t%1").arg( m_literal ); +} + +void Instr_movlw::generateLinksAndStates( Code::iterator current ) +{ + makeOutputLinks( current ); + m_outputState = m_inputState; + m_outputState.working.known = 0xff; + m_outputState.working.value = m_literal; +} + +ProcessorBehaviour Instr_movlw::behaviour() const +{ + ProcessorBehaviour behaviour; + behaviour.working.indep = 0xff; + return behaviour; +} + + +QString Instr_retfie::code() const +{ + return "retfie"; +} + +void Instr_retfie::generateLinksAndStates( Code::iterator current ) +{ + // Don't generate any output links + (void)current; + + m_inputState = m_outputState; +} + +ProcessorBehaviour Instr_retfie::behaviour() const +{ + ProcessorBehaviour behaviour; + return behaviour; +} + + +QString Instr_retlw::code() const +{ + return QString("retlw\t%1").arg( m_literal ); +} + +void Instr_retlw::generateLinksAndStates( Code::iterator current ) +{ + (void)current; + + m_outputState = m_inputState; + m_outputState.working.known = 0xff; + m_outputState.working.value = m_literal; +} + +ProcessorBehaviour Instr_retlw::behaviour() const +{ + ProcessorBehaviour behaviour; + behaviour.working.indep = 0xff; + return behaviour; +} + + + +QString Instr_return::code() const +{ + return "return"; +} + +void Instr_return::generateLinksAndStates( Code::iterator current ) +{ + (void)current; + + m_outputState = m_inputState; +} + +ProcessorBehaviour Instr_return::behaviour() const +{ + ProcessorBehaviour behaviour; + return behaviour; +} + + +QString Instr_sleep::code() const +{ + return "sleep"; +} + +void Instr_sleep::generateLinksAndStates( Code::iterator current ) +{ + // Don't generate any output links + (void)current; + + m_outputState = m_inputState; + m_outputState.status.value &= ~(1 << RegisterBit::NOT_PD); + m_outputState.status.value |= (1 << RegisterBit::NOT_TO); + m_outputState.status.known |= (1 << RegisterBit::NOT_TO) | (1 << RegisterBit::NOT_PD); +} + +ProcessorBehaviour Instr_sleep::behaviour() const +{ + ProcessorBehaviour behaviour; + behaviour.status.indep = (1 << RegisterBit::NOT_TO) | (1 << RegisterBit::NOT_PD); + return behaviour; +} + + +QString Instr_sublw::code() const +{ + return QString("sublw\t%1").arg( m_literal ); +} + +void Instr_sublw::generateLinksAndStates( Code::iterator current ) +{ + makeOutputLinks( current ); + + m_outputState = m_inputState; + m_outputState.working.value = (m_literal - m_inputState.working.value) & 0xff; + m_outputState.working.known = (m_inputState.working.known == 0xff) ? 0xff : 0x00; + m_outputState.status.known &= ~( (1 << RegisterBit::C) | (1 << RegisterBit::DC) | (1 << RegisterBit::Z) ); + + if ( m_inputState.working.minValue() > m_literal ) + { + m_outputState.status.value &= ~(1 << RegisterBit::C); + m_outputState.status.known |= (1 << RegisterBit::C); + } + else if ( m_inputState.working.maxValue() <= m_literal ) + { + m_outputState.status.value |= (1 << RegisterBit::C); + m_outputState.status.known |= (1 << RegisterBit::C); + } + + if ( m_inputState.working.known == 0xff ) + { + bool isZero = (m_inputState.working.value == m_literal); + if ( isZero ) + m_outputState.status.value |= (1 << RegisterBit::Z); + else + m_outputState.status.value &= ~(1 << RegisterBit::Z); + m_outputState.status.known |= (1 << RegisterBit::Z); + } +} + +ProcessorBehaviour Instr_sublw::behaviour() const +{ + ProcessorBehaviour behaviour; + behaviour.working.depends = 0xff; + behaviour.status.indep = (1 << RegisterBit::C) | (1 << RegisterBit::DC) | (1 << RegisterBit::Z); + return behaviour; +} + + +QString Instr_xorlw::code() const +{ + return QString("xorlw\t%1").arg( m_literal ); +} + +void Instr_xorlw::generateLinksAndStates( Code::iterator current ) +{ + makeOutputLinks( current ); + m_outputState = m_inputState; + m_outputState.working.value = (m_inputState.working.value ^ m_literal) & 0xff; + m_outputState.working.known = m_inputState.working.known; + m_outputState.status.known &= ~(1 << RegisterBit::Z); +} + +ProcessorBehaviour Instr_xorlw::behaviour() const +{ + ProcessorBehaviour behaviour; + behaviour.working.depends = 0xff; + behaviour.status.indep = (1 << RegisterBit::Z); + return behaviour; +} +//END Literal and Control Operations + + + +//BEGIN Microbe (non-assembly) Operations +QString Instr_sourceCode::code() const +{ + QStringList sourceLines = QStringList::split("\n",m_raw); + return ";" + sourceLines.join("\n;"); +} + + +QString Instr_asm::code() const +{ + return "; asm {\n" + m_raw + "\n; }"; +} + + +QString Instr_raw::code() const +{ + return m_raw; +} +//END Microbe (non-assembly) Operations + diff --git a/microbe/instruction.h b/microbe/instruction.h new file mode 100644 index 0000000..2d43343 --- /dev/null +++ b/microbe/instruction.h @@ -0,0 +1,1273 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by Daniel Clarke * + * 2005 by David Saxton * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef INSTRUCTION_H +#define INSTRUCTION_H + +#include +#include +#include +#include + +class Code; +class CodeIterator; +class CodeConstIterator; +class Instruction; +class PIC14; + +typedef QValueList InstructionList; + + +/** +Abstraction for a Register - should be used instead of a register name. Contains +info like whether or not the adressing of the register depends on the bank +selection. + +@author David Saxton +*/ +class Register +{ + public: + enum Type + { + TMR0, + OPTION_REG, + PCL, + STATUS, + FSR, + PORTA, + TRISA, + PORTB, + TRISB, + EEDATA, + EECON1, + EEADR, + EECON2, + PCLATH, + INTCON, + + // The following three are "special" + WORKING, // Not a register that is addressable by an address + GPR, // Refers to the collection of General Purpose Registers + none, // used in default constructor + }; + + // These banks are used for ORing together in the banks() function + enum Banks + { + Bank0 = 1 << 0, + Bank1 = 1 << 1, + }; + + /** + * Creates a register of the given type, giving it the appropriate name. + * Note that this constructor should not be used for GPR. + */ + Register( Type type = none ); + /** + * Construct a Register with the given name. If the name is not + * recognized, then it is assumed to be a GPR register. + */ + Register( const QString & name ); + /** + * Construct a Register with the given name. If the name is not + * recognized, then it is assumed to be a GPR register. + */ + Register( const char * name ); + /** + * @return less-than-equality between registers; name is only compared + * if both registers have type GPR. + */ + bool operator < ( const Register & reg ) const; + /** + * @return equality between registers; name is only compared if both + * registers have type GPR. + */ + bool operator == ( const Register & reg ) const; + /** + * @return 0x1 and 0x2 for being addressable from banks 0 and 1 + * respectively, OR'ed together. + */ + uchar banks() const; + /** + * Convenience function. + * @see banks + */ + bool bankDependent() const; + /** + * Returns the name of the register, or the alias for the GPR. + */ + QString name() const { return m_name; } + /** + * @return the type of register. + */ + Type type() const { return m_type; } + /** + * From the Optimizer's perspective, it is OK to remove, change or add + * any instruction so long as there are no visible external changes that + * go against the original intention of the microbe source (a general + * guiding principle). Therefore, this function returns true for PORT + * and TRIS registers, false for everything else. + */ + bool affectsExternal() const; + + protected: + QString m_name; + Type m_type; +}; + + + +class RegisterBit +{ + public: + enum STATUS_bits + { + C = 0, // Carry + DC = 1, // Digit carry + Z = 2, // Zero + NOT_PD = 3, // Power-down + NOT_TO = 4, // Time-out + RP0 = 5, // Bank Select + RP1 = 6, + IRP = 7, + }; + + enum INTCON_bits + { + RBIF = 0, + INTF = 1, + T0IF = 2, + RBIE = 3, + INTE = 4, + T0IE = 5, + EEIE = 6, + GIE = 7, + }; + + enum OPTION_bits + { + PS0 = 0, + PS1 = 1, + PS2 = 2, + PSA = 3, + T0SE = 4, + T0CS = 5, + INTEDG = 6, + NOT_RBPU = 7, + }; + + enum EECON1_bits + { + RD = 0, + WR = 1, + WREN = 2, + WRERR = 3, + EEIF = 4, + }; + /** + * Constructs a bit of the given register type at the given position. + */ + RegisterBit( uchar bitPos = 0, Register::Type reg = Register::none ); + /** + * Construct a register bit with the given name. + */ + RegisterBit( const QString & name ); + /** + * Construct a register bit with the given name. + */ + RegisterBit( const char * name ); + /** + * @warning do not trust this value! actually, this function should be + * removed, or the constructors fixed so that this value can be trusted. + * @return the register type that the bit belongs to. + */ + Register::Type registerType() const { return m_registerType; } + /** + * @return the position of the bit, e.g. "5" for RP0. + */ + uchar bitPos() const { return m_bitPos; } + /** + * @return the bit, e.g. "0x20" for Z. + */ + uchar bit() const { return (1 << m_bitPos); } + /** + * @return the name of the bit, e.g. "Z" for Z. + */ + QString name() const { return m_name; } + + + protected: + /** + * Determines the register type and bit pos from the bit name (m_name). + */ + void initFromName(); + + Register::Type m_registerType; + uchar m_bitPos:3; + QString m_name; +}; + + + + +/** +Contains information on the state of a register before an instruction is +executed. + +Note that all the "uchar" values in this class should be considered as the 8 +bits of a register. So for example, if known=0x2, then only the second bit of +the register is known, and its value is given in the second bit of value. + +@author David Saxton +*/ +class RegisterState +{ + public: + RegisterState(); + + /** + * Merges the known and values together, (possibly) reducing what is + * known. + */ + void merge( const RegisterState & state ); + /** + * Sets known to unknown and value to zero. + */ + void reset(); + /** + * Returns the bits that are definitely zero. + */ + uchar definiteZeros() const { return (~value) & known; } + /** + * Returns the bits that are definitely one. + */ + uchar definiteOnes() const { return value & known; } + /** + * Returns the bits that are unknown. + */ + uchar unknown() const { return ~known; } + /** + * @return the largest possible value that this register might be + * storing, based on which bits are known and the value of those bits. + */ + uchar maxValue() const { return (value & known) | (~known); } + /** + * @return the smallest possible value that this register might be + * storing, based on which bits are known and the value of those bits. + */ + uchar minValue() const { return (value & known); } + /** + * @return whether the known and value uchars are equal + */ + bool operator == ( const RegisterState & state ) const; + /** + * @return whether either of the known and value uchars are not equal. + */ + bool operator != ( const RegisterState & state ) const { return !( *this == state ); } + /** + * Prints known and value. + */ + void print(); + + /// Whether or not the value is known (for each bit). + uchar known; + + /// The value of the register. + uchar value; +}; + + +/** +Setting and dependency information for register bits. See the respective member +descriptions for more information. + +@author David Saxton +*/ +class RegisterBehaviour +{ + public: + RegisterBehaviour(); + /** + * Sets "depends", "indep" and "changes" to 0x0. + */ + void reset(); + + /** + * The bits whose value before the instruction is executed will affect + * the processor state after execution. So for example, + * in MOVLW this will be 0x0; + * in ANDLW this will be the bits that are non-zero in the literal; + * in BTFSC this will be the bit being tested (if this is the register + * being tested). + */ + uchar depends; + + /** + * The bits whose value after the instruction is executed is independent + * of the value before execution. So for example, + * in MOVLW, this will be 0xff; + * in ANDLW this will be the bits that are zero in the literal; + * in BTFSC this will be 0x0. + */ + uchar indep; +}; + + + +/** +Contains information on the state of a processor; e.g. register values + +@author David Saxton + */ +class ProcessorState +{ + public: + ProcessorState(); + /** + * Calls merge for each RegisterState. + */ + void merge( const ProcessorState & state ); + /** + * Calls reset() for each RegisterState. + */ + void reset(); + /** + * @return state for the given register. + */ + RegisterState & reg( const Register & reg ); + /** + * @return state for the given register. + */ + RegisterState reg( const Register & reg ) const; + /** + * @return whether all the RegisterStates are identical + */ + bool operator == ( const ProcessorState & state ) const; + /** + * @return whether any of the RegisterStates are not equal. + */ + bool operator != ( const ProcessorState & state ) const { return !( *this == state ); } + /** + * Displays each register's name and calls RegisterState::print in turn. + */ + void print(); + + /// The working register + RegisterState working; + + /// The status register + RegisterState status; + + protected: + typedef QMap< Register, RegisterState > RegisterMap; + /** + * All registers other than working and status. Entries are created on + * calls to reg with a new Register. + */ + RegisterMap m_registers; +}; + + +/** +Contains behavioural information for each register. + +@author David Saxton +*/ +class ProcessorBehaviour +{ + public: + ProcessorBehaviour(); + /** + * Calls reset() for each RegisterBehaviour. + */ + void reset(); + /** + * @return behaviour for the given register. + */ + RegisterBehaviour & reg( const Register & reg ); + + /// The working register + RegisterBehaviour working; + + /// The status register + RegisterBehaviour status; + + protected: + typedef QMap< Register, RegisterBehaviour > RegisterMap; + /** + * All registers other than working and status. Entries are created on + * calls to reg with a new Register. + */ + RegisterMap m_registers; +}; + + +/** +Contains information on whether a register is overwritten before its value is +used. Each uchar respresents the 8 bits of the register; if the bit is 1, then +the corresponding bit of the register is used by the Instruction or one +of its outputs before it is overwritten. + +@author David Saxton +*/ +class RegisterDepends +{ + public: + RegisterDepends(); + /** + * Sets all the depends values to 0x0. + */ + void reset(); + /** + * @return behaviour for the given register. + */ + uchar & reg( const Register & reg ); + + /// The working register + uchar working; + + /// The status register + uchar status; + + protected: + typedef QMap< Register, uchar > RegisterMap; + /** + * All registers other than working and status. Entries are created on + * calls to reg with a new Register. + */ + RegisterMap m_registers; +}; + + + +/** +Holds a program structure; an (ordered) list of blocks of code, each of which +contains a list of instructions. The structure is such as to provide easy +manipulation of the program, as well as aiding the optimizer. + +@author David Saxton +*/ +class Code +{ + public: + Code(); + + typedef CodeIterator iterator; + typedef CodeConstIterator const_iterator; + + enum InstructionPosition + { + InterruptHandler = 0, + LookupTable = 1, + Middle = 2, ///< Used for main code + Subroutine = 3, ///< Used for subroutines + + PositionCount = 4, ///< This must remain the last item and be the number of valid positions + }; + + CodeIterator begin(); + CodeIterator end(); + CodeConstIterator begin() const; + CodeConstIterator end() const; + + /** + * Queues a label to be given to the next instruction to be added in the + * given position + */ + void queueLabel( const QString & label, InstructionPosition position = Middle ); + /** + * Returns the list of queued labels for the given position. This is + * used in merging code, as we also need to merge any queued labels. + */ + QStringList queuedLabels( InstructionPosition position ) const { return m_queuedLabels[position]; } + /** + * Adds the Instruction at the given position. + */ + void append( Instruction * instruction, InstructionPosition position = Middle ); + /** + * @returns the Instruction with the given label (or null if no such + * Instruction). + */ + Instruction * instruction( const QString & label ) const; + /** + * Look for an Assembly instruction (other types are ignored). + * @return an iterator to the current instruction, or end if it wasn't + * found. + */ + iterator find( Instruction * instruction ); + /** + * Removes the Instruction (regardless of position). + * @warning You should always use only this function to remove an + * instruction as this function handles stuff such as pushing labels + * from this instruction onto the next before deletion. + */ + void removeInstruction( Instruction * instruction ); + /** + * Merges all the blocks output together with other magic such as adding + * variables, gpasm directives, etc. + */ + QString generateCode( PIC14 * pic ) const; + /** + * Appends the InstructionLists to the end of the ones in this instance. + * @param middleInsertionPosition is the position where the middle code + * blocks of the given code will be merged at. + */ + void merge( Code * code, InstructionPosition middleInsertionPosition = Middle ); + /** + * @returns the InstructionList for the given insertion position. + */ + InstructionList * instructionList( InstructionPosition position ) { return & m_instructionLists[position]; } + /** + * @returns the InstructionList for the given insertion position. + */ + const InstructionList * instructionList( InstructionPosition position ) const { return & m_instructionLists[position]; } + /** + * Calls generateOutputLinks for each Instruction + */ + void generateLinksAndStates(); + /** + * Calls setUsed(false) for all instructions. + */ + void setAllUnused(); + /** + * Does any work that is needed to the code before it can be passed to + * the optimizer (such as flushing out queued labels). This is called + * after all the instructions have been added to the code. + */ + void postCompileConstruct(); + + protected: + /** + * Used when generating the code. Finds the list of general purpose + * registers that are referenced and returns their aliases. + */ + QStringList findVariables() const; + + InstructionList m_instructionLists[ PositionCount ]; ///< @see InstructionPosition + QStringList m_queuedLabels[ PositionCount ]; ///< @see InstructionPosition + + private: // Disable copy constructor and operator= + Code( const Code & ); + Code &operator=( const Code & ); +}; + + +/** +Iterates over all the instructions, going seamlessly between the different lists +and avoiding the non-assembly instructions. + +@author David Saxton + */ +class CodeIterator +{ + public: + bool operator != ( const CodeIterator & i ) const { return it != i.it; } + bool operator == ( const CodeIterator & i ) const { return it == i.it; } + CodeIterator & operator ++ (); + Instruction * & operator * () { return *it; } + /** + * Deletes the instruction that this iterator is currently pointing at + * (removing it from any lists), and increments the iterator to the next + * instruction. + */ + CodeIterator & removeAndIncrement(); + /** + * Inserts the given instruction before the instruction pointed at by + * this iterator. + */ + void insertBefore( Instruction * ins ); + + InstructionList::iterator it; + InstructionList::iterator listEnd; + Code::InstructionPosition pos; + Code * code; + InstructionList * list; +}; + + +/** +A const version of CodeIterator (cannot change instructions). + +@author David Saxton + */ +class CodeConstIterator +{ + public: + bool operator != ( const CodeConstIterator & i ) const { return it != i.it; } + bool operator == ( const CodeConstIterator & i ) const { return it == i.it; } + CodeConstIterator & operator ++ (); + const Instruction * operator * () const { return *it; } + + InstructionList::const_iterator it; + InstructionList::const_iterator listEnd; + Code::InstructionPosition pos; + const Code * code; + const InstructionList * list; +}; + + +/** +@author Daniel Clarke +@author David Saxton +*/ +class Instruction +{ + public: + enum InstructionType + { + Assembly, + Raw, // User-inserted assembly + Comment, + }; + /** + * Used in optimization. Note that this follows roughly, but not + * exactly, the Microchip classifications of similar categories. + */ + enum AssemblyType + { + /** + * Writes to a file (which can be obtained by calling outputReg(). + */ + FileOriented, + + /** + * Writes to a file bit (so BCF or BSF). + */ + BitOriented, + + /** + * Affects the working register via a literal operation, with no + * branching (so excludes retlw). + */ + WorkingOriented, + + /** + * Assembly instructions that don't come under the above categories + * (so control and branching instructions). + */ + Other, + + /** + * The Instruction is not of Assembly InstructionType. + */ + None, + }; + + Instruction(); + virtual ~Instruction(); + void setCode( Code * code ) { m_pCode = code; } + + /** + * This is used to decide how to output the instruction, and which + * instructions to avoid while optimizing. + */ + virtual InstructionType type() const { return Assembly; } + /** + * @return the AssemblyType (None for non-Assembly instructions). + */ + virtual AssemblyType assemblyType() const = 0; + /** + * The text to output to the generated assembly. + */ + virtual QString code() const = 0; + /** + * The input processor state is used to generate the outputlinks and the + * output processor state. + */ + void setInputState( const ProcessorState & processorState ) { m_inputState = processorState; } + /** + * By using the ProcessorState, the Instruction should: + * * Find all instructions that could be executed after this instruction. + * * Generate the output ProcessorState. + * The default behaviour of this function is to link to the next + * sequential instruction, and to generate an unknown ProcessorState. + * @warning if your instruction depends on any bits, then it must + * reinherit this function and say so. + * @param instruction points at this instruction + */ + virtual void generateLinksAndStates( Code::iterator instruction ); + /** + * @return the processor behaviour for this instruction. + */ + virtual ProcessorBehaviour behaviour() const; + /** + * An input link is an instruction that might be executed immediately + * before this Instruction. + */ + void addInputLink( Instruction * inputLink ); + /** + * An output link is an instruction that might be executed immediately + * after this Instruction. + */ + void addOutputLink( Instruction * inputLink ); + /** + * The list of instructions that might be executed immediately before + * this instruction. + * @see addInputLink + */ + InstructionList inputLinks() const { return m_inputLinks; } + /** + * The list of instructions that might be executed immediately after + * this instruction. Instruction does not generate these links; instead + * the list is generated Code::generateLinksAndStates function. + */ + InstructionList outputLinks() const { return m_outputLinks; } + /** + * Remove the given input link from the instruction. + */ + void removeInputLink( Instruction * ins ); + /** + * Remove the given output link from the instruction. + */ + void removeOutputLink( Instruction * ins ); + /** + * Clears all input and output links from this instruction. This does + * not remove references to this instruction from other instructions. + */ + void clearLinks(); + /** + * An instruction may have zero, or more than zero labels associated + * with it - these will be printed before the instruction in the + * assembly output. + */ + QStringList labels() const { return m_labels; } + /** + * @see labels + */ + void addLabels( const QStringList & labels ); + /** + * @see labels + */ + void setLabels( const QStringList & labels ); + /** + * @see used + */ + void setUsed( bool used ) { m_bUsed = used; } + /** + * Used for optimization purposes in determining whether the instruction + * has been examined yet (to avoid infinite loops). + */ + bool isUsed() const { return m_bUsed; } + /** + * Set by the optimizer to indicate whether this instruction or any of + * its outputs overwrite any of the bits of the given register. + */ + void setRegisterDepends( uchar depends, const Register & reg ) { m_registerDepends.reg(reg) = depends; } + /** + * @see setOutputsOverwriteWorking + */ + uchar registerDepends( const Register & reg ) { return m_registerDepends.reg(reg); } + /** + * Resets the overwrites. + */ + void resetRegisterDepends() { m_registerDepends.reset(); } + /** + * @return the input processor state to this instruction. + * @see setInputState + */ + ProcessorState inputState() const { return m_inputState; } + /** + * @return the output processor state from this instruction. + * @see generateLinksAndStates. + */ + ProcessorState outputState() const { return m_outputState; } + /** + * Only applicable to Instructions that refer to a file. + */ + Register file() const { return m_file; } + /** + * Only applicable to Instructions that refer to a bit (such as BCF). + */ + RegisterBit bit() const { return m_bit; } + /** + * Only applicable to instructions that refer to a literal (such as + * XORLW). + */ + uchar literal() const { return m_literal; } + /** + * Applicable only to instructions that save a result to working or file + * depending on the destination bit. + */ + Register outputReg() const { return (m_dest == 0) ? Register::WORKING : m_file; } + /** + * Applicable only to instructions that use the destination flag. + */ + unsigned dest() const { return m_dest; } + + protected: + /** + * This function is provided for convenience; it creates links to the + * first or second instructions after this one, depending on the value + * of firstOutput and secondOutput. + * @see generateOutputLinks + */ + void makeOutputLinks( Code::iterator current, bool firstOutput = true, bool secondOutput = false ); + /** + * This function is provided for instructions that jump to a label (i.e. + * call and goto). + */ + void makeLabelOutputLink( const QString & label ); + + RegisterDepends m_registerDepends; + bool m_bInputStateChanged; + bool m_bUsed; + bool m_bPositionAffectsBranching; + InstructionList m_inputLinks; + InstructionList m_outputLinks; + QStringList m_labels; + Code * m_pCode; + + // Commonly needed member variables for assembly instructions + Register m_file; + RegisterBit m_bit; + QString m_raw; // Used by source code, raw asm, etc + uchar m_literal; + unsigned m_dest:1; // is 0 (W) or 1 (file). + ProcessorState m_inputState; + ProcessorState m_outputState; + + private: // Disable copy constructor and operator= + Instruction( const Instruction & ); + Instruction &operator=( const Instruction & ); +}; + + + +//BEGIN Byte-Oriented File Register Operations +class Instr_addwf : public Instruction +{ + public: + Instr_addwf( const Register & file, int dest ) { m_file = file; m_dest = dest; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return FileOriented; } +}; + + +class Instr_andwf : public Instruction +{ + public: + Instr_andwf( const Register & file, int dest ) { m_file = file; m_dest = dest; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return FileOriented; } +}; + + +class Instr_clrf : public Instruction +{ + public: + Instr_clrf( const Register & file ) { m_file = file; m_dest = 1; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return FileOriented; } +}; + + +//TODO CLRW +//TODO COMF + + +class Instr_decf : public Instruction +{ + public: + Instr_decf( const Register & file, int dest ) { m_file = file; m_dest = dest; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return FileOriented; } +}; + + +class Instr_decfsz : public Instruction +{ + public: + Instr_decfsz( const Register & file, int dest ) { m_file = file; m_dest = dest; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return FileOriented; } +}; + + +class Instr_incf : public Instruction +{ + public: + Instr_incf( const Register & file, int dest ) { m_file = file; m_dest = dest; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return FileOriented; } +}; + + +//TODO INCFSZ + + +class Instr_iorwf : public Instruction +{ + public: + Instr_iorwf( const Register & file, int dest ) { m_file = file; m_dest = dest; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return FileOriented; } +}; + + +class Instr_movf : public Instruction +{ + public: + Instr_movf( const Register & file, int dest ) { m_file = file; m_dest = dest; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return FileOriented; } +}; + + +class Instr_movwf : public Instruction +{ + public: + Instr_movwf( const Register & file ) { m_file = file; m_dest = 1; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return FileOriented; } +}; + + +//TODO NOP + + +class Instr_rlf : public Instruction +{ + public: + Instr_rlf( const Register & file, int dest ) { m_file = file; m_dest = dest; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return FileOriented; } +}; + + +class Instr_rrf : public Instruction +{ + public: + Instr_rrf( const Register & file, int dest ) { m_file = file; m_dest = dest; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return FileOriented; } +}; + + +class Instr_subwf : public Instruction +{ + public: + Instr_subwf( const Register & file, int dest ) { m_file = file; m_dest = dest; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return FileOriented; } +}; + + +class Instr_swapf : public Instruction +{ + public: + Instr_swapf( const Register & file, int dest ) { m_file = file; m_dest = dest; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return FileOriented; } +}; + + +class Instr_xorwf : public Instruction +{ + public: + Instr_xorwf( const Register & file, int dest ) { m_file = file; m_dest = dest; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return FileOriented; } +}; +//END Byte-Oriented File Register Operations + + + +//BEGIN Bit-Oriented File Register Operations +class Instr_bcf : public Instruction +{ + public: + Instr_bcf( const Register & file, const RegisterBit & bit ) { m_file = file; m_bit = bit; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return BitOriented; } +}; + + +class Instr_bsf : public Instruction +{ + public: + Instr_bsf( const Register & file, const RegisterBit & bit ) { m_file = file; m_bit = bit; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return BitOriented; } +}; + + +class Instr_btfsc : public Instruction +{ + public: + Instr_btfsc( const Register & file, const RegisterBit & bit ) { m_file = file; m_bit = bit; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return Other; } +}; + + +class Instr_btfss : public Instruction +{ + public: + Instr_btfss( const Register & file, const RegisterBit & bit ) { m_file = file; m_bit = bit; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return Other; } +}; +//END Bit-Oriented File Register Operations + + + +//BEGIN Literal and Control Operations +class Instr_addlw : public Instruction +{ + public: + Instr_addlw( int literal ) { m_literal = literal; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return WorkingOriented; } +}; + + + +class Instr_andlw : public Instruction +{ + public: + Instr_andlw( int literal ) { m_literal = literal; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return WorkingOriented; } +}; + + +class Instr_call : public Instruction +{ + public: + Instr_call( const QString & label ) { m_label = label; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return Other; } + /** + * Called from Code after all the output links have been generated. The + * instruction that is called has its output links followed, and any + * returns encountered are linked back to the instruction after this + * one. + * @param next the instruction after this one which the return points + * will be linked to. + */ + void makeReturnLinks( Instruction * next ); + + QString label() const { return m_label; } + void setLabel( const QString & label ) { m_label = label; } + + protected: + /** + * Used by makeReturnLinks. Recursively follows the instruction's output + * links, until a return is found - then, link the return point back to + * the instruction after this one. Call instructions found while + * following the output are ignored. + * @param returnPoint the instruction to link back to on finding a + * return. + */ + void linkReturns( Instruction * current, Instruction * returnPoint ); + + QString m_label; +}; + + +//TODO CLRWDT + + +class Instr_goto : public Instruction +{ + public: + Instr_goto( const QString & label ) { m_label = label; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return Other; } + + QString label() const { return m_label; } + void setLabel( const QString & label ) { m_label = label; } + + protected: + QString m_label; +}; + + +class Instr_iorlw : public Instruction +{ + public: + Instr_iorlw( int literal ) { m_literal = literal; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return WorkingOriented; } +}; + + +class Instr_movlw : public Instruction +{ + public: + Instr_movlw( int literal ) { m_literal = literal; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return WorkingOriented; } +}; + + +class Instr_retfie : public Instruction +{ + public: + Instr_retfie() {}; + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return Other; } +}; + + +class Instr_retlw : public Instruction +{ + public: + Instr_retlw( int literal ) { m_literal = literal; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return Other; } +}; + + +class Instr_return : public Instruction +{ + public: + Instr_return() {}; + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return Other; } +}; + + +class Instr_sleep : public Instruction +{ + public: + Instr_sleep() {}; + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return Other; } +}; + + +class Instr_sublw : public Instruction +{ + public: + Instr_sublw( int literal ) { m_literal = literal; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return WorkingOriented; } +}; + + +class Instr_xorlw : public Instruction +{ + public: + Instr_xorlw( int literal ) { m_literal = literal; } + virtual QString code() const; + virtual void generateLinksAndStates( Code::iterator current ); + virtual ProcessorBehaviour behaviour() const; + virtual AssemblyType assemblyType() const { return WorkingOriented; } +}; +//END Literal and Control Operations + + + +//BEGIN Microbe (non-assembly) Operations +class Instr_sourceCode : public Instruction +{ + public: + Instr_sourceCode( const QString & source ) { m_raw = source; } + virtual QString code() const; + virtual InstructionType type() const { return Comment; } + virtual AssemblyType assemblyType() const { return None; } +}; + + +class Instr_asm : public Instruction +{ + public: + Instr_asm( const QString & raw ) { m_raw = raw; } + virtual QString code() const; + virtual InstructionType type() const { return Raw; } + virtual AssemblyType assemblyType() const { return None; } +}; + + +// Like Instr_asm, but does not put ;asm {} in, used +// for internal things like gpasm directives etc... +class Instr_raw : public Instruction +{ + public: + Instr_raw( const QString & raw ) { m_raw = raw; } + virtual QString code() const; + virtual InstructionType type() const { return Raw; } + virtual AssemblyType assemblyType() const { return None; } +}; +//END Microbe (non-assembly) Operations + + + +#endif diff --git a/microbe/main.cpp b/microbe/main.cpp new file mode 100644 index 0000000..1325159 --- /dev/null +++ b/microbe/main.cpp @@ -0,0 +1,80 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by Daniel Clarke * + * Copyright (C) 2005 by David Saxton * + * daniel.jc@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "microbe.h" +#include "pic14.h" + +#include +#include +#include +#include + +#include +#include +using namespace std; + +static const char description[] = + I18N_NOOP("The Microbe Compiler"); + +static const char version[] = "0.3"; + +static KCmdLineOptions options[] = +{ + { "show-source", I18N_NOOP( "Show source code lines in assembly output"),0}, + { "nooptimize", I18N_NOOP( "Do not attempt optimization of generated instructions."),0}, + { "+[Input URL]", I18N_NOOP( "Input filename" ),0}, + { "+[Output URL]", I18N_NOOP( "Output filename" ),0}, + KCmdLineLastOption +}; + +int main(int argc, char **argv) +{ + KAboutData about("microbe", I18N_NOOP("Microbe"), version, description, + KAboutData::License_GPL, "(C) 2004-2005, The KTechlab developers", 0, "http://ktechlab.org", "ktechlab-devel@lists.sourceforge.net" ); + about.addAuthor( "Daniel Clarke", 0, "daniel.jc@gmail.com" ); + about.addAuthor( "David Saxton", 0, "david@bluehaze.org" ); + KCmdLineArgs::init(argc, argv, &about); + KCmdLineArgs::addCmdLineOptions( options ); + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if(args->count() == 2 ) + { + Microbe mb; + QString s = mb.compile( args->arg(0), args->isSet("show-source"), args->isSet("optimize")); + QString errorReport = mb.errorReport(); + + if ( !errorReport.isEmpty() ) + { + cerr << mb.errorReport(); + return 1; // If there was an error, don't write the output to file. + } + + else + { + ofstream out(args->arg(1)); + out << s; + return 0; + } + } + else args->usage(); +} + diff --git a/microbe/microbe.cpp b/microbe/microbe.cpp new file mode 100644 index 0000000..d94cba7 --- /dev/null +++ b/microbe/microbe.cpp @@ -0,0 +1,472 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by Daniel Clarke daniel.jc@gmail.com * + * Copyright (C) 2005 by David Saxton * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "instruction.h" +#include "microbe.h" +#include "parser.h" +#include "optimizer.h" +#include "pic14.h" + +#include +#include +#include + +#include +using namespace std; + + +//BEGIN class Microbe +Microbe::Microbe() +{ + m_maxDelaySubroutine = PIC14::Delay_None; + m_dest = 0; + m_uniqueLabel = 0; + + // Hardwired constants + m_aliasList["true"] = "1"; + m_aliasList["false"] = "0"; + // Things starting with b are reserved by gpasm (for binary numbers) + m_aliasList["b"] = "_b"; + + //BEGIN Keypad values + int bv[4][6] = { + { 1, 2, 3, 10, 14, 18 }, + { 4, 5, 6, 11, 15, 19 }, + { 7, 8, 9, 12, 16, 20 }, + { 253, 0, 254, 13, 17, 21 } }; + + for ( unsigned row = 0; row < 4; ++row ) + { + for ( unsigned col = 0; col < 6; ++col ) + { + m_aliasList[ QString("Keypad_%1_%2").arg(row+1).arg(col+1) ] = QString::number( bv[row][col] ); + } + } + + m_aliasList[ "Keypad_None" ] = "0xff"; + //END Keypad values +} + + +Microbe::~Microbe() +{ +} + + +QString Microbe::compile( const QString & url, bool showSource, bool optimize ) +{ + QFile file( url ); + if( file.open( IO_ReadOnly ) ) + { + QTextStream stream(&file); + unsigned line = 0; + while( !stream.atEnd() ) + m_program += SourceLine( stream.readLine(), url, line++ ); + file.close(); + simplifyProgram(); + } + else + { + m_errorReport += i18n("Could not open file '%1'\n").arg(url); + return 0; + } + + Parser parser(this); + + // Extract the PIC ID + if ( !m_program.isEmpty() ) + { + m_picType = PIC14::toType( m_program[0].text() ); + m_program.remove( m_program.begin() ); + } + + PIC14 * pic = makePic(); + if ( !pic ) + return 0; + + Code * code = parser.parse( m_program ); + pic->setCode( code ); + pic->addCommonFunctions( (PIC14::DelaySubroutine)m_maxDelaySubroutine ); + + pic->postCompileConstruct( m_usedInterrupts ); + code->postCompileConstruct(); + + if ( optimize ) + { + Optimizer opt; + opt.optimize( code ); + } + + return code->generateCode( pic ); +} + + +PIC14 * Microbe::makePic() +{ + return new PIC14( this, (PIC14::Type)m_picType ); +} + + +void Microbe::simplifyProgram() +{ + SourceLineList simplified; + + enum CommentType { None, SingleLine, MultiLine }; + CommentType commentType = None; + + SourceLineList::const_iterator end = m_program.end(); + for ( SourceLineList::const_iterator it = m_program.begin(); it != end; ++it ) + { + QString code = (*it).text(); + QString simplifiedLine; + + if ( commentType == SingleLine ) + commentType = None; + + unsigned l = code.length(); + + for ( unsigned i = 0; i < l; ++i ) + { + QChar c = code[i]; + switch ( c ) + { + case '/': + // Look for start of comments in form "//" and "/*" + + if ( commentType == None && (i+1 < l) ) + { + if ( code[i+1] == '/' ) + { + commentType = SingleLine; + i++; + } + + else if ( code[i+1] == '*' ) + { + commentType = MultiLine; + i++; + } + } + break; + + case '*': + // Look for end of comments in form "*/" + if ( commentType == MultiLine && (i+1 < l) && code[i+1] == '/' ) + { + i++; + commentType = None; + continue; + } + break; + + case '{': + case '}': + // Put braces on seperate lines + + if ( commentType != None ) + break; + + simplified << SourceLine( simplifiedLine.simplifyWhiteSpace(), (*it).url(), (*it).line() ); + simplified << SourceLine( c, (*it).url(), (*it).line() ); + + simplifiedLine = ""; + continue; + } + + if ( commentType == None ) + simplifiedLine += c; + } + + simplified << SourceLine( simplifiedLine.simplifyWhiteSpace(), (*it).url(), (*it).line() ); + } + + m_program.clear(); + end = simplified.end(); + for ( SourceLineList::const_iterator it = simplified.begin(); it != end; ++it ) + { + if ( !(*it).text().isEmpty() ) + m_program << *it; + } +} + + +void Microbe::compileError( MistakeType type, const QString & context, const SourceLine & sourceLine ) +{ + QString message; + switch (type) + { + case UnknownStatement: + message = i18n("Unknown statement"); + break; + case InvalidPort: + message = i18n("Port '%1' is not supported by target PIC").arg(context); + break; + case UnassignedPin: + message = i18n("Pin identifier was not followed by '='"); + break; + case NonHighLowPinState: + message = i18n("Pin state can only be 'high' or 'low'"); + break; + case UnassignedPort: + message = i18n("Invalid token '%1'. Port identifier should be followed by '='").arg(context); + break; + case UnexpectedStatementBeforeBracket: + message = i18n("Unexpected statement before '{'"); + break; + case MismatchedBrackets: + message = i18n("Mismatched brackets in expression '%1'").arg(context); + break; + case InvalidEquals: + message = i18n("Invalid '=' found in expression"); + break; + case ReservedKeyword: + message = i18n("Reserved keyword '%1' cannot be a variable name.").arg(context); + break; + case ConsecutiveOperators: + message = i18n("Nothing between operators"); + break; + case MissingOperator: + message = i18n("Missing operator or space in operand"); + break; + case UnknownVariable: + if ( context.isEmpty() ) + message = i18n("Unknown variable"); + else + message = i18n("Unknown variable '%1'").arg(context); + break; + case UnopenableInclude: + message = i18n("Could not open include file '%1'").arg(context); + break; + case DivisionByZero: + message = i18n("Division by zero"); + break; + case NumberTooBig: + message = i18n("Number too big"); + break; + case NonConstantStep: + message = i18n("Step can only be a constant expression"); + break; + case NonConstantDelay: + message = i18n("Delay must be a positive constant value"); + break; + case HighLowExpected: + message = i18n("'high' or 'low' expected after pin expression '%1'").arg(context); + break; + case InvalidComparison: + message = i18n("Comparison operator in '%1' is not recognized"); + break; + case SubBeforeEnd: + message = i18n("Subroutine definition before end of program"); + break; + case InterruptBeforeEnd: + message = i18n("Interrupt routine definition before end of program"); + break; + case LabelExpected: + message = i18n("Label expected"); + break; + case TooManyTokens: + message = i18n("Extra tokens at end of line"); + break; + case FixedStringExpected: + message = i18n("Expected '%1'").arg(context); + break; + case PinListExpected: + message = i18n("Pin list expected"); + break; + case AliasRedefined: + message = i18n("Alias already definied"); + break; + case InvalidInterrupt: + message = i18n("Interrupt type not supported by target PIC"); + break; + case InterruptRedefined: + message = i18n("Interrupt already definied"); + break; + case ReadOnlyVariable: + message = i18n("Variable '%1' is read only").arg(context); + break; + case WriteOnlyVariable: + message = i18n("Variable '%1' is write only").arg(context); + break; + case InvalidPinMapSize: + message = i18n("Invalid pin list size"); + break; + case VariableRedefined: + message = i18n("Variable '%1' is already defined").arg(context); + break; + case InvalidVariableName: + message = i18n("'%1' is not a valid variable name").arg(context); + break; + case VariableExpected: + message = i18n("Variable expected"); + break; + case NameExpected: + message = i18n("Name expected"); + break; + } + + + m_errorReport += QString("%1:%2:Error [%3] %4\n") + .arg( sourceLine.url() ) + .arg( sourceLine.line()+1 ) + .arg( type ) + .arg( message ); +} + + +bool Microbe::isValidVariableName( const QString & variableName ) +{ + if ( variableName.isEmpty() ) + return false; + + if ( !variableName[0].isLetter() && variableName[0] != '_' ) + return false; + + for ( unsigned i = 1; i < variableName.length(); ++i ) + { + if ( !variableName[i].isLetterOrNumber() && variableName[i] != '_' ) + return false; + } + + return true; +} + + +void Microbe::addVariable( const Variable & variable ) +{ + if ( variable.type() == Variable::invalidType ) + return; + + if ( !isVariableKnown( variable.name() ) ) + m_variables << variable; +} + + +Variable Microbe::variable( const QString & name ) const +{ + VariableList::const_iterator end = m_variables.end(); + for ( VariableList::const_iterator it = m_variables.begin(); it != end; ++it ) + { + if ( (*it).name() == name ) + return *it; + } + return Variable(); +} + + +bool Microbe::isVariableKnown( const QString & name ) const +{ + return variable(name).type() != Variable::invalidType; +} + + +void Microbe::addDelayRoutineWanted( unsigned routine ) +{ + if ( m_maxDelaySubroutine < routine ) + m_maxDelaySubroutine = routine; +} + + +void Microbe::addAlias( const QString & name, const QString & dest ) +{ + m_aliasList[name] = dest; +} + + +QString Microbe::alias( const QString & alias ) const +{ + // If the string is an alias, return the real string, + // otherwise just return the alias as that is the real string. + AliasMap::const_iterator it = m_aliasList.find(alias); + if ( it != m_aliasList.constEnd() ) + return it.data(); + return alias; +} + + +void Microbe::setInterruptUsed(const QString &interruptName) +{ + // Don't add it again if it is already in the list + if ( m_usedInterrupts.contains( interruptName ) ) + return; + m_usedInterrupts.append(interruptName); +} + + +bool Microbe::isInterruptUsed( const QString & interruptName ) +{ + return m_usedInterrupts.contains( interruptName ); +} + + +QString Microbe::dest() const +{ + return QString("__op%1").arg(m_dest); +} + + +void Microbe::incDest() +{ + m_dest++; +// if ( ++m_dest > m_highestDest ) +// m_highestDest = m_dest; +} + + +void Microbe::decDest() +{ + m_dest--; +} + + +void Microbe::resetDest() +{ + m_dest = 0; +} +//END class Microbe + + + +//BEGIN class SourceLine +SourceLine::SourceLine( const QString & text, const QString & url, int line ) +{ + m_text = text; + m_url = url; + m_line = line; +} + + +SourceLine::SourceLine() +{ + m_line = -1; +} + + +QStringList SourceLine::toStringList( const SourceLineList & lines ) +{ + QStringList joined; + SourceLineList::const_iterator end = lines.end(); + for ( SourceLineList::const_iterator it = lines.begin(); it != end; ++it ) + joined << (*it).text(); + return joined; + +} +//END class SourceLine + diff --git a/microbe/microbe.h b/microbe/microbe.h new file mode 100644 index 0000000..efa7aa4 --- /dev/null +++ b/microbe/microbe.h @@ -0,0 +1,249 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by Daniel Clarke * + * daniel.jc@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef MICROBE_H +#define MICROBE_H + +#include +#include +// #include + +#include +#include +#include + +class QString; +class BTreeBase; +class BTreeNode; +class Code; +class PIC14; +class PortPin; + +typedef QValueList PortPinList; + +typedef QValueList VariableList; +typedef QMap AliasMap; + +enum ExprType +{ + unset = 1, + working = 2, + number = 3, + variable = 4, + extpin = 5, + keypad = 6, +}; + + +class SourceLine; +typedef QValueList SourceLineList; +/** +Represents a source line, with the convention of line number starting at zero. +@author David Saxton +*/ +class SourceLine +{ + public: + /** + * The QValueList template requires a default constructor - calling this + * though creates an invalid SourceLine with line() returning -1. So + * this constructor should never be used. + */ + SourceLine(); + SourceLine( const QString & text, const QString & url, int line ); + + QString text() const { return m_text; } + QString url() const { return m_url; } + int line() const { return m_line; } + + /** + * Extracts the text from each SourceLine and adds it to the + * returned QStringList. + */ + static QStringList toStringList( const SourceLineList & lines ); + + protected: + QString m_text; + QString m_url; + int m_line; +}; + + + +/** +@author Daniel Clarke +@author David Saxton +*/ +class Microbe +{ + public: + Microbe(); + ~Microbe(); + + enum MistakeType + { + UnknownStatement = 1, + InvalidPort = 2, + UnassignedPin = 3, // pin identifier without an "= something" + NonHighLowPinState = 4, + UnassignedPort = 5, // port identifier without an "= something" + UnexpectedStatementBeforeBracket = 6, + MismatchedBrackets = 7, + InvalidEquals = 8, + ReservedKeyword = 9, + ConsecutiveOperators = 10, + MissingOperator = 11, + UnknownVariable = 12, + UnopenableInclude = 16, + DivisionByZero = 17, + NumberTooBig = 18, + NonConstantStep = 19, + NonConstantDelay = 20, + HighLowExpected = 21, + InvalidComparison = 22, + SubBeforeEnd = 23, + LabelExpected = 24, + TooManyTokens = 25, + FixedStringExpected = 26, + PinListExpected = 27, + AliasRedefined = 28, + InvalidInterrupt = 29, + InterruptRedefined = 30, + InterruptBeforeEnd = 31, + ReadOnlyVariable = 32, + WriteOnlyVariable = 33, + InvalidPinMapSize = 34, + VariableRedefined = 35, + InvalidVariableName = 36, + VariableExpected = 40, + NameExpected = 41 + }; + + /** + * Returns a list of errors occured during compilation, intended for + * outputting to stderr. + */ + QString errorReport() const { return m_errorReport; } + /** + * Call this to compile the given code. This serves as the top level of + * recursion as it performs initialisation of things, to recurse at + * levels use parseUsingChild(), or create your own Parser. + * @param url is used for reporting errors + */ + QString compile( const QString & url, bool showSource, bool optimize ); + /** + * Adds the given compiler error at the file line number to the + * compilation report. + */ + void compileError( MistakeType type, const QString & context, const SourceLine & sourceLine ); + /** + * This is for generating unique numbers for computer generated labels. + */ + QString uniqueLabel() { return QString("__%1").arg(m_uniqueLabel++); } + /** + * If alias is an alias for something then it returns that something, + * otherwise it just returns alias (which in that case is not an alias!) + */ + QString alias( const QString & alias ) const; + /** + * Aliases the name to the dest. + */ + void addAlias( const QString & name, const QString & dest ); + /** + * Tell Microbe that a minimum of the given delay routine needs to be + * created. + * @see PIC14::DelaySubroutine + * @param routine - DelaySubroutine enum, higher is more priority + */ + void addDelayRoutineWanted( unsigned routine ); + /** + * Makes a new PIC assembly object, based on the PIC string that the + * user has given in the source. + */ + PIC14 * makePic(); + /** + * Add the interrupt as being used, i.e. make sure there is one and only + * one occurance of its name in m_usedInterrupts. + */ + void setInterruptUsed( const QString & interruptName ); + /** + * @returns whether the given interrupt has already been used. + */ + bool isInterruptUsed( const QString & interruptName ); + /** + * @returns whether the variable name is valid. + */ + static bool isValidVariableName( const QString & variableName ); + /** + * Appends the given variable name to the variable list. + */ + void addVariable( const Variable & variable ); + /** + * @returns the variable with the given name, or one of invalidType if + * no such variable exists. + */ + Variable variable( const QString & variableName ) const; + /** + * @returns whether the variable has been declared yet. + */ + bool isVariableKnown( const QString & variableName ) const; + /** + * This is used as a temporary variable while evaluating an expression. + */ + QString dest() const; + void incDest(); + void decDest(); + void resetDest(); + + protected: + /** + * Strips comments from m_program, simplifies the white space in each line, + * puts braces on separate lines, and then removes any blank lines. + */ + void simplifyProgram(); + + QStringList m_usedInterrupts; + SourceLineList m_program; + QString m_errorReport; + int m_uniqueLabel; + VariableList m_variables; + int m_dest; + unsigned m_maxDelaySubroutine; + + /** + * Keeps a list of aliases that have been created which maps the key as + * the alias text to the data which is the thing being aliased, so that + * something can be aliased to two different things. e.g. + * alias ken bob + * alias mary bob + */ + QMap m_aliasList; + /** + * Once the child parser has found it, this is set to the pic type + * string found in the source file. The pic type directive must be + * the first thing in the microbe program, before even includes. + * @see PIC14::Type + */ + int m_picType; +}; + + +#endif + diff --git a/microbe/optimizer.cpp b/microbe/optimizer.cpp new file mode 100644 index 0000000..33b0bcd --- /dev/null +++ b/microbe/optimizer.cpp @@ -0,0 +1,512 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "instruction.h" +#include "optimizer.h" + +#include + +#include +#include +using namespace std; + + +QString binary( uchar val ) +{ + QString bin = QString::number( val, 2 ); + QString pad; + pad.fill( '0', 8-bin.length() ); + return pad + bin; +} + + +Optimizer::Optimizer() +{ + m_pCode = 0l; +} + + +Optimizer::~Optimizer() +{ +} + + +void Optimizer::optimize( Code * code ) +{ +// return; + m_pCode = code; + + bool changed; + do + { + changed = false; + + // Repeatedly generate links and states until + // we know as much as possible about the system. + propagateLinksAndStates(); + + // Remove instructions without input links + changed |= pruneInstructions(); + + // Perform optimizations based on processor states + changed |= optimizeInstructions(); + } + while ( changed ); +} + + +void Optimizer::propagateLinksAndStates() +{ + int count = 0; + + do + { + count++; + m_pCode->generateLinksAndStates(); + } + while ( giveInputStates() ); + +// cout << "count="<end(); + for ( Code::iterator it = m_pCode->begin(); it != end; ++it ) + { + // Now, build up the most specific known processor state from the instructins + // that could be executed immediately before this instruction. + // This is done by taking the output state of the first input link, and + // then reducing it to the greatest common denominator of all the input states. + + const InstructionList list = (*it)->inputLinks(); + if ( list.isEmpty() ) + continue; + + InstructionList::const_iterator inputIt = list.begin(); + InstructionList::const_iterator inputsEnd = list.end(); + + ProcessorState input = (*(inputIt++))->outputState(); + + while ( inputIt != inputsEnd ) + input.merge( (*inputIt++)->outputState() ); + + if ( !changed ) + { + ProcessorState before = (*it)->inputState(); + bool stateChanged = ( before != input ); + changed |= stateChanged; + } + + (*it)->setInputState( input ); + } + return changed; +} + + +bool Optimizer::pruneInstructions() +{ + bool removed = false; + + //BEGIN remove instructions without any input links + Code::iterator it = m_pCode->begin(); + Code::iterator end = m_pCode->end(); + + // Jump past the first instruction, as nothing (necessarily) points to that + if ( it != end ) + ++it; + + while ( it != end ) + { + if ( (*it)->inputLinks().isEmpty() ) + { +// cout << "Removing: " << (*it)->code() << endl; + it.removeAndIncrement(); + removed = true; + } + else + ++it; + } + end = m_pCode->end(); // Reset end as instructions may have been removed + //END remove instructions without any input links + + + //BEGIN remove labels without any reference to them + // First: build up a list of labels which are referenced + QStringList referencedLabels; + for ( it = m_pCode->begin(); it != end; ++it ) + { + if ( Instr_goto * ins = dynamic_cast(*it) ) + referencedLabels << ins->label(); + else if ( Instr_call * ins = dynamic_cast(*it) ) + referencedLabels << ins->label(); + } + + // Now remove labels from instructions that aren't in the referencedLabels list + for ( it = m_pCode->begin(); it != end; ++it ) + { + QStringList labels = (*it)->labels(); + + QStringList::iterator labelsEnd = labels.end(); + for ( QStringList::iterator labelsIt = labels.begin(); labelsIt != labelsEnd; ) + { + if ( !referencedLabels.contains( *labelsIt ) ) + { + labelsIt = labels.erase( labelsIt ); + removed = true; + } + else + ++labelsIt; + } + + (*it)->setLabels( labels); + } + //END remove labels without any reference to them + + return removed; +} + + +bool Optimizer::optimizeInstructions() +{ + //BEGIN Optimization 1: Concatenate chained GOTOs + // We go through the instructions looking for GOTO statements. If we find any, then + // we trace back through their input links to any other GOTO statements - any that + // are found are then redirected to point to the label that the original GOTO statement + // was pointing at. + Code::iterator end = m_pCode->end(); + for ( Code::iterator it = m_pCode->begin(); it != end; ++it ) + { + Instr_goto * gotoIns = dynamic_cast(*it); + if ( !gotoIns ) + continue; + + if ( redirectGotos( gotoIns, gotoIns->label() ) ) + return true; + m_pCode->setAllUnused(); + } + //END Optimization 1: Concatenate chained GOTOs + + + //BEGIN Optimization 2: Remove GOTOs when jumping to the subsequent instruction + // Any GOTO instructions that just jump to the next instruction can be removed. + for ( Code::iterator it = m_pCode->begin(); it != end; ++it ) + { + Instruction * next = *(++Code::iterator(it)); + Instruction * gotoIns = dynamic_cast(*it); + if ( !gotoIns || !next || (gotoIns->outputLinks().first() != next) ) + continue; + +// cout << "Removing: " << gotoIns->code() << endl; + it.removeAndIncrement(); + return true; + } + end = m_pCode->end(); + //END Optimization 2: Remove GOTOs when jumping to the subsequent instruction + + + //BEGIN Optimization 3: Replace MOVWF with CLRF with W is 0 + // We look for MOVWF instructions where the working register holds zero. + // We then replace the MOVWf instruction with a CLRF instruction. + for ( Code::iterator it = m_pCode->begin(); it != end; ++it ) + { + Instr_movwf * ins = dynamic_cast(*it); + if ( !ins ) + continue; + + ProcessorState inputState = ins->inputState(); + RegisterState working = inputState.working; + if ( (working.value != 0x0) || (working.known != 0xff) ) + continue; + + // CLRF sets the Z flag of STATUS to 1, but MOVWF does not set any flags. + // So we need to check for dependence of the Z flag if we are possibly + // changing the flag by replacing the instruction. + if ( !(inputState.status.definiteOnes() & (1 << RegisterBit::Z)) ) + { + // Input state of Z flag is either unknown or low. + + uchar depends = generateRegisterDepends( *it, Register::STATUS ); + if ( depends & (1 << RegisterBit::Z) ) + { + // Looks like there's some instruction that depends on the zero bit, + // and we about potentially about to change it. + continue; + } + } + + + Instr_clrf * instr_clrf = new Instr_clrf( ins->file() ); +// cout << "Replacing \""<<(*it)->code()<<"\" with \""<code()<<"\"\n"; + it.insertBefore( instr_clrf ); + it.removeAndIncrement(); + return true; + } + //END Optimization 3: Replace MOVWF with CLRF with W is 0 + + + //BEGIN Optimization 4: Replace writes to W with MOVLW when value is known + // We look for instructions with AssemblyType either WorkingOriented, or FileOriented + // and writing to W. Then, if the value is known and there are no instructions that + // depend on the STATUS bits set by the instruction, then we replace it with a MOVLW + for ( Code::iterator it = m_pCode->begin(); it != end; ++it ) + { + if ( dynamic_cast(*it) ) + { + // If we don't catch this condition, we'll end up in an infinite loop, + // repeatedly replacing the first MOVLW that we come across. + continue; + } + + bool workingOriented = (*it)->assemblyType() == Instruction::WorkingOriented; + bool fileOriented = (*it)->assemblyType() == Instruction::FileOriented; + if ( !workingOriented && (!fileOriented || ((*it)->dest() != 0)) ) + continue; + + // So can now assume that workingOriented and fileOriented are logical opposites + + RegisterState outputState = (*it)->outputState().working; + if ( outputState.known != 0xff ) + continue; + + ProcessorBehaviour behaviour = (*it)->behaviour(); + + // MOVLW does not set any STATUS flags, but the instruction that we are replacing + // might. So we must check if any of these STATUS flags are depended upon, and if so + // only allow replacement if the STATUS flags are not being changed. + if ( !canRemove( *it, Register::STATUS, behaviour.reg( Register::STATUS ).indep ) ) + continue; + + Instr_movlw * movlw = new Instr_movlw( outputState.value ); +// cout << "Replacing \""<<(*it)->code()<<"\" with \""<code()<<"\"\n"; + it.insertBefore( movlw ); + it.removeAndIncrement(); + return true; + } + //END Optimization 4: Replace writes to W with MOVLW when value is known + + + //BEGIN Optimization 5: Remove writes to a bit when the value is ignored and overwritten again + // We go through the instructions looking for statements that write to a bit (bcf, bsf). + // If we find any, then we trace through their output links to see if their value is + // overwritten before it is used - and if so, the instruction can be removed. + for ( Code::iterator it = m_pCode->begin(); it != end; ++it ) + { + if ( (*it)->assemblyType() != Instruction::BitOriented ) + continue; + + const Register regSet = (*it)->file(); + + if ( regSet.affectsExternal() ) + continue; + + uchar bitPos = (*it)->bit().bitPos(); + + ProcessorState inputState = (*it)->inputState(); + ProcessorState outputState = (*it)->outputState(); + ProcessorBehaviour behaviour = (*it)->behaviour(); + + // Are we rewriting over a bit that already has the same value? + // (Note this check is just for the bit changing instructions, as there is a similar + // check for register changing actions later on when we know which bits care about + // being overwritten). + if ( inputState.reg( regSet ).known & (1 << bitPos) ) + { + bool beforeVal = (inputState.reg( regSet ).value & (1 << bitPos)); + bool afterVal = (outputState.reg( regSet ).value & (1 << bitPos)); + if ( beforeVal == afterVal ) + { +// cout << "Removing: " << (*it)->code() << endl; + it.removeAndIncrement(); + return true; + } + } + + uchar depends = generateRegisterDepends( *it, regSet ); + if ( !(depends & (1 << bitPos)) ) + { + // Bit is overwritten before being used - so lets remove this instruction :) +// cout << "Removing: " << (*it)->code() << endl; + it.removeAndIncrement(); + return true; + } + } + m_pCode->setAllUnused(); + //END Optimization 5: Remove writes to a bit when the value is ignored and overwritten again + + + //BEGIN Optimization 6: Remove writes to a register when the value is ignored and overwritten again + // We go through the instructions looking for statements that write to a register (such as MOVLW). + // If we find any, then we trace through their output links to see if their value is + // overwritten before it is used - and if so, the instruction can be removed. + for ( Code::iterator it = m_pCode->begin(); it != end; ++it ) + { + bool noFile = false; + + switch ( (*it)->assemblyType() ) + { + case Instruction::WorkingOriented: + noFile = true; + // (no break) + + case Instruction::FileOriented: + break; + + case Instruction::BitOriented: + case Instruction::Other: + case Instruction::None: + continue; + } + + const Register regSet = noFile ? Register( Register::WORKING ) : (*it)->outputReg(); + + if ( regSet.affectsExternal() ) + continue; + + ProcessorState inputState = (*it)->inputState(); + ProcessorState outputState = (*it)->outputState(); + ProcessorBehaviour behaviour = (*it)->behaviour(); + + // All ins_file instructions will affect at most two registers; the + // register it is writing to (regSet) and the status register. + // In i==0, test regSet + // In i==1, test STATUS + bool ok = true; + for ( unsigned i = 0; i < 2; ++ i) + { + // If we are testing STATUS, then we assume that the bits changed + // are only those that are marked as independent. + uchar bitmask = ( i == 1 ) ? behaviour.reg( Register::STATUS ).indep : 0xff; + if ( !canRemove( *it, (i == 0) ? regSet : Register::STATUS, bitmask ) ) + { + ok = false; + break; + } + } + + if ( !ok ) + continue; + + // Looks like we're free to remove the instruction :); +// cout << "Removing: " << (*it)->code() << endl; + it.removeAndIncrement(); + return true; + } + m_pCode->setAllUnused(); + //END Optimization 6: Remove writes to a register when the value is ignored and overwritten again + + return false; +} + + +bool Optimizer::redirectGotos( Instruction * current, const QString & label ) +{ + if ( current->isUsed() ) + return false; + + current->setUsed( true ); + + bool changed = false; + + const InstructionList list = current->inputLinks(); + InstructionList::const_iterator end = list.end(); + for ( InstructionList::const_iterator it = list.begin(); it != end; ++it ) + { + Instr_goto * gotoIns = dynamic_cast(*it); + if ( !gotoIns || (gotoIns->label() == label) ) + continue; + +// cout << "Redirecting goto to label \"" << label << "\" : " << gotoIns->code() << endl; + gotoIns->setLabel( label ); + changed = true; + } + + return changed; +} + + +uchar Optimizer::generateRegisterDepends( Instruction * current, const Register & reg ) +{ + m_pCode->setAllUnused(); + + const InstructionList list = current->outputLinks(); + InstructionList::const_iterator listEnd = list.end(); + + uchar depends = 0x0; + + for ( InstructionList::const_iterator listIt = list.begin(); listIt != listEnd; ++listIt ) + depends |= registerDepends( *listIt, reg ); + + return depends; +} + + +uchar Optimizer::registerDepends( Instruction * current, const Register & reg ) +{ + if ( current->isUsed() ) + return current->registerDepends( reg ); + + current->setUsed( true ); + + uchar depends = 0x0; + + const InstructionList list = current->outputLinks(); + InstructionList::const_iterator end = list.end(); + for ( InstructionList::const_iterator it = list.begin(); it != end; ++it ) + depends |= registerDepends( *it, reg ); + + RegisterBehaviour behaviour = current->behaviour().reg( reg ); + depends &= ~(behaviour.indep); // Get rid of depend bits that are set in this instruction + depends |= behaviour.depends; // And add the ones that are dependent in this instruction + + current->setRegisterDepends( depends, reg ); + return depends; +} + + +bool Optimizer::canRemove( Instruction * ins, const Register & reg, uchar bitMask ) +{ + // The bits that are depended upon in the future for this register + uchar depends = generateRegisterDepends( ins, reg ); + + // Only interested in those bits allowed by the bit mask + depends &= bitMask; + + RegisterState inputState = ins->inputState().reg( reg ); + RegisterState outputState = ins->outputState().reg( reg ); + + if ( inputState.unknown() & depends ) + { + // There's at least one bit whose value is depended on, but is not known before this + // instruction is executed. Therefore, it is not safe to remove this instruction. + return false; + } + + if ( outputState.unknown() & depends ) + { + // There's at least one bit whose value is depended on, but is not known after this + // instruction is executed. Therefore, it is not safe to remove this instruction. + return false; + } + + uchar dependsInput = inputState.value & depends; + uchar dependsOutput = outputState.value & depends; + if ( dependsInput != dependsOutput ) + { + // At least one bit whose value is depended upon was changed. + return false; + } + + return true; +} + diff --git a/microbe/optimizer.h b/microbe/optimizer.h new file mode 100644 index 0000000..249abd0 --- /dev/null +++ b/microbe/optimizer.h @@ -0,0 +1,87 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef OPTIMIZER_H +#define OPTIMIZER_H + +#include "instruction.h" + + +/// Used for debugging; returns the uchar as a binary string (e.g. 01101010). +QString binary( uchar val ); + + +/** +@author David Saxton +*/ +class Optimizer +{ + public: + Optimizer(); + ~Optimizer(); + + void optimize( Code * code ); + + protected: + /** + * Repeatedly generates links and states for the instructions and + * refining their input states, until equilibrium in the input states + * is reached. + */ + void propagateLinksAndStates(); + /** + * Tell the instructions about their input states. + * @return whether any input states changed from the previous value + * stored in the instruction (if checkChanged is true - else returns + * true). + */ + bool giveInputStates(); + /** + * Remove instructions without any input links (and the ones that are + * only linked to from a removed instruction). + * @return whether any instructions were removed + */ + bool pruneInstructions(); + /** + * Perform optimizations (code cropping, modification, assembly, etc) + * based on instruction linkage and processor states. + * @return whether anything was changed + */ + bool optimizeInstructions(); + /** + * Redirects any GOTOs that point at the given instruction to the given + * label. + * @return whether any GOTOs were redirected + */ + bool redirectGotos( Instruction * current, const QString & label ); + /** + * Find out if the given instruction or any of its outputs overwrite + * any of the bits of the given register before they are used. + */ + uchar generateRegisterDepends( Instruction * current, const Register & reg ); + /** + * This function should only be used from generateRegisterDepends. + * Recursively looks at the output links of the given instruction, and + * returns which bits are eventually used before being overwritten. + */ + uchar registerDepends( Instruction * current, const Register & reg ); + /** + * We often need to know whether removing an instruction will affect the + * future processor state. This function looks are all possible future + * dependencies of the given register, and returns true if the removal + * of the instruction will have no critical effect. + * @param bitMask only look at the given bits of the register + */ + bool canRemove( Instruction * ins, const Register & reg, uchar bitMask = 0xff ); + + Code * m_pCode; +}; + +#endif diff --git a/microbe/parser.cpp b/microbe/parser.cpp new file mode 100644 index 0000000..15335e0 --- /dev/null +++ b/microbe/parser.cpp @@ -0,0 +1,1054 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by Daniel Clarke * + * daniel.jc@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "btreebase.h" +#include "expression.h" +#include "instruction.h" +#include "parser.h" +#include "pic14.h" +#include "traverser.h" + +#include +#include +#include +#include +#include +#include + +#include +using namespace std; + + +//BEGIN class Parser +Parser::Parser( Microbe * _mb ) +{ + m_code = 0; + m_pPic = 0; + mb = _mb; + // Set up statement definitions. + StatementDefinition definition; + + definition.append( Field(Field::Label, "label") ); + m_definitionMap["goto"] = definition; + definition.clear(); + + definition.append( Field(Field::Label, "label") ); + m_definitionMap["call"] = definition; + definition.clear(); + + definition.append( Field(Field::Expression, "expression") ); + definition.append( Field(Field::Code, "code") ); + m_definitionMap["while"] = definition; + definition.clear(); + + m_definitionMap["end"] = definition; + definition.clear(); + + definition.append( Field(Field::Label, "label") ); + definition.append( Field(Field::Code, "code") ); + // For backwards compataibility + m_definitionMap["sub"] = definition; + m_definitionMap["subroutine"] = definition; + definition.clear(); + + definition.append( Field(Field::Label, "label") ); + definition.append( Field(Field::Code, "code") ); + m_definitionMap["interrupt"] = definition; + definition.clear(); + + definition.append( Field(Field::Label, "alias") ); + definition.append( Field(Field::Label, "dest") ); + m_definitionMap["alias"] = definition; + definition.clear(); + + definition.append( Field(Field::Expression, "expression") ); + definition.append( Field(Field::FixedString, 0, "then", true) ); + definition.append( Field(Field::Code, "ifCode") ); + definition.append( Field(Field::Newline) ); + definition.append( Field(Field::FixedString, 0, "else", false) ); + definition.append( Field(Field::Code, "elseCode") ); + m_definitionMap["if"] = definition; + definition.clear(); + + definition.append( Field(Field::Expression, "initExpression") ); + definition.append( Field(Field::FixedString, 0, "to", true) ); + definition.append( Field(Field::Expression, "toExpression") ); + definition.append( Field(Field::FixedString, 0, "step", false) ); + definition.append( Field(Field::Expression, "stepExpression") ); + definition.append( Field(Field::Code, "code") ); + m_definitionMap["for"] = definition; + definition.clear(); + + definition.append( Field(Field::Variable, "variable") ); + m_definitionMap["decrement"] = definition; + definition.clear(); + + definition.append( Field(Field::Variable, "variable") ); + m_definitionMap["increment"] = definition; + definition.clear(); + + definition.append( Field(Field::Variable, "variable") ); + m_definitionMap["rotateleft"] = definition; + definition.clear(); + + definition.append( Field(Field::Variable, "variable") ); + m_definitionMap["rotateright"] = definition; + definition.clear(); + + definition.append( Field(Field::Code, "code") ); + m_definitionMap["asm"] = definition; + definition.clear(); + + definition.append( Field(Field::Expression, "expression") ); + m_definitionMap["delay"] = definition; + definition.clear(); + + definition.append( Field(Field::Code, "code") ); + definition.append( Field(Field::Newline) ); + definition.append( Field(Field::FixedString, 0, "until", true) ); + definition.append( Field(Field::Expression, "expression") ); + m_definitionMap["repeat"] = definition; + definition.clear(); + + definition.append( Field(Field::Name, "name") ); + definition.append( Field(Field::PinList, "pinlist") ); + m_definitionMap["sevenseg"] = definition; + definition.clear(); + + definition.append( Field(Field::Name, "name") ); + definition.append( Field(Field::PinList, "pinlist") ); + m_definitionMap["keypad"] = definition; + definition.clear(); +} + +Parser::~Parser() +{ +} + +Parser* Parser::createChildParser() +{ + Parser * parser = new Parser( mb ); + + return parser; +} + + +Code * Parser::parseWithChild( const SourceLineList & lines ) +{ + Parser * p = createChildParser(); + Code * code = p->parse(lines); + delete p; + return code; +} + + +Code * Parser::parse( const SourceLineList & lines ) +{ + StatementList sList; + m_pPic = mb->makePic(); + m_code = new Code(); + m_pPic->setCode( m_code ); + m_pPic->setParser(this); + m_bPassedEnd = false; + + /* First pass + ========== + + Here we go through the code making each line into a statement object, + looking out for braced code as we go, if we find it then we put then + we make attach the braced code to the statment. + */ + + SourceLineList::const_iterator end = lines.end(); + for ( SourceLineList::const_iterator slit = lines.begin(); slit != end; ++slit ) + { + Statement s; + s.content = *slit; + + // Check to see if the line after next is a brace + SourceLineList::const_iterator previous = slit; + if ( (++slit != end) && (*slit).text() == "{" ) + s.bracedCode = getBracedCode( & slit, end ); + else + slit = previous; + + if ( !s.text().isEmpty() ) + sList.append(s); + } + + mb->resetDest(); + + for( StatementList::Iterator sit = sList.begin(); sit != sList.end(); ++sit ) + { + m_currentSourceLine = (*sit).content; + + QString line = (*sit).text(); + + QString command; // e.g. "delay", "for", "subroutine", "increment", etc + { + int spacepos = line.find(' '); + if ( spacepos >= 0 ) + command = line.left( spacepos ); + else + command = line; + } + OutputFieldMap fieldMap; + + if ( (*sit).content.line() >= 0 ) + m_code->append( new Instr_sourceCode( QString("#MSRC\t%1; %2\t%3").arg( (*sit).content.line() + 1 ).arg( (*sit).content.url() ).arg( (*sit).content.text() ) )); + bool showBracesInSource = (*sit).hasBracedCode(); + if ( showBracesInSource ) + m_code->append(new Instr_sourceCode("{")); + + // Use the first token in the line to look up the statement type + DefinitionMap::Iterator dmit = m_definitionMap.find(command); + if(dmit == m_definitionMap.end()) + { + if( !processAssignment( (*sit).text() ) ) + { + // Not an assignement, maybe a label + if( (*sit).isLabel() ) + { + QString label = (*sit).text().left( (*sit).text().length() - 1 ); + ///TODO sanity check label name and then do error like "Bad label" + m_pPic->Slabel( label ); + } + else + mistake( Microbe::Microbe::UnknownStatement ); + } + + continue; // Give up on the current statement + } + StatementDefinition definition = dmit.data(); + + // Start at the first white space character following the statement name + int newPosition = 0; + int position = command.length() + 1; + + // Temporaries for use inside the switch + Field nextField; + Statement nextStatement; + + bool errorInLine = false; + bool finishLine = false; + + for( StatementDefinition::Iterator sdit = definition.begin(); sdit != definition.end(); ++sdit ) + { + // If there is an error, or we have finished the statement, + // the stop. If we are at the end of a line in a multiline, then + // break to fall through to the next line + if( errorInLine || finishLine) break; + + Field field = (*sdit); + QString token; + + bool saveToken = false; + bool saveBraced = false; + bool saveSingleLine = false; + + switch(field.type()) + { + case (Field::Label): + case (Field::Variable): + case (Field::Name): + { + newPosition = line.find( ' ', position ); + if(position == newPosition) + { + newPosition = -1; + token = line.mid(position); + } + else token = line.mid(position, newPosition - position); + if( token.isEmpty() ) + { + if(field.type() == Field::Label) + mistake( Microbe::Microbe::LabelExpected ); + else if (field.type() == Field::Variable) + mistake( Microbe::VariableExpected ); + else // field.type() == Field::Name + mistake( Microbe::NameExpected ); + errorInLine = true; + continue; + } + position = newPosition; + saveToken = true; + break; + } + + case (Field::Expression): + { + // This is slightly different, as there is nothing + // in particular that delimits an expression, we just have to + // look at what comes next and hope we can use that. + StatementDefinition::Iterator it(sdit); + ++it; + if( it != definition.end() ) + { + nextField = (*it); + if(nextField.type() == Field::FixedString) + newPosition = line.find(QRegExp("\\b" + nextField.string() + "\\b")); + // Although code is not neccessarily braced, after an expression it is the only + // sensilbe way to have it. + else if(nextField.type() == Field::Code) + { + newPosition = line.find("{"); + if(newPosition == -1) newPosition = line.length() + 1; + } + else if(nextField.type() == Field::Newline) + newPosition = line.length()+1; + else kdDebug() << "Bad statement definition - awkward field type after expression"; + } + else newPosition = line.length() + 1; + if(newPosition == -1) + { + // Something was missing, we'll just play along for now, + // the next iteration will catch whatever was supposed to be there + } + token = line.mid(position, newPosition - position); + position = newPosition; + saveToken = true; + } + break; + + case (Field::PinList): + { + // For now, just assume that the list of pins will continue to the end of the tokens. + // (we could check until we come across a non-pin, but no command has that format at + // the moment). + + token = line.mid( position + 1 ); + position = line.length() + 1; + if ( token.isEmpty() ) + mistake( Microbe::PinListExpected ); + else + saveToken = true; + + break; + } + + case (Field::Code): + if ( !(*sit).hasBracedCode() ) + { + saveSingleLine = true; + token = line.mid(position); + position = line.length() + 1; + } + else if( position != -1 && position <= int(line.length()) ) + { + mistake( Microbe::UnexpectedStatementBeforeBracket ); + errorInLine = true; + continue; + } + else + { + // Because of the way the superstructure parsing works there is no + // 'next line' as it were, the braced code is attached to the current line. + saveBraced = true; + } + break; + + case (Field::FixedString): + { + // Is the string found, and is it starting in the right place? + int stringPosition = line.find(QRegExp("\\b"+field.string()+"\\b")); + if( stringPosition != position || stringPosition == -1 ) + { + if( !field.compulsory() ) + { + position = -1; + // Skip the next field + ++sdit; + continue; + } + else + { + // Otherwise raise an appropriate error + mistake( Microbe::FixedStringExpected, field.string() ); + errorInLine = true; + continue; + } + } + else + { + position += field.string().length() + 1; + } + } + break; + + case (Field::Newline): + // It looks like the best way to handle this is to just actually + // look at the next line, and see if it begins with an expected fixed + // string. + + // Assume there is a next field, it would be silly if there weren't. + nextField = *(++StatementDefinition::Iterator(sdit)); + if( nextField.type() == Field::FixedString ) + { + nextStatement = *(++StatementList::Iterator(sit)); + newPosition = nextStatement.text().find(QRegExp("\\b" + nextField.string() + "\\b")); + if(newPosition != 0) + { + // If the next field is optional just carry on as nothing happened, + // the next line will be processed as a new statement + if(!nextField.compulsory()) continue; + + } + position = 0; + line = (*(++sit)).text(); + m_currentSourceLine = (*sit).content; + } + + break; + + case (Field::None): + // Do nothing + break; + } + + if ( saveToken ) + fieldMap[field.key()] = OutputField( token ); + + if ( saveSingleLine ) + { + SourceLineList list; + list << SourceLine( token, 0, -1 ); + fieldMap[field.key()] = OutputField( list ); + } + + if ( saveBraced ) + fieldMap[field.key()] = OutputField( (*sit).bracedCode ); + // If position = -1, we have reached the end of the line. + } + + // See if we got to the end of the line, but not all fields had been + // processed. + if( position != -1 && position <= int(line.length()) ) + { + mistake( Microbe::TooManyTokens ); + errorInLine = true; + } + + if( errorInLine ) continue; + + // Everything has been parsed up, so send it off for processing. + processStatement( command, fieldMap ); + + if( showBracesInSource ) + m_code->append(new Instr_sourceCode("}")); + } + + delete m_pPic; + return m_code; +} + +bool Parser::processAssignment(const QString &line) +{ + QStringList tokens = Statement::tokenise(line); + + // Have to have at least 3 tokens for an assignment; + if ( tokens.size() < 3 ) + return false; + + QString firstToken = tokens[0]; + + firstToken = mb->alias(firstToken); + // Well firstly we look to see if it is a known variable. + // These can include 'special' variables such as ports + // For now, the processor subclass generates ports it self + // and puts them in a list for us. + + + // Look for port variables first. + if ( firstToken.contains(".") ) + { + PortPin portPin = m_pPic->toPortPin( firstToken ); + + // check port is valid + if ( portPin.pin() == -1 ) + mistake( Microbe::InvalidPort, firstToken ); + // more error checking + if ( tokens[1] != "=" ) + mistake( Microbe::UnassignedPin ); + + QString state = tokens[2]; + if( state == "high" ) + m_pPic->Ssetlh( portPin, true ); + else if( state == "low" ) + m_pPic->Ssetlh( portPin, false ); + else + mistake( Microbe::NonHighLowPinState ); + } + // no dots, lets try for just a port name + else if( m_pPic->isValidPort( firstToken ) ) + { + // error checking + if ( tokens[1] != "=" ) + mistake( Microbe::UnassignedPort, tokens[1] ); + + Expression( m_pPic, mb, m_currentSourceLine, false ).compileExpression(line.mid(line.find("=")+1)); + m_pPic->saveResultToVar( firstToken ); + } + else if ( m_pPic->isValidTris( firstToken ) ) + { + if( tokens[1] == "=" ) + { + Expression( m_pPic, mb, m_currentSourceLine, false ).compileExpression(line.mid(line.find("=")+1)); + m_pPic->Stristate(firstToken); + } + } + else + { + // Is there an assignment? + if ( tokens[1] != "=" ) + return false; + + if ( !mb->isValidVariableName( firstToken ) ) + { + mistake( Microbe::InvalidVariableName, firstToken ); + return true; + } + + // Don't care whether or not the variable is new; Microbe will only add it if it + // hasn't been defined yet. + mb->addVariable( Variable( Variable::charType, firstToken ) ); + + Expression( m_pPic, mb, m_currentSourceLine, false ).compileExpression(line.mid(line.find("=")+1)); + + Variable v = mb->variable( firstToken ); + switch ( v.type() ) + { + case Variable::charType: + m_pPic->saveResultToVar( v.name() ); + break; + + case Variable::keypadType: + mistake( Microbe::ReadOnlyVariable, v.name() ); + break; + + case Variable::sevenSegmentType: + m_pPic->SsevenSegment( v ); + break; + + case Variable::invalidType: + // Doesn't happen, but include this case to avoid compiler warnings + break; + } + } + + return true; +} + + +SourceLineList Parser::getBracedCode( SourceLineList::const_iterator * it, SourceLineList::const_iterator end ) +{ + // Note: The sourceline list has the braces on separate lines. + + // This function should only be called when the parser comes across a line that is a brace. + assert( (**it).text() == "{" ); + + SourceLineList braced; + + // Jump past the first brace + unsigned level = 1; + ++(*it); + + for ( ; *it != end; ++(*it) ) + { + if ( (**it).text() == "{" ) + level++; + + else if ( (**it).text() == "}" ) + level--; + + if ( level == 0 ) + return braced; + + braced << **it; + } + + // TODO Error: mismatched bracing + return braced; +} + + +void Parser::processStatement( const QString & name, const OutputFieldMap & fieldMap ) +{ + // Name is guaranteed to be something known, the calling + // code has taken care of that. Also fieldMap is guaranteed to contain + // all required fields. + + if ( name == "goto" ) + m_pPic->Sgoto(fieldMap["label"].string()); + + else if ( name == "call" ) + m_pPic->Scall(fieldMap["label"].string()); + + else if ( name == "while" ) + m_pPic->Swhile( parseWithChild(fieldMap["code"].bracedCode() ), fieldMap["expression"].string() ); + + else if ( name == "repeat" ) + m_pPic->Srepeat( parseWithChild(fieldMap["code"].bracedCode() ), fieldMap["expression"].string() ); + + else if ( name == "if" ) + m_pPic->Sif( + parseWithChild(fieldMap["ifCode"].bracedCode() ), + parseWithChild(fieldMap["elseCode"].bracedCode() ), + fieldMap["expression"].string() ); + + else if ( name == "sub" || name == "subroutine" ) + { + if(!m_bPassedEnd) + { + mistake( Microbe::InterruptBeforeEnd ); + } + else + { + m_pPic->Ssubroutine( fieldMap["label"].string(), parseWithChild( fieldMap["code"].bracedCode() ) ); + } + } + else if( name == "interrupt" ) + { + QString interrupt = fieldMap["label"].string(); + + if(!m_bPassedEnd) + { + mistake( Microbe::InterruptBeforeEnd ); + } + else if( !m_pPic->isValidInterrupt( interrupt ) ) + { + mistake( Microbe::InvalidInterrupt ); + } + else if ( mb->isInterruptUsed( interrupt ) ) + { + mistake( Microbe::InterruptRedefined ); + } + else + { + mb->setInterruptUsed( interrupt ); + m_pPic->Sinterrupt( interrupt, parseWithChild( fieldMap["code"].bracedCode() ) ); + } + } + else if( name == "end" ) + { + ///TODO handle end if we are not in the top level + m_bPassedEnd = true; + m_pPic->Send(); + } + else if( name == "for" ) + { + QString step = fieldMap["stepExpression"].string(); + bool stepPositive; + + if( fieldMap["stepExpression"].found() ) + { + if(step.left(1) == "+") + { + stepPositive = true; + step = step.mid(1).stripWhiteSpace(); + } + else if(step.left(1) == "-") + { + stepPositive = false; + step = step.mid(1).stripWhiteSpace(); + } + else stepPositive = true; + } + else + { + step = "1"; + stepPositive = true; + } + + QString variable = fieldMap["initExpression"].string().mid(0,fieldMap["initExpression"].string().find("=")).stripWhiteSpace(); + QString endExpr = variable+ " <= " + fieldMap["toExpression"].string().stripWhiteSpace(); + + if( fieldMap["stepExpression"].found() ) + { + bool isConstant; + step = processConstant(step,&isConstant); + if( !isConstant ) + mistake( Microbe::NonConstantStep ); + } + + SourceLineList tempList; + tempList << SourceLine( fieldMap["initExpression"].string(), 0, -1 ); + + m_pPic->Sfor( parseWithChild( fieldMap["code"].bracedCode() ), parseWithChild( tempList ), endExpr, variable, step, stepPositive ); + } + else if( name == "alias" ) + { + // It is important to get this the right way round! + // The alias should be the key since two aliases could + // point to the same name. + + QString alias = fieldMap["alias"].string().stripWhiteSpace(); + QString dest = fieldMap["dest"].string().stripWhiteSpace(); + + // Check to see whether or not we've already aliased it... +// if ( mb->alias(alias) != alias ) +// mistake( Microbe::AliasRedefined ); +// else + mb->addAlias( alias, dest ); + } + else if( name == "increment" ) + { + QString variableName = fieldMap["variable"].string(); + + if ( !mb->isVariableKnown( variableName ) ) + mistake( Microbe::UnknownVariable ); + else if ( !mb->variable( variableName ).isWritable() ) + mistake( Microbe::ReadOnlyVariable, variableName ); + else + m_pPic->SincVar( variableName ); + } + else if( name == "decrement" ) + { + QString variableName = fieldMap["variable"].string(); + + if ( !mb->isVariableKnown( variableName ) ) + mistake( Microbe::UnknownVariable ); + else if ( !mb->variable( variableName ).isWritable() ) + mistake( Microbe::ReadOnlyVariable, variableName ); + else + m_pPic->SdecVar( variableName ); + } + else if( name == "rotateleft" ) + { + QString variableName = fieldMap["variable"].string(); + + if ( !mb->isVariableKnown( variableName ) ) + mistake( Microbe::UnknownVariable ); + else if ( !mb->variable( variableName ).isWritable() ) + mistake( Microbe::ReadOnlyVariable, variableName ); + else + m_pPic->SrotlVar( variableName ); + } + else if( name == "rotateright" ) + { + QString variableName = fieldMap["variable"].string(); + + if ( !mb->isVariableKnown( variableName ) ) + mistake( Microbe::UnknownVariable ); + else if ( !mb->variable( variableName ).isWritable() ) + mistake( Microbe::ReadOnlyVariable, variableName ); + else + m_pPic->SrotrVar( variableName ); + } + else if( name == "asm" ) + { + m_pPic->Sasm( SourceLine::toStringList( fieldMap["code"].bracedCode() ).join("\n") ); + } + else if( name == "delay" ) + { + // This is one of the rare occasions that the number will be bigger than a byte, + // so suppressNumberTooBig must be used + bool isConstant; + QString delay = processConstant(fieldMap["expression"].string(),&isConstant,true); + if (!isConstant) + mistake( Microbe::NonConstantDelay ); +// else m_pPic->Sdelay( fieldMap["expression"].string(), ""); + else + { + // TODO We should use the "delay" string returned by processConstant - not the expression (as, e.g. 2*3 won't be ok) + int length_ms = literalToInt( fieldMap["expression"].string() ); + if ( length_ms >= 0 ) + m_pPic->Sdelay( length_ms * 1000 ); // Pause the delay length in microseconds + else + mistake( Microbe::NonConstantDelay ); + } + } + else if ( name == "keypad" || name == "sevenseg" ) + { + QStringList pins = QStringList::split( ' ', fieldMap["pinlist"].string() ); + QString variableName = fieldMap["name"].string(); + + if ( mb->isVariableKnown( variableName ) ) + { + mistake( Microbe::VariableRedefined, variableName ); + return; + } + + PortPinList pinList; + + QStringList::iterator end = pins.end(); + for ( QStringList::iterator it = pins.begin(); it != end; ++it ) + { + PortPin portPin = m_pPic->toPortPin(*it); + if ( portPin.pin() == -1 ) + { + // Invalid port/pin + //TODO mistake + return; + } + pinList << portPin; + } + + if ( name == "keypad" ) + { + Variable v( Variable::keypadType, variableName ); + v.setPortPinList( pinList ); + mb->addVariable( v ); + } + + else // name == "sevenseg" + { + if ( pinList.size() != 7 ) + mistake( Microbe::InvalidPinMapSize ); + else + { + Variable v( Variable::sevenSegmentType, variableName ); + v.setPortPinList( pinList ); + mb->addVariable( v ); + } + } + } +} + + +void Parser::mistake( Microbe::MistakeType type, const QString & context ) +{ + mb->compileError( type, context, m_currentSourceLine ); +} + + +// static function +QStringList Statement::tokenise(const QString &line) +{ + QStringList result; + QString current; + int count = 0; + + for(int i = 0; i < int(line.length()); i++) + { + QChar nextChar = line[i]; + if( nextChar.isSpace() ) + { + if( count > 0 ) + { + result.append(current); + current = ""; + count = 0; + } + } + else if( nextChar == '=' ) + { + if( count > 0 ) result.append(current); + current = ""; + count = 0; + result.append("="); + } + else if( nextChar == '{' ) + { + if( count > 0 ) result.append(current); + current = ""; + count = 0; + result.append("{"); + } + else + { + count++; + current.append(nextChar); + } + } + if( count > 0 ) result.append(current); + return result; +} + +int Parser::doArithmetic(int lvalue, int rvalue, Expression::Operation op) +{ + switch(op) + { + case Expression::noop: return 0; + case Expression::addition: return lvalue + rvalue; + case Expression::subtraction: return lvalue - rvalue; + case Expression::multiplication: return lvalue * rvalue; + case Expression::division: return lvalue / rvalue; + case Expression::exponent: return lvalue ^ rvalue; + case Expression::equals: return lvalue == rvalue; + case Expression::notequals: return !(lvalue == rvalue); + case Expression::bwand: return lvalue & rvalue; + case Expression::bwor: return lvalue | rvalue; + case Expression::bwxor: return lvalue ^ rvalue; + case Expression::bwnot: return !rvalue; + case Expression::le: return lvalue <= rvalue; + case Expression::ge: return lvalue >= rvalue; + case Expression::lt: return lvalue < rvalue; + case Expression::gt: return lvalue > rvalue; + + case Expression::pin: + case Expression::notpin: + case Expression::function: + case Expression::divbyzero: + case Expression::read_keypad: + // Not applicable actions. + break; + } + return -1; +} + +bool Parser::isLiteral( const QString &text ) +{ + bool ok; + literalToInt( text, & ok ); + return ok; +} + +/* +Literal's in form: +-> 321890 +-> 021348 +-> 0x3C +-> b'0100110' +-> 0101001b +-> h'43A' +-> 2Ah + +Everything else is non-literal... +*/ +int Parser::literalToInt( const QString &literal, bool * ok ) +{ + bool temp; + if ( !ok ) + ok = & temp; + *ok = true; + + int value = -1; + + // Note when we use toInt, we don't have to worry about checking + // that literal.mid() is convertible, as toInt returns this in ok anyway. + + // Try binary first, of form b'n...n' + if( literal.left(2) == "b'" && literal.right(1) == "'" ) + { + value = literal.mid(2,literal.length() - 3).toInt(ok,2); + return *ok ? value : -1; + } + + // Then try hex of form h'n...n' + if( literal.left(2) == "h'" && literal.right(1) == "'" ) + { + value = literal.mid(2,literal.length() - 3).toInt(ok,16); + return *ok ? value : -1; + } + + // otherwise, let QString try and convert it + // base 0 == automatic base guessing + value = literal.toInt( ok, 0 ); + return *ok ? value : -1; +} + + +void Parser::compileConditionalExpression( const QString & expression, Code * ifCode, Code * elseCode ) const +{ + ///HACK ///TODO this is a little improper, I don't think we should be using the pic that called us... + + Expression( m_pPic, mb, m_currentSourceLine, false ).compileConditional(expression,ifCode,elseCode); +} + + +QString Parser::processConstant(const QString &expression, bool * isConstant, bool suppressNumberTooBig) const +{ + return Expression( m_pPic, mb, m_currentSourceLine, suppressNumberTooBig ).processConstant(expression, isConstant); +} +//END class Parser + + + +//BEGIN class Field +Field::Field() +{ + m_type = None; + m_compulsory = false; +} + + +Field::Field( Type type, const QString & key ) +{ + m_type = type; + m_compulsory = false; + m_key = key; +} + + +Field::Field( Type type, const QString & key, const QString & string, bool compulsory ) +{ + m_type = type; + m_compulsory = compulsory; + m_key = key; + m_string = string; +} +//END class Field + + + +//BEGIN class OutputField +OutputField::OutputField() +{ + m_found = false; +} + + +OutputField::OutputField( const SourceLineList & bracedCode ) +{ + m_bracedCode = bracedCode; + m_found = true; +} + +OutputField::OutputField( const QString & string/*, int lineNumber*/ ) +{ + m_string = string; + m_found = true; +} +//END class OutputField + + + +#if 0 +// Second pass + + else if( firstToken == "include" ) + { + // only cope with 'sane' strings a.t.m. + // e.g. include "filename.extenstion" + QString filename = (*sit).content.mid( (*sit).content.find("\"") ).stripWhiteSpace(); + // don't strip whitespace from within quotes as you + // can have filenames composed entirely of spaces (kind of weird)... + // remove quotes. + filename = filename.mid(1); + filename = filename.mid(0,filename.length()-1); + QFile includeFile(filename); + if( includeFile.open(IO_ReadOnly) ) + { + QTextStream stream( &includeFile ); + QStringList includeCode; + while( !stream.atEnd() ) + { + includeCode += stream.readLine(); + } + ///TODO make includes work + //output += parse(includeCode); + includeFile.close(); + } + else + mistake( Microbe::UnopenableInclude, filename ); + } +#endif + + diff --git a/microbe/parser.h b/microbe/parser.h new file mode 100644 index 0000000..ece433d --- /dev/null +++ b/microbe/parser.h @@ -0,0 +1,293 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by Daniel Clarke * + * daniel.jc@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef PARSER_H +#define PARSER_H + +#include "expression.h" +#include "instruction.h" +#include "microbe.h" + +#include "qmap.h" +#include "qvaluelist.h" + +class PIC14; + +/** +@author Daniel Clarke +@author David Saxton +*/ +class Statement +{ + public: + /** + * Is the assembly output generated for this statement. + */ + InstructionList * code; + /** + * The original microbe source line. + */ + SourceLine content; + /** + * Returns the microbe code from content. + */ + QString text() const { return content.text(); } + /** + * If this Statement is for a for loop, then content will contain + * something like "for x = 1 to 10", and bracedCode will contain the + * source code within (but not including) the braces. + */ + SourceLineList bracedCode; + /** + * Just returns whether or not the braced code is empty. + */ + bool hasBracedCode() const { return !bracedCode.isEmpty(); } + /** + * This breaks up the line seperated by spaces,{,and =/ + */ + static QStringList tokenise(const QString &line); + /** + * @see tokenise(const QString &line) + */ + QStringList tokenise() const { return tokenise( content.text() ); } + /** + * @returns whether or not the content looks like a label (ends with a + * colon). + */ + bool isLabel() const { return content.text().right(1) == ":"; } +}; + +typedef QValueList StatementList; + +/** +@author Daniel Clarke +@author David Saxton +*/ +class Field +{ + public: + enum Type + { + // String that doesn't change the program logic, but might or might + // not need to be there depending on the statement (e.g. "then" in + // the if-statement). + FixedString, + + // Label, Variable, Name are all treated similarly (only different + // error messages are given). + Label, // e.g. in "goto [Label]" + Variable, // e.g. in "increment [Variable]" + Name, // e.g. in "sevenseg [Name]" + + // List of strings which should be pin names. + PinList, + + // Braced code. + Code, + + Expression, + Newline, + None + }; + + /** + * Create a Field of type None. + */ + Field(); + /** + * Create a Field. + */ + Field( Type type, const QString & key = 0 ); + /** + * Create a Field (this constructor should only be used with + * FixedStrings. + */ + Field( Type type, const QString & key, const QString & string, bool compulsory = true); + + /** + * The type of field expected. + */ + Type type() const { return m_type; } + /** + * String data relevant to the field dependent on m_type. + */ + QString string() const { return m_string; } + /** + * The key in which the found token will be attached to + * in the output map. If it is an empty string, then the field will be + * processed but not put in the output, effectively ignoring it. + */ + QString key() const { return m_key; } + /** + * Only FixedStrings may be compulsory, that is the only type that can + * actually have its presence checked. + * This flag is set to indicate that no error should be rasied if the + * field is not present. Note that if a field is found missing, then + * the rest of the statement is ignored (regardless of whether the rest + * is marked compulsory or not.) + */ + bool compulsory() const { return m_compulsory; } + + private: + Type m_type; + QString m_string; + QString m_key; + bool m_compulsory; +}; + + +class OutputField +{ + public: + /** + * Constructs an empty output field. + */ + OutputField(); + /** + * Constructs an output field consisting of braced code. + */ + OutputField( const SourceLineList & bracedCode ); + /** + * Constructs an output field consisting of a single string. + */ + OutputField( const QString &string ); + + QString string() const { return m_string; } + SourceLineList bracedCode() const { return m_bracedCode; } + bool found() const { return m_found; } + + private: + QString m_string; + SourceLineList m_bracedCode; + /** + * This specifies if a non compulsory field was found or not. + */ + bool m_found; +}; + +typedef QValueList StatementDefinition; +typedef QMap DefinitionMap; +typedef QMap OutputFieldMap; + + +/** +@author Daniel Clarke +@author David Saxton +*/ +class Parser +{ + public: + Parser( Microbe * mb ); + ~Parser(); + + /** + * Report a compile error to Microbe; the current source line will be + * sent. Context is extra information to be inserted into the error + * message, only applicable to some errors (such as a use of a reserved + * keyword). + */ + void mistake( Microbe::MistakeType type, const QString & context = 0 ); + /** + * Creates a new instance of the parser class with all state information + * (class members) copied from this instance of the class. Don't forget to + * delete it when you are done! + */ + Parser * createChildParser(); + /** + * Creates a child class and uses it to parse recursively. + */ + Code * parseWithChild( const SourceLineList & lines ); + /** + * This is the actual parsing function, make sure to use parseUsingChild + * instead (???) + */ + Code * parse( const SourceLineList & lines ); + /** + * Returns the lines between the braces, excluding the braces, e.g. + * defproc name + * { + * more code + * some more code + * } + * returns ("more code","some more code"). + * Note that Microbe has already put the braces on separate lines for us. + * @param it is the iterator at the position of the first brace, this + * function will return with it pointing at the matching closing brace. + * @param end is the iterator pointing to the end of the source line + * list, so that we don't search past it. + * @returns The braced code (excluding the braces). + */ + SourceLineList getBracedCode( SourceLineList::const_iterator * it, SourceLineList::const_iterator end ); + /** + * Returns expression type. + * 0 = directly usable number (literal). + * 1 = variable. + * 2 = expression that needs evaluating. + */ + ExprType getExpressionType( const QString & expression ); + /** + * Examines the text to see if it looks like a literal, i.e. of the form + * "321890","021348","0x3C","b'0100110'","0101001b","h'43A'", or "2Ah". + * Everything else is considered non-literal. + * @see literalToInt. + */ + static bool isLiteral( const QString &text ); + /** + * Tries to convert the given literal string into a integer. If it fails, + * i.e. it is not any recognised literal, then it returns -1 and sets *ok to + * false. Else, *ok is set to true and the literal value is returned. + * @see isLiteral + */ + static int literalToInt( const QString & literal, bool * ok = 0l ); + /** + * Does the specified operation on the given numbers and returns the result. + */ + static int doArithmetic( int lvalue, int rvalue, Expression::Operation op ); + /** + * @return whether it was an assignment (which might not have been in + * the proper form). + */ + bool processAssignment(const QString &line); + + void compileConditionalExpression( const QString & expression, Code * ifCode, Code * elseCode ) const; + QString processConstant(const QString &expression, bool * isConstant, bool suppressNumberTooBig = false) const; + + private: + /** + * This is called when the bulk of the actual parsing has been carried + * out and is ready to be turned into assembly code. + * @param name Name of the statement to be processed + * @param fieldMap A map of named fields as appropriate to the statement + */ + void processStatement( const QString & name, const OutputFieldMap & fieldMap ); + + DefinitionMap m_definitionMap; + PIC14 * m_pPic; + bool m_bPassedEnd; + Microbe * mb; + Code * m_code; + SourceLine m_currentSourceLine; + + private: // Disable copy constructor and operator= + Parser( const Parser & ); + Parser &operator=( const Parser & ); +}; + +#endif diff --git a/microbe/pic14.cpp b/microbe/pic14.cpp new file mode 100644 index 0000000..7785afb --- /dev/null +++ b/microbe/pic14.cpp @@ -0,0 +1,1196 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by Daniel Clarke * + * daniel.jc@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + + +#include "instruction.h" +#include "parser.h" +#include "pic14.h" + +#include +#include +#include +using namespace std; + +bool LEDSegTable[][7] = { +{ 1, 1, 1, 1, 1, 1, 0 }, +{ 0, 1, 1, 0, 0, 0, 0 }, // 1 +{ 1, 1, 0, 1, 1, 0, 1 }, // 2 +{ 1, 1, 1, 1, 0, 0, 1 }, // 3 +{ 0, 1, 1, 0 ,0, 1, 1 }, // 4 +{ 1, 0, 1, 1, 0, 1, 1 }, // 5 +{ 1, 0, 1, 1, 1, 1, 1 }, // 6 +{ 1, 1, 1, 0, 0, 0, 0 }, // 7 +{ 1, 1, 1, 1, 1, 1, 1 }, // 8 +{ 1, 1, 1, 0, 0, 1, 1 }, // 9 +{ 1, 1, 1, 0, 1, 1, 1 }, // A +{ 0, 0, 1, 1, 1, 1, 1 }, // b +{ 1, 0, 0, 1, 1, 1, 0 }, // C +{ 0, 1, 1, 1, 1, 0, 1 }, // d +{ 1, 0, 0, 1, 1, 1, 1 }, // E +{ 1, 0, 0, 0, 1, 1, 1 } // F +}; + + + +PIC14::PIC14( Microbe * master, Type type ) +{ + mb = master; + m_pCode = 0l; + m_type = type; + +} + + +PIC14::~PIC14() +{ +} + +PortPin PIC14::toPortPin( const QString & portPinString ) +{ + QString port; + int pin = -1; + + // In form e.g. RB3 + if ( portPinString.length() == 3 ) + { + port = QString("PORT%1").arg( portPinString[1].upper() ); + pin = QString( portPinString[2] ).toInt(); + } + else + { + int dotpos = portPinString.find("."); + if ( dotpos == -1 ) + return PortPin(); + + port = portPinString.left(dotpos); + pin = portPinString.mid(dotpos+1).toInt(); + } + + PortPin portPin( port, pin ); + + if ( isValidPortPin( portPin ) ) + return portPin; + else + return PortPin(); +} + + +void PIC14::mergeCode( Code * code ) +{ + m_pCode->merge( code ); +} + + +uchar PIC14::gprStart() const +{ + switch ( m_type ) + { + case P16C84: + case P16F84: + return 0xc; + + case P16F627: + case P16F628: + return 0x20; + + case unknown: + break; + } + + kdError() << k_funcinfo << "Unknown PIC type = " << m_type << endl; + return 0xc; +} + + +PIC14::Type PIC14::toType( const QString & _text ) +{ + QString text = _text.upper().simplifyWhiteSpace().remove('P'); + + if ( text == "16C84" ) + return P16C84; + + if ( text == "16F84" ) + return P16F84; + + if ( text == "16F627" ) + return P16F627; + + if ( text == "16F628" ) + return P16F628; + + cerr << QString("%1 is not a known PIC identifier\n").arg(_text); + return unknown; +} + + +QString PIC14::minimalTypeString() const +{ + switch ( m_type ) + { + case P16C84: + return "16C84"; + + case P16F84: + return "16F84"; + + case P16F627: + return "16F627"; + + case P16F628: + return "16F628"; + + case unknown: + break; + } + + kdError() << k_funcinfo << "Unknown PIC type = " << m_type << endl; + return 0;; +} + + +void PIC14::postCompileConstruct( const QStringList &interrupts ) +{ + m_pCode->append( new Instr_raw("\n\tEND\n"), Code::Subroutine ); + + if ( interrupts.isEmpty() ) + { + // If there are no ISRs then we don't need to put in any handler code. + // Instead, just insert the goto start instruction in case we need to + // jump past any lookup tabes (and if there are none, then the optimizer + // will remove the goto instruction). + m_pCode->append(new Instr_goto("_start"), Code::InterruptHandler); + m_pCode->queueLabel( "_start", Code::LookupTable ); + return; + } + + /* + INTCON register: + 7 --- GIE EEIE T0IE INTE RBIE T0IF INTF RBIF --- 0 + + E: enable + F: flag + Flag bits must be cleared manually before reactivating GIE, + but we do this in each individual interrupt handler + */ + + // The bizarre dance with swap is to ensure the status bits + // are preserved properly + m_pCode->append(new Instr_goto("_start"), Code::InterruptHandler); + + m_pCode->append(new Instr_raw("ORG 0x4"), Code::InterruptHandler); + // When we arrive here: + // Return address on stack, + // GIE flag cleared (globally interrupts disabled) + // W or STATUS not preserved by processor. + m_pCode->append(new Instr_movwf("W_TEMP"), Code::InterruptHandler); + m_pCode->append(new Instr_swapf("STATUS",0), Code::InterruptHandler); + m_pCode->append(new Instr_movwf("STATUS_TEMP"), Code::InterruptHandler); + + QStringList::ConstIterator interruptsEnd = interrupts.end(); + for( QStringList::ConstIterator it = interrupts.begin(); it != interruptsEnd; ++it ) + { + // Is the interrupt's flag bit set? + m_pCode->append(new Instr_btfsc("INTCON",QString::number(interruptNameToBit((*it), true))), Code::InterruptHandler); + m_pCode->append(new Instr_goto("_interrupt_" + (*it)), Code::InterruptHandler); // Yes, do its handler routine + // Otherwise fall through to the next. + } + + // If there was "somehow" a suprious interrupt there isn't really + // much we can do about that (??) so just fall through and hope for the worst. + + m_pCode->queueLabel( "_interrupt_end", Code::InterruptHandler ); + m_pCode->append(new Instr_swapf("STATUS_TEMP",0), Code::InterruptHandler ); + m_pCode->append(new Instr_movwf("STATUS"), Code::InterruptHandler ); + m_pCode->append(new Instr_swapf("W_TEMP",1), Code::InterruptHandler ); + m_pCode->append(new Instr_swapf("W_TEMP",0), Code::InterruptHandler ); + m_pCode->append(new Instr_retfie()); // Returns and renables globally interrupts. + + m_pCode->queueLabel( "_start", Code::LookupTable ); +} + +int PIC14::interruptNameToBit(const QString &name, bool flag) +{ + // 7 --- GIE EEIE T0IE INTE RBIE T0IF INTF RBIF --- 0 + + if( name == "change" ) // RB + { + if(flag) return 0; + else return 3; + } + else if( name == "timer" ) + { + if(flag) return 2; + else return 5; + } + else if( name == "external" ) + { + if(flag) return 1; + else return 4; + } + + return -1; +} + + +bool PIC14::isValidPort( const QString & portName ) const +{ + return ( portName == "PORTA" || portName == "porta" || + portName == "PORTB" || portName == "portb" ); +} + + +bool PIC14::isValidPortPin( const PortPin & portPin ) const +{ + if ( portPin.port() == "PORTA" ) + return (portPin.pin() >= 0) && (portPin.pin() <= 4); + + if ( portPin.port() == "PORTB" ) + return (portPin.pin() >= 0) && (portPin.pin() <= 7); + + return false; +} + + +bool PIC14::isValidTris( const QString & trisName ) const +{ + return ( trisName == "TRISA" || trisName == "trisa" || + trisName == "TRISB" || trisName == "trisb" ); +} + + +bool PIC14::isValidInterrupt( const QString & interruptName ) const +{ + if(m_type == "P16F84" || m_type =="P16C84") + { + return ( interruptName == "change" || + interruptName == "timer" || + interruptName == "external" ); + } + return false; +} + + +void PIC14::setConditionalCode( Code * ifCode, Code * elseCode ) +{ + m_ifCode = ifCode; + m_elseCode = elseCode; +} + +void PIC14::Sgoto(const QString &label) +{ + m_pCode->append( new Instr_goto(label) ); +} + +void PIC14::Slabel(const QString &label) +{ +// std::cout << k_funcinfo << "label="<queueLabel( label, Code::Middle ); +} + +void PIC14::Send() +{ + m_pCode->append( new Instr_sleep() ); +} + +void PIC14::Ssubroutine( const QString &procName, Code * subCode ) +{ + m_pCode->queueLabel( procName, Code::Subroutine ); + m_pCode->merge( subCode, Code::Subroutine ); + m_pCode->append( new Instr_return(), Code::Subroutine ); +} + +void PIC14::Sinterrupt( const QString &procName, Code * subCode ) +{ + m_pCode->queueLabel( "_interrupt_" + procName, Code::Subroutine ); + + // Clear the interrupt flag for this particular interrupt source + m_pCode->append( new Instr_bcf("INTCON",QString::number(interruptNameToBit(procName,true))) ); + m_pCode->merge( subCode, Code::Subroutine ); + + m_pCode->append( new Instr_goto("_interrupt_end"), Code::Subroutine ); +} + + +void PIC14::Scall(const QString &name) +{ + m_pCode->append( new Instr_call(name) ); +} + + +void PIC14::Ssetlh( const PortPin & portPin, bool high) +{ + if(high) + m_pCode->append( new Instr_bsf( portPin.port(),QString::number(portPin.pin()) ) ); + else + m_pCode->append( new Instr_bcf( portPin.port(), QString::number(portPin.pin()) ) ); +} + +void PIC14::rearrangeOpArguments( QString * val1, QString * val2, LocationType * val1Type, LocationType * val2Type) +{ + if( *val2Type == work && *val1Type != work ) + { + LocationType tempType = *val2Type; + QString tempVal = *val2; + + *val2Type = *val1Type; + *val2 = *val1; + + *val1Type = tempType; + *val1 = tempVal; + } +} + +void PIC14::add( QString val1, QString val2, LocationType val1Type, LocationType val2Type ) +{ + rearrangeOpArguments( &val1, &val2, &val1Type, &val2Type ); + + switch(val1Type) + { + case num: m_pCode->append(new Instr_movlw( val1.toInt( 0, 0 ) )); break; + case work: break; + case var: m_pCode->append(new Instr_movf(val1,0)); break; + } + + switch(val2Type) + { + case num: m_pCode->append(new Instr_addlw(val2.toInt( 0, 0 ))); break; + case work: break; + case var: m_pCode->append(new Instr_addwf(val2,0)); break; + } +} + +void PIC14::subtract( const QString & val1, const QString & val2, LocationType val1Type, LocationType val2Type ) +{ + switch(val2Type) + { + case num: m_pCode->append(new Instr_movlw( val2.toInt( 0, 0 ) )); break; + case work: break; + case var: m_pCode->append(new Instr_movf(val2,0)); break; + } + switch(val1Type) + { + case num: m_pCode->append(new Instr_sublw(val1.toInt( 0, 0 ))); break; + case work: break; + case var: m_pCode->append(new Instr_subwf(val1,0)); break; + } +} + +void PIC14::assignNum(const QString & val) +{ + m_pCode->append(new Instr_movlw(val.toInt( 0, 0 ))); +} + +void PIC14::assignVar(const QString &val) +{ + m_pCode->append(new Instr_movf(val,0)); +} + +void PIC14::saveToReg(const QString &dest) +{ + m_pCode->append(new Instr_movwf(dest)); +} + +void PIC14::saveResultToVar( const QString & var ) +{ + m_pCode->append( new Instr_movwf( var ) ); +} + +void PIC14::mul(QString val1, QString val2, LocationType val1Type, LocationType val2Type) +{ + multiply(); + + rearrangeOpArguments( &val1, &val2, &val1Type, &val2Type ); + + // First, set _i argument + switch(val1Type) + { + case num: m_pCode->append(new Instr_movlw(val1.toInt( 0, 0 ))); break; + case work: break; + case var: m_pCode->append(new Instr_movf(val1,0)); break; + } + + m_pCode->append(new Instr_movwf("__i")); + + // Then set _j argument + switch(val2Type) + { + case num: m_pCode->append(new Instr_movlw(val2.toInt( 0, 0 ))); break; + case work: break; + case var: m_pCode->append(new Instr_movf(val2,0)); break; + } + + m_pCode->append(new Instr_movwf("__j")); + m_pCode->append(new Instr_call("__picfunc_multiply")); + m_pCode->append(new Instr_movf("__result",0)); +} + + +void PIC14::multiply() +{ + if ( m_pCode->instruction("__picfunc_multiply") ) + return; + + m_pCode->queueLabel( "__picfunc_multiply", Code::Subroutine ); + m_pCode->append(new Instr_clrf("__result"), Code::Subroutine ); //result+=m_pCode->appenduction("clrf __result"); + + m_pCode->queueLabel( "__picfunc_multiply_loop", Code::Subroutine ); + m_pCode->append(new Instr_movf("__i",0), Code::Subroutine ); //result+=m_pCode->appenduction("movf __i,0"); + m_pCode->append(new Instr_btfsc("__j","0"), Code::Subroutine ); //result+=m_pCode->appenduction("btfsc __j,0"); + m_pCode->append(new Instr_addwf("__result",1), Code::Subroutine ); //result+=m_pCode->appenduction("addwf __result,1"); + m_pCode->append(new Instr_bcf("STATUS","C"), Code::Subroutine ); //result+=m_pCode->appenduction("bcf STATUS,C"); + m_pCode->append(new Instr_rrf("__j",1), Code::Subroutine ); //result+=m_pCode->appenduction("rrf __j,1"); + m_pCode->append(new Instr_bcf("STATUS","C"), Code::Subroutine ); //result+=m_pCode->appenduction("bcf STATUS,C"); + m_pCode->append(new Instr_rlf("__i",1), Code::Subroutine ); //result+=m_pCode->appenduction("rlf __i,1"); + m_pCode->append(new Instr_movf("__j",1), Code::Subroutine ); //result+=m_pCode->appenduction("movf __j,1"); + m_pCode->append(new Instr_btfss("STATUS","Z"), Code::Subroutine ); //result+=m_pCode->appenduction("btfss STATUS,Z"); + m_pCode->append(new Instr_goto("__picfunc_multiply_loop"), Code::Subroutine ); //result+=m_pCode->appenduction("goto __picfunc_multiply_loop"); + m_pCode->append(new Instr_return(), Code::Subroutine ); //result+=m_pCode->appenduction("return"); +} + + +void PIC14::div( const QString & val1, const QString & val2, LocationType val1Type, LocationType val2Type) +{ + divide(); + + // NOO - "x / 2" is NOT the same as "2 / x" +// rearrangeOpArguments( val1, val2, val1Type, val2Type ); + + // First, set _i argument + switch(val1Type) + { + case num: m_pCode->append(new Instr_movlw(val1.toInt( 0, 0 ))); break; + case work: break; + case var: m_pCode->append(new Instr_movf(val1,0)); break; + } + + m_pCode->append(new Instr_movwf("__i")); + + // Then set _j argument + switch(val2Type) + { + case num: m_pCode->append(new Instr_movlw(val2.toInt( 0, 0 ))); break; + case work: break; + case var: m_pCode->append(new Instr_movf(val2,0)); break; + } + + m_pCode->append(new Instr_movwf("__j")); + + m_pCode->append(new Instr_call("__picfunc_divide"));//result+=instruction("call __picfunc_divide"); + m_pCode->append(new Instr_movf("__result",0));//result+=instruction("movf __result,0"); +} + +void PIC14::divide() +{ + m_pCode->queueLabel( "__picfunc_divide", Code::Subroutine ); + m_pCode->append(new Instr_movf("__j",1), Code::Subroutine ); + m_pCode->append(new Instr_btfsc("STATUS","2"), Code::Subroutine ); + m_pCode->append(new Instr_return(), Code::Subroutine ); + m_pCode->append(new Instr_clrf("__result"), Code::Subroutine ); + m_pCode->append(new Instr_movlw(1), Code::Subroutine ); + m_pCode->append(new Instr_movwf("__k"), Code::Subroutine ); + + m_pCode->queueLabel( "__divide_shift", Code::Subroutine ); + m_pCode->append(new Instr_bcf("STATUS","C"), Code::Subroutine ); + m_pCode->append(new Instr_rlf("__k",1), Code::Subroutine ); + m_pCode->append(new Instr_bcf("STATUS","C"), Code::Subroutine ); + m_pCode->append(new Instr_rlf("__j",1), Code::Subroutine ); + m_pCode->append(new Instr_btfss("__j","7"), Code::Subroutine ); + m_pCode->append(new Instr_goto("__divide_shift"), Code::Subroutine ); + + m_pCode->queueLabel( "__divide_loop", Code::Subroutine ); + m_pCode->append(new Instr_movf("__j",0), Code::Subroutine ); + m_pCode->append(new Instr_subwf("__i",1), Code::Subroutine ); + m_pCode->append(new Instr_btfsc("STATUS","C"), Code::Subroutine ); + m_pCode->append(new Instr_goto("__divide_count"), Code::Subroutine ); + m_pCode->append(new Instr_addwf("__i",1), Code::Subroutine ); + m_pCode->append(new Instr_goto("__divide_final"), Code::Subroutine ); + + m_pCode->queueLabel( "__divide_count", Code::Subroutine ); + m_pCode->append(new Instr_movf("__k",0), Code::Subroutine ); + m_pCode->append(new Instr_addwf("__result",1), Code::Subroutine ); + + m_pCode->queueLabel( "__divide_final", Code::Subroutine ); + m_pCode->append(new Instr_bcf("STATUS","C"), Code::Subroutine ); + m_pCode->append(new Instr_rrf("__j",1), Code::Subroutine ); + m_pCode->append(new Instr_bcf("STATUS","C"), Code::Subroutine ); + m_pCode->append(new Instr_rrf("__k",1), Code::Subroutine ); + m_pCode->append(new Instr_btfss("STATUS","C"), Code::Subroutine ); + m_pCode->append(new Instr_goto("__divide_loop"), Code::Subroutine ); + m_pCode->append(new Instr_return(), Code::Subroutine ); +} + + +Code * PIC14::ifCode() +{ + return m_ifCode; +} + + +Code * PIC14::elseCode() +{ + return m_elseCode; +} + + +void PIC14::ifInitCode( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type ) +{ + // NOO - "x < 2" is NOT the same as "2 < x" +// rearrangeOpArguments( val1, val2, val1Type, val2Type ); + + switch(val1Type) + { + case num: + m_pCode->append(new Instr_movlw(val1.toInt( 0, 0 ))); + break; + + case work: + break; // Nothing to do + + case var: + m_pCode->append(new Instr_movf(val1,0)); + break; + } + + switch(val2Type) + { + case num: + m_pCode->append(new Instr_sublw(val2.toInt( 0, 0 ))); + break; + + case work: + kdError() << k_funcinfo << "Cannot subtract working from working!" << endl; + break; + + case var: + m_pCode->append(new Instr_subwf(val2,0)); + break; + } +} + +void PIC14::equal( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type ) +{ + ifInitCode( val1, val2, val1Type, val2Type ); + const QString labelEnd = mb->uniqueLabel()+"_endif"; + const QString labelFalse = mb->uniqueLabel()+"_case_false"; + + m_pCode->append(new Instr_btfss("STATUS","2")); + m_pCode->append(new Instr_goto(labelFalse)); + + mergeCode( ifCode() ); + + m_pCode->append(new Instr_goto(labelEnd)); + + m_pCode->queueLabel( labelFalse ); + mergeCode( elseCode() ); + m_pCode->queueLabel( labelEnd ); +} + +void PIC14::notEqual( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type ) +{ + ifInitCode( val1, val2, val1Type, val2Type ); + const QString labelEnd = mb->uniqueLabel()+"_endif"; + const QString labelFalse = mb->uniqueLabel()+"_case_false"; + + m_pCode->append(new Instr_btfsc("STATUS","2")); + m_pCode->append(new Instr_goto(labelFalse)); + + mergeCode( ifCode() ); + + m_pCode->append(new Instr_goto(labelEnd)); + + m_pCode->queueLabel( labelFalse ); + mergeCode( elseCode() ); + m_pCode->queueLabel( labelEnd ); +} + +void PIC14::greaterThan( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type ) +{ + ifInitCode( val1, val2, val1Type, val2Type ); + const QString labelEnd = mb->uniqueLabel()+"_endif"; + const QString labelFalse = mb->uniqueLabel()+"_case_false"; + + m_pCode->append(new Instr_btfsc("STATUS","0")); + m_pCode->append(new Instr_goto(labelFalse)); + + mergeCode( ifCode() ); + m_pCode->append(new Instr_goto(labelEnd)); + + m_pCode->queueLabel( labelFalse ); + mergeCode( elseCode() ); + m_pCode->queueLabel( labelEnd ); +} + +void PIC14::lessThan( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type ) +{ + cout << k_funcinfo << endl; + ifInitCode( val1, val2, val1Type, val2Type ); + const QString labelEnd = mb->uniqueLabel()+"_endif"; + const QString labelFalse = mb->uniqueLabel()+"_case_false"; + + m_pCode->append(new Instr_btfss("STATUS","0")); + m_pCode->append(new Instr_goto(labelFalse)); + m_pCode->append(new Instr_btfsc("STATUS","2")); + m_pCode->append(new Instr_goto(labelFalse)); + + mergeCode( ifCode() ); + + m_pCode->append(new Instr_goto(labelEnd)); + + m_pCode->queueLabel( labelFalse ); + mergeCode( elseCode() ); + m_pCode->queueLabel( labelEnd ); +} + +void PIC14::greaterOrEqual( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type ) +{ + ifInitCode( val1, val2, val1Type, val2Type ); + const QString labelEnd = mb->uniqueLabel()+"_endif"; + const QString labelTrue = mb->uniqueLabel()+"_case_true"; // Note that unlike the others, this is labelTrue, not labelFalse + + m_pCode->append(new Instr_btfsc("STATUS","2")); + m_pCode->append(new Instr_goto(labelTrue)); + m_pCode->append(new Instr_btfss("STATUS","0")); + m_pCode->append(new Instr_goto(labelTrue)); + + mergeCode( elseCode() ); + + m_pCode->append(new Instr_goto(labelEnd)); + + m_pCode->queueLabel( labelTrue ); + mergeCode( ifCode() ); + m_pCode->queueLabel( labelEnd ); +} + +void PIC14::lessOrEqual( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type ) +{ + ifInitCode( val1, val2, val1Type, val2Type ); + const QString labelEnd = mb->uniqueLabel()+"_endif"; + const QString labelFalse = mb->uniqueLabel()+"_case_false"; + + m_pCode->append(new Instr_btfss("STATUS","0")); + m_pCode->append(new Instr_goto(labelFalse)); + + mergeCode( ifCode() ); + m_pCode->append(new Instr_goto(labelEnd)); + + m_pCode->queueLabel( labelFalse ); + mergeCode( elseCode() ); + m_pCode->queueLabel( labelEnd ); +} + + +void PIC14::Swhile( Code * whileCode, const QString &expression) +{ + QString result; + QString ul = mb->uniqueLabel(); + + whileCode->append( new Instr_goto(ul) ); + + m_pCode->queueLabel( ul, Code::Middle ); + + // If the condition is not true, just fall through + m_parser->compileConditionalExpression( expression, whileCode, 0 ); +} + + +void PIC14::Srepeat( Code * repeatCode, const QString &expression) +{ + QString result; + QString ul = mb->uniqueLabel(); + + Code * elseCode = new Code; + elseCode->append( new Instr_goto(ul) ); + + m_pCode->queueLabel( ul ); + m_pCode->merge( repeatCode ); + + // If the condition is true, just fall through + m_parser->compileConditionalExpression( expression, 0, elseCode ); +} + +void PIC14::Sif( Code * ifCode, Code * elseCode, const QString &expression) +{ + m_parser->compileConditionalExpression( expression, ifCode, elseCode ); +} + + +void PIC14::Sfor( Code * forCode, Code * initCode, const QString &expression, const QString &variable, const QString &step, bool stepPositive) +{ + QString ul = mb->uniqueLabel(); + + if ( step == "1" ) + { + if (stepPositive) + forCode->append(new Instr_incf(variable,1)); + else + forCode->append(new Instr_decf(variable,1)); + } + else + { + forCode->append(new Instr_movlw(step.toInt( 0, 0 ))); + if (stepPositive) + forCode->append(new Instr_addwf(variable,1)); + else + forCode->append(new Instr_subwf(variable,1)); + } + forCode->append(new Instr_goto(ul)); + + m_pCode->merge( initCode ); + + m_pCode->queueLabel( ul ); + + m_parser->compileConditionalExpression( expression, forCode, 0 ); +} + + +void PIC14::Spin( const PortPin & portPin, bool NOT) +{ + QString lowLabel, highLabel, postLabel; + lowLabel = mb->uniqueLabel(); + highLabel = mb->uniqueLabel(); + postLabel = mb->uniqueLabel(); + /*result += indent + "goto\t" + lowLabel; + result += indent + "movlw\t1" + "goto\t"+postLabel+; + result += lowLabel + + indent + "movlw\t0" + indent; + result += postLabel + ;*/ + + if(NOT) + m_pCode->append(new Instr_btfsc( portPin.port(), QString::number( portPin.pin() ) )); + //result +=instruction((QString)(NOT?"btfsc":"btfss")+"\t"+port+","+pin); + else + m_pCode->append(new Instr_btfss( portPin.port(), QString::number( portPin.pin() ) )); + + m_pCode->append(new Instr_goto(lowLabel));//result += instruction("goto\t" + lowLabel); + mergeCode( ifCode() ); + m_pCode->append(new Instr_goto(postLabel));//result += instruction("goto\t"+postLabel); + + m_pCode->queueLabel( lowLabel ); + mergeCode( elseCode() ); + + m_pCode->queueLabel( postLabel ); +} + + +void PIC14::Sdelay( unsigned length_us, Code::InstructionPosition pos ) +{ + if ( length_us == 0 ) + return; + + if ( length_us > 50070524 ) + { + length_us += 50267642; + int l = length_us/50070530; + length_us -= l * 50070530; + int k = length_us/196355; + + m_pCode->append( new Instr_movlw( l ), pos ); + m_pCode->append( new Instr_movwf( "__l" ), pos ); + m_pCode->append( new Instr_movlw( k ), pos ); + m_pCode->append( new Instr_movwf( "__k" ), pos ); + + mb->addDelayRoutineWanted( Delay_50S ); + } + + else if ( length_us > 196350 ) + { + length_us += 197116; + int k = length_us/196355; + length_us -= k * 196355; + int j = length_us/770; + + m_pCode->append( new Instr_incf( "__l", 1 ), pos ); + m_pCode->append( new Instr_movlw( k ), pos ); + m_pCode->append( new Instr_movwf( "__k" ), pos ); + m_pCode->append( new Instr_movlw( j ), pos ); + m_pCode->append( new Instr_movwf( "__j" ), pos ); + + mb->addDelayRoutineWanted( Delay_200mS ); + } + + else if ( length_us > 766 ) + { + length_us += 765; + int j = length_us/770; + length_us -= j * 770; + int i = length_us/3; + + m_pCode->append( new Instr_incf( "__l", 1 ), pos ); + m_pCode->append( new Instr_incf( "__k", 1 ), pos ); + m_pCode->append( new Instr_movlw( j ), pos ); + m_pCode->append( new Instr_movwf( "__j" ), pos ); + m_pCode->append( new Instr_movlw( i ), pos ); + m_pCode->append( new Instr_movwf( "__i" ), pos ); + + mb->addDelayRoutineWanted( Delay_768uS ); + } + + else + { + length_us += -1; + int i = length_us/3; + + m_pCode->append( new Instr_incf( "__l", 1 ), pos ); + m_pCode->append( new Instr_incf( "__k", 1 ), pos ); + m_pCode->append( new Instr_incf( "__j", 1 ), pos ); + m_pCode->append( new Instr_movlw( i ), pos ); + m_pCode->append( new Instr_movwf( "__i" ), pos ); + + mb->addDelayRoutineWanted( Delay_3uS ); + } + + m_pCode->append( new Instr_call( "__delay_subroutine"), pos ); +} + + +void PIC14::addCommonFunctions( DelaySubroutine delay ) +{ + if ( delay != Delay_None ) + { + QString subName = "__delay_subroutine"; + m_pCode->queueLabel( subName, Code::Subroutine ); + + m_pCode->append( new Instr_decfsz( "__i", 1 ), Code::Subroutine ); + m_pCode->append( new Instr_goto( subName ), Code::Subroutine ); + + if ( delay > Delay_3uS ) + { + m_pCode->append( new Instr_decfsz( "__j", 1 ), Code::Subroutine ); + m_pCode->append( new Instr_goto( subName ), Code::Subroutine ); + } + + if ( delay > Delay_768uS ) + { + m_pCode->append( new Instr_decfsz( "__k", 1 ), Code::Subroutine ); + m_pCode->append( new Instr_goto( subName ), Code::Subroutine ); + } + + if ( delay > Delay_200mS ) + { + m_pCode->append( new Instr_decfsz( "__l", 1 ), Code::Subroutine ); + m_pCode->append( new Instr_goto( subName ), Code::Subroutine ); + } + + m_pCode->append( new Instr_return(), Code::Subroutine ); + } +} + + +void PIC14::SsevenSegment( const Variable & pinMap ) +{ + assert( pinMap.type() == Variable::sevenSegmentType ); + assert( pinMap.portPinList().size() == 7 ); + + QString subName = QString("__output_seven_segment_%1").arg( pinMap.name() ); + + m_pCode->append( new Instr_call( subName ) ); + + if ( m_pCode->instruction(subName) ) + return; + + // Build up what are going to write to each port from the pin map + struct SSPortOutput + { + bool used; // Wheter we use this port at all + bool use[8]; // Whether or not we use each pin. + bool out[16][8]; // The bit to write to each pin for each value. + uchar useMask; // The bits of use[8] - this is generated later from use[8] + }; + + unsigned numPorts = 2; + SSPortOutput portOutput[ numPorts ]; + memset( portOutput, 0, numPorts * sizeof(SSPortOutput) ); + + for ( unsigned i = 0; i < 7; ++i ) + { + PortPin portPin = pinMap.portPinList()[i]; + + unsigned port = unsigned( portPin.portPosition() ); + unsigned pin = unsigned( portPin.pin() ); + + portOutput[ port ].used = true; + portOutput[ port ].use[ pin ] = true; + + for ( unsigned num = 0; num < 16; ++num ) + { + portOutput[ port ].out[ num ][ pin ] = LEDSegTable[num][ i ]; + } + } + + + // See if we've used more than one port + unsigned portsUsed = 0; + for ( unsigned port = 0; port < numPorts; ++port ) + { + if ( portOutput[port].used ) + portsUsed++; + } + + + // Generate the useMasks + for ( unsigned port = 0; port < numPorts; ++port ) + { + portOutput[port].useMask = 0; + for ( unsigned pin = 0; pin < 8; ++pin ) + portOutput[port].useMask |= portOutput[port].use[pin] ? (1 << pin) : 0; + } + + + //BEGIN Generate [subName] Subroutine + m_pCode->queueLabel( subName, Code::Subroutine ); +// if ( portsUsed > 1 ) + { + m_pCode->append( new Instr_movwf("__i"), Code::Subroutine ); + } + +// bool overwrittenW = false; + bool overwrittenW = true; + + for ( unsigned port = 0; port < numPorts; ++port ) + { + if ( !portOutput[port].used ) + continue; + + QString portName = QString("PORT%1").arg( char('A'+port) ); + + // Save the current value of the port pins that we should not be writing to + m_pCode->append( new Instr_movf( portName, 0 ), Code::Subroutine ); + m_pCode->append( new Instr_andlw( ~portOutput[port].useMask ), Code::Subroutine ); + m_pCode->append( new Instr_movwf( "__j" ), Code::Subroutine ); + + if ( overwrittenW ) + m_pCode->append( new Instr_movf("__i",0), Code::Subroutine ); + + m_pCode->append( new Instr_call( subName + QString("_lookup_%1").arg(port) ), Code::Subroutine ); + overwrittenW = true; + + // Restore the state of the pins which aren't used + m_pCode->append( new Instr_iorwf( "__j", 0 ), Code::Subroutine ); + + // And write the result to the port + m_pCode->append( new Instr_movwf( portName ), Code::Subroutine ); + } + + m_pCode->append( new Instr_return(), Code::Subroutine ); + //END Generate [subName] Subroutine + + // For each port, generate code for looking up the value for writing to it + for ( unsigned port = 0; port < numPorts; ++port ) + { + if ( !portOutput[port].used ) + continue; + + m_pCode->queueLabel( subName + QString("_lookup_%1").arg(port), Code::LookupTable ); + m_pCode->append( new Instr_andlw(15), Code::LookupTable ); + + // Generate the lookup table + m_pCode->append( new Instr_addwf( "pcl", 1 ), Code::LookupTable ); + for ( unsigned num = 0; num < 16; ++num ) + { + unsigned literal = 0; + for ( unsigned bit = 0; bit < 8; ++bit ) + literal += ( portOutput[port].out[num][bit] ? 1 : 0 ) << bit; + + m_pCode->append( new Instr_retlw( literal ), Code::LookupTable ); + } + } +} + + +void PIC14::Skeypad( const Variable & pinMap ) +{ + // pinMap = 4 rows, n columns + + assert( pinMap.type() == Variable::keypadType ); + assert( pinMap.portPinList().size() >= 7 ); // 4 rows, at least 3 columns + + QString subName = QString("__wait_read_keypad_%1").arg( pinMap.name() ); + QString waitName = QString("__wait_keypad_%1").arg( pinMap.name() ); + QString readName = QString("__read_keypad_%1").arg( pinMap.name() ); + + m_pCode->append( new Instr_call( subName ) ); + + if ( m_pCode->instruction( subName ) ) + return; + + //BEGIN Wait until read subroutine + m_pCode->queueLabel( subName, Code::Subroutine ); + + // Read current key (if any) from keypad and save to temporary variable + m_pCode->append( new Instr_call( readName ), Code::Subroutine ); + m_pCode->append( new Instr_movwf( "__m" ), Code::Subroutine ); + + // Test if any key was pressed; if not, then start again +// std::cout << "mb->alias(\"Keypad_None\")="<alias("Keypad_None") << std::endl; + m_pCode->append( new Instr_sublw( mb->alias("Keypad_None").toInt( 0, 0 ) ), Code::Subroutine ); + m_pCode->append( new Instr_btfsc( "STATUS","Z" ), Code::Subroutine ); + m_pCode->append( new Instr_goto( subName ), Code::Subroutine ); + m_pCode->append( new Instr_goto( waitName ), Code::Subroutine ); + //END Wait until read subroutine + + + //BEGIN Wait until released subroutine + m_pCode->queueLabel( waitName, Code::Subroutine ); + + Sdelay( 10000, Code::Subroutine ); // 10 milliseconds for debouncing + + // Key was pressed; now we wait until the key is released again + m_pCode->append( new Instr_call( readName ), Code::Subroutine ); + m_pCode->append( new Instr_sublw( mb->alias("Keypad_None").toInt( 0, 0 ) ), Code::Subroutine ); + m_pCode->append( new Instr_btfss( "STATUS","Z" ), Code::Subroutine ); + m_pCode->append( new Instr_goto( waitName ), Code::Subroutine ); + m_pCode->append( new Instr_movf( "__m", 0 ), Code::Subroutine ); + m_pCode->append( new Instr_return(), Code::Subroutine ); + //END Wait until released subroutine + + + if ( m_pCode->instruction( readName ) ) + return; + + //BEGIN Read current value of keypad subroutine + m_pCode->queueLabel( readName, Code::Subroutine ); + + // Make the four row lines low + for ( unsigned row = 0; row < 4; ++ row ) + { + PortPin rowPin = pinMap.portPinList()[row]; + m_pCode->append( new Instr_bcf( rowPin.port(), QString::number( rowPin.pin() ) ), Code::Subroutine ); + } + + // Test each row in turn + for ( unsigned row = 0; row < 4; ++ row ) + { + // Make the high low + PortPin rowPin = pinMap.portPinList()[row]; + m_pCode->append( new Instr_bsf( rowPin.port(), QString::number( rowPin.pin() ) ), Code::Subroutine ); + + for ( unsigned col = 0; col < 3; ++ col ) + { + PortPin colPin = pinMap.portPinList()[4+col]; + m_pCode->append( new Instr_btfsc( colPin.port(), QString::number( colPin.pin() ) ), Code::Subroutine ); + m_pCode->append( new Instr_retlw( mb->alias( QString("Keypad_%1_%2").arg(row+1).arg(col+1) ).toInt( 0, 0 ) ), Code::Subroutine ); + } + + // Make the low again + m_pCode->append( new Instr_bcf( rowPin.port(), QString::number( rowPin.pin() ) ), Code::Subroutine ); + } + + // No key was pressed + m_pCode->append( new Instr_retlw( mb->alias("Keypad_None").toInt( 0, 0 ) ), Code::Subroutine ); + //END Read current value of keypad subroutine +} + + +void PIC14::bitwise( Expression::Operation op, const QString &r_val1, const QString &val2, bool val1IsNum, bool val2IsNum ) +{ + QString val1 = r_val1; + // There is no instruction for notting a literal, + // so instead I am going to XOR with 0xFF + if( op == Expression::bwnot ) val1 = "0xFF"; + if( val1IsNum ) m_pCode->append(new Instr_movlw(val1.toInt( 0, 0 )));// result += instruction("movlw\t"+val1); + else m_pCode->append(new Instr_movf(val1,0));//result += instruction("movf\t"+val1+",0"); + + QString opString; + if( val2IsNum ) + { + switch(op) + { + case Expression::bwand: m_pCode->append(new Instr_andlw(val2.toInt( 0, 0 ))); break; + case Expression::bwor: m_pCode->append(new Instr_iorlw(val2.toInt( 0, 0 ))); break; + case Expression::bwxor: m_pCode->append(new Instr_xorlw(val2.toInt( 0, 0 ))); break; + case Expression::bwnot: m_pCode->append(new Instr_xorlw(val2.toInt( 0, 0 ))); break; + default: break; + } + } + else + { + switch(op) + { + case Expression::bwand: m_pCode->append(new Instr_andwf(val2,0)); break; + case Expression::bwor: m_pCode->append(new Instr_iorwf(val2,0)); break; + case Expression::bwxor: m_pCode->append(new Instr_xorwf(val2,0)); break; + case Expression::bwnot: m_pCode->append(new Instr_xorwf(val2,0)); break; + default: break; + } + + } +} + +void PIC14::SincVar( const QString &var ) +{ + m_pCode->append(new Instr_incf(var,1) ); +} + +void PIC14::SdecVar( const QString &var ) +{ + m_pCode->append(new Instr_decf(var,1) ); +} + +void PIC14::SrotlVar( const QString &var ) +{ + m_pCode->append(new Instr_rlf(var,1)); +} + +void PIC14::SrotrVar( const QString &var ) +{ + m_pCode->append(new Instr_rrf(var,1)); +} + +void PIC14::Stristate(const QString &port) +{ + m_pCode->append( new Instr_bsf("STATUS","5") ); + + if( port == "trisa" || port == "TRISA" ) + saveResultToVar( "TRISA" ); + else + saveResultToVar( "TRISB" ); + + m_pCode->append( new Instr_bcf(Register("STATUS"),"5") ); +} + +void PIC14::Sasm(const QString &raw) +{ + m_pCode->append(new Instr_asm(raw)); +} + + + + +//BEGIN class PortPin +PortPin::PortPin( const QString & port, int pin ) +{ + m_port = port.upper(); + m_pin = pin; +} + + +PortPin::PortPin() +{ + m_port = ' '; + m_pin = -1; +} + + +int PortPin::portPosition() const +{ + if ( m_port.isEmpty() ) + return 0; + return uchar( m_port[ m_port.length() - 1 ] ) - 'A'; +} +//END class PortPin diff --git a/microbe/pic14.h b/microbe/pic14.h new file mode 100644 index 0000000..5fd5a40 --- /dev/null +++ b/microbe/pic14.h @@ -0,0 +1,253 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by Daniel Clarke * + * daniel.jc@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef PIC14_H +#define PIC14_H + +#include "expression.h" +#include "microbe.h" + +#include +#include +#include + +class Code; +class Microbe; +class Parser; + +/** +@author David Saxton + */ +class PortPin +{ + public: + PortPin( const QString & port, int pin ); + /** + * Creates an invalid PortPin ( pin() will return -1). + */ + PortPin(); + /** + * Returns port (uppercase). + */ + QString port() const { return m_port; } + /** + * Returns the port position (e.g. "PORTA" is 0, "PORTB" is 1, etc). + */ + int portPosition() const; + /** + * Returns the pin (-1 == invalid PortPin). + */ + int pin() const { return m_pin; } + + protected: + QString m_port; + int m_pin; +}; +typedef QValueList PortPinList; + + +/** +@author Daniel Clarke +@author David Saxton +*/ +class PIC14 +{ + public: + enum Type + { + P16C84, + P16F84, + P16F627, + P16F628, + unknown, + }; + enum LocationType + { + num = 1, + work = 2, + var = 3, + }; + /** + * Used in determining which delay subroutine should be created. + */ + enum DelaySubroutine + { + Delay_None = 0, + Delay_3uS = 1, + Delay_768uS = 2, + Delay_200mS = 3, + Delay_50S = 4, + }; + + PIC14( Microbe * master, Type type ); + ~PIC14(); + + /** + * Tries to convert the string to a PIC type, returning unknown if + * unsuccessful. + */ + static Type toType( const QString & text ); + /** + * @return the PIC type. + */ + Type type() const { return m_type; } + /** + * @return the Type as a string without the P at the front. + */ + QString minimalTypeString() const; + /** + * Translates the portPinString (e.g. "PORTA.2") into a PortPin if the port + * and pin combination is valid (otherwise returns an invalid PortPin with + * a pin of -1. + */ + PortPin toPortPin( const QString & portPinString ); + /** + * Returns the address that the General Purpose Registers starts at. + */ + uchar gprStart() const; + + void setParser(Parser *parser) { m_parser = parser; } + void setCode( Code * code ) { m_pCode = code; } + void mergeCode( Code * code ); + + void setConditionalCode( Code * ifCode, Code * elseCode ); + Code * ifCode(); + Code * elseCode(); + + Code * m_ifCode; + Code * m_elseCode; + + void postCompileConstruct( const QStringList &interrupts ); + + /** + * @returns whether or not the port is valid. + * @see isValidPortPin + */ + bool isValidPort( const QString & portName ) const; + /** + * @returns whether or not the port and pin is a valid combination. + * @see isValidPort + */ + bool isValidPortPin( const PortPin & portPin ) const; + bool isValidTris( const QString & trisName ) const; + bool isValidInterrupt( const QString & interruptName ) const; + + void Sgoto(const QString &label); + void Slabel(const QString &label); + void Send(); + void Ssubroutine(const QString &procName, Code * compiledProcCode); + void Sinterrupt(const QString & procName, Code * compiledProcCode); + void Scall(const QString &name); + + void Ssetlh( const PortPin & portPin, bool high); + + void add( QString val1, QString val2, LocationType val1Type, LocationType val2Type ); + void subtract( const QString & val1, const QString & val2, LocationType val1Type, LocationType val2Type ); + void mul( QString val1, QString val2, LocationType val1Type, LocationType val2Type); + void div( const QString & val1, const QString & val2, LocationType val1Type, LocationType val2Type); + + void assignNum(const QString & val); + void assignVar(const QString & val); + + void saveToReg(const QString &dest); + /** + * Move the contents of the working register to the register with the given + * name. + */ + void saveResultToVar( const QString & var ); + /** Code for "==" */ + void equal( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type ); + /** Code for "!=" */ + void notEqual( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type ); + /** Code for ">" */ + void greaterThan( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type ); + /** Code for "<" */ + void lessThan( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type ); + /** Code for ">=" */ + void greaterOrEqual( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type ); + /** Code for "<=" */ + void lessOrEqual( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type ); + + void bitwise( Expression::Operation op, const QString &val1, const QString &val2, bool val1IsNum, bool val2IsNum ); + + void Swhile( Code * whileCode, const QString &expression); + void Srepeat( Code * repeatCode, const QString &expression); + void Sif( Code * ifCode, Code * elseCode, const QString &expression); + void Sfor( Code * forCode, Code * initCode, const QString &expression, const QString &variable, const QString &step, bool stepPositive); + + void Spin( const PortPin & portPin, bool NOT); + void addCommonFunctions( DelaySubroutine delay ); + + //BEGIN "Special Functionality" functions + /** + * Delay the program execution, for the given period of length_us (unit: + * microseconds). + * @param pos the position to add the code for calling the delay subroutine. + */ + void Sdelay( unsigned length_us, Code::InstructionPosition pos = Code::Middle ); + /** + * Output the working register to the given seven segment. + * @param name The variable giving the pin configuration of the seven + * segment. + */ + void SsevenSegment( const Variable & pinMap ); + /** + * Read the value of the keypad to the working register. + * @param name The variable giving the pin configuration of the keypad. + */ + void Skeypad( const Variable & pinMap ); + //END "Special Functionality" functions + + void SincVar( const QString &var ); + void SdecVar( const QString &var ); + void SrotlVar( const QString &var ); + void SrotrVar( const QString &var ); + + void Stristate( const QString &port ); + + void Sasm(const QString &raw); + + protected: + void multiply(); + void divide(); + + /** @see Microbe::m_picType */ + Type m_type; + + Parser * m_parser; + Microbe * mb; + Code * m_pCode; + + void ifInitCode( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type ); + + /** + * The function makes sure that val1 always contains a working register + * variable, if one has been passed, this is done by swapping val1 and val2 when + * neccessary + */ + void rearrangeOpArguments( QString * val1, QString * val2, LocationType * val1Type, LocationType * val2Type); + + /** + * @param flag True means give flag bit, false means give enable bit instead + */ + int interruptNameToBit(const QString &name, bool flag); +}; + +#endif diff --git a/microbe/traverser.cpp b/microbe/traverser.cpp new file mode 100644 index 0000000..e066381 --- /dev/null +++ b/microbe/traverser.cpp @@ -0,0 +1,100 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by Daniel Clarke * + * daniel.jc@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "traverser.h" +#include "pic14.h" + +Traverser::Traverser(BTreeNode *root) +{ + m_root = root; + m_current = root; +} + +Traverser::~Traverser() +{ +} + +BTreeNode * Traverser::start() +{ + /* To find the start we will iterate, or possibly recurse + down the tree, each time turning down the node that has children, + if they both have no children we have reached the end and it shouldn't + really matter which we pick (check this algorithm) */ + + BTreeNode *n = m_root; + bool found = false; + + while(!found) + { + if( !n->hasChildren() ) found = true; + else + { + if( !n->left()->hasChildren() ) + { + if( !n->right()->hasChildren() ) found = true; + n = n->right(); + } + else n = n->left(); + } + } + //if(n->parent()) m_current = n->parent(); + //else m_current = n; + m_current = n; + return m_current; +} + +BTreeNode * Traverser::next() +{ + // a.t.m we will just take the next thing to be the parent. + if( m_current != m_root ) m_current = m_current->parent(); + return m_current; +} + +bool Traverser::onLeftBranch() +{ + return current()->parent()->left() == current(); +} + +BTreeNode * Traverser::oppositeNode() +{ + if ( onLeftBranch() ) + return current()->parent()->right(); + else + return current()->parent()->left(); +} + +void Traverser::descendLeftwardToTerminal() +{ + bool done = false; + while(!done) + { + if( !current()->hasChildren() ) return; + else + { + m_current = current()->left(); + } + } +} + +void Traverser::moveToParent() +{ + if(current()->parent()) m_current = current()->parent(); +} + diff --git a/microbe/traverser.h b/microbe/traverser.h new file mode 100644 index 0000000..7593ba7 --- /dev/null +++ b/microbe/traverser.h @@ -0,0 +1,72 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by Daniel Clarke * + * daniel.jc@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef TRAVERSER_H +#define TRAVERSER_H + +#include "btreenode.h" + +/** +Keeps persistant information needed and the algorithm for traversing the binary trees made of BTreeNodes, initialise either by passing a BTreeBase or BTreeNode to traverse a sub tree. + +Note that this is designed for traversing in the *reverse* way starting at the end of each branch +in order to calculate the expression contained in the tree. + +@author Daniel Clarke +*/ +class Traverser +{ +public: + Traverser(BTreeNode *root); + ~Traverser(); + + /** Find where to start in the tree and return it also resets all the data related to the traversal. */ + BTreeNode *start(); + + /** Finds the next node to move to and returns it. */ + BTreeNode *next(); + + /** Returns true if we are on the left branch, false otherwise. */ + bool onLeftBranch(); + + /** Returns the node on the opposite branch of the parent. */ + BTreeNode * oppositeNode(); + + BTreeNode * current() const { return m_current; } + + void setCurrent(BTreeNode *current){m_current = current;} + + /** From the current position, go down the tree taking a left turn always, + and stopping when reaching the left terminal node. + */ + void descendLeftwardToTerminal(); + + /** It might occur in the future that next() does not just move to the parent, + so use this for moving to parent + */ + void moveToParent(); + + BTreeNode *root() const {return m_root;} + +protected: + BTreeNode *m_root; + BTreeNode *m_current; +}; + +#endif diff --git a/microbe/variable.cpp b/microbe/variable.cpp new file mode 100644 index 0000000..dbc20ba --- /dev/null +++ b/microbe/variable.cpp @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by Daniel Clarke daniel.jc@gmail.com * + * Copyright (C) 2005 by David Saxton * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "pic14.h" +#include "variable.h" + +Variable::Variable( VariableType type, const QString & name ) +{ + m_type = type; + m_name = name; +} + + +Variable::Variable() +{ + m_type = invalidType; +} + + +Variable::~Variable() +{ +} + + +void Variable::setPortPinList( const PortPinList & portPinList ) +{ + m_portPinList = portPinList; +} + + +bool Variable::isReadable() const +{ + switch (m_type) + { + case charType: + case keypadType: + return true; + case sevenSegmentType: + case invalidType: + return false; + } + + return false; +} + + +bool Variable::isWritable() const +{ + switch (m_type) + { + case charType: + case sevenSegmentType: + return true; + case keypadType: + case invalidType: + return false; + } + + return false; +} + + diff --git a/microbe/variable.h b/microbe/variable.h new file mode 100644 index 0000000..f5848c1 --- /dev/null +++ b/microbe/variable.h @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by Daniel Clarke daniel.jc@gmail.com * + * Copyright (C) 2005 by David Saxton * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef VARIABLE_H +#define VARIABLE_H + +#include +#include + +class PortPin; +typedef QValueList PortPinList; + + +/** +@author Daniel Clarke +@author David Saxton +*/ +class Variable +{ + public: + enum VariableType + { + charType, // 8 bit file register + sevenSegmentType, // A pin configuration for a seven segment is represented by a write-only variable. + keypadType, // A pin configuration for a keypad has 4 rows and n columns (typically n = 3 or 4) - a read-only variable + invalidType + }; + + Variable( VariableType type, const QString & name ); + Variable(); + ~Variable(); + + VariableType type() const { return m_type; } + QString name() const { return m_name; } + + /** + * @returns whether the variable can be read from (e.g. the seven + * segment variable cannot). + */ + bool isReadable() const; + /** + * @returns whether the variable can be written to (e.g. the keypad + * variable cannot). + */ + bool isWritable() const; + /** + * @see portPinList + */ + void setPortPinList( const PortPinList & portPinList ); + /** + * Used in seven-segments and keypads, + */ + PortPinList portPinList() const { return m_portPinList; } + + protected: + VariableType m_type; + QString m_name; + PortPinList m_portPinList; +}; +typedef QValueList VariableList; + +#endif diff --git a/po/Makefile.am b/po/Makefile.am new file mode 100644 index 0000000..0fa209c --- /dev/null +++ b/po/Makefile.am @@ -0,0 +1 @@ +POFILES = AUTO diff --git a/po/fr.po b/po/fr.po new file mode 100644 index 0000000..7e3c12f --- /dev/null +++ b/po/fr.po @@ -0,0 +1,4101 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: Ktechlab 0.3\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2008-06-08 20:16+0200\n" +"PO-Revision-Date: 2008-06-08 20:16+0200\n" +"Last-Translator: Georges Khaznadar \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../src/languages/processchain.cpp:59 +msgid "Building: %1" +msgstr "Construction : %1" + +#: ../src/languages/microbe.cpp:28 ../src/languages/sdcc.cpp:27 +msgid "*** Compilation failed ***" +msgstr "*** Compilation ratée ***" + +#: ../src/languages/microbe.cpp:29 ../src/languages/sdcc.cpp:26 +msgid "*** Compilation successful ***" +msgstr "*** Compilation réussie ***" + +#: ../src/languages/microbe.cpp:32 +msgid "error_messages_en_gb" +msgstr "error_messages_en_gb" + +#: ../src/languages/microbe.cpp:77 +msgid "" +"Assembly failed. Please check you have KTechlab installed properly " +"(\"microbe\" could not be started)." +msgstr "" +"Assemblage raté. Veuillez vérifier que Ktechlab est correctement installé. " +"(\"microbe\" n'a pas pu démarrer." + +#: ../src/languages/sdcc.cpp:43 +msgid "Could not find PIC with ID \"%1\"." +msgstr "Impossible de trouver un PIC avec l'ID \"%1\"." + +#: ../src/languages/sdcc.cpp:132 +msgid "Compilation failed. Please check you have sdcc installed." +msgstr "Compilation ratée. Veuillez vérifier que sdcc est installé." + +#: ../src/languages/gplink.cpp:22 +msgid "*** Linking successful ***" +msgstr "*** Ligature réussie ***" + +#: ../src/languages/gplink.cpp:23 +msgid "*** Linking failed ***" +msgstr "*** Ligature ratée ***" + +#: ../src/languages/gplink.cpp:80 ../src/languages/gplib.cpp:49 +msgid "Linking failed. Please check you have gputils installed." +msgstr "Ligature ratée. Veuillez vérifier que gputils soit installé." + +#: ../src/languages/gpasm.cpp:26 +msgid "*** Assembly successful ***" +msgstr "*** Assemblage réussi ***" + +#: ../src/languages/gpasm.cpp:27 +msgid "*** Assembly failed ***" +msgstr "*** Assemblage raté ***" + +#: ../src/languages/gpasm.cpp:120 +msgid "Assembly failed. Please check you have gputils installed." +msgstr "Assemblage raté. Veuillez vérifier que gputils soit installé." + +#: ../src/languages/gpdasm.cpp:25 +msgid "*** Disassembly successful ***" +msgstr "*** Désassemblage réussi ***" + +#: ../src/languages/gpdasm.cpp:26 +msgid "*** Disassembly failed ***" +msgstr "Désassemblage raté ***" + +#: ../src/languages/gpdasm.cpp:49 +msgid "Disassembly failed. Please check you have gputils installed." +msgstr "Désassemblage raté. Veuillez vérifier que gputils soit installé." + +#: ../src/languages/languagemanager.cpp:54 +msgid "" +"These messages show the output of language-related functionality such as " +"compiling and assembling.

For error messages, clicking on the line " +"will automatically open up the file at the position of the error." +msgstr "" +"Ces message montrent la sortie des fonctionnalités langagières telles\n" +"que la compilation et l'assemblage

Pour des messages d'erreur, un " +"clic sur la ligne ouvrira automatiquement le fichier à la position erronée." + +#: ../src/languages/picprogrammer.cpp:66 +#: ../src/languages/picprogrammer.cpp:78 +#: ../src/languages/picprogrammer.cpp:90 +#: ../src/languages/picprogrammer.cpp:101 +#: ../src/languages/picprogrammer.cpp:112 +#: ../src/languages/picprogrammer.cpp:123 +#: ../src/languages/picprogrammer.cpp:135 +#: ../src/languages/picprogrammer.cpp:148 +#: ../src/languages/picprogrammer.cpp:159 +#: ../src/languages/picprogrammer.cpp:170 +#: ../src/languages/picprogrammer.cpp:181 +msgid "Supported programmers: %1" +msgstr "Programmateurs supportés : %1" + +#: ../src/languages/picprogrammer.cpp:67 +#: ../src/languages/picprogrammer.cpp:91 +#: ../src/languages/picprogrammer.cpp:124 +msgid "
Interface: Serial Port" +msgstr "
Interface : Port Série" + +#: ../src/languages/picprogrammer.cpp:79 +#: ../src/languages/picprogrammer.cpp:102 +#: ../src/languages/picprogrammer.cpp:149 +#: ../src/languages/picprogrammer.cpp:160 +#: ../src/languages/picprogrammer.cpp:171 +#: ../src/languages/picprogrammer.cpp:182 +msgid "
Interface: Parallel Port" +msgstr "
Interface : Port Parallèle" + +#: ../src/languages/picprogrammer.cpp:113 +msgid "
Interface: USB Port" +msgstr "
Interface : Port USB" + +#: ../src/languages/picprogrammer.cpp:136 +msgid "
Interface: Serial Port and Parallel Port" +msgstr "
Interface : Ports Parallèle et Série" + +#: ../src/languages/picprogrammer.cpp:359 +msgid "*** Programming successful ***" +msgstr "*** Programmation réussie ***" + +#: ../src/languages/picprogrammer.cpp:360 +msgid "*** Programming failed ***" +msgstr "*** Programmation ratée ***" + +#: ../src/languages/flowcode.cpp:26 ../src/ktechlab.cpp:437 +msgid "FlowCode" +msgstr "FlowCode" + +#: ../src/languages/flowcode.cpp:28 +msgid "*** Microbe generation successful ***" +msgstr "*** Génération Microbe réussie ***" + +#: ../src/languages/flowcode.cpp:29 +msgid "*** Microbe generation failed ***" +msgstr "*** Génération Microbe ratée ***" + +#: ../src/languages/flowcode.cpp:176 +msgid "Warning: Floating connection for %1" +msgstr "Avertissement : Connexion flottante pour %1" + +#: ../src/languages/flowcode.cpp:194 +msgid "" +"KTechlab was unable to find the \"Start\" part.\n" +"This must be included as the starting point for your program." +msgstr "" +"Ktechlab n'a pas pu trouver la partie \"Start\".\n" +"Il faut l'inclure comme point de départ de votre programme." + +#: ../src/languages/gplib.cpp:22 +msgid "*** Archiving successful ***" +msgstr "*** Archivage réussi ***" + +#: ../src/languages/gplib.cpp:23 +msgid "*** Archiving failed ***" +msgstr "*** Archivage raté ***" + +#: ../src/gui/oscilloscopeview.cpp:126 +msgid "Framerate" +msgstr "Nombre de trames par seconde" + +#: ../src/gui/oscilloscopeview.cpp:133 +msgid "%1 fps" +msgstr "%1 fps" + +#: ../src/gui/microsettingsdlg.cpp:35 ../src/picitem.cpp:318 rc.cpp:423 +#, no-c-format +msgid "PIC Settings" +msgstr "Réglages PIC" + +#: ../src/gui/microsettingsdlg.cpp:42 +msgid "This dialog allows editing of the initial properties of the PIC" +msgstr "Ce dialogue permet l'édition des propriétés initiales du PIC" + +#: ../src/gui/microsettingsdlg.cpp:43 +msgid "" +"Edit the initial value of the ports here. For each binary number, the order " +"from right-to-left is pins 0 through 7.

The \"Type (TRIS)\" edit " +"shows the initial input/output state of the ports; 1 represents an input, " +"and 0 an output.

The \"State (PORT)\" edit shows the initial high/" +"low state of the ports; 1 represents a high, and 0 a low." +msgstr "" +"Éditez la valeur intiale des ports ici. Pour chaque nombre bianire, l'ordre " +"de gauche à droite est de la broche 0 à la broche 7.

L'éditeur " +"\"Type (TRIS)\" montre l'état intial des entrées/sorties des ports ; 1 " +"représente une entrée, et 0 une sortie.

L'éditeur \"State PORT\" " +"montre les états initiaux hauts/bas des ports ; 1 représente une état haut, " +"0 un état bas." + +#: ../src/gui/microsettingsdlg.cpp:44 +msgid "" +"Edit the initial value of the variables here.

Note that the value of " +"the variable can only be in the range 0->255. These variables will be " +"initialized before any other code is executed." +msgstr "" +"Éditez la valeur initiale des variables ici.

Notez que la valeur " +"d'une variable ne peut être que dans l'intervalle 0 -> 255. Ces variables " +"seront intialisées avant l'exécution de tout autre code." + +#: ../src/gui/microsettingsdlg.cpp:78 +msgid "Type (TRIS register):" +msgstr "Type (TRIS register):" + +#: ../src/gui/microsettingsdlg.cpp:79 +msgid "State (PORT register):" +msgstr "State (PORT register):" + +#: ../src/gui/microsettingsdlg.cpp:243 rc.cpp:631 rc.cpp:640 +#, no-c-format +msgid "New Pin Mapping" +msgstr "Nouveau brochage" + +#: ../src/gui/microsettingsdlg.cpp:244 rc.cpp:448 +#, no-c-format +msgid "Create" +msgstr "Créer" + +#: ../src/gui/microsettingsdlg.cpp:306 +msgid "New Pin Map Name" +msgstr "Nouveau nom de brochage" + +#: ../src/gui/microsettingsdlg.cpp:306 ../src/gui/symbolviewer.cpp:97 +#: ../src/gui/settingsdlg.cpp:235 +#: ../src/electronics/components/externalconnection.cpp:41 +msgid "Name" +msgstr "Nom" + +#: ../src/gui/microsettingsdlg.cpp:414 +msgid "Invalid variable value: %1" +msgstr "Valeur de variable invalide : %1" + +#: ../src/gui/colorcombo.cpp:120 ../src/gui/colorcombo.cpp:172 +msgid "Custom..." +msgstr "Personnalisation ..." + +#: ../src/gui/contexthelp.cpp:43 +msgid "" +"Provides context-sensitive help relevant to the current editing being " +"performed." +msgstr "Fournit une aide contextuelle relative à l'action d'édition en cours." + +#: ../src/gui/contexthelp.cpp:81 ../src/gui/itemeditor.cpp:151 +msgid "

No Item Selected

" +msgstr "

Aucun item sélectionné

" + +#: ../src/gui/contexthelp.cpp:88 ../src/gui/itemeditor.cpp:108 +msgid "

Multiple Items

" +msgstr "

Items multiples

" + +#: ../src/gui/pieditor.cpp:53 ../src/variant.cpp:103 +msgid "True" +msgstr "Vrai" + +#: ../src/gui/pieditor.cpp:54 ../src/variant.cpp:103 +msgid "False" +msgstr "Faux" + +#: ../src/gui/itemeditor.cpp:43 +msgid "" +"This allows editing of advanced properties of the selected item(s). Right " +"click on the picture of the item to set the orientation." +msgstr "" +"Ceci permet l'édition des propriétés avancées des items sélectionnés. Faire " +"un clic droit sur l'image de l'item pour en fixer l'orientation." + +#: ../src/gui/itemeditor.cpp:53 +msgid "" +"Shows properties associated with the currently selected item(s)." +"

Select a property to change its value. If multiple items are selected " +"with different values then the property will appear greyed out, use Merge " +"Properties to make them the same.

Select Defaults to set all properties " +"to their default values" +msgstr "" +"Montre les propriétés associée avec la sélection courante d'item(s)." +"

Sélectionnez une propriété pour changer sa valeur. Si plusieurs items " +"avec différentes valeurs sont sélectionnés alors la propriété apparaîtra " +"grisée, utilisez Insérer Propriétés pour les obtenir à l'identique." +"

Valeurs par Défaut pour ramener toues les valeurs à leur réglage " +"d'origine." + +#: ../src/gui/itemeditor.cpp:59 +msgid "Defaults" +msgstr "Valeurs par Défaut" + +#: ../src/gui/itemeditor.cpp:64 +msgid "Merge properties" +msgstr "Insérer Propriétés" + +#: ../src/gui/itemeditor.cpp:75 +msgid "" +"Change the orientation of the selected item by selecting the appropriate " +"button" +msgstr "Changer l'orientation de l'item sélectionné grâce au bouton approprié" + +#: ../src/gui/symbolviewer.cpp:82 +msgid "Value radix:" +msgstr "Base pour les valeurs :" + +#: ../src/gui/symbolviewer.cpp:86 rc.cpp:107 +#, no-c-format +msgid "Binary" +msgstr "Binaire" + +#: ../src/gui/symbolviewer.cpp:87 rc.cpp:110 +#, no-c-format +msgid "Octal" +msgstr "Octale" + +#: ../src/gui/symbolviewer.cpp:88 rc.cpp:104 +#, no-c-format +msgid "Decimal" +msgstr "Décimale" + +#: ../src/gui/symbolviewer.cpp:89 rc.cpp:113 +#, no-c-format +msgid "Hexadecimal" +msgstr "Hexadécimale" + +#: ../src/gui/symbolviewer.cpp:98 ../src/flowparts/repeat.cpp:55 +#: ../src/flowparts/varassignment.cpp:49 +#: ../src/flowparts/varcomparison.cpp:56 ../src/flowparts/while.cpp:55 +#: rc.cpp:439 +#, no-c-format +msgid "Value" +msgstr "Valeur" + +#: ../src/gui/propertieslistview.cpp:31 +msgid "Property" +msgstr "Propriété" + +#: ../src/gui/propertieslistview.cpp:32 +msgid "Data" +msgstr "Données" + +#: ../src/gui/microselectwidget.cpp:26 +msgid "Microprocessor" +msgstr "Microprocesseur" + +#: ../src/gui/microselectwidget.cpp:35 +msgid "Family" +msgstr "Famille" + +#: ../src/gui/microselectwidget.cpp:41 +msgid "Micro" +msgstr "Micro" + +#: ../src/gui/oscilloscope.cpp:336 +msgid "Oscilloscope" +msgstr "Oscilloscope" + +#: ../src/gui/programmerdlg.cpp:25 ../src/gui/settingsdlg.cpp:59 +msgid "PIC Programmer" +msgstr "Programmateur de PIC" + +#: ../src/gui/programmerdlg.cpp:29 +msgid "Burn" +msgstr "Brûler" + +#: ../src/gui/settingsdlg.cpp:58 +msgid "General" +msgstr "Général" + +#: ../src/gui/settingsdlg.cpp:58 rc.cpp:685 +#, no-c-format +msgid "General Options" +msgstr "Options Générales" + +#: ../src/gui/settingsdlg.cpp:59 rc.cpp:655 +#, no-c-format +msgid "Programmer" +msgstr "Programmateur" + +#: ../src/gui/settingsdlg.cpp:60 +msgid "Formatter" +msgstr "Formatteur" + +#: ../src/gui/settingsdlg.cpp:60 +msgid "Assembly Formatter" +msgstr "Formatteur d'assemblage" + +#: ../src/gui/settingsdlg.cpp:61 +#: ../src/electronics/components/multiinputgate.cpp:149 +#: ../src/electronics/components/multiinputgate.cpp:221 +#: ../src/electronics/components/multiinputgate.cpp:291 +#: ../src/electronics/components/multiinputgate.cpp:362 +#: ../src/electronics/components/multiinputgate.cpp:433 +#: ../src/electronics/components/multiinputgate.cpp:489 +#: ../src/electronics/components/ecclockinput.cpp:37 +#: ../src/electronics/components/discretelogic.cpp:35 +#: ../src/electronics/components/discretelogic.cpp:98 +#: ../src/electronics/components/discretelogic.cpp:160 +#: ../src/electronics/components/discretelogic.cpp:229 rc.cpp:517 +#, no-c-format +msgid "Logic" +msgstr "Logique" + +#: ../src/gui/settingsdlg.cpp:61 +msgid "Electronic Logic Values" +msgstr "Valeurs Électroniques Logiques" + +#: ../src/gui/settingsdlg.cpp:107 +msgid "Lowest (%1 FPS)" +msgstr "Minimale (%1 FPS)" + +#: ../src/gui/settingsdlg.cpp:110 +msgid "Low (%1 FPS)" +msgstr "Basse (%1 FPS)" + +#: ../src/gui/settingsdlg.cpp:113 +msgid "Medium (%1 FPS)" +msgstr "Moyenne (%1 FPS)" + +#: ../src/gui/settingsdlg.cpp:116 +msgid "High (%1 FPS)" +msgstr "Haute (%1 FPS)" + +#: ../src/gui/settingsdlg.cpp:119 +msgid "Highest (%1 FPS)" +msgstr "Maximale (%1 FPS)" + +#: ../src/gui/settingsdlg.cpp:122 +msgid "Unknown value" +msgstr "Valeur inconnue" + +#: ../src/gui/settingsdlg.cpp:144 +msgid "%1 cannot be found.
" +msgstr "%1 introuvable." + +#: ../src/gui/settingsdlg.cpp:146 +msgid "%1 found: %2
" +msgstr "%1 trouvé(e) : %2
" + +#: ../src/gui/settingsdlg.cpp:196 +msgid "Remove programmer configuration \"%1\"?" +msgstr "Retirer la configuration de programmateur \"%1\" ?" + +#: ../src/gui/settingsdlg.cpp:196 +msgid "Remove \"%1\"" +msgstr "Retirer \"%1\"" + +#: ../src/gui/settingsdlg.cpp:196 ../src/projectmanager.cpp:1133 rc.cpp:445 +#, no-c-format +msgid "Remove" +msgstr "Retirer" + +#: ../src/gui/settingsdlg.cpp:235 +msgid "Configuration Name" +msgstr "Nom de Configuration" + +#: ../src/gui/itemselector.cpp:53 ../src/gui/itemselector.cpp:292 +msgid "Component" +msgstr "Composant" + +#: ../src/gui/itemselector.cpp:166 +msgid "Remove %1" +msgstr "Retirer %1" + +#: ../src/gui/itemselector.cpp:285 +msgid "" +"Add components to the circuit diagram by dragging them into the circuit." +"

To add more than one component of the same type, doubleclick on a " +"component, and click repeatedly in the circuit to place the component. " +"Right click to stop placement.

Some components (such as subcircuits) " +"can be removed by right clicking on the item and selecting \"Remove\"." +msgstr "" +"Ajoutez des composants au diagramme du circuit en les tirant vers le " +"circuit.

Pour ajouter plus d'un composant du même type, cliquez " +"double sur un composant, puis cliquez plusieurs fois sur le circuit pour " +"placer le composant. Cliquez droit pour arrêter le placement." +"

Certains composants (comme les sous-circuits) peuvent être retirés " +"en cliquant droit sur l'item et en sélectionnant \"Retirer\"." + +#: ../src/gui/itemselector.cpp:324 +msgid "" +"Add FlowPart to the FlowCode document by dragging them there.

To add " +"more than one FlowPart of the same type, doubleclick on a FlowPart, and " +"click repeatedly in the FlowChart to place the component. Right click to " +"stop placement." +msgstr "" +"Ajouter un FlowPart dans le FlowCode en le tirant là.

Pour ajouter " +"plus d'un FlowPart du même type, cliquez double sur un FlowPart, puis " +"cliquez plusieurs fois sur le FlowChart pour le placer. Cliquez droit pour " +"arrêter le placement." + +#: ../src/gui/itemselector.cpp:326 +msgid "Flow Part" +msgstr "Flow Part" + +#: ../src/gui/itemselector.cpp:357 +msgid "" +"Add mechanical parts to the mechanics work area by dragging them there." +msgstr "Ajoutez des parties mécaniques au plan mécanique en les tirant là." + +#: ../src/gui/projectdlgs.cpp:167 +msgid "Link libraries outside project" +msgstr "Lier les bibliothèques d'un projet externe" + +#: ../src/gui/logview.cpp:105 +msgid "Clear All" +msgstr "Tout Effacer" + +#: ../src/circuitview.cpp:31 +msgid "0 Degrees" +msgstr "0 Degrés" + +#: ../src/circuitview.cpp:34 +msgid "90 Degrees" +msgstr "90 Degrés" + +#: ../src/circuitview.cpp:36 +msgid "180 Degrees" +msgstr "180 Degrés" + +#: ../src/circuitview.cpp:38 +msgid "270 Degrees" +msgstr "270 Degrés" + +#: ../src/circuitview.cpp:41 +msgid "Create Subcircuit" +msgstr "Créer un Sous-circuit" + +#: ../src/circuitview.cpp:42 +msgid "Rotate Clockwise" +msgstr "Tourner (sens horaire)" + +#: ../src/circuitview.cpp:43 +msgid "Rotate Counter-Clockwise" +msgstr "Tourner (sens anti-horaire)" + +#: ../src/circuitview.cpp:44 +msgid "Flip" +msgstr "Retourner" + +#: ../src/circuitview.cpp:51 +msgid "" +"Construct a circuit by dragging components from the Component selector from " +"the left. Create the connections by dragging a wire from the component " +"connectors.

The simulation is running by default, but can be paused " +"and resumed from the Tools menu.

To delete a wire, select it with a " +"select box, and hit delete.

To edit the attributes of a component, " +"select it (making sure that no components of another type are also " +"selected), and edit in the toolbar. More advanced properties can be edited " +"using the item editor on the right.

Subcircuits can be created by " +"connecting the components with an External Connection, selecting the " +"desired components and clicking on \"Create Subcircuit\" in the right-click " +"menu." +msgstr "" +"Construisez un circuit en tirant des comosants depuis le Sélecteur de " +"Composants à gauche. Créez les connexions en tirant un fil entre les " +"connecteurs des composants.

La simulation est active par défaut, " +"mais peut être mise en pause et relancée à partir du menu d'Outils." +"

Pour supprimer un fil, sélectionnez-le avec un rectangle de " +"sélection, et appuyez sur la touche d'effacement.

Pour éditer les " +"attributs d'un composant, sélectionnez-le (assurez qu'aucun autre composant " +"du même type ne soit sélectionné), et éditez-le dans la barre d'Outils. On " +"peut éditer plusde propriétés avancées à l'aide de l'Éditeur d'Items à " +"droite.

On peut créer des sous-circuits en connectant les composants " +"avec un Connecteur Externe, puis en sélectionnant le comosant désiré et en " +"cliquant sur \"Créer un Sous-circuit\" dans le menu contextuel (clic droit)." + +#: ../src/circuitview.cpp:79 +msgid "Simulation Running" +msgstr "Simulation active" + +#: ../src/circuitview.cpp:79 +msgid "Simulation Paused" +msgstr "Simulation arrêtée" + +#: ../src/drawparts/dptext.cpp:32 +msgid "Canvas Text" +msgstr "Canevas Texte" + +#: ../src/drawparts/dptext.cpp:33 ../src/drawparts/solidshape.cpp:32 +#: ../src/drawparts/solidshape.cpp:150 ../src/drawparts/dpline.cpp:33 +#: ../src/drawparts/dpline.cpp:161 +msgid "Other" +msgstr "Autre" + +#: ../src/drawparts/dptext.cpp:43 ../src/drawparts/dptext.cpp:47 +#: ../src/itemview.cpp:68 +msgid "Text" +msgstr "Texte" + +#: ../src/drawparts/dptext.cpp:44 +msgid "Doubleclick the Text Item to set the text" +msgstr "Clique double l'Item Texte pour modifier le texte" + +#: ../src/drawparts/dptext.cpp:51 ../src/drawparts/solidshape.cpp:46 +msgid "Display Background" +msgstr "Afficher le fond" + +#: ../src/drawparts/dptext.cpp:56 ../src/drawparts/solidshape.cpp:51 +msgid "Background Color" +msgstr "Couleur de Fond" + +#: ../src/drawparts/dptext.cpp:61 +msgid "Frame Color" +msgstr "Couleur de la Trame" + +#: ../src/drawparts/dptext.cpp:66 +msgid "Text Color" +msgstr "Couleur du Texte" + +#: ../src/drawparts/solidshape.cpp:31 ../src/drawparts/solidshape.cpp:42 +#: ../src/itemview.cpp:72 +msgid "Rectangle" +msgstr "Rectangle" + +#: ../src/drawparts/solidshape.cpp:56 ../src/drawparts/dpline.cpp:47 +msgid "Line Color" +msgstr "Couleur de Ligne" + +#: ../src/drawparts/solidshape.cpp:60 ../src/drawparts/dpline.cpp:51 +msgid "Line Width" +msgstr "Épaisseur de Ligne" + +#: ../src/drawparts/solidshape.cpp:149 ../src/drawparts/solidshape.cpp:159 +#: ../src/itemview.cpp:71 +msgid "Ellipse" +msgstr "Ellipse" + +#: ../src/drawparts/drawpart.cpp:211 +msgid "Solid" +msgstr "Plein" + +#: ../src/drawparts/drawpart.cpp:213 ../src/drawparts/drawpart.cpp:229 +msgid "None" +msgstr "Sans" + +#: ../src/drawparts/drawpart.cpp:215 ../src/drawparts/drawpart.cpp:231 +msgid "Dash" +msgstr "Tiret" + +#: ../src/drawparts/drawpart.cpp:217 ../src/drawparts/drawpart.cpp:233 +msgid "Dot" +msgstr "Pointillé" + +#: ../src/drawparts/drawpart.cpp:219 ../src/drawparts/drawpart.cpp:235 +msgid "Dash Dot" +msgstr "Point-tiret" + +#: ../src/drawparts/drawpart.cpp:221 ../src/drawparts/drawpart.cpp:237 +msgid "Dash Dot Dot" +msgstr "Point-point-tiret" + +#: ../src/drawparts/drawpart.cpp:246 +msgid "Flat" +msgstr "Plat" + +#: ../src/drawparts/drawpart.cpp:248 ../src/drawparts/drawpart.cpp:258 +msgid "Square" +msgstr "Carré" + +#: ../src/drawparts/drawpart.cpp:250 ../src/drawparts/drawpart.cpp:260 +msgid "Round" +msgstr "Rond" + +#: ../src/drawparts/dpline.cpp:32 ../src/drawparts/dpline.cpp:43 +#: ../src/itemview.cpp:69 +msgid "Line" +msgstr "Ligne" + +#: ../src/drawparts/dpline.cpp:44 +msgid "Select the line to position the end points" +msgstr "Sélectionnez la ligne pour positionnerles extrémités" + +#: ../src/drawparts/dpline.cpp:57 +msgid "Line Style" +msgstr "Style de ligne" + +#: ../src/drawparts/dpline.cpp:62 +msgid "Cap Style" +msgstr "Cap Style" + +#: ../src/drawparts/dpline.cpp:160 ../src/drawparts/dpline.cpp:170 +#: ../src/itemview.cpp:70 +msgid "Arrow" +msgstr "Flèche" + +#: ../src/flowcodedocument.cpp:47 +msgid "" +"*.flowcode|FlowCode (*.flowcode)\n" +"*|All Files" +msgstr "" +"*.flowcode|FlowCode (*.flowcode)\n" +"*|Tous fichiers" + +#: ../src/flowcodedocument.cpp:183 +msgid "Microbe Code Output" +msgstr "Sortie de Code Microbe" + +#: ../src/flowcodedocument.cpp:205 ../src/textdocument.cpp:438 +msgid "Assembly Code Output" +msgstr "Sortie de Code Assembleur" + +#: ../src/flowcodedocument.cpp:227 ../src/textdocument.cpp:480 +msgid "Hex Code Output" +msgstr "Sortie de code Hexa" + +#: ../src/docmanager.cpp:102 +msgid "Could not open '%1'" +msgstr "Impossible d'ouvrir '%1'" + +#: ../src/docmanager.cpp:169 +msgid "Untitled (Circuit %1)" +msgstr "Sans titre (Circuit %1)" + +#: ../src/docmanager.cpp:171 +msgid "Untitled (Circuit)" +msgstr "Sans titre (Circuit)" + +#: ../src/docmanager.cpp:178 +msgid "Untitled (FlowCode %1)" +msgstr "Sans titre (FlowCode %1)" + +#: ../src/docmanager.cpp:180 +msgid "Untitled (FlowCode)" +msgstr "Sans titre (FlowCode)" + +#: ../src/docmanager.cpp:187 +msgid "Untitled (Mechanics %1)" +msgstr "Sans titre (Mécanique %1)" + +#: ../src/docmanager.cpp:189 +msgid "Untitled (Mechanics)" +msgstr "Sans titre (Mécanique)" + +#: ../src/docmanager.cpp:196 +msgid "Untitled (%1)" +msgstr "Sans titre (%1)" + +#: ../src/docmanager.cpp:198 ../src/view.cpp:208 +msgid "Untitled" +msgstr "Sans titre" + +#: ../src/docmanager.cpp:434 +msgid "Could not open Circuit file \"%1\"" +msgstr "Impossible d'ouvrir le fichier de Circuit \"%1\"" + +#: ../src/docmanager.cpp:451 +msgid "Could not open FlowCode file \"%1\"" +msgstr "Impossible d'ouvrir le fichier de Flowcode \"%1\"" + +#: ../src/docmanager.cpp:468 +msgid "Could not open Mechanics file \"%1\"" +msgstr "Impossible d'ouvrir le fichier de Mécanique \"%1\"" + +#: ../src/docmanager.cpp:489 +msgid "Could not open text file \"%1\"" +msgstr "Impossible d'ouvrir le fichier de texte \"%1\"" + +#: ../src/flowcodeview.cpp:27 ../src/textview.cpp:58 +msgid "Convert to ..." +msgstr "Convertir en ..." + +#: ../src/flowcodeview.cpp:32 ../src/textview.cpp:53 +msgid "Convert to" +msgstr "Convertir en" + +#: ../src/flowcodeview.cpp:33 ../src/textview.cpp:59 +msgid "Microbe" +msgstr "Microbe" + +#: ../src/flowcodeview.cpp:34 ../src/ktechlab.cpp:434 ../src/textview.cpp:60 +msgid "Assembly" +msgstr "Assembleur" + +#: ../src/flowcodeview.cpp:35 ../src/textview.cpp:61 +msgid "Hex" +msgstr "Hexa" + +#: ../src/flowcodeview.cpp:36 ../src/textview.cpp:62 +msgid "PIC (upload)" +msgstr "PIC (upload)" + +#: ../src/flowcodeview.cpp:54 +msgid "" +"Construct a FlowCode document by dragging FlowParts from the list on the " +"left. All FlowCharts require an initial \"Start\" part, of which there can " +"only be one.

Some FlowParts, such as Subroutines, act as a container " +"element for other FlowParts. Drag the items in or out of a container as " +"appropritate. The container that will become the parent of the part being " +"dragged is indicated by being selected.

Note that connections cannot " +"be made between FlowParts in different containers, or at different levels." +msgstr "" +"Construisez un document FlowCode en tirant des FlowParts depuis la liste à " +"gauche. Tous les FlowCharts mécessitent une partie intiale \"Start\", et " +"une seule.

Certains FlowParts, tels que les Subroutines, se " +"comportent comme des éléments conteneurs pour d'autres FlowParts. Tirez les " +"élements depuis ou ers un conteneur à votre gré. Le conteneur qui deviendra " +"parent de la part qui a été tirée est indiqué comme étant sélectionné." +"

Notez qu'il est impossible de faire des connexions entre FlowParts " +"dans des conteneurs différents, ou à des niveaux différents." + +#: ../src/itemview.cpp:47 ../src/projectmanager.cpp:1133 +msgid "Cancel" +msgstr "Échappement" + +#: ../src/itemview.cpp:47 +msgid "Cancel the current operation" +msgstr "Échapper à l'opération courante" + +#: ../src/itemview.cpp:50 +msgid "Delete" +msgstr "Supprimer" + +#: ../src/itemview.cpp:51 +msgid "Export as Image..." +msgstr "Exporter comme image ..." + +#: ../src/itemview.cpp:54 +msgid "Align Horizontally" +msgstr "Aligner horizontalement" + +#: ../src/itemview.cpp:55 +msgid "Align Vertically" +msgstr "Aligner verticalement" + +#: ../src/itemview.cpp:56 +msgid "Distribute Horizontally" +msgstr "Distribuer horizontalement" + +#: ../src/itemview.cpp:57 +msgid "Distribute Vertically" +msgstr "Distribuer verticalement" + +#: ../src/itemview.cpp:62 ../src/itemview.cpp:66 +msgid "Draw" +msgstr "Dessiner" + +#: ../src/itemview.cpp:78 +msgid "Raise Selection" +msgstr "Monter la sélection" + +#: ../src/itemview.cpp:79 +msgid "Lower Selection" +msgstr "Descendre la sélection" + +#: ../src/itemview.cpp:385 ../src/itemview.cpp:398 +msgid "Left click to add. Right click to resume normal editing" +msgstr "" +"Clic gauche pour ajouter. Clic droit pour le retour à l'édition normale" + +#: ../src/itemview.cpp:390 +msgid "Click and hold to start drawing." +msgstr "Cliquer et maintenir pour commencer à dessiner." + +#: ../src/itemview.cpp:401 +msgid "Right click to cancel the connector" +msgstr "Clic droit pour annuler le connecteur" + +#: ../src/electronics/components/multiinputgate.cpp:45 +#: ../src/electronics/components/magnitudecomparator.cpp:50 +msgid "Number Inputs" +msgstr "Nombre d'entrées" + +#: ../src/electronics/components/multiinputgate.cpp:148 +#: ../src/electronics/components/multiinputgate.cpp:158 +msgid "XNOR gate" +msgstr "Porte XNOR" + +#: ../src/electronics/components/multiinputgate.cpp:159 +msgid "Exclusive NOR gate. Output is low when exactly one input is high." +msgstr "" +"Porte NOR exclusive. La sortie est basse quand exactement une entrée est " +"haute." + +#: ../src/electronics/components/multiinputgate.cpp:220 +#: ../src/electronics/components/multiinputgate.cpp:230 +msgid "XOR gate" +msgstr "Porte XOR" + +#: ../src/electronics/components/multiinputgate.cpp:231 +msgid "Exclusive OR gate. Output is high when exactly one input is high." +msgstr "" +"Porte OR exclusive. La sortie est haute quand exactement une entrée est " +"haute." + +#: ../src/electronics/components/multiinputgate.cpp:290 +#: ../src/electronics/components/multiinputgate.cpp:300 +msgid "OR gate" +msgstr "Porte OR" + +#: ../src/electronics/components/multiinputgate.cpp:301 +msgid "" +"The output is high when at least one of the inputs is high; or low when all " +"of the inputs are off" +msgstr "" +"La sortie est haute quand au moins une des entrées est haute ; ou basse " +"quand toutes les entrées sont basses." + +#: ../src/electronics/components/multiinputgate.cpp:361 +msgid "NOR gate" +msgstr "Porte NOR" + +#: ../src/electronics/components/multiinputgate.cpp:371 +msgid "NOR Gate" +msgstr "Porte NOR" + +#: ../src/electronics/components/multiinputgate.cpp:372 +msgid "The output is high when all inputs are low." +msgstr "La sortie est haute quand toutes les entrées sont basses." + +#: ../src/electronics/components/multiinputgate.cpp:432 +msgid "NAND gate" +msgstr "Porte NAND" + +#: ../src/electronics/components/multiinputgate.cpp:442 +msgid "NAND Gate" +msgstr "Porte NAND" + +#: ../src/electronics/components/multiinputgate.cpp:443 +msgid "The output is low only when all of the inputs are high." +msgstr "La sortie est basse quand toutes les entrées sont hautes." + +#: ../src/electronics/components/multiinputgate.cpp:488 +msgid "AND gate" +msgstr "Porte AND" + +#: ../src/electronics/components/multiinputgate.cpp:498 +msgid "AND Gate" +msgstr "Porte AND" + +#: ../src/electronics/components/multiinputgate.cpp:499 +msgid "The output is high if and only if all of the inputs are high." +msgstr "" +"La sortie est haute si et seulement si toutes les entrées sont hautes." + +#: ../src/electronics/components/ram.cpp:28 +#: ../src/electronics/components/ram.cpp:39 +msgid "RAM" +msgstr "RAM" + +#: ../src/electronics/components/ram.cpp:29 +#: ../src/electronics/components/piccomponent.cpp:55 +#: ../src/electronics/components/ec555.cpp:32 +#: ../src/electronics/components/magnitudecomparator.cpp:28 +#: ../src/electronics/components/fulladder.cpp:30 +#: ../src/electronics/components/ecbcdto7segment.cpp:48 +#: ../src/electronics/components/ecopamp.cpp:30 +#: ../src/electronics/components/multiplexer.cpp:31 +#: ../src/electronics/components/flipflop.cpp:34 +#: ../src/electronics/components/flipflop.cpp:146 +#: ../src/electronics/components/flipflop.cpp:248 +#: ../src/electronics/components/demultiplexer.cpp:31 +#: ../src/electronics/components/matrixdisplaydriver.cpp:304 +#: ../src/electronics/components/addac.cpp:40 +#: ../src/electronics/components/addac.cpp:53 +#: ../src/electronics/components/binarycounter.cpp:31 +msgid "Integrated Circuits" +msgstr "Circuits Intégrés" + +#: ../src/electronics/components/ram.cpp:40 +msgid "" +"This RAM stores data as a collection of words; each of which contains " +"word size bits of data.

To read data, set the CS (chip " +"select) and the OE (output enable) pins high, and select the " +"word using the address pins A*. The word is outputted on the data-" +"out pins: DO*.

To write data, set the CS (chip select) " +"and the WE (write enable) pins high, and select the address to write " +"to with the A* pins. Write to the selected word using the data-in " +"pins: DI*.

The Address Size is the number of bits that " +"determine an address; so the total number of words stored will be " +"2^Address Size." +msgstr "" +"Cette RAM conserve les données comme une collection de mots ; chacun d'entr " +"eux contient la taille d'un mot de bits de données.

Pour lire " +"des données, mettez les broches CS (Chips Select) et OE (Output " +"Enable) à l'état haut, et sélectionnez le mot en utilisant les broches " +"d'adresses A*. Le mot apparaît sur le broches de sortie : DO*." +"

Pour écrire des données, mettez les broches CS (Chips Select) et WE (Write Enable) à l'état haut, sélectionnez l'adresse où " +"écrire avec les broches A*. Écrivez le mot choisi en utilisant les " +"broches d'entrée de données : DI*.

La Taille d'Adrresse est le nombre de bits qui forment une adresse; donc le nombre total de " +"mots enregistrés sera 2^Taille d'Adresse." + +#: ../src/electronics/components/ram.cpp:50 +msgid "Word Size" +msgstr "Taille de Mot" + +#: ../src/electronics/components/ram.cpp:56 +#: ../src/electronics/components/multiplexer.cpp:47 +#: ../src/electronics/components/demultiplexer.cpp:47 +msgid "Address Size" +msgstr "Taille d'Adresse" + +#: ../src/electronics/components/eckeypad.cpp:28 +#: ../src/electronics/components/eckeypad.cpp:44 +#: ../src/flowparts/keypad.cpp:27 ../src/flowparts/keypad.cpp:38 +msgid "Keypad" +msgstr "Clavier" + +#: ../src/electronics/components/eckeypad.cpp:29 +#: ../src/electronics/components/pushswitch.cpp:33 +#: ../src/electronics/components/pushswitch.cpp:125 +#: ../src/electronics/components/toggleswitch.cpp:32 +#: ../src/electronics/components/toggleswitch.cpp:138 +#: ../src/electronics/components/toggleswitch.cpp:234 +#: ../src/electronics/components/toggleswitch.cpp:329 +#: ../src/electronics/components/rotoswitch.cpp:36 +msgid "Switches" +msgstr "Interrupteurs" + +#: ../src/electronics/components/eckeypad.cpp:45 +msgid "" +"Provides a numeric array of Push-to-Make switches, with 4 rows and a " +"configurable number of columns." +msgstr "" +"Fabrique une grille de bouton actifs en appuyant, avec 4 lignes et un " +"nombre configurable de colonnes." + +#: ../src/electronics/components/eckeypad.cpp:48 +msgid "Use Toggles" +msgstr "Utiliser des Bascules" + +#: ../src/electronics/components/eckeypad.cpp:52 +#: ../src/electronics/components/matrixdisplay.cpp:69 +msgid "Columns" +msgstr "Colonnes" + +#: ../src/electronics/components/externalconnection.cpp:26 +#: ../src/electronics/components/externalconnection.cpp:36 +msgid "External Connection" +msgstr "Connexion Externe" + +#: ../src/electronics/components/externalconnection.cpp:27 +#: ../src/electronics/components/bussplitter.cpp:30 +#: ../src/electronics/components/serialportcomponent.cpp:37 +#: ../src/electronics/components/parallelportcomponent.cpp:37 +msgid "Connections" +msgstr "Connexions" + +#: ../src/electronics/components/externalconnection.cpp:37 +msgid "" +"Point to connect the circuit to an external entity - e.g. a mechanical " +"component or as part of a subcircuit." +msgstr "" +"Un point pour connecter le circuit à une entité externe -- p. ex. un " +"composant mécanique ou en tant que partie de sous-circuit." + +#: ../src/electronics/components/ecdiode.cpp:28 +#: ../src/electronics/components/ecdiode.cpp:38 +msgid "Diode" +msgstr "Diode" + +#: ../src/electronics/components/ecdiode.cpp:29 +#: ../src/electronics/components/eccapacitor.cpp:29 +#: ../src/electronics/components/resistordip.cpp:30 +#: ../src/electronics/components/ecbjt.cpp:37 +#: ../src/electronics/components/ecbjt.cpp:49 +#: ../src/electronics/components/inductor.cpp:28 +#: ../src/electronics/components/ecpotentiometer.cpp:31 +#: ../src/electronics/components/ecresistor.cpp:29 +msgid "Discrete" +msgstr "Discrète" + +#: ../src/electronics/components/ecdiode.cpp:39 +msgid "" +"Allows current to flow in the direction indicated by the arrow when a " +"certain voltage difference has been reached." +msgstr "" +"Autorise le passage du courant dans la direction indiquée par la flèche " +"quand une certaine différence de potentiel a été atteinte." + +#: ../src/electronics/components/ecdiode.cpp:59 +msgid "Emission Coefficient" +msgstr "Coefficient d'émission" + +#: ../src/electronics/components/ecdiode.cpp:66 +msgid "Breakdown Voltage" +msgstr "Tension d'avalanche" + +#: ../src/electronics/components/dependentsource.cpp:34 +msgid "Gain" +msgstr "Gain" + +#: ../src/electronics/components/dependentsource.cpp:131 +msgid "CCCS" +msgstr "CCCS" + +#: ../src/electronics/components/dependentsource.cpp:132 +#: ../src/electronics/components/dependentsource.cpp:182 +#: ../src/electronics/components/dependentsource.cpp:231 +#: ../src/electronics/components/dependentsource.cpp:280 +#: ../src/electronics/components/ecvoltagesignal.cpp:33 +#: ../src/electronics/components/eccurrentsignal.cpp:31 +#: ../src/electronics/components/ecground.cpp:29 +#: ../src/electronics/components/ecvoltagesource.cpp:35 +#: ../src/electronics/components/eccurrentsource.cpp:31 +#: ../src/electronics/components/ecfixedvoltage.cpp:29 +msgid "Sources" +msgstr "Sources" + +#: ../src/electronics/components/dependentsource.cpp:141 +msgid "Current Controlled Currrent Source" +msgstr "Source de courant contrôlée par courant" + +#: ../src/electronics/components/dependentsource.cpp:181 +msgid "CCVS" +msgstr "CCVS" + +#: ../src/electronics/components/dependentsource.cpp:191 +msgid "Current Controlled Voltage Source" +msgstr "Source de tension commandée par courant" + +#: ../src/electronics/components/dependentsource.cpp:230 +msgid "VCCS" +msgstr "VCCS" + +#: ../src/electronics/components/dependentsource.cpp:240 +msgid "Voltage Controlled Current Source" +msgstr "Source de courant commandée par tension" + +#: ../src/electronics/components/dependentsource.cpp:279 +msgid "VCVS" +msgstr "VCVS" + +#: ../src/electronics/components/dependentsource.cpp:289 +msgid "Voltage Controlled Voltage Source" +msgstr "Source de tension commandée par tension" + +#: ../src/electronics/components/piccomponent.cpp:38 +msgid "" +msgstr "" + +#: ../src/electronics/components/piccomponent.cpp:64 +msgid "PIC Micro" +msgstr "Micro PIC" + +#: ../src/electronics/components/piccomponent.cpp:65 +msgid "" +"The PIC component allows the simulation of a PIC program.

The " +"loadable PIC program must be one of the following formats:

  • Assembly " +"(.asm)
  • FlowCode (.flowcode)
  • Symbol file (.cod)
  • Microbe (.microbe, .basic)
  • C source (.c)
  • Doubleclick on the PIC component to open up the program source file." +"

    If the program source file is of type assembly, then the the opened " +"text file will automatically be linked to the simulation. You can control " +"the program from the text document using the debug controls." +"

    Explanation of buttons:
    • Play - Run the PIC program from the " +"point at which it was paused, or from the start otherwise.
    • Pause - " +"Pause the simulation at the current execution point.
    • Stop - Reset " +"all parts of the simulation.
    • Reload - Reread the PIC program from " +"disk and restart gpsim.
    " +msgstr "" +"Le composant PIC permet la simulation d'un programme PIC.

    Le " +"programme PIC chargeable doit être dans l'un des formats suivants :" +"
    • Assembleur (.asm)
    • FlowCode (.flowcode)
    • Fichier " +"Symbolique (.cod)
    • Microbe (.microbe, .basic)
    • Source C (.c)
    Cliquez double sur le composant PIC pour ouvrir le fichier source " +"du programme.

    Si le fichier source est de type assembleur, alors le " +"fichier texte ouvert sera automatiquement lié à la simulation. On peut " +"contrôler le programme depuis le document texte en utilisant les contrôles " +"de débogage.

    Explication des boutons :
    • Play - Lance le " +"programme PIC depuis le point où il était arrêté, ou depuis le début sinon." +"
    • Pause - Arrête la simulation au point d'exécution courant.
    • Stop - Remet à zéro toutes les parties de la simulation.
    • Reload - Lit à nouveau le programme PIC depuis le disque et relance " +"gpsim.
    " + +#: ../src/electronics/components/piccomponent.cpp:101 rc.cpp:625 +#, no-c-format +msgid "Program" +msgstr "Programme" + +#: ../src/electronics/components/piccomponent.cpp:162 +msgid "The file \"%1\" does not exist." +msgstr "Le fichier \"%1\" n'existe pas." + +#: ../src/electronics/components/piccomponent.cpp:169 +msgid "" +"\"%1\" is not a valid PIC program.\n" +"The file must exist, and the extension should be \".cod\", \".asm\", \"." +"flowcode\", \".basic\", \".microbe\" or \".c\".\n" +"\".hex\" is allowed, provided that there is a corresponding \".cod\" file." +msgstr "" +"\"%1\" n'est pas un programme PIC valide.\n" +"Le fichier doit exister, et l'extension doit être \".cod\", \".asm\", \"." +"flowcode\", \".basic\", \".microbe\" ou \".c\".\n" +"\".hex\" est autorisé, à condition qu'il existe un fichier \".cod\" " +"correspondant." + +#: ../src/electronics/components/piccomponent.cpp:256 +msgid "" +"(No\n" +"program\n" +"loaded)" +msgstr "" +"(Aucun\n" +"programme\n" +"chargé)" + +#: ../src/electronics/components/ec555.cpp:31 +#: ../src/electronics/components/ec555.cpp:42 +msgid "555" +msgstr "555" + +#: ../src/electronics/components/ec555.cpp:43 +msgid "Common timer IC" +msgstr "CI timer ordinaire" + +#: ../src/electronics/components/pushswitch.cpp:32 +msgid "Push-to-Break" +msgstr "Appuyer-pour-ouvrir" + +#: ../src/electronics/components/pushswitch.cpp:42 +msgid "Push to Break" +msgstr "Appuyer pour ouvrir" + +#: ../src/electronics/components/pushswitch.cpp:48 +#: ../src/electronics/components/pushswitch.cpp:140 +#: ../src/electronics/components/toggleswitch.cpp:49 +#: ../src/electronics/components/toggleswitch.cpp:154 +#: ../src/electronics/components/toggleswitch.cpp:251 +#: ../src/electronics/components/toggleswitch.cpp:348 +msgid "Button Text" +msgstr "Texte du bouton" + +#: ../src/electronics/components/pushswitch.cpp:51 +msgid "Bounce" +msgstr "Rebond" + +#: ../src/electronics/components/pushswitch.cpp:56 +msgid "Bounce Period" +msgstr "Période du rebond" + +#: ../src/electronics/components/pushswitch.cpp:124 +msgid "Push-to-Make" +msgstr "Appuyer-pour-fermer" + +#: ../src/electronics/components/pushswitch.cpp:134 +msgid "Push to Make" +msgstr "Appuyer pour fermer" + +#: ../src/electronics/components/bussplitter.cpp:29 +msgid "Bus" +msgstr "Bus" + +#: ../src/electronics/components/bussplitter.cpp:43 +msgid "Bus Splitter" +msgstr "Séparateur de Bus" + +#: ../src/electronics/components/bussplitter.cpp:44 +msgid "Merges several connections into one." +msgstr "Associe plusieurs connexions dans une." + +#: ../src/electronics/components/bussplitter.cpp:51 +msgid "Size" +msgstr "Taille" + +#: ../src/electronics/components/ecsignallamp.cpp:30 +#: ../src/electronics/components/ecsignallamp.cpp:40 +msgid "Signal Lamp" +msgstr "Lampe Signal" + +#: ../src/electronics/components/ecsignallamp.cpp:31 +#: ../src/electronics/components/matrixdisplay.cpp:35 +#: ../src/electronics/components/probe.cpp:138 +#: ../src/electronics/components/probe.cpp:181 +#: ../src/electronics/components/probe.cpp:228 +#: ../src/electronics/components/meter.cpp:156 +#: ../src/electronics/components/meter.cpp:196 +#: ../src/electronics/components/meter.cpp:239 +#: ../src/electronics/components/ecled.cpp:31 +#: ../src/electronics/components/bidirled.cpp:32 +#: ../src/electronics/components/ecsevensegment.cpp:33 +msgid "Outputs" +msgstr "Sorties" + +#: ../src/electronics/components/ecsignallamp.cpp:41 +msgid "A simple filament signal lamp, with a 100 ohms series resistance." +msgstr "" +"Une lampe simple à incandescence, avec une résistance série de 100 ohm." + +#: ../src/electronics/components/toggleswitch.cpp:31 +msgid "DPDT" +msgstr "DPDT" + +#: ../src/electronics/components/toggleswitch.cpp:42 +msgid "DPDT Toggle" +msgstr "DPDT Bascule" + +#: ../src/electronics/components/toggleswitch.cpp:43 +msgid "Double-Pole Double-Throw switch." +msgstr "Interrupteur Bipolaire Va-et-vient" + +#: ../src/electronics/components/toggleswitch.cpp:137 +msgid "DPST" +msgstr "DPST" + +#: ../src/electronics/components/toggleswitch.cpp:147 +msgid "DPST Toggle" +msgstr "DPST Bascule" + +#: ../src/electronics/components/toggleswitch.cpp:148 +msgid "Double-Pole Single-Throw switch." +msgstr "Interrupteur Bipolaire Simple" + +#: ../src/electronics/components/toggleswitch.cpp:233 +msgid "SPDT" +msgstr "SPDT" + +#: ../src/electronics/components/toggleswitch.cpp:244 +msgid "SPDT Toggle" +msgstr "SPDT Bascule" + +#: ../src/electronics/components/toggleswitch.cpp:245 +msgid "Single-Pole Double-Throw switch." +msgstr "Interrupteur Unipolaire Va-et-Vient" + +#: ../src/electronics/components/toggleswitch.cpp:328 +msgid "SPST" +msgstr "SPST" + +#: ../src/electronics/components/toggleswitch.cpp:340 +msgid "SPST Toggle" +msgstr "SPST Bascule" + +#: ../src/electronics/components/toggleswitch.cpp:341 +msgid "Single-Pole Single-Throw switch." +msgstr "Interrupteur Unipolaire Simple" + +#: ../src/electronics/components/ecvoltagesignal.cpp:32 +#: ../src/electronics/components/ecvoltagesignal.cpp:42 +msgid "Voltage Signal" +msgstr "Signal en tension" + +#: ../src/electronics/components/ecvoltagesignal.cpp:43 +msgid "Provides a variety of voltage signals." +msgstr "Fournit un choix de signaux en tension" + +#: ../src/electronics/components/ecvoltagesignal.cpp:54 +#: ../src/electronics/components/eccurrentsignal.cpp:52 +msgid "Frequency" +msgstr "Fréquence" + +#: ../src/electronics/components/ecvoltagesignal.cpp:61 +msgid "Voltage Range" +msgstr "Intervalle de tension" + +#: ../src/electronics/components/eccurrentsignal.cpp:30 +#: ../src/electronics/components/eccurrentsignal.cpp:40 +msgid "Current Signal" +msgstr "Signal en courant" + +#: ../src/electronics/components/eccurrentsignal.cpp:41 +msgid "Provides a variety of current signals" +msgstr "Fournit un choix de signaux en courant" + +#: ../src/electronics/components/eccurrentsignal.cpp:59 +msgid "Current Range" +msgstr "Intervalle de courant" + +#: ../src/electronics/components/magnitudecomparator.cpp:27 +#: ../src/electronics/components/magnitudecomparator.cpp:38 +msgid "Magnitude Comparator" +msgstr "Comparateur Binaire" + +#: ../src/electronics/components/magnitudecomparator.cpp:40 +msgid "" +"Compares two binary numbers and generates output to indicate which binary " +"number has the greater magnitude. It has 3 cascading inputs:
    • I: A " +"> B
    • I: A < B
    • I: A = B
    and 3 outputs:" +"
    • O: A > B
    • O: A < B
    • O: A = B
    " +msgstr "" +"Compare deux nombres bianires et génère une sortie indiquant lequel est le " +"plus grand. Il a trois entrées en cascade :
    • I: A > B
    • I: A " +"< B
    • I: A = B
    et trois sorties :
    • O: A > B
    • O: A < B
    • O: A = B
    " + +#: ../src/electronics/components/ecground.cpp:28 +msgid "Ground (0V)" +msgstr "Masse (0V)" + +#: ../src/electronics/components/ecground.cpp:38 +msgid "Ground" +msgstr "Masse" + +#: ../src/electronics/components/ecground.cpp:39 +msgid "Ground (0V) point" +msgstr "Point de masse (0V)" + +#: ../src/electronics/components/ecclockinput.cpp:36 +#: ../src/electronics/components/ecclockinput.cpp:46 +msgid "Clock Input" +msgstr "Horloge" + +#: ../src/electronics/components/ecclockinput.cpp:47 +msgid "" +"A square-wave generator, outputing logical high/low at repeating time " +"intervals." +msgstr "" +"Un générateur de signal carré, qui sort un signal logique haut/bas à " +"intervalle de temps régulier." + +#: ../src/electronics/components/ecclockinput.cpp:69 +msgid "Low Time" +msgstr "Durée \"bas\"" + +#: ../src/electronics/components/ecclockinput.cpp:75 +#: ../src/flowparts/pulse.cpp:49 ../src/flowparts/pulse.cpp:54 +msgid "High Time" +msgstr "Durée \"haut\"" + +#: ../src/electronics/components/discretelogic.cpp:34 +#: ../src/electronics/components/discretelogic.cpp:44 +msgid "Inverter" +msgstr "Inverseur" + +#: ../src/electronics/components/discretelogic.cpp:45 +msgid "The output is the logical inverse of the logic-input state." +msgstr "La sortie est l'inverse logique de l'entrée." + +#: ../src/electronics/components/discretelogic.cpp:97 +#: ../src/electronics/components/discretelogic.cpp:107 +msgid "Buffer" +msgstr "Tampon" + +#: ../src/electronics/components/discretelogic.cpp:108 +msgid "" +"Cleans the logic input, with the output high or low depending on input " +"trigger levels." +msgstr "" +"Nettoie le signal d'entrée, les états haut et bas de la sortie dépendant du " +"niveau d'entrée par un hystérésis." + +#: ../src/electronics/components/discretelogic.cpp:159 +#: ../src/electronics/components/discretelogic.cpp:169 +msgid "Logic Input" +msgstr "Entrée Logique" + +#: ../src/electronics/components/discretelogic.cpp:170 +msgid "" +"Provides a user-adjustable logic state.

    Click to pulse high, or drag " +"the mouse off to keep the output high." +msgstr "" +"Fournit un état logique justable par l'utilisateur.

    Cliquer pour une " +"impulsion haute, ou tirer la souris pour garder la sortie haute." + +#: ../src/electronics/components/discretelogic.cpp:178 +msgid "Use Toggle" +msgstr "Utiliser une Bascule" + +#: ../src/electronics/components/discretelogic.cpp:228 +#: ../src/electronics/components/discretelogic.cpp:238 +msgid "Logic Output" +msgstr "Sortie Logique" + +#: ../src/electronics/components/discretelogic.cpp:239 +msgid "Shows the logic-state of the input." +msgstr "Montre l'état logique de la sortie." + +#: ../src/electronics/components/fulladder.cpp:29 +#: ../src/electronics/components/fulladder.cpp:40 +msgid "Adder" +msgstr "Additionneur" + +#: ../src/electronics/components/ecsubcircuit.cpp:41 +msgid "Subcircuit" +msgstr "Sous-cirduit" + +#: ../src/electronics/components/matrixdisplay.cpp:34 +#: ../src/electronics/components/matrixdisplay.cpp:45 +msgid "Matrix Display" +msgstr "Afficheur matriciel" + +#: ../src/electronics/components/matrixdisplay.cpp:46 +msgid "" +"A matrix display of LEDs with a configurable number of columns and rows." +msgstr "" +"Un afficheur matriciel à DELs avec un nombre de lignes et de colonnes " +"configurable." + +#: ../src/electronics/components/matrixdisplay.cpp:63 +msgid "Rows" +msgstr "Lignes" + +#: ../src/electronics/components/matrixdisplay.cpp:75 +#: ../src/electronics/components/probe.cpp:32 +#: ../src/electronics/components/ecled.cpp:51 +#: ../src/electronics/components/ecsevensegment.cpp:49 +msgid "Color" +msgstr "Couleur" + +#: ../src/electronics/components/matrixdisplay.cpp:79 +#: ../src/electronics/components/matrixdisplaydriver.cpp:321 +#: ../src/electronics/components/ecsevensegment.cpp:53 +msgid "Configuration" +msgstr "Configuration" + +#: ../src/electronics/components/eccapacitor.cpp:28 +#: ../src/electronics/components/eccapacitor.cpp:39 +msgid "Capacitor" +msgstr "Condenstaeur" + +#: ../src/electronics/components/eccapacitor.cpp:40 +msgid "" +"Stores electrical charge.

    The voltage across the capacitor and " +"capacitance are related by Charge = Capacitance x Voltage." +msgstr "" +"Stocke une charge électrique.

    La tension aux bornes du condensateur " +"et la capacité sont reliés par Charge = Capacité x Tension." + +#: ../src/electronics/components/eccapacitor.cpp:50 +msgid "Capacitance" +msgstr "Capacité" + +#: ../src/electronics/components/resistordip.cpp:29 +#: ../src/electronics/components/resistordip.cpp:40 +msgid "Resistor DIP" +msgstr "Résistances DIP" + +#: ../src/electronics/components/resistordip.cpp:41 +msgid "Set of resistors with identical values in a Dual Inline Package." +msgstr "" +"Ensemble de résistances avec des valeurs identiques dans un Paquet Dual " +"Inline." + +#: ../src/electronics/components/resistordip.cpp:48 +#: ../src/electronics/components/ecpotentiometer.cpp:55 +#: ../src/electronics/components/ecresistor.cpp:47 +msgid "Resistance" +msgstr "Résistance" + +#: ../src/electronics/components/resistordip.cpp:54 +#: ../src/flowparts/count.cpp:27 ../src/flowparts/count.cpp:37 +msgid "Count" +msgstr "Nombre" + +#: ../src/electronics/components/ecbcdto7segment.cpp:47 +msgid "BCD to 7 Segment" +msgstr "BCD vers 7 Segments" + +#: ../src/electronics/components/ecbcdto7segment.cpp:58 +msgid "BCD to Seven Segment" +msgstr "BCD vers Sept Segments" + +#: ../src/electronics/components/ecbcdto7segment.cpp:59 +msgid "" +"Converts a binary-coded-input to a form displayable by a seven segment " +"display.

    Normal operation: lt (Lamp Test) and the rb " +"(Ripple Blanking) are held high, en (Enable) is held low." +msgstr "" +"Convertit une entrée codée en binaire en une forme lisible sur un afficheur " +"sept segments.

    Mode normal : lt (Lamp Test) et le rb " +"(Ripple Blanking) sont à l'état haut, en (Enable) est à l'état bas." + +#: ../src/electronics/components/serialportcomponent.cpp:36 +#: ../src/electronics/components/serialportcomponent.cpp:47 +msgid "Serial Port" +msgstr "Port Série" + +#: ../src/electronics/components/serialportcomponent.cpp:48 +msgid "" +"Interface to a serial port. The pins are:
    • CD - Carrier " +"Detect (control; output)
    • RD - Received Data (data; output)
    • TD - Transmitted Data (data; input)
    • DTR - Data " +"Terminal Ready (control; input)
    • GND - Signal Ground (ground)" +"
    • DSR - Data Set Ready (control; input)
    • RTS - " +"Request to Send (control; input)
    • CTS - Clear to Send " +"(control; output)
    • RI - Ring Indicator (control; output)
    " +msgstr "" +"Interface à un port série. Les broches sont :
    • CD - " +"Carrier Detect (contrôle; sortie)
    • RD - Received Data " +"(donnée; sortie)
    • TD - Transmitted Data (donnée; entrée)
    • DTR - Data Terminal Ready (contrôle; entrée)
    • GND - Signal Ground (ground)
    • DSR - Data Set Ready (contrôle; " +"entrée)
    • RTS - Request to Send (contrôle; entrée)
    • CTS - Clear to Send (contrôle; sortie)
    • RI - " +"Ring Indicator (contrôle; sortie)
    " + +#: ../src/electronics/components/serialportcomponent.cpp:124 +#: ../src/electronics/components/parallelportcomponent.cpp:177 +#: ../src/flowparts/readport.cpp:45 ../src/flowparts/writeport.cpp:50 +#: rc.cpp:661 +#, no-c-format +msgid "Port" +msgstr "Port" + +#: ../src/electronics/components/serialportcomponent.cpp:200 +#: ../src/electronics/components/parallelportcomponent.cpp:203 +msgid "Could not open port %1" +msgstr "Impossible d'ouvrir le port %1" + +#: ../src/electronics/components/ecbjt.cpp:36 +msgid "NPN" +msgstr "NPN" + +#: ../src/electronics/components/ecbjt.cpp:48 +msgid "PNP" +msgstr "PNP" + +#: ../src/electronics/components/ecbjt.cpp:61 +msgid "NPN Transistor" +msgstr "Transistor NPN" + +#: ../src/electronics/components/ecbjt.cpp:63 +msgid "PNP Transistor" +msgstr "Transistor PNP" + +#: ../src/electronics/components/ecbjt.cpp:79 +msgid "Forward Coefficient" +msgstr "Coefficient avant" + +#: ../src/electronics/components/ecbjt.cpp:86 +msgid "Reverse Coefficient" +msgstr "Coefficient retour" + +#: ../src/electronics/components/ecbjt.cpp:93 +msgid "Forward Beta" +msgstr "Beta avant" + +#: ../src/electronics/components/ecbjt.cpp:100 +msgid "Reverse Beta" +msgstr "Beta retour" + +#: ../src/electronics/components/rotoswitch.cpp:35 +msgid "Rotary" +msgstr "Rotatif" + +#: ../src/electronics/components/rotoswitch.cpp:48 +#: ../src/electronics/components/rotoswitch.cpp:49 +msgid "Rotary Switch" +msgstr "Interrupteur rotatif" + +#: ../src/electronics/components/rotoswitch.cpp:67 +msgid "Number of Positions" +msgstr "Nombre de positions" + +#: ../src/electronics/components/inductor.cpp:27 +#: ../src/electronics/components/inductor.cpp:38 +msgid "Inductor" +msgstr "Bobinage" + +#: ../src/electronics/components/inductor.cpp:49 +msgid "Inductance" +msgstr "Inductance" + +#: ../src/electronics/components/ecpotentiometer.cpp:30 +#: ../src/electronics/components/ecpotentiometer.cpp:40 +msgid "Potentiometer" +msgstr "Potentiomètre" + +#: ../src/electronics/components/ecpotentiometer.cpp:41 +msgid "" +"Consists of a resistor connected to the end pins, with a central pin " +"connected at an adjustable point along the resistor" +msgstr "" +"Consiste en une résistance connectée aux broches terminales, avec un broche " +"centrale connectée à un point ajustable le long du corps de la résistance." + +#: ../src/electronics/components/probe.cpp:62 +msgid "Scaling" +msgstr "Échelle" + +#: ../src/electronics/components/probe.cpp:68 +msgid "Upper Absolute Value" +msgstr "Valeur absolue supérieure" + +#: ../src/electronics/components/probe.cpp:75 +msgid "Lower Absolute Value" +msgstr "Valeur absolue inférieure" + +#: ../src/electronics/components/probe.cpp:137 +#: ../src/electronics/components/probe.cpp:147 +msgid "Voltage Probe" +msgstr "Sonde de tension" + +#: ../src/electronics/components/probe.cpp:148 +msgid "Displays the voltage at the probe point on the oscilloscope." +msgstr "Affiche la tension au point de la sonde à l'oscilloscope." + +#: ../src/electronics/components/probe.cpp:180 +#: ../src/electronics/components/probe.cpp:190 +msgid "Current Probe" +msgstr "Sonde de courant" + +#: ../src/electronics/components/probe.cpp:191 +msgid "Displays the current at the probe point on the oscilloscope." +msgstr "Affiche le courant au point de la sonde à l'oscilloscope." + +#: ../src/electronics/components/probe.cpp:227 +#: ../src/electronics/components/probe.cpp:237 +msgid "Logic Probe" +msgstr "Sonde logique" + +#: ../src/electronics/components/probe.cpp:238 +msgid "" +"Connect this probe the the point in the circuit to measure the logic value. " +"The output will be displayed in the Oscilloscope view." +msgstr "" +"Connectez cette sonde à un point du circuit pour mesurer sa valeur logique. " +"La sortie sera affichée dans la vue Oscilloscope." + +#: ../src/electronics/components/ecopamp.cpp:29 +msgid "Op Amp" +msgstr "Ampli op" + +#: ../src/electronics/components/ecopamp.cpp:40 +msgid "Operational Amplifier" +msgstr "Amplificateur opérationnel" + +#: ../src/electronics/components/ecopamp.cpp:41 +msgid "Ideal amplifier" +msgstr "Amplificateur idéal" + +#: ../src/electronics/components/multiplexer.cpp:30 +#: ../src/electronics/components/multiplexer.cpp:41 +msgid "Multiplexer" +msgstr "Multiplexeur" + +#: ../src/electronics/components/multiplexer.cpp:42 +msgid "" +"Combines the input data stream into one single stream. The value of the " +"input selected by the \"A\" inputs is passed to the output." +msgstr "" +"Combine les flux de données entrants en un seul flux. La valeur de l'entrée " +"sélectionnée par les broches \"A\" est passée à la sortie." + +#: ../src/electronics/components/ecresistor.cpp:28 +#: ../src/electronics/components/ecresistor.cpp:38 +msgid "Resistor" +msgstr "Résistance" + +#: ../src/electronics/components/ecresistor.cpp:39 +msgid "Limits the flow of current, obeying Ohms Law" +msgstr "Limite la valeur du courant, en obéissant à la loi d'Ohm." + +#: ../src/electronics/components/parallelportcomponent.cpp:36 +#: ../src/electronics/components/parallelportcomponent.cpp:47 +msgid "Parallel Port" +msgstr "Port Prallèle" + +#: ../src/electronics/components/parallelportcomponent.cpp:48 +msgid "" +"The pins are divided into 3 registers.

    Data Pins

    The " +"data pins can be configured as either all input or all output. They are:" +"
    • D[0..7]

    Status Pins

    The " +"status pins are read-only. They area:
    • ERR - Error
    • ON - Online
    • PE - Paper End
    • ACK " +"- Acknowledge
    • BUSY - Busy

    Control Pins
    • STR - Strobe
    • AUT - Auto Feed
    • INIT - Init
    • SEL - Select

    The " +"remaining pins are all ground." +msgstr "" +"Les broches sont réparties en trois registres.

    Broches de " +"données

    Les broches de données peuvent être configurées comme " +"toutes en entrée ou toutes en sortie. Elles sont :
    • D[0..7]

    Broches de statut

    Les broches de statut " +"sont en lecture seule. Elles sont :
    • ERR - Erreur
    • ON - Online
    • PE - Paper End
    • ACK " +"- Acknowledge
    • BUSY - Busy

    Broches de " +"contrôle
    • STR - Strobe
    • AUT - Auto Feed
    • INIT - Init
    • SEL - Select

    Les " +"broches restantes sont toutes à la masse." + +#: ../src/electronics/components/meter.cpp:41 +msgid "Minimum Value" +msgstr "Valeur minimale" + +#: ../src/electronics/components/meter.cpp:47 +msgid "Maximum Value" +msgstr "Valeur maximale" + +#: ../src/electronics/components/meter.cpp:155 +msgid "Frequency Meter (TODO)" +msgstr "Fréquencemètre (À FAIRE)" + +#: ../src/electronics/components/meter.cpp:165 +msgid "Frequency Meter" +msgstr "Fréquencemètre" + +#: ../src/electronics/components/meter.cpp:166 +msgid "Place this at the point where frequency is to be measured." +msgstr "Placez-le là où il faut mesurer une fréquence." + +#: ../src/electronics/components/meter.cpp:195 +#: ../src/electronics/components/meter.cpp:206 +msgid "Ammeter" +msgstr "Ampèremètre" + +#: ../src/electronics/components/meter.cpp:207 +msgid "Place this in series in the circuit to measure the current flowing." +msgstr "Placez-le dans le circuit pour mesurer le courant qui passe." + +#: ../src/electronics/components/meter.cpp:238 +#: ../src/electronics/components/meter.cpp:248 +msgid "Voltmeter" +msgstr "Voltmètre" + +#: ../src/electronics/components/meter.cpp:249 +msgid "" +"Place this in parallel in the circuit to meaure the voltage between two " +"points." +msgstr "Placez-le dans le circuit pour mesurer la tension entre deux points." + +#: ../src/electronics/components/ecvoltagesource.cpp:34 +#: ../src/electronics/components/ecvoltagesource.cpp:44 +msgid "Battery" +msgstr "Pile" + +#: ../src/electronics/components/ecvoltagesource.cpp:45 +msgid "Provides a potential-difference." +msgstr "Fournit une différence de potentiel." + +#: ../src/electronics/components/ecvoltagesource.cpp:57 +#: ../src/electronics/components/ecfixedvoltage.cpp:49 +msgid "Voltage" +msgstr "Tension" + +#: ../src/electronics/components/eccurrentsource.cpp:30 +#: ../src/electronics/components/eccurrentsource.cpp:40 +msgid "Current Source" +msgstr "Source de courant" + +#: ../src/electronics/components/eccurrentsource.cpp:41 +msgid "Provides a fixed current source." +msgstr "Fournit une source de courant constant." + +#: ../src/electronics/components/eccurrentsource.cpp:51 +msgid "Current" +msgstr "Courant" + +#: ../src/electronics/components/flipflop.cpp:33 +msgid "D Flip-Flop" +msgstr "Bascule D" + +#: ../src/electronics/components/flipflop.cpp:43 +msgid "D-Type Flip-Flop" +msgstr "Bascule de type D" + +#: ../src/electronics/components/flipflop.cpp:44 +msgid "The output state is set from the input state when the clock is pulsed." +msgstr "" +"L'état de la sortie est copié sur l'état de l'entré quand une impulsion " +"d'horloge arrive." + +#: ../src/electronics/components/flipflop.cpp:145 +msgid "JK Flip-Flop" +msgstr "Bascule JK" + +#: ../src/electronics/components/flipflop.cpp:155 +msgid "JK-Type Flip-Flop" +msgstr "Bascule de type Maître-Esclave" + +#: ../src/electronics/components/flipflop.cpp:156 +msgid "The output state is set according to J and K when the clock is pulsed." +msgstr "" +"L'état de sortie est fixé selon les états de J et K au moent de l'impulsion " +"d'horloge." + +#: ../src/electronics/components/flipflop.cpp:247 +#: ../src/electronics/components/flipflop.cpp:257 +msgid "SR Flip-Flop" +msgstr "Bascule SR" + +#: ../src/electronics/components/flipflop.cpp:258 +msgid "" +"The output is made high by holding set high, and low by holding " +"reset high." +msgstr "" +"La sortie devient haute quand set est mis à l'état haut, et basse " +"quand reset est mis à l'état haut." + +#: ../src/electronics/components/demultiplexer.cpp:30 +#: ../src/electronics/components/demultiplexer.cpp:41 +msgid "Demultiplexer" +msgstr "Démultiplexeur" + +#: ../src/electronics/components/demultiplexer.cpp:42 +msgid "" +"Seperates the input data stream into components. The value of the input is " +"passed to the \"X\" output selected by the binary number given by the \"A\" " +"inputs." +msgstr "" +"Partage le flux de données d'entré entre plusieurs composants. La valeur de " +"l'entrée est copiée vers la sortie \"X\" sélectionnée par le nombre binaire " +"donnée par les entrées \"A\"." + +#: ../src/electronics/components/ecled.cpp:30 +#: ../src/electronics/components/ecled.cpp:42 +msgid "LED" +msgstr "DEL" + +#: ../src/electronics/components/ecled.cpp:43 +msgid "Light Emitting Diode" +msgstr "Diode Émettrice de Lumière" + +#: ../src/electronics/components/ecfixedvoltage.cpp:28 +#: ../src/electronics/components/ecfixedvoltage.cpp:38 +msgid "Fixed Voltage" +msgstr "Tension fixe" + +#: ../src/electronics/components/ecfixedvoltage.cpp:39 +msgid "Provides a fixed voltage point to connect components to." +msgstr "Fournit une source de tension fixe où connecter des composants." + +#: ../src/electronics/components/matrixdisplaydriver.cpp:303 +#: ../src/electronics/components/matrixdisplaydriver.cpp:314 +msgid "Matrix Display Driver" +msgstr "Pilote d'afficheur matriciel" + +#: ../src/electronics/components/bidirled.cpp:31 +#: ../src/electronics/components/bidirled.cpp:42 +msgid "Bidirectional LED" +msgstr "DEL bidirectionnelle" + +#: ../src/electronics/components/bidirled.cpp:43 +msgid "Bidrectional Light Emitting Diode" +msgstr "Diode Émettrice de Lumière bidirectionnelle." + +#: ../src/electronics/components/bidirled.cpp:60 +msgid "Color 1" +msgstr "Couleur 1" + +#: ../src/electronics/components/bidirled.cpp:64 +msgid "Colour 2" +msgstr "Couleur 2" + +#: ../src/electronics/components/ecsevensegment.cpp:32 +#: ../src/flowparts/sevenseg.cpp:28 rc.cpp:646 +#, no-c-format +msgid "Seven Segment" +msgstr "Sept Segments" + +#: ../src/electronics/components/ecsevensegment.cpp:42 +msgid "Seven Segment LED" +msgstr "DEL Sept Segments" + +#: ../src/electronics/components/ecsevensegment.cpp:43 +msgid "" +"A seven segment display with a decimal point. This can be configured to " +"either have a common cathode or a common anode." +msgstr "" +"Un afficheur à sept segments avec un point décimal. On peut le configurer " +"pour avoir soit une cathode commune soit une anode commune." + +#: ../src/electronics/components/addac.cpp:39 +msgid "Analog-Digital" +msgstr "Analogique-Numérique" + +#: ../src/electronics/components/addac.cpp:52 +msgid "Digital-Analog" +msgstr "Numérique-Analogique" + +#: ../src/electronics/components/addac.cpp:69 +msgid "Number Bits" +msgstr "Nombre de bits" + +#: ../src/electronics/components/addac.cpp:75 +msgid "Input Range" +msgstr "Intervalle d'entrée" + +#: ../src/electronics/components/addac.cpp:102 +msgid "ADC" +msgstr "CAN" + +#: ../src/electronics/components/addac.cpp:103 +msgid "Converts an analog signal into a digital output." +msgstr "Convertit un signal analogique en une sortie numérique." + +#: ../src/electronics/components/addac.cpp:198 +msgid "DAC" +msgstr "CNA" + +#: ../src/electronics/components/addac.cpp:199 +msgid "Converts a digital input to an analog output signal." +msgstr "Convertit une entrée numérique en un signal de sortie analogique." + +#: ../src/electronics/components/binarycounter.cpp:30 +#: ../src/electronics/components/binarycounter.cpp:41 +msgid "Binary Counter" +msgstr "Compteur binaire" + +#: ../src/electronics/components/binarycounter.cpp:42 +msgid "" +"Holds an internal count, which changes when the clock input > pin " +"is pulsed.

    Normal operation: en (Enable) and u/d (Up/" +"Down) are held high, r (Reset) is low." +msgstr "" +"Maintient un comptage interne, qui change quand >la broche " +"d'entrée Horloge reçoit une impusion.

    Mode normal : en " +"(Enable) et u/d (Up/Down) sont à l'état haut, r (Reset) est à " +"l'état bas." + +#: ../src/electronics/components/binarycounter.cpp:58 +msgid "Trigger Edge" +msgstr "Déclenchement" + +#: ../src/electronics/components/binarycounter.cpp:63 +msgid "Bit Count" +msgstr "Nombre de bits" + +#: ../src/electronics/gpsimprocessor.cpp:164 +msgid "The cod file \"%1\" was not found." +msgstr "Le fichier cod \"%1\" n'a pas été trouvé." + +#: ../src/electronics/gpsimprocessor.cpp:164 +msgid "File Not Found" +msgstr "Fichier Non Trouvé" + +#: ../src/electronics/gpsimprocessor.cpp:167 +msgid "The processor for cod file \"%1\" is unrecognized." +msgstr "Le processeur pour le fichier cod \"%1\" n'est pas reconnu." + +#: ../src/electronics/gpsimprocessor.cpp:167 +msgid "Unrecognized Processor" +msgstr "Processeur non reconnu" + +#: ../src/electronics/gpsimprocessor.cpp:170 +msgid "The file name \"%1\" is too long." +msgstr "Le nom de fichier \"%1\" est trop long." + +#: ../src/electronics/gpsimprocessor.cpp:170 +msgid "Filename Too Long" +msgstr "Nom de fichier trop long" + +#: ../src/electronics/gpsimprocessor.cpp:173 +msgid "The lst file associated with the cod file \"%1\" was not found." +msgstr "Le 1er fichier assocué avec le fichier cod \"%1\" n'a pas été trouvé." + +#: ../src/electronics/gpsimprocessor.cpp:173 +msgid "LST File Not Found" +msgstr "Fichier LST pas trouvé" + +#: ../src/electronics/gpsimprocessor.cpp:176 +msgid "The cod file \"%1\" is bad." +msgstr "Le fichier cod \"%1\" est mauvais." + +#: ../src/electronics/gpsimprocessor.cpp:176 +msgid "Bad File" +msgstr "Mauvais fichier" + +#: ../src/electronics/gpsimprocessor.cpp:179 +msgid "The cod file \"%1\" could not be read from." +msgstr "Impossible de lire depuis le fichier cod \"%1\"." + +#: ../src/electronics/gpsimprocessor.cpp:179 +msgid "Unreadable File" +msgstr "Fichier non lisible" + +#: ../src/electronics/gpsimprocessor.cpp:183 +msgid "An error occured with the cod file \"%1\"." +msgstr "Une erreur s'est produite avec le fichier cod \"%1\"." + +#: ../src/electronics/gpsimprocessor.cpp:183 +msgid "Error" +msgstr "Erreur" + +#: ../src/electronics/gpsimprocessor.cpp:839 +msgid "Generic" +msgstr "Générique" + +#: ../src/electronics/gpsimprocessor.cpp:842 ../src/projectmanager.cpp:911 +msgid "File" +msgstr "Fichier" + +#: ../src/electronics/gpsimprocessor.cpp:845 +msgid "SFR" +msgstr "SFR" + +#: ../src/electronics/gpsimprocessor.cpp:848 ../src/textdocument.cpp:82 +msgid "Breakpoint" +msgstr "Point d'arrêt" + +#: ../src/electronics/gpsimprocessor.cpp:851 +msgid "Invalid" +msgstr "Invalide" + +#: ../src/electronics/gpsimprocessor.cpp:854 +msgid "Unknown" +msgstr "Inconnu" + +#: ../src/document.cpp:105 +msgid "Save Location" +msgstr "Emplacement de sauvegarde" + +#: ../src/document.cpp:113 ../src/itemdocument.cpp:823 +msgid "" +"A file named \"%1\" already exists. Are you sure you want to overwrite it?" +msgstr "" +"Un fichier de nom \"%1\" existe déjà. Êtes-vous sûr de vouloir l'écraser ?" + +#: ../src/document.cpp:114 ../src/itemdocument.cpp:823 +msgid "Overwrite File?" +msgstr "Écraser le fichier ?" + +#: ../src/document.cpp:115 ../src/itemdocument.cpp:823 +msgid "Overwrite" +msgstr "Écraser" + +#: ../src/document.cpp:138 +msgid "" +"The document '%1' has been modified.\n" +"Do you want to save it?" +msgstr "" +"Le document '%1' a été modifié.\n" +"Voulez-vous l'enregistrer ?" + +#: ../src/document.cpp:139 +msgid "Save Document?" +msgstr "Enregistrer le document ?" + +#: ../src/document.cpp:140 ../src/ktechlab.cpp:823 +msgid "Save" +msgstr "Enregistrer" + +#: ../src/document.cpp:141 +msgid "Discard" +msgstr "Jeter" + +#: ../src/mechanics/mechanicsdocument.cpp:28 +msgid "" +"*.mechanics|Mechanics (*.mechanics)\n" +"*|All Files" +msgstr "" +"*.mechanics|Mechanics (*.mechanics)\n" +"*|Tous fichiers" + +#: ../src/mechanics/chassiscircular2.cpp:35 +#: ../src/mechanics/chassiscircular2.cpp:46 +msgid "Circular 2-Wheel Chassis" +msgstr "Chassis circulaire 2-roues" + +#: ../src/mechanics/chassiscircular2.cpp:36 +msgid "Chassis'" +msgstr "Chassis" + +#: ../src/mechanics/chassiscircular2.cpp:47 +msgid "A circular base with two wheels and a support point." +msgstr "Une base circulaire avec deux roues et un point de support" + +#: ../src/mechanics/mechanicsitem.cpp:40 +msgid "Mass" +msgstr "Masse" + +#: ../src/mechanics/mechanicsitem.cpp:48 +msgid "Moment of Inertia" +msgstr "Moment d'inertie" + +#: ../src/katemdi.cpp:401 +msgid "Behavior" +msgstr "Comportement" + +#: ../src/katemdi.cpp:403 +msgid "Make Non-Persistent" +msgstr "Rendre non-persistant" + +#: ../src/katemdi.cpp:403 +msgid "Make Persistent" +msgstr "Rendre persistant" + +#: ../src/katemdi.cpp:405 +msgid "Move To" +msgstr "Aller à" + +#: ../src/katemdi.cpp:408 +msgid "Left Sidebar" +msgstr "Barre latérale gauche" + +#: ../src/katemdi.cpp:411 +msgid "Right Sidebar" +msgstr "Barre latérale droite" + +#: ../src/katemdi.cpp:414 +msgid "Top Sidebar" +msgstr "Barre latérale supérieure" + +#: ../src/katemdi.cpp:417 +msgid "Bottom Sidebar" +msgstr "Barre latérale inférieure" + +#: ../src/flowparts/testpin.cpp:27 ../src/flowparts/testpin.cpp:37 +msgid "Test Pin State" +msgstr "Tester l'état de la broche" + +#: ../src/flowparts/testpin.cpp:28 ../src/flowparts/readport.cpp:28 +#: ../src/flowparts/writeport.cpp:28 ../src/flowparts/setpin.cpp:31 +msgid "I\\/O" +msgstr "E\\/S" + +#: ../src/flowparts/testpin.cpp:38 +msgid "Conditional branch point, depending on the high/low state of a pin." +msgstr "" +"Point de branchement conditionnel, dépendant de l'état haut/bas d'une " +"broche." + +#: ../src/flowparts/testpin.cpp:45 ../src/flowparts/pulse.cpp:59 +#: ../src/flowparts/inputbutton.cpp:51 ../src/flowparts/setpin.cpp:52 +msgid "Pin" +msgstr "Broche" + +#: ../src/flowparts/readport.cpp:27 ../src/flowparts/readport.cpp:37 +msgid "Read from Port" +msgstr "Lire depuis le Port" + +#: ../src/flowparts/readport.cpp:38 +msgid "Assign the value of a port to a variable." +msgstr "Donner la valeur d'un port à une variable." + +#: ../src/flowparts/readport.cpp:44 +msgid "Read" +msgstr "Lire" + +#: ../src/flowparts/readport.cpp:50 ../src/flowparts/sevenseg.cpp:48 +#: ../src/flowparts/unary.cpp:45 ../src/flowparts/writeport.cpp:45 +#: ../src/flowparts/repeat.cpp:44 ../src/flowparts/keypad.cpp:46 +#: ../src/flowparts/varassignment.cpp:44 ../src/flowparts/forloop.cpp:45 +#: ../src/flowparts/varcomparison.cpp:45 ../src/flowparts/while.cpp:44 +#: rc.cpp:436 +#, no-c-format +msgid "Variable" +msgstr "Variable" + +#: ../src/flowparts/readport.cpp:61 ../src/flowparts/keypad.cpp:58 +msgid "Read %1 to %2" +msgstr "Lire %1 vers %2" + +#: ../src/flowparts/sevenseg.cpp:40 +msgid "SevenSeg" +msgstr "SeptSeg" + +#: ../src/flowparts/sevenseg.cpp:41 +msgid "Output to a Seven Segment display." +msgstr "Sorie vers un afficheur sept segments." + +#: ../src/flowparts/sevenseg.cpp:51 ../src/flowparts/keypad.cpp:49 +msgid "Pin map" +msgstr "Brochage" + +#: ../src/flowparts/sevenseg.cpp:62 +msgid "Display %1 on %2" +msgstr "Afficher %1 sur %2" + +#: ../src/flowparts/unary.cpp:27 ../src/flowparts/unary.cpp:37 +msgid "Unary" +msgstr "Unaire" + +#: ../src/flowparts/unary.cpp:28 ../src/flowparts/varassignment.cpp:28 +#: ../src/flowparts/varcomparison.cpp:28 +msgid "Variables" +msgstr "Variables" + +#: ../src/flowparts/unary.cpp:38 +msgid "" +"A unary operation involves only one variable. Suppo operations are:" +"
    • Rotate Left rotates the binary bits of the variable left " +"(discarding the end bits).
    • Rotate Right rotates the binary " +"bits right (discarding the start bits).
    • Increment increases " +"the value of the variable by 1. A value of 255 wraps around to 0.
    • Decrement decreases the value of a variable by 1. A value of " +"0 wraps around to 255.
    " +msgstr "" +"Une opération unaire implique une seule variable. Les opérations supportées " +"sont :
    • Rotation gauche fait tourner le nombres binaires " +"de la variable vers la gauche (en jetant les bits qui dépassent).
    • Rotation droite fait tourner les nombres binaires vers le " +"droite (en jetant les bits qui dépasent).
    • Incrément augmente " +"la valeur d'une varible de 1. Un valeur de 255 revient alors à zéro.
    • Décrément diminue la valeur d'une variable de 1. Une valeurs " +"nulle revient alors à 255.
    " + +#: ../src/flowparts/unary.cpp:48 ../src/flowparts/repeat.cpp:49 +#: ../src/flowparts/varcomparison.cpp:52 ../src/flowparts/while.cpp:49 +msgid "Operation" +msgstr "Opération" + +#: ../src/flowparts/callsub.cpp:27 ../src/flowparts/callsub.cpp:37 +msgid "Sub Call" +msgstr "Appel de Subroutine" + +#: ../src/flowparts/callsub.cpp:28 ../src/flowparts/end.cpp:28 +#: ../src/flowparts/embed.cpp:28 ../src/flowparts/sub.cpp:28 +#: ../src/flowparts/interrupt.cpp:28 ../src/flowparts/start.cpp:28 +msgid "Common" +msgstr "Commun" + +#: ../src/flowparts/callsub.cpp:38 +msgid "" +"Call a subroutine. When the subroutine returns, the code will continue " +"execution from this point." +msgstr "" +"Appelle une Subroutine. Au retour de la Subroutine, le code continuera à " +"s'exécuter à partir de ce point." + +#: ../src/flowparts/callsub.cpp:44 ../src/flowparts/sub.cpp:27 +#: ../src/flowparts/sub.cpp:41 +msgid "Subroutine" +msgstr "Subroutine" + +#: ../src/flowparts/callsub.cpp:54 +msgid "Call %1" +msgstr "Appel %1" + +#: ../src/flowparts/pulse.cpp:26 ../src/flowparts/pulse.cpp:37 +msgid "Pulse" +msgstr "Impulsion" + +#: ../src/flowparts/pulse.cpp:27 ../src/flowparts/inputbutton.cpp:28 +#: ../src/flowparts/count.cpp:28 ../src/flowparts/delay.cpp:28 +#: ../src/flowparts/keypad.cpp:28 +msgid "Functions" +msgstr "Fonctions" + +#: ../src/flowparts/pulse.cpp:38 +msgid "Pulse a pin high/low for a given duration." +msgstr "Impulsion haute/basse sur une broche pendant une durée déterminée." + +#: ../src/flowparts/pulse.cpp:44 +msgid "Duration" +msgstr "Durée" + +#: ../src/flowparts/pulse.cpp:71 +msgid "Pulse %1 for %2 sec" +msgstr "Impulsion %1 pendant %2 sec" + +#: ../src/flowparts/pinmapping.cpp:54 +msgid "Pin Map Editor" +msgstr "Éditeur de brochage" + +#: ../src/flowparts/inputbutton.cpp:27 ../src/flowparts/inputbutton.cpp:39 +msgid "InputButton" +msgstr "Bonton d'entrée" + +#: ../src/flowparts/inputbutton.cpp:40 +msgid "" +"Pauses program execution until a inputbutton has been pressed or released " +"(i.e. on rising or falling input), after performing debouncing." +msgstr "" +"Arrête l'exécution du programme jusqu'à ce qu'un bouton d'entrée soit " +"appuyé ou relâché (c'est à dire à la monté ou à la descente du signal " +"d'entré), après l'application d'un anti-rebond." + +#: ../src/flowparts/inputbutton.cpp:46 ../src/flowparts/count.cpp:46 +msgid "Trigger" +msgstr "Trigger" + +#: ../src/flowparts/inputbutton.cpp:62 +msgid "Continue on %1 %2" +msgstr "Continuer en %1 %2" + +#: ../src/flowparts/end.cpp:27 ../src/flowparts/end.cpp:37 +#: ../src/flowparts/end.cpp:41 +msgid "End" +msgstr "Fin" + +#: ../src/flowparts/end.cpp:38 +msgid "" +"End the program execution, putting the IC into sleep. Unlike Start, " +"however, this FlowPart is not necessary for proper program execution" +msgstr "" +"Fin de l'exécution du programme, qui met le CI en sommeil. Au contraire de " +"Start, cependant, ce FlowPart n'est pas nécessaire pour une exécution " +"valide du programme." + +#: ../src/flowparts/writeport.cpp:27 ../src/flowparts/writeport.cpp:37 +msgid "Write to Port" +msgstr "Écrire sur le port" + +#: ../src/flowparts/writeport.cpp:38 +msgid "" +"Sets the port's pins state to high/low from the given value. Only pins that " +"have been configured as output pins will take on the value assigned to them." +msgstr "" +"Règle les valeurs hautes/basses du port selon la valeur donnée. Seles les " +"broches qui ont été configurées comme broches de sortie prendront la valeur " +"qu'on leur affecte." + +#: ../src/flowparts/writeport.cpp:44 +msgid "Write" +msgstr "Écrire" + +#: ../src/flowparts/writeport.cpp:62 +msgid "Write %1 to %2" +msgstr "Écrire %1 vers %2" + +#: ../src/flowparts/count.cpp:38 +msgid "" +"Count the number of pulses during a fixed interval. To avoid ambiguity, " +"this increments the counter on either a rising or falling edge, as opposed " +"to a high or a low." +msgstr "" +"Compte le nombre d'impulsions durant un intervalle de temps donné. Pour " +"éviter l'ambigüité, cela incrémente le compteur sur front montant ou " +"descendant, et non pas sur un état haut ou bas." + +#: ../src/flowparts/count.cpp:61 +msgid "Count %1 for %2 sec" +msgstr "Compter %1 pendant %2 sec" + +#: ../src/flowparts/embed.cpp:27 ../src/flowparts/embed.cpp:38 +msgid "Embed" +msgstr "Embarquer" + +#: ../src/flowparts/embed.cpp:39 +msgid "Doubleclick on the item to edit the embedded code." +msgstr "Cliquez double sur l'item pour éditer le code embarqué." + +#: ../src/flowparts/embed.cpp:47 +msgid "Type" +msgstr "Type" + +#: ../src/flowparts/embed.cpp:50 +msgid "Code" +msgstr "Code" + +#: ../src/flowparts/embed.cpp:51 +msgid "// Embedded code:" +msgstr "Code embarqué :" + +#: ../src/flowparts/embed.cpp:62 +msgid "%1: %2..." +msgstr "%1 : %2..." + +#: ../src/flowparts/sub.cpp:37 +msgid "Sub" +msgstr "Sub" + +#: ../src/flowparts/sub.cpp:38 +msgid "" +"Defines the starting point of a subroutine. Call this subroutine using " +"\"Call Sub\"" +msgstr "" +"Définit le point de départ d'une subroutine. Applez cette subroutine en " +"utilisant \"Appel Sub\"" + +#: ../src/flowparts/delay.cpp:27 ../src/flowparts/delay.cpp:37 +msgid "Delay" +msgstr "Délai" + +#: ../src/flowparts/delay.cpp:38 +msgid "Delay the program execution for a fixed period of time." +msgstr "Retarde l'exécution du programme pendant un délai fixé." + +#: ../src/flowparts/delay.cpp:44 +msgid "Pause Length" +msgstr "Longueur de la pause" + +#: ../src/flowparts/delay.cpp:56 +msgid "Delay for %1 sec" +msgstr "Délai pendant %1 sec" + +#: ../src/flowparts/repeat.cpp:27 ../src/flowparts/repeat.cpp:37 +msgid "Repeat" +msgstr "Repeat" + +#: ../src/flowparts/repeat.cpp:28 ../src/flowparts/forloop.cpp:28 +#: ../src/flowparts/while.cpp:28 +msgid "Loops" +msgstr "Boucles" + +#: ../src/flowparts/repeat.cpp:38 +msgid "" +"Repeatedly execute code, until the given condition is false. The condition " +"is checked after the code has been executed.

    This is different from " +"\"While\", which checks for the condition to be true before the code is " +"executed." +msgstr "" +"Exécute le code de façon itérative, jusqu'à ce qu'une condition donnée soit " +"fausse. La condition est testée après que le code aura été exécuté." +"

    C'est différent de \"While\", qui vérifie que la condition soit " +"vraie avant d'exécuter le code." + +#: ../src/flowparts/repeat.cpp:65 +msgid "repeat until %1 %2 %3" +msgstr "répéter jusqu'à ce que %1 %2 %3" + +#: ../src/flowparts/keypad.cpp:39 +msgid "Gets a key from a keypad connected to the PIC." +msgstr "Sasit une touche d'un clavier connecté au PIC." + +#: ../src/flowparts/interrupt.cpp:27 ../src/flowparts/interrupt.cpp:37 +#: ../src/flowparts/interrupt.cpp:48 ../src/textview.cpp:76 +msgid "Interrupt" +msgstr "Interruption" + +#: ../src/flowparts/interrupt.cpp:38 +msgid "Defines the starting point of a interrupt handler." +msgstr "Définit le point de départ d'un gestionnaire d'interruption." + +#: ../src/flowparts/interrupt.cpp:58 +msgid "Interrupt %1" +msgstr "Interruption %1" + +#: ../src/flowparts/varassignment.cpp:27 +msgid "Assignment" +msgstr "Affectation" + +#: ../src/flowparts/varassignment.cpp:37 +msgid "Variable Assignment" +msgstr "Affectation de variable" + +#: ../src/flowparts/varassignment.cpp:38 +msgid "" +"Assigns the evaluation of an expression to a variable. The expression can " +"take many forms. For example:
    • x = 2
    • x = y + 3
    • x = y + z
    • x = 2 * y
    " +msgstr "" +"Affecte la valeur d'une expression à une variable. L'expression peut " +"prendre plusieurs formes. Par exemple :
    • x = 2
    • x = " +"y + 3
    • x = y + z
    • x = 2 * y
    " + +#: ../src/flowparts/start.cpp:27 ../src/flowparts/start.cpp:37 +#: ../src/flowparts/start.cpp:41 +msgid "Start" +msgstr "Start" + +#: ../src/flowparts/start.cpp:38 +msgid "Determines the initial program execution point." +msgstr "Détermine le point d'exécution intial du programme." + +#: ../src/flowparts/forloop.cpp:27 +msgid "For" +msgstr "For" + +#: ../src/flowparts/forloop.cpp:37 +msgid "For Loop" +msgstr "Boucle For" + +#: ../src/flowparts/forloop.cpp:38 +msgid "" +"The code contained in the foor loop is repeatedly executed. By default, the " +"variable used will be incremented every time. This can be changed by " +"entering a value other than 1 into Step.

    The for loop will exit when " +"the value contained in the variable is equal to the end value." +msgstr "" +"Le code contenu dans la boucle For est exécuté itérativement. Par défaut, " +"la variable utilisée sera incrémentée de 1 à chaque fois. On peut changer " +"ça en entrant une valeur autre que 1 dans Step.

    La boucke For se " +"terminera quand la valeur contenue dans la veriable sera égale à la valeur " +"finale." + +#: ../src/flowparts/forloop.cpp:50 +msgid "Initial Value" +msgstr "Valeur intiale" + +#: ../src/flowparts/forloop.cpp:55 +msgid "End Value" +msgstr "Valeur finale" + +#: ../src/flowparts/forloop.cpp:60 ../src/textview.cpp:78 +msgid "Step" +msgstr "Step" + +#: ../src/flowparts/varcomparison.cpp:27 +msgid "Comparison" +msgstr "Comparaison" + +#: ../src/flowparts/varcomparison.cpp:37 +msgid "Variable Comparison" +msgstr "Comparaison de variables" + +#: ../src/flowparts/varcomparison.cpp:38 +msgid "" +"Conditional branch point, depending on the comparison of two values. The " +"supported comparisons are:
    • x == y - Equality: true if x has " +"the same value as y.
    • x < y - Less than: true if x is " +"smaller than y.
    • x > y - Greater than: true if x is bigger " +"than y.
    • x <= y - Less than or equal: true if x is less " +"than or equal to y.
    • x >= y - Greater than or equal: true " +"if x is greater than or equal to y.
    • x != y - Does not equal: " +"true if x does not have the same value as y.
    " +msgstr "" +"Point de branchement conditionnel, selon la comparaison de deux valeurs. " +"Les comparaisons supportées sont :
    • x == y - Égalié : vrie si " +"x a la maême valeur que y.
    • x < y - Plus petit que : vraie " +"sir x est plus petit que y.
    • x > y - Plus grand que : vrie " +"si x est plus grand que y.
    • x <= y - Plus petit ou égal : " +"vraie si x est plus petit ou égal à y.
    • x >= y - Plus " +"grand ou égal : vraie si x est plus grand ou égal à y.
    • x != y - Différent de : vraie si x est différent de y.
    " + +#: ../src/flowparts/while.cpp:27 ../src/flowparts/while.cpp:37 +msgid "While" +msgstr "While" + +#: ../src/flowparts/while.cpp:38 +msgid "" +"Repeatedly execute code, until the given condition is false. The condition " +"is checked before the code has been executed.

    This is different from " +"\"Repeat\", which checks for the condition to be true after the code is " +"executed." +msgstr "" +"Exécute le code de façon itérative, jusqu'à ce que la condtion donnée soit " +"fausse. La condition est testée avant que le code ne soit exécuté." +"

    C'est différent de \"Repeat\", qui teste si la condition est vraie " +"après que le code aité été exécuté." + +#: ../src/flowparts/while.cpp:65 +msgid "while %1 %2 %3" +msgstr "tant que %1 %2 %3" + +#: ../src/flowparts/setpin.cpp:30 ../src/flowparts/setpin.cpp:40 +msgid "Set Pin State" +msgstr "Fixer l'état d'une broche" + +#: ../src/flowparts/setpin.cpp:41 +msgid "" +"Set a pin on a port high or low. The pin needs to be set as an output pin." +msgstr "" +"Fixe à l'état haut ou bas une broche d'un port. La broche doit avoir été " +"définie comme broche de sortie." + +#: ../src/flowparts/setpin.cpp:47 +msgid "State" +msgstr "État" + +#: ../src/flowparts/setpin.cpp:62 +msgid "Set %1 %2" +msgstr "Set %1 %2" + +#: ../src/ktechlab.cpp:167 +msgid "Project" +msgstr "Projet" + +#: ../src/ktechlab.cpp:174 +msgid "Components" +msgstr "Composants" + +#: ../src/ktechlab.cpp:185 +msgid "Flow Parts" +msgstr "Flow Parts" + +#: ../src/ktechlab.cpp:193 ../src/ktechlab.cpp:439 +msgid "Mechanics" +msgstr "Mécanique" + +#: ../src/ktechlab.cpp:201 rc.cpp:749 rc.cpp:800 rc.cpp:809 +#, no-c-format +msgid "Item Editor" +msgstr "Éditeur d'item" + +#: ../src/ktechlab.cpp:207 +msgid "Context Help" +msgstr "Aide Contextuelle" + +#: ../src/ktechlab.cpp:213 +msgid "Messages" +msgstr "Messages" + +#: ../src/ktechlab.cpp:220 +msgid "Symbol Viewer" +msgstr "Visualisation de symboles" + +#: ../src/ktechlab.cpp:432 +msgid "&New" +msgstr "&Nouveau" + +#: ../src/ktechlab.cpp:433 rc.cpp:3 +#, no-c-format +msgid "New File" +msgstr "Nouveau Fichier" + +#: ../src/ktechlab.cpp:435 +msgid "C source" +msgstr "Source C" + +#: ../src/ktechlab.cpp:436 +msgid "Circuit" +msgstr "Circuit" + +#: ../src/ktechlab.cpp:446 +msgid "Open Recent" +msgstr "Ouvrir Récent" + +#: ../src/ktechlab.cpp:451 +msgid "New Project.." +msgstr "Nouveau Projet ..." + +#: ../src/ktechlab.cpp:452 +msgid "Open Project..." +msgstr "Ouvrir Projet ..." + +#: ../src/ktechlab.cpp:454 +msgid "Open &Recent Project..." +msgstr "Ouvrir Projet &Récent ..." + +#: ../src/ktechlab.cpp:455 +msgid "Export to Makefile..." +msgstr "Exportation vers Makefile ..." + +#: ../src/ktechlab.cpp:456 +msgid "Create Subproject..." +msgstr "Créer Sous-projet ..." + +#: ../src/ktechlab.cpp:457 +msgid "Add Existing File..." +msgstr "Ajout Fichier Existant ..." + +#: ../src/ktechlab.cpp:458 +msgid "Add Current File..." +msgstr "Ajout Fichier Courant ..." + +#: ../src/ktechlab.cpp:460 +msgid "Close Project" +msgstr "Fermer Projet" + +#: ../src/ktechlab.cpp:461 +msgid "Remove from Project" +msgstr "Retirer du Projet" + +#: ../src/ktechlab.cpp:462 +msgid "Insert Existing File..." +msgstr "Insérer Fichier Existant ..." + +#: ../src/ktechlab.cpp:463 +msgid "Insert Current File..." +msgstr "Insérer Fichier Courant ..." + +#: ../src/ktechlab.cpp:464 +msgid "Linker Options..." +msgstr "Option de Ligature ..." + +#: ../src/ktechlab.cpp:465 +msgid "Build..." +msgstr "Construire ..." + +#: ../src/ktechlab.cpp:466 +msgid "Upload..." +msgstr "Télécharger ..." + +#: ../src/ktechlab.cpp:467 +msgid "Processing Options..." +msgstr "Options de traitement ..." + +#: ../src/ktechlab.cpp:470 +msgid "Split View Left/Right" +msgstr "Couper la vue Gauche/Droite" + +#: ../src/ktechlab.cpp:471 +msgid "Split View Top/Bottom" +msgstr "Couper la vue Haut/Bas" + +#: ../src/ktechlab.cpp:473 +msgid "Run Simulation" +msgstr "Activer la simulation" + +#: ../src/ktechlab.cpp:478 +msgid "Pause Simulation" +msgstr "Arrêter la simulation" + +#: ../src/ktechlab.cpp:558 +msgid "&Insert Into" +msgstr "&Insérer dans" + +#: ../src/ktechlab.cpp:559 +msgid "&Copy Into" +msgstr "&Copier dans" + +#: ../src/ktechlab.cpp:561 +msgid "C&ancel" +msgstr "Éch&appement" + +#: ../src/ktechlab.cpp:818 +msgid "Close" +msgstr "Fermer" + +#: ../src/ktechlab.cpp:826 +msgid "Reload" +msgstr "Recharger" + +#: ../src/ktechlab.cpp:829 +msgid "Close All Others" +msgstr "Fermer tous les autres" + +#: ../src/ktechlab.cpp:1003 ../src/projectmanager.cpp:959 +msgid "Open Location" +msgstr "Ouvrir Emplacement" + +#: ../src/ktechlab.cpp:1164 +msgid "Exiting..." +msgstr "En cours de sortie ..." + +#: ../src/itemdocumentdata.cpp:113 ../src/projectmanager.cpp:791 +msgid "Could not open %1 for reading" +msgstr "Impossible d'ouvrir %1 en lecture" + +#: ../src/itemdocumentdata.cpp:135 ../src/projectmanager.cpp:808 +msgid "" +"Couldn't parse xml:\n" +"%1" +msgstr "" +"Impossible d'analyser le xml :\n" +"%1" + +#: ../src/itemdocumentdata.cpp:183 +msgid "Could not open '%1' for writing. Check that you have write permissions" +msgstr "" +"Impossible d'ouvrir '%1' en écriture. Vérifiez que vous avec les droits " +"d'écriture." + +#: ../src/itemdocumentdata.cpp:183 +msgid "Saving File" +msgstr "Fichier en cours d'enregistrement" + +#: ../src/picitem.cpp:256 +msgid "Advanced..." +msgstr "Avancé ..." + +#: ../src/icnview.cpp:31 ../src/icnview.cpp:49 +msgid "Automatic" +msgstr "Automatique" + +#: ../src/icnview.cpp:36 ../src/icnview.cpp:50 +msgid "Manual" +msgstr "Manuel" + +#: ../src/icnview.cpp:43 ../src/icnview.cpp:47 +msgid "Connection Routing Mode" +msgstr "Mode de connextion du routage" + +#: ../src/icnview.cpp:97 +msgid "Manual connection routing enabled." +msgstr "Connexion de routage manuelle activée." + +#: ../src/icnview.cpp:97 +msgid "Automatic connection routing enabled." +msgstr "Connexion de routage automatique activée." + +#: ../src/viewcontainer.cpp:348 +msgid "(empty)" +msgstr "(vide)" + +#: ../src/circuitdocument.cpp:39 +msgid "Orientation" +msgstr "Orientation" + +#: ../src/circuitdocument.cpp:43 +msgid "" +"*.circuit|Circuit(*.circuit)\n" +"*|All Files" +msgstr "" +"*.circuit|Circuit(*.circuit)\n" +"*|Tous fichiers" + +#: ../src/circuitdocument.cpp:754 +msgid "No components were found in the selection." +msgstr "Aucun composant trouvé dans la sélection." + +#: ../src/circuitdocument.cpp:762 +msgid "No External Connection components were found in the selection." +msgstr "" +"Aucun composant de connexion externe n'a été trouvé dans la sélection." + +#: ../src/itemdocument.cpp:84 +msgid "Alignment" +msgstr "Alignement" + +#: ../src/itemdocument.cpp:797 +msgid "Crop image to program parts" +msgstr "Découper l'image en parties de programme" + +#: ../src/itemdocument.cpp:800 +msgid "Crop image to circuit components" +msgstr "Découper l'image en composants de circuit" + +#: ../src/itemdocument.cpp:803 +msgid "Crop image" +msgstr "Découper l'image" + +#: ../src/itemdocument.cpp:810 ../src/itemdocument.cpp:852 +#: ../src/itemdocument.cpp:859 ../src/itemdocument.cpp:868 +msgid "Export As Image" +msgstr "Exporter comme image" + +#: ../src/itemdocument.cpp:852 +msgid "SVG export is sub-functional" +msgstr "L'exportation SVG est sous-fonctionnelle" + +#: ../src/itemdocument.cpp:859 +msgid "Unknown extension, please select one from the filter list." +msgstr "" +"Extension inconnue, veuillez en sélectionner une parmi la liste de filtres." + +#: ../src/itemdocument.cpp:868 +msgid "There is nothing to crop" +msgstr "Il n'y a rien à découper" + +#: ../src/itemdocument.cpp:934 +msgid "Export failed" +msgstr "Exportation ratée" + +#: ../src/itemdocument.cpp:934 +msgid "Image Export" +msgstr "Exportation d'image" + +#: ../src/textdocument.cpp:69 +msgid "Libkatepart not available for constructing editor" +msgstr "Libkatepart non disponible pour l'éditeur constructif" + +#: ../src/textdocument.cpp:606 +msgid "%1 - %2" +msgstr "%1 - %2" + +#: ../src/textdocument.cpp:732 +msgid "Unknown code type." +msgstr "Type de code inconnu." + +#: ../src/textdocument.cpp:732 ../src/textdocument.cpp:736 +msgid "Cannot debug" +msgstr "Imossible de déboguer" + +#: ../src/textdocument.cpp:736 +msgid "Cannot debug hex." +msgstr "Impossible de déboguer l'hexa." + +#: ../src/textview.cpp:69 +msgid "Format Assembly Code" +msgstr "Format Code Assembleur" + +#: ../src/textview.cpp:74 ../src/textview.cpp:280 +msgid "Set &Breakpoint" +msgstr "Fixer &Point d'arrêt" + +#: ../src/textview.cpp:75 +msgid "Run" +msgstr "Lancer" + +#: ../src/textview.cpp:77 +msgid "Stop" +msgstr "Arrêter" + +#: ../src/textview.cpp:79 +msgid "Step Over" +msgstr "Avancer au-delà" + +#: ../src/textview.cpp:80 +msgid "Step Out" +msgstr "Avancer vers la sortie" + +#: ../src/textview.cpp:265 +msgid " Line: %1 Col: %2 " +msgstr " Ligne : %1 Col. : %2 " + +#: ../src/textview.cpp:278 +msgid "Clear &Breakpoint" +msgstr "Supprimer &Point d'arrêt" + +#: ../src/projectmanager.cpp:423 +msgid "Don't know how to build \"%1\" (output url is empty)." +msgstr "Je ne sais pas comment construire \"%1\" (l'url de sortie est vide)." + +#: ../src/projectmanager.cpp:434 +msgid "Don't know how to build \"%1\" (library does not exist in project)." +msgstr "" +"Je ne sais pas comment construire \"%1\" (bibliothèque inexistante dans le " +"projet)" + +#: ../src/projectmanager.cpp:464 +msgid "Don't know how to build \"%1\" (unknown output type)." +msgstr "Je ne sais pas comment construire \"%1\" (type de sortie inconnu)." + +#: ../src/projectmanager.cpp:848 +msgid "Project could not be saved to \"%1\"" +msgstr "Le projet n'a pas pu être enregistré dans \"%1\"" + +#: ../src/projectmanager.cpp:848 +msgid "Saving Project" +msgstr "Enregistrement du projet en cours" + +#: ../src/projectmanager.cpp:909 +msgid "" +"Displays the list of files in the project.\n" +"To open or close a project, use the \"Project\" menu. Right click on a file " +"to remove it from the project" +msgstr "" +"Affiche la liste des fichiers du projet.\n" +"Pour ouvrir ou fermer un projet, utilisez le menu \"Projet\". Cliquez " +"droit\n" +"sur un fichier pour le retirer du projet." + +#: ../src/projectmanager.cpp:912 +msgid "Project Manager" +msgstr "Gestionnaire de Projet" + +#: ../src/projectmanager.cpp:1133 +msgid "Do you really want to remove \"%1\"?" +msgstr "Voulez-vous vraiment retier \"%1\" ?" + +#: ../src/projectmanager.cpp:1133 +msgid "Remove Project File?" +msgstr "Retire le fichier de Projet ?" + +#: rc.cpp:6 +#, no-c-format +msgid "" +"Select the type of file you wish to create.
    \n" +"

    \n" +"Pic Program
    \n" +"Creates a new PIC program, with flow chart editor. Select the target device " +"for your program below.\n" +"

    \n" +"Circuit
    \n" +"Creates a new circuit, with drag and drop editor. Real time simulation of " +"the circuit occurs automatically." +msgstr "" +"Sélectionnez le type de fichier que vous voulez créer.
    \n" +"

    \n" +"Programme Pic
    \n" +"Crée une nouveau programme PIV, avec l'éditeur de FlowChart. Sélectionnez " +"la cible pour votre programme dessous.\n" +"

    \n" +"Circuit
    \n" +"Crée un nouveau circuit, avec l'éditeur Drag&Drop. Une simulation du " +"circuit en temps réel est activée automatiquement." + +#: rc.cpp:15 +#, no-c-format +msgid "New File Details" +msgstr "Détails de Nouveau Fichier" + +#: rc.cpp:18 +#, no-c-format +msgid "File Type:" +msgstr "Type de fichier :" + +#: rc.cpp:21 +#, no-c-format +msgid "&Add to project" +msgstr "&Ajouter au projet" + +#: rc.cpp:24 rc.cpp:55 rc.cpp:274 rc.cpp:283 rc.cpp:470 rc.cpp:728 +#, no-c-format +msgid "Alt+A" +msgstr "Alt+A" + +#: rc.cpp:27 +#, no-c-format +msgid "Asm Formatting" +msgstr "Formattage d'assembleur" + +#: rc.cpp:30 +#, no-c-format +msgid "" +"The values control the indentation from the left margin of the various " +"types of assembly code." +msgstr "" +"Les valeurs contrôlent l'indentation depuis la marge gauche des divers " +"types de code assembleur." + +#: rc.cpp:33 +#, no-c-format +msgid "Output Code Indentation" +msgstr "Indentation du code en sortie" + +#: rc.cpp:36 +#, no-c-format +msgid "'equ' Value" +msgstr "'equ' Valeur" + +#: rc.cpp:39 +#, no-c-format +msgid "Instruction Data" +msgstr "Données d'instruction" + +#: rc.cpp:42 +#, no-c-format +msgid "Comment" +msgstr "Commentaire" + +#: rc.cpp:45 +#, no-c-format +msgid "'equ'" +msgstr "'equ'" + +#: rc.cpp:48 +#, no-c-format +msgid "Instruction Name" +msgstr "Nom d'instruction" + +#: rc.cpp:52 +#, no-c-format +msgid "&Automatically format Microbe output" +msgstr "Formatte &Automatiquement la sortie Microbe" + +#: rc.cpp:58 +#, no-c-format +msgid "Gpasm Settings" +msgstr "Réglages Gpasm" + +#: rc.cpp:62 +#, no-c-format +msgid "Radix (-r):" +msgstr "Base de numéRation (-r)" + +#: rc.cpp:65 +#, no-c-format +msgid "Warning level (-w):" +msgstr "niveau de Warning (-w)" + +#: rc.cpp:68 rc.cpp:163 +#, no-c-format +msgid "Hex Format (-a):" +msgstr "Format hexa (-a)" + +#: rc.cpp:71 +#, no-c-format +msgid "Ign&ore case (-i)" +msgstr "Ig&norer la casse (-i)" + +#: rc.cpp:74 rc.cpp:169 rc.cpp:338 rc.cpp:695 +#, no-c-format +msgid "Alt+O" +msgstr "Alt+O" + +#: rc.cpp:77 +#, no-c-format +msgid "" +"All user defined symbols and macros are case sensitive. This option makes " +"them case insensitive." +msgstr "" +"Tous les symboles et macros définis par l'utilisateur sont sensibles à la " +"casse. Cette option les rend insensibles à la casse." + +#: rc.cpp:80 +#, no-c-format +msgid "Generate DOS-formated hex file (-&n)" +msgstr "Génération de fichier hexa au format DOS (-&n)" + +#: rc.cpp:83 rc.cpp:313 +#, no-c-format +msgid "Alt+N" +msgstr "Alt+N" + +#: rc.cpp:86 +#, no-c-format +msgid "" +"By default, gpasm generates hex files using ISO format. However, some " +"device programmers required a DOS formatted file. This option will cause " +"gpasm to generate a DOS formatted hex file. " +msgstr "" +"Par défaut, gpasm génère des fichiers hexa en utilisant le format ISO. " +"Cependant, quelques programmateurs nécessitent un fichier au format DOS. " +"Cette option force gpasm à générer un fichier hexa au format DOS." + +#: rc.cpp:89 rc.cpp:145 +#, no-c-format +msgid "inhx32" +msgstr "inhx32" + +#: rc.cpp:92 rc.cpp:148 +#, no-c-format +msgid "inhx8m" +msgstr "inhx8m" + +#: rc.cpp:95 rc.cpp:151 +#, no-c-format +msgid "inhx8s" +msgstr "inhx8s" + +#: rc.cpp:98 rc.cpp:154 +#, no-c-format +msgid "inhx16" +msgstr "inhx16" + +#: rc.cpp:101 rc.cpp:157 +#, no-c-format +msgid "" +"GPASM supports inhx8m, inhx8s, inhx16, and inhx32 hex file formats. This " +"option controls which hex file format is used." +msgstr "" +"GPASM supporte les formats de fichiers hexa inhx8m, inhx8s, inhx16, et " +"inhx32. Cette option contrôle quel format de fichier hexa est utilisé." + +#: rc.cpp:116 +#, no-c-format +msgid "All" +msgstr "Tout" + +#: rc.cpp:119 +#, no-c-format +msgid "Warnings" +msgstr "Warnings" + +#: rc.cpp:122 +#, no-c-format +msgid "Errors" +msgstr "Erreurs" + +#: rc.cpp:125 +#, no-c-format +msgid "" +"This sets the threshold of messages displayed in the log view.

    • \"All" +"\" will display all output - information, warnings and errors.
    • \"Warnings" +"\" will supress messages.
    • \"Errors\" will supress both messages and " +"warnings.
    " +msgstr "" +"Ceci règle le seuil pour les messages affichés dans la vue de journal." +"
    • \"Tout\" affichera toute la sortie - informations, warnings et " +"erreurs.
    • \"Warnings\" supprimera les messages.
    • \"Erreurs\" " +"supprimera les messages et les warnings.
    " + +#: rc.cpp:128 rc.cpp:414 +#, no-c-format +msgid "Other options:" +msgstr "Autres Options :" + +#: rc.cpp:131 +#, no-c-format +msgid "Form1" +msgstr "Form1" + +#: rc.cpp:134 +#, no-c-format +msgid "Zoom" +msgstr "Zoom" + +#: rc.cpp:138 +#, no-c-format +msgid "Reset" +msgstr "Reset" + +#: rc.cpp:142 +#, no-c-format +msgid "Linker Options" +msgstr "Option de Ligature" + +#: rc.cpp:160 +#, no-c-format +msgid "Library Directory (-I):" +msgstr "Répertoire de Bibliothèques (-I) :" + +#: rc.cpp:166 +#, no-c-format +msgid "&Output a map file (-m)" +msgstr "S&ortir un fichier map (-m)" + +#: rc.cpp:172 +#, no-c-format +msgid "Linker Script (-s):" +msgstr "Script de ligature (-s) :" + +#: rc.cpp:175 +#, no-c-format +msgid "Other:" +msgstr "Autre :" + +#: rc.cpp:178 +#, no-c-format +msgid "Link libraries inside project" +msgstr "Lier les bibliothèques à l'intérieur du projet" + +#: rc.cpp:181 rc.cpp:628 +#, no-c-format +msgid "Library" +msgstr "Bibliothèque" + +#: rc.cpp:185 +#, no-c-format +msgid "SDCC Options" +msgstr "Options SDCC" + +#: rc.cpp:188 +#, no-c-format +msgid "Ge&neral" +msgstr "Gé&néral" + +#: rc.cpp:191 +#, no-c-format +msgid "Don't search in the standard librar&y directory (--nostdlib)" +msgstr "" +"Ne pas chercher dans le répertoire de bibliothèque statndard (--nostdlib)" + +#: rc.cpp:194 rc.cpp:252 rc.cpp:379 rc.cpp:454 +#, no-c-format +msgid "Alt+Y" +msgstr "Alt+Y" + +#: rc.cpp:197 +#, no-c-format +msgid "Don't search in the standard include directory (--nostdinc)" +msgstr "Ne pas chercher dans le répertoire standard d'inclusion (--nostdinc)" + +#: rc.cpp:201 +#, no-c-format +msgid "Disa&ble pedantic warnings (--less-pedantic)" +msgstr "Dés&activer les avertissements pédants (--less-pedantic)" + +#: rc.cpp:204 rc.cpp:242 rc.cpp:347 rc.cpp:397 +#, no-c-format +msgid "Alt+B" +msgstr "Alt+B" + +#: rc.cpp:207 +#, no-c-format +msgid "Use C&89 standard only (--std-c89)" +msgstr "Utiliser le standard C&89 seulement (--std-c89)" + +#: rc.cpp:210 +#, no-c-format +msgid "Alt+8" +msgstr "Alt+8" + +#: rc.cpp:213 +#, no-c-format +msgid "" +"Follow the C89 standard and disable SDCC features that conflict with the " +"standard." +msgstr "" +"Suivre le standard C89 et désactiver les particularités SDCC qui entrent en " +"conflit avec celui-ci." + +#: rc.cpp:216 +#, no-c-format +msgid "Use C&99 standard only (--std-c99)" +msgstr "Utiliser le standard C&99 seulement (--std-c99)" + +#: rc.cpp:219 +#, no-c-format +msgid "Alt+9" +msgstr "Alt+9" + +#: rc.cpp:223 +#, no-c-format +msgid "" +"Follow the C99 standard and disable SDCC features that conflict with the " +"standard (incomplete support)." +msgstr "" +"Suivre le standard C99 et désactiver les particularités SDCC qui entrent en " +"conflit avec celui-ci." + +#: rc.cpp:226 +#, no-c-format +msgid "Code Gener&ation" +msgstr "Génér&ation de Code" + +#: rc.cpp:229 +#, no-c-format +msgid "Stack auto&matic variables (--stack-auto)" +msgstr "Empiler les variables auto&matiques (--stack-auto)" + +#: rc.cpp:232 rc.cpp:329 rc.cpp:391 rc.cpp:476 rc.cpp:734 +#, no-c-format +msgid "Alt+M" +msgstr "Alt+M" + +#: rc.cpp:236 +#, no-c-format +msgid "" +"All functions in the source file will be compiled as reentrant, i.e. the " +"parameters and local variables will be allocated on the stack. If this " +"option is used all source files in the project should be compiled with this " +"option. It automatically implies -int-long-reent and -float-reent." +msgstr "" +"Toutes les fonctions dans le fichier source seront compilées de façon " +"réentrante, c'est à dire que les paramètres et les variables locales seront " +"alloués dans la pile. Si l'option est utilisée, tous les fichiers source du " +"projet seront compilés avec cette option. Elle implique automatiquement -" +"int-long-reent et -float-reent." + +#: rc.cpp:239 +#, no-c-format +msgid "Integer li&braries were compiled as reentrant (--int-long-reent)" +msgstr "" +"Les &bibliothèques d'entiers ont été compilées comme réentrantes (--int-" +"long-reent)" + +#: rc.cpp:246 +#, no-c-format +msgid "" +"Integer (16 bit) and long (32 bit) libraries have been compiled as " +"reentrant. Note by default these libraries are compiled as non-reentrant." +msgstr "" +"Les bibliothèques d'entiers (16 bit) et d'entiers longs (32 bits) ont été " +"compilées comme réentrantes. Notez que par défaut ces bibliothèques sont " +"compilées comme non-réentrantes." + +#: rc.cpp:249 +#, no-c-format +msgid "Floating point librar&y was compiled as reentrant (--float-reent)" +msgstr "" +"Les bibliothèques de nombres flottants ont été compilées comme réentrantes " +"(--float-reent)" + +#: rc.cpp:255 +#, no-c-format +msgid "Floating point library is compiled as reentrant." +msgstr "La bibliothèque de nombres flottants est compilée comme réentrante." + +#: rc.cpp:258 +#, no-c-format +msgid "Leave out the frame pointer (--fommit-frame-pointer)" +msgstr "Laisse tomber le pointer de trame (--fommit-frame-pointer)" + +#: rc.cpp:262 +#, no-c-format +msgid "Don't memcpy initialized &xram from code (--no-xinit-opt)" +msgstr "Ne fait pas memcpy du code vers la &xram initialisée (--no-xinit-opt)" + +#: rc.cpp:265 rc.cpp:385 +#, no-c-format +msgid "Alt+X" +msgstr "Alt+X" + +#: rc.cpp:268 +#, no-c-format +msgid "" +"Will not memcpy initialized data from code space into xdata space. This " +"saves a few bytes in code space if you don't have initialized data." +msgstr "" +"Ne fera pas memcpy depuis des données initialisées de l'espace de code vers " +"un espace xdata. Ça économise quelques octets dans l'espace de code si vous " +"n'avez pas de données initialisées." + +#: rc.cpp:271 +#, no-c-format +msgid "Callee will &always save registers used (--all-callee-saves)" +msgstr "" +"L'&appelé sauvera toujours les registres utilisés (--all-callee-saves)" + +#: rc.cpp:277 +#, no-c-format +msgid "&Optimization" +msgstr "&Optimisation" + +#: rc.cpp:280 +#, no-c-format +msgid "Disable overlaying leaf function &auto variables (--nooverlay)" +msgstr "" +"Inactive l'overlay pour les variables &automatiques feuilles d'une fonction " +"(--nooverlay)" + +#: rc.cpp:286 +#, no-c-format +msgid "" +"The compiler will not overlay parameters and local variables of any " +"function, see section Parameters and local variables for more details." +msgstr "" +"Le compilateur ne fera pas d'overlay sur les paramètres et les variables " +"locales d'aucune fonction, voyez le chapitre Paramètres et variables " +"locales pour plus de détails." + +#: rc.cpp:289 +#, no-c-format +msgid "Disable the GCSE optimization (--nogcse)" +msgstr "Inactive l'optimisation GCSE (--nogcse)" + +#: rc.cpp:293 +#, no-c-format +msgid "Disable label optimi&zation (--nolabelopt)" +msgstr "Inactive l'optimi&zation de lable (--nolabelopt)" + +#: rc.cpp:296 rc.cpp:403 +#, no-c-format +msgid "Alt+Z" +msgstr "Alt+Z" + +#: rc.cpp:299 +#, no-c-format +msgid "Will not optimize labels (makes the dumpfiles more readable)." +msgstr "" +"N'optimisera pas les labels (rend les fichiers de dump plus lisibles)." + +#: rc.cpp:302 +#, no-c-format +msgid "Disable optimization of invariants (--noinvariant)" +msgstr "Inactive l'optimisation des invariants (--noinvariant)" + +#: rc.cpp:306 +#, no-c-format +msgid "Disable loop variable induction (--noinduction)" +msgstr "Incative l'induction de variable de boucle (--noinduction)" + +#: rc.cpp:310 +#, no-c-format +msgid "Disable peep-hole optimization (--&no-peep)" +msgstr "Inactive l'optimisation peep-hole (--&no-peep)" + +#: rc.cpp:316 +#, no-c-format +msgid "Disable peep-hole optimization." +msgstr "Inactive l'optimisation peep-hole." + +#: rc.cpp:319 +#, no-c-format +msgid "Disable loop reverse optimization (--noloopreverse)" +msgstr "Désactive l'optimisation d'inversion de boucle (--noloopreverse)" + +#: rc.cpp:323 +#, no-c-format +msgid "Will not do loop reversal optimization." +msgstr "Ne fera pas d'optimisation d'inversion de boucle" + +#: rc.cpp:326 +#, no-c-format +msgid "Opti&mize for compact code (--opt-code-size)" +msgstr "Opti&mise pour un code compact (--opt-code-size)" + +#: rc.cpp:332 +#, no-c-format +msgid "" +"The compiler will optimize code generation towards compact code, possibly " +"at the expense of code speed." +msgstr "" +"Le compilateur optimisera la génération de code pour faire un code compact, " +"éventuellement aux dépens de la vitesse." + +#: rc.cpp:335 +#, no-c-format +msgid "&Optimize for fast code (--opt-code-speed)" +msgstr "&Optimise pour la rapidité du code (--opt-code-speed)" + +#: rc.cpp:341 +#, no-c-format +msgid "" +"The compiler will optimize code generation towards fast code, possibly at " +"the expense of code size." +msgstr "" +"Le compilateur optimisera la génération de code pour faire du code rapide, " +"éventuellement aux dépens de la taille du code." + +#: rc.cpp:344 +#, no-c-format +msgid "Ena&ble inline assembly peephole optimization (--peep-asm)" +msgstr "Active l'optimisation peephole de l'assem&blage inline (--peep-asm)" + +#: rc.cpp:350 +#, no-c-format +msgid "" +"Pass the inline assembler code through the peep hole optimizer. This can " +"cause unexpected changes to inline assembler code, please go through the " +"peephole optimizer rules defined in the source file tree '/peeph." +"def' before using this option." +msgstr "" +"Passe le code de l'assembleur inline à travers l'optimisation peephole. Ça " +"peut provoquer des changements inattendus au code assembleur inline, " +"veuillez paser par les règles de l'optimiseur peephole définies dans " +"l'arbre des fichiers sources '/peeph.def' avant d'utiliser cette " +"option." + +#: rc.cpp:353 +#, no-c-format +msgid "Don't generate boundary check for &jump tables (--nojtbound)" +msgstr "" +"Ne génère pas de vérification de limites pour les tables de sauts (--" +"no&jtbound)" + +#: rc.cpp:356 +#, no-c-format +msgid "Alt+J" +msgstr "Alt+J" + +#: rc.cpp:359 +#, no-c-format +msgid "PIC&16 Specific" +msgstr "Spécifique PIC&16" + +#: rc.cpp:362 +#, no-c-format +msgid "Don't use default libraries (--nodefaultlibs)" +msgstr "Ne pas utiliser les bibliothèques par défaut (--nodefaultlibs)" + +#: rc.cpp:366 +#, no-c-format +msgid "Don't generate BANKSEL directives (--pno-banksel)" +msgstr "Ne pas générer de directives BANKSEL (--pno-banksel)" + +#: rc.cpp:370 +#, no-c-format +msgid "Use large stac&k model (--pstack-model=large)" +msgstr "Utiliser le modèle de grande pile ((--pstac&k-model=large)" + +#: rc.cpp:373 +#, no-c-format +msgid "Alt+K" +msgstr "Alt+K" + +#: rc.cpp:376 +#, no-c-format +msgid "Show more debug info in assembl&y output (--debug-xtra)" +msgstr "" +"Montrer plus d'information de débogage dans la sortie de l'assembleur (--" +"debug-xtra)" + +#: rc.cpp:382 +#, no-c-format +msgid "E&xplicit enable of peepholes (--denable-peeps)" +msgstr "Activation e&xplicite des peepholes (--denable-peeps)" + +#: rc.cpp:388 +#, no-c-format +msgid "Du&mp call tree in .calltree file (--calltree)" +msgstr "" +"Faire un du&mp de l'arbre d'appel dans un fichier .calltree (--calltree)" + +#: rc.cpp:394 +#, no-c-format +msgid "Ena&ble stack optimizations (--fstack)" +msgstr "Activer les optimisations de pile (--fstack)" + +#: rc.cpp:400 +#, no-c-format +msgid "Try to use conditional BRA instead of GOTO (--optimi&ze-goto)" +msgstr "" +"Essayer d'utiliser BRA conditionnel au lieu de GOTO (--optimi&ze-goto)" + +#: rc.cpp:406 +#, no-c-format +msgid "Try to optimize some compares (--optimize-cmp)" +msgstr "Essayer d'optimiser quelques comparaisons (--optimize-cmp)" + +#: rc.cpp:410 +#, no-c-format +msgid "Thorough data flow analyis (resource intensive) (--optimize-df)" +msgstr "" +"Analyse détaillée du data flow (gourmand en ressource) (--optimize-df)" + +#: rc.cpp:417 +#, no-c-format +msgid "Processing Options" +msgstr "Traitement de Options en cours" + +#: rc.cpp:420 +#, no-c-format +msgid "Output File:" +msgstr "Fichier de Sortie :" + +#: rc.cpp:426 +#, no-c-format +msgid "Initial Port Settings" +msgstr "Réglages initiaux de port" + +#: rc.cpp:429 +#, no-c-format +msgid "" +"Tip: Toggle the initial state (high/low) of a pin by clicking its picture.\n" +"Drag it to set the type (input/output)." +msgstr "" +"Astuce : basculez l'état initial (haut/bas) d'une broche en cliquant sur " +"son image\n" +"Tirez-la pour en fixer le type (entrée/sortie)." + +#: rc.cpp:433 +#, no-c-format +msgid "Initial Variable Values" +msgstr "Valeurs intiales de variable" + +#: rc.cpp:442 +#, no-c-format +msgid "Pin Map Definitions" +msgstr "Définitions de brochage" + +#: rc.cpp:451 +#, no-c-format +msgid "Modif&y" +msgstr "Modifier" + +#: rc.cpp:457 +#, no-c-format +msgid "Rename" +msgstr "Renommer" + +#: rc.cpp:461 +#, no-c-format +msgid "PIC Programmer Config" +msgstr "Configuration du Programmateur de PIC" + +#: rc.cpp:464 +#, no-c-format +msgid "Programmer Configuration" +msgstr "Configuration du programmateur" + +#: rc.cpp:467 +#, no-c-format +msgid "&Add ..." +msgstr "&Ajout ..." + +#: rc.cpp:473 +#, no-c-format +msgid "Re&move" +msgstr "Retirer" + +#: rc.cpp:479 rc.cpp:658 +#, no-c-format +msgid "Program:" +msgstr "Programme :" + +#: rc.cpp:482 +#, no-c-format +msgid "(Program Description)" +msgstr "(Description de programme)" + +#: rc.cpp:485 +#, no-c-format +msgid "Commands" +msgstr "Commandes" + +#: rc.cpp:488 +#, no-c-format +msgid "Initialization:" +msgstr "Initialisation :" + +#: rc.cpp:491 +#, no-c-format +msgid "Read:" +msgstr "Lire :" + +#: rc.cpp:494 +#, no-c-format +msgid "Write:" +msgstr "Écrire :" + +#: rc.cpp:497 +#, no-c-format +msgid "" +"The following strings will be replaced when the command is run:\n" +"
      \n" +"
    • %port - Port that the programmer is connected to
    • \n" +"
    • %device - PIC device
    • \n" +"
    • %file - File to read from or write to
    • \n" +"
    " +msgstr "" +"Les chaînes suivants seront remplacées quand la commande sera lancée :\n" +"
      \n" +"
    • %port - Port auquel le programmateur est connecté
    • \n" +"
    • %device - composant PIC
    • \n" +"
    • %file - Fichier à lire ou à écrire
    • \n" +"
    " + +#: rc.cpp:505 +#, no-c-format +msgid "Erase:" +msgstr "Effacer :" + +#: rc.cpp:508 +#, no-c-format +msgid "Verify:" +msgstr "Vérifier :" + +#: rc.cpp:511 +#, no-c-format +msgid "Blank Check:" +msgstr "Vérification de virginté :" + +#: rc.cpp:514 +#, no-c-format +msgid "Default port:" +msgstr "Port par défaut :" + +#: rc.cpp:520 +#, no-c-format +msgid "Input" +msgstr "Entrée" + +#: rc.cpp:523 rc.cpp:536 rc.cpp:558 +#, no-c-format +msgid " V" +msgstr " V" + +#: rc.cpp:526 rc.cpp:546 +#, no-c-format +msgid "Required voltage level before the input will be considered high." +msgstr "" +"Tension requise pour que l'entrée soit considérée comme à l'état haut." + +#: rc.cpp:530 +#, no-c-format +msgid "Falling Trigger Threshold:" +msgstr "Seuil de front descendant :" + +#: rc.cpp:533 rc.cpp:539 +#, no-c-format +msgid "Required voltage level before an input will be considered low." +msgstr "Tension requise pour que l'entrée soit considérée à l'état bas." + +#: rc.cpp:543 +#, no-c-format +msgid "Rising Trigger Threshold:" +msgstr "Seuil de front montant :" + +#: rc.cpp:549 +#, no-c-format +msgid "Output" +msgstr "Sortie" + +#: rc.cpp:552 +#, no-c-format +msgid "Output High:" +msgstr "Sortie à l'état haut :" + +#: rc.cpp:555 rc.cpp:561 +#, no-c-format +msgid "Voltage level for high on logic components." +msgstr "Niveau de tension pour l'état haut pour les composants logiques." + +#: rc.cpp:565 +#, no-c-format +msgid "High Output Impedance:" +msgstr "Impédance à l'état haut :" + +#: rc.cpp:568 rc.cpp:578 +#, no-c-format +msgid "This is the output impedance when the output is high." +msgstr "C'est l'impédance de sortie quand la sortie est à l'état haut." + +#: rc.cpp:571 +#, no-c-format +msgid "Low Output Impedance:" +msgstr "Impédance de sortie à l'état bas :" + +#: rc.cpp:574 rc.cpp:586 +#, no-c-format +msgid "This is the output impedance when the output is low." +msgstr "C'est l'impédance de sortie quand celle-ci est à l'état bas." + +#: rc.cpp:583 +#, no-c-format +msgid "Floating" +msgstr "Flottant" + +#: rc.cpp:590 +#, no-c-format +msgid "" +"Here, you can configure the behaviour of logic components.\n" +"\n" +"These values will apply to all components, apart from the PIC, whose pins' " +"impedances depend on the pin in use." +msgstr "" +"Ici, vous pouvez configurer le comportment des composants logiques.\n" +"\n" +"Ces valeurs s'appliqueront à tous les composants, excepté le PIC, dont " +"l'impédance des broches dépend de la broche utilisée." + +#: rc.cpp:595 +#, no-c-format +msgid "New Project" +msgstr "Nouveau Projet" + +#: rc.cpp:598 +#, no-c-format +msgid "Final location:" +msgstr "Emplacement final :" + +#: rc.cpp:601 +#, no-c-format +msgid "/" +msgstr "/" + +#: rc.cpp:604 +#, no-c-format +msgid "Location:" +msgstr "Emplacement :" + +#: rc.cpp:607 +#, no-c-format +msgid "New Project Details" +msgstr "Détails du Nouveau Projet" + +#: rc.cpp:610 +#, no-c-format +msgid "Project Name:" +msgstr "Nom du Projet :" + +#: rc.cpp:613 +#, no-c-format +msgid "Create Subproject" +msgstr "Créer Sous-projet" + +#: rc.cpp:616 +#, no-c-format +msgid "Subproject Details" +msgstr "Détails de sous-projet" + +#: rc.cpp:619 +#, no-c-format +msgid "Target File:" +msgstr "Fichier cible :" + +#: rc.cpp:622 rc.cpp:634 +#, no-c-format +msgid "Type:" +msgstr "Type :" + +#: rc.cpp:637 +#, no-c-format +msgid "Name:" +msgstr "Nom :" + +#: rc.cpp:643 +#, no-c-format +msgid "" +"The variable name of the pin mapping - this must be a valid Microbe " +"variable name." +msgstr "" +"Le nom de variable du brochage - ce doit être un nom de variable Microbe " +"valide." + +#: rc.cpp:649 +#, no-c-format +msgid "Keypad (4x3)" +msgstr "Clavier (4x3)" + +#: rc.cpp:652 +#, no-c-format +msgid "Keypad (4x4)" +msgstr "Clavier (4x4)" + +#: rc.cpp:664 rc.cpp:667 +#, no-c-format +msgid "Output Method" +msgstr "Méthode de Sortie" + +#: rc.cpp:670 +#, no-c-format +msgid "Displa&y directly" +msgstr "Afficher directement" + +#: rc.cpp:673 +#, no-c-format +msgid "Save to file" +msgstr "Enregistrer dans un Fichier" + +#: rc.cpp:676 +#, no-c-format +msgid "Output File Options" +msgstr "Options du fichier de sortie" + +#: rc.cpp:679 +#, no-c-format +msgid "Load File in &New View" +msgstr "Ouvrir le fichier dans une &Nouvelle vue" + +#: rc.cpp:682 +#, no-c-format +msgid "&Add to Project" +msgstr "&Ajout au Projet" + +#: rc.cpp:688 +#, no-c-format +msgid "Reuse the same output view for code generation" +msgstr "Réutiliser la même vue de sortie pour la génération de code" + +#: rc.cpp:692 +#, no-c-format +msgid "Show voltage bars &on electronic components" +msgstr "M&ontrer les barres de tension sur les composants électroniques" + +#: rc.cpp:698 +#, no-c-format +msgid "Grid Colour" +msgstr "Couleur de Grille" + +#: rc.cpp:701 +#, no-c-format +msgid "The grid color in the work area." +msgstr "La couleur de la grille dans la zone de travail." + +#: rc.cpp:704 +#, no-c-format +msgid "Show &grid:" +msgstr "Montrer la &grille :" + +#: rc.cpp:707 +#, no-c-format +msgid "Alt+G" +msgstr "Alt+G" + +#: rc.cpp:710 +#, no-c-format +msgid "Maximum undo steps for work area:" +msgstr "Nombre maximum d'étapes \"défaire\" dans la zone de travail :" + +#: rc.cpp:713 +#, no-c-format +msgid "" +"Maximum undo steps for work area. This doesn't apply to text documents - " +"that is configurable seperately under Configure Editor." +msgstr "" +"Nombre maximum d'étapes \"défaire\" dans la zone de travail. Ça ne " +"s'applique pas aux documents texte - on peut le configurer séparément sous " +"l'éditeur de configuration." + +#: rc.cpp:716 +#, no-c-format +msgid "Convenience" +msgstr "Commodités" + +#: rc.cpp:719 +#, no-c-format +msgid "Restore opened doc&uments on startup" +msgstr "Restaurer les doc&uments ouverts au démarrage" + +#: rc.cpp:722 +#, no-c-format +msgid "Alt+U" +msgstr "Alt+U" + +#: rc.cpp:725 +#, no-c-format +msgid "Raise the &appropriate item selector on creating a new document" +msgstr "" +"Faire &apparaître le sélecteur d'items approprié à la création d'un nouveau " +"document" + +#: rc.cpp:731 +#, no-c-format +msgid "Raise the &Messages log when compiling" +msgstr "Faire apparaître le journal de &Messages en cours de compilation" + +#: rc.cpp:737 +#, no-c-format +msgid "Display Refresh Rate" +msgstr "Vitesse de rafraîchissement de l'affichage" + +#: rc.cpp:740 +#, no-c-format +msgid "Refresh rate:" +msgstr "Vitesse de rafraîchissement :" + +#: rc.cpp:743 +#, no-c-format +msgid "Medium (50 FPS)" +msgstr "Moyenne (50 FPS)" + +#: rc.cpp:746 +#, no-c-format +msgid "" +"This is the number of times per second that the work area view is updated; " +"a compromise between CPU usage and smoothness of display." +msgstr "" +"C'est le nombre de fois par seconde que la zone de travail sera mise à " +"jour ; un compromis entre la vitesse du processeur et la fluidité de " +"l'affichage." + +#: rc.cpp:752 rc.cpp:767 rc.cpp:779 rc.cpp:812 +#, no-c-format +msgid "&File" +msgstr "&Fichier" + +#: rc.cpp:755 rc.cpp:776 rc.cpp:788 rc.cpp:794 rc.cpp:803 rc.cpp:824 +#, no-c-format +msgid "&Tools" +msgstr "Ou&tils" + +#: rc.cpp:758 +#, no-c-format +msgid "&Debug" +msgstr "&Débogage" + +#: rc.cpp:761 rc.cpp:830 +#, no-c-format +msgid "Main Toolbar" +msgstr "Barre d'outils principale" + +#: rc.cpp:764 +#, no-c-format +msgid "Debugger" +msgstr "Débogueur" + +#: rc.cpp:770 rc.cpp:785 rc.cpp:818 +#, no-c-format +msgid "&View" +msgstr "&Voir" + +#: rc.cpp:773 +#, no-c-format +msgid "&Project" +msgstr "&Projet" + +#: rc.cpp:782 rc.cpp:815 +#, no-c-format +msgid "&Edit" +msgstr "&Editer" + +#: rc.cpp:791 +#, no-c-format +msgid "Tools" +msgstr "Outils" + +#: rc.cpp:797 rc.cpp:806 +#, no-c-format +msgid "Routing Mode" +msgstr "Mode de routage" + +#: rc.cpp:821 +#, no-c-format +msgid "&Code Folding" +msgstr "Pliage du &Code" + +#: rc.cpp:827 +#, no-c-format +msgid "&Settings" +msgstr "&Réglages" diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..a41144e --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,88 @@ +## Makefile.am for ktechlab + +# this is the program that gets installed. it's name is used for all +# of the other Makefile.am variables +bin_PROGRAMS = ktechlab + +# set the include path for X, qt and KDE +INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/drawparts \ + -I$(top_srcdir)/src/electronics -I$(top_srcdir)/src/electronics/components \ + -I$(top_srcdir)/src/electronics/simulation -I$(top_srcdir)/src/flowparts -I$(top_srcdir)/src/gui \ + -I$(top_srcdir)/src/languages -I$(top_srcdir)/src/mechanics -I$(top_srcdir)/src/micro $(all_includes) + +# the library search path. +ktechlab_LDFLAGS = -module $(all_libraries) $(KDE_RPATH) + +# the libraries to link against. +ktechlab_LDADD = $(top_builddir)/src/gui/libgui.la \ + $(top_builddir)/src/micro/libmicro.la $(top_builddir)/src/flowparts/libflowparts.la \ + $(top_builddir)/src/mechanics/libmechanics.la $(top_builddir)/src/electronics/libelectronics.la \ + $(top_builddir)/src/electronics/simulation/libelements.la $(top_builddir)/src/electronics/components/libcomponents.la \ + $(top_builddir)/src/languages/liblanguages.la $(top_builddir)/src/drawparts/libdrawparts.la \ + $(top_builddir)/src/core/libcore.la -lkutils $(LIB_GPSIM) -lktexteditor $(LIB_KFILE) $(LIB_KDEPRINT) + +# which sources should be compiled for ktechlab +ktechlab_SOURCES = ktechlab.cpp node.cpp connector.cpp itemlibrary.cpp \ + libraryitem.cpp projectmanager.cpp picitem.cpp variant.cpp canvasitemparts.cpp \ + flowcontainer.cpp microsettings.cpp fpnode.cpp cells.cpp asmformatter.cpp conrouter.cpp \ + nodegroup.cpp canvasmanipulator.cpp iteminterface.cpp itemgroup.cpp ciwidgetmgr.cpp \ + filemetainfo.cpp resizeoverlay.cpp document.cpp view.cpp docmanager.cpp cnitem.cpp \ + item.cpp cnitemgroup.cpp itemview.cpp itemdocument.cpp textview.cpp \ + textdocument.cpp circuitdocument.cpp flowcodedocument.cpp icnview.cpp icndocument.cpp \ + viewcontainer.cpp circuitview.cpp flowcodeview.cpp eventinfo.cpp oscilloscopedata.cpp \ + itemdocumentdata.cpp docmanageriface.cpp documentiface.cpp viewiface.cpp \ + docmanageriface.skel viewiface.skel documentiface.skel simulator.cpp katemdi.cpp \ + debugmanager.cpp recentfilesaction.cpp variablelabel.cpp + +ktechlab_PCH = AUTO + + +# these are the headers for your project +noinst_HEADERS = ktechlab.h node.h connector.h itemlibrary.h libraryitem.h \ + projectmanager.h picitem.h canvasitemparts.h microsettings.h fpnode.h cells.h \ + asmformatter.h conrouter.h nodegroup.h canvasmanipulator.h iteminterface.h itemgroup.h \ + ciwidgetmgr.h filemetainfo.h resizeoverlay.h document.h view.h docmanager.h cnitem.h \ + item.h cnitemgroup.h itemview.h itemdocument.h textview.h textdocument.h \ + circuitdocument.h flowcodedocument.h icnview.h icndocument.h viewcontainer.h \ + circuitview.h flowcodeview.h eventinfo.h oscilloscopedata.h itemdocumentdata.h \ + docmanageriface.h documentiface.h viewiface.h simulator.h katemdi.h debugmanager.h \ + recentfilesaction.h variablelabel.h + + +# client stuff + + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + + +messages: rc.cpp + $(EXTRACTRC) `find . -name "*.rc" -o -name "*.ui" -o -name "*.kcfg"` > 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)/ktechlab.pot; \ + fi + +#KDE_ICON = ktechlab +#KDE_ICON = AUTO + +# this is where the kdelnk file will go +kdelnkdir = $(kde_appsdir)/Development +kdelnk_DATA = ktechlab.desktop + +# this is where the XML-GUI resource file goes +rcdir = $(kde_datadir)/ktechlab +rc_DATA = ktechlabui.rc error_messages_en_gb ktechlabcircuitui.rc \ + ktechlabflowcodeui.rc ktechlabitemviewui.rc ktechlabmechanicsui.rc ktechlabtextui.rc ktechlabkateui.rc + +SUBDIRS = core gui flowparts micro mechanics electronics languages drawparts +#iconsdir = $(kde_datadir)/ktechlab/icons + + +mimedir = $(kde_mimedir)/application +mime_DATA = x-circuit.desktop x-flowcode.desktop x-ktechlab.desktop x-microbe.desktop +EXTRA_DIST = $(mime_DATA) + +katesyntaxdir = $(kde_datadir)/katepart/syntax +katesyntax_DATA = microbe.xml + diff --git a/src/asmformatter.cpp b/src/asmformatter.cpp new file mode 100644 index 0000000..fb77789 --- /dev/null +++ b/src/asmformatter.cpp @@ -0,0 +1,209 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "asmformatter.h" +#include "core/ktlconfig.h" +#include "picinfo12bit.h" +#include "picinfo14bit.h" +#include "picinfo16bit.h" + +static QString extractComment( const QString & line ) +{ + int pos = line.find( ';' ); + + if ( pos == -1 ) + return ""; + + return line.right( line.length() - pos ); +} + + +//BEGIN class AsmFormatter +AsmFormatter::AsmFormatter() +{ +} + + +AsmFormatter::~AsmFormatter() +{ +} + + +QString AsmFormatter::tidyAsm( QStringList lines ) +{ + // Update our indentation values from config + m_indentAsmName = KTLConfig::indentAsmName(); + m_indentAsmData = KTLConfig::indentAsmData(); + m_indentEqu = KTLConfig::indentEqu(); + m_indentEquValue = KTLConfig::indentEquValue(); + m_indentComment = m_indentEquComment = KTLConfig::indentComment(); + + QStringList::iterator end = lines.end(); + for ( QStringList::iterator slit = lines.begin(); slit != end; ++slit ) + { + switch ( lineType(*slit) ) + { + case Other: + break; + + case Equ: + *slit = tidyEqu( *slit ); + break; + + case Instruction: + *slit = tidyInstruction( *slit ); + break; + } + } + + QString code; + + for ( QStringList::iterator slit = lines.begin(); slit != end; ++slit ) + code.append( *slit + '\n' ); + + return code; +} + + +void AsmFormatter::pad( QString & text, int length ) +{ + int padLength = length - text.length(); + if ( padLength <= 0 ) + return; + + QString pad; + pad.fill( ' ', padLength ); + text += pad; +} + + +QString AsmFormatter::tidyInstruction( const QString & oldLine ) +{ + InstructionParts parts( oldLine ); + QString line; + + if ( !parts.label().isEmpty() ) + line = parts.label() + ' '; + pad( line, m_indentAsmName ); + + if ( !parts.operand().isEmpty() ) + line += parts.operand() + ' '; + pad( line, m_indentAsmData ); + + if ( !parts.operandData().isEmpty() ) + line += parts.operandData(); + pad( line, m_indentComment ); + + if ( parts.comment().isEmpty() ) + { + // Remove any whitespace at the end if we're not padding out a comment + while ( !line.isEmpty() && line[ line.length() - 1 ].isSpace() ) + line.remove( line.length() -1, 1 ); + } + else + line += parts.comment(); + + return line; +} + + +QString AsmFormatter::tidyEqu( const QString & oldLine ) +{ + QString comment = extractComment( oldLine ); + QString code = oldLine; + code.remove( comment ); + code = code.simplifyWhiteSpace(); + + QStringList parts = QStringList::split( ' ', code ); + + QString pad0, pad1, pad2; + pad0.fill( ' ', m_indentEqu - (*parts.at(0)).length() ); + pad1.fill( ' ', m_indentEquValue - m_indentEqu - (*parts.at(1)).length() ); + pad2.fill( ' ', m_indentEquComment - m_indentEquValue - m_indentEqu - (*parts.at(2)).length() ); + + code = *parts.at(0) + pad0; + code += *parts.at(1) + pad1; + code += *parts.at(2); + if ( !comment.isEmpty() ) + { + code += pad2; + code += comment; + } + + return code; +} + + +AsmFormatter::LineType AsmFormatter::lineType( QString line ) +{ + line = line.simplifyWhiteSpace(); + + line.remove( extractComment( line ) ); + + QStringList parts = QStringList::split( ' ', line ); + QStringList::iterator end = parts.end(); + for ( QStringList::iterator it = parts.begin(); it != end; ++it ) + { + if ( (*it).lower() == "equ" ) + return Equ; + } + + InstructionParts instructionParts( line ); + if ( !instructionParts.operand().isEmpty() ) + return Instruction; + + return Other; +} +//END class AsmFormatter + + + +//BEGIN class InstructionParts +InstructionParts::InstructionParts( QString line ) +{ + m_comment = extractComment( line ); + line.remove( m_comment ); + + line = line.simplifyWhiteSpace(); + QStringList parts = QStringList::split( ' ', line ); + + bool foundOperand = false; + QStringList::iterator end = parts.end(); + for ( QStringList::iterator it = parts.begin(); it != end; ++it ) + { + if ( foundOperand ) + { + // Already found the operand, so anything else must be the operand + // data. + + if ( m_operandData.isEmpty() ) + m_operandData = *it; + else + m_operandData += ' ' + *it; + + continue; + } + + if ( PicAsm12bit::self()->operandList().contains( (*it).upper() ) + || PicAsm14bit::self()->operandList().contains( (*it).upper() ) + || PicAsm16bit::self()->operandList().contains( (*it).upper() ) ) + { + m_operand = *it; + foundOperand = true; + } + else + { + // Must be a label + m_label = *it; + } + } +} +//END class InstructionParts + diff --git a/src/asmformatter.h b/src/asmformatter.h new file mode 100644 index 0000000..a6fa361 --- /dev/null +++ b/src/asmformatter.h @@ -0,0 +1,76 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ASMFORMATTER_H +#define ASMFORMATTER_H + +#include + +/** +@author David Saxton + */ +class InstructionParts +{ + public: + /** + * Breaks up the line into parts. + */ + InstructionParts( QString line ); + + QString label() const { return m_label; } + QString operand() const { return m_operand; } + QString operandData() const { return m_operandData; } + QString comment() const { return m_comment; } + + protected: + QString m_label; + QString m_operand; + QString m_operandData; + QString m_comment; ///< includes the ";" part +}; + +/** +@author David Saxton +*/ +class AsmFormatter +{ + public: + AsmFormatter(); + ~AsmFormatter(); + + enum LineType + { + Equ, + Instruction, // could include label + Other, // eg comments, __config + }; + + QString tidyAsm( QStringList lines ); + + static LineType lineType( QString line ); + + protected: + QString tidyInstruction( const QString & line ); + QString tidyEqu( const QString & line ); + /** + * Appends spaces to the end of text until it is greater or equakl to + * length. + */ + static void pad( QString & text, int length ); + + int m_indentAsmName; + int m_indentAsmData; + int m_indentEqu; + int m_indentEquValue; + int m_indentEquComment; + int m_indentComment; +}; + +#endif diff --git a/src/canvasitemparts.cpp b/src/canvasitemparts.cpp new file mode 100644 index 0000000..7f4b03d --- /dev/null +++ b/src/canvasitemparts.cpp @@ -0,0 +1,553 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasitemparts.h" +#include "cells.h" +#include "cnitem.h" +#include "icndocument.h" + +#include + + +//BEGIN Class GuiPart +GuiPart::GuiPart( CNItem *parent, const QRect & r, QCanvas * canvas ) + : QObject(parent), + QCanvasRectangle( r, canvas ), + m_angleDegrees(0), + p_parent(parent), + b_pointsAdded(false), + m_originalRect(r) +{ + connect( parent, SIGNAL(movedBy(double, double )), this, SLOT(slotMoveBy(double, double )) ); + setZ( parent->z() + 0.5 ); +} + + +GuiPart::~GuiPart() +{ + hide(); +} + + +void GuiPart::setAngleDegrees( int angleDegrees ) +{ + m_angleDegrees = angleDegrees; + posChanged(); + if (canvas()) + canvas()->setChanged( boundingRect() ); +} + + +void GuiPart::setGuiPartSize( int width, int height ) +{ + updateConnectorPoints(false); + setSize( width, height ); + posChanged(); +} + + +void GuiPart::initPainter( QPainter &p ) +{ + if ( (m_angleDegrees%180) == 0 ) + return; + + p.translate( int(x()+(width()/2)), int(y()+(height()/2)) ); + p.rotate(m_angleDegrees); + p.translate( -int(x()+(width()/2)), -int(y()+(height()/2)) ); +} + + +void GuiPart::deinitPainter( QPainter &p ) +{ + if ( (m_angleDegrees%180) == 0 ) + return; + + p.translate( int(x()+(width()/2)), int(y()+(height()/2)) ); + p.rotate(-m_angleDegrees); + p.translate( -int(x()+(width()/2)), -int(y()+(height()/2)) ); +} + + +void GuiPart::slotMoveBy( double dx, double dy ) +{ + if ( dx==0 && dy==0 ) + return; + + moveBy( dx, dy ); + posChanged(); +} + + +void GuiPart::updateConnectorPoints( bool add ) +{ + ICNDocument *icnd = dynamic_cast(p_parent->itemDocument()); + if ( !icnd) + return; + + Cells * cells = icnd->cells(); + if (!cells) + return; + + if ( add == b_pointsAdded ) + return; + + b_pointsAdded = add; + + int mult = add ? 1 : -1; + int sx = int(x()/8); + int sy = int(y()/8); + int ex = int((x()+width())/8); + int ey = int((y()+height())/8); + + for ( int x=sx; x<=ex; ++x ) + { + for ( int y=sy; y<=ey; ++y ) + { + if ( icnd->isValidCellReference( x, y ) ) + (*cells)[x][y].CIpenalty += mult*ICNDocument::hs_item/2; + } + } +} + + +QRect GuiPart::drawRect() +{ + QRect dr = rect(); + if ( m_angleDegrees%180 != 0 ) + { + QWMatrix m; + m.translate( int(x()+(width()/2)), int(y()+(height()/2)) ); + + if ( (m_angleDegrees%180) != 0 ) + m.rotate(-m_angleDegrees); + + m.translate( -int(x()+(width()/2)), -int(y()+(height()/2)) ); + + dr = m.mapRect(dr); + } + return dr; +} +//END Class GuiPart + + + +//BEGIN Class Text +Text::Text( const QString &text, CNItem *parent, const QRect & r, QCanvas * canvas, int flags ) + : GuiPart( parent, r, canvas ) +{ + m_flags = flags; + setText(text); +} + + +Text::~Text() +{ +} + + +bool Text::setText( const QString & text ) +{ + if ( m_text == text ) + return false; + + updateConnectorPoints(false); + + m_text = text; + return true; +} + + +void Text::setFlags( int flags ) +{ + updateConnectorPoints( false ); + m_flags = flags; +} + + +void Text::drawShape( QPainter & p ) +{ + initPainter(p); + p.setFont( p_parent->font() ); + p.drawText( drawRect(), m_flags, m_text ); + deinitPainter(p); +} + + +QRect Text::recommendedRect() const +{ + return QFontMetrics( p_parent->font() ).boundingRect( m_originalRect.x(), m_originalRect.y(), m_originalRect.width(), m_originalRect.height(), m_flags, m_text ); +} +//END Class Text + + + +//BEGIN Class Widget +Widget::Widget( const QString & id, CNItem * parent, const QRect & r, QCanvas * canvas ) + : GuiPart( parent, r, canvas ) +{ + m_id = id; + show(); +} + +Widget::~Widget() +{ +} + + +int Widget::rtti() const +{ + return ItemDocument::RTTI::Widget; +} + + +void Widget::setEnabled( bool enabled ) +{ + widget()->setEnabled(enabled); +} + + +void Widget::posChanged() +{ + // Swap around the width / height if we are rotated at a non-half way around + if ( m_angleDegrees%90 != 0 ) + widget()->setFixedSize( QSize( height(), width() ) ); + else + widget()->setFixedSize( size() ); + + widget()->move( int(x()), int(y()) ); +} + + +void Widget::drawShape( QPainter &p ) +{ +// initPainter(p); + p.drawPixmap( int(x()), int(y()), QPixmap::grabWidget( widget() ) ); +// deinitPainter(p); +} +//END Class Widget + + +//BEGIN Class ToolButton +ToolButton::ToolButton( QWidget *parent ) + : QToolButton(parent) +{ + m_angleDegrees = 0; + if ( QFontInfo(m_font).pixelSize() > 11 ) // It has to be > 11, not > 12, as (I think) pixelSize() rounds off the actual size + m_font.setPixelSize(12); +} + + +void ToolButton::drawButtonLabel( QPainter * p ) +{ + if ( m_angleDegrees % 180 == 0 || text().isEmpty() ) + { + QToolButton::drawButtonLabel(p); + return; + } + + double dx = size().width()/2; + double dy = size().height()/2; + + p->translate( dx, dy ); + p->rotate( m_angleDegrees ); + p->translate( -dx, -dy ); + + p->translate( -dy+dx, 0 ); + + int m = width() > height() ? width() : height(); + + p->setPen( Qt::black ); + p->drawText( isDown()?1:0, isDown()?1:0, m, m, Qt::AlignVCenter | Qt::AlignHCenter, text() ); + + p->translate( dy-dx, 0 ); + + p->translate( dx, dy ); + p->rotate( -m_angleDegrees ); + p->translate( -dx, -dy ); +} +//END Class ToolButton + + +//BEGIN Class Button +Button::Button( const QString & id, CNItem * parent, bool isToggle, const QRect & r, QCanvas * canvas ) + : Widget( id, parent, r, canvas ) +{ + b_isToggle = isToggle; + m_button = new ToolButton(0l); + m_button->setUsesTextLabel(false); + m_button->setToggleButton(b_isToggle); + connect( m_button, SIGNAL(pressed()), this, SLOT(slotStateChanged()) ); + connect( m_button, SIGNAL(released()), this, SLOT(slotStateChanged()) ); + posChanged(); +} + + +Button::~Button() +{ + delete m_button; +} + + +void Button::setToggle( bool toggle ) +{ + if ( b_isToggle == toggle ) + return; + + if (b_isToggle) + { + // We must first untoggle it, else it'll be forever stuck... + setState(false); + } + + b_isToggle = toggle; + m_button->setToggleButton(b_isToggle); +} + + +void Button::posChanged() +{ + Widget::posChanged(); + m_button->setAngleDegrees(m_angleDegrees); +} + +void Button::slotStateChanged() +{ + parent()->buttonStateChanged( id(), m_button->isDown() || m_button->isOn() ); +} +QWidget* Button::widget() const +{ + return m_button; +} +void Button::setPixmap( const QPixmap &p ) +{ + m_button->setPixmap(p); +} +void Button::setState( bool state ) +{ + if ( this->state() == state ) + return; + + if ( isToggle() ) + m_button->setOn(state); + else + m_button->setDown(state); + + slotStateChanged(); +} +bool Button::state() const +{ + if ( isToggle() ) + return m_button->state(); + else + return m_button->isDown(); +} + + +QRect Button::recommendedRect() const +{ + QSize sizeHint = m_button->sizeHint(); + if ( sizeHint.width() < m_originalRect.width() ) + sizeHint.setWidth( m_originalRect.width() ); + + // Hmm...for now, lets just keep the recomended rect the same height as the original rect + sizeHint.setHeight( m_originalRect.height() ); + + int hdw = (sizeHint.width() - m_originalRect.width())/2; + int hdh = (sizeHint.height() - m_originalRect.height())/2; + + return QRect( m_originalRect.x()-hdw, m_originalRect.y()-hdh, sizeHint.width(), sizeHint.height() ); +} + + +void Button::setText( const QString &text ) +{ + if ( m_button->text() == text ) + return; + + updateConnectorPoints(false); + + m_button->setUsesTextLabel(true); + m_button->setText(text); + m_button->setTextLabel(text); + canvas()->setChanged( rect() ); + p_parent->updateAttachedPositioning(); +} + + +void Button::mousePressEvent( QMouseEvent *e ) +{ + if ( !m_button->isEnabled() ) + return; + + QMouseEvent event( QEvent::MouseButtonPress, e->pos()-QPoint(int(x()),int(y())), e->button(), e->state() ); + m_button->mousePressEvent(&event); + if (event.isAccepted()) + e->accept(); + canvas()->setChanged( rect() ); +} + + +void Button::mouseReleaseEvent( QMouseEvent *e ) +{ + QMouseEvent event( QEvent::MouseButtonRelease, e->pos()-QPoint(int(x()),int(y())), e->button(), e->state() ); + m_button->mouseReleaseEvent(&event); + if (event.isAccepted()) + e->accept(); + canvas()->setChanged( rect() ); +} + + +void Button::enterEvent() +{ + m_button->enterEvent(); +// m_button->setFocus(); +// bool hasFocus = m_button->hasFocus(); +// m_button->setAutoRaise(true); +// m_button->setOn(true); +} + +void Button::leaveEvent() +{ + m_button->leaveEvent(); +// m_button->clearFocus(); +// bool hasFocus = m_button->hasFocus(); +// m_button->setAutoRaise(false); +// m_button->setOn(false); +} +//END Class Button + + +//BEGIN Class SliderWidget +SliderWidget::SliderWidget( QWidget *parent ) + : QSlider(parent) +{ + setWFlags(WNoAutoErase|WRepaintNoErase); +} +//END Class SliderWidget + + +//BEGIN Class Slider +Slider::Slider( const QString & id, CNItem * parent, const QRect & r, QCanvas * canvas ) + : Widget( id, parent, r, canvas ) +{ + m_orientation = Qt::Vertical; + m_slider = new SliderWidget(0l); + m_slider->setPaletteBackgroundColor(Qt::white); + m_slider->setPaletteForegroundColor(Qt::white); + m_slider->setEraseColor(Qt::white); + m_slider->setBackgroundMode( Qt::NoBackground ); + connect( m_slider, SIGNAL(valueChanged(int)), this, SLOT(slotValueChanged(int)) ); + posChanged(); +} + + +Slider::~Slider() +{ + delete m_slider; +} + + +QWidget* Slider::widget() const +{ + return m_slider; +} + + +int Slider::value() const +{ + return m_slider->value(); +} + +void Slider::setValue( int value ) +{ + m_slider->setValue(value); +} + + +void Slider::mousePressEvent( QMouseEvent *e ) +{ + QMouseEvent event( QEvent::MouseButtonPress, e->pos()-QPoint(int(x()),int(y())), e->button(), e->state() ); + m_slider->mousePressEvent(&event); + if (event.isAccepted()) + e->accept(); + canvas()->setChanged( rect() ); +} + +void Slider::mouseReleaseEvent( QMouseEvent *e ) +{ + QMouseEvent event( QEvent::MouseButtonRelease, e->pos()-QPoint(int(x()),int(y())), e->button(), e->state() ); + m_slider->mouseReleaseEvent(&event); + if (event.isAccepted()) + e->accept(); + canvas()->setChanged( rect() ); +} + +void Slider::mouseDoubleClickEvent ( QMouseEvent *e ) +{ + QMouseEvent event( QEvent::MouseButtonDblClick, e->pos()-QPoint(int(x()),int(y())), e->button(), e->state() ); + m_slider->mouseDoubleClickEvent(&event); + if (event.isAccepted()) + e->accept(); + canvas()->setChanged( rect() ); +} + +void Slider::mouseMoveEvent( QMouseEvent *e ) +{ + QMouseEvent event( QEvent::MouseMove, e->pos()-QPoint(int(x()),int(y())), e->button(), e->state() ); + m_slider->mouseMoveEvent(&event); + if (event.isAccepted()) + e->accept(); +} + +void Slider::wheelEvent( QWheelEvent *e ) +{ + QWheelEvent event( e->pos()-QPoint(int(x()),int(y())), e->delta(), e->state(), e->orientation() ); + m_slider->wheelEvent(&event); + if (event.isAccepted()) + e->accept(); + canvas()->setChanged( rect() ); +} + +void Slider::enterEvent() +{ + m_slider->enterEvent(); +} + +void Slider::leaveEvent() +{ + m_slider->leaveEvent(); +} + +void Slider::slotValueChanged( int value ) +{ + parent()->itemDocument()->setModified(true); + parent()->sliderValueChanged(id(),value); +} + +void Slider::setOrientation( Qt::Orientation o ) +{ + m_orientation = o; + posChanged(); +} + +void Slider::posChanged() +{ + Widget::posChanged(); + + if ( m_orientation == Qt::Vertical ) + m_slider->setOrientation( (m_angleDegrees%180 == 0) ? Qt::Vertical : Qt::Horizontal ); + + else + m_slider->setOrientation( (m_angleDegrees%180 == 0) ? Qt::Horizontal : Qt::Vertical ); +} +//END Class Slider + + +#include "canvasitemparts.moc" diff --git a/src/canvasitemparts.h b/src/canvasitemparts.h new file mode 100644 index 0000000..44bd6be --- /dev/null +++ b/src/canvasitemparts.h @@ -0,0 +1,291 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef CANVASITEMPARTS_H +#define CANVASITEMPARTS_H + +#include +#include +#include +#include + +class Cells; +class CIWidgetMgr; +class CNItem; +class SliderWidget; +class ToolButton; +class QString; + +class GuiPart : public QObject, public QCanvasRectangle +{ + Q_OBJECT + public: + /** + * Create a GuiPart. Control the position using setGuiPartSize, instead + * of calling QCanvasRectangle::setSize. This allows GuiPart to know + * when its size has been changed + */ + GuiPart( CNItem *parent, const QRect & r, QCanvas * canvas ); + virtual ~GuiPart(); + + virtual QRect recommendedRect() const { return m_originalRect; } + void setOriginalRect( const QRect & r ) { m_originalRect = r; } + + virtual void updateConnectorPoints( bool add ); + + /** + * Set the angle that the GuiPart draws itself (if the GuiPart chooses + * to use it by calling initPainter and deinitPainter from drawShape). + * Note that this doesn't affect the rectangle position that the + * GuiPart is in. The rotation is taken to be about the center of the + * rectangle. + */ + void setAngleDegrees( int angleDegrees ); + /** + * Control the size. Call this instead of QCanvasRectangle::setSize. In + * turn, this function will notify subclasses via posChanged(); + */ + void setGuiPartSize( int width, int height ); + /** + * Returns the rectangle to draw in to compensate for rotation of + * the QPainter + */ + QRect drawRect(); + + int angleDegrees() const { return m_angleDegrees; } + CNItem *parent() const { return p_parent; } + + protected: + /** + * Called when the size or angle changes + */ + virtual void posChanged() {;} + /** + * Rotate / etc the painter. You must call deinitPainter after + * calling this function. + */ + void initPainter( QPainter & p ); + /** + * Complement function to initPainter - restores painter to normal + * transform + */ + void deinitPainter( QPainter & p ); + int m_angleDegrees; + CNItem *p_parent; + bool b_pointsAdded; + QRect m_originalRect; + + private slots: + void slotMoveBy( double dx, double dy ); +}; + + +/** +@short Stores internal information about text associated with CNItem +@author David Saxton +*/ +class Text : public GuiPart +{ + Q_OBJECT + public: + Text( const QString &text, CNItem *parent, const QRect & r, QCanvas * canvas, int flags = Qt::AlignHCenter | Qt::AlignVCenter ); + ~Text(); + + /** + * Set the text, returning true if the size of this Text on the canvas + * has changed. + */ + bool setText( const QString & text ); + virtual QRect recommendedRect() const; + virtual void drawShape ( QPainter & p ); + /** + * The text flags (see QPainter::drawText) - Qt::AlignmentFlags and + * Qt::TextFlags OR'd together. + */ + int flags() const { return m_flags; } + /** + * @see flags + */ + void setFlags( int flags ); + + protected: + QString m_text; + int m_flags; +}; +typedef QMap > TextMap; + + +/** +@short Base class for embedding Qt Widgets into the canvas +@author David Saxton +*/ +class Widget : public GuiPart +{ + public: + Widget( const QString & id, CNItem *parent, const QRect & r, QCanvas * canvas ); + ~Widget(); + + virtual int rtti() const; + + virtual QWidget *widget() const = 0; + QString id() const { return m_id; } + + /** + * Set the widget enabled/disabled + */ + void setEnabled( bool enabled ); + + virtual void enterEvent() {}; + virtual void leaveEvent() {}; + + /** + * Mouse was pressed. pos is given relative to CNItem position. + */ + virtual void mousePressEvent( QMouseEvent *e ) { Q_UNUSED(e); } + /** + * Mouse was released. pos is given relative to CNItem position. + */ + virtual void mouseReleaseEvent( QMouseEvent *e ) { Q_UNUSED(e); } + /** + * Mouse was double clicked. pos is given relative to CNItem position. + */ + virtual void mouseDoubleClickEvent( QMouseEvent *e ) { Q_UNUSED(e); } + /** + * Mouse was moved. pos is given relative to CNItem position. + */ + virtual void mouseMoveEvent( QMouseEvent *e ) { Q_UNUSED(e); } + /** + * Mouse was scrolled. pos is given relative to CNItem position. + */ + virtual void wheelEvent( QWheelEvent *e ) { Q_UNUSED(e); } + + virtual void drawShape( QPainter &p ); + + protected: + virtual void posChanged(); + QString m_id; +}; + + +class ToolButton : public QToolButton +{ + public: + ToolButton( QWidget* parent ); + + virtual void mousePressEvent( QMouseEvent *e ) { QToolButton::mousePressEvent(e); } + virtual void mouseReleaseEvent( QMouseEvent *e ) { QToolButton::mouseReleaseEvent(e); } + virtual void mouseDoubleClickEvent ( QMouseEvent *e ) { QToolButton::mouseDoubleClickEvent(e); } + virtual void mouseMoveEvent( QMouseEvent *e ) { QToolButton::mouseMoveEvent(e); } + virtual void wheelEvent( QWheelEvent *e ) { QToolButton::wheelEvent(e); } + virtual void enterEvent() { QToolButton::enterEvent(0l); } + virtual void leaveEvent() { QToolButton::leaveEvent(0l); } + + void setAngleDegrees( int angleDegrees ) { m_angleDegrees = angleDegrees; } + + protected: + virtual void drawButtonLabel( QPainter * p ); + + int m_angleDegrees; + QFont m_font; +}; + + +/** +@short Stores internal information about button associated with CNItem +@author David Saxton +*/ +class Button : public Widget +{ + Q_OBJECT + public: + Button( const QString & id, CNItem *parent, bool isToggle, const QRect & r, QCanvas * canvas ); + ~Button(); + + virtual void mousePressEvent( QMouseEvent *e ); + virtual void mouseReleaseEvent( QMouseEvent *e ); + virtual void enterEvent(); + virtual void leaveEvent(); + + /** + * Set the text displayed inside the button + */ + void setText( const QString &text ); + void setToggle( bool toggle ); + bool isToggle() const { return b_isToggle; } + virtual QWidget *widget() const; + bool state() const; + void setPixmap( const QPixmap & ); + void setState( bool state ); + virtual QRect recommendedRect() const; + + protected: + virtual void posChanged(); + + private slots: + void slotStateChanged(); + + private: + bool b_isToggle; // i.e. whether it should be depressed when the mouse is released + ToolButton *m_button; +}; + + +class SliderWidget : public QSlider +{ + public: + SliderWidget( QWidget* parent ); + + virtual void mousePressEvent( QMouseEvent *e ) { QSlider::mousePressEvent(e); } + virtual void mouseReleaseEvent( QMouseEvent *e ) { QSlider::mouseReleaseEvent(e); } + virtual void mouseDoubleClickEvent ( QMouseEvent *e ) { QSlider::mouseDoubleClickEvent(e); } + virtual void mouseMoveEvent( QMouseEvent *e ) { QSlider::mouseMoveEvent(e); } + virtual void wheelEvent( QWheelEvent *e ) { QSlider::wheelEvent(e); } + virtual void enterEvent() { QSlider::enterEvent(0l); } + virtual void leaveEvent() { QSlider::leaveEvent(0l); } +}; + + +/** +@short Stores internal information about a QSlider associated with CNItem +@author David Saxton +*/ +class Slider : public Widget +{ + Q_OBJECT + public: + Slider( const QString & id, CNItem *parent, const QRect & r, QCanvas * canvas ); + ~Slider(); + + virtual void mousePressEvent( QMouseEvent *e ); + virtual void mouseReleaseEvent( QMouseEvent *e ); + virtual void mouseDoubleClickEvent ( QMouseEvent *e ); + virtual void mouseMoveEvent( QMouseEvent *e ); + virtual void wheelEvent( QWheelEvent *e ); + virtual void enterEvent(); + virtual void leaveEvent(); + + virtual QWidget *widget() const; + int value() const; + void setValue( int value ); + void setOrientation( Qt::Orientation o ); + + protected: + virtual void posChanged(); + + private slots: + void slotValueChanged( int value ); + + private: + SliderWidget *m_slider; + Orientation m_orientation; +}; + +#endif + diff --git a/src/canvasmanipulator.cpp b/src/canvasmanipulator.cpp new file mode 100644 index 0000000..7c3ed17 --- /dev/null +++ b/src/canvasmanipulator.cpp @@ -0,0 +1,1904 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "cnitemgroup.h" +#include "canvasitemparts.h" +#include "dptext.h" +#include "canvasmanipulator.h" +#include "connector.h" +#include "flowcontainer.h" +#include "icndocument.h" +#include "itemview.h" +#include "mechanicsdocument.h" +#include "mechanicsgroup.h" +#include "mechanicsitem.h" +#include "node.h" +#include "nodegroup.h" +#include "picitem.h" +#include "resizeoverlay.h" + +#include + +#include +#include +#include + +#include +#include + + +CMManager::CMManager( ItemDocument *itemDocument ) + : QObject() +{ + b_allowItemScroll = true; + p_lastMouseOverResizeHandle = 0l; + m_canvasManipulator = 0l; + p_itemDocument = itemDocument; + m_cmState = 0; + p_lastMouseOverItem = 0l; + p_lastItemClicked = 0l; + m_drawAction = -1; + m_allowItemScrollTmr = new QTimer(this); + connect( m_allowItemScrollTmr, SIGNAL(timeout()), this, SLOT(slotAllowItemScroll()) ); + + KGlobal::config()->setGroup("General"); + slotSetManualRoute( KGlobal::config()->readBoolEntry( "ManualRouting", false ) ); +} + + +CMManager::~CMManager() +{ + delete m_allowItemScrollTmr; + m_allowItemScrollTmr = 0l; + delete m_canvasManipulator; + m_canvasManipulator = 0l; + + const ManipulatorInfoList::iterator end = m_manipulatorInfoList.end(); + for ( ManipulatorInfoList::iterator it = m_manipulatorInfoList.begin(); it != end; ++it ) + { + delete *it; + } + m_manipulatorInfoList.clear(); +} + + +void CMManager::addManipulatorInfo( ManipulatorInfo *eventInfo ) +{ + if ( eventInfo && !m_manipulatorInfoList.contains(eventInfo) ) { + m_manipulatorInfoList.prepend(eventInfo); + } +} + + +void CMManager::cancelCurrentManipulation() +{ + delete m_canvasManipulator; + m_canvasManipulator = 0l; + setRepeatedAddId(); +} + + +void CMManager::mousePressEvent( EventInfo eventInfo ) +{ + if (m_canvasManipulator) + { + if (m_canvasManipulator->mousePressedRepeat(eventInfo)) + { + delete m_canvasManipulator; + m_canvasManipulator = 0l; + } + return; + } + + uint eventState=0; + if (eventInfo.isRightClick) + eventState |= CMManager::es_right_click; + + if (eventInfo.ctrlPressed) + eventState |= CMManager::es_ctrl_pressed; + + uint itemType=0; + uint cnItemType=0; + + + switch ( eventInfo.itemRtti ) + { + case ItemDocument::RTTI::None: itemType = CMManager::it_none; break; + case ItemDocument::RTTI::Node: itemType = CMManager::it_node; break; + case ItemDocument::RTTI::Connector: itemType = CMManager::it_connector; break; + case ItemDocument::RTTI::Pin: itemType = CMManager::it_pin; break; + case ItemDocument::RTTI::ResizeHandle: itemType = CMManager::it_resize_handle; break; + case ItemDocument::RTTI::DrawPart: + { + itemType = CMManager::it_drawpart; + DrawPart *drawPartClickedOn = dynamic_cast(eventInfo.qcanvasItemClickedOn); + + if ( drawPartClickedOn->mousePressEvent(eventInfo) ) + { + p_lastItemClicked = drawPartClickedOn; + return; + } + + if ( drawPartClickedOn->isMovable() ) + cnItemType |= CMManager::isi_isMovable; + break; + } + case ItemDocument::RTTI::Widget: + { + Widget *widget = dynamic_cast(eventInfo.qcanvasItemClickedOn); + if (widget) + eventInfo.qcanvasItemClickedOn = widget->parent(); + } + case ItemDocument::RTTI::CNItem: + { + itemType = CMManager::it_canvas_item; + CNItem *cnItemClickedOn = dynamic_cast(eventInfo.qcanvasItemClickedOn); + + if ( cnItemClickedOn->mousePressEvent(eventInfo) ) + { + p_lastItemClicked = cnItemClickedOn; + return; + } + + if ( cnItemClickedOn->isMovable() ) + cnItemType |= CMManager::isi_isMovable; + break; + } + case ItemDocument::RTTI::MechanicsItem: + { + itemType = CMManager::it_mechanics_item; + MechanicsItem *p_mechanicsItemClickedOn = dynamic_cast(eventInfo.qcanvasItemClickedOn); + + if ( p_mechanicsItemClickedOn->mousePressEvent(eventInfo) ) + { + p_lastItemClicked = p_mechanicsItemClickedOn; + return; + } + break; + } + } + +// uint highestScore=0; +// ManipulatorInfo *best=0l; + const ManipulatorInfoList::iterator end = m_manipulatorInfoList.end(); + for ( ManipulatorInfoList::iterator it = m_manipulatorInfoList.begin(); it != end && !m_canvasManipulator; ++it ) + { + if ( (*it)->m_acceptManipulationPtr( eventState, m_cmState, itemType, cnItemType ) ) + { + m_canvasManipulator = (*it)->m_createManipulatorPtr( p_itemDocument, this ); + } + } + if (m_canvasManipulator) + { + if (m_canvasManipulator->mousePressedInitial(eventInfo)) + { + delete m_canvasManipulator; + m_canvasManipulator = 0l; + } + } +} + + +void CMManager::mouseDoubleClickEvent( const EventInfo &eventInfo ) +{ + Item *item = dynamic_cast(eventInfo.qcanvasItemClickedOn); + if (item) + { + item->mouseDoubleClickEvent(eventInfo); + return; + } + Widget *widget = dynamic_cast(eventInfo.qcanvasItemClickedOn); + if (widget) + { + widget->parent()->mouseDoubleClickEvent(eventInfo); + return; + } +} + + +void CMManager::mouseMoveEvent( const EventInfo &eventInfo ) +{ + if (m_canvasManipulator) + { + if (m_canvasManipulator->mouseMoved(eventInfo)) + { + kdDebug() << k_funcinfo << "About to delete" << endl; + delete m_canvasManipulator; + kdDebug() << k_funcinfo << "Deleted" << endl; + m_canvasManipulator = 0l; + kdDebug() << k_funcinfo << "Nullified" << endl; + } + ItemView *itemView = dynamic_cast(p_itemDocument->activeView()); + if (itemView) + itemView->scrollToMouse(eventInfo.pos); + return; + } + + //BEGIN + QCanvasItem *qcnItem = p_itemDocument->itemAtTop(eventInfo.pos); + Item *item; + Widget *widget = dynamic_cast(qcnItem); + if (widget) + item = widget->parent(); + else + item = dynamic_cast(qcnItem); + + if ( p_lastMouseOverItem != (QGuardedPtr)item ) + { + QEvent event(QEvent::Leave); + + if (p_lastMouseOverItem) + p_lastMouseOverItem->leaveEvent(); + + if (item) + item->enterEvent(); + + p_lastMouseOverItem = item; + } + + // If we clicked on an item, then continue to pass mouse events to that item until we release the mouse... + if (p_lastItemClicked) + { + p_lastItemClicked->mouseMoveEvent(eventInfo); + } + else if (item) + { + item->mouseMoveEvent(eventInfo); + } + //END + + updateCurrentResizeHandle( dynamic_cast(qcnItem) ); +} + + +void CMManager::updateCurrentResizeHandle( ResizeHandle * resizeHandle ) +{ + if ( p_lastMouseOverResizeHandle != (QGuardedPtr)resizeHandle ) + { + if (p_lastMouseOverResizeHandle) + p_lastMouseOverResizeHandle->setHover(false); + p_lastMouseOverResizeHandle = resizeHandle; + if (resizeHandle) + resizeHandle->setHover(true); + } +} + + +void CMManager::mouseReleaseEvent( const EventInfo &eventInfo ) +{ + // If it returns true, then it has finished its editing operation + if ( m_canvasManipulator && m_canvasManipulator->mouseReleased(eventInfo) ) + { + delete m_canvasManipulator; + m_canvasManipulator = 0l; + } + + if (p_lastItemClicked) + { + p_lastItemClicked->mouseReleaseEvent(eventInfo); + p_lastItemClicked=0l; + } + + updateCurrentResizeHandle( dynamic_cast( p_itemDocument->itemAtTop(eventInfo.pos) ) ); +} + + +void CMManager::wheelEvent( const EventInfo &eventInfo ) +{ + bool accepted = false; + if (b_allowItemScroll) + { + QCanvasItem *qcnItem = p_itemDocument->itemAtTop(eventInfo.pos); + Item *item; + Widget *widget = dynamic_cast(qcnItem); + if (widget) + item = widget->parent(); + else + item = dynamic_cast(qcnItem); + + if (item) + accepted = item->wheelEvent(eventInfo); + } + if (!accepted) + { + // Only allow scrolling of items if we have not just been scrolling the canvas + b_allowItemScroll = false; + m_allowItemScrollTmr->stop(); + m_allowItemScrollTmr->start(500,true); + + ItemView *itemView = dynamic_cast(p_itemDocument->activeView()); + if (itemView) + { + itemView->cvbEditor()->setPassEventsToView(false); + itemView->cvbEditor()->contentsWheelEvent( eventInfo.wheelEvent( 0, 0 ) ); + itemView->cvbEditor()->setPassEventsToView(true); + } + } +} + + +void CMManager::setDrawAction( int drawAction ) +{ + if ( m_drawAction == drawAction ) + return; + + m_drawAction = drawAction; + setCMState( cms_draw, (m_drawAction != -1) ); +} + + +void CMManager::slotSetManualRoute( bool manualRoute ) +{ + KGlobal::config()->setGroup("General"); + KGlobal::config()->writeEntry( "ManualRouting", manualRoute ); + + setCMState( cms_manual_route, manualRoute ); +} + + +void CMManager::setCMState( CMState type, bool state ) +{ + // Set or clear the correct bit + state ? (m_cmState|=type) : (m_cmState&=(~type)); + + if ( type == CMManager::cms_manual_route ) + emit manualRoutingChanged(state); +} + + +void CMManager::setRepeatedAddId( const QString & repeatedId ) +{ + m_repeatedItemId = repeatedId; +} + + + + +CanvasManipulator::CanvasManipulator( ItemDocument *itemDocument, CMManager *cmManager ) +{ + p_itemDocument = itemDocument; + p_icnDocument = dynamic_cast(itemDocument); + p_mechanicsDocument = dynamic_cast(itemDocument); + p_canvas = p_itemDocument->canvas(); +// b_connectorsAllowedRouting = true; + p_selectList = p_itemDocument->selectList(); + p_cnItemSelectList = dynamic_cast(p_selectList); + p_mechItemSelectList = dynamic_cast(p_selectList); + p_cnItemClickedOn = 0l; + p_cmManager = cmManager; +} + + +CanvasManipulator::~CanvasManipulator() +{ +} + + + + +CMRepeatedItemAdd::CMRepeatedItemAdd( ItemDocument *itemDocument, CMManager *cmManager ) + : CanvasManipulator( itemDocument, cmManager ) +{ +} +CMRepeatedItemAdd::~CMRepeatedItemAdd() +{ +} +CanvasManipulator* CMRepeatedItemAdd::construct( ItemDocument *itemDocument, CMManager *cmManager ) +{ + return new CMRepeatedItemAdd(itemDocument,cmManager); +} +ManipulatorInfo *CMRepeatedItemAdd::manipulatorInfo() +{ + ManipulatorInfo *eventInfo = new ManipulatorInfo(); + eventInfo->m_acceptManipulationPtr = CMRepeatedItemAdd::acceptManipulation; + eventInfo->m_createManipulatorPtr = CMRepeatedItemAdd::construct; + return eventInfo; +} +bool CMRepeatedItemAdd::acceptManipulation( uint /*eventState*/, uint cmState, uint /*itemType*/, uint /*cnItemType*/ ) +{ + return (cmState & CMManager::cms_repeated_add); +} + +bool CMRepeatedItemAdd::mousePressedRepeat( const EventInfo &eventInfo ) +{ + return mousePressedInitial(eventInfo); +} +bool CMRepeatedItemAdd::mousePressedInitial( const EventInfo &eventInfo ) +{ + m_eventInfo = eventInfo; + if (eventInfo.isRightClick) + { + p_cmManager->setCMState( CMManager::cms_repeated_add, false ); + return true; + } + + p_icnDocument->addItem( p_cmManager->repeatedItemId(), eventInfo.pos, true ); + p_itemDocument->requestStateSave(); + return false; +} + + +bool CMRepeatedItemAdd::mouseMoved( const EventInfo &/*eventInfo*/ ) +{ + return false; +} + + +bool CMRepeatedItemAdd::mouseReleased( const EventInfo &/*eventInfo*/ ) +{ + return false; +} + + + + +CMRightClick::CMRightClick( ItemDocument *itemDocument, CMManager *cmManager ) + : CanvasManipulator( itemDocument, cmManager ) +{ +} +CMRightClick::~CMRightClick() +{ +} +CanvasManipulator* CMRightClick::construct( ItemDocument *itemDocument, CMManager *cmManager ) +{ + return new CMRightClick(itemDocument,cmManager); +} +ManipulatorInfo *CMRightClick::manipulatorInfo() +{ + ManipulatorInfo *eventInfo = new ManipulatorInfo(); +// eventInfo->m_eventState.m_activate = CMManager::es_right_click; + eventInfo->m_acceptManipulationPtr = CMRightClick::acceptManipulation; + eventInfo->m_createManipulatorPtr = CMRightClick::construct; + return eventInfo; +} +bool CMRightClick::acceptManipulation( uint eventState, uint /*cmState*/, uint /*itemType*/, uint /*cnItemType*/ ) +{ + return eventState & CMManager::es_right_click; +} + + +bool CMRightClick::mousePressedInitial( const EventInfo &eventInfo ) +{ + m_eventInfo = eventInfo; + p_itemDocument->canvasRightClick( eventInfo.globalPos, eventInfo.qcanvasItemClickedOn ); + return true; +} + + +bool CMRightClick::mouseMoved( const EventInfo &/*eventInfo*/ ) +{ + return true; +} + + +bool CMRightClick::mouseReleased( const EventInfo &/*eventInfo*/ ) +{ + return true; +} + + + +//BEGIN class ConnectorDraw +ConnectorDraw::ConnectorDraw( ItemDocument *itemDocument, CMManager *cmManager ) + : CanvasManipulator( itemDocument, cmManager ) +{ + p_startNode = 0l; + p_startConnector = 0l; + p_endNode = 0l; + p_endConnector = 0l; +} + + +ConnectorDraw::~ConnectorDraw() +{ +} + + +QColor ConnectorDraw::validConnectionColor() +{ + return QColor( 255, 166, 0 ); +} + + +static double qpoint_distance( const QPoint & p1, const QPoint & p2 ) +{ + double dx = p1.x() - p2.x(); + double dy = p1.y() - p2.y(); + + return std::sqrt( dx*dx + dy*dy ); +} + + +QPoint ConnectorDraw::toValidPos( const QPoint & clickPos, Connector * clickedConnector ) const +{ + if ( !clickedConnector ) + return clickPos; + + const QPointList pointList = clickedConnector->connectorPoints(); + + QPointList::const_iterator end = pointList.end(); + + double dl[] = { 0.5, 8.5, 11.5, 18.0, 23.0 }; // various distances rounded up of (0,0) cells, (0,1), etc + for ( unsigned i = 0; i < 5; ++i ) + { + for ( QPointList::const_iterator it = pointList.begin(); it != end; ++it ) + { + if ( qpoint_distance( *it, clickPos ) <= dl[i] ) + return *it; + } + } + + return clickPos; +} + + +Connector * ConnectorDraw::toConnector( Node * node ) +{ + if ( !node || node->numCon( true, false ) < 3 ) + return 0l; + + const ConnectorList inList = node->inputConnectorList(); + if ( !inList.isEmpty() ) + return *inList.begin(); + + const ConnectorList outList = node->outputConnectorList(); + if ( !outList.isEmpty() ) + return *outList.begin(); + + return 0l; +} + + +void ConnectorDraw::grabEndStuff( QCanvasItem * endItem, const QPoint & pos, bool posIsExact ) +{ + if (!endItem) + return; + + CNItem * cnItem = dynamic_cast(endItem); + if ( cnItem && !posIsExact ) + p_endNode = cnItem->getClosestNode(pos); + else + p_endNode = dynamic_cast(endItem); + + if ( p_endNode && p_endNode->numCon( true, false ) > 2 ) + { + p_endConnector = toConnector(p_endNode); + p_endNode = 0l; + } + + // If the endItem is a node, we have to finish exactly on the end when posIsExact is true + if ( posIsExact && p_endNode && (p_endNode->x() != pos.x() || p_endNode->y() != pos.y()) ) + p_endNode = 0l; + + if (!p_endConnector) + p_endConnector = dynamic_cast(endItem); +} +//END class ConnectorDraw + + + +//BEGIN class CMAutoConnector +CMAutoConnector::CMAutoConnector( ItemDocument *itemDocument, CMManager *cmManager ) + : ConnectorDraw( itemDocument, cmManager ) +{ + m_connectorLine = 0l; + p_startNode = 0l; + p_startConnector = 0l; +} +CMAutoConnector::~CMAutoConnector() +{ + delete m_connectorLine; + m_connectorLine = 0l; +} +CanvasManipulator* CMAutoConnector::construct( ItemDocument *itemDocument, CMManager *cmManager ) +{ + return new CMAutoConnector(itemDocument,cmManager); +} +ManipulatorInfo *CMAutoConnector::manipulatorInfo() +{ + ManipulatorInfo *eventInfo = new ManipulatorInfo(); + eventInfo->m_acceptManipulationPtr = CMAutoConnector::acceptManipulation; + eventInfo->m_createManipulatorPtr = CMAutoConnector::construct; + return eventInfo; +} +bool CMAutoConnector::acceptManipulation( uint /*eventState*/, uint cmState, uint itemType, uint /*cnItemType*/ ) +{ + return (itemType & (CMManager::it_node | CMManager::it_connector)) && !(cmState & CMManager::cms_manual_route); +} + +bool CMAutoConnector::mousePressedInitial( const EventInfo &eventInfo ) +{ + m_eventInfo = eventInfo; + + p_startNode = dynamic_cast(eventInfo.qcanvasItemClickedOn); + + if (p_startNode) + { + m_eventInfo.pos = m_prevPos = p_icnDocument->gridSnap( QPoint( (int)p_startNode->x(), (int)p_startNode->y() ) ); + if (p_startNode->numCon( true, false ) > 2) + { + p_startConnector = toConnector(p_startNode); + p_startNode = 0l; + } + } + else if (p_startConnector = dynamic_cast(eventInfo.qcanvasItemClickedOn) ) + { +// startConnectorPoint = m_eventInfo.pos = m_prevPos = p_icnDocument->gridSnap(m_eventInfo.pos); + startConnectorPoint = m_eventInfo.pos = m_prevPos = toValidPos( m_eventInfo.pos, p_startConnector ); + } + + else + return true; + + p_icnDocument->unselectAll(); + + delete m_connectorLine; + m_connectorLine = new QCanvasLine(p_canvas); + m_connectorLine->setPen( QColor(0,0,0) ); + m_connectorLine->setZ( ItemDocument::Z::ConnectorCreateLine ); + m_connectorLine->show(); + return false; +} + + +bool CMAutoConnector::mouseMoved( const EventInfo &eventInfo ) +{ + const QPoint pos = eventInfo.pos; + + int newX = p_icnDocument->gridSnap( pos.x() ); + int newY = p_icnDocument->gridSnap( pos.y() ); + + bool movedFlag = false; + + if ( newX != m_prevPos.x() ) + { + m_prevPos.setX(newX); + movedFlag = true; + } + + if ( newY != m_prevPos.y() ) + { + m_prevPos.setY(newY); + movedFlag = true; + } + + m_connectorLine->setPoints( m_eventInfo.pos.x(), m_eventInfo.pos.y(), newX, newY ); + + if (movedFlag) + { + QCanvasItem *startItem = 0l; + if (p_startNode) + startItem = p_startNode; + else if (p_startConnector) + startItem = p_startConnector; + + QCanvasItem *endItem = p_icnDocument->itemAtTop( QPoint( newX, newY ) ); + if ( endItem && endItem->rtti() == ItemDocument::RTTI::CNItem ) + endItem = (static_cast(endItem))->getClosestNode( QPoint( newX, newY ) ); + + bool validLine = p_icnDocument->canConnect( startItem, endItem ); + m_connectorLine->setPen( validLine ? validConnectionColor() : Qt::black ); + } + return false; +} + + +bool CMAutoConnector::mouseReleased( const EventInfo &eventInfo ) +{ + const QPoint pos = eventInfo.pos; + + QPoint end = m_connectorLine->endPoint(); + delete m_connectorLine; + m_connectorLine = 0l; + + QCanvasItem *qcanvasItem = p_icnDocument->itemAtTop(end); + if ( !qcanvasItem ) + return true; + + grabEndStuff( qcanvasItem, pos, false ); + + if (p_startConnector) + { + if (p_endConnector) + { + if ( !p_icnDocument->createConnector( p_endConnector, p_startConnector, p_icnDocument->gridSnap(pos), startConnectorPoint ) ) + return true; + } + else if (p_endNode) + { + if ( !p_icnDocument->createConnector( p_endNode, p_startConnector, startConnectorPoint ) ) + return true; + } + else + return true; + } + else if (p_startNode) + { + if (p_endConnector) + { + if ( !p_icnDocument->createConnector( p_startNode, p_endConnector, p_icnDocument->gridSnap(pos) ) ) + return true; + } + else if (p_endNode) + { + if ( !p_icnDocument->createConnector( p_startNode, p_endNode ) ) + return true; + } + else + return true; + } + else + return true; + + p_itemDocument->requestStateSave(); + return true; +} +//END class CMAutoConnector + + + +//BEGIN class CMManualConnector +CMManualConnector::CMManualConnector( ItemDocument *itemDocument, CMManager *cmManager ) + : ConnectorDraw( itemDocument, cmManager ) +{ + m_manualConnectorDraw = 0l; +} +CMManualConnector::~CMManualConnector() +{ + delete m_manualConnectorDraw; + m_manualConnectorDraw = 0l; +} +CanvasManipulator* CMManualConnector::construct( ItemDocument *itemDocument, CMManager *cmManager ) +{ + return new CMManualConnector(itemDocument,cmManager); +} +ManipulatorInfo *CMManualConnector::manipulatorInfo() +{ + ManipulatorInfo *eventInfo = new ManipulatorInfo(); + eventInfo->m_acceptManipulationPtr = CMManualConnector::acceptManipulation; + eventInfo->m_createManipulatorPtr = CMManualConnector::construct; + return eventInfo; +} +bool CMManualConnector::acceptManipulation( uint /*eventState*/, uint cmState, uint itemType, uint /*cnItemType*/ ) +{ + return (itemType & (CMManager::it_node | CMManager::it_connector)) && (cmState & CMManager::cms_manual_route); +} + + +bool CMManualConnector::mousePressedInitial( const EventInfo &eventInfo ) +{ + if ( eventInfo.isRightClick ) { + return true; + } + + m_eventInfo = eventInfo; + + p_icnDocument->unselectAll(); + + QPoint sp; + + if ( eventInfo.itemRtti == ItemDocument::RTTI::Node ) + { + p_startNode = static_cast(eventInfo.qcanvasItemClickedOn); + sp.setX( (int)p_startNode->x() ); + sp.setY( (int)p_startNode->y() ); + if ( p_startNode->numCon( true, false ) > 2 ) + { + p_startConnector = toConnector(p_startNode); + p_startNode = 0l; + } + } + else + { + p_startConnector = dynamic_cast(eventInfo.qcanvasItemClickedOn); + sp = toValidPos( eventInfo.pos, p_startConnector ); + } + startConnectorPoint = sp; + + if (m_manualConnectorDraw) + delete m_manualConnectorDraw; + m_manualConnectorDraw = new ManualConnectorDraw( p_icnDocument, sp ); + return false; +} + + +bool CMManualConnector::mousePressedRepeat( const EventInfo &eventInfo ) +{ + m_eventInfo = eventInfo; + if ( eventInfo.isRightClick ) { + return true; + } + m_manualConnectorDraw->mouseClicked( p_icnDocument->gridSnap(m_eventInfo.pos) ); + return false; +} + + +bool CMManualConnector::mouseMoved( const EventInfo &eventInfo ) +{ + if ( !m_manualConnectorDraw ) + return true; + + const QPoint pos = eventInfo.pos; + + int newX = p_icnDocument->gridSnap( pos.x() ); + int newY = p_icnDocument->gridSnap( pos.y() ); + + bool movedFlag = false; + + if ( newX != m_prevPos.x() ) + { + m_prevPos.setX(newX); + movedFlag = true; + } + + if ( newY != m_prevPos.y() ) + { + m_prevPos.setY(newY); + movedFlag = true; + } + + if ( movedFlag ) + { + QCanvasItem *startItem = 0l; + if (p_startNode) + startItem = p_startNode; + else if (p_startConnector) + startItem = p_startConnector; + + QCanvasItem * endItem = p_icnDocument->itemAtTop( QPoint( newX, newY ) ); + + // If the endItem is a node, we have to finish exactly on the end. + if ( Node * node = dynamic_cast(endItem) ) + { + if ( node->x() != newX || node->y() != newY ) + endItem = 0l; + } + + bool validLine = p_icnDocument->canConnect( startItem, endItem ); + + m_manualConnectorDraw->setColor( validLine ? validConnectionColor() : Qt::black ); + m_manualConnectorDraw->mouseMoved( QPoint( newX, newY ) ); + } + + return false; +} + + +bool CMManualConnector::mouseReleased( const EventInfo &eventInfo ) +{ + if (!m_manualConnectorDraw) { + return true; + } + + QPoint pos = p_icnDocument->gridSnap(eventInfo.pos); + + grabEndStuff( m_manualConnectorDraw->mouseClicked(pos), pos, true ); + + if ( !p_endNode && !p_endConnector ) + return false; + + // Create the points that define the manual route + QPointList list = m_manualConnectorDraw->pointList(); + delete m_manualConnectorDraw; + m_manualConnectorDraw = 0l; + + if (p_startConnector) + { + if (p_endConnector) + { + if ( !p_icnDocument->createConnector( p_endConnector, p_startConnector, p_icnDocument->gridSnap(pos), startConnectorPoint, &list ) ) + return true; + } + else // if (p_endNode) + { + if ( !p_icnDocument->createConnector( p_endNode, p_startConnector, startConnectorPoint, &list ) ) + return true; + } + } + else if (p_startNode) + { + if (p_endConnector) + { + if ( !p_icnDocument->createConnector( p_startNode, p_endConnector, p_icnDocument->gridSnap(pos), &list ) ) + return true; + } + else // if (p_endNode) + { + if ( !p_icnDocument->createConnector( p_startNode, p_endNode, &list ) ) + return true; + } + } + else + return true; + + p_itemDocument->requestStateSave(); + return true; +} +//END class CMManualConnector + + + + +CMItemMove::CMItemMove( ItemDocument *itemDocument, CMManager *cmManager ) + : CanvasManipulator( itemDocument, cmManager ) +{ + p_flowContainerCandidate = 0l; +} +CMItemMove::~CMItemMove() +{ +} +CanvasManipulator* CMItemMove::construct( ItemDocument *itemDocument, CMManager *cmManager ) +{ + return new CMItemMove(itemDocument,cmManager); +} +ManipulatorInfo *CMItemMove::manipulatorInfo() +{ + ManipulatorInfo *eventInfo = new ManipulatorInfo(); + eventInfo->m_acceptManipulationPtr = CMItemMove::acceptManipulation; + eventInfo->m_createManipulatorPtr = CMItemMove::construct; + return eventInfo; +} +bool CMItemMove::acceptManipulation( uint eventState, uint /*cmState*/, uint itemType, uint cnItemType ) +{ + return ((itemType & CMManager::it_canvas_item) || (itemType & CMManager::it_drawpart)) && (cnItemType & CMManager::isi_isMovable) && !(eventState & CMManager::es_right_click); +} + + +bool CMItemMove::mousePressedInitial( const EventInfo &eventInfo ) +{ + m_eventInfo = eventInfo; + m_prevPos = eventInfo.pos; + + Item *item = dynamic_cast(eventInfo.qcanvasItemClickedOn); + if (!item) + return true; + + + if ( !p_selectList->contains(item) ) + { + if (!eventInfo.ctrlPressed) + p_itemDocument->unselectAll(); + + p_itemDocument->select(item); + } + else if (m_eventInfo.ctrlPressed) + p_itemDocument->unselect(item); + + if ( p_selectList->isEmpty() ) + return true; + + // We want to allow dragging into FlowContainers if this is a FlowView + p_flowContainerCandidate = 0l; + { + const ItemList &itemList = p_icnDocument->itemList(); + const ItemList::const_iterator ciEnd = itemList.end(); + for ( ItemList::const_iterator it = itemList.begin(); it != ciEnd; ++it ) + { + if ( FlowContainer *flowContainer = dynamic_cast((Item*)*it) ) + flowContainer->setFullBounds(true); + } + } + + ItemList itemList = p_cnItemSelectList->items(false); + itemList.remove((Item*)0l); + + const ItemList::iterator itemListEnd = itemList.end(); + for ( ItemList::iterator it = itemList.begin(); it != itemListEnd; ++it ) + { + CNItem *cnItem = dynamic_cast((Item*)*it); + if ( !cnItem || !cnItem->canvas() ) + continue; + + cnItem->setInitialPos(m_eventInfo.pos); + } + + ConnectorList fixedConnectors; + p_icnDocument->getTranslatable( itemList, &fixedConnectors, &m_translatableConnectors, &m_translatableNodeGroups ); + + const ConnectorList::iterator fixedConnectorsEnd = fixedConnectors.end(); + for ( ConnectorList::iterator it = fixedConnectors.begin(); it != fixedConnectorsEnd; ++it ) + (*it)->setSemiHidden(true); + + p_flowContainerCandidate = p_icnDocument->flowContainer(eventInfo.pos); + + return false; +} + + +bool CMItemMove::mouseMoved( const EventInfo &eventInfo ) +{ + const QPoint pos = eventInfo.pos; + + int x = pos.x(); + int y = pos.y(); + + + const ItemList itemList = p_cnItemSelectList->items(); + const ItemList::const_iterator end = itemList.end(); + int dx=0, dy=0; + for ( ItemList::const_iterator it = itemList.begin(); it != end; ++it ) + { + if ( !*it || !(*it)->isMovable() ) + continue; + + const QRect oldRect = (*it)->boundingRect(); + (*it)->setChanged(); + + if ( CNItem *cnItem = dynamic_cast((Item*)*it) ) + { + dx = -int((*it)->x()); + dy = -int((*it)->y()); + cnItem->snap( x, y ); + dx += int((*it)->x()); + dy += int((*it)->y()); + } + else + (*it)->moveBy( eventInfo.pos.x()-m_prevPos.x(), eventInfo.pos.y()-m_prevPos.y() ); + + QRect newRect = (*it)->boundingRect(); + QRect merged = oldRect | newRect; + } + + if ( (dx != 0) || (dy != 0) ) + { + const ConnectorList::iterator frEnd = m_translatableConnectors.end(); + for ( ConnectorList::iterator it = m_translatableConnectors.begin(); it != frEnd; ++it ) + (*it)->translateRoute( dx, dy ); + + const NodeGroupList::iterator end = m_translatableNodeGroups.end(); + for ( NodeGroupList::iterator it = m_translatableNodeGroups.begin(); it != end; ++it ) + (*it)->translate( dx, dy ); + } + + FlowContainer *fc = p_icnDocument->flowContainer(pos); + if ( fc != p_flowContainerCandidate ) + { + if ( p_flowContainerCandidate ) + { + p_flowContainerCandidate->setSelected(false); + p_flowContainerCandidate = 0l; + } + } + if (fc) + { + p_flowContainerCandidate = fc; + p_flowContainerCandidate->setSelected(true); + } + + p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems ); + p_canvas->update(); + m_prevPos = eventInfo.pos; + return false; +} + + +bool CMItemMove::mouseReleased( const EventInfo &eventInfo ) +{ + QStringList itemIDs; + + const ItemList itemList = p_cnItemSelectList->items(); + const ItemList::const_iterator ilEnd = itemList.end(); + for ( ItemList::const_iterator it = itemList.begin(); it != ilEnd; ++it ) + { + if (*it) + itemIDs.append( (*it)->id() ); + } + + const QPoint pos = eventInfo.pos; + + // And make sure all connectors are properly shown + const ConnectorList &connectorList = p_icnDocument->connectorList(); + const ConnectorList::const_iterator conEnd = connectorList.end(); + for ( ConnectorList::const_iterator it = connectorList.begin(); it != conEnd; ++it ) + { + (*it)->setSemiHidden(false); + } + + if (p_flowContainerCandidate) + { + for ( ItemList::const_iterator it = itemList.begin(); it != ilEnd; ++it ) + p_flowContainerCandidate->addChild(*it); + + p_flowContainerCandidate->setSelected(false); + p_flowContainerCandidate = 0l; + } + else + { + for ( ItemList::const_iterator it = itemList.begin(); it != ilEnd; ++it ) + (*it)->setParentItem(0l); + } + + // And disable the FlowContainers again... + const ItemList &cnItemList = p_icnDocument->itemList(); + const ItemList::const_iterator end = cnItemList.end(); + for ( ItemList::const_iterator it = cnItemList.begin(); it != end; ++it ) + { + if ( FlowContainer *flowContainer = dynamic_cast((Item*)*it) ) + flowContainer->setFullBounds(false); + } + + if (p_icnDocument) + p_icnDocument->requestRerouteInvalidatedConnectors(); + + if ( m_eventInfo.pos != eventInfo.pos ) + p_itemDocument->requestStateSave(); + + p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems ); + + return true; +} + + + + + +CMItemResize::CMItemResize( ItemDocument *itemDocument, CMManager *cmManager ) + : CanvasManipulator( itemDocument, cmManager ) +{ +} +CMItemResize::~CMItemResize() +{ +} +CanvasManipulator* CMItemResize::construct( ItemDocument *itemDocument, CMManager *cmManager ) +{ + return new CMItemResize(itemDocument,cmManager); +} +ManipulatorInfo *CMItemResize::manipulatorInfo() +{ + ManipulatorInfo *eventInfo = new ManipulatorInfo(); +// eventInfo->m_itemType.m_activate = CMManager::it_canvas_item; + eventInfo->m_acceptManipulationPtr = CMItemResize::acceptManipulation; + eventInfo->m_createManipulatorPtr = CMItemResize::construct; + return eventInfo; +} +bool CMItemResize::acceptManipulation( uint eventState, uint /*cmState*/, uint itemType, uint /*cnItemType*/ ) +{ + return (itemType & CMManager::it_resize_handle) && !(eventState & CMManager::es_right_click); +} + + + +bool CMItemResize::mousePressedInitial( const EventInfo &eventInfo ) +{ + m_eventInfo = eventInfo; + p_resizeHandle = dynamic_cast(eventInfo.qcanvasItemClickedOn); + m_rh_dx = p_resizeHandle->x()-eventInfo.pos.x(); + m_rh_dy = p_resizeHandle->y()-eventInfo.pos.y(); + return false; +} + + +bool CMItemResize::mouseMoved( const EventInfo &eventInfo ) +{ + int _x = int(m_rh_dx + eventInfo.pos.x()); + int _y = int(m_rh_dy + eventInfo.pos.y()); + + // Shift pressed == snap to grid + if ( eventInfo.shiftPressed ) + { + _x = int(_x/8)*8+4; + _y = int(_y/8)*8+4; + } + + p_resizeHandle->moveRH( _x, _y ); + return false; +} + + +bool CMItemResize::mouseReleased( const EventInfo &/*eventInfo*/ ) +{ + if (p_icnDocument) + p_icnDocument->requestRerouteInvalidatedConnectors(); + p_itemDocument->requestStateSave(); + return true; +} + + + + + + + +CMMechItemMove::CMMechItemMove( ItemDocument *itemDocument, CMManager *cmManager ) + : CanvasManipulator( itemDocument, cmManager ) +{ +} +CMMechItemMove::~CMMechItemMove() +{ +} +CanvasManipulator* CMMechItemMove::construct( ItemDocument *itemDocument, CMManager *cmManager ) +{ + return new CMMechItemMove(itemDocument,cmManager); +} +ManipulatorInfo *CMMechItemMove::manipulatorInfo() +{ + ManipulatorInfo *eventInfo = new ManipulatorInfo(); +// eventInfo->m_itemType.m_activate = CMManager::it_canvas_item; + eventInfo->m_acceptManipulationPtr = CMMechItemMove::acceptManipulation; + eventInfo->m_createManipulatorPtr = CMMechItemMove::construct; + return eventInfo; +} +bool CMMechItemMove::acceptManipulation( uint eventState, uint /*cmState*/, uint itemType, uint /*cnItemType*/ ) +{ + return ((itemType & CMManager::it_mechanics_item) || (itemType & CMManager::it_drawpart)) && !(eventState & CMManager::es_right_click); +} + + +bool CMMechItemMove::mousePressedInitial( const EventInfo &eventInfo ) +{ + m_eventInfo = eventInfo; + m_prevPos = eventInfo.pos; + + Item *item = dynamic_cast(eventInfo.qcanvasItemClickedOn); + if (!item) + return true; + + MechanicsItem *mechItem = dynamic_cast(eventInfo.qcanvasItemClickedOn); + + if (mechItem) + m_prevClickedOnSM = mechItem->selectionMode(); + + if (eventInfo.shiftPressed) + { + p_mechanicsDocument->unselectAll(); + p_mechanicsDocument->select(item); + if (mechItem) + { + mechItem->setSelectionMode(MechanicsItem::sm_move); + mechItem->setParentItem(0l); + } + } + else if ( !p_selectList->contains(mechItem) ) + { + if (!eventInfo.ctrlPressed) + p_mechanicsDocument->unselectAll(); + + p_mechanicsDocument->select(item); + + if (mechItem) + mechItem->setSelectionMode(MechanicsItem::sm_move); + } + else + { + if (mechItem) + mechItem->setSelectionMode(MechanicsItem::sm_move); + + if (m_eventInfo.ctrlPressed) + p_mechanicsDocument->unselect(item); + } + + if ( p_selectList->isEmpty() ) + return true; + + p_mechItemSelectList->setSelectionMode( MechanicsItem::sm_move ); + p_mechItemSelectList->setRaised(true); + return false; +} + + +bool CMMechItemMove::mouseMoved( const EventInfo &eventInfo ) +{ + const QPoint pos = eventInfo.pos; + + int x = pos.x(); + int y = pos.y(); + + const MechItemList itemList = p_mechItemSelectList->toplevelMechItemList(); + const MechItemList::const_iterator ilEnd = itemList.end(); + for ( MechItemList::const_iterator it = itemList.begin(); it != ilEnd; ++it ) + { + if (*it) + (*it)->moveBy( x - m_prevPos.x(), y - m_prevPos.y() ); + } + + m_prevPos = QPoint( x, y ); + + p_canvas->update(); + p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems ); + return false; +} + + +bool CMMechItemMove::mouseReleased( const EventInfo &eventInfo ) +{ + const QPoint pos = eventInfo.pos; + + int dx = pos.x() - m_eventInfo.pos.x(); + int dy = pos.y() - m_eventInfo.pos.y(); + + p_mechItemSelectList->setRaised(false); + + MechanicsItem *mechItem = dynamic_cast(m_eventInfo.qcanvasItemClickedOn); + if ( dx == 0 && dy == 0 ) + { + if ( mechItem && mechItem->isSelected() ) + { + if ( m_prevClickedOnSM == MechanicsItem::sm_resize ) + mechItem->setSelectionMode( MechanicsItem::sm_rotate ); + else + mechItem->setSelectionMode( MechanicsItem::sm_resize ); + } + p_itemDocument->requestStateSave(); + return true; + } + + if ( mechItem && mechItem->isSelected() ) + { + if ( m_prevClickedOnSM == MechanicsItem::sm_rotate ) + mechItem->setSelectionMode(MechanicsItem::sm_rotate); + else + mechItem->setSelectionMode(MechanicsItem::sm_resize); + } + + QStringList itemIDs; + + ItemList itemList = p_mechItemSelectList->items(); + const ItemList::iterator ilEnd = itemList.end(); + for ( ItemList::iterator it = itemList.begin(); it != ilEnd; ++it ) + { + if (*it) { + itemIDs.append( (*it)->id() ); + } + } + + p_mechItemSelectList->setSelectionMode( MechanicsItem::sm_resize ); + p_itemDocument->requestStateSave(); + p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems ); + return true; +} + + + +//BEGIN class SelectRectangle +SelectRectangle::SelectRectangle( int x, int y, int w, int h, QCanvas *qcanvas ) + : m_x(x), m_y(y) +{ + m_topLine = new QCanvasLine(qcanvas); + m_rightLine = new QCanvasLine(qcanvas); + m_bottomLine = new QCanvasLine(qcanvas); + m_leftLine = new QCanvasLine(qcanvas); + setSize( w, h ); + + QCanvasLine* lines[] = { m_topLine, m_rightLine, m_bottomLine, m_leftLine }; + for ( int i=0; i<4; ++ i) + { + lines[i]->setPen( QPen( QColor(190,190,190), 1, Qt::DotLine ) ); + lines[i]->setZ( ICNDocument::Z::Select ); + lines[i]->show(); + } +} + + +SelectRectangle::~SelectRectangle() +{ + delete m_topLine; + delete m_rightLine; + delete m_bottomLine; + delete m_leftLine; +} + + +void SelectRectangle::setSize( int w, int h ) +{ + m_topLine->setPoints( m_x, m_y, m_x+w, m_y ); + m_rightLine->setPoints( m_x+w, m_y, m_x+w, m_y+h ); + m_bottomLine->setPoints( m_x+w, m_y+h, m_x, m_y+h ); + m_leftLine->setPoints( m_x, m_y+h, m_x, m_y ); + m_w = w; + m_h = h; +} + + +QCanvasItemList SelectRectangle::collisions() +{ + QCanvas *canvas = m_topLine->canvas(); + + return canvas->collisions( QRect( m_x, m_y, m_w, m_h ) ); +} +//END class SelectRectangle + + +//BEGIN class CMSelect +CMSelect::CMSelect( ItemDocument *itemDocument, CMManager *cmManager ) + : CanvasManipulator( itemDocument, cmManager ) +{ + m_selectRectangle = 0l; +} +CMSelect::~CMSelect() +{ + delete m_selectRectangle; + m_selectRectangle = 0l; +} +CanvasManipulator* CMSelect::construct( ItemDocument *itemDocument, CMManager *cmManager ) +{ + return new CMSelect(itemDocument,cmManager); +} +ManipulatorInfo *CMSelect::manipulatorInfo() +{ + ManipulatorInfo *eventInfo = new ManipulatorInfo(); +// eventInfo->m_itemType.m_activate = CMManager::it_none; + eventInfo->m_acceptManipulationPtr = CMSelect::acceptManipulation; + eventInfo->m_createManipulatorPtr = CMSelect::construct; + return eventInfo; +} +bool CMSelect::acceptManipulation( uint /*eventState*/, uint /*cmState*/, uint itemType, uint /*cnItemType*/ ) +{ + return (itemType & CMManager::it_none); +} + + +bool CMSelect::mousePressedInitial( const EventInfo &eventInfo ) +{ + m_eventInfo = eventInfo; + + if (!eventInfo.ctrlPressed) { + p_itemDocument->unselectAll(); + } + + m_selectRectangle = new SelectRectangle( eventInfo.pos.x(), eventInfo.pos.y(), 0, 0, p_canvas ); + return false; +} + + +bool CMSelect::mouseMoved( const EventInfo &eventInfo ) +{ + QPoint pos = eventInfo.pos; + + m_selectRectangle->setSize( pos.x()-m_eventInfo.pos.x(), pos.y()-m_eventInfo.pos.y() ); + + if (m_eventInfo.ctrlPressed) { + p_itemDocument->select( m_selectRectangle->collisions() ); + } else if (p_selectList) { + p_selectList->setItems( m_selectRectangle->collisions() ); + } + + if (p_selectList && !p_mechanicsDocument) { + p_selectList->setSelected(true); + } + return false; +} + + +bool CMSelect::mouseReleased( const EventInfo &/*eventInfo*/ ) +{ + delete m_selectRectangle; + m_selectRectangle = 0l; + + return true; +} +//END class CMSelect + + + + +CMItemDrag::CMItemDrag( ItemDocument *itemDocument, CMManager *cmManager ) + : CanvasManipulator( itemDocument, cmManager ) +{ + b_dragged = false; +} +CMItemDrag::~CMItemDrag() +{ +} +CanvasManipulator* CMItemDrag::construct( ItemDocument *itemDocument, CMManager *cmManager ) +{ + return new CMItemDrag(itemDocument,cmManager); +} +ManipulatorInfo *CMItemDrag::manipulatorInfo() +{ + ManipulatorInfo *eventInfo = new ManipulatorInfo(); +// eventInfo->m_itemType.m_activate = CMManager::it_canvas_item; + eventInfo->m_acceptManipulationPtr = CMItemDrag::acceptManipulation; + eventInfo->m_createManipulatorPtr = CMItemDrag::construct; + return eventInfo; +} +bool CMItemDrag::acceptManipulation( uint /*eventState*/, uint /*cmState*/, uint itemType, uint cnItemType ) +{ + return (itemType & (CMManager::it_canvas_item|CMManager::it_pin)) && !(cnItemType & CMManager::isi_isMovable); +} + + +bool CMItemDrag::mousePressedInitial( const EventInfo &eventInfo ) +{ + m_eventInfo = eventInfo; + b_dragged = false; + return false; +} + + +bool CMItemDrag::mouseMoved( const EventInfo &eventInfo ) +{ + const QPoint pos = eventInfo.pos; + + if ( b_dragged || + pos.x() > (m_eventInfo.pos.x()+4 ) || + pos.x() < (m_eventInfo.pos.x()-4) || + pos.y() > (m_eventInfo.pos.y()+4) || + pos.y() < (m_eventInfo.pos.y()-4) ) + { + + b_dragged = true; + + if ( m_eventInfo.itemRtti == ItemDocument::RTTI::Pin ) + ((PinItem*)m_eventInfo.qcanvasItemClickedOn)->dragged( pos.x() - m_eventInfo.pos.x() ); + } + return false; +} + + +bool CMItemDrag::mouseReleased( const EventInfo &/*eventInfo*/ ) +{ + if ( !b_dragged && m_eventInfo.itemRtti == ItemDocument::RTTI::Pin ) + (static_cast(m_eventInfo.qcanvasItemClickedOn))->switchState(); + + p_itemDocument->requestStateSave(); + return true; +} + + +//BEGIN class CanvasEllipseDraw +CanvasEllipseDraw::CanvasEllipseDraw( int x, int y, QCanvas * canvas ) + : QCanvasEllipse( 0, 0, canvas ) +{ + move( x, y ); +} + + +void CanvasEllipseDraw::drawShape( QPainter & p ) +{ + p.drawEllipse( int(x()-width()/2), int(y()-height()/2), width(), height() ); +} +//END class CanvasEllipseDraw + + + +//BEGIN class CMDraw +CMDraw::CMDraw( ItemDocument *itemDocument, CMManager *cmManager ) + : CanvasManipulator( itemDocument, cmManager ) +{ + m_pDrawLine = 0l; + m_pDrawRectangle = 0l; + m_pDrawEllipse = 0l; +} +CMDraw::~CMDraw() +{ + p_cmManager->setDrawAction(-1); +} +CanvasManipulator* CMDraw::construct( ItemDocument *itemDocument, CMManager *cmManager ) +{ + return new CMDraw(itemDocument,cmManager); +} +ManipulatorInfo *CMDraw::manipulatorInfo() +{ + ManipulatorInfo *eventInfo = new ManipulatorInfo(); + eventInfo->m_acceptManipulationPtr = CMDraw::acceptManipulation; + eventInfo->m_createManipulatorPtr = CMDraw::construct; + return eventInfo; +} +bool CMDraw::acceptManipulation( uint /*eventState*/, uint cmState, uint /*itemType*/, uint /*cnItemType*/ ) +{ + return (cmState & CMManager::cms_draw); +} + + +bool CMDraw::mousePressedInitial( const EventInfo &eventInfo ) +{ + m_eventInfo = eventInfo; + + switch ( (DrawPart::DrawAction) p_cmManager->drawAction() ) + { + case DrawPart::da_text: + case DrawPart::da_rectangle: + { + m_pDrawRectangle = new QCanvasRectangle( eventInfo.pos.x(), eventInfo.pos.y(), 0, 0, p_canvas ); + m_pDrawRectangle->setPen( QPen( QColor(0,0,0), 1 ) ); + m_pDrawRectangle->setZ( ICNDocument::Z::Select ); + m_pDrawRectangle->show(); + break; + } + case DrawPart::da_ellipse: + { + m_pDrawEllipse = new CanvasEllipseDraw( eventInfo.pos.x(), eventInfo.pos.y(), p_canvas ); + m_pDrawEllipse->setPen( QPen( QColor(0,0,0), 1 ) ); + m_pDrawEllipse->setZ( ICNDocument::Z::Select ); + m_pDrawEllipse->show(); + break; + } + case DrawPart::da_line: + case DrawPart::da_arrow: + { + m_pDrawLine = new QCanvasLine(p_canvas); + m_pDrawLine->setPoints( eventInfo.pos.x(), eventInfo.pos.y(), eventInfo.pos.x(), eventInfo.pos.y() ); + m_pDrawLine->setPen( QPen( QColor(0,0,0), 1 ) ); + m_pDrawLine->setZ( ICNDocument::Z::Select ); + m_pDrawLine->show(); + break; + } + default: + return true; + } + + return false; +} + + +bool CMDraw::mouseMoved( const EventInfo &eventInfo ) +{ + const QPoint pos = eventInfo.pos; + + if (m_pDrawRectangle) + m_pDrawRectangle->setSize( pos.x()-m_eventInfo.pos.x(), pos.y()-m_eventInfo.pos.y() ); + + else if (m_pDrawEllipse) + { +// QRect r( m_eventInfo.pos.x(), m_eventInfo.pos.y(), pos.x()-m_eventInfo.pos.x(), pos.y()-m_eventInfo.pos.y() ); +// r = r.normalize(); +// +// m_pDrawEllipse->setSize( r.width(), r.height() ); +// m_pDrawEllipse->move( r.left()+(r.width()/2), r.top()+(r.height()/2) ); + + m_pDrawEllipse->setSize( 2*QABS(pos.x()-m_eventInfo.pos.x()), 2*QABS(pos.y()-m_eventInfo.pos.y()) ); + } + + else if (m_pDrawLine) + m_pDrawLine->setPoints( eventInfo.pos.x(), eventInfo.pos.y(), m_pDrawLine->endPoint().x(), m_pDrawLine->endPoint().y() ); + + else + return true; + + return false; +} + + +bool CMDraw::mouseReleased( const EventInfo &eventInfo ) +{ + const QPoint pos = eventInfo.pos; + + QRect sizeRect; + + if ( m_pDrawRectangle || m_pDrawEllipse ) + { + if (m_pDrawRectangle) + { + sizeRect = m_pDrawRectangle->rect(); + + // We have to manually adjust the size rect so that it matches up with what the user has drawn + + sizeRect.setWidth( sizeRect.width()+1 ); + sizeRect.setHeight( sizeRect.height()+1 ); + + sizeRect = sizeRect.normalize(); + + if ( m_pDrawRectangle->rect().width() < 0 ) + sizeRect.moveLeft( sizeRect.left() + 1); + + if ( m_pDrawRectangle->rect().height() < 0 ) + sizeRect.moveTop( sizeRect.top() + 1); + } + else + { + int w = m_pDrawEllipse->width()+1; + int h = m_pDrawEllipse->height()+1; + int x = int(m_pDrawEllipse->x()-w/2); + int y = int(m_pDrawEllipse->y()-h/2); + sizeRect = QRect( x, y, w, h ).normalize(); + } + + delete m_pDrawRectangle; + delete m_pDrawEllipse; + m_pDrawRectangle = 0l; + m_pDrawEllipse = 0l; + } + else if (m_pDrawLine) + { + int sx = m_pDrawLine->startPoint().x(); + int sy = m_pDrawLine->startPoint().y(); + int ex = m_pDrawLine->endPoint().x(); + int ey = m_pDrawLine->endPoint().y(); + + sizeRect = QRect( ex, ey, sx-ex, sy-ey ); + + delete m_pDrawLine; + m_pDrawLine = 0l; + } + else + return true; + + QString id; + switch ( (DrawPart::DrawAction) p_cmManager->drawAction() ) + { + case DrawPart::da_rectangle: + id = "dp/rectangle"; + break; + + case DrawPart::da_ellipse: + id = "dp/ellipse"; + break; + + case DrawPart::da_text: + id = "dp/canvas_text"; + + if ( sizeRect.width() < 56 ) + sizeRect.setWidth( 56 ); + + if ( sizeRect.height() < 24 ) + sizeRect.setHeight( 24 ); + + break; + + case DrawPart::da_line: + id = "dp/line"; + break; + + case DrawPart::da_arrow: + id = "dp/arrow"; + break; + } + if ( id.isEmpty() ) + return true; + + Item * item = p_itemDocument->addItem( id, sizeRect.topLeft(), true ); + if (!item) + return true; + item->move( sizeRect.x(), sizeRect.y() ); // We call this again as p_itemDocument->addItem will move the item if it is slightly off the canvas. + + item->setSize( 0, 0, sizeRect.width(), sizeRect.height() ); + + p_itemDocument->requestStateSave(); + return true; +} +//END class CMDraw + + + +//BEGIN class ManualConnectorDraw +ManualConnectorDraw::ManualConnectorDraw( ICNDocument *_icnDocument, const QPoint &initialPos ) +{ + m_color = Qt::black; + + icnDocument = _icnDocument; + m_currentPos = m_previousPos = m_initialPos = initialPos; + p_initialItem = icnDocument->itemAtTop(initialPos); + + b_currentVertical = false; + b_orientationDefined = false; + + m_connectorLines.append( m_previousCon = new QCanvasLine( icnDocument->canvas() ) ); + m_connectorLines.append( m_currentCon = new QCanvasLine( icnDocument->canvas() ) ); + + m_currentCon->setPoints( initialPos.x(), initialPos.y(), initialPos.x(), initialPos.y() ); + m_previousCon->setPoints( initialPos.x(), initialPos.y(), initialPos.x(), initialPos.y() ); + + m_currentCon->setPen( m_color ); + m_previousCon->setPen( m_color ); + + updateConnectorEnds(); + + m_currentCon->show(); + m_previousCon->show(); +} + + +ManualConnectorDraw::~ManualConnectorDraw() +{ + const QValueList::iterator end = m_connectorLines.end(); + for ( QValueList::iterator it = m_connectorLines.begin(); it != end; ++it ) + delete *it; + + m_connectorLines.clear(); +} + + +void ManualConnectorDraw::setColor( const QColor & color ) +{ + m_color = color; + + const QValueList::iterator end = m_connectorLines.end(); + for ( QValueList::iterator it = m_connectorLines.begin(); it != end; ++it ) + (*it)->setPen( m_color ); +} + + +void ManualConnectorDraw::mouseMoved( const QPoint &pos ) +{ + if ( m_currentPos == pos ) return; + + if (!b_orientationDefined) + { + QPoint previousStart = m_previousCon->startPoint(); + + double distance = std::sqrt( std::pow( (double)(m_currentPos.x()-previousStart.x()), 2. ) + + std::pow( (double)(m_currentPos.y()-previousStart.y()), 2. ) ); + + if ( distance < 24 ) + { + b_currentVertical = ( std::abs( double(m_currentPos.x()-previousStart.x()) ) >= std::abs( double(m_currentPos.y()-previousStart.y()) ) ); + } + + } + + m_previousPos = m_currentPos; + m_currentPos = pos; + updateConnectorEnds(); +} + + +QCanvasItem* ManualConnectorDraw::mouseClicked( const QPoint &pos ) +{ + if (b_orientationDefined) + b_currentVertical = !b_currentVertical; + + else + mouseMoved(pos); + + b_orientationDefined = true; + + m_currentPos = pos; + + QCanvasItem * qcanvasItem = icnDocument->itemAtTop(pos); + + if ( qcanvasItem && pos != m_initialPos && qcanvasItem != p_initialItem ) + return qcanvasItem; + + m_previousCon = m_currentCon; + + m_connectorLines.append( m_currentCon = new QCanvasLine( icnDocument->canvas() ) ); + m_currentCon->setPoints( pos.x(), pos.y(), pos.x(), pos.y() ); + m_currentCon->setPen( m_color ); + updateConnectorEnds(); + m_currentCon->show(); + + return 0L; +} + + +void ManualConnectorDraw::updateConnectorEnds() +{ + QPoint pivot = m_currentPos; + QPoint previousStart = m_previousCon->startPoint(); + + if (b_currentVertical) + { + pivot.setY( previousStart.y() ); + m_currentCon->setPoints( pivot.x(), pivot.y(), pivot.x(), m_currentPos.y() ); + } + else + { + pivot.setX( previousStart.x() ); + m_currentCon->setPoints( pivot.x(), pivot.y(), m_currentPos.x(), pivot.y() ); + } + + m_previousCon->setPoints( previousStart.x(), previousStart.y(), pivot.x(), pivot.y() ); +} + + +QPointList ManualConnectorDraw::pointList() +{ + QPointList list; + list.append(m_initialPos); + + const QValueList::iterator end = m_connectorLines.end(); + for ( QValueList::iterator it = m_connectorLines.begin(); it != end; ++it ) + { + list.append( (*it)->endPoint() ); + } + + return list; +} +//END class ManualConnectorDraw + + +//BEGIN class ManipulatorInfo +ManipulatorInfo::ManipulatorInfo() +{ +} +//END class ManipulatorInfo + + +#include "canvasmanipulator.moc" diff --git a/src/canvasmanipulator.h b/src/canvasmanipulator.h new file mode 100644 index 0000000..06d463c --- /dev/null +++ b/src/canvasmanipulator.h @@ -0,0 +1,605 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef CANVAsmANIPULATOR_H +#define CANVAsmANIPULATOR_H + +#include "eventinfo.h" + +#include +#include + +class CanvasManipulator; +class Connector; +class CMManager; +class CNItem; +class CNItemGroup; +class EventInfo; +class FlowContainer; +class ICNDocument; +class Item; +class ItemDocument; +class ItemGroup; +class ItemView; +class ManipulatorInfo; +class ManualConnectorDraw; +class MechanicsItem; +class MechanicsGroup; +class MechanicsDocument; +class Node; +class NodeGroup; +class ResizeHandle; + +class QCanvas; +class QCanvasItem; +class QCanvasLine; +class QCanvasRectangle; +class QMouseEvent; +class QTimer; +class QWheelEvent; + +typedef CanvasManipulator*(*CreateManipulatorPtr)( ItemDocument *, CMManager * ); +typedef bool(*AcceptManipulationPtr)( uint eventState, uint cmState, uint itemType, uint cnItemType ); +typedef QValueList NodeGroupList; +typedef QValueList > ConnectorList; +typedef QValueList QPointList; + + +class ManipulatorInfo +{ +public: + ManipulatorInfo(); + AcceptManipulationPtr m_acceptManipulationPtr; + CreateManipulatorPtr m_createManipulatorPtr; +}; +typedef QValueList ManipulatorInfoList; + + +/** +Handles canvas manipulation, such as moving an item or resizing the canvas +@author David Saxton +*/ +class CMManager : public QObject +{ +Q_OBJECT +public: + enum EventState + { + es_right_click = 1 << 0, + es_ctrl_pressed = 1 << 1 + }; + enum CMState + { + cms_repeated_add = 1 << 0, + cms_manual_route = 1 << 1, + cms_draw = 1 << 2 + }; + enum ItemType + { + it_none = 1 << 0, + it_node = 1 << 1, + it_connector = 1 << 2, + it_pin = 1 << 3, + it_canvas_item = 1 << 4, + it_mechanics_item = 1 << 5, + it_resize_handle = 1 << 6, + it_drawpart = 1 << 7 + }; + enum ItemStateInfo + { + isi_isMovable = 0x2, + }; + CMManager( ItemDocument *itemDocument ); + ~CMManager(); + /** + * Called when the user single-clicks the mouse + */ + void mousePressEvent( EventInfo eventInfo ); + /** + * Called when the user releases the mouse + */ + void mouseReleaseEvent( const EventInfo &eventInfo ); + /** + * Called when the user double clicks the mouse + */ + void mouseDoubleClickEvent( const EventInfo &eventInfo ); + /** + * Called when the user moves the mouse + */ + void mouseMoveEvent( const EventInfo &eventInfo ); + /** + * Called when the user scrolls the mouse + */ + void wheelEvent( const EventInfo &eventInfo ); + /** + * Set a current CMState to true or false + */ + void setCMState( CMState type, bool state ); + /** + * Cancels the current manipulation (if there is one) + */ + void cancelCurrentManipulation(); + CanvasManipulator * currentManipulator() const { return m_canvasManipulator; } + void setRepeatedAddId( const QString & repeatedId = QString::null ); + uint cmState() const { return m_cmState; } + void addManipulatorInfo( ManipulatorInfo *info ); + QString repeatedItemId() const { return m_repeatedItemId; } + void setDrawAction( int drawAction ); + int drawAction() const { return m_drawAction; } + +public slots: + void slotSetManualRoute( bool manualRoute ); + +signals: + void manualRoutingChanged( bool manualRouting ); + +protected: + /** + * Called when the mouse is moved or released, with the ResizeHandle that + * the mouse is currently over (which can be null). Updates which handle is + * selected, etc. + */ + void updateCurrentResizeHandle( ResizeHandle * mouseOver ); + CanvasManipulator *m_canvasManipulator; + uint m_cmState; + QString m_repeatedItemId; + ItemDocument *p_itemDocument; + ManipulatorInfoList m_manipulatorInfoList; + QGuardedPtr p_lastMouseOverItem; // Pointer to the item where the mouse was last over - this is used to determine when mouse + QGuardedPtr p_lastMouseOverResizeHandle; + QGuardedPtr p_lastItemClicked; + QTimer *m_allowItemScrollTmr; // When a user scrolls on the canvas, we don't want to stop scrolling when the user gets to (e.g.) a scrollable widget. So this timer prevents scrolling a widget for a few hundred milliseconds after a scroll event if it was initiated over the canvas + bool b_allowItemScroll; // See above. + int m_drawAction; + +private slots: + void slotAllowItemScroll() { b_allowItemScroll = true; } +}; + + +/** +Abstract class for a "editing operation" on the ICNDocument, such as moving an item or resizing the canvas +@author David Saxton +*/ +class CanvasManipulator +{ +public: + CanvasManipulator( ItemDocument *itemDocument, CMManager *cmManager ); + virtual ~CanvasManipulator(); + enum Type + { + RepeatedItemAdd, + RightClick, + AutoConnector, + ManualConnector, + ItemMove, + ItemResize, + MechItemMove, + Select, + CanvasResize, + ItemDrag, + Draw + }; + virtual Type type() const = 0; + /** + * Called when the user single-clicks the mouse + * @returns true if the manipulation operation has finished + */ + virtual bool mousePressedInitial( const EventInfo &/*info*/ ) { return false; } + /** + * Called when the user single-clicks the mouse after the first time (only + * applicable for those operations who are not oneClick + * @returns true if the manipulation operation has finished + */ + virtual bool mousePressedRepeat( const EventInfo &/*info*/ ) { return false; }; + /** + * Called when the user moves the mouse + * @returns true if the manipulation operation has finished + */ + virtual bool mouseMoved( const EventInfo &/*info*/ ) { return false; }; + /** + * Called when the user releases the mouse + * @returns true if the manipulation operation has finished + */ + virtual bool mouseReleased( const EventInfo &/*info*/ ) { return true; } + +protected: + Type m_type; + EventInfo m_eventInfo; + QPoint m_prevPos; + ItemDocument *p_itemDocument; + ICNDocument *p_icnDocument; + MechanicsDocument *p_mechanicsDocument; + QCanvas *p_canvas; + ItemGroup *p_selectList; + CNItemGroup *p_cnItemSelectList; + MechanicsGroup *p_mechItemSelectList; + CNItem *p_cnItemClickedOn; + MechanicsItem *p_mechanicsItemClickedOn; + CMManager *p_cmManager; +}; + + +/** +@author David Saxton +*/ +class CMRepeatedItemAdd : public CanvasManipulator +{ +public: + CMRepeatedItemAdd( ItemDocument *itemDocument, CMManager *cmManager ); + virtual ~CMRepeatedItemAdd(); + virtual Type type() const { return RepeatedItemAdd; } + + static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); + static ManipulatorInfo *manipulatorInfo(); + static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); + + virtual bool mousePressedInitial( const EventInfo &info ); + virtual bool mousePressedRepeat( const EventInfo &info ); + virtual bool mouseMoved( const EventInfo &info ); + virtual bool mouseReleased( const EventInfo &info ); + +protected: +}; + + + +/** +@author David Saxton +*/ +class CMRightClick : public CanvasManipulator +{ +public: + CMRightClick( ItemDocument *itemDocument, CMManager *cmManager ); + virtual ~CMRightClick(); + virtual Type type() const { return RightClick; } + + static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); + static ManipulatorInfo *manipulatorInfo(); + static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); + + virtual bool mousePressedInitial( const EventInfo &info ); + virtual bool mouseMoved( const EventInfo &info ); + virtual bool mouseReleased( const EventInfo &info ); + +protected: +}; + + +/** +@author David Saxton +*/ +class ConnectorDraw : public CanvasManipulator +{ + public: + ConnectorDraw( ItemDocument *itemDocument, CMManager *cmManager ); + virtual ~ConnectorDraw(); + + /** + * Returns the colour used to indicate that the current connection + * being drawn is valid. Invalid colour is black. + */ + static QColor validConnectionColor(); + + protected: + /** + * If the node has more than 2 connections, return one of the + * connectors + */ + Connector * toConnector( Node * node ); + /** + * Converts the given qcanvasitem to an appropriate node or connector. + * @param posIsExact if true, then only gets an appropriate node or + * connector when the to-be end-point of the new connector will coincide + * with pos (i.e. auto-connector will call this with posIsExact = false, + * and manual-connector will call this with posIsExact = true). + */ + void grabEndStuff( QCanvasItem * endItem, const QPoint & pos, bool posIsExact ); + /** + * Returns the closest point to the clickPos that is on the given + * connector. + */ + QPoint toValidPos( const QPoint & clickPos, Connector * clickedConnector ) const; + + QGuardedPtr p_startNode; + QGuardedPtr p_startConnector; + Node * p_endNode; + Connector * p_endConnector; + QPoint startConnectorPoint; +}; + + +/** +@author David Saxton +*/ +class CMAutoConnector : public ConnectorDraw +{ +public: + CMAutoConnector( ItemDocument *itemDocument, CMManager *cmManager ); + virtual ~CMAutoConnector(); + virtual Type type() const { return AutoConnector; } + + static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); + static ManipulatorInfo *manipulatorInfo(); + static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); + + virtual bool mousePressedInitial( const EventInfo &info ); + virtual bool mouseMoved( const EventInfo &info ); + virtual bool mouseReleased( const EventInfo &info ); + +protected: + QCanvasLine *m_connectorLine; +}; + + +/** +@author David Saxton +*/ +class CMManualConnector : public ConnectorDraw +{ +public: + CMManualConnector( ItemDocument *itemDocument, CMManager *cmManager ); + virtual ~CMManualConnector(); + virtual Type type() const { return ManualConnector; } + + static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); + static ManipulatorInfo *manipulatorInfo(); + static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); + + virtual bool mousePressedInitial( const EventInfo &info ); + virtual bool mousePressedRepeat( const EventInfo &info ); + virtual bool mouseMoved( const EventInfo &info ); + virtual bool mouseReleased( const EventInfo &info ); + +protected: + ConnectorList m_fixedRouteConnectors; + ManualConnectorDraw *m_manualConnectorDraw; +}; + + +/** +@author David Saxton +*/ +class CMItemMove : public CanvasManipulator +{ +public: + CMItemMove( ItemDocument *itemDocument, CMManager *cmManager ); + virtual ~CMItemMove(); + virtual Type type() const { return ItemMove; } + + static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); + static ManipulatorInfo *manipulatorInfo(); + static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); + + virtual bool mousePressedInitial( const EventInfo &info ); + virtual bool mouseMoved( const EventInfo &info ); + virtual bool mouseReleased( const EventInfo &info ); + +protected: + ConnectorList m_translatableConnectors; + NodeGroupList m_translatableNodeGroups; + FlowContainer *p_flowContainerCandidate; +}; + + +/** +@author David Saxton +*/ +class CMItemResize : public CanvasManipulator +{ +public: + CMItemResize( ItemDocument *itemDocument, CMManager *cmManager ); + virtual ~CMItemResize(); + virtual Type type() const { return ItemResize; } + + static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); + static ManipulatorInfo *manipulatorInfo(); + static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); + + virtual bool mousePressedInitial( const EventInfo &info ); + virtual bool mouseMoved( const EventInfo &info ); + virtual bool mouseReleased( const EventInfo &info ); + +protected: + ResizeHandle *p_resizeHandle; + double m_rh_dx; + double m_rh_dy; +}; + + +/** +@author David Saxton +*/ +class CMMechItemMove : public CanvasManipulator +{ +public: + CMMechItemMove( ItemDocument *itemDocument, CMManager *cmManager ); + virtual ~CMMechItemMove(); + virtual Type type() const { return MechItemMove; } + + static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); + static ManipulatorInfo *manipulatorInfo(); + static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); + + virtual bool mousePressedInitial( const EventInfo &info ); + virtual bool mouseMoved( const EventInfo &info ); + virtual bool mouseReleased( const EventInfo &info ); + +protected: + uint m_prevClickedOnSM; // Previous select mode of the item that was clicked on +}; + + +/** +@author David Saxton +*/ +class SelectRectangle +{ + public: + SelectRectangle( int x, int y, int w, int h, QCanvas *qcanvas ); + ~SelectRectangle(); + + void setSize( int w, int h ); + QCanvasItemList collisions(); + + protected: + QCanvasLine *m_topLine; + QCanvasLine *m_rightLine; + QCanvasLine *m_bottomLine; + QCanvasLine *m_leftLine; + const int m_x; + const int m_y; + int m_w; + int m_h; + int m_prevCollisions_w; + int m_prevCollisions_h; + QCanvasItemList m_prevCollisions; +}; + + +/** +@author David Saxton +*/ +class CMSelect : public CanvasManipulator +{ +public: + CMSelect( ItemDocument *itemDocument, CMManager *cmManager ); + virtual ~CMSelect(); + virtual Type type() const { return Select; } + + static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); + static ManipulatorInfo *manipulatorInfo(); + static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); + + virtual bool mousePressedInitial( const EventInfo &info ); + virtual bool mouseMoved( const EventInfo &info ); + virtual bool mouseReleased( const EventInfo &info ); + +protected: + SelectRectangle *m_selectRectangle; +}; + + +/** +@author David Saxton +*/ +class CMItemDrag : public CanvasManipulator +{ +public: + CMItemDrag( ItemDocument *itemDocument, CMManager *cmManager ); + virtual ~CMItemDrag(); + virtual Type type() const { return ItemDrag; } + + static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); + static ManipulatorInfo *manipulatorInfo(); + static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); + + virtual bool mousePressedInitial( const EventInfo &info ); + virtual bool mouseMoved( const EventInfo &info ); + virtual bool mouseReleased( const EventInfo &info ); + +protected: + bool b_dragged; +}; + + + +/** +@author David Saxton +A QCanvasEllipse that uses a pen (not a brush) to paint +*/ +class CanvasEllipseDraw : public QCanvasEllipse +{ + public: + CanvasEllipseDraw( int x, int y, QCanvas * canvas ); + + protected: + virtual void drawShape( QPainter & p ); +}; + + +/** +@author David Saxton +*/ +class CMDraw : public CanvasManipulator +{ + public: + CMDraw( ItemDocument *itemDocument, CMManager *cmManager ); + virtual ~CMDraw(); + virtual Type type() const { return Draw; } + + static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); + static ManipulatorInfo *manipulatorInfo(); + static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); + + virtual bool mousePressedInitial( const EventInfo &info ); + virtual bool mouseMoved( const EventInfo &info ); + virtual bool mouseReleased( const EventInfo &info ); + + protected: + QCanvasRectangle * m_pDrawRectangle; + CanvasEllipseDraw * m_pDrawEllipse; + QCanvasLine * m_pDrawLine; +}; + + +/** +@author David Saxton +*/ +class ManualConnectorDraw +{ + public: + ManualConnectorDraw( ICNDocument *_icnDocument, const QPoint &initialPos ); + virtual ~ManualConnectorDraw(); + + /** + * Called when the mouse is moved. + * Normally will do something like updating the connector route + */ + void mouseMoved( const QPoint &pos ); + /** + * Called when the user clicks the mouse. If the connector finishes on a + * valid QCanvasItem (Node or Connetor), then this is returned. Otherwise, + * null is returned. + */ + QCanvasItem * mouseClicked( const QPoint &pos ); + /** + * Returns the list of points that define the manual connection route + */ + QPointList pointList(); + /** + * Sets the colour used to draw the connection lines. + */ + void setColor( const QColor & color ); + + protected: + void updateConnectorEnds(); + + QValueList m_connectorLines; + ICNDocument *icnDocument; + + bool b_currentVertical; + bool b_orientationDefined; + + QPoint m_initialPos; + QPoint m_previousPos; + QPoint m_currentPos; + + QCanvasLine *m_currentCon; + QCanvasLine *m_previousCon; + + // The first item that we clicked on + QCanvasItem *p_initialItem; + + QColor m_color; +}; + + +#endif diff --git a/src/cells.cpp b/src/cells.cpp new file mode 100644 index 0000000..804a5dc --- /dev/null +++ b/src/cells.cpp @@ -0,0 +1,140 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "cells.h" + + + +#if 0 +class CellSmall +{ + public: + /** + * Resets bestScore, prevX, prevY, addedToLabels, it, permanent for each cell + */ + void reset(); + +// Point *point; // Pointer to the point in the TempLabelMap + short prevX, prevY; // Which cell this came from, (-1,-1) if originating cell + unsigned short CIpenalty; // 'Penalty' of using the cell from CNItem + unsigned short Cpenalty; // 'Penalty' of using the cell from Connector + unsigned short bestScore; // Best (lowest) score so far, _the_ best if it is permanent + unsigned char numCon; // Number of connectors through that point + bool permanent:1; // Whether the score can be improved on + bool addedToLabels:1; // Whether the cell has already been added to the list of cells to check +}; + +class CellBig +{ + public: + /** + * Resets bestScore, prevX, prevY, addedToLabels, it, permanent for each cell + */ + void reset(); + + Point *point; // Pointer to the point in the TempLabelMap + short prevX, prevY; // Which cell this came from, (-1,-1) if originating cell + unsigned short CIpenalty; // 'Penalty' of using the cell from CNItem + unsigned short Cpenalty; // 'Penalty' of using the cell from Connector + unsigned short bestScore; // Best (lowest) score so far, _the_ best if it is permanent + unsigned char numCon; // Number of connectors through that point + bool permanent:1; // Whether the score can be improved on + bool addedToLabels:1; // Whether the cell has already been added to the list of cells to check +}; +#endif + + +Cells::Cells( const uint w, const uint h ) +{ +#if 0 + kdDebug() << "sizeof(CellSmall)="< +#include +#include +#include +#include +#include + + +CircuitDocument::CircuitDocument( const QString & caption, KTechlab *ktechlab, const char *name ) + : ICNDocument( caption, ktechlab, name ) +{ + m_pOrientationAction = new KActionMenu( i18n("Orientation"), "rotate", this ); + + m_type = Document::dt_circuit; + m_pDocumentIface = new CircuitDocumentIface(this); + m_fileExtensionInfo = i18n("*.circuit|Circuit(*.circuit)\n*|All Files"); + + m_cmManager->addManipulatorInfo( CMSelect::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMDraw::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMRightClick::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMRepeatedItemAdd::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMItemResize::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMItemDrag::manipulatorInfo() ); + + connect( this, SIGNAL(connectorAdded(Connector*)), this, SLOT(requestAssignCircuits()) ); + connect( this, SIGNAL(connectorAdded(Connector*)), this, SLOT(connectorAdded(Connector*)) ); + + m_updateCircuitsTmr = new QTimer(); + connect( m_updateCircuitsTmr, SIGNAL(timeout()), this, SLOT(assignCircuits()) ); + + requestStateSave(); +} + +CircuitDocument::~CircuitDocument() +{ + m_bDeleted = true; + deleteCircuits(); + + delete m_updateCircuitsTmr; + m_updateCircuitsTmr = 0l; + + delete m_pDocumentIface; + m_pDocumentIface = 0l; +} + + +void CircuitDocument::slotInitItemActions( Item *itemBase ) +{ + ICNDocument::slotInitItemActions(itemBase); + + CircuitView * activeCircuitView = dynamic_cast(activeView()); + if ( !p_ktechlab || !activeCircuitView ) + return; + + Component * item = dynamic_cast(itemBase); + + if ( !item && m_selectList->count() > 0 || !m_selectList->itemsAreSameType() ) + return; + + KAction * orientation_actions[] = { + activeCircuitView->action("edit_orientation_0"), + activeCircuitView->action("edit_orientation_90"), + activeCircuitView->action("edit_orientation_180"), + activeCircuitView->action("edit_orientation_270") }; + + if ( !item || !item->canRotate() ) + { + for ( unsigned i = 0; i < 4; ++i ) + orientation_actions[i]->setEnabled(false); + return; + } + + for ( unsigned i = 0; i < 4; ++ i) + { + orientation_actions[i]->setEnabled(true); + m_pOrientationAction->remove( orientation_actions[i] ); + m_pOrientationAction->insert( orientation_actions[i] ); + } + + if ( item->angleDegrees() == 0 ) + (static_cast( orientation_actions[0] ))->setChecked(true); + + else if ( item->angleDegrees() == 90 ) + (static_cast( orientation_actions[1] ))->setChecked(true); + + else if ( item->angleDegrees() == 180 ) + (static_cast( orientation_actions[2] ))->setChecked(true); + + else if ( item->angleDegrees() == 270 ) + (static_cast( orientation_actions[3] ))->setChecked(true); +} + + +void CircuitDocument::rotateCounterClockwise() +{ + m_selectList->slotRotateCCW(); + requestRerouteInvalidatedConnectors(); +} +void CircuitDocument::rotateClockwise() +{ + m_selectList->slotRotateCW(); + requestRerouteInvalidatedConnectors(); +} +void CircuitDocument::itemFlip() +{ + m_selectList->slotFlip(); + requestRerouteInvalidatedConnectors(); +} +void CircuitDocument::setOrientation0() +{ + m_selectList->slotSetOrientation0(); + requestRerouteInvalidatedConnectors(); +} +void CircuitDocument::setOrientation90() +{ + m_selectList->slotSetOrientation90(); + requestRerouteInvalidatedConnectors(); +} +void CircuitDocument::setOrientation180() +{ + m_selectList->slotSetOrientation180(); + requestRerouteInvalidatedConnectors(); +} +void CircuitDocument::setOrientation270() +{ + m_selectList->slotSetOrientation270(); + requestRerouteInvalidatedConnectors(); +} + + +View *CircuitDocument::createView( ViewContainer *viewContainer, uint viewAreaId, const char *name ) +{ + View *view = new CircuitView( this, viewContainer, viewAreaId, name ); + handleNewView(view); + return view; +} + + +void CircuitDocument::slotUpdateConfiguration() +{ + ICNDocument::slotUpdateConfiguration(); + + NodeList::iterator nodeEnd = m_nodeList.end(); + for ( NodeList::iterator it = m_nodeList.begin(); it != nodeEnd; ++it ) + { + (static_cast((Node*)*it))->setShowVoltageBars( KTLConfig::showVoltageBars() ); + } + + ComponentList::iterator componentsEnd = m_componentList.end(); + for ( ComponentList::iterator it = m_componentList.begin(); it != componentsEnd; ++it ) + (*it)->slotUpdateConfiguration(); +} + + +void CircuitDocument::update() +{ + ICNDocument::update(); + + if ( KTLConfig::showVoltageBars() ) + { + NodeList::iterator end = m_nodeList.end(); + for ( NodeList::iterator it = m_nodeList.begin(); it != end; ++it ) + { + (static_cast((Node*)*it))->setNodeChanged(); + } + } +} + + +void CircuitDocument::fillContextMenu( const QPoint &pos ) +{ + ICNDocument::fillContextMenu(pos); + + CircuitView * activeCircuitView = dynamic_cast(activeView()); + + if ( m_selectList->count() < 1 || !activeCircuitView ) + return; + + Component * item = dynamic_cast( selectList()->activeItem() ); + + // NOTE: I negated this whole condition because I couldn't make out quite what the + //logic was --electronerd + if (!( !item && m_selectList->count() > 0 || !m_selectList->itemsAreSameType() )) + { + KAction * orientation_actions[] = { + activeCircuitView->action("edit_orientation_0"), + activeCircuitView->action("edit_orientation_90"), + activeCircuitView->action("edit_orientation_180"), + activeCircuitView->action("edit_orientation_270") }; + + if ( !item || !item->canRotate() ) + return; + + for ( unsigned i = 0; i < 4; ++ i) + { + m_pOrientationAction->remove( orientation_actions[i] ); + m_pOrientationAction->insert( orientation_actions[i] ); + } + + QPtrList orientation_actionlist; + // orientation_actionlist.prepend( new KActionSeparator() ); + orientation_actionlist.append( m_pOrientationAction ); + p_ktechlab->plugActionList( "orientation_actionlist", orientation_actionlist ); + } + + if(m_selectList->count() > 1 && countExtCon(m_selectList->items()) > 0) + { + QPtrList component_actionlist; + // component_actionlist.append( new KActionSeparator() ); + component_actionlist.append( activeCircuitView->action("circuit_create_subcircuit") ); + p_ktechlab->plugActionList( "component_actionlist", component_actionlist ); + } +} + + +void CircuitDocument::deleteCircuits() +{ + const CircuitList::iterator end = m_circuitList.end(); + for ( CircuitList::iterator it = m_circuitList.begin(); it != end; ++it ) + { + Simulator::self()->detachCircuit(*it); + delete *it; + } + m_circuitList.clear(); + m_pinList.clear(); + m_wireList.clear(); +} + + +void CircuitDocument::requestAssignCircuits() +{ +// kdDebug() << k_funcinfo << endl; + deleteCircuits(); + m_updateCircuitsTmr->stop(); + m_updateCircuitsTmr->start( 0, true ); +} + + +void CircuitDocument::connectorAdded( Connector * connector ) +{ + if (connector) + { + connect( connector, SIGNAL(numWiresChanged(unsigned )), this, SLOT(requestAssignCircuits()) ); + connect( connector, SIGNAL(removed(Connector*)), this, SLOT(requestAssignCircuits()) ); + } +} + + +void CircuitDocument::itemAdded( Item * item) +{ + ICNDocument::itemAdded( item ); + componentAdded( item ); +} + + +void CircuitDocument::componentAdded( Item * item ) +{ + Component * component = dynamic_cast(item); + if (!component) + return; + + requestAssignCircuits(); + + connect( component, SIGNAL(elementCreated(Element*)), this, SLOT(requestAssignCircuits()) ); + connect( component, SIGNAL(elementDestroyed(Element*)), this, SLOT(requestAssignCircuits()) ); + connect( component, SIGNAL(removed(Item*)), this, SLOT(componentRemoved(Item*)) ); + + // We don't attach the component to the Simulator just yet, as the + // Component's vtable is not yet fully constructed, and so Simulator can't + // tell whether or not it is a logic component + if ( !m_toSimulateList.contains(component) ) + m_toSimulateList << component; +} + + +void CircuitDocument::componentRemoved( Item * item ) +{ + Component * component = dynamic_cast(item); + if (!component) + return; + m_componentList.remove(component); + + requestAssignCircuits(); + Simulator::self()->detachComponent(component); +} + + +void CircuitDocument::calculateConnectorCurrents() +{ + const CircuitList::iterator circuitEnd = m_circuitList.end(); + for ( CircuitList::iterator it = m_circuitList.begin(); it != circuitEnd; ++it ) + (*it)->updateCurrents(); + + PinList groundPins; + + // Tell the Pins to reset their calculated currents to zero + m_pinList.remove((Pin*)0l); + const PinList::iterator pinEnd = m_pinList.end(); + for ( PinList::iterator it = m_pinList.begin(); it != pinEnd; ++it ) + { + if ( Pin *n = dynamic_cast((Pin*)*it) ) + { + n->resetCurrent(); + n->setSwitchCurrentsUnknown(); + + if ( !n->parentECNode()->isChildNode() ) + { + n->setCurrentKnown( true ); + // (and it has a current of 0 amps) + } + else if ( n->groundType() == Pin::gt_always ) + { + groundPins << n; + n->setCurrentKnown( false ); + } + else + { + // Child node that is non ground + n->setCurrentKnown( n->parentECNode()->numPins() < 2 ); + } + } + } + + + // Tell the components to update their ECNode's currents' from the elements + const ComponentList::iterator componentEnd = m_componentList.end(); + for ( ComponentList::iterator it = m_componentList.begin(); it != componentEnd; ++it ) + (*it)->setNodalCurrents(); + + + // And now for the wires and switches... + m_wireList.remove((Wire*)0l); + const WireList::iterator clEnd = m_wireList.end(); + for ( WireList::iterator it = m_wireList.begin(); it != clEnd; ++it ) + (*it)->setCurrentKnown(false); + + SwitchList switches = m_switchList; + WireList wires = m_wireList; + bool found = true; + while ( (!wires.isEmpty() || !switches.isEmpty() || !groundPins.isEmpty()) && found ) + { + found = false; + + WireList::iterator wiresEnd = wires.end(); + for ( WireList::iterator it = wires.begin(); it != wiresEnd; ) + { + if ( (*it)->calculateCurrent() ) + { + found = true; + WireList::iterator oldIt = it; + ++it; + wires.remove(oldIt); + } + else + ++it; + } + + SwitchList::iterator switchesEnd = switches.end(); + for ( SwitchList::iterator it = switches.begin(); it != switchesEnd; ) + { + if ( (*it)->calculateCurrent() ) + { + found = true; + SwitchList::iterator oldIt = it; + ++it; + switches.remove(oldIt); + } + else + ++it; + } + + PinList::iterator groundPinsEnd = groundPins.end(); + for ( PinList::iterator it = groundPins.begin(); it != groundPinsEnd; ) + { + if ( (*it)->calculateCurrentFromWires() ) + { + found = true; + PinList::iterator oldIt = it; + ++it; + groundPins.remove(oldIt); + } + else + ++it; + } + } +} + + +void CircuitDocument::assignCircuits() +{ + // Now we can finally add the unadded components to the Simulator + const ComponentList::iterator toSimulateEnd = m_toSimulateList.end(); + for ( ComponentList::iterator it = m_toSimulateList.begin(); it != toSimulateEnd; ++it ) + Simulator::self()->attachComponent(*it); + m_toSimulateList.clear(); + + + + // Stage 0: Build up pin and wire lists + m_pinList.clear(); + const NodeList::const_iterator nodeListEnd = m_nodeList.end(); + for ( NodeList::const_iterator it = m_nodeList.begin(); it != nodeListEnd; ++it ) + { + if ( ECNode * ecnode = dynamic_cast((Node*)*it) ) + { + for ( unsigned i = 0; i < ecnode->numPins(); i++ ) + m_pinList << ecnode->pin(i); + } + } + + m_wireList.clear(); + const ConnectorList::const_iterator connectorListEnd = m_connectorList.end(); + for ( ConnectorList::const_iterator it = m_connectorList.begin(); it != connectorListEnd; ++it ) + { + for ( unsigned i = 0; i < (*it)->numWires(); i++ ) + m_wireList << (*it)->wire(i); + } + + + + + typedef QValueList PinListList; + + // Stage 1: Partition the circuit up into dependent areas (bar splitting + // at ground pins) + PinList unassignedPins = m_pinList; + PinListList pinListList; + while ( !unassignedPins.isEmpty() ) + { + PinList pinList; + getPartition( *unassignedPins.begin(), & pinList, & unassignedPins ); + pinListList.append(pinList); + } +// kdDebug () << "pinListList.size()="<init(); + + m_switchList.clear(); + m_componentList.clear(); + const ItemList::const_iterator cilEnd = m_itemList.end(); + for ( ItemList::const_iterator it = m_itemList.begin(); it != cilEnd; ++it ) + { + Component * component = dynamic_cast((Item*)(*it)); + if ( !component ) + continue; + + m_componentList << component; + component->initElements(0); + m_switchList += component->switchList(); + } + + circuitListEnd = m_circuitList.end(); + for ( CircuitList::iterator it = m_circuitList.begin(); it != circuitListEnd; ++it ) + (*it)->createMatrixMap(); + + for ( ItemList::const_iterator it = m_itemList.begin(); it != cilEnd; ++it ) + { + Component * component = dynamic_cast((Item*)(*it)); + if (component) + component->initElements(1); + } + + circuitListEnd = m_circuitList.end(); + for ( CircuitList::iterator it = m_circuitList.begin(); it != circuitListEnd; ++it ) + { + (*it)->initCache(); + Simulator::self()->attachCircuit(*it); + } +} + + +void CircuitDocument::getPartition( Pin *pin, PinList *pinList, PinList *unassignedPins, bool onlyGroundDependent ) +{ + if (!pin) + return; + + unassignedPins->remove(pin); + + if ( pinList->contains(pin) ) + return; + pinList->append(pin); + + const PinList localConnectedPins = pin->localConnectedPins(); + const PinList::const_iterator end = localConnectedPins.end(); + for ( PinList::const_iterator it = localConnectedPins.begin(); it != end; ++it ) + getPartition( *it, pinList, unassignedPins, onlyGroundDependent ); + + const PinList groundDependentPins = pin->groundDependentPins(); + const PinList::const_iterator dEnd = groundDependentPins.end(); + for ( PinList::const_iterator it = groundDependentPins.begin(); it != dEnd; ++it ) + getPartition( *it, pinList, unassignedPins, onlyGroundDependent ); + + if (!onlyGroundDependent) + { + PinList circuitDependentPins = pin->circuitDependentPins(); + const PinList::const_iterator dEnd = circuitDependentPins.end(); + for ( PinList::const_iterator it = circuitDependentPins.begin(); it != dEnd; ++it ) + getPartition( *it, pinList, unassignedPins, onlyGroundDependent ); + } +} + + +void CircuitDocument::splitIntoCircuits( PinList *pinList ) +{ + // First: identify ground + PinList unassignedPins = *pinList; + typedef QValueList PinListList; + PinListList pinListList; + while ( !unassignedPins.isEmpty() ) + { + PinList tempPinList; + getPartition( *unassignedPins.begin(), & tempPinList, & unassignedPins, true ); + pinListList.append(tempPinList); + } + const PinListList::iterator nllEnd = pinListList.end(); + for ( PinListList::iterator it = pinListList.begin(); it != nllEnd; ++it ) + Circuit::identifyGround(*it); + + + + bool allGround = false; + while ( !pinList->isEmpty() && !allGround ) + { + PinList::iterator end = pinList->end(); + PinList::iterator it = pinList->begin(); + + while ( it != end && (*it)->eqId() == -1 ) + ++it; + + if ( it == end ) + allGround = true; + + else + { + Circuitoid *circuitoid = new Circuitoid; + recursivePinAdd( *it, circuitoid, pinList ); + + if ( !tryAsLogicCircuit(circuitoid) ) + m_circuitList += createCircuit(circuitoid); + + delete circuitoid; + } + } + + + // Remaining pins are ground; tell them about it + // TODO This is a bit hacky.... + const PinList::iterator end = pinList->end(); + for ( PinList::iterator it = pinList->begin(); it != end; ++it ) + { + (*it)->setVoltage(0.0); + + ElementList elements = (*it)->elements(); + const ElementList::iterator eEnd = elements.end(); + for ( ElementList::iterator it = elements.begin(); it != eEnd; ++it ) + { + if ( LogicIn * logicIn = dynamic_cast(*it) ) + { + logicIn->setLastState(false); + logicIn->callCallback(); + } + } + } +} + + +void CircuitDocument::recursivePinAdd( Pin *pin, Circuitoid *circuitoid, PinList *unassignedPins ) +{ + if (!pin) + return; + + if ( pin->eqId() != -1 ) + unassignedPins->remove(pin); + + if ( circuitoid->contains(pin) ) + return; + circuitoid->addPin(pin); + + if ( pin->eqId() == -1 ) + return; + + const PinList localConnectedPins = pin->localConnectedPins(); + const PinList::const_iterator end = localConnectedPins.end(); + for ( PinList::const_iterator it = localConnectedPins.begin(); it != end; ++it ) + recursivePinAdd( *it, circuitoid, unassignedPins ); + + const WireList inputList = pin->inputWireList(); + WireList::const_iterator conEnd = inputList.end(); + for ( WireList::const_iterator it = inputList.begin(); it != conEnd; ++it ) + circuitoid->addWire(*it); + + const WireList outputList = pin->outputWireList(); + conEnd = outputList.end(); + for ( WireList::const_iterator it = outputList.begin(); it != conEnd; ++it ) + circuitoid->addWire(*it); + + const PinList groundDependentPins = pin->groundDependentPins(); + const PinList::const_iterator gdEnd = groundDependentPins.end(); + for ( PinList::const_iterator it = groundDependentPins.begin(); it != gdEnd; ++it ) + recursivePinAdd( *it, circuitoid, unassignedPins ); + + const PinList circuitDependentPins = pin->circuitDependentPins(); + const PinList::const_iterator cdEnd = circuitDependentPins.end(); + for ( PinList::const_iterator it = circuitDependentPins.begin(); it != cdEnd; ++it ) + recursivePinAdd( *it, circuitoid, unassignedPins ); + + const ElementList elements = pin->elements(); + const ElementList::const_iterator eEnd = elements.end(); + for ( ElementList::const_iterator it = elements.begin(); it != eEnd; ++it ) + circuitoid->addElement(*it); +} + + +bool CircuitDocument::tryAsLogicCircuit( Circuitoid *circuitoid ) +{ + if (!circuitoid) + return false; + + if ( circuitoid->elementList.size() == 0 ) + { + // This doesn't quite belong here...but whatever. Initialize all + // pins to voltage zero as they won't get set to zero otherwise + const PinList::const_iterator pinListEnd = circuitoid->pinList.constEnd(); + for ( PinList::const_iterator it = circuitoid->pinList.constBegin(); it != pinListEnd; ++it ) + (*it)->setVoltage(0.0); + + // A logic circuit only requires there to be no non-logic components, + // and at most one LogicOut - so this qualifies + return true; + } + + LogicInList logicInList; + LogicOut *out = 0l; + + uint logicInCount = 0; + uint logicOutCount = 0; + ElementList::const_iterator end = circuitoid->elementList.end(); + for ( ElementList::const_iterator it = circuitoid->elementList.begin(); it != end; ++it ) + { + if ( (*it)->type() == Element::Element_LogicOut ) + { + logicOutCount++; + out = static_cast(*it); + } + else if ( (*it)->type() == Element::Element_LogicIn ) + { + logicInCount++; + logicInList += static_cast(*it); + } + else + return false; + } + if ( logicOutCount > 1 ) + return false; + + else if ( logicOutCount == 1 ) + Simulator::self()->createLogicChain( out, logicInList, circuitoid->pinList ); + + else + { + // We have ourselves stranded LogicIns...so lets set them all to low + + const PinList::const_iterator pinListEnd = circuitoid->pinList.constEnd(); + for ( PinList::const_iterator it = circuitoid->pinList.constBegin(); it != pinListEnd; ++it ) + (*it)->setVoltage(0.0); + + for ( ElementList::const_iterator it = circuitoid->elementList.begin(); it != end; ++it ) + { + LogicIn * logicIn = static_cast(*it); + logicIn->setNextLogic(0l); + logicIn->setElementSet(0l); + if ( logicIn->isHigh() ) + { + logicIn->setLastState(false); + logicIn->callCallback(); + } + } + } + + return true; +} + + +Circuit *CircuitDocument::createCircuit( Circuitoid *circuitoid ) +{ + if (!circuitoid) { + return 0l; + } + + Circuit *circuit = new Circuit(); + + const PinList::const_iterator nEnd = circuitoid->pinList.end(); + for ( PinList::const_iterator it = circuitoid->pinList.begin(); it != nEnd; ++it ) + circuit->addPin(*it); + + const ElementList::const_iterator eEnd = circuitoid->elementList.end(); + for ( ElementList::const_iterator it = circuitoid->elementList.begin(); it != eEnd; ++it ) + circuit->addElement(*it); + + return circuit; +} + + + +void CircuitDocument::createSubcircuit() +{ + ItemList itemList = m_selectList->items(); + const ItemList::iterator itemListEnd = itemList.end(); + for ( ItemList::iterator it = itemList.begin(); it != itemListEnd; ++it ) + { + if ( !dynamic_cast((Item*)*it) ) + *it = 0l; + } + itemList.remove((Item*)0l); + + if ( itemList.isEmpty() ) + { + KMessageBox::sorry( activeView(), i18n("No components were found in the selection.") ); + return; + } + + // Number of external connections + const int extConCount = countExtCon(itemList); + if ( extConCount == 0 ) + { + KMessageBox::sorry( activeView(), i18n("No External Connection components were found in the selection.") ); + return; + } + + bool ok; + const QString name = KInputDialog::getText( "Subcircuit", "Name", QString::null, &ok, activeView() ); + if (!ok) + return; + + SubcircuitData subcircuit; + subcircuit.addItems(itemList); + subcircuit.addNodes( getCommonNodes(itemList) ); + subcircuit.addConnectors( getCommonConnectors(itemList) ); + + Subcircuits::addSubcircuit( name, subcircuit.toXML() ); +} + + +int CircuitDocument::countExtCon( const ItemList &itemList ) const +{ + int count = 0; + const ItemList::const_iterator end = itemList.end(); + for ( ItemList::const_iterator it = itemList.begin(); it != end; ++it ) + { + Item * item = *it; + if ( item && item->type() == "ec/external_connection" ) + count++; + } + return count; +} + + +bool CircuitDocument::isValidItem( const QString &itemId ) +{ + return itemId.startsWith("ec/") || itemId.startsWith("dp/") || itemId.startsWith("sc/"); +} + + +bool CircuitDocument::isValidItem( Item *item ) +{ + return (dynamic_cast(item) || dynamic_cast(item)); +} + + +void CircuitDocument::displayEquations() +{ + kdDebug() << "######################################################" << endl; + const CircuitList::iterator end = m_circuitList.end(); + int i = 1; + for ( CircuitList::iterator it = m_circuitList.begin(); it != end; ++it ) + { + kdDebug() << "Equation set "<displayEquations(); + i++; + } + kdDebug() << "######################################################" << endl; +} + + +#include "circuitdocument.moc" diff --git a/src/circuitdocument.h b/src/circuitdocument.h new file mode 100644 index 0000000..581438b --- /dev/null +++ b/src/circuitdocument.h @@ -0,0 +1,157 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef CIRCUITDOCUMENT_H +#define CIRCUITDOCUMENT_H + +#include "icndocument.h" + +class Circuit; +class Component; +class Connector; +class ECNode; +class Element; +class ICNDocument; +class KTechlab; +class Pin; +class QTimer; +class Switch; +class Wire; + +class KActionMenu; + +typedef QValueList CircuitList; +typedef QValueList ComponentList; +typedef QValueList > ConnectorList; +typedef QValueList ECNodeList; +typedef QValueList ElementList; +typedef QValueList > PinList; +typedef QValueList SwitchList; +typedef QValueList > WireList; + +class Circuitoid +{ +public: + bool contains( Pin *node ) { return pinList.contains(node); } + bool contains( Wire *con ) { return wireList.contains(con); } + bool contains( Element *ele ) { return elementList.contains(ele); } + + void addPin( Pin *node ) { if (node && !contains(node)) pinList += node; } + void addWire( Wire *con ) { if (con && !contains(con)) wireList += con; } + void addElement( Element *ele ) { if (ele && !contains(ele)) elementList += ele; } + + WireList wireList; + PinList pinList; + ElementList elementList; +}; + +/** +CircuitDocument handles allocation of the components displayed in the ICNDocument +to various Circuits, where the simulation can be performed, and displays the +information from those simulations back on the ICNDocument +@short Circuit view +@author David Saxton +*/ +class CircuitDocument : public ICNDocument +{ + Q_OBJECT + public: + CircuitDocument( const QString &caption, KTechlab *ktechlab, const char *name = 0L ); + ~CircuitDocument(); + + virtual View *createView( ViewContainer *viewContainer, uint viewAreaId, const char *name = 0l ); + + void calculateConnectorCurrents(); + /** + * Count the number of ExternalConnection components in the CNItemList + */ + int countExtCon( const ItemList &cnItemList ) const; + + virtual void update(); + + public slots: + /** + * Creates a subcircuit from the currently selected components + */ + void createSubcircuit(); + void displayEquations(); + void setOrientation0(); + void setOrientation90(); + void setOrientation180(); + void setOrientation270(); + void rotateCounterClockwise(); + void rotateClockwise(); + void itemFlip(); + /** + * Enables / disables / selects various actions depending on what is + * selected or not. + * @param plugContextMenu If true, then will insert actions into contextmenu + */ + virtual void slotInitItemActions( Item *item = 0L ); + void requestAssignCircuits(); + void componentAdded( Item * item ); + void componentRemoved( Item * item ); + void connectorAdded( Connector * connector ); + virtual void slotUpdateConfiguration(); + + protected: + virtual void itemAdded( Item * item ); + virtual void fillContextMenu( const QPoint &pos ); + virtual bool isValidItem( Item *item ); + virtual bool isValidItem( const QString &itemId ); + + KActionMenu * m_pOrientationAction; + + private slots: + void assignCircuits(); + + private: + /** + * If the given circuitoid can be a LogicCircuit, then it will be added to + * m_logicCircuits, and return true. Else returns false. + */ + bool tryAsLogicCircuit( Circuitoid *circuitoid ); + /** + * Creates a circuit from the circuitoid + */ + Circuit *createCircuit( Circuitoid *circuitoid ); + /** + * @param node Current node (will be added, then tested for further + * connections). + * @param nodeList List of nodes in current partition. + * @param unassignedNodes The pool of all nodes in the CircuitDocument + * waiting for assignment. + * @param onlyGroundDependent if true, then the partition will not use + * circuit-dependent pins to include new pins while growing the + * partition. + */ + void getPartition( Pin * pin, PinList * pinList, PinList * unassignedPins, bool onlyGroundDependent = false ); + /** + * Takes the nodeList (generated by getPartition), splits it at ground nodes, + * and creates circuits from each split. + */ + void splitIntoCircuits( PinList * pinList ); + /** + * Construct a circuit from the given node, stopping at the groundnodes + */ + void recursivePinAdd( Pin * pin, Circuitoid *circuitoid, PinList * unassignedPins ); + void deleteCircuits(); + + QTimer *m_updateCircuitsTmr; + CircuitList m_circuitList; + ComponentList m_toSimulateList; + ComponentList m_componentList; // List is built up during call to assignCircuits + PinList m_pinList; + WireList m_wireList; + SwitchList m_switchList; +}; + +#endif + diff --git a/src/circuitview.cpp b/src/circuitview.cpp new file mode 100644 index 0000000..f451c26 --- /dev/null +++ b/src/circuitview.cpp @@ -0,0 +1,92 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "circuitdocument.h" +#include "circuitview.h" +#include "config.h" +#include "ktechlab.h" +#include "simulator.h" +#include "viewiface.h" + +#include +#include + +CircuitView::CircuitView( CircuitDocument * circuitDocument, ViewContainer *viewContainer, uint viewAreaId, const char *name ) + : ICNView( circuitDocument, viewContainer, viewAreaId, name ), + p_circuitDocument(circuitDocument) +{ + KActionCollection * ac = actionCollection(); + + new KAction( "Dump linear equations", Qt::CTRL|Qt::Key_D, circuitDocument, SLOT(displayEquations()), ac, "dump_les" ); + + //BEGIN Item Control Actions + KRadioAction * ra; + ra = new KRadioAction( i18n("0 Degrees"), "", 0, circuitDocument, SLOT(setOrientation0()), ac, "edit_orientation_0" ); + ra->setExclusiveGroup("orientation"); + ra->setChecked(true); + ra = new KRadioAction( i18n("90 Degrees"), "", 0, circuitDocument, SLOT(setOrientation90()), ac, "edit_orientation_90" ); + ra->setExclusiveGroup("orientation"); + ra = new KRadioAction( i18n("180 Degrees"), "", 0, circuitDocument, SLOT(setOrientation180()), ac, "edit_orientation_180" ); + ra->setExclusiveGroup("orientation"); + ra =new KRadioAction( i18n("270 Degrees"), "", 0, circuitDocument, SLOT(setOrientation270()), ac, "edit_orientation_270" ); + ra->setExclusiveGroup("orientation"); + + new KAction( i18n("Create Subcircuit"), "", 0, circuitDocument, SLOT(createSubcircuit()), ac, "circuit_create_subcircuit" ); + new KAction( i18n("Rotate Clockwise"), "rotate_cw", "]", circuitDocument, SLOT(rotateClockwise()), ac, "edit_rotate_cw" ); + new KAction( i18n("Rotate Counter-Clockwise"), "rotate_ccw", "[", circuitDocument, SLOT(rotateCounterClockwise()), ac, "edit_rotate_ccw" ); + new KAction( i18n("Flip"), "", 0, circuitDocument, SLOT(itemFlip()), ac, "edit_flip" ); + //END Item Control Actions + + setXMLFile( "ktechlabcircuitui.rc", true ); + + + QWhatsThis::add( this, i18n( + "Construct a circuit by dragging components from the Component selector from the left. Create the connections by dragging a wire from the component connectors.

    " + + "The simulation is running by default, but can be paused and resumed from the Tools menu.

    " + + "To delete a wire, select it with a select box, and hit delete.

    " + + "To edit the attributes of a component, select it (making sure that no components of another type are also selected), and edit in the toolbar. More advanced properties can be edited using the item editor on the right.

    " + + "Subcircuits can be created by connecting the components with an External Connection, selecting the desired components and clicking on \"Create Subcircuit\" in the right-click menu.") + ); + + m_pViewIface = new CircuitViewIface(this); + + m_statusBar->insertItem( "", ViewStatusBar::SimulationState ); + connect( Simulator::self(), SIGNAL(simulatingStateChanged(bool )), this, SLOT(slotUpdateRunningStatus(bool )) ); + slotUpdateRunningStatus( Simulator::self()->isSimulating() ); +} + + +CircuitView::~CircuitView() +{ + delete m_pViewIface; + m_pViewIface = 0l; +} + + +void CircuitView::slotUpdateRunningStatus( bool isRunning ) +{ + m_statusBar->changeItem( isRunning ? i18n("Simulation Running") : i18n("Simulation Paused"), ViewStatusBar::SimulationState ); +} + + +void CircuitView::dragEnterEvent( QDragEnterEvent * e ) +{ + ICNView::dragEnterEvent(e); + if ( e->isAccepted() ) + return; + + e->accept( e->provides("ktechlab/component") || e->provides("ktechlab/subcircuit") ); +} + +#include "circuitview.moc" diff --git a/src/circuitview.h b/src/circuitview.h new file mode 100644 index 0000000..8097685 --- /dev/null +++ b/src/circuitview.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef CIRCUITVIEW_H +#define CIRCUITVIEW_H + +#include + +class CircuitDocument; + +/** +@author David Saxton +*/ +class CircuitView : public ICNView +{ +Q_OBJECT +public: + CircuitView( CircuitDocument *circuitDocument, ViewContainer *viewContainer, uint viewAreaId, const char *name = 0l ); + ~CircuitView(); + +public slots: + virtual void slotUpdateRunningStatus( bool isRunning ); + +protected: + virtual void dragEnterEvent( QDragEnterEvent * e ); + CircuitDocument *p_circuitDocument; +}; + +#endif diff --git a/src/ciwidgetmgr.cpp b/src/ciwidgetmgr.cpp new file mode 100644 index 0000000..6e32423 --- /dev/null +++ b/src/ciwidgetmgr.cpp @@ -0,0 +1,308 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "cnitem.h" +#include "canvasitemparts.h" +#include "eventinfo.h" + +#include + +CIWidgetMgr::CIWidgetMgr( QCanvas *canvas, CNItem *item ) +{ + p_cnItem = item; + p_canvas = canvas; +} + + +CIWidgetMgr::~CIWidgetMgr() +{ + // QCanvas deletes our items for us. Actually, it pretty much insists on deleting them, + // despite me telling it not to, so if I delete them then it gets confused and crashes. + // Naughty QCanvas! + const WidgetMap::iterator widgetMapEnd = m_widgetMap.end(); + for ( WidgetMap::iterator it = m_widgetMap.begin(); it != widgetMapEnd; ++it ) + { + delete it.data(); + } + m_widgetMap.clear(); +} + + +void CIWidgetMgr::setWidgetsPos( const QPoint &pos ) +{ + m_pos = pos; +} + + +void CIWidgetMgr::setDrawWidgets( bool draw ) +{ + const WidgetMap::iterator widgetMapEnd = m_widgetMap.end(); + for ( WidgetMap::iterator it = m_widgetMap.begin(); it != widgetMapEnd; ++it ) + { + draw ? it.data()->show() : it.data()->hide(); + } +} + + +Widget *CIWidgetMgr::widgetWithID( const QString &id ) const +{ + WidgetMap::const_iterator it = m_widgetMap.find(id); + if ( it == m_widgetMap.end() ) + return 0l; + else return it.data(); +} + + +Button *CIWidgetMgr::button( const QString &id ) const +{ + return dynamic_cast(widgetWithID(id)); +} + +Slider *CIWidgetMgr::slider( const QString &id ) const +{ + return dynamic_cast(widgetWithID(id)); +} + + + +void CIWidgetMgr::setButtonState( const QString &id, int state ) +{ + Button *b = button(id); + if (!b) + return; + + // Actually, we don't want to check to see if we are already down; this way, + // we get toggle events when loading from file +// bool oldState = b->isDown(); +// if ( oldState == state ) +// return; + + b->setState(state); +} + + +void CIWidgetMgr::drawWidgets( QPainter &p ) +{ + const WidgetMap::iterator widgetMapEnd = m_widgetMap.end(); + for ( WidgetMap::iterator it = m_widgetMap.begin(); it != widgetMapEnd; ++it ) + { + it.data()->drawShape(p); + } +} + + +void CIWidgetMgr::removeWidget( const QString & id ) +{ + if ( !m_widgetMap.contains(id) ) + return; + + delete m_widgetMap[id]; + m_widgetMap.remove(id); +} + + +Button* CIWidgetMgr::addButton( const QString &id, const QRect & pos, const QString &display, bool toggle ) +{ + WidgetMap::iterator it; + + Button *button = new Button( id, p_cnItem, toggle, pos, p_canvas ); + (dynamic_cast(button->widget()))->setText(display); + + it = m_widgetMap.find(id); + if ( it == m_widgetMap.end() ) + { + m_widgetMap[id] = button; + } + else + { + kdWarning() << "CIWidgetMgr::addButton: Attempting to re-add button with same id as previous"<updateAttachedPositioning(); + return button; +} + + +Button* CIWidgetMgr::addButton( const QString &id, const QRect & pos, QPixmap pixmap, bool toggle ) +{ + WidgetMap::iterator it; + + Button *button = new Button( id, p_cnItem, toggle, pos, p_canvas ); + button->setPixmap(pixmap); + + it = m_widgetMap.find(id); + if ( it == m_widgetMap.end() ) + { + m_widgetMap[id] = button; + } + else + { + kdWarning() << "CIWidgetMgr::addButton: Attempting to re-add button with same id as previous"<updateAttachedPositioning(); + return button; +} + + +Slider* CIWidgetMgr::addSlider( const QString &id, int minValue, int maxValue, int pageStep, int value, Qt::Orientation orientation, const QRect & pos ) +{ + Slider *slider = new Slider( id, p_cnItem, pos, p_canvas ); + QSlider *qslider = dynamic_cast(slider->widget()); + + qslider->setMinValue(minValue); + qslider->setMaxValue(maxValue); + qslider->setPageStep(pageStep); + qslider->setValue(value); + slider->setOrientation(orientation); + + WidgetMap::iterator it = m_widgetMap.find(id); + if ( it == m_widgetMap.end() ) + { + m_widgetMap[id] = slider; + } + else + { + kdWarning() << "CIWidgetMgr::addSlider: Attempting to re-add slider with same id as previous"<updateAttachedPositioning(); + return slider; +} + + +bool CIWidgetMgr::mousePressEvent( const EventInfo &info ) +{ + QMouseEvent *e = info.mousePressEvent( 0, 0 ); + + const WidgetMap::iterator widgetMapEnd = m_widgetMap.end(); + for ( WidgetMap::iterator it = m_widgetMap.begin(); it != widgetMapEnd; ++it ) + { + if ( it.data()->rect().contains(info.pos) ) + { + it.data()->mousePressEvent(e); + if (e->isAccepted()) + { + delete e; + return true; + } + } + } + delete e; + return false; +} + + +bool CIWidgetMgr::mouseReleaseEvent( const EventInfo &info ) +{ + QMouseEvent *e = info.mouseReleaseEvent( 0, 0 ); + + const WidgetMap::iterator widgetMapEnd = m_widgetMap.end(); + for ( WidgetMap::iterator it = m_widgetMap.begin(); it != widgetMapEnd; ++it ) + { + it.data()->mouseReleaseEvent(e); + } + + bool accepted = e->isAccepted(); + delete e; + return accepted; +} + + +bool CIWidgetMgr::mouseDoubleClickEvent( const EventInfo &info ) +{ + QMouseEvent *e = info.mouseDoubleClickEvent( 0, 0 ); + + const WidgetMap::iterator widgetMapEnd = m_widgetMap.end(); + for ( WidgetMap::iterator it = m_widgetMap.begin(); it != widgetMapEnd; ++it ) + { + if ( it.data()->rect().contains(info.pos) ) + { + it.data()->mouseDoubleClickEvent(e); + if (e->isAccepted()) + { + delete e; + return true; + } + } + } + delete e; + return false; +} + + +bool CIWidgetMgr::mouseMoveEvent( const EventInfo &info ) +{ + QMouseEvent *e = info.mouseMoveEvent( 0, 0 ); + + const WidgetMap::iterator widgetMapEnd = m_widgetMap.end(); + for ( WidgetMap::iterator it = m_widgetMap.begin(); it != widgetMapEnd; ++it ) + { + it.data()->mouseMoveEvent(e); + if (e->isAccepted()) + { + delete e; + return true; + } + } + delete e; + return false; +} + + +bool CIWidgetMgr::wheelEvent( const EventInfo &info ) +{ + QWheelEvent *e = info.wheelEvent( 0, 0 ); + + const WidgetMap::iterator widgetMapEnd = m_widgetMap.end(); + for ( WidgetMap::iterator it = m_widgetMap.begin(); it != widgetMapEnd; ++it ) + { + if ( it.data()->rect().contains(info.pos) ) + { + it.data()->wheelEvent(e); + if (e->isAccepted()) + { + delete e; + return true; + } + } + } + + delete e; + return false; +} + + +void CIWidgetMgr::enterEvent() +{ + const WidgetMap::iterator widgetMapEnd = m_widgetMap.end(); + for ( WidgetMap::iterator it = m_widgetMap.begin(); it != widgetMapEnd; ++it ) + { + it.data()->enterEvent(); + } +} + + +void CIWidgetMgr::leaveEvent() +{ + const WidgetMap::iterator widgetMapEnd = m_widgetMap.end(); + for ( WidgetMap::iterator it = m_widgetMap.begin(); it != widgetMapEnd; ++it ) + { + it.data()->leaveEvent(); + } +} + + diff --git a/src/ciwidgetmgr.h b/src/ciwidgetmgr.h new file mode 100644 index 0000000..b79fc06 --- /dev/null +++ b/src/ciwidgetmgr.h @@ -0,0 +1,103 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef CIWIDGETMGR_H +#define CIWIDGETMGR_H + +#include +#include + +class Button; +class CNItem; +class Slider; +class QCanvas; +class Widget; + +typedef QMap WidgetMap; + +/** +This class handles the widgets (those things associated with CNItems that use QWidgets. +This class is pretty much to maintain a tidy interface: the functions could just as well be +all shoved in CNItem, but that gets messy. +@author David Saxton +*/ +class CIWidgetMgr +{ +public: + CIWidgetMgr( QCanvas *canvas, CNItem *item ); + virtual ~CIWidgetMgr(); + + /** + * Set the top-left position from which mouse events are interpreted and the + * widgets are drawn from. + */ + void setWidgetsPos( const QPoint &pos ); + /** + * Returns a pointer to the widget with the given id, or NULL if no such + * widgets are found. + */ + Widget *widgetWithID( const QString &id ) const; + Button *button( const QString &id ) const; + Slider *slider( const QString &id ) const; + void setButtonState( const QString &id, int state ); + /** + * Adds a slider with the given id and values to the position + */ + Slider* addSlider( const QString &id, int minValue, int maxValue, int pageStep, int value, Qt::Orientation orientation, const QRect & pos ); + /** + * Essentially the same as addDisplayText, but displays a button with + * text on it. The virtual functions buttonPressed( const QString &id ) and + * buttonReleased( const QString &id ) are called as appropriate with button id + */ + Button* addButton( const QString &id, const QRect & pos, const QString &display, bool toggle = false ); + /** + * Adds a button with a QPixmap pixmap on it instead of text + * @see void addButton( const QString &id, QRect pos, const QString &display ) + */ + Button* addButton( const QString &id, const QRect & pos, QPixmap pixmap, bool toggle = false ); + /** + * Removes the widget with the given id. + */ + void removeWidget( const QString & id ); + /** + * Sets whether or not to draw the widgets (drawing widgets mucks up SVG + * export). This function just calls either hide() or show() in each widget. + */ + void setDrawWidgets( bool draw ); + + bool mousePressEvent( const EventInfo &info ); + bool mouseReleaseEvent( const EventInfo &info ); + bool mouseDoubleClickEvent ( const EventInfo &info ); + bool mouseMoveEvent( const EventInfo &info ); + bool wheelEvent( const EventInfo &info ); + void enterEvent(); + void leaveEvent(); + + virtual void buttonStateChanged( const QString &/*id*/, bool /*on*/ ) {}; + virtual void sliderValueChanged( const QString &/*id*/, int /*value*/ ) {}; + + int mgrX() const { return m_pos.x(); } + int mgrY() const { return m_pos.y(); } + /** + * Draw the widgets using the given painter. This function isn't actually + * used to draw the widgets on the canvas, as they are QCanvasItems + * themselves, but allows other classes (e.g. ItemLibrary) to draw them + * using a special painter. + */ + void drawWidgets( QPainter &p ); + +protected: + WidgetMap m_widgetMap; + QPoint m_pos; + QCanvas *p_canvas; + CNItem *p_cnItem; +}; + +#endif diff --git a/src/cnitem.cpp b/src/cnitem.cpp new file mode 100644 index 0000000..9d949f0 --- /dev/null +++ b/src/cnitem.cpp @@ -0,0 +1,647 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasitemparts.h" +#include "icndocument.h" +#include "cells.h" +#include "component.h" +#include "ecnode.h" +#include "fpnode.h" +#include "itemdocumentdata.h" +#include + +#include +#include + +#include + +// Degrees per radian +const double DPR = 57.29577951308232087665461840231273527024; + + +CNItem::CNItem( ICNDocument *icnDocument, bool newItem, const QString &id ) + : Item( icnDocument, newItem, id ), + CIWidgetMgr( icnDocument->canvas(), this ), + p_icnDocument(icnDocument), + b_pointsAdded(false) +{ + setZ( ICNDocument::Z::Item ); + setSelected(false); + + m_brushCol = QColor( 0xf7, 0xf7, 0xff ); + m_selectedCol = QColor( 101, 134, 192 ); + + setBrush(m_brushCol); + setPen( Qt::black ); +} + +CNItem::~CNItem() +{ + const TextMap::iterator textMapEnd = m_textMap.end(); + for ( TextMap::iterator it = m_textMap.begin(); it != textMapEnd; ++it ) + { + if (it.data()) + it.data()->setCanvas(0l); + delete (Text*)it.data(); + } + m_textMap.clear(); + + updateConnectorPoints(false); +} + + +int CNItem::rtti() const +{ + return ItemDocument::RTTI::CNItem; +} + + +bool CNItem::preResize( QRect sizeRect ) +{ + if ( (std::abs((double)sizeRect.width()) < minimumSize().width()) || + (std::abs((double)sizeRect.height()) < minimumSize().height()) ) + return false; + + updateConnectorPoints(false); + return true; +} + + +void CNItem::postResize() +{ + updateAttachedPositioning(); +} + + +void CNItem::setVisible( bool yes ) +{ + if (b_deleted) + { + Item::setVisible(false); + return; + } + + Item::setVisible(yes); + + const TextMap::iterator textMapEnd = m_textMap.end(); + for ( TextMap::iterator it = m_textMap.begin(); it != textMapEnd; ++it ) + { + it.data()->setVisible(yes); + } + + const NodeMap::iterator nodeMapEnd = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != nodeMapEnd; ++it ) + { + it.data().node->setVisible(yes); + } + + CNItem::setDrawWidgets(yes); + + if (!yes) + updateConnectorPoints(false); +} + + +void CNItem::setInitialPos( const QPoint &pos ) +{ + m_offset = pos - QPoint( (int)x(), (int)y() ); +} + + +void CNItem::reparented( Item *oldParent, Item *newParent ) +{ + Item::reparented( oldParent, newParent ); + updateNodeLevels(); +} + + +void CNItem::updateNodeLevels() +{ + int l = level(); + + // Tell our nodes about our level + const NodeMap::iterator nodeMapEnd = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != nodeMapEnd; ++it ) + { + it.data().node->setLevel(l); + } + + const ItemList::iterator end = m_children.end(); + for ( ItemList::iterator it = m_children.begin(); it != end; ++it ) + { + if ( CNItem *cnItem = dynamic_cast((Item*)*it) ) + cnItem->updateNodeLevels(); + } +} + + +ConnectorList CNItem::connectorList() +{ + ConnectorList list; + + const NodeMap::iterator nodeMapEnd = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != nodeMapEnd; ++it ) + { + Node *node = p_icnDocument->nodeWithID(it.data().id); + if (node) + { + ConnectorList nodeList = node->inputConnectorList(); + ConnectorList::iterator end = nodeList.end(); + for ( ConnectorList::iterator it = nodeList.begin(); it != end; ++it ) + { + if ( *it && !list.contains(*it) ) + { + list.append(*it); + } + } + nodeList = node->outputConnectorList(); + end = nodeList.end(); + for ( ConnectorList::iterator it = nodeList.begin(); it != end; ++it ) + { + if ( *it && !list.contains(*it) ) + { + list.append(*it); + } + } + } + } + + return list; +} + + +void CNItem::removeItem() +{ + if (b_deleted) + return; + + const TextMap::iterator textMapEnd = m_textMap.end(); + for ( TextMap::iterator it = m_textMap.begin(); it != textMapEnd; ++it ) + it.data()->setCanvas(0l); + + Item::removeItem(); + updateConnectorPoints(false); +} + + +void CNItem::restoreFromItemData( const ItemData &itemData ) +{ + Item::restoreFromItemData(itemData); + + updateConnectorPoints(false); + + { + const BoolMap::const_iterator end = itemData.buttonMap.end(); + for ( BoolMap::const_iterator it = itemData.buttonMap.begin(); it != end; ++it ) + { + Button *b = button(it.key()); + if (b) + b->setState(it.data()); + } + } + { + const IntMap::const_iterator end = itemData.sliderMap.end(); + for ( IntMap::const_iterator it = itemData.sliderMap.begin(); it != end; ++it ) + { + Slider *s = slider(it.key()); + if (s) + s->setValue(it.data()); + } + } +} + + +ItemData CNItem::itemData() const +{ + ItemData itemData = Item::itemData(); + + const WidgetMap::const_iterator end = m_widgetMap.end(); + for ( WidgetMap::const_iterator it = m_widgetMap.begin(); it != end; ++it ) + { + if ( Slider *slider = dynamic_cast(*it) ) + itemData.sliderMap[slider->id()] = slider->value(); + + else if ( Button *button = dynamic_cast(*it) ) + itemData.buttonMap[button->id()] = button->state(); + + } + + return itemData; +} + + +Node* CNItem::createNode( double _x, double _y, int orientation, const QString &name, uint type ) +{ + orientation %= 360; + if ( orientation < 0 ) + orientation += 360; + + Node::node_dir dir; + + if ( orientation == 0 ) dir = Node::dir_right; + else if ( orientation == 90 ) dir = Node::dir_down; + else if ( orientation == 180 ) dir = Node::dir_left; + else if ( orientation == 270 ) dir = Node::dir_up; + else + { + kdError() << k_funcinfo << "Unknown orientation: " << orientation << endl; + return 0l; + } + + Node *node; + if ( (type == Node::ec_pin) || (type == Node::ec_junction) ) + { + node = new ECNode( p_icnDocument, Node::node_type(type), dir, QPoint( 0, 0 ) ); + } + else + { + node = new FPNode( p_icnDocument, Node::node_type(type), dir, QPoint( 0, 0 ) ); + } + node->setLevel( level() ); + + node->setParentItem(this); + node->setChildId(name); + + NodeInfo info; + info.id = node->id(); + info.node = node; + info.x = _x; + info.y = _y; + info.orientation = orientation; + + m_nodeMap[name] = info; + + updateAttachedPositioning(); + + return node; +} + + +bool CNItem::removeNode( const QString &name ) +{ + NodeMap::iterator it = m_nodeMap.find(name); + if ( it == m_nodeMap.end() ) { + return false; + } + it.data().node->removeNode(); + p_icnDocument->flushDeleteList(); + m_nodeMap.erase(it); + return true; +} + + +Node *CNItem::getClosestNode( const QPoint &pos ) +{ + // Work through the nodes, finding the one closest to the (x, y) position + Node *shortestNode = 0L; + double shortestDistance = 1e10; // Nice large distance :-) + + const NodeMap::iterator end = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != end; ++it ) + { + Node *node = p_icnDocument->nodeWithID(it.data().id); + if (node) + { + // Calculate the distance + // Yeah, it's actually the distance squared; but it's all relative, so doesn't matter + double distance = std::pow(node->x()-pos.x(),2) + std::pow(node->y()-pos.y(),2); + + if ( distance < shortestDistance ) + { + shortestDistance = distance; + shortestNode = node; + } + } + } + + return shortestNode; +} + + +void CNItem::updateAttachedPositioning() +{ + if (b_deleted) + return; + + // Actually, we don't do anything anymore... +} + + +void CNItem::updateZ( int baseZ ) +{ + Item::updateZ(baseZ); + + double _z = z(); + + const NodeMap::iterator nodeMapEnd = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != nodeMapEnd; ++it ) + it.data().node->setZ( _z + 0.5 ); + + const WidgetMap::iterator widgetMapEnd = m_widgetMap.end(); + for ( WidgetMap::iterator it = m_widgetMap.begin(); it != widgetMapEnd; ++it ) + it.data()->setZ( _z + 0.5 ); + + const TextMap::iterator textMapEnd = m_textMap.end(); + for ( TextMap::iterator it = m_textMap.begin(); it != textMapEnd; ++it ) + it.data()->setZ( _z + 0.5 ); +} + + +void CNItem::snap( int newx, int newy ) +{ + // Ugly looking thing + // Basically means: Move item to the new position of newx-offsetx and then snap it to the 8-square-side grid + // This is in one move item call so that any attached connectors are only called once to update their routes. + moveBy( 4+newx-m_offset.x()-x()-(int)(newx-m_offset.x())%8, 4+newy-m_offset.y()-y()-(int)(newy-m_offset.y())%8 ); +} + +void CNItem::moveBy( double dx, double dy ) +{ + if ( dx == 0 && dy == 0 ) return; + updateConnectorPoints(false); + Item::moveBy( dx, dy ); + + setWidgetsPos( QPoint( int(x()), int(y()) ) ); +} + + +bool CNItem::mousePressEvent( const EventInfo &info ) +{ + bool accepted = Item::mousePressEvent(info); + if (!accepted) + accepted = CIWidgetMgr::mousePressEvent(info); + if (accepted) + setChanged(); + return accepted; +} + + +bool CNItem::mouseReleaseEvent( const EventInfo &info ) +{ + bool accepted = Item::mouseReleaseEvent(info); + if (!accepted) + accepted = CIWidgetMgr::mouseReleaseEvent(info); + if (accepted) + setChanged(); + return accepted; +} + + +bool CNItem::mouseDoubleClickEvent( const EventInfo &info ) +{ + bool accepted = Item::mouseDoubleClickEvent(info); + if (!accepted) + accepted = CIWidgetMgr::mouseDoubleClickEvent(info); + if (accepted) + setChanged(); + return accepted; +} + + +bool CNItem::mouseMoveEvent( const EventInfo &info ) +{ + bool accepted = Item::mouseMoveEvent(info); + if (!accepted) + accepted = CIWidgetMgr::mouseMoveEvent(info); + if (accepted) + setChanged(); + return accepted; +} + + +bool CNItem::wheelEvent( const EventInfo &info ) +{ + bool accepted = Item::wheelEvent(info); + if (!accepted) + accepted = CIWidgetMgr::wheelEvent(info); + if (accepted) + setChanged(); + return accepted; +} + + +void CNItem::enterEvent() +{ + Item::enterEvent(); + CIWidgetMgr::enterEvent(); + setChanged(); +} + + +void CNItem::leaveEvent() +{ + Item::leaveEvent(); + CIWidgetMgr::leaveEvent(); + setChanged(); +} + + +void CNItem::drawShape( QPainter &p ) +{ + if (!isVisible()) + return; + +// initPainter(p); + if ( isSelected() ) + p.setPen(m_selectedCol); + + p.drawPolygon(areaPoints()); + p.drawPolyline(areaPoints()); +// deinitPainter(p); +} + + +void CNItem::initPainter( QPainter &p ) +{ + if ( isSelected() ) + p.setPen(m_selectedCol); +} + + +void CNItem::updateConnectorPoints( bool add ) +{ + if ( b_deleted || !isVisible() ) + add = false; + + if ( b_pointsAdded == add ) + return; + + b_pointsAdded = add; + + Cells *cells = p_icnDocument->cells(); + if (!cells) return; + + const int cx = cells->width(); + const int cy = cells->height(); + + if ( cx < 1 || cy < 1 ) { + return; + } + + // Get translation matrix + // Hackish... + QWMatrix m; + if ( Component *c = dynamic_cast(this) ) + m = c->transMatrix( c->angleDegrees(), c->flipped(), int(x()), int(y()), false ); + + // Convention used here: _UM = unmapped by both matrix and cell reference, _M = mapped + + const QPoint start_UM = QPoint( int(x()+offsetX())-cellSize, int(y()+offsetY())-cellSize ); + const QPoint end_UM = start_UM + QPoint( width()+2*cellSize, height()+2*cellSize ); + + const QPoint start_M = m.map(start_UM)/cellSize; + const QPoint end_M = m.map(end_UM)/cellSize; + + + int sx_M = start_M.x(); + int ex_M = end_M.x(); + + int sy_M = start_M.y(); + int ey_M = end_M.y(); + + + // Normalise start and end points + if ( sx_M > ex_M ) + { + const int temp = sx_M; + sx_M = ex_M; + ex_M = temp; + } + if ( sy_M > ey_M ) + { + const int temp = sy_M; + sy_M = ey_M; + ey_M = temp; + } + + ex_M++; + ey_M++; + + const int mult = add ? 1 : -1; + + for ( int x = sx_M; x < ex_M; x++ ) + { + for ( int y = sy_M; y < ey_M; y++ ) + { + if ( p_icnDocument->isValidCellReference( x, y ) ) + { + if ( x != sx_M && y != sy_M && x != (ex_M-1) && y != (ey_M-1) ) + { + (*cells)[x][y].CIpenalty += mult*ICNDocument::hs_item; + } + else + { +// (*cells)[x][y].CIpenalty += mult*ICNDocument::hs_item/2; + (*cells)[x][y].CIpenalty += mult*ICNDocument::hs_connector*5; + } + } + } + } + +#if 0 + // And subtract the positions of the node on the border + NodeMap::iterator end = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != end; ++it ) + { + const int x = (int)((it->second.node->x()-4)/cellSize); + const int y = (int)((it->second.node->y()-4)/cellSize); + if ( p_icnDocument->isValidCellReference(x,y) ) { + (*cells)[x][y].CIpenalty -= mult*ICNDocument::hs_connector*5; + } + } +#endif + + const TextMap::iterator textMapEnd = m_textMap.end(); + for ( TextMap::iterator it = m_textMap.begin(); it != textMapEnd; ++it ) + { + it.data()->updateConnectorPoints(add); + } + const WidgetMap::iterator widgetMapEnd = m_widgetMap.end(); + for ( WidgetMap::iterator it = m_widgetMap.begin(); it != widgetMapEnd; ++it ) + { + it.data()->updateConnectorPoints(add); + } +} + + +Text* CNItem::addDisplayText( const QString &id, const QRect & pos, const QString &display, bool internal, int flags ) +{ + Text *text = 0l; + TextMap::iterator it = m_textMap.find(id); + if ( it != m_textMap.end() ) + { +// kdWarning() << "CNItem::addDisplayText: removing old text"<setZ( z()+(internal?0.1:-0.1) ); + + m_textMap[id] = text; + + // Calculate the correct size + setDisplayText( id, display ); + text->show(); + return text; +} + + +void CNItem::setDisplayText( const QString &id, const QString &display ) +{ + TextMap::iterator it = m_textMap.find(id); + if ( it == m_textMap.end() ) + { + kdError() << "CNItem::setDisplayText: Could not find text with id \""<setText(display); + updateAttachedPositioning(); +} + + +void CNItem::removeDisplayText( const QString &id ) +{ + TextMap::iterator it = m_textMap.find(id); + if ( it == m_textMap.end() ) + { +// kdError() << "CNItem::removeDisplayText: Could not find text with id \""<updateConnectorPoints(false); + delete it.data(); + m_textMap.remove(it); +} + + +QString CNItem::nodeId( const QString &internalNodeId ) +{ + NodeMap::iterator it = m_nodeMap.find(internalNodeId); + if ( it == m_nodeMap.end() ) return ""; + else return it.data().id; +} + + +Node *CNItem::childNode( const QString &childId ) +{ + return p_icnDocument->nodeWithID( nodeId(childId) ); +} + + +NodeInfo::NodeInfo() +{ + node = 0l; + x = 0.; + y = 0.; + orientation = 0; +} + + +#include "cnitem.moc" diff --git a/src/cnitem.h b/src/cnitem.h new file mode 100644 index 0000000..7a5f55a --- /dev/null +++ b/src/cnitem.h @@ -0,0 +1,191 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef CNITEM_H +#define CNITEM_H + +#include "item.h" +#include "ciwidgetmgr.h" + + +class Button; +class CNItem; +class ICNDocument; +class Connector; +class DoubleSpinBox; +class LibraryItem; +class Node; +class QSlider; +class QString; +class QToolButton; +class QWMatrix; +class Slider; +class Text; + + +class NodeInfo +{ +public: + NodeInfo(); + + QString id; // External id (ICNDocument scope) + Node *node; //Pointer to the node + double x; // X position relative to item + double y; // Y position relative to item + int orientation; // Orientation relative to item +}; + +typedef QMap StringMap; +typedef QMap NodeMap; // Internal id, node info +typedef QValueList > ConnectorList; +typedef QMap > TextMap; + +/** +Essentially, all items that live on ICNDocument should inherit from this class. +This class provides much functionality (moving items, creation of associated nodes, +saving and editing of associated data, cutting / copying, etc) +@short Base class for all components/flowparts/etc +@author Daniel Clarke +@author David Saxton +*/ +class CNItem : public Item, public CIWidgetMgr +{ +Q_OBJECT +public: + CNItem( ICNDocument *_icnView, bool newItem, const QString &id ); + virtual ~CNItem(); + + /** + * Returns the run-time identifier for the CNItem - ItemDocument::RTTI::CNItem + */ + int rtti() const; + /** + * Creates a node which is attached to the item. The node will be moved + * about with the item, and destroyed along with the item. The position + * coordinates of the node are relative to the upper left corner of the item. + * @param type See Node::node_type + */ + Node* createNode( double _x, double _y, int orientation, const QString &name, uint type ); + /** + * Removes a child node. You should use this function if you want to remove + * any nodes during the lifetime of the CNItem. + */ + bool removeNode( const QString &name ); + /** + * Sets the mouse click point when moving this item + */ + void setInitialPos( const QPoint &pos ); + /** + * Snaps the component to the grid. + */ + void snap( int newx = -1, int newy = -1 ); + /** + * Returns the closest node that is associated with the CNItem + */ + Node *getClosestNode( const QPoint &pos ); + /** + * Returns a list of connectors associated with the CNItem + */ + ConnectorList connectorList(); + virtual bool preResize( QRect sizeRect ); + virtual bool mousePressEvent( const EventInfo &eventInfo ); + virtual bool mouseReleaseEvent( const EventInfo &eventInfo ); + virtual bool mouseDoubleClickEvent ( const EventInfo &eventInfo ); + virtual bool mouseMoveEvent( const EventInfo &eventInfo ); + virtual bool wheelEvent( const EventInfo &eventInfo ); + virtual void enterEvent(); + virtual void leaveEvent(); + /** + * ICNDocument needs to know what 'cells' a CNItem is present in, + * so that connection mapping can be done to avoid CNItems. + * This function will add the hit penalty to the cells pointed to + * by ICNDocument::cells() + */ + virtual void updateConnectorPoints( bool add ); + /** + * Converts the id used to internally identify a node to the global + * ICNDocument node id. eg "vss" might return "node__13". + */ + QString nodeId( const QString &internalNodeId ); + /** + * Returns a pointer to the node with the given internal (child) id + */ + Node *childNode( const QString &childId ); + /** + * Returns the node map used: + * QMap NodeMap + * It's probably best to cache this data + */ + NodeMap nodeMap() const { return m_nodeMap; } + /** + * Returns the TextMap used for canvas text + */ + TextMap textMap() const { return m_textMap; } + virtual void setVisible( bool yes ); + virtual void updateZ( int baseZ ); + + virtual ItemData itemData() const; + virtual void restoreFromItemData( const ItemData &itemData ); + virtual void updateNodeLevels(); + +public slots: + /** + * Moves item - use this instead of moveBy() so that associated Nodes also get moved + */ + virtual void moveBy( double dx, double dy ); + /** + * Remove the item and associated nodes. It appends the item to the + * ICNDocument's delete list, so you must call ICNDocument::flushDeleteList() + * after calling this (and possible ICNDocument::clearDeleteList() befor + * calling it) The virtual function void handleRemove() is called to allow + * any child classes to clear up any neccessary data (which doesn't do + * anything by default), before CNItem does the rest + */ + virtual void removeItem(); + /** + * This item has been resized, so update the nodes relative positions + */ + virtual void updateAttachedPositioning(); + +protected: + virtual void reparented( Item *oldParent, Item *newParent ); + virtual void drawShape( QPainter &p ); + virtual void postResize(); + /** + * CNItem handles drawing of text associated with the CNItem. + * @param id is a unique identifier that can be used to change the text displayed. + * @param pos is the position that the text occupies relative to the top left corner of the CNItem. + * @param display is the actual text to be displayed. + * @param internal is used to determine the z-level of the text - whether it should be below or above the item + * @param flags Text alignment flags - Qt::AlignmentFlags and Qt::TextFlags OR'd together. + */ + Text* addDisplayText( const QString &id, const QRect & pos, const QString &display, bool internal = true, int flags = Qt::AlignHCenter | Qt::AlignVCenter ); + void setDisplayText( const QString &id, const QString &display ); + /** + * Remove the display text with the given id + */ + void removeDisplayText( const QString &id ); + /** + * Sets the right colour if selected, transforms the matrix of the painter + */ + virtual void initPainter( QPainter &p ); + + QPoint m_offset; + QGuardedPtr p_icnDocument; + TextMap m_textMap; + NodeMap m_nodeMap; + QColor m_selectedCol; + QColor m_brushCol; + bool b_pointsAdded; +}; +typedef QValueList CNItemList; + +#endif + diff --git a/src/cnitemgroup.cpp b/src/cnitemgroup.cpp new file mode 100644 index 0000000..21a9878 --- /dev/null +++ b/src/cnitemgroup.cpp @@ -0,0 +1,598 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "cnitemgroup.h" +#include "component.h" +#include "connector.h" +#include "flowpart.h" +#include "icndocument.h" +#include "node.h" +#include "nodegroup.h" + +CNItemGroup::CNItemGroup( ICNDocument *icnDocument, const char *name) + : ItemGroup( icnDocument, name ) +{ + p_icnDocument = icnDocument; + m_connectorCount = 0; + m_nodeCount = 0; + m_currentLevel = -1; +} + + +CNItemGroup::~CNItemGroup() +{ +} + + +bool CNItemGroup::addItem( Item *item ) +{ + // Note, we must prepend the item to the list so that + // activeCNItem() can return the item at the start + // of the list as the most recently added item if some + // the previous activeCNItem is removed + + if ( !item || !item->canvas() || m_itemList.contains(item) || !item->isMovable() ) + return false; + + if ( m_currentLevel != -1 && item->level() > m_currentLevel ) + return false; + + if ( item && m_currentLevel > item->level() ) + removeAllItems(); + + registerItem(item); + m_currentLevel = item->level(); + setActiveItem(item); + item->setSelected(true); + updateInfo(); + emit itemAdded(item); + return true; +} + + +bool CNItemGroup::addNode( Node *node ) +{ + if ( !node || m_nodeList.contains(node) || node->isChildNode() ) + return false; + m_nodeList.prepend(node); + node->setSelected(true); + updateInfo(); + emit nodeAdded(node); + return true; +} + + +bool CNItemGroup::addConnector( Connector *con ) +{ + if ( !con || m_connectorList.contains(con) ) + return false; + m_connectorList.prepend(con); + con->setSelected(true); + updateInfo(); + emit connectorAdded(con); + return true; +} + + +bool CNItemGroup::addQCanvasItem( QCanvasItem *qcanvasItem ) +{ + if (!qcanvasItem) return false; + + Item *item = dynamic_cast(qcanvasItem); + if (item) + return addItem(item); + + Node *node = dynamic_cast(qcanvasItem); + if (node) + return addNode(node); + + Connector *connector = dynamic_cast(qcanvasItem); + if (!connector) + { + ConnectorLine *connectorLine = dynamic_cast(qcanvasItem); + if (connectorLine) + connector = connectorLine->parent(); + } + if (connector) + return addConnector(connector); + + return false; +} + +void CNItemGroup::setItems( QCanvasItemList list ) +{ + ItemList itemRemoveList = m_itemList; + ConnectorList connectorRemoveList = m_connectorList; + NodeList nodeRemoveList = m_nodeList; + + const QCanvasItemList::const_iterator end = list.end(); + for ( QCanvasItemList::const_iterator it = list.begin(); it != end; ++it ) + { + switch ( *it ? (*it)->rtti() : 0 ) + { + case ItemDocument::RTTI::CNItem: + case ItemDocument::RTTI::DrawPart: + { + itemRemoveList.remove( dynamic_cast(*it) ); + break; + } + case ItemDocument::RTTI::Node: + { + nodeRemoveList.remove( dynamic_cast(*it) ); + break; + } + case ItemDocument::RTTI::Connector: + { + connectorRemoveList.remove( dynamic_cast(*it) ); + break; + } + case ItemDocument::RTTI::ConnectorLine: + { + connectorRemoveList.remove( (dynamic_cast(*it))->parent() ); + break; + } + default: + break; + } + } + + { + const ItemList::const_iterator end = itemRemoveList.end(); + for ( ItemList::const_iterator it = itemRemoveList.begin(); it != end; ++it ) + { + removeItem(*it); + (*it)->setSelected(false); + } + } + + { + const NodeList::const_iterator end = nodeRemoveList.end(); + for ( NodeList::const_iterator it = nodeRemoveList.begin(); it != end; ++it ) + { + removeNode(*it); + (*it)->setSelected(false); + } + } + + { + const ConnectorList::const_iterator end = connectorRemoveList.end(); + for ( ConnectorList::const_iterator it = connectorRemoveList.begin(); it != end; ++it ) + { + removeConnector(*it); + (*it)->setSelected(false); + } + } + + { + const QCanvasItemList::const_iterator end = list.end(); + for ( QCanvasItemList::const_iterator it = list.begin(); it != end; ++it ) + { + // We don't need to check that we've already got the item as it will + // be checked in the function call + addQCanvasItem(*it); + } + } +} + + +void CNItemGroup::removeItem( Item *item ) +{ + if ( !item || !m_itemList.contains(item) ) + return; + unregisterItem(item); + if ( m_activeItem == item ) + getActiveItem(); + + item->setSelected(false); + updateInfo(); + emit itemRemoved(item); +} + + +void CNItemGroup::removeNode( Node *node ) +{ + if ( !node || !m_nodeList.contains(node) ) + return; + m_nodeList.remove(node); + node->setSelected(false); + updateInfo(); + emit nodeRemoved(node); +} + + +void CNItemGroup::removeConnector( Connector *con ) +{ + if ( !con || !m_connectorList.contains(con) ) return; + m_connectorList.remove(con); + con->setSelected(false); + updateInfo(); + emit connectorRemoved(con); +} + + +void CNItemGroup::removeQCanvasItem( QCanvasItem *qcanvasItem ) +{ + if (!qcanvasItem) return; + + Item *item = dynamic_cast(qcanvasItem); + if (item) + return removeItem(item); + + Node *node = dynamic_cast(qcanvasItem); + if (node) + return removeNode(node); + + Connector *connector = dynamic_cast(qcanvasItem); + if (!connector) + { + ConnectorLine *connectorLine = dynamic_cast(qcanvasItem); + if (connectorLine) + connector = connectorLine->parent(); + } + if (connector) + return removeConnector(connector); +} + + +NodeList CNItemGroup::nodes( bool excludeParented ) const +{ + NodeList nodeList = m_nodeList; + if (excludeParented) + return nodeList; + + NodeGroupList translatableNodeGroups; + p_icnDocument->getTranslatable( items(false), 0l, 0l, &translatableNodeGroups ); + + NodeGroupList::iterator end = translatableNodeGroups.end(); + for ( NodeGroupList::iterator it = translatableNodeGroups.begin(); it != end; ++it ) + { + const NodeList internal = (*it)->internalNodeList(); + NodeList::const_iterator internalEnd = internal.end(); + for ( NodeList::const_iterator intIt = internal.begin(); intIt != internalEnd; ++intIt ) + { + if ( *intIt && !nodeList.contains(*intIt) ) + nodeList << *intIt; + } + } + + return nodeList; +} + + +ConnectorList CNItemGroup::connectors( bool excludeParented ) const +{ + ConnectorList connectorList = m_connectorList; + if (excludeParented) + return connectorList; + + ConnectorList translatableConnectors; + NodeGroupList translatableNodeGroups; + p_icnDocument->getTranslatable( items(false), 0l, &translatableConnectors, &translatableNodeGroups ); + + ConnectorList::iterator tcEnd = translatableConnectors.end(); + for ( ConnectorList::iterator it = translatableConnectors.begin(); it != tcEnd; ++it ) + { + if ( *it && !connectorList.contains(*it) ) + connectorList << *it; + } + + NodeGroupList::iterator end = translatableNodeGroups.end(); + for ( NodeGroupList::iterator it = translatableNodeGroups.begin(); it != end; ++it ) + { + const NodeList internal = (*it)->internalNodeList(); + NodeList::const_iterator internalEnd = internal.end(); + for ( NodeList::const_iterator intIt = internal.begin(); intIt != internalEnd; ++intIt ) + { + const ConnectorList connected = (*intIt)->inputConnectorList() + (*intIt)->outputConnectorList(); + ConnectorList::const_iterator connectedEnd = connected.end(); + for ( ConnectorList::const_iterator conIt = connected.begin(); conIt != connectedEnd; ++conIt ) + { + if ( *conIt && !connectorList.contains(*conIt) ) + connectorList << *conIt; + } + } + } + + return connectorList; +} + + +bool CNItemGroup::contains( QCanvasItem *qcanvasItem ) const +{ + if (!qcanvasItem) + return false; + + const ItemList::const_iterator ciEnd = m_itemList.end(); + for ( ItemList::const_iterator it = m_itemList.begin(); it != ciEnd; ++it ) + { + if ( *it == qcanvasItem ) + return true; + } + const ConnectorList::const_iterator conEnd = m_connectorList.end(); + for ( ConnectorList::const_iterator it = m_connectorList.begin(); it != conEnd; ++it ) + { + if ( *it == qcanvasItem ) + return true; + } + const NodeList::const_iterator nodeEnd = m_nodeList.end(); + for ( NodeList::const_iterator it = m_nodeList.begin(); it != nodeEnd; ++it ) + { + if ( *it == qcanvasItem ) + return true; + } + + return false; +} + + +void CNItemGroup::setSelected( bool sel ) +{ + const ItemList::iterator ciEnd = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != ciEnd; ++it ) + { + if (*it && (*it)->isSelected() != sel ) + (*it)->setSelected(sel); + } + const ConnectorList::iterator conEnd = m_connectorList.end(); + for ( ConnectorList::iterator it = m_connectorList.begin(); it != conEnd; ++it ) + { + if ( *it && (*it)->isSelected() != sel ) + (*it)->setSelected(sel); + } + const NodeList::iterator nodeEnd = m_nodeList.end(); + for ( NodeList::iterator it = m_nodeList.begin(); it != nodeEnd; ++it ) + { + if ( *it && (*it)->isSelected() != sel ) + (*it)->setSelected(sel); + } +} + + +bool CNItemGroup::canRotate() const +{ + const ItemList::const_iterator end = m_itemList.end(); + for ( ItemList::const_iterator it = m_itemList.begin(); it != end; ++it ) + { + CNItem *cnItem = dynamic_cast((Item*)*it); + if ( cnItem && cnItem->canRotate() ) + return true; + } + return false; +} + + +bool CNItemGroup::canFlip() const +{ + const ItemList::const_iterator end = m_itemList.end(); + for ( ItemList::const_iterator it = m_itemList.begin(); it != end; ++it ) + { + CNItem *cnItem = dynamic_cast((Item*)*it); + if ( cnItem && cnItem->canFlip() ) + return true; + } + return false; +} + + +void CNItemGroup::slotRotateCW() +{ + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + Component *component = dynamic_cast((Item*)*it); + if ( component && component->isMovable() && component->canRotate() ) + { + int oldAngle = component->angleDegrees(); + component->setAngleDegrees((oldAngle+90)%360); + } + } + p_icnDocument->requestStateSave(); +} + +void CNItemGroup::slotRotateCCW() +{ + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + Component *component = dynamic_cast((Item*)*it); + if ( component && component->isMovable() && component->canRotate() ) + { + int oldAngle = component->angleDegrees(); + component->setAngleDegrees((oldAngle+270)%360); + } + } + p_icnDocument->requestStateSave(); +} + +void CNItemGroup::slotFlip() +{ + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + Component *component = dynamic_cast((Item*)*it); + if ( component && component->isMovable() && component->canFlip() ) + { + bool oldFlipped = component->flipped(); + component->setFlipped(!oldFlipped); + } + } + p_icnDocument->requestStateSave(); +} + + +void CNItemGroup::setOrientationAngle( int _angle ) +{ + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + Component *component = dynamic_cast((Item*)*it); + if ( component && component->isMovable() && component->canRotate() ) + { + int oldAngle = component->angleDegrees(); + if ( oldAngle != _angle ) + { + component->setAngleDegrees(_angle); + } + } + } + p_icnDocument->requestStateSave(); +} + + +void CNItemGroup::setComponentOrientation( int angleDegrees, bool flipped ) +{ + bool flipping = flipped; + bool rotating = (((angleDegrees%360)+360)%360) != 0; + + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + Component *component = dynamic_cast((Item*)*it); + if ( component && component->isMovable() && (!flipping || component->canFlip()) && (!rotating || component->canRotate()) ) + { + int oldAngle = component->angleDegrees(); + int oldFlipped = component->flipped(); + if ( (oldAngle != angleDegrees) || (oldFlipped != flipped) ) + { + if ( component->canFlip() ) + component->setFlipped(flipped); + if ( component->canRotate() ) + component->setAngleDegrees(angleDegrees); + } + } + } + p_icnDocument->requestStateSave(); +} + + +void CNItemGroup::setFlowPartOrientation( unsigned orientation ) +{ + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + FlowPart * flowPart = dynamic_cast((Item*)*it); + if ( flowPart && flowPart->isMovable() ) + flowPart->setOrientation(orientation); + } + p_icnDocument->requestStateSave(); +} + + +void CNItemGroup::mergeGroup( ItemGroup *itemGroup ) +{ + CNItemGroup *group = dynamic_cast(itemGroup); + if (!group) return; + + const ItemList items = group->items(); + const ConnectorList connectors = group->connectors(); + const NodeList nodes = group->nodes(); + + const ItemList::const_iterator ciEnd = items.end(); + for ( ItemList::const_iterator it = items.begin(); it != ciEnd; ++it ) + { + addItem(*it); + } + const ConnectorList::const_iterator conEnd = connectors.end(); + for ( ConnectorList::const_iterator it = connectors.begin(); it != conEnd; ++it ) + { + addConnector(*it); + } + const NodeList::const_iterator nodeEnd = nodes.end(); + for ( NodeList::const_iterator it = nodes.begin(); it != nodeEnd; ++it ) + { + addNode(*it); + } +} + + +void CNItemGroup::removeAllItems() +{ + while ( !m_itemList.isEmpty() ) + removeItem(*m_itemList.begin()); + + while ( !m_connectorList.isEmpty() ) + removeConnector(*m_connectorList.begin()); + + while ( !m_nodeList.isEmpty() ) + removeNode(*m_nodeList.begin()); +} + + +void CNItemGroup::deleteAllItems() +{ + const ItemList::iterator ciEnd = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != ciEnd; ++it ) + { + if (*it) + (*it)->removeItem(); + } + const NodeList::iterator nodeEnd = m_nodeList.end(); + for ( NodeList::iterator it = m_nodeList.begin(); it != nodeEnd; ++it ) + { + if ( *it && !(*it)->isChildNode() ) + { + (*it)->removeNode(); + } + } + const ConnectorList::iterator conEnd = m_connectorList.end(); + for ( ConnectorList::iterator it = m_connectorList.begin(); it != conEnd; ++it ) + { + if (*it) + { + (*it)->removeConnector(); + } + } + + // Clear the lists + removeAllItems(); +} + + +void CNItemGroup::updateInfo() +{ + m_connectorCount = m_connectorList.count(); + m_nodeCount = m_nodeList.count(); + + if ( m_itemList.isEmpty() ) + m_currentLevel = -1; +} + + +void CNItemGroup::getActiveItem() +{ + if ( m_itemList.isEmpty() ) + setActiveItem(0l); + else + setActiveItem( *m_itemList.begin() ); +} + + +void CNItemGroup::setActiveItem( Item *item ) +{ + if ( item == m_activeItem ) + return; + m_activeItem = item; +} + + +QStringList CNItemGroup::itemIDs() +{ + QStringList list; + ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + if (*it) { + list += (*it)->id(); + } + } + return list; +} + +#include "cnitemgroup.moc" diff --git a/src/cnitemgroup.h b/src/cnitemgroup.h new file mode 100644 index 0000000..fe2c064 --- /dev/null +++ b/src/cnitemgroup.h @@ -0,0 +1,215 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef CANVASITEMGROUP_H +#define CANVASITEMGROUP_H + +#include "itemgroup.h" + + +class CNItem; +class Item; +class ICNDocument; +class Component; +class Connector; +class FlowPart; +class Node; +class ECNode; +class FPNode; +class ICNDocument; +class QCanvasItem; +class QCanvasItemList; + +typedef QValueList > ItemList; +typedef QValueList > NodeList; +typedef QValueList > ConnectorList; + +/** +@author David Saxton +*/ +class CNItemGroup : public ItemGroup +{ +Q_OBJECT +public: + CNItemGroup( ICNDocument *icnDocument, const char *name = 0 ); + ~CNItemGroup(); + + /** + * Adds a CNItem to the group, if it is not already in it, or other items at + * a lower levels are already in the group. If there are items are a high level, + * those items are removed first. Returns false on failure to add. + */ + bool addItem( Item *item ); + /** + * Adds a Node to the group, if it is not already in it. Note: This node + * will *NOT* be added if it is a child node, and the function will return false. + * If the node is not already present, and is added, then this will return true. + */ + bool addNode( Node *node ); + /** + * Adds a Connector to the group, if it is not already in it (if it is, returns false) + */ + bool addConnector( Connector *con ); + /** + * If the item is a a CNItem, Node or Connector, returns the status + * for that particular add function, else returns false + */ + virtual bool addQCanvasItem( QCanvasItem *qcanvasItem ); + /** + * Sets the contained items to those in this list + */ + virtual void setItems( QCanvasItemList list ); + /** + * Removes the CNItem from the group + */ + void removeItem( Item *item ); + /** + * Removes the Node from the group + */ + void removeNode( Node *node ); + /** + * Removes the Connector from the group + */ + void removeConnector( Connector *con ); + /** + * If the item is a a CNItem, Node or Connector, then attempts to remove it + */ + virtual void removeQCanvasItem( QCanvasItem *qcanvasItem ); + /** + * Returns true if the QCanvasItem passed is contained in the group + */ + virtual bool contains( QCanvasItem *qcanvasItem ) const; + /** + * Returns the number of Nodes in the CanvasGroup + */ + uint nodeCount() const { return m_nodeCount; } + /** + * Returns the number of Connectors in the CanvasGroup + */ + uint connectorCount() const { return m_connectorCount; } + /** + * Returns the total number of items in the group + * (CNItems, Nodes, Connectors) + */ + uint count() const { return itemCount()+m_nodeCount+m_connectorCount; } + /** + * Sets the selected state of all items in the group + */ + virtual void setSelected( bool sel ); + /** + * Sets the orientation (degrees component) of all items in the group + */ + void setOrientationAngle( int angleDegrees ); + /** + * Sets the orientation (flipped component) of all items in the group + */ + void setOrientationFlipped( bool flipped ); + /** + * Sets the orientation of all flowparts in the group + */ + void setFlowPartOrientation( unsigned orientation ); + /** + * Sets the orientation (degrees and flipped) of all components in the group + */ + void setComponentOrientation( int angleDegrees, bool flipped ); + /** + * Merges all items in the given group with this group + */ + virtual void mergeGroup( ItemGroup *group ); + /** + * Removes all items from this group (doesn't delete them) + * @param unselect whether to unselect the items or not. This will be done after removal from group + */ + virtual void removeAllItems(); + /** + * Attempts to delete everything in the group. + * Note: You *must* call ICNDocument::flushDeleteList() after calling this function, + * as this function only tells the items to remove themselves + */ + virtual void deleteAllItems(); + /** + * Returns a list of all the Nodes in the group. + * @param excludeParented if false, then nodes that are fully contained + * within item children will also be returned. + */ + NodeList nodes( bool excludeParented = true ) const; + /** + * Returns a list of all the Connectors in the group. + * @param excludeParented if false, then connectors that are fully contained + * within item children will also be returned. + */ + ConnectorList connectors( bool excludeParented = true ) const; + /** + * Returns a list of the ids of all the CNItems in the group. + */ + QStringList itemIDs(); + /** + * Returns true if at least some of the CNItems in this group can be + * rotated. Returns false if no items present. + */ + bool canRotate() const; + /** + * Returns true if at least some of the CNItems in this group can be + * flipped. Returns false if no items present. + */ + bool canFlip() const; + + +public slots: + /** + * Sets the orientation of all selected items to 0 degrees. + */ + void slotSetOrientation0() { setOrientationAngle(0); } + /** + * Sets the orientation of all selected items to 90 degrees. + */ + void slotSetOrientation90() { setOrientationAngle(90); } + /** + * Sets the orientation of all selected items to 180 degrees. + */ + void slotSetOrientation180() { setOrientationAngle(180); } + /** + * Sets the orientation of all selected items to 270 (actually -90) degrees. + */ + void slotSetOrientation270() { setOrientationAngle(-90); } + /** + * Rotates all CNItems in the group clockwise + */ + void slotRotateCW(); + /** + * Rotates all CNItems in the group counter-clockwise + */ + void slotRotateCCW(); + /** + * Flips all CNItems in the group + */ + void slotFlip(); + +signals: + void connectorAdded( Connector *con ); + void connectorRemoved( Connector *con ); + void nodeAdded( Node *node ); + void nodeRemoved( Node *node ); + +protected: + void updateInfo(); + void getActiveItem(); + void setActiveItem( Item *item ); + +private: + ICNDocument *p_icnDocument; + ConnectorList m_connectorList; + NodeList m_nodeList; + uint m_connectorCount; + uint m_nodeCount; + int m_currentLevel; // We can only accept CNItems of one level +}; + +#endif diff --git a/src/connector.cpp b/src/connector.cpp new file mode 100644 index 0000000..03a304c --- /dev/null +++ b/src/connector.cpp @@ -0,0 +1,652 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "circuitdocument.h" +#include "connector.h" +#include "conrouter.h" +#include "cnitem.h" +#include "ecnode.h" +#include "itemdocumentdata.h" +#include "wire.h" + +#include + + +#include + +inline static int toCanvas( int pos ) +{ + return pos*8+4; +} +inline static int fromCanvas( int pos ) +{ + return (pos-4)/8; +// return (pos>0) ? int((pos-3)/8) : int((pos-5)/8); +} + +inline static QPoint toCanvas( const QPoint * const pos ) +{ + return QPoint( toCanvas(pos->x()), toCanvas(pos->y()) ); +} +inline static QPoint fromCanvas( const QPoint * const pos ) +{ + return QPoint( fromCanvas(pos->x()), fromCanvas(pos->y()) ); +} + +inline static QPoint toCanvas( const QPoint &pos ) +{ + return QPoint( toCanvas(pos.x()), toCanvas(pos.y()) ); +} +inline static QPoint fromCanvas( const QPoint &pos ) +{ + return QPoint( fromCanvas(pos.x()), fromCanvas(pos.y()) ); +} + + +//BEGIN class Connector +Connector::Connector( Node * startNode, Node * endNode, ICNDocument *icnDocument, QString *id ) + : QObject(icnDocument), + QCanvasPolygon( icnDocument->canvas() ) +{ + p_icnDocument = icnDocument; + m_conRouter = new ConRouter(p_icnDocument); + p_parentContainer = 0l; + m_startNode = startNode; + m_endNode = endNode; + p_nodeGroup = 0l; + b_semiHidden = false; + b_deleted = false; + b_pointsAdded = false; + b_manualPoints = false; + m_bIsSyncingWires = false; + + if (id) + { + m_id = *id; + if ( !p_icnDocument->registerUID(*id) ) + { +// kdDebug() << k_funcinfo << "KTechlab: Connector attempted to register given ID, but ID already in use"<generateUID("connector"); + + p_icnDocument->registerItem(this); + + p_icnDocument->requestRerouteInvalidatedConnectors(); + setVisible(true); + + ECNode * startECNode = dynamic_cast(startNode); + ECNode * endECNode = dynamic_cast(endNode); + if ( startECNode && endECNode ) + { + connect( startECNode, SIGNAL(numPinsChanged(unsigned)), this, SLOT(syncWiresWithNodes()) ); + connect( endECNode, SIGNAL(numPinsChanged(unsigned)), this, SLOT(syncWiresWithNodes()) ); + syncWiresWithNodes(); + } +} + + +Connector::~Connector() +{ + p_icnDocument->unregisterUID( id() ); + + delete m_conRouter; + m_conRouter = 0l; + + for ( unsigned i = 0; i < m_wires.size(); i++ ) + delete m_wires[i]; + m_wires.resize(0); +} + + +int Connector::rtti() const +{ + return ItemDocument::RTTI::Connector; +} + + +void Connector::syncWiresWithNodes() +{ + ECNode * startECNode = dynamic_cast((Node*)m_startNode); + ECNode * endECNode = dynamic_cast((Node*)m_endNode); + + if ( !startECNode || !endECNode ) + return; + + unsigned newNumWires = 0; + + if ( startECNode->type() == Node::ec_junction || + endECNode->type() == Node::ec_junction ) + newNumWires = QMAX( startECNode->numPins(), endECNode->numPins() ); + + else + newNumWires = QMIN( startECNode->numPins(), endECNode->numPins() ); + + unsigned oldNumWires = m_wires.size(); + + if ( newNumWires == oldNumWires ) + return; + + m_bIsSyncingWires = true; + if ( startECNode->type() == Node::ec_junction ) + startECNode->setNumPins(newNumWires); + if ( endECNode->type() == Node::ec_junction ) + endECNode->setNumPins(newNumWires); + m_bIsSyncingWires = false; + + if ( newNumWires > oldNumWires ) + { + m_wires.resize(newNumWires); + for ( unsigned i = oldNumWires; i < newNumWires; i++ ) + { + if ( startECNode->pin(i) && endECNode->pin(i) ) + m_wires[i] = new Wire( startECNode->pin(i), endECNode->pin(i) ); + } + } + else + { + for ( unsigned i = newNumWires; i < oldNumWires; i++ ) + delete m_wires[i]; + m_wires.resize(newNumWires); + } + + updateConnectorLines(); + emit numWiresChanged(newNumWires); +} + + +void Connector::setParentContainer( const QString &cnItemId ) +{ +// // We only allow the node to be parented once +// if ( p_parentContainer || !ICNDocument->itemWithID(cnItemId) ) return; + p_parentContainer = p_icnDocument->cnItemWithID(cnItemId); +} + + +void Connector::removeConnector( Node* ) +{ + if (b_deleted) + return; + b_deleted = true; + + // Remove 'penalty' points for this connector from the ICNDocument + updateConnectorPoints(false); + + emit selected(false); + emit removed(this); + if ( m_startNode ) + m_startNode->removeConnector(this); + if ( m_endNode ) + m_endNode->removeConnector(this); + p_icnDocument->appendDeleteList(this); +} + + +int getSlope( float x1, float y1, float x2, float y2 ) +{ + enum slope + { + s_n = 0,// . + s_v, // | + s_h, // - + s_s, // / + s_d // \ (backwards slash) + + }; + + if ( x1 == x2 ) + { + if ( y1 == y2 ) { + return s_n; + } + return s_v; + } + else if ( y1 == y2 ) { + return s_h; + } + else if ( (y2-y1)/(x2-x1) > 0 ) { + return s_s; + } + else { + return s_d; + } +} + + +void Connector::updateDrawList() +{ + if ( !m_startNode || !m_endNode || !canvas() ) { + return; + } + + QPointList drawLineList; + + int prevX = (*m_conRouter->cellPointList()->begin()).x(); + int prevY = (*m_conRouter->cellPointList()->begin()).y(); + + int prevX_canvas = toCanvas(prevX); + int prevY_canvas = toCanvas(prevY); + + Cells *cells = p_icnDocument->cells(); + + bool bumpNow = false; + const QPointList::const_iterator cplEnd = m_conRouter->cellPointList()->end(); + for ( QPointList::const_iterator it = m_conRouter->cellPointList()->begin(); it != cplEnd; ++it ) + { + const int x = (*it).x(); + const int y = (*it).y(); + const int numCon = p_icnDocument->isValidCellReference(x,y) ? (*cells)[x][y].numCon : 0; + + const int y_canvas = toCanvas(y); + const int x_canvas = toCanvas(x); + + const bool bumpNext = ( prevX == x && + numCon > 1 && + std::abs(y_canvas-m_startNode->y())>8 && + std::abs(y_canvas-m_endNode->y())>8 ); + + int x0 = prevX_canvas; + int x2 = x_canvas; + int x1 = (x0+x2)/2; + + int y0 = prevY_canvas; + int y3 = y_canvas; + int y1 = ( y0 == y3 ) ? y0 : ((y0 x2 || x2 == -1 ) { + x2 = p.x(); + } + if ( p.y() < y1 || y1 == -1 ) { + y1 = p.y(); + } + if ( p.y() > y2 || y2 == -1 ) { + y2 = p.y(); + } + } + + QRect boundRect( x1, y1, x2-x1, y2-y1 ); + if ( boundRect != m_oldBoundRect ) + { + canvas()->setChanged( boundRect | m_oldBoundRect ); + m_oldBoundRect = boundRect; + } + } + + //BEGIN build up ConnectorLine list + const ConnectorLineList::iterator ConnectorLineEnd = m_connectorLineList.end(); + for ( ConnectorLineList::iterator it = m_connectorLineList.begin(); it != ConnectorLineEnd; ++it ) + delete *it; + m_connectorLineList.clear(); + + if ( drawLineList.size() > 1 ) + { + QPoint prev = drawLineList.first(); + const QPointList::iterator end = drawLineList.end(); + for ( QPointList::iterator it = ++drawLineList.begin(); it != end; ++it ) + { + const QPoint next = *it; + ConnectorLine *line = new ConnectorLine(this); + line->setPoints( prev.x(), prev.y(), next.x(), next.y() ); + m_connectorLineList.append(line); + prev = next; + } + } + updateConnectorLines(); + //END build up ConnectorPoint list +} + + +void Connector::setSemiHidden( bool semiHidden ) +{ + if ( !canvas() || semiHidden == b_semiHidden ) + return; + + b_semiHidden = semiHidden; + updateConnectorLines(); +} + + +void Connector::updateConnectorPoints( bool add ) +{ + if (!canvas()) { + return; + } + + if ( b_deleted || !isVisible() ) + add = false; + + // Check we haven't already added/removed the points... + if ( b_pointsAdded == add ) + return; + + b_pointsAdded = add; + + // We don't include the end points in the mapping + if ( m_conRouter->cellPointList()->size() < 3 ) { + return; + } + + const int mult = (add)?1:-1; + const QPointList::iterator end = --m_conRouter->cellPointList()->end(); + for ( QPointList::iterator it = ++m_conRouter->cellPointList()->begin(); it != end; ++it ) + { + int x = (*it).x(); + int y = (*it).y(); + + // Add the points of this connector to the cell array in the ICNDocument, + // so that other connectors still to calculate their points know to try + // and avoid this connector + + p_icnDocument->addCPenalty( x, y-1, mult*ICNDocument::hs_connector/2 ); + p_icnDocument->addCPenalty( x-1, y, mult*ICNDocument::hs_connector/2 ); + p_icnDocument->addCPenalty( x, y, mult*ICNDocument::hs_connector ); + p_icnDocument->addCPenalty( x+1, y, mult*ICNDocument::hs_connector/2 ); + p_icnDocument->addCPenalty( x, y+1, mult*ICNDocument::hs_connector/2 ); + + if ( p_icnDocument->isValidCellReference( x, y ) ) { + (*p_icnDocument->cells())[x][y].numCon += mult; + } + } + +// updateDrawList(); +} + + +void Connector::setRoutePoints( QPointList pointList, bool setManual, bool checkEndPoints ) +{ + if (!canvas()) { + return; + } + updateConnectorPoints(false); + + bool reversed = pointsAreReverse(pointList); + if (checkEndPoints) + { + if (reversed) + { + pointList.prepend( QPoint( int(m_endNode->x()), int(m_endNode->y()) ) ); + pointList.append( QPoint( int(m_startNode->x()), int(m_startNode->y()) ) ); + } + else + { + pointList.prepend( QPoint( int(m_startNode->x()), int(m_startNode->y()) ) ); + pointList.append( QPoint( int(m_endNode->x()), int(m_endNode->y()) ) ); + } + } + + m_conRouter->setPoints( pointList, reversed ); + b_manualPoints = setManual; + updateConnectorPoints(true); +} + + +bool Connector::pointsAreReverse( const QPointList &pointList ) const +{ + if ( !m_startNode || !m_endNode ) + { + kdWarning() << k_funcinfo << "Cannot determine orientation as no start and end nodes" << endl; + return false; + } + + if ( pointList.isEmpty() ) + return false; + + + int plsx = pointList.first().x(); + int plsy = pointList.first().y(); + int plex = pointList.last().x(); + int pley = pointList.last().y(); + + double nsx = m_startNode->x(); + double nsy = m_startNode->y(); + double nex = m_endNode->x(); + double ney = m_endNode->y(); + + double dist_normal = (nsx-plsx)*(nsx-plsx) + (nsy-plsy)*(nsy-plsy) + (nex-plex)*(nex-plex) + (ney-pley)*(ney-pley); + double dist_reverse = (nsx-plex)*(nsx-plex) + (nsy-pley)*(nsy-pley) + (nex-plsx)*(nex-plsx) + (ney-plsy)*(ney-plsy); + + return dist_reverse < dist_normal; +} + + +void Connector::rerouteConnector() +{ + if (!isVisible()) + return; + + if ( nodeGroup() ) + { + kdWarning() << k_funcinfo << "Connector is controlled by a NodeGroup! Use that to reroute the connector" << endl; + return; + } + + if ( !startNode() || !endNode() ) + return; + + updateConnectorPoints(false); + m_conRouter->mapRoute( int(startNode()->x()), int(startNode()->y()), int(endNode()->x()), int(endNode()->y()) ); + b_manualPoints = false; + updateConnectorPoints(true); +} + + +void Connector::translateRoute( int dx, int dy ) +{ + updateConnectorPoints(false); + m_conRouter->translateRoute( dx, dy ); + updateConnectorPoints(true); + updateDrawList(); +} + + +void Connector::restoreFromConnectorData( const ConnectorData &connectorData ) +{ + updateConnectorPoints(false); + b_manualPoints = connectorData.manualRoute; + m_conRouter->setRoutePoints( connectorData.route ); + updateConnectorPoints(true); + updateDrawList(); +} + + +ConnectorData Connector::connectorData() const +{ + ConnectorData connectorData; + if ( !m_startNode || !m_endNode ) + { + kdDebug() << k_funcinfo << " m_startNode="< +#include +#include + +class Cell; +class ConnectorData; +class ConnectorLine; +class ConRouter; +class CNItem; +class ICNDocument; +class Node; +class NodeGroup; +class Wire; + +typedef QValueList ConnectorLineList; +typedef QValueList QPointList; +typedef QValueVector > WireVector; + + +/** +@short Represents a connection between two Nodes on a ICNDocument +@author David Saxton +*/ +class Connector : public QObject, public QCanvasPolygon +{ +Q_OBJECT +public: + Connector( Node * startNode, Node * endNode, ICNDocument *_ICNDocument, QString *id = 0L ); + ~Connector(); + + virtual int rtti() const; + /** + * Node at start of connector (which refers to this as the output connector) + */ + Node * startNode() const { return m_startNode; } + /** + * Node at end of connector (which refers to this as the input connector) + */ + Node * endNode() const { return m_endNode; } + /** + * @returns connector data describing this connector + */ + ConnectorData connectorData() const; + /** + * Restore the state of the connector (route, etc) from the saved data + */ + void restoreFromConnectorData( const ConnectorData &connectorData ); + /** + * If selected, will be drawn in a different colour + */ + virtual void setSelected( bool yes ); + /** + * Connected id + */ + QString id() const { return m_id; } + /** + * Update the list of lines and connetion-points that the connector uses for + * drawing. + */ + void updateDrawList(); + /** + * Tells the connector that it is under the control of a NodeGroup. When + * the connector is under the control of a NodeGroup, all requests for + * connection rerouting will be passed onto that NodeGroup + */ + void setNodeGroup( NodeGroup *nodeGroup ) { p_nodeGroup = nodeGroup; } + /** + * Returns the NodeGroup that the connector is under the control of (if any) + */ + NodeGroup *nodeGroup() const { return p_nodeGroup; } + /** + * ICNDocument needs to know what 'cells' a connector is present in, + * so that connection mapping can be done to avoid connectors. + * This function will add the hit penalty to the cells pointed to + * by ICNDocument::cells() + */ + void updateConnectorPoints( bool add ); + /** + * Sets the canvas points that the connector should route itself along. + * This is used for manual routing. The cells points are absolute positions + * (unlike the points stored internally in this class, which are the cell poisition + * @param setManual if true then the connector will change to a manual route one + * @param checkEndPoints if true then will check to see if the end points are at the nodes, and adds them if not + */ + void setRoutePoints( QPointList pointList, bool setManual, bool checkEndPoints = false ); + /** + * Call this function (e.g. when moving a CNItem connected to the connector) + * to make the connector partially hidden - probably grayed out - if semiHidden + * is true. + */ + void setSemiHidden( bool semiHidden ); + /** + * Sets the container parent (i.e. the container of the parent item) + */ + void setParentContainer( const QString &cnItemId ); + /** + * Returns a pointer to the parent item container + */ + CNItem *parentContainer() const { return p_parentContainer; } + /** + * @returns whether the points have been set by the user manually defining them + */ + bool usesManualPoints() const { return b_manualPoints; } + /** + * Returns two sets of points (in canvas-reference) that define the connector + * from start to finish, when it is split at the given point (in canvas-reference) + */ + QValueList splitConnectorPoints( const QPoint &pos ) const; + /** + * @returns pointer to ICNDocument that this connector is a member of + */ + ICNDocument *icnDocument() const { return p_icnDocument; } + /** + * Looks at the set of canvas points and tries to determine whether they are + * in the reverse order from start to end node + */ + bool pointsAreReverse( const QPointList &pointList ) const; + /** + * Returns the points, given in canvas-reference, in order of start node to + * end node if reverse is false + * @param reverse whether or not to reverse the points from start node to end node + */ + QPointList connectorPoints( bool reverse = false ) const; + /** + * Reroute the connector. Note that if this connector is controlled by a + * NodeGroup, it will do nothing (other than print out a warning) + */ + void rerouteConnector(); + /** + * Translates the route by the given amoumt. No checking is done to see if + * the translation is useful, etc. + */ + void translateRoute( int dx, int dy ); + virtual void setVisible( bool yes ); + WireVector wires() const { return m_wires; } + unsigned numWires() const { return m_wires.size(); } + Wire * wire( unsigned num = 0 ) const { return (num < m_wires.size()) ? m_wires[num] : 0l; } + +signals: + void removed( Connector *connector ); + void selected( bool yes ); + void numWiresChanged( unsigned newNum ); + +public slots: + void removeConnector( Node* = 0L ); + /** + * Takes the minimum pin count of the start and end nodes, and creates a + * connector for each pin up to that minimum. + */ + void syncWiresWithNodes(); + +protected: + void updateConnectorLines(); + + bool m_bIsSyncingWires; + bool b_semiHidden; + QGuardedPtr m_startNode; + QGuardedPtr m_endNode; + NodeGroup *p_nodeGroup; + CNItem *p_parentContainer; + ICNDocument *p_icnDocument; + ConRouter *m_conRouter; + QString m_id; + ConnectorLineList m_connectorLineList; + QRect m_oldBoundRect; + WireVector m_wires; + bool b_deleted; + bool b_manualPoints; + bool b_pointsAdded; +}; +typedef QValueList > ConnectorList; + + +//BEGIN ConnectorLine things +class ConnectorLine : public QObject, public QCanvasLine +{ + public: + ConnectorLine( Connector *connector ); + Connector *parent() const { return p_connector; } + virtual int rtti() const; + + protected: + Connector *p_connector; +}; +//END ConnectorLine things + +#endif + diff --git a/src/conrouter.cpp b/src/conrouter.cpp new file mode 100644 index 0000000..2c2d6da --- /dev/null +++ b/src/conrouter.cpp @@ -0,0 +1,537 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "conrouter.h" +#include "icndocument.h" + +#include + +#include +#include + +inline static int toCanvas( int pos ) +{ + return pos*8+4; +} +inline static int fromCanvas( int pos ) +{ + return (pos-4)/8; +} + +inline static QPoint toCanvas( const QPoint * const pos ) +{ + return QPoint( toCanvas(pos->x()), toCanvas(pos->y()) ); +} +inline static QPoint fromCanvas( const QPoint * const pos ) +{ + return QPoint( fromCanvas(pos->x()), fromCanvas(pos->y()) ); +} + +inline static QPoint toCanvas( const QPoint &pos ) +{ + return QPoint( toCanvas(pos.x()), toCanvas(pos.y()) ); +} +inline static QPoint fromCanvas( const QPoint &pos ) +{ + return QPoint( fromCanvas(pos.x()), fromCanvas(pos.y()) ); +} + +static inline int roundDouble( const double x ) +{ + return int(std::floor(x+0.5)); +} + +ConRouter::ConRouter( ICNDocument *cv ) +{ + p_icnDocument = cv; + m_lcx = m_lcy = 0; +} + + +ConRouter::~ConRouter() +{ +} + + +QPointList ConRouter::pointList( bool reverse ) const +{ + QPointList pointList; + + if (reverse) + { + bool notDone = m_cellPointList.size() > 0; + for ( QPointList::const_iterator it = m_cellPointList.fromLast(); notDone; --it ) + { + pointList.append( toCanvas(&*it) ); + if ( it == m_cellPointList.begin() ) notDone = false; + } + } + else + { + const QPointList::const_iterator end = m_cellPointList.end(); + for ( QPointList::const_iterator it = m_cellPointList.begin(); it != end; ++it ) + { + pointList.append( toCanvas(&*it) ); + } + } + + return pointList; +} + + +static double qpoint_distance( const QPoint & p1, const QPoint & p2 ) +{ + double dx = p1.x() - p2.x(); + double dy = p1.y() - p2.y(); + + return std::sqrt( dx*dx + dy*dy ); +} + + +QPointListList ConRouter::splitPoints( const QPoint &pos ) const +{ + const QPoint split = fromCanvas(&pos); + + QValueList list; + + // Check that the point is in the connector points, and not at the start or end + bool found = false; + QPointList::const_iterator end = m_cellPointList.end(); + + double dl[] = { 0.0, 1.1, 1.5 }; // sqrt(2) < 1.5 < sqrt(5) + for ( unsigned i = 0; (i < 3) && !found; ++i ) + { + for ( QPointList::const_iterator it = m_cellPointList.begin(); it != end && !found; ++it ) + { + if ( qpoint_distance( *it, split ) <= dl[i] && it != m_cellPointList.begin() && it != m_cellPointList.fromLast() ) + found = true; + } + } + + QPointList first; + QPointList second; + + if (!found) + { + kdWarning() << "ConRouter::splitConnectorPoints: Could not find point ("<isValidCellReference(x,y) ) return; + Cell * const c = &(*cellsPtr)[x][y]; + if ( c->permanent ) return; + int newScore = nextScore + c->CIpenalty + c->Cpenalty; + + // Check for changing direction + if ( x != prevX && prev->prevX == prevX ) newScore += 5; + else if ( y != prevY && prev->prevY == prevY ) newScore += 5; + + if ( c->bestScore < newScore ) return; + + // We only want to change the previous cell if the score is different, + // or the score is the same but this cell allows the connector + // to travel in the same direction + + if ( c->bestScore == newScore && + x != prevX && + y != prevY ) return; + + c->bestScore = newScore; + c->prevX = prevX; + c->prevY = prevY; + + if ( !c->addedToLabels ) + { + c->addedToLabels = true; + Point point; + point.x = x; + point.y = y; + point.prevX = prevX; + point.prevY = prevY; + TempLabelMap::iterator it = tempLabels.insert( std::make_pair(newScore,point) ); + c->point = &it->second; + } + else + { + c->point->prevX = prevX; + c->point->prevY = prevY; + } +} + +void ConRouter::checkCell( int x, int y ) +{ + Cell * const c = &(*cellsPtr)[x][y]; + + c->permanent = true; + const int nextScore = c->bestScore+1; + + // Check the surrounding cells (up, left, right, down) + if ( y > 0 ) checkACell( x, y-1, c, x, y, nextScore ); + if ( x > 0 ) checkACell( x-1, y, c, x, y, nextScore ); + if ( x+1 < xcells ) checkACell( x+1, y, c, x, y, nextScore ); + if ( y+1 < ycells ) checkACell( x, y+1, c, x, y, nextScore ); +} + + +bool ConRouter::needsRouting( int sx, int sy, int ex, int ey ) const +{ + if ( m_cellPointList.size() < 2 ) + { + // Better be on the safe side... + return true; + } + + const int scx = fromCanvas(sx); + const int scy = fromCanvas(sy); + const int ecx = fromCanvas(ex); + const int ecy = fromCanvas(ey); + + const int psx = m_cellPointList.first().x(); + const int psy = m_cellPointList.first().y(); + const int pex = m_cellPointList.last().x(); + const int pey = m_cellPointList.last().y(); + + return (psx != scx || psy != scy || pex != ecx || pey != ecy ) && + (pex != scx || pey != scy || psx != ecx || psy != ecy ); +} + + +void ConRouter::setRoutePoints( const QPointList &pointList ) +{ + m_cellPointList = pointList; + removeDuplicatePoints(); +} + + +void ConRouter::setPoints( const QPointList &pointList, bool reverse ) +{ + if ( pointList.size() == 0 ) + return; + + QPointList cellPointList; + + QPoint prevCellPoint = fromCanvas(*pointList.begin()); + cellPointList.append(prevCellPoint); + const QPointList::const_iterator end = pointList.end(); + for ( QPointList::const_iterator it = pointList.begin(); it != end; ++it ) + { + QPoint cellPoint = fromCanvas(*it); + + while ( prevCellPoint != cellPoint ) + { + cellPointList.append(prevCellPoint); + + if ( prevCellPoint.x() < cellPoint.x() ) prevCellPoint.setX( prevCellPoint.x()+1 ); + else if ( prevCellPoint.x() > cellPoint.x() ) prevCellPoint.setX( prevCellPoint.x()-1 ); + if ( prevCellPoint.y() < cellPoint.y() ) prevCellPoint.setY( prevCellPoint.y()+1 ); + else if ( prevCellPoint.y() > cellPoint.y() ) prevCellPoint.setY( prevCellPoint.y()-1 ); + }; + + prevCellPoint = cellPoint; + } + cellPointList.append(prevCellPoint); + + if (reverse) + { + m_cellPointList.clear(); + const QPointList::iterator begin = cellPointList.begin(); + for ( QPointList::iterator it = cellPointList.fromLast(); it != begin; --it ) + { + m_cellPointList += *it; + } + m_cellPointList += *begin; + } + else { + m_cellPointList = cellPointList; + } + + removeDuplicatePoints(); +} + + +void ConRouter::translateRoute( int dx, int dy ) +{ + if ( dx == 0 && dy == 0 ) { + return; + } + + m_lcx += dx; + m_lcy += dy; + +// const QPoint ds = QPoint( fromCanvas(dx), fromCanvas(dy) ); + const QPoint ds = QPoint( dx/8, dy/8 ); + + QPointList::iterator end = m_cellPointList.end(); + for ( QPointList::iterator it = m_cellPointList.begin(); it != end; ++it ) + { + (*it) += ds; + } + + removeDuplicatePoints(); +} + + +void ConRouter::mapRoute( int sx, int sy, int ex, int ey ) +{ + const int scx = fromCanvas(sx); + const int scy = fromCanvas(sy); + const int ecx = fromCanvas(ex); + const int ecy = fromCanvas(ey); + + if ( !p_icnDocument->isValidCellReference( scx, scy ) || + !p_icnDocument->isValidCellReference( ecx, ecy ) ) + { + return; + } + + m_cellPointList.clear(); + m_lcx = ecx; + m_lcy = ecy; + + + // First, lets try some common connector routes (which will not necesssarily + // be shortest, but they will be neat, and cut down on overall CPU usage) + // If that fails, we will resort to a shortest-route algorithm to find an + // appropriate route. + + // Connector configuration: Line + { + bool ok = checkLineRoute( scx, scy, ecx, ecy, 4*ICNDocument::hs_connector, 0 ); + if (ok) { + return; + } else { + m_cellPointList.clear(); + } + } + + // Corner 1 + { + bool ok = checkLineRoute( scx, scy, ecx, ecy, 2*ICNDocument::hs_connector, 0 ); + if (!ok) { + m_cellPointList.clear(); + } else { + ok = checkLineRoute( scx, scy, ecx, ecy, ICNDocument::hs_connector-1, 0 ); + if (ok) { + return; + } else { + m_cellPointList.clear(); + } + } + } + + // Corner 2 + { + bool ok = checkLineRoute( scx, scy, ecx, ecy, 2*ICNDocument::hs_connector, 0 ); + if (!ok) { + m_cellPointList.clear(); + } else { + ok = checkLineRoute( scx, scy, ecx, ecy, ICNDocument::hs_connector-1, 0 ); + if (ok) { + return; + } else { + m_cellPointList.clear(); + } + } + } + + // It seems we must resort to brute-force route-checking + { + cellsPtr = p_icnDocument->cells(); + cellsPtr->reset(); + + xcells = p_icnDocument->canvas()->width()/8; + ycells = p_icnDocument->canvas()->height()/8; + + // Now to map out the shortest routes to the cells + Cell * const startCell = &(*cellsPtr)[ecx][ecy]; + startCell->permanent = true; + startCell->bestScore = 0; + startCell->prevX = -1; + startCell->prevY = -1; + + tempLabels.clear(); + checkCell( ecx, ecy ); + + // Daniel: I changed it from a do while to a while otherwise + // in rare cases the iterator can end up as end(). + while ( tempLabels.size() > 0 && !(*cellsPtr)[scx][scy].permanent ) + { + TempLabelMap::iterator it = tempLabels.begin(); + checkCell( it->second.x, it->second.y ); + tempLabels.erase(it); + } + + // Now, retrace the shortest route from the endcell to get out points :) + int x = scx, y = scy; + bool ok = true; + do + { + m_cellPointList.append( QPoint( x, y ) ); + int newx = (*cellsPtr)[x][y].prevX; + int newy = (*cellsPtr)[x][y].prevY; + if ( newx == x && newy == y ) { + ok = false; + } + x = newx; + y = newy; + } + while ( p_icnDocument->isValidCellReference(x,y) && x != -1 && y != -1 && ok ); + + // And append the last point... + m_cellPointList.append( QPoint( ecx, ecy ) ); + } + + removeDuplicatePoints(); +} + + +bool ConRouter::checkLineRoute( int scx, int scy, int ecx, int ecy, int maxConScore, int maxCIScore ) +{ + if ( (scx != ecx) && (scy != ecy) ) { + return false; + } + + const bool isHorizontal = scy == ecy; + + int start=0, end=0, x=0, y=0, dd=0; + if (isHorizontal) + { + dd = (scxcells(); + + if (isHorizontal) + { + for ( int x = start; x!=end; x+=dd ) + { + if ( std::abs((double)(x-start))>1 && std::abs((double)(x-end))>1 && ((*cells)[x][y].CIpenalty > maxCIScore || (*cells)[x][y].Cpenalty > maxConScore) ) + { + return false; + } else { + m_cellPointList.append( QPoint( x, y ) ); + } + } + } + else + { + for ( int y = start; y!=end; y+=dd ) + { + if ( std::abs((double)(y-start))>1 && std::abs((double)(y-end))>1 && ((*cells)[x][y].CIpenalty > maxCIScore || (*cells)[x][y].Cpenalty > maxConScore) ) + { + return false; + } else { + m_cellPointList.append( QPoint( x, y ) ); + } + } + } + + m_cellPointList.prepend( QPoint( scx, scy ) ); + m_cellPointList.append( QPoint( ecx, ecy ) ); + removeDuplicatePoints(); + return true; +} + + +void ConRouter::removeDuplicatePoints() +{ + QPoint prev(-1,-1); + + const QPointList::iterator end = m_cellPointList.end(); + for ( QPointList::iterator it = m_cellPointList.begin(); it != end; ++it ) + { + if ( *it == prev ) { + *it = QPoint(-1,-1); + } else { + prev = *it; + } + } + m_cellPointList.remove( QPoint(-1,-1) ); +} diff --git a/src/conrouter.h b/src/conrouter.h new file mode 100644 index 0000000..2a522b7 --- /dev/null +++ b/src/conrouter.h @@ -0,0 +1,102 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef CONROUTER_H +#define CONROUTER_H + +#include "cells.h" + +#include +#include + +class ICNDocument; +class Cell; + +typedef QValueList QPointList; +typedef QValueList QPointListList; + +/** +Abstraction for the routing of a connector. + +NB: As a general rule of thumb, the point references stored as members of this +class are in Cell-space (i.e. 8^2 x smaller than Canvas-space), and the +interfacing functions take or give point references in Canvas-space (unless +otherwise indicated). + +@author David Saxton +*/ +class ConRouter +{ +public: + ConRouter( ICNDocument *cv ); + ~ConRouter(); + + /** + * What this class is all about - finding a route, from (sx,sy) to (ex,ey). + */ + void mapRoute( int sx, int sy, int ex, int ey ); + /** + * Translates the precalculated routepoints by the given amount + */ + void translateRoute( int dx, int dy ); + /** + * Sets the route to the given canvas points + * @param reverse if true, the points in pointList will be reversed + */ + void setPoints( const QPointList &pointList, bool reverse = false ); + /** + * Sets the route to the given route points + */ + void setRoutePoints( const QPointList &pointList ); + /** + * @returns true if the start or end points differ from that of the current route + */ + bool needsRouting( int sx, int sy, int ex, int ey ) const; + /** + * Returns the list of canvas points + */ + QPointList pointList( bool reverse ) const; + /** + * Returns a pointer to the internall cellPointList + */ + QPointList *cellPointList() { return &m_cellPointList; } + /** + * This will return two lists of Canvas points from the splitting of the + * route at the Canvas point "pos". The internall stored points are not + * affected. + */ + QPointListList splitPoints( const QPoint &pos ) const; + /** + * This will return a list of Canvas pointLists from the route, divided + * into n parts (at n-1 equally spaced places). + */ + QPointListList dividePoints( uint n ) const; + +protected: + /** + * Check a line of the ICNDocument cells for a valid route + */ + bool checkLineRoute( int scx, int scy, int ecx, int ecy, int maxConScore, int maxCIScore ); + void checkACell( int x, int y, Cell *prev, int prevX, int prevY, int nextScore ); + void checkCell( int x, int y ); // Gets the shortest route from the final cell + /** + * Remove duplicated points from the route + */ + void removeDuplicatePoints(); + + int xcells, ycells; + int m_lcx, m_lcy; // Last x / y from mapRoute, if we need a point on the route + Cells *cellsPtr; + TempLabelMap tempLabels; + ICNDocument *p_icnDocument; + QPointList m_cellPointList; +}; + +#endif diff --git a/src/core/Makefile.am b/src/core/Makefile.am new file mode 100644 index 0000000..145add8 --- /dev/null +++ b/src/core/Makefile.am @@ -0,0 +1,6 @@ +INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/drawparts -I$(top_srcdir)/src/electronics -I$(top_srcdir)/src/electronics/components -I$(top_srcdir)/src/electronics/simulation -I$(top_srcdir)/src/flowparts -I$(top_srcdir)/src/gui -I$(top_srcdir)/src/languages -I$(top_srcdir)/src/mechanics -I$(top_srcdir)/src/micro $(all_includes) +METASOURCES = AUTO +libcore_la_LDFLAGS = $(all_libraries) +noinst_LTLIBRARIES = libcore.la +kde_kcfg_DATA = ktechlab.kcfg +libcore_la_SOURCES = ktlconfig.kcfgc main.cpp diff --git a/src/core/ktechlab.kcfg b/src/core/ktechlab.kcfg new file mode 100644 index 0000000..de1c18f --- /dev/null +++ b/src/core/ktechlab.kcfg @@ -0,0 +1,290 @@ + + + + + + + 100 + + + + true + + + + true + + + + true + + + + true + + + + 50 + + + + #E8E8E8 + + + + + true + + + + false + + + + + + + 4 + + + + 14 + + + + 40 + + + + 14 + + + + 20 + + + + false + + + + + + + 2.5 + + + + 2 + + + + 5 + + + + 15 + + + + 0 + + + + + + + + + + + + + inhx32 + + + + + + + + + + Decimal + + + + + + + + + All + + + + true + + + + false + + + + + + + + + + + false + + + + false + + + + false + + + + false + + + + false + + + + + false + + + + false + + + + false + + + + false + + + + false + + + + false + + + + + false + + + + false + + + + false + + + + false + + + + false + + + + false + + + + false + + + + false + + + + false + + + + false + + + + false + + + + + false + + + + false + + + + false + + + + false + + + + false + + + + false + + + + false + + + + false + + + + false + + + + false + + + + + + + + + + + + picp + + + + + + + diff --git a/src/core/ktlconfig.kcfgc b/src/core/ktlconfig.kcfgc new file mode 100644 index 0000000..f056eb6 --- /dev/null +++ b/src/core/ktlconfig.kcfgc @@ -0,0 +1,3 @@ +File=ktechlab.kcfg +ClassName=KTLConfig +Singleton=true diff --git a/src/core/main.cpp b/src/core/main.cpp new file mode 100644 index 0000000..0c43a35 --- /dev/null +++ b/src/core/main.cpp @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "ktechlab.h" + +#include +#include +#include +#include +#include +#include + +static const char description[] = + I18N_NOOP("An IDE for microcontrollers and electronics"); + +static const char version[] = "0.3"; + +static KCmdLineOptions options[] = +{ + { "+[URL]", I18N_NOOP( "Document to open." ), 0 }, + KCmdLineLastOption +}; + + +int main(int argc, char **argv) +{ + KAboutData about("ktechlab", I18N_NOOP("KTechlab"), version, description, + KAboutData::License_GPL, "(C) 2003-2005, The KTechlab developers", "", "http://ktechlab.org", "ktechlab-devel@lists.sourceforge.net" ); + about.addAuthor( "David Saxton", 0, "david@bluehaze.org" ); + about.addAuthor( "Daniel Clarke", 0, "daniel.jc@gmail.com" ); + about.addCredit( "Couriousous", "JK flip-flop, asyncronous preset/reset in the D flip-flop." ); + about.addCredit( "John Myers", "Rotary Switch" ); + about.addCredit( "Ali Akcaagac", "Glib friendliness." ); + about.addCredit( "David Leggett", "Website hosting and feedback during early development." ); + KCmdLineArgs::init(argc, argv, &about); + KCmdLineArgs::addCmdLineOptions(options); + KApplication app; + + // register ourselves as a dcop client + app.dcopClient()->registerAs(app.name(), false); + + KTechlab *ktechlab = new KTechlab(); + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + for ( int i=0; i < args->count(); ++i ) + ktechlab->load( args->url(i) ); + + ktechlab->show(); + args->clear(); // Free up some memory + return app.exec(); +} diff --git a/src/debugmanager.cpp b/src/debugmanager.cpp new file mode 100644 index 0000000..425232c --- /dev/null +++ b/src/debugmanager.cpp @@ -0,0 +1,89 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "config.h" +#ifndef NO_GPSIM + +#include "debugmanager.h" +#include "docmanager.h" +#include "gpsimprocessor.h" +#include "textdocument.h" + +#include +#include + + +//BEGIN class DebugManager +DebugManager * DebugManager::m_pSelf = 0l; +static KStaticDeleter staticDebugManagerDeleter; + +DebugManager * DebugManager::self() +{ + if (!m_pSelf) + staticDebugManagerDeleter.setObject( m_pSelf, new DebugManager ); + return m_pSelf; +} + + +DebugManager::DebugManager() + : QObject() +{ +} + + +DebugManager::~DebugManager() +{ +} + + +void DebugManager::registerGpsim( GpsimProcessor * gpsim ) +{ + if (!gpsim) + return; + + m_processors << gpsim; + + const QStringList files = gpsim->sourceFileList(); + QStringList::const_iterator end = files.end(); + for ( QStringList::const_iterator it = files.begin(); it != end; ++it ) + { + if ( TextDocument * doc = dynamic_cast(DocManager::self()->findDocument(*it)) ) + { + if ( !doc->debuggerIsRunning() ) + doc->setDebugger( gpsim->currentDebugger(), false ); + } + } +} + + +void DebugManager::urlOpened( TextDocument * td ) +{ + if ( td->debuggerIsRunning() ) + return; + + m_processors.remove( (GpsimProcessor*)0l ); + GpsimProcessorList::iterator end = m_processors.end(); + for ( GpsimProcessorList::iterator it = m_processors.begin(); it != end; ++it ) + { + if ( !(*it)->sourceFileList().contains( td->url().path() ) ) + continue; + + (*it)->setDebugMode( (td->guessedCodeType() == TextDocument::ct_asm) ? GpsimDebugger::AsmDebugger : GpsimDebugger::HLLDebugger ); + + td->setDebugger( (*it)->currentDebugger(), false ); + return; + } +} +//END class DebugManager + + +#include "debugmanager.moc" + +#endif diff --git a/src/debugmanager.h b/src/debugmanager.h new file mode 100644 index 0000000..2d48eac --- /dev/null +++ b/src/debugmanager.h @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "config.h" +#ifndef NO_GPSIM + +#ifndef DEBUGMANAGER_H +#define DEBUGMANAGER_H + +#include +#include +#include + +class GpsimProcessor; +class TextDocument; + +typedef QValueList< QGuardedPtr > GpsimProcessorList; + +/** +@author David Saxton +*/ +class DebugManager : public QObject +{ + Q_OBJECT + public: + static DebugManager * self(); + ~DebugManager(); + + void registerGpsim( GpsimProcessor * gpsim ); + /** + * Called from TextDocument when it opens a URL so that it can be + * connected up to any processors that refer to its url. + */ + void urlOpened( TextDocument * td ); + + protected: + GpsimProcessorList m_processors; + + private: + DebugManager(); + static DebugManager * m_pSelf; + +}; + +#endif + +#endif diff --git a/src/docmanager.cpp b/src/docmanager.cpp new file mode 100644 index 0000000..bf49985 --- /dev/null +++ b/src/docmanager.cpp @@ -0,0 +1,500 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "circuitdocument.h" +#include "docmanager.h" +#include "docmanageriface.h" +#include "flowcodedocument.h" +#include "iteminterface.h" +#include "itemselector.h" +#include "ktechlab.h" +#include "core/ktlconfig.h" +#include "mechanicsdocument.h" +#include "textdocument.h" +#include "textview.h" +#include "viewcontainer.h" + +#include +#include +#include +#include + +#include + +DocManager * DocManager::m_pSelf = 0l; + +DocManager * DocManager::self( KTechlab * ktechlab ) +{ + if ( !m_pSelf ) + { + assert(ktechlab); + m_pSelf = new DocManager(ktechlab); + } + return m_pSelf; +} + + +DocManager::DocManager( KTechlab * ktechlab ) + : QObject( ktechlab ), + p_ktechlab(ktechlab) +{ + p_focusedView = 0l; + m_countCircuit = 0; + m_countFlowCode = 0; + m_countMechanics = 0; + m_countOther = 0; + p_connectedDocument = 0l; + m_nextDocumentID = 1; + m_pIface = new DocManagerIface(this); +} + + +DocManager::~DocManager() +{ +} + + +bool DocManager::closeAll() +{ + const DocumentList::iterator end = m_documentList.end(); + while ( !m_documentList.isEmpty() ) + { + Document *document = m_documentList.first(); + if ( document->fileClose() ) + { + m_documentList.remove(document); + removeDocumentAssociations(document); + } + else + return false; + } + return true; +} + + +void DocManager::gotoTextLine( const KURL &url, int line ) +{ + TextDocument * doc = dynamic_cast( openURL(url) ); + if (!doc) + return; + + doc->textView()->gotoLine(line); +} + + +Document* DocManager::openURL( const KURL &url, ViewArea *viewArea ) +{ + if ( url.isEmpty() ) + return 0l; + + if ( url.isLocalFile() ) + { + QFile file(url.path()); + if ( file.open(IO_ReadOnly) == false ) + { + KMessageBox::sorry( 0l, i18n("Could not open '%1'").arg( url.prettyURL() ) ); + return 0l; + } + file.close(); + } + + // If the document is already open, and a specific view area hasn't been + // specified, then just return that document - otherwise, create a new + // view in the viewarea + Document *document = findDocument(url); + if ( document ) + { + if ( viewArea ) + createNewView( document, viewArea ); + else + giveDocumentFocus( document, viewArea ); + return document; + } + + QString fileName = url.fileName(); + QString extension = fileName.right( fileName.length() - fileName.findRev('.') ); + + if ( extension == ".circuit" ) + return openCircuitFile( url, viewArea ); + + else if ( extension == ".flowcode" ) + return openFlowCodeFile( url, viewArea ); + + else if ( extension == ".mechanics" ) + return openMechanicsFile( url, viewArea ); + + else + return openTextFile( url, viewArea ); +} + + +Document *DocManager::getFocusedDocument() const +{ + Document * doc = p_focusedView ? p_focusedView->document() : 0l; + return (doc && !doc->isDeleted()) ? doc : 0l; +} + + +void DocManager::giveDocumentFocus( Document * toFocus, ViewArea * viewAreaForNew ) +{ + if ( !toFocus ) + return; + + if ( View * activeView = toFocus->activeView() ) + { + p_ktechlab->tabWidget()->showPage( activeView->viewContainer() ); + activeView->setFocused(); + activeView->viewContainer()->setFocused(); + } + else if ( viewAreaForNew ) + createNewView( toFocus, viewAreaForNew ); +} + + +QString DocManager::untitledName( int type ) +{ + QString name; + switch(type) + { + case Document::dt_circuit: + { + if ( m_countCircuit>1 ) + name = i18n("Untitled (Circuit %1)").arg(QString::number(m_countCircuit)); + else + name = i18n("Untitled (Circuit)"); + m_countCircuit++; + break; + } + case Document::dt_flowcode: + { + if ( m_countFlowCode>1 ) + name = i18n("Untitled (FlowCode %1)").arg(QString::number(m_countFlowCode)); + else + name = i18n("Untitled (FlowCode)"); + m_countFlowCode++; + break; + } + case Document::dt_mechanics: + { + if ( m_countMechanics>1 ) + name = i18n("Untitled (Mechanics %1)").arg(QString::number(m_countMechanics)); + else + name = i18n("Untitled (Mechanics)"); + m_countMechanics++; + break; + } + default: + { + if ( m_countOther>1 ) + name = i18n("Untitled (%1)").arg(QString::number(m_countOther)); + else + name = i18n("Untitled"); + m_countOther++; + break; + } + } + return name; +} + + +Document *DocManager::findDocument( const KURL &url ) const +{ + // First, look in the associated documents + if ( m_associatedDocuments.contains(url) ) + return m_associatedDocuments[url]; + + // Not found, so look in the known documents + const DocumentList::const_iterator end = m_documentList.end(); + for ( DocumentList::const_iterator it = m_documentList.begin(); it != end; ++it ) + { + if ( (*it)->url() == url ) + return *it; + } + + return 0l; +} + + +void DocManager::associateDocument( const KURL &url, Document *document ) +{ + if (!document) + return; + + m_associatedDocuments[url] = document; +} + + +void DocManager::removeDocumentAssociations( Document *document ) +{ + bool doneErase; + do + { + doneErase = false; + const URLDocumentMap::iterator end = m_associatedDocuments.end(); + for ( URLDocumentMap::iterator it = m_associatedDocuments.begin(); it != end; ++it ) + { + if ( it.data() == document ) + { + doneErase = true; + m_associatedDocuments.erase(it); + break; + } + } + } + while (doneErase); +} + + +void DocManager::handleNewDocument( Document *document, ViewArea *viewArea ) +{ + if ( !document || m_documentList.contains(document) ) + return; + + m_documentList.append(document); + document->setDCOPID(m_nextDocumentID++); + + connect( document, SIGNAL(modifiedStateChanged()), p_ktechlab, SLOT(slotDocModifiedChanged()) ); + connect( document, SIGNAL(fileNameChanged(const KURL&)), p_ktechlab, SLOT(slotDocModifiedChanged()) ); + connect( document, SIGNAL(fileNameChanged(const KURL&)), p_ktechlab, SLOT(addRecentFile(const KURL&)) ); + connect( document, SIGNAL(destroyed(QObject* )), this, SLOT(documentDestroyed(QObject* )) ); + connect( document, SIGNAL(viewFocused(View* )), this, SLOT(slotViewFocused(View* )) ); + connect( document, SIGNAL(viewUnfocused()), this, SLOT(slotViewUnfocused()) ); + + createNewView( document, viewArea ); +} + + +View *DocManager::createNewView( Document *document, ViewArea *viewArea ) +{ + if (!document) + return 0l; + + View *view = 0l; + + if (viewArea) + view = document->createView( viewArea->viewContainer(), viewArea->id() ); + + else + { + ViewContainer *viewContainer = new ViewContainer( document->caption(), p_ktechlab ); + view = document->createView( viewContainer, 0 ); + p_ktechlab->addWindow(viewContainer); + } + + view->setFocused(); + return view; +} + + +void DocManager::documentDestroyed( QObject *obj ) +{ + Document *doc = static_cast(obj); + m_documentList.remove(doc); + removeDocumentAssociations(doc); + disableContextActions(); +} + + +void DocManager::slotViewFocused( View *view ) +{ + ViewContainer * vc = static_cast(p_ktechlab->tabWidget()->currentPage()); + if (!vc) + view = 0l; + + if (!view) + return; + + // This function can get called with a view that is not in the current view + // container (such as when the user right clicks and then the popup is + // destroyed - not too sure why, but this is the easiest way to fix it). + if ( view->viewContainer() != vc ) + view = vc->activeView(); + + if ( !view || (View*)p_focusedView == view ) + return; + + if (p_focusedView) + slotViewUnfocused(); + + p_focusedView = view; + + if ( TextView * textView = dynamic_cast((View*)p_focusedView) ) + p_ktechlab->factory()->addClient( textView->kateView() ); + else + p_ktechlab->factory()->addClient( p_focusedView ); + + Document *document = view->document(); + + connect( document, SIGNAL(undoRedoStateChanged()), p_ktechlab, SLOT(slotDocUndoRedoChanged()) ); + p_connectedDocument = document; + + if ( document->type() == Document::dt_circuit || + document->type() == Document::dt_flowcode || + document->type() == Document::dt_mechanics ) + { + ItemDocument *cvb = static_cast(view->document()); + ItemInterface::self()->slotItemDocumentChanged(cvb); + } + + p_ktechlab->slotDocUndoRedoChanged(); + p_ktechlab->slotDocModifiedChanged(); + p_ktechlab->requestUpdateCaptions(); +} + + +void DocManager::slotViewUnfocused() +{ + p_ktechlab->removeGUIClients(); + disableContextActions(); + + if (!p_focusedView) + return; + + if (p_connectedDocument) + { + disconnect( p_connectedDocument, SIGNAL(undoRedoStateChanged()), p_ktechlab, SLOT(slotDocUndoRedoChanged()) ); + p_connectedDocument = 0l; + } + + ItemInterface::self()->slotItemDocumentChanged(0l); + p_focusedView = 0l; + +// p_ktechlab->setCaption( 0 ); + p_ktechlab->requestUpdateCaptions(); +} + + +void DocManager::disableContextActions() +{ + p_ktechlab->action("file_save")->setEnabled(false); + p_ktechlab->action("file_save_as")->setEnabled(false); + p_ktechlab->action("file_close")->setEnabled(false); + p_ktechlab->action("file_print")->setEnabled(false); + p_ktechlab->action("edit_undo")->setEnabled(false); + p_ktechlab->action("edit_redo")->setEnabled(false); + p_ktechlab->action("edit_cut")->setEnabled(false); + p_ktechlab->action("edit_copy")->setEnabled(false); + p_ktechlab->action("edit_paste")->setEnabled(false); + p_ktechlab->action("view_split_leftright")->setEnabled(false); + p_ktechlab->action("view_split_topbottom")->setEnabled(false); +} + + +TextDocument *DocManager::createTextDocument() +{ + TextDocument *document = TextDocument::constructTextDocument( untitledName(Document::dt_text), p_ktechlab ); + handleNewDocument(document); + return document; +} + + +CircuitDocument *DocManager::createCircuitDocument() +{ + CircuitDocument *document = new CircuitDocument( untitledName(Document::dt_circuit), p_ktechlab ); + handleNewDocument(document); + if ( KTLConfig::raiseItemSelectors() ) + p_ktechlab->showToolView( p_ktechlab->toolView( ComponentSelector::toolViewIdentifier() ) ); + return document; +} + + +FlowCodeDocument *DocManager::createFlowCodeDocument() +{ + FlowCodeDocument *document = new FlowCodeDocument( untitledName(Document::dt_flowcode), p_ktechlab ); + handleNewDocument(document); + if ( KTLConfig::raiseItemSelectors() ) + p_ktechlab->showToolView( p_ktechlab->toolView( FlowPartSelector::toolViewIdentifier() ) ); + return document; +} + + +MechanicsDocument *DocManager::createMechanicsDocument() +{ + MechanicsDocument *document = new MechanicsDocument( untitledName(Document::dt_mechanics), p_ktechlab ); + handleNewDocument(document); + if ( KTLConfig::raiseItemSelectors() ) + p_ktechlab->showToolView( p_ktechlab->toolView( MechanicsSelector::toolViewIdentifier() ) ); + return document; +} + + +CircuitDocument *DocManager::openCircuitFile( const KURL &url, ViewArea *viewArea ) +{ + CircuitDocument *document = new CircuitDocument( url.fileName().remove(url.directory()), p_ktechlab ); + + if ( !document->openURL(url) ) + { + KMessageBox::sorry( 0l, i18n("Could not open Circuit file \"%1\"").arg(url.prettyURL()) ); + document->deleteLater(); + return 0l; + } + + handleNewDocument( document, viewArea ); + emit fileOpened(url); + return document; +} + + +FlowCodeDocument *DocManager::openFlowCodeFile( const KURL &url, ViewArea *viewArea ) +{ + FlowCodeDocument *document = new FlowCodeDocument( url.fileName().remove(url.directory()), p_ktechlab ); + + if ( !document->openURL(url) ) + { + KMessageBox::sorry( 0l, i18n("Could not open FlowCode file \"%1\"").arg(url.prettyURL()) ); + document->deleteLater(); + return 0l; + } + + handleNewDocument( document, viewArea ); + emit fileOpened(url); + return document; +} + + +MechanicsDocument *DocManager::openMechanicsFile( const KURL &url, ViewArea *viewArea ) +{ + MechanicsDocument *document = new MechanicsDocument( url.fileName().remove(url.directory()), p_ktechlab ); + + if ( !document->openURL(url) ) + { + KMessageBox::sorry( 0l, i18n("Could not open Mechanics file \"%1\"").arg(url.prettyURL()) ); + document->deleteLater(); + return 0l; + } + + handleNewDocument( document, viewArea ); + emit fileOpened(url); + return document; + +} + + +TextDocument *DocManager::openTextFile( const KURL &url, ViewArea *viewArea ) +{ + TextDocument *document = TextDocument::constructTextDocument( url.fileName().remove(url.directory()), p_ktechlab ); + + if (!document) + return 0l; + + if ( !document->openURL(url) ) + { + KMessageBox::sorry( 0l, i18n("Could not open text file \"%1\"").arg(url.prettyURL()) ); + document->deleteLater(); + return 0l; + } + + handleNewDocument( document, viewArea ); + emit fileOpened(url); + return document; +} + + +#include "docmanager.moc" diff --git a/src/docmanager.h b/src/docmanager.h new file mode 100644 index 0000000..0ba300e --- /dev/null +++ b/src/docmanager.h @@ -0,0 +1,169 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef DOCMANAGER_H +#define DOCMANAGER_H + +#include +#include + +class CircuitDocument; +class DocManager; +class DocManagerIface; +class Document; +class FlowCodeDocument; +class KTechlab; +class MechanicsDocument; +class TextDocument; +class View; +class ViewArea; + +class KAction; + +typedef QValueList DocumentList; +typedef QMap< KURL, Document* > URLDocumentMap; +typedef QValueList KActionList; + +/** +@author David Saxton +*/ +class DocManager : public QObject +{ +Q_OBJECT +public: + static DocManager * self( KTechlab * ktechlab = 0l ); + ~DocManager(); + + /** + * Attempts to close all open documents, returning true if successful + */ + bool closeAll(); + /** + * Goes to the given line in the given text file (if the file exists) + */ + void gotoTextLine( const KURL &url, int line ); + /** + * Attempts to open the document at the given url. + * @param ViewArea if non-null, will open the new view into the ViewArea + */ + Document* openURL( const KURL &url, ViewArea *viewArea = 0l ); + /** + * Returns the focused View + */ + View *getFocusedView() const { return p_focusedView; } + /** + * Returns the focused Document (the document of the focused view) + */ + Document *getFocusedDocument() const; + /** + * Get a unique name, e.g. Untitled (circuit) - n" depending on the types + * of Document and whether it is the first one or not + * @param type Document::DocumentType - type of Document + */ + QString untitledName( int type ); + /** + * Checks to see if a document with the given URL is already open, and + * returns a pointer to that Document if so - otherwises returns null + * @see associateDocument + */ + Document *findDocument( const KURL &url ) const; + /** + * Associates a url with a pointer to a document. When findFile is called + * with the given url, it will return a pointer to this document if it still + * exists. + * @see findDocument + */ + void associateDocument( const KURL &url, Document *document ); + /** + * Gives the given document focus. If it has no open views, one will be + * created for it if viewAreaForNew is non-null + */ + void giveDocumentFocus( Document * toFocus, ViewArea * viewAreaForNew = 0l ); + void removeDocumentAssociations( Document *document ); + void disableContextActions(); + +public slots: + /** + * Creates an empty text document (with an open view) + */ + TextDocument *createTextDocument(); + /** + * Creates an empty circuit document (with an open view), and shows the + * component selector. + */ + CircuitDocument *createCircuitDocument(); + /** + * Creates an empty flowcode document (with an open view), and shows the + * flowpart selector. + */ + FlowCodeDocument *createFlowCodeDocument(); + /** + * Creates an empty mechanics document (with an open view), and shows the + * mechanics selector. + */ + MechanicsDocument *createMechanicsDocument(); + +signals: + /** + * Emitted when a file is successfully opened + */ + void fileOpened( const KURL &url ); + +protected slots: + /** + * Does the appropriate enabling / disabling of actions, connections, etc + */ + void slotViewFocused( View *view ); + /** + * Does the appropriate enabling / disabling of actions, connections, etc + */ + void slotViewUnfocused(); + void documentDestroyed( QObject *obj ); + +protected: + /** + * This function should be called after creating a new document to add it + * to the appropriate lists and connect it up as appropriate + */ + void handleNewDocument( Document *document, ViewArea *viewArea = 0l ); + /** + * Takes the document, creates a new view and shoves it in a new + * ViewContainer + */ + View *createNewView( Document *document, ViewArea *viewArea = 0l ); + CircuitDocument *openCircuitFile( const KURL &url, ViewArea *viewArea = 0l ); + FlowCodeDocument *openFlowCodeFile( const KURL &url, ViewArea *viewArea = 0l ); + MechanicsDocument *openMechanicsFile( const KURL &url, ViewArea *viewArea = 0l ); + TextDocument *openTextFile( const KURL &url, ViewArea *viewArea = 0l ); + + DocumentList m_documentList; + URLDocumentMap m_associatedDocuments; + + // Keeps track of how many + // new files have been made + // for the purpose of making + // titles of the form Untitled (n) + int m_countCircuit; + int m_countFlowCode; + int m_countMechanics; + int m_countOther; + + KTechlab * const p_ktechlab; + QGuardedPtr p_focusedView; + QGuardedPtr p_connectedDocument; + DocManagerIface *m_pIface; + unsigned m_nextDocumentID; + +private: + DocManager( KTechlab *ktechlab ); + static DocManager * m_pSelf; +}; + +#endif diff --git a/src/docmanageriface.cpp b/src/docmanageriface.cpp new file mode 100644 index 0000000..2f19511 --- /dev/null +++ b/src/docmanageriface.cpp @@ -0,0 +1,69 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "docmanager.h" +#include "docmanageriface.h" +#include "document.h" + + +DocManagerIface::DocManagerIface( DocManager * docManager ) + : DCOPObject("DocumentManager") +{ + m_pDocManager = docManager; +} + + +DocManagerIface::~DocManagerIface() +{ +} + +bool DocManagerIface::closeAll( ) +{ + return m_pDocManager->closeAll(); +} + +DCOPRef DocManagerIface::openURL( const QString & url ) +{ + return docToRef( m_pDocManager->openURL(url) ); +} + +void DocManagerIface::gotoTextLine( const QString & url, int line ) +{ + m_pDocManager->gotoTextLine( url, line ); +} + +DCOPRef DocManagerIface::createTextDocument( ) +{ + return docToRef( (Document*)m_pDocManager->createTextDocument() ); +} + +DCOPRef DocManagerIface::createCircuitDocument( ) +{ + return docToRef( (Document*)m_pDocManager->createCircuitDocument() ); +} + +DCOPRef DocManagerIface::createFlowCodeDocument( ) +{ + return docToRef( (Document*)m_pDocManager->createFlowCodeDocument() ); +} + +DCOPRef DocManagerIface::createMechanicsDocument( ) +{ + return docToRef( (Document*)m_pDocManager->createMechanicsDocument() ); +} + +DCOPRef DocManagerIface::docToRef( Document * document ) +{ + if (document) + return DCOPRef(document->dcopObject()); + return DCOPRef(); +} + + diff --git a/src/docmanageriface.h b/src/docmanageriface.h new file mode 100644 index 0000000..f788dc2 --- /dev/null +++ b/src/docmanageriface.h @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef DOCMANAGERIFACE_H +#define DOCMANAGERIFACE_H + +#include +#include + +class DocManager; +class Document; + +/** +@author David Saxton +*/ +class DocManagerIface : public DCOPObject +{ + K_DCOP + + public: + DocManagerIface( DocManager * docManager ); + ~DocManagerIface(); + + k_dcop: + /** + * Attempt to close all documents, returning true if successful. + */ + bool closeAll(); + /** + * Attempt to open the given URL. + */ + DCOPRef openURL( const QString & url ); + /** + * Attempt to open the text file at the given url (if it isn't already + * open), and then go to that line in the text file. + */ + void gotoTextLine( const QString & url, int line ); + /** + * Creates a new Text document. + */ + DCOPRef createTextDocument(); + /** + * Creates a new Circuit document. + */ + DCOPRef createCircuitDocument(); + /** + * Creates a new FlowCode document. + */ + DCOPRef createFlowCodeDocument(); + /** + * Creates a new Mechanics document. + */ + DCOPRef createMechanicsDocument(); + + protected: + DCOPRef docToRef( Document * document ); + + DocManager * m_pDocManager; +}; + +#endif diff --git a/src/document.cpp b/src/document.cpp new file mode 100644 index 0000000..cc43f00 --- /dev/null +++ b/src/document.cpp @@ -0,0 +1,205 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "document.h" +#include "documentiface.h" +#include "ktechlab.h" +#include "projectmanager.h" +#include "view.h" +#include "viewcontainer.h" + +#include +#include +#include +#include + +Document::Document( const QString &caption, KTechlab *ktechlab, const char *name ) + : QObject( ktechlab, name ), + b_modified(false), + p_ktechlab(ktechlab), + p_activeView(0l), + m_caption(caption), + m_bAddToProjectOnSave(false), + m_pDocumentIface(0l), + m_dcopID(0), + m_nextViewID(0), + m_bDeleted(false) +{ + if (p_ktechlab) + connect( p_ktechlab, SIGNAL(configurationChanged()), this, SLOT(slotUpdateConfiguration()) ); +} + + +Document::~Document() +{ + m_bDeleted = true; + + ViewList viewsToDelete = m_viewList; + const ViewList::iterator end = viewsToDelete.end(); + for ( ViewList::iterator it = viewsToDelete.begin(); it != end; ++it ) + (*it)->deleteLater(); +} + + +void Document::handleNewView( View *view ) +{ + if ( !view || m_viewList.contains(view) ) + return; + + m_viewList.append(view); + view->setDCOPID(m_nextViewID++); + view->setCaption(m_caption); + connect( view, SIGNAL(destroyed(QObject* )), this, SLOT(slotViewDestroyed(QObject* )) ); + connect( view, SIGNAL(viewFocused(View* )), this, SLOT(slotViewFocused(View* )) ); + connect( view, SIGNAL(viewUnfocused()), this, SIGNAL(viewUnfocused()) ); + view->show(); + view->setFocused(); +} + + +void Document::slotViewDestroyed( QObject *obj ) +{ + View *view = static_cast(obj); + + m_viewList.remove(view); + + if ( p_activeView == (QGuardedPtr)view ) + { + p_activeView = 0l; + emit viewUnfocused(); + } + + if ( m_viewList.isEmpty() ) + deleteLater(); +} + + +void Document::slotViewFocused(View *view) +{ + if (!view) + return; + + p_activeView = view; + emit viewFocused(view); +} + + +void Document::setCaption( const QString &caption ) +{ + m_caption = caption; + const ViewList::iterator end = m_viewList.end(); + for ( ViewList::iterator it = m_viewList.begin(); it != end; ++it ) + (*it)->setCaption(caption); +} + + +bool Document::getURL( const QString &types ) +{ + KURL url = KFileDialog::getSaveURL( QString::null, types, p_ktechlab, i18n("Save Location")); + + if ( url.isEmpty() ) + return false; + + if ( QFile::exists( url.path() ) ) + { + int query = KMessageBox::warningYesNo( p_ktechlab, + i18n( "A file named \"%1\" already exists. Are you sure you want to overwrite it?" ).arg( url.fileName() ), + i18n( "Overwrite File?" ), + i18n( "Overwrite" ), + KStdGuiItem::cancel() ); + if ( query == KMessageBox::No ) + return false; + } + + setURL(url); + + return true; +} + + +bool Document::fileClose() +{ + if ( isModified() ) + { + // If the filename is empty then it must be an untitled file. + QString name = m_url.fileName().isEmpty() ? caption() : m_url.fileName(); + + if ( ViewContainer * viewContainer = (activeView() ? activeView()->viewContainer() : 0l) ) + p_ktechlab->tabWidget()->setCurrentPage( p_ktechlab->tabWidget()->indexOf(viewContainer) ); + + int choice = KMessageBox::warningYesNoCancel( p_ktechlab, + i18n("The document \'%1\' has been modified.\nDo you want to save it?").arg(name), + i18n("Save Document?"), + i18n("Save"), + i18n("Discard") ); + + if ( choice == KMessageBox::Cancel ) + return false; + if ( choice == KMessageBox::Yes ) + fileSave(); + } + + deleteLater(); + return true; +} + + +void Document::setModified( bool modified ) +{ + if ( b_modified == modified ) + return; + + b_modified = modified; + + if (!m_bDeleted) + emit modifiedStateChanged(); +} + + +void Document::setURL( const KURL &url ) +{ + if ( m_url == url ) + return; + + bool wasEmpty = m_url.isEmpty(); + m_url = url; + + if ( wasEmpty && m_bAddToProjectOnSave && ProjectManager::self()->currentProject() ) + ProjectManager::self()->currentProject()->addFile(m_url); + + emit fileNameChanged(url); + + if (p_ktechlab) + { + p_ktechlab->addRecentFile(url); + p_ktechlab->requestUpdateCaptions(); + } +} + +DCOPObject * Document::dcopObject( ) const +{ + return m_pDocumentIface; +} + +void Document::setDCOPID( unsigned id ) +{ + if ( m_dcopID == id ) + return; + + m_dcopID = id; + if ( m_pDocumentIface ) + { + QCString docID; + docID.setNum( dcopID() ); + m_pDocumentIface->setObjId( "Document#" + docID ); + } +} + +#include "document.moc" diff --git a/src/document.h b/src/document.h new file mode 100644 index 0000000..eb465ad --- /dev/null +++ b/src/document.h @@ -0,0 +1,243 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef DOCUMENT_H +#define DOCUMENT_H + +#include +#include + +class DCOPObject; +class Document; +class DocumentIface; +class KTechlab; +class View; +class ViewContainer; + +typedef QValueList > ViewList; + +/** +@author David Saxton +*/ +class Document : public QObject +{ +Q_OBJECT +public: + enum DocumentType + { + dt_none, // Used to denote document type not known / specified / etc, when appropriate + dt_flowcode, + dt_circuit, + dt_mechanics, + dt_text, + dt_pinMapEditor + }; + Document( const QString &caption, KTechlab *ktechlab, const char *name = 0 ); + virtual ~Document(); + /** + * If the user has created a new document from the new file dialog, and + * wants to add it to the project, then this must wait until this file is + * given a url. Set this to true to add the file to the active project when + * it is first saved. + */ + void setAddToProjectOnSave( bool add ) { m_bAddToProjectOnSave = add; } + /** + * Caption of document, e.g. "Untitled 2" + */ + QString caption() const { return m_caption; } + /** + * Set the caption of the document, to be displayed in the tab bar when + * active + */ + void setCaption( const QString &caption ); + /** + * Return the dcop object for this document + */ + DCOPObject * dcopObject() const; + /** + * Returns the dcop suffix for this document - a unique ID for the current + * app session. DCOP name will be "Document#dcopID()" + */ + unsigned dcopID() const { return m_dcopID; } + /** + * Sets the dcop suffix. The DCOP object for this document will be renamed. + * @see dcopID + */ + void setDCOPID( unsigned id ); + /** + * Returns the active view, which is the last view to be used to edit in + */ + View *activeView() const { return p_activeView; } + ViewList viewList() const { return m_viewList; } + /** + * Returns the type of document. + * @see Document::DocumentType + */ + DocumentType type() const { return m_type; } + /** + * Returns the number of open views. + */ + uint numberOfViews() const { return m_viewList.size(); } + /** + * Create a view that will display the document data. In all reimplemented + * functions, you must call handleNewView after creating the view, so that + * the appropriate slots, pointers, etc can all be initialised. + */ + virtual View *createView( ViewContainer *viewContainer, uint viewAreaId, const char *name = 0l ) = 0; + /** + * Returns the url of the file that the Document refers to + */ + const KURL& url() const { return m_url; } + /** + * Prompts the user for a url, with the given types for the filter. + * If user accepts, returns true, and set the url to the new url. + */ + bool getURL( const QString &types ); + /** + * Attempts to open a url, and returns true if succesful. + * You must reinherit this function. + */ + virtual bool openURL( const KURL &url ) = 0; + /** + * Sets the url of the file that this Document refers to + */ + void setURL( const KURL &url ); + /** + * Sets whether the file is modified or not. Will emit modifiedStateChanged + * if state changes. You must emit this signal if you reinherit this + */ + virtual void setModified( bool modified ); + /** + * Returns the modification state since last-save. + */ + virtual bool isModified() const { return b_modified; } + /** + * Returns true if undo is avilable. + */ + virtual bool isUndoAvailable() const { return false; } + /** + * Returns true if redo is avilable. + */ + virtual bool isRedoAvailable() const { return false; } + /** + * Saves the file to a new name. + */ + virtual void fileSaveAs() = 0; + /** + * Attempts to close the file without saving, prompting the user if the + * file has been modified. If succesful, calls QObject::deleteLater(), and + * returns true (otherwise returns false). + */ + virtual bool fileClose(); + /** + * Saves the file. + */ + virtual void fileSave() = 0; + /** + * Prints the file. + */ + virtual void print() {}; + /** + * Cuts whatever is selected. + */ + virtual void cut() {}; + /** + * Copies whatever is selected. + */ + virtual void copy() {}; + /** + * Attempts to paste whatever is in the clipboard. + */ + virtual void paste() {}; + /** + * Undo the last operation. You should reinherit this function. + */ + virtual void undo() {}; + /** + * Redo the undone last operation. You should reinherit this function. + */ + virtual void redo() {}; + /** + * Selects everything in the view. + */ + virtual void selectAll() {}; + + virtual void convertToMicrobe() {}; + virtual void convertToHex() {}; + virtual void convertToPIC() {}; + virtual void convertToAssembly() {}; + virtual void debugRun() {}; + virtual void debugInterrupt() {}; + virtual void debugStop() {}; + virtual void debugStep() {}; + KTechlab *ktechlab() const { return p_ktechlab; } + bool isDeleted() const { return m_bDeleted; } + +protected slots: + /** + * Called when the user changes the configuration. + */ + virtual void slotUpdateConfiguration() {}; + +#define protected public +signals: + /** + * Emitted when an operation has been performed that + * has caused the stack of available undo/redo operations to + * have changed + */ + void undoRedoStateChanged(); +#undef protected + +signals: + /** + * Emitted when the Document goes from modified to unmodified, + * or vice-versa + */ + void modifiedStateChanged(); + /** + * Emitted when the name of the file that the Document refers to + * is changed. + */ + void fileNameChanged( const KURL &url ); + + void viewFocused( View *view ); + void viewUnfocused(); + +private slots: + void slotViewDestroyed( QObject *obj ); + void slotViewFocused( View *view ); + +protected: + /** + * You must call this function after creating a new view + */ + virtual void handleNewView( View *view ); + + bool b_modified; + KTechlab *p_ktechlab; + QGuardedPtr p_activeView; + DocumentType m_type; + ViewList m_viewList; + QString m_caption; + bool m_bAddToProjectOnSave; + DocumentIface * m_pDocumentIface; + unsigned m_dcopID; + unsigned m_nextViewID; + + // Set to true by the document et subclasses destructors, used to avoid + // doing stuff that might lead to crash when being deleted. + bool m_bDeleted; + +private: + KURL m_url; +}; + +#endif diff --git a/src/documentiface.cpp b/src/documentiface.cpp new file mode 100644 index 0000000..dd7e0eb --- /dev/null +++ b/src/documentiface.cpp @@ -0,0 +1,445 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "circuitdocument.h" +#include "connector.h" +#include "cnitem.h" +#include "documentiface.h" +#include "flowcodedocument.h" +#include "itemlibrary.h" +#include "libraryitem.h" +#include "mechanicsdocument.h" +#include "textdocument.h" +#include "view.h" + + +//BEGIN class DocumentIface +DocumentIface::DocumentIface( Document * document ) + : DCOPObject("Document") +{ + m_pDocument = document; +} + + +DocumentIface::~DocumentIface() +{ +} + +void DocumentIface::selectAll( ) +{ + m_pDocument->selectAll(); +} + +void DocumentIface::redo( ) +{ + m_pDocument->redo(); +} + +void DocumentIface::undo( ) +{ + m_pDocument->undo(); +} + +void DocumentIface::paste( ) +{ + m_pDocument->paste(); +} + +void DocumentIface::copy( ) +{ + m_pDocument->copy(); +} + +void DocumentIface::cut( ) +{ + m_pDocument->cut(); +} + +void DocumentIface::print( ) +{ + m_pDocument->print(); +} + + +bool DocumentIface::close( ) +{ + return m_pDocument->fileClose(); +} + +void DocumentIface::saveAs( ) +{ + m_pDocument->fileSaveAs(); +} + +void DocumentIface::save( ) +{ + m_pDocument->fileSave(); +} + +bool DocumentIface::isRedoAvailable( ) +{ + return m_pDocument->isRedoAvailable(); +} + +bool DocumentIface::isUndoAvailable( ) +{ + return m_pDocument->isUndoAvailable(); +} + +bool DocumentIface::isModified( ) +{ + return m_pDocument->isModified(); +} + +bool DocumentIface::openURL( const QString & url ) +{ + return m_pDocument->openURL(url); +} + +QString DocumentIface::url( ) +{ + return m_pDocument->url().url(); +} + +uint DocumentIface::numberOfViews( ) +{ + return m_pDocument->numberOfViews(); +} + +DCOPRef DocumentIface::activeView( ) +{ + return viewToRef( m_pDocument->activeView() ); +} + +QString DocumentIface::caption( ) const +{ + return m_pDocument->caption(); +} + +DCOPRef DocumentIface::viewToRef( View * view ) +{ + return DCOPRef( view->dcopObject() ); +} +//END class DocumentIface + + + +//BEGIN class FlowCodeDocumentIface +FlowCodeDocumentIface::FlowCodeDocumentIface( FlowCodeDocument * document ) + : ICNDocumentIface(document) +{ + m_pFlowCodeDocument = document; +} + +void FlowCodeDocumentIface::setPicType( const QString & id ) +{ + m_pFlowCodeDocument->setPicType(id); +} + +void FlowCodeDocumentIface::convertToMicrobe() +{ + m_pFlowCodeDocument->convertToMicrobe(); +} + +void FlowCodeDocumentIface::convertToHex() +{ + m_pFlowCodeDocument->convertToHex(); +} + +void FlowCodeDocumentIface::convertToPIC() +{ + m_pFlowCodeDocument->convertToPIC(); +} + +void FlowCodeDocumentIface::convertToAssembly() +{ + m_pFlowCodeDocument->convertToAssembly(); +} +//END class FlowCodeDocumentIface + + + +//BEGIN class CircuitDocumentIface +CircuitDocumentIface::CircuitDocumentIface( CircuitDocument * document ) + : ICNDocumentIface(document) +{ + m_pCircuitDocument = document; +} + +void CircuitDocumentIface::setOrientation0( ) +{ + m_pCircuitDocument->setOrientation0(); +} + +void CircuitDocumentIface::setOrientation90( ) +{ + m_pCircuitDocument->setOrientation90(); +} + +void CircuitDocumentIface::setOrientation180( ) +{ + m_pCircuitDocument->setOrientation180(); +} + +void CircuitDocumentIface::setOrientation270( ) +{ + m_pCircuitDocument->setOrientation270(); +} + +void CircuitDocumentIface::rotateCounterClockwise( ) +{ + m_pCircuitDocument->rotateCounterClockwise(); +} + +void CircuitDocumentIface::rotateClockwise( ) +{ + m_pCircuitDocument->rotateClockwise(); +} + +void CircuitDocumentIface::flip( ) +{ + m_pCircuitDocument->itemFlip(); +} + +void CircuitDocumentIface::displayEquations( ) +{ + m_pCircuitDocument->displayEquations(); +} + +void CircuitDocumentIface::createSubcircuit( ) +{ + m_pCircuitDocument->createSubcircuit(); +} +//END class CircuitDocumentIface + + + +//BEGIN class ICNDocumentIface +ICNDocumentIface::ICNDocumentIface( ICNDocument * document ) + : ItemDocumentIface(document) +{ + m_pICNDocument = document; +} + +void ICNDocumentIface::exportToImage( ) +{ + m_pICNDocument->exportToImage(); +} + +QCStringList ICNDocumentIface::nodeIDs( const QString & id ) +{ + CNItem * item = m_pICNDocument->cnItemWithID(id); + + QCStringList ids; + if ( !item ) + return ids; + + const NodeMap nm = item->nodeMap(); + const NodeMap::const_iterator end = nm.end(); + for ( NodeMap::const_iterator it = nm.begin(); it != end; ++it ) + ids.append( it.key().ascii() ); + + return ids; +} + +QString ICNDocumentIface::makeConnection( const QString & item1, const QString & node1, const QString & item2, const QString & node2 ) +{ + CNItem * i1 = m_pICNDocument->cnItemWithID(item1); + CNItem * i2 = m_pICNDocument->cnItemWithID(item2); + + if ( !i1 || !i2 ) + return QString::null; + + Node * n1 = m_pICNDocument->nodeWithID( i1->nodeId(node1) ); + Node * n2 = m_pICNDocument->nodeWithID( i2->nodeId(node2) ); + + if ( !n1 || !n2 ) + return QString::null; + + Connector * connector = m_pICNDocument->createConnector( n1, n2 ); + return connector ? connector->id() : QString::null; +} + +void ICNDocumentIface::selectConnector( const QString & id ) +{ + m_pICNDocument->select( m_pICNDocument->connectorWithID(id) ); +} + +void ICNDocumentIface::unselectConnector( const QString & id ) +{ + m_pItemDocument->unselect( m_pICNDocument->connectorWithID(id) ); +} +//END class ICNDocumentIface + + + +//BEGIN class ItemDocumentIface +ItemDocumentIface::ItemDocumentIface( ItemDocument * document ) + : DocumentIface(document) +{ + m_pItemDocument = document; +} + +QCStringList ItemDocumentIface::validItemIDs( ) +{ + QCStringList validIDs; + + LibraryItemList * allItems = itemLibrary()->items(); + const LibraryItemList::iterator end = allItems->end(); + for ( LibraryItemList::iterator it = allItems->begin(); it != end; ++it ) + { + QString id = (*it)->activeID(); + if ( m_pItemDocument->isValidItem(id) ) + validIDs << id.utf8(); + } + return validIDs; +} + +QString ItemDocumentIface::addItem( const QString & id, int x, int y ) +{ + Item * item = m_pItemDocument->addItem( id, QPoint( x, y ), true ); + return item ? item->id() : QString::null; +} + +void ItemDocumentIface::selectItem( const QString & id ) +{ + m_pItemDocument->select( m_pItemDocument->itemWithID(id) ); +} + +void ItemDocumentIface::unselectItem( const QString & id ) +{ + m_pItemDocument->unselect( m_pItemDocument->itemWithID(id) ); +} + +void ItemDocumentIface::deleteSelection( ) +{ + m_pItemDocument->deleteSelection(); +} + +void ItemDocumentIface::clearHistory( ) +{ + m_pItemDocument->clearHistory(); +} + +void ItemDocumentIface::unselectAll( ) +{ + m_pItemDocument->unselectAll(); +} + +void ItemDocumentIface::alignHorizontally( ) +{ + m_pItemDocument->alignHorizontally(); +} + +void ItemDocumentIface::alignVertically( ) +{ + m_pItemDocument->alignVertically(); +} + +void ItemDocumentIface::distributeHorizontally( ) +{ + m_pItemDocument->distributeHorizontally(); +} + +void ItemDocumentIface::distributeVertically( ) +{ + m_pItemDocument->distributeVertically(); +} +//END class ItemDocumentIface + + + +//BEGIN class TextDocumentIface +TextDocumentIface::TextDocumentIface( TextDocument * document ) + : DocumentIface(document) +{ + m_pTextDocument = document; +} + +void TextDocumentIface::debugStepOver( ) +{ + m_pTextDocument->debugStepOver(); +} + +void TextDocumentIface::debugStepOut( ) +{ + m_pTextDocument->debugStepOut(); +} + +void TextDocumentIface::debugStep( ) +{ + m_pTextDocument->debugStep(); +} + +void TextDocumentIface::debugStop( ) +{ + m_pTextDocument->debugStop(); +} + +void TextDocumentIface::debugInterrupt( ) +{ + m_pTextDocument->debugInterrupt(); +} + +void TextDocumentIface::debugRun( ) +{ + m_pTextDocument->debugRun(); +} + +bool TextDocumentIface::isDebugging( ) +{ +#ifndef NO_GPSIM + return m_pTextDocument->debuggerIsRunning(); +#else + return false; +#endif +} + +void TextDocumentIface::clearBookmarks( ) +{ + m_pTextDocument->clearBookmarks(); +} + +void TextDocumentIface::convertToAssembly( ) +{ + m_pTextDocument->convertToAssembly(); +} + +void TextDocumentIface::convertToPIC( ) +{ + m_pTextDocument->convertToPIC(); +} + +void TextDocumentIface::convertToHex( ) +{ + m_pTextDocument->convertToHex(); +} + +void TextDocumentIface::convertToMicrobe( ) +{ + m_pTextDocument->convertToMicrobe(); +} + +void TextDocumentIface::formatAssembly( ) +{ + m_pTextDocument->formatAssembly(); +} +//END class TextDocumentIface + + + +//BEGIN class MechanicsDocumentIface +MechanicsDocumentIface::MechanicsDocumentIface( MechanicsDocument * document ) + : ItemDocumentIface(document) +{ + m_pMechanicsDocument = document; +} +//END class MechanicsDocumentIface + diff --git a/src/documentiface.h b/src/documentiface.h new file mode 100644 index 0000000..5f32cfe --- /dev/null +++ b/src/documentiface.h @@ -0,0 +1,193 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef DOCUMENTIFACE_H +#define DOCUMENTIFACE_H + +#include "config.h" + +#include +#include + +class CircuitDocument; +class Document; +class FlowCodeDocument; +class ICNDocument; +class ItemDocument; +class MechanicsDocument; +class TextDocument; +class View; + +/** +@author David Saxton +*/ +class DocumentIface : public DCOPObject +{ + K_DCOP + + public: + DocumentIface( Document * document ); + virtual ~DocumentIface(); + + k_dcop: + QString caption() const; + DCOPRef activeView(); + uint numberOfViews(); +// View *createView( ViewContainer *viewContainer, uint viewAreaId, const char *name = 0l ); + QString url(); + bool openURL( const QString & url ); + bool isModified(); + bool isUndoAvailable(); + bool isRedoAvailable(); + void save(); + void saveAs(); + bool close(); + void print(); + void cut(); + void copy(); + void paste(); + void undo(); + void redo(); + void selectAll(); + + protected: + DCOPRef viewToRef( View * view ); + + Document * m_pDocument; +}; + +class TextDocumentIface : public DocumentIface +{ + K_DCOP + + public: + TextDocumentIface( TextDocument * document ); + + k_dcop: + void formatAssembly(); + void convertToMicrobe(); + void convertToHex(); + void convertToPIC(); + void convertToAssembly(); + void clearBookmarks(); + bool isDebugging(); + void debugRun(); + void debugInterrupt(); + void debugStop(); + void debugStep(); + void debugStepOver(); + void debugStepOut(); + + protected: + TextDocument * m_pTextDocument; +}; + +class ItemDocumentIface : public DocumentIface +{ + K_DCOP + + public: + ItemDocumentIface( ItemDocument * document ); + + k_dcop: + QCStringList validItemIDs(); + /** + * Create an item with the given id (e.g. "ec/resistor") at the given + * position. + * @return name of item (assigned to it by KTechlab) + */ + QString addItem( const QString & id, int x, int y ); + void selectItem( const QString & id ); + void unselectItem( const QString & id ); + void clearHistory(); + void unselectAll(); + void alignHorizontally(); + void alignVertically(); + void distributeHorizontally(); + void distributeVertically(); + void deleteSelection(); + + protected: + ItemDocument * m_pItemDocument; +}; + +class MechanicsDocumentIface : public ItemDocumentIface +{ + K_DCOP + + public: + MechanicsDocumentIface( MechanicsDocument * document ); + + protected: + MechanicsDocument * m_pMechanicsDocument; +}; + +class ICNDocumentIface : public ItemDocumentIface +{ + K_DCOP + + public: + ICNDocumentIface( ICNDocument * document ); + + k_dcop: + void exportToImage(); + QCStringList nodeIDs( const QString & id ); + /** + * Makes a connection from node1 on item1 to node2 on item2 + */ + QString makeConnection( const QString & item1, const QString & node1, const QString & item2, const QString & node2 ); + void selectConnector( const QString & id ); + void unselectConnector( const QString & id ); + + protected: + ICNDocument * m_pICNDocument; +}; + +class CircuitDocumentIface : public ICNDocumentIface +{ + K_DCOP + + public: + CircuitDocumentIface( CircuitDocument * document ); + + k_dcop: + void setOrientation0(); + void setOrientation90(); + void setOrientation180(); + void setOrientation270(); + void rotateCounterClockwise(); + void rotateClockwise(); + void flip(); + void displayEquations(); + void createSubcircuit(); + + protected: + CircuitDocument * m_pCircuitDocument; +}; + +class FlowCodeDocumentIface : public ICNDocumentIface +{ + K_DCOP + + public: + FlowCodeDocumentIface( FlowCodeDocument * document ); + void convertToMicrobe(); + void convertToHex(); + void convertToPIC(); + void convertToAssembly(); + + k_dcop: + void setPicType( const QString & id ); + + protected: + FlowCodeDocument * m_pFlowCodeDocument; +}; + +#endif diff --git a/src/drawparts/Makefile.am b/src/drawparts/Makefile.am new file mode 100644 index 0000000..f3c1c25 --- /dev/null +++ b/src/drawparts/Makefile.am @@ -0,0 +1,6 @@ +INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/electronics -I$(top_srcdir)/src/electronics/components -I$(top_srcdir)/src/electronics/simulation -I$(top_srcdir)/src/flowparts -I$(top_srcdir)/src/gui -I$(top_srcdir)/src/languages -I$(top_srcdir)/src/mechanics -I$(top_srcdir)/src/micro $(all_includes) +METASOURCES = AUTO +noinst_LTLIBRARIES = libdrawparts.la +libdrawparts_la_SOURCES = drawpart.cpp dpline.cpp solidshape.cpp dptext.cpp +noinst_HEADERS = drawpart.h dpline.h solidshape.h dptext.h + diff --git a/src/drawparts/dpline.cpp b/src/drawparts/dpline.cpp new file mode 100644 index 0000000..59fa789 --- /dev/null +++ b/src/drawparts/dpline.cpp @@ -0,0 +1,227 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "dpline.h" +#include "libraryitem.h" +#include "resizeoverlay.h" +#include "variant.h" + +#include +#include +#include +#include + + +//BEGIN class DPLine +Item* DPLine::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new DPLine( itemDocument, newItem, id ); +} + +LibraryItem* DPLine::libraryItem() +{ + return new LibraryItem( + QString("dp/line"), + i18n("Line"), + i18n("Other"), + KGlobal::iconLoader()->loadIcon( "text", KIcon::Small ), + LibraryItem::lit_drawpart, + DPLine::construct ); +} + +DPLine::DPLine( ItemDocument *itemDocument, bool newItem, const char *id ) + : DrawPart( itemDocument, newItem, id ? id : "line" ) +{ + m_pLineOverlay = new LineOverlay(this); + m_name = i18n("Line"); + m_desc = i18n("Select the line to position the end points"); + + createProperty( "line-color", Variant::Type::Color ); + property("line-color")->setCaption( i18n("Line Color") ); + property("line-color")->setValue(Qt::black); + + createProperty( "line-width", Variant::Type::Int ); + property("line-width")->setCaption( i18n("Line Width") ); + property("line-width")->setMinValue(1); + property("line-width")->setMaxValue(1000); + property("line-width")->setValue(1); + + createProperty( "line-style", Variant::Type::PenStyle ); + property("line-style")->setCaption( i18n("Line Style") ); + property("line-style")->setAdvanced(true); + setDataPenStyle( "line-style", Qt::SolidLine ); + + createProperty( "cap-style", Variant::Type::PenCapStyle ); + property("cap-style")->setCaption( i18n("Cap Style") ); + property("cap-style")->setAdvanced(true); + setDataPenCapStyle( "cap-style", Qt::FlatCap ); +} + +DPLine::~DPLine() +{ +} + +void DPLine::setSelected( bool yes ) +{ + if ( yes == isSelected() ) + return; + + DrawPart::setSelected(yes); + m_pLineOverlay->showResizeHandles(yes); +} + + +void DPLine::dataChanged() +{ + setPen( QPen( dataColor("line-color"), + unsigned( dataInt("line-width") ), + getDataPenStyle("line-style"), + getDataPenCapStyle("cap-style"), + Qt::MiterJoin ) ); + + postResize(); // in case the pen width has changed + update(); +} + + +void DPLine::postResize() +{ + int x1 = offsetX(); + int y1 = offsetY(); + int x2 = x1+width(); + int y2 = y1+height(); + + QPointArray p(4); + int pw = pen().width(); + int dx = QABS(x1-x2); + int dy = QABS(y1-y2); + pw = pw*4/3+2; // approx pw*sqrt(2) + int px = x1 dy ? (dx*2/dy <= 2) : (dy*2/dx <= 2)) ) { + // steep + if ( px == py ) { + p[0] = QPoint(x1 ,y1+py); + p[1] = QPoint(x2-px,y2 ); + p[2] = QPoint(x2 ,y2-py); + p[3] = QPoint(x1+px,y1 ); + } else { + p[0] = QPoint(x1+px,y1 ); + p[1] = QPoint(x2 ,y2-py); + p[2] = QPoint(x2-px,y2 ); + p[3] = QPoint(x1 ,y1+py); + } + } else if ( dx > dy ) { + // horizontal + p[0] = QPoint(x1+px,y1+py); + p[1] = QPoint(x2-px,y2+py); + p[2] = QPoint(x2-px,y2-py); + p[3] = QPoint(x1+px,y1-py); + } else { + // vertical + p[0] = QPoint(x1+px,y1+py); + p[1] = QPoint(x2+px,y2-py); + p[2] = QPoint(x2-px,y2-py); + p[3] = QPoint(x1-px,y1+py); + } + setItemPoints( p, false ); +} + + +void DPLine::drawShape( QPainter & p ) +{ + int x1 = int(x()+offsetX()); + int y1 = int(y()+offsetY()); + int x2 = x1+width(); + int y2 = y1+height(); + + p.drawLine( x1, y1, x2, y2 ); +} +//END class DPLine + + +//BEGIN class DPArrow +Item* DPArrow::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new DPArrow( itemDocument, newItem, id ); +} + +LibraryItem* DPArrow::libraryItem() +{ + return new LibraryItem( + QString("dp/arrow"), + i18n("Arrow"), + i18n("Other"), + KGlobal::iconLoader()->loadIcon( "text", KIcon::Small ), + LibraryItem::lit_drawpart, + DPArrow::construct ); +} + +DPArrow::DPArrow( ItemDocument *itemDocument, bool newItem, const char *id ) + : DPLine( itemDocument, newItem, id ? id : "arrow" ) +{ + m_name = i18n("Arrow"); + + // We don't want to use the square cap style as it screws up drawing our arrow head + QStringList allowed = property("cap-style")->allowed(); + allowed.remove( DrawPart::penCapStyleToName( Qt::SquareCap ) ); + property("cap-style")->setAllowed(allowed); +} + +DPArrow::~DPArrow() +{ +} + + +void DPArrow::drawShape( QPainter & p ) +{ + int x1 = int(x()+offsetX()); + int y1 = int(y()+offsetY()); + int x2 = x1+width(); + int y2 = y1+height(); + + p.drawLine( x1, y1, x2, y2 ); + + double dx = x2-x1; + double dy = y2-y1; + + if ( dx == 0. && dy == 0. ) + return; + + double pi = 3.14159265358979323846264; + double arrow_angle = ( dx == 0 ? (dy>0?(pi/2.):(-pi/2.)) : std::atan(dy/dx) ); + if ( dx < 0 ) + arrow_angle += pi; + + double head_angle = 0.6; // Angle of arrowhead + double head_length = 10.; + + // Position of arrowhead + int x3 = int( x2 + head_length*std::cos( pi + arrow_angle - head_angle ) ); + int y3 = int( y2 + head_length*std::sin( pi + arrow_angle - head_angle ) ); + int x4 = int( x2 + head_length*std::cos( pi + arrow_angle + head_angle ) ); + int y4 = int( y2 + head_length*std::sin( pi + arrow_angle + head_angle ) ); + + // Draw arrowhead + QPen pen = p.pen(); + pen.setCapStyle( Qt::RoundCap ); + p.setPen(pen); + p.setBrush(pen.color()); + QPointArray pa(3); + pa[0] = QPoint( x2, y2 ); + pa[1] = QPoint( x3, y3 ); + pa[2] = QPoint( x4, y4 ); + p.drawPolygon(pa); + p.drawPolyline(pa); +// p.drawLine( x2, y2, x3, y3 ); +// p.drawLine( x2, y2, x4, y4 ); +} +//END class DPLine + diff --git a/src/drawparts/dpline.h b/src/drawparts/dpline.h new file mode 100644 index 0000000..e47aca8 --- /dev/null +++ b/src/drawparts/dpline.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef DPLINE_H +#define DPLINE_H + +#include "drawpart.h" + +class LineOverlay; + +/** +@author David Saxton +*/ +class DPLine : public DrawPart +{ + public: + DPLine( ItemDocument *itemDocument, bool newItem, const char *id = 0L ); + ~DPLine(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void setSelected( bool yes ); + + protected: + virtual void postResize(); + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + LineOverlay * m_pLineOverlay; +}; + +/** +@author David Saxton +*/ +class DPArrow : public DPLine +{ + public: + DPArrow( ItemDocument *itemDocument, bool newItem, const char *id = 0L ); + ~DPArrow(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void drawShape( QPainter &p ); +}; + +#endif diff --git a/src/drawparts/dptext.cpp b/src/drawparts/dptext.cpp new file mode 100644 index 0000000..ebb239a --- /dev/null +++ b/src/drawparts/dptext.cpp @@ -0,0 +1,133 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "dptext.h" +#include "itemdocument.h" +#include "libraryitem.h" +#include "resizeoverlay.h" + +#include +#include +#include + +Item* DPText::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new DPText( itemDocument, newItem, id ); +} + +LibraryItem* DPText::libraryItem() +{ + QStringList idList; + idList << "dp/text" << "dp/canvas_text" << "canvas_text"; + + return new LibraryItem( + idList, + i18n("Canvas Text"), + i18n("Other"), + KGlobal::iconLoader()->loadIcon( "text", KIcon::Small ), + LibraryItem::lit_drawpart, + DPText::construct ); +} + +DPText::DPText( ItemDocument *itemDocument, bool newItem, const char *id ) + : DrawPart( itemDocument, newItem, (id) ? id : "canvas_text" ) +{ + m_rectangularOverlay = new RectangularOverlay(this); + m_name = i18n("Text"); + m_desc = i18n("Doubleclick the Text Item to set the text"); + + createProperty( "text", Variant::Type::Multiline ); + property("text")->setValue( i18n("Text") ); + + createProperty( "background", Variant::Type::Bool ); + property("background")->setValue(false); + property("background")->setCaption( i18n("Display Background") ); + property("background")->setAdvanced(true); + + createProperty( "background-color", Variant::Type::Color ); + property("background-color")->setValue(Qt::white); + property("background-color")->setCaption( i18n("Background Color") ); + property("background-color")->setAdvanced(true); + + createProperty( "frame-color", Variant::Type::Color ); + property("frame-color")->setValue(Qt::black); + property("frame-color")->setCaption( i18n("Frame Color") ); + property("frame-color")->setAdvanced(true); + + createProperty( "text-color", Variant::Type::Color ); + property("text-color")->setValue(Qt::black); + property("text-color")->setCaption( i18n("Text Color") ); +} + +DPText::~DPText() +{ +} + +void DPText::setSelected( bool yes ) +{ + if ( yes == isSelected() ) + return; + + DrawPart::setSelected(yes); + m_rectangularOverlay->showResizeHandles(yes); +} + + +void DPText::dataChanged() +{ + m_caption = dataString("text"); + b_displayBackground = dataBool("background"); + m_backgroundColor = dataColor("background-color"); + m_textColor = dataColor("text-color"); + m_frameColor = dataColor("frame-color"); + update(); +} + + +void DPText::postResize() +{ + setItemPoints( QPointArray(m_sizeRect), false ); +} + + +QSize DPText::minimumSize() const +{ + return QSize( 48, 24 ); +} + + +void DPText::drawShape( QPainter &p ) +{ + QRect bound = m_sizeRect; + bound.setWidth( bound.width()-2 ); + bound.setHeight( bound.height()-2 ); + bound.moveBy( int(x()+1), int(y()+1) ); + + if (b_displayBackground) + { + p.save(); + p.setPen( QPen( m_frameColor, 1, Qt::DotLine) ); + p.setBrush(m_backgroundColor); + p.drawRect(bound); + p.restore(); + } + + const int pad = 6; + + bound.setLeft( bound.left()+pad ); + bound.setTop( bound.top()+pad ); + bound.setRight( bound.right()-pad ); + bound.setBottom( bound.bottom()-pad ); + + p.setPen(m_textColor); + p.setFont( font() ); + p.drawText( bound, (Qt::WordBreak | Qt::AlignHCenter | Qt::AlignVCenter), m_caption ); +} + diff --git a/src/drawparts/dptext.h b/src/drawparts/dptext.h new file mode 100644 index 0000000..a6f5a4a --- /dev/null +++ b/src/drawparts/dptext.h @@ -0,0 +1,48 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef CANVASTEXT_H +#define CANVASTEXT_H + +#include "drawpart.h" + +/** +@short Represents editable text on the canvas +@author David Saxton +*/ +class DPText : public DrawPart +{ +public: + DPText( ItemDocument *itemDocument, bool newItem, const char *id = 0L ); + ~DPText(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + static LibraryItem *libraryItemOld(); + + virtual void setSelected( bool yes ); + + virtual QSize minimumSize() const; + +protected: + virtual void postResize(); + +private: + virtual void drawShape( QPainter &p ); + void dataChanged(); + QString m_caption; + bool b_displayBackground; + QColor m_textColor; + QColor m_backgroundColor; + QColor m_frameColor; + RectangularOverlay *m_rectangularOverlay; +}; + +#endif diff --git a/src/drawparts/drawpart.cpp b/src/drawparts/drawpart.cpp new file mode 100644 index 0000000..6d9708d --- /dev/null +++ b/src/drawparts/drawpart.cpp @@ -0,0 +1,264 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "itemdocument.h" +#include "itemdocumentdata.h" +#include "drawpart.h" +#include "variant.h" + +#include +#include + +DrawPart::DrawPart( ItemDocument *itemDocument, bool newItem, const char *id ) + : Item( itemDocument, newItem, id ) +{ + itemDocument->registerItem(this); +} + + +DrawPart::~DrawPart() +{ +} + + +int DrawPart::rtti() const +{ + return ItemDocument::RTTI::DrawPart; +} + + +Variant * DrawPart::createProperty( const QString & id, Variant::Type::Value type ) +{ + if ( type == Variant::Type::PenStyle ) + { + QStringList penStyles; + penStyles << DrawPart::penStyleToName(Qt::SolidLine) << DrawPart::penStyleToName(Qt::DashLine) + << DrawPart::penStyleToName(Qt::DotLine) << DrawPart::penStyleToName(Qt::DashDotLine) + << DrawPart::penStyleToName(Qt::DashDotDotLine); + + Variant * v = createProperty( id, Variant::Type::String ); + v->setType( Variant::Type::PenStyle ); + v->setAllowed(penStyles); + return v; + } + + if ( type == Variant::Type::PenCapStyle ) + { + QStringList penCapStyles; + penCapStyles << DrawPart::penCapStyleToName(Qt::FlatCap) << DrawPart::penCapStyleToName(Qt::SquareCap) + << DrawPart::penCapStyleToName(Qt::RoundCap); + + Variant * v = createProperty( id, Variant::Type::String ); + v->setType( Variant::Type::PenCapStyle ); + v->setAllowed(penCapStyles); + return v; + } + + return Item::createProperty( id, type ); +} + + +Qt::PenStyle DrawPart::getDataPenStyle( const QString & id ) +{ + return nameToPenStyle( dataString(id) ); +} +Qt::PenCapStyle DrawPart::getDataPenCapStyle( const QString & id ) +{ + return nameToPenCapStyle( dataString(id) ); +} +void DrawPart::setDataPenStyle( const QString & id, Qt::PenStyle value ) +{ + property(id)->setValue( penStyleToName(value) ); +} +void DrawPart::setDataPenCapStyle( const QString & id, Qt::PenCapStyle value ) +{ + property(id)->setValue( penCapStyleToName(value) ); +} + + +ItemData DrawPart::itemData() const +{ + ItemData itemData = Item::itemData(); + + const VariantDataMap::const_iterator end = m_variantData.end(); + for ( VariantDataMap::const_iterator it = m_variantData.begin(); it != end; ++it ) + { + switch( it.data()->type() ) + { + case Variant::Type::PenStyle: + itemData.dataString[it.key()] = penStyleToID( nameToPenStyle( it.data()->value().toString() ) ); + break; + case Variant::Type::PenCapStyle: + itemData.dataString[it.key()] = penCapStyleToID( nameToPenCapStyle( it.data()->value().toString() ) ); + break; + case Variant::Type::String: + case Variant::Type::FileName: + case Variant::Type::Port: + case Variant::Type::Pin: + case Variant::Type::VarName: + case Variant::Type::Combo: + case Variant::Type::Select: + case Variant::Type::Multiline: + case Variant::Type::Int: + case Variant::Type::Double: + case Variant::Type::Color: + case Variant::Type::Bool: + case Variant::Type::Raw: + case Variant::Type::SevenSegment: + case Variant::Type::KeyPad: + case Variant::Type::None: + // All of these are handled by Item + break; + } + } + + return itemData; +} + + +void DrawPart::restoreFromItemData( const ItemData &itemData ) +{ + Item::restoreFromItemData(itemData); + + const QStringMap::const_iterator stringEnd = itemData.dataString.end(); + for ( QStringMap::const_iterator it = itemData.dataString.begin(); it != stringEnd; ++it ) + { + VariantDataMap::iterator vit = m_variantData.find(it.key()); + if ( vit == m_variantData.end() ) + continue; + + if ( vit.data()->type() == Variant::Type::PenStyle ) + setDataPenStyle( it.key(), idToPenStyle( it.data() ) ); + + else if ( vit.data()->type() == Variant::Type::PenCapStyle ) + setDataPenCapStyle( it.key(), idToPenCapStyle( it.data() ) ); + } +} + + + +QString DrawPart::penStyleToID( Qt::PenStyle style ) +{ + switch (style) + { + case Qt::SolidLine: + return "SolidLine"; + case Qt::NoPen: + return "NoPen"; + case Qt::DashLine: + return "DashLine"; + case Qt::DotLine: + return "DotLine"; + case Qt::DashDotLine: + return "DashDotLine"; + case Qt::DashDotDotLine: + return "DashDotDotLine"; + case Qt::MPenStyle: + default: + return ""; // ?! + } +} +Qt::PenStyle DrawPart::idToPenStyle( const QString & id ) +{ + if ( id == "NoPen" ) + return Qt::NoPen; + if ( id == "DashLine" ) + return Qt::DashLine; + if ( id == "DotLine" ) + return Qt::DotLine; + if ( id == "DashDotLine" ) + return Qt::DashDotLine; + if ( id == "DashDotDotLine" ) + return Qt::DashDotDotLine; + return Qt::SolidLine; +} +QString DrawPart::penCapStyleToID( Qt::PenCapStyle style ) +{ + switch (style) + { + case Qt::FlatCap: + return "FlatCap"; + case Qt::SquareCap: + return "SquareCap"; + case Qt::RoundCap: + return "RoundCap"; + case Qt::MPenCapStyle: + default: + return ""; // ?! + } +} +Qt::PenCapStyle DrawPart::idToPenCapStyle( const QString & id ) +{ + if ( id == "SquareCap" ) + return Qt::SquareCap; + if ( id == "RoundCap" ) + return Qt::RoundCap; + return Qt::FlatCap; +} + +QString DrawPart::penStyleToName( Qt::PenStyle style ) +{ + switch (style) + { + case Qt::SolidLine: + return i18n("Solid"); + case Qt::NoPen: + return i18n("None"); + case Qt::DashLine: + return i18n("Dash"); + case Qt::DotLine: + return i18n("Dot"); + case Qt::DashDotLine: + return i18n("Dash Dot"); + case Qt::DashDotDotLine: + return i18n("Dash Dot Dot"); + case Qt::MPenStyle: + default: + return ""; // ?! + } +} +Qt::PenStyle DrawPart::nameToPenStyle( const QString & name ) +{ + if ( name == i18n("None") ) + return Qt::NoPen; + if ( name == i18n("Dash") ) + return Qt::DashLine; + if ( name == i18n("Dot") ) + return Qt::DotLine; + if ( name == i18n("Dash Dot") ) + return Qt::DashDotLine; + if ( name == i18n("Dash Dot Dot") ) + return Qt::DashDotDotLine; + return Qt::SolidLine; +} +QString DrawPart::penCapStyleToName( Qt::PenCapStyle style ) +{ + switch (style) + { + case Qt::FlatCap: + return i18n("Flat"); + case Qt::SquareCap: + return i18n("Square"); + case Qt::RoundCap: + return i18n("Round"); + case Qt::MPenCapStyle: + default: + return ""; // ?! + } +} +Qt::PenCapStyle DrawPart::nameToPenCapStyle( const QString & name ) +{ + if ( name == i18n("Square") ) + return Qt::SquareCap; + if ( name == i18n("Round") ) + return Qt::RoundCap; + return Qt::FlatCap; +} + diff --git a/src/drawparts/drawpart.h b/src/drawparts/drawpart.h new file mode 100644 index 0000000..8dc9f50 --- /dev/null +++ b/src/drawparts/drawpart.h @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef DRAWPART_H +#define DRAWPART_H + +#include + +class ICNDocument; +class ItemDocument; +class LibraryItem; +class RectangularOverlay; + +/** +@author David Saxton +*/ +class DrawPart : public Item +{ + public: + enum DrawAction + { + // Note: values are used for popup menu + da_text = 0, + da_line = 1, + da_arrow = 2, + da_rectangle = 3, + da_ellipse = 4 + }; + + DrawPart( ItemDocument *itemDocument, bool newItem, const char *id ); + virtual ~DrawPart(); + + int rtti() const; + + virtual bool canResize() const { return true; } + + virtual Variant * createProperty( const QString & id, Variant::Type::Value type ); + + Qt::PenStyle getDataPenStyle( const QString & id ); + Qt::PenCapStyle getDataPenCapStyle( const QString & id ); + + void setDataPenStyle( const QString & id, Qt::PenStyle value ); + void setDataPenCapStyle( const QString & id, Qt::PenCapStyle value ); + + virtual ItemData itemData() const; + virtual void restoreFromItemData( const ItemData &itemData ); + + // Convention for following functions: name is i18n'd name of style, id is the english one + + static QString penStyleToID( Qt::PenStyle style ); + static Qt::PenStyle idToPenStyle( const QString & id ); + static QString penCapStyleToID( Qt::PenCapStyle style ); + static Qt::PenCapStyle idToPenCapStyle( const QString & id ); + + static QString penStyleToName( Qt::PenStyle style ); + static Qt::PenStyle nameToPenStyle( const QString & name ); + static QString penCapStyleToName( Qt::PenCapStyle style ); + static Qt::PenCapStyle nameToPenCapStyle( const QString & name ); +}; + +#endif diff --git a/src/drawparts/solidshape.cpp b/src/drawparts/solidshape.cpp new file mode 100644 index 0000000..e60efef --- /dev/null +++ b/src/drawparts/solidshape.cpp @@ -0,0 +1,192 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "solidshape.h" +#include "libraryitem.h" +#include "resizeoverlay.h" + +#include +#include +#include +#include + + +//BEGIN class DPRectangle +Item * DPRectangle::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new DPRectangle( itemDocument, newItem, id ); +} + +LibraryItem* DPRectangle::libraryItem() +{ + return new LibraryItem( + QString("dp/rectangle"), + i18n("Rectangle"), + i18n("Other"), + KGlobal::iconLoader()->loadIcon( "text", KIcon::Small ), + LibraryItem::lit_drawpart, + DPRectangle::construct ); +} + +DPRectangle::DPRectangle( ItemDocument *itemDocument, bool newItem, const char *id ) + : DrawPart( itemDocument, newItem, id ? id : "rectangle" ) +{ + m_pRectangularOverlay = new RectangularOverlay(this); + m_name = i18n("Rectangle"); + + createProperty( "background", Variant::Type::Bool ); + property("background")->setValue(false); + property("background")->setCaption( i18n("Display Background") ); + property("background")->setAdvanced(true); + + createProperty( "background-color", Variant::Type::Color ); + property("background-color")->setValue(Qt::white); + property("background-color")->setCaption( i18n("Background Color") ); + property("background-color")->setAdvanced(true); + + createProperty( "line-color", Variant::Type::Color ); + property("line-color")->setValue(Qt::black); + property("line-color")->setCaption( i18n("Line Color") ); + property("line-color")->setAdvanced(true); + + createProperty( "line-width", Variant::Type::Int ); + property("line-width")->setCaption( i18n("Line Width") ); + property("line-width")->setMinValue(1); + property("line-width")->setMaxValue(1000); + property("line-width")->setValue(1); + property("line-width")->setAdvanced(true); + + createProperty( "line-style", Variant::Type::PenStyle ); + property("line-style")->setAdvanced(true); + setDataPenStyle( "line-style", Qt::SolidLine ); +} + +DPRectangle::~DPRectangle() +{ +} + +void DPRectangle::setSelected( bool yes ) +{ + if ( yes == isSelected() ) + return; + + DrawPart::setSelected(yes); + m_pRectangularOverlay->showResizeHandles(yes); +} + + +void DPRectangle::dataChanged() +{ + bool displayBackground = dataBool("background"); + QColor line_color = dataColor("line-color"); + unsigned width = unsigned( dataInt("line-width") ); + Qt::PenStyle style = getDataPenStyle("line-style"); + + setPen( QPen( line_color, width, style ) ); + + if (displayBackground) + setBrush( dataColor("background-color") ); + else + setBrush( Qt::NoBrush ); + + postResize(); + update(); +} + + +QSize DPRectangle::minimumSize() const +{ + int side = QMAX(16, pen().width()+2); + return QSize( side, side ); +} + + +void DPRectangle::postResize() +{ + setItemPoints( m_sizeRect, false ); +} + + +QRect DPRectangle::drawRect() const +{ + int lw = pen().width(); + + if ( lw > m_sizeRect.width() ) + lw = m_sizeRect.width(); + + if ( lw > m_sizeRect.height() ) + lw = m_sizeRect.height(); + + return QRect( int(x() + m_sizeRect.x()+lw/2), int(y() + m_sizeRect.y()+lw/2), + m_sizeRect.width()-lw, m_sizeRect.height()-lw ); +} + + +void DPRectangle::drawShape( QPainter & p ) +{ + p.drawRect(drawRect()); +} +//END class DPRectangle + + +//BEGIN class DPEllipse +Item * DPEllipse::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new DPEllipse( itemDocument, newItem, id ); +} + +LibraryItem* DPEllipse::libraryItem() +{ + return new LibraryItem( + QString("dp/ellipse"), + i18n("Ellipse"), + i18n("Other"), + KGlobal::iconLoader()->loadIcon( "text", KIcon::Small ), + LibraryItem::lit_drawpart, + DPEllipse::construct ); +} + +DPEllipse::DPEllipse( ItemDocument *itemDocument, bool newItem, const char *id ) + : DPRectangle( itemDocument, newItem, id ? id : "ellipse" ) +{ + m_name = i18n("Ellipse"); +} + +DPEllipse::~DPEllipse() +{ +} + + +void DPEllipse::postResize() +{ + QRect br = m_sizeRect; + + // Make octagon that roughly covers ellipse + QPointArray pa(8); + pa[0] = QPoint( br.x() + br.width()/4, br.y() ); + pa[1] = QPoint( br.x() + 3*br.width()/4, br.y() ); + pa[2] = QPoint( br.x() + br.width(), br.y() + br.height()/4 ); + pa[3] = QPoint( br.x() + br.width(), br.y() + 3*br.height()/4 ); + pa[4] = QPoint( br.x() + 3*br.width()/4, br.y() + br.height() ); + pa[5] = QPoint( br.x() + br.width()/4, br.y() + br.height() ); + pa[6] = QPoint( br.x(), br.y() + 3*br.height()/4 ); + pa[7] = QPoint( br.x(), br.y() + br.height()/4 ); + + setItemPoints( pa, false ); +} + + +void DPEllipse::drawShape( QPainter & p ) +{ + p.drawEllipse(drawRect()); +} +//END class SolidShape + + diff --git a/src/drawparts/solidshape.h b/src/drawparts/solidshape.h new file mode 100644 index 0000000..317f417 --- /dev/null +++ b/src/drawparts/solidshape.h @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef SOLIDSHAPE_H +#define SOLIDSHAPE_H + +#include + +class RectangularOverlay; + +/** +@short Represents a drawable rectangle on the canvas +@author David Saxton +*/ +class DPRectangle : public DrawPart +{ + public: + DPRectangle( ItemDocument *itemDocument, bool newItem, const char *id = 0L ); + ~DPRectangle(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void setSelected( bool yes ); + + virtual QSize minimumSize() const; + + protected: + virtual void drawShape( QPainter &p ); + void dataChanged(); + virtual void postResize(); + + /** Returns the rectangle to draw in, taking into account the line + * width */ + QRect drawRect() const; + + private: + RectangularOverlay *m_pRectangularOverlay; +}; + +/** +@short Represents a drawable rectangle on the canvas +@author David Saxton +*/ +class DPEllipse : public DPRectangle +{ + public: + DPEllipse( ItemDocument *itemDocument, bool newItem, const char *id = 0L ); + ~DPEllipse(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void postResize(); + + private: + virtual void drawShape( QPainter &p ); +}; + +#endif diff --git a/src/electronics/Makefile.am b/src/electronics/Makefile.am new file mode 100644 index 0000000..c15e689 --- /dev/null +++ b/src/electronics/Makefile.am @@ -0,0 +1,18 @@ +INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/electronics \ + -I$(top_srcdir)/src/electronics/components -I$(top_srcdir)/src/electronics/simulation \ + -I$(top_srcdir)/src/flowparts -I$(top_srcdir)/src/gui -I$(top_srcdir)/src/languages \ + -I$(top_srcdir)/src/mechanics -I$(top_srcdir)/src/micro $(glib_cflags) $(all_includes) + +METASOURCES = AUTO + +SUBDIRS = simulation components + +noinst_LTLIBRARIES = libelectronics.la + +libelectronics_la_SOURCES = component.cpp subcircuits.cpp gpsimprocessor.cpp \ + switch.cpp pin.cpp wire.cpp ecnode.cpp port.cpp + +libelectronics_la_LIBADD = \ + $(top_builddir)/src/electronics/simulation/libelements.la $(top_builddir)/src/electronics/components/libcomponents.la + +noinst_HEADERS = gpsimprocessor.h switch.h pin.h wire.h ecnode.h port.h diff --git a/src/electronics/component.cpp b/src/electronics/component.cpp new file mode 100644 index 0000000..f9f3c12 --- /dev/null +++ b/src/electronics/component.cpp @@ -0,0 +1,1017 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasitemparts.h" +#include "circuitdocument.h" +#include "component.h" +#include "src/core/ktlconfig.h" +#include "ecnode.h" +#include "itemdocumentdata.h" +#include "node.h" +#include "pin.h" +#include "simulator.h" + +#include "bjt.h" +#include "capacitance.h" +#include "cccs.h" +#include "ccvs.h" +#include "currentsignal.h" +#include "currentsource.h" +#include "diode.h" +#include "inductance.h" +#include "logic.h" +#include "opamp.h" +#include "resistance.h" +#include "switch.h" +#include "vccs.h" +#include "vcvs.h" +#include "voltagepoint.h" +#include "voltagesignal.h" +#include "voltagesource.h" + +#include +#include +#include +#include +#include +#include + +const int dipWidth = 112; +const int pairSep = 32; + +// Degrees per radian +static const double DPR = 57.29577951308232087665461840231273527024; + +Component::Component( ICNDocument *icnDocument, bool newItem, const QString &id ) + : CNItem( icnDocument, newItem, id ), + m_angleDegrees(0), + b_flipped(false) +{ + m_pCircuitDocument = dynamic_cast(icnDocument); + + for ( int i=0; i<4; ++i ) + { + m_pPNode[i] = 0l; + m_pNNode[i] = 0l; + } + + // Get configuration options + slotUpdateConfiguration(); + + // And finally register this :-) + icnDocument->registerItem(this); +} + +Component::~Component() +{ + removeElements(); + Simulator::self()->detachComponent(this); +} + +void Component::removeItem( ) +{ + if (b_deleted) + return; + Simulator::self()->detachComponent(this); + CNItem::removeItem(); +} + +void Component::removeElements( bool setPinsInterIndependent ) +{ + const ElementMapList::iterator end = m_elementMapList.end(); + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) + { + Element * e = (*it).e; + if (e) + { + emit elementDestroyed(e); + e->componentDeleted(); + } + } + m_elementMapList.clear(); + + const SwitchList::iterator swEnd = m_switchList.end(); + for ( SwitchList::iterator it = m_switchList.begin(); it != swEnd; ++it ) + { + Switch * sw = *it; + if ( !sw ) + continue; + + emit switchDestroyed( sw ); + delete sw; + } + m_switchList.clear(); + + if ( setPinsInterIndependent ) + setAllPinsInterIndependent(); +} + + +void Component::removeElement( Element * element, bool setPinsInterIndependent ) +{ + if (!element) + return; + + emit elementDestroyed(element); + element->componentDeleted(); + + const ElementMapList::iterator end = m_elementMapList.end(); + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ) + { + ElementMapList::iterator next = it; + ++next; + + if ( (*it).e == element ) + m_elementMapList.remove(it); + + it = next; + } + + if ( setPinsInterIndependent ) + rebuildPinInterDepedence(); +} + + +void Component::removeSwitch( Switch * sw ) +{ + if ( !sw ) + return; + + emit switchDestroyed( sw ); + delete sw; + m_switchList.remove(sw); + m_pCircuitDocument->requestAssignCircuits(); +} + + +void Component::setNodalCurrents() +{ + const ElementMapList::iterator end = m_elementMapList.end(); + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) + { + ElementMap m = (*it); + for ( int i=0; i<4; i++ ) + { + if ( m.n[i] ) { + m.n[i]->mergeCurrent( m.e->m_cnodeI[i] ); + } + } + } +} + + +void Component::initPainter( QPainter &p ) +{ + CNItem::initPainter(p); + + if ( !b_flipped && (m_angleDegrees%360 == 0) ) + return; + + p.save(); + + p.translate( int(x()), int(y()) ); + if (b_flipped) + p.scale( -1, 1 ); + + p.rotate(m_angleDegrees); + p.translate( -int(x()), -int(y()) ); +} + + +void Component::deinitPainter( QPainter &p ) +{ + if ( !b_flipped && (m_angleDegrees%360 == 0) ) + return; + + p.restore(); +} + + +void Component::setAngleDegrees( int degrees ) +{ + updateConnectorPoints(false); + m_angleDegrees = degrees; + itemPointsChanged(); + updateAttachedPositioning(); + p_icnDocument->requestRerouteInvalidatedConnectors(); +} + + +void Component::setFlipped( bool flipped ) +{ + updateConnectorPoints(false); + b_flipped = flipped; + itemPointsChanged(); + updateAttachedPositioning(); + p_icnDocument->requestRerouteInvalidatedConnectors(); +} + + +void Component::itemPointsChanged() +{ + QPointArray transformedPoints = transMatrix( m_angleDegrees, b_flipped, 0, 0, false ).map(m_itemPoints); +// transformedPoints.translate( int(x()), int(y()) ); + setPoints(transformedPoints); +} + + +void Component::restoreFromItemData( const ItemData &itemData ) +{ + CNItem::restoreFromItemData(itemData); + + setAngleDegrees( int(itemData.angleDegrees) ); + setFlipped(itemData.flipped); +} + + +ItemData Component::itemData() const +{ + ItemData itemData = CNItem::itemData(); + itemData.angleDegrees = m_angleDegrees; + itemData.flipped = b_flipped; + return itemData; +} + + +QWMatrix Component::transMatrix( int angleDegrees, bool flipped, int x, int y, bool inverse ) +{ + QWMatrix m; + m.translate( x, y ); + if (inverse) + { + m.rotate(-angleDegrees); + if (flipped) + m.scale( -1, 1 ); + } + else + { + if (flipped) + m.scale( -1, 1 ); + m.rotate(angleDegrees); + } + m.translate( -x, -y ); + m.setTransformationMode( QWMatrix::Areas ); + return m; +} + + +void Component::finishedCreation() +{ + CNItem::finishedCreation(); + updateAttachedPositioning(); +} + + +void Component::updateAttachedPositioning() +{ + if (b_deleted || !m_bDoneCreation) + return; + + //BEGIN Transform the nodes + const NodeMap::iterator end = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != end; ++it ) + { + if ( !it.data().node ) + kdError() << k_funcinfo << "Node in nodemap is null" << endl; + else + { + int nx = int((std::cos(m_angleDegrees/DPR) * it.data().x) - (std::sin(m_angleDegrees/DPR) * it.data().y)); + int ny = int((std::sin(m_angleDegrees/DPR) * it.data().x) + (std::cos(m_angleDegrees/DPR) * it.data().y)); + + if (b_flipped) + nx = -nx; + +#define round_8(x) (((x) > 0) ? int(((x)+4)/8)*8 : int(((x)-4)/8)*8) + nx = round_8(nx); + ny = round_8(ny); +#undef round_8 + + int newDir = (((m_angleDegrees + it.data().orientation)%360)+360)%360; + if (b_flipped) + newDir = (((180-newDir)%360)+360)%360; + + it.data().node->move( nx+x(), ny+y() ); + it.data().node->setOrientation( (Node::node_dir)newDir ); + } + } + //END Transform the nodes + + + //BEGIN Transform the GuiParts + QWMatrix m; + + if (b_flipped) + m.scale( -1, 1 ); + m.rotate(m_angleDegrees); + m.setTransformationMode( QWMatrix::Areas ); + + const TextMap::iterator textMapEnd = m_textMap.end(); + for ( TextMap::iterator it = m_textMap.begin(); it != textMapEnd; ++it ) + { + QRect newPos = m.mapRect( it.data()->recommendedRect() ); + it.data()->move( newPos.x() + x(), newPos.y() + y() ); + it.data()->setGuiPartSize( newPos.width(), newPos.height() ); + it.data()->setAngleDegrees(m_angleDegrees); + } + const WidgetMap::iterator widgetMapEnd = m_widgetMap.end(); + for ( WidgetMap::iterator it = m_widgetMap.begin(); it != widgetMapEnd; ++it ) + { + QRect newPos = m.mapRect( it.data()->recommendedRect() ); + it.data()->move( newPos.x() + x(), newPos.y() + y() ); + it.data()->setGuiPartSize( newPos.width(), newPos.height() ); + it.data()->setAngleDegrees(m_angleDegrees); + } + //END Transform the GuiParts +} + + +void Component::drawPortShape( QPainter & p ) +{ + int h = height(); + int w = width() - 1; + int _x = int( x() + offsetX() ); + int _y = int( y() + offsetY() ); + + double roundSize = 8; + double slantIndent = 8; + + const double pi = 3.1415926536; + const double DPR = 180./pi; + double inner = std::atan(h/slantIndent); // Angle for slight corner + double outer = pi-inner; // Angle for sharp corner + + int inner16 = int(16*inner*DPR); + int outer16 = int(16*outer*DPR); + + p.save(); + p.setPen( Qt::NoPen ); + p.drawPolygon( areaPoints() ); + p.restore(); + + initPainter( p ); + + // Left line + p.drawLine( int(_x), int(_y+roundSize/2), int(_x), int(_y+h-roundSize/2) ); + + // Right line + p.drawLine( int(_x+w), int(_y-slantIndent+h-roundSize/2), int(_x+w), int(_y+slantIndent+roundSize/2) ); + + // Bottom line + p.drawLine( int(_x+(1-std::cos(outer))*(roundSize/2)), int(_y+h+(std::sin(outer)-1)*(roundSize/2)), + int(_x+w+(std::cos(inner)-1)*(roundSize/2)), int(_y+h-slantIndent+(std::sin(inner)-1)*(roundSize/2)) ); + + // Top line + p.drawLine( int(_x+w+(std::cos(outer)-1)*(roundSize/2)), int(_y+slantIndent+(1-std::sin(inner))*(roundSize/2)), + int(_x+(1-std::cos(inner))*(roundSize/2)), int(_y+(1-std::sin(outer))*(roundSize/2)) ); + + + // Top left + p.drawArc( int(_x), int(_y), int(roundSize), int(roundSize), 90*16, outer16 ); + + // Bottom left + p.drawArc( int(_x), int(_y+h-roundSize), int(roundSize), int(roundSize), 180*16, outer16 ); + + // Top right + p.drawArc( int(_x+w-roundSize), int(_y+slantIndent), int(roundSize), int(roundSize), 0, inner16 ); + + // Bottom right + p.drawArc( int(_x+w-roundSize), int(_y-slantIndent+h-roundSize), int(roundSize), int(roundSize), 270*16, inner16 ); + + deinitPainter( p ); +} + + +void Component::initDIP( const QStringList & pins ) +{ + const int numPins = pins.size(); + const int numSide = numPins/2 + numPins%2; + + // Pins along left + for ( int i=0; i( p_icnDocument->nodeWithID( nodeId(ecNodeId) ) ); +} + + +void Component::slotUpdateConfiguration() +{ + const LogicConfig logicConfig = LogicIn::getConfig(); + + const ElementMapList::iterator end = m_elementMapList.end(); + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) + { + if ( LogicIn * logicIn = dynamic_cast((*it).e) ) + logicIn->setLogic(logicConfig); + } +} + + + +BJT * Component::createBJT( ECNode *c, ECNode *b, ECNode *e, bool isNPN ) +{ return createBJT( c->pin(), b->pin(), e->pin(), isNPN ); } +Capacitance * Component::createCapacitance( ECNode *n0, ECNode *n1, double capacitance ) +{ return createCapacitance( n0->pin(), n1->pin(), capacitance ); } +CCCS * Component::createCCCS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ) +{ return createCCCS( n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain ); } +CCVS * Component::createCCVS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ) +{ return createCCVS( n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain ); } +CurrentSignal * Component::createCurrentSignal( ECNode *n0, ECNode *n1, double current ) +{ return createCurrentSignal( n0->pin(), n1->pin(), current ); } +CurrentSource * Component::createCurrentSource( ECNode *n0, ECNode *n1, double current ) +{ return createCurrentSource( n0->pin(), n1->pin(), current ); } +Diode * Component::createDiode( ECNode *n0, ECNode *n1 ) +{ return createDiode( n0->pin(), n1->pin() ); } +Inductance * Component::createInductance( ECNode *n0, ECNode *n1, double inductance ) +{ return createInductance( n0->pin(), n1->pin(), inductance ); } +LogicIn * Component::createLogicIn( ECNode *node ) +{ return createLogicIn( node->pin() ); } +LogicOut * Component::createLogicOut( ECNode *node, bool isHigh ) +{ return createLogicOut( node->pin(), isHigh ); } +OpAmp * Component::createOpAmp( ECNode * nonInverting, ECNode * out, ECNode * inverting ) +{ return createOpAmp( nonInverting->pin(), out->pin(), inverting->pin() ); } +Resistance * Component::createResistance( ECNode *n0, ECNode *n1, double resistance ) +{ return createResistance( n0->pin(), n1->pin(), resistance ); } +Switch * Component::createSwitch( ECNode *n0, ECNode *n1, bool open ) +{ return createSwitch( n0->pin(), n1->pin(), open ); } +VCCS * Component::createVCCS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ) +{ return createVCCS( n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain ); } +VCVS * Component::createVCVS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ) +{ return createVCVS( n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain ); } +VoltagePoint * Component::createVoltagePoint( ECNode *n0, double voltage ) +{ return createVoltagePoint( n0->pin(), voltage ); } +VoltageSignal * Component::createVoltageSignal( ECNode *n0, ECNode *n1, double voltage ) +{ return createVoltageSignal( n0->pin(), n1->pin(), voltage ); } +VoltageSource * Component::createVoltageSource( ECNode *n0, ECNode *n1, double voltage ) +{ return createVoltageSource( n0->pin(), n1->pin(), voltage ); } + +BJT* Component::createBJT( Pin *cN, Pin *bN, Pin *eN, bool isNPN ) +{ + BJT *e = new BJT(isNPN); + + QValueList pins; + pins << bN << cN << eN; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +Capacitance* Component::createCapacitance( Pin *n0, Pin *n1, double capacitance ) +{ + Capacitance *e = new Capacitance( capacitance, 1./LINEAR_UPDATE_RATE ); + + QValueList pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +CCCS* Component::createCCCS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ) +{ + CCCS *e = new CCCS(gain); + + QValueList pins; + pins << n0 << n1 << n2 << n3; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +CCVS* Component::createCCVS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ) +{ + CCVS *e = new CCVS(gain); + + QValueList pins; + pins << n0 << n1 << n2 << n3; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterCircuitDependent( it, pins ); + + pins.clear(); + pins << n0 << n1; + setInterGroundDependent( it, pins ); + + pins.clear(); + pins << n2 << n3; + setInterGroundDependent( it, pins ); + + return e; +} + +CurrentSignal* Component::createCurrentSignal( Pin *n0, Pin *n1, double current ) +{ + CurrentSignal *e = new CurrentSignal( 1./LINEAR_UPDATE_RATE, current ); + + QValueList pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +CurrentSource* Component::createCurrentSource( Pin *n0, Pin *n1, double current ) +{ + CurrentSource *e = new CurrentSource(current); + + QValueList pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +Diode* Component::createDiode( Pin *n0, Pin *n1 ) +{ + Diode *e = new Diode(); + + QValueList pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +Inductance* Component::createInductance( Pin *n0, Pin *n1, double inductance ) +{ + Inductance *e = new Inductance( inductance, 1./LINEAR_UPDATE_RATE ); + + QValueList pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +LogicIn *Component::createLogicIn( Pin *node ) +{ + LogicIn *e = new LogicIn(LogicIn::getConfig()); + + QValueList pins; + pins << node; + + ElementMapList::iterator it = handleElement( e, pins ); + return e; +} + +LogicOut *Component::createLogicOut( Pin *node, bool isHigh ) +{ + LogicOut *e = new LogicOut( LogicIn::getConfig(), isHigh); + + QValueList pins; + pins << node; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +OpAmp * Component::createOpAmp( Pin * nonInverting, Pin * inverting, Pin * out ) +{ + OpAmp * e = new OpAmp(); + + QValueList pins; + pins << nonInverting << inverting << out; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +Resistance* Component::createResistance( Pin *n0, Pin *n1, double resistance ) +{ + Resistance *e = new Resistance(resistance); + + QValueList pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +Switch* Component::createSwitch( Pin *n0, Pin *n1, bool open ) +{ + // Note that a Switch is not really an element (although in many cases it + // behaves very much like one). + + Switch * e = new Switch( this, n0, n1, open ? Switch::Open : Switch::Closed ); + m_switchList.append(e); + n0->addSwitch( e ); + n1->addSwitch( e ); + emit switchCreated( e ); + return e; +} + +VCCS* Component::createVCCS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ) +{ + VCCS *e = new VCCS(gain); + + QValueList pins; + pins << n0 << n1 << n2 << n3; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +VCVS* Component::createVCVS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ) +{ + VCVS *e = new VCVS(gain); + + QValueList pins; + pins << n0 << n1 << n2 << n3; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterCircuitDependent( it, pins ); + + pins.clear(); + pins << n0 << n1; + setInterGroundDependent( it, pins ); + + pins.clear(); + pins << n2 << n3; + setInterGroundDependent( it, pins ); + return e; +} + +VoltagePoint* Component::createVoltagePoint( Pin *n0, double voltage ) +{ + VoltagePoint *e = new VoltagePoint(voltage); + + QValueList pins; + pins << n0; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +VoltageSignal* Component::createVoltageSignal( Pin *n0, Pin *n1, double voltage ) +{ + VoltageSignal *e = new VoltageSignal( 1./LINEAR_UPDATE_RATE, voltage ); + + QValueList pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +VoltageSource* Component::createVoltageSource( Pin *n0, Pin *n1, double voltage ) +{ + VoltageSource *e = new VoltageSource(voltage); + + QValueList pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + + +ElementMapList::iterator Component::handleElement( Element *e, const QValueList & pins ) +{ + if (!e) + return m_elementMapList.end(); + + ElementMap em; + em.e = e; + int at = 0; + QValueList::ConstIterator end = pins.end(); + for ( QValueList::ConstIterator it = pins.begin(); it != end; ++it ) + { + (*it)->addElement(e); + em.n[at++] = *it; + } + + ElementMapList::iterator it = m_elementMapList.append(em); + + emit elementCreated(e); + return it; +} + + +void Component::setInterDependent( ElementMapList::iterator it, const QValueList & pins ) +{ + setInterCircuitDependent( it, pins ); + setInterGroundDependent( it, pins ); +} + + +void Component::setInterCircuitDependent( ElementMapList::iterator it, const QValueList & pins ) +{ + QValueList::ConstIterator end = pins.end(); + for ( QValueList::ConstIterator it1 = pins.begin(); it1 != end; ++it1 ) + { + for ( QValueList::ConstIterator it2 = pins.begin(); it2 != end; ++it2 ) + { + (*it1)->addCircuitDependentPin( *it2 ); + } + } + + (*it).interCircuitDependent.append( pins ); +} + + +void Component::setInterGroundDependent( ElementMapList::iterator it, const QValueList & pins ) +{ + QValueList::ConstIterator end = pins.end(); + for ( QValueList::ConstIterator it1 = pins.begin(); it1 != end; ++it1 ) + { + for ( QValueList::ConstIterator it2 = pins.begin(); it2 != end; ++it2 ) + { + (*it1)->addGroundDependentPin( *it2 ); + } + } + + (*it).interGroundDependent.append( pins ); +} + + +void Component::rebuildPinInterDepedence() +{ + setAllPinsInterIndependent(); + + // Rebuild dependencies + ElementMapList::iterator emlEnd = m_elementMapList.end(); + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != emlEnd; ++it ) + { + // Many copies of the pin lists as these will be affected when we call setInter*Dependent + PinListList list = (*it).interCircuitDependent; + + PinListList::iterator depEnd = list.end(); + for ( PinListList::iterator depIt = list.begin(); depIt != depEnd; ++depIt ) + setInterCircuitDependent( it, *depIt ); + + list = (*it).interGroundDependent; + + depEnd = list.end(); + for ( PinListList::iterator depIt = list.begin(); depIt != depEnd; ++depIt ) + setInterGroundDependent( it, *depIt ); + } +} + + +void Component::setAllPinsInterIndependent() +{ + NodeMap::iterator nmEnd = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != nmEnd; ++it ) + { + PinVector pins = (static_cast(it.data().node))->pins(); + PinVector::iterator pinsEnd = pins.end(); + for ( PinVector::iterator pinsIt = pins.begin(); pinsIt != pinsEnd; ++pinsIt ) + { + if ( *pinsIt ) + (*pinsIt)->removeDependentPins(); + } + } +} + + +void Component::initElements( const uint stage ) +{ + /// @todo this function is ugly and messy and needs tidying up + + const ElementMapList::iterator end = m_elementMapList.end(); + + if ( stage == 1 ) + { + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) + { + (*it).e->add_initial_dc(); + } + return; + } + + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) + { + ElementMap m = (*it); + + if ( m.n[3] ) { + m.e->setCNodes( m.n[0]->eqId(), m.n[1]->eqId(), m.n[2]->eqId(), m.n[3]->eqId() ); + } + else if ( m.n[2] ) { + m.e->setCNodes( m.n[0]->eqId(), m.n[1]->eqId(), m.n[2]->eqId() ); + } + else if ( m.n[1] ) { + m.e->setCNodes( m.n[0]->eqId(), m.n[1]->eqId() ); + } + else if ( m.n[0] ) { + m.e->setCNodes( m.n[0]->eqId() ); + } + } + + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) + { + (*it).e->add_map(); + } +} + + +ECNode * Component::createPin( double x, double y, int orientation, const QString & name ) +{ + return dynamic_cast( createNode( x, y, orientation, name, Node::ec_pin ) ); +} + + +//BEGIN class ElementMap +ElementMap::ElementMap() +{ + e = 0; + for ( int i = 0; i < 4; ++i ) + n[i] = 0; +} +//END class ElementMap + + +#include "component.moc" + + diff --git a/src/electronics/component.h b/src/electronics/component.h new file mode 100644 index 0000000..d45d835 --- /dev/null +++ b/src/electronics/component.h @@ -0,0 +1,362 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef COMPONENT_H +#define COMPONENT_H + +#include "cnitem.h" + +#include + +class ICNDocument; +class CircuitDocument; +class ECNode; +class ECSubcircuit; +class Element; +class Node; +class Pin; + +class BJT; +class Capacitance; +class CCCS; +class CCVS; +class CurrentSignal; +class CurrentSource; +class Diode; +class Inductance; +class LogicIn; +class LogicOut; +class OpAmp; +class Resistance; +class Switch; +class Transformer; +class VCCS; +class VCVS; +class VoltagePoint; +class VoltageSignal; +class VoltageSource; + +typedef QValueList ECNodeList; +typedef QValueList ElementList; +typedef QValueList SwitchList; + +typedef QValueList< QValueList > PinListList; + +/** +Contains vital information about the elements in the component. +*/ +class ElementMap +{ + public: + ElementMap(); + + Element * e; // The element + Pin * n[4]; // The Pins associated with the CNodes in the element + + /// @see Component::setInterCircuitDependent + PinListList interCircuitDependent; + + /// @see Component::setInterGroundDependent + PinListList interGroundDependent; +}; + +typedef QValueList ElementMapList; + +/** +@short Bass class for all electrical components +@author David Saxton +*/ +class Component : public CNItem +{ + Q_OBJECT + public: + Component( ICNDocument *icnDocument, bool newItem, const QString &id ); + virtual ~Component(); + + ECNode* createPin( double _x, double _y, int orientation, const QString &name ); + /** + * Reinherit this function to disallow rotation of the component. + */ + virtual bool canRotate() const { return true; } + /** + * Angle of orientation + */ + int angleDegrees() const { return m_angleDegrees; } + /** + * Sets the angle (in degrees) + */ + void setAngleDegrees( int degrees ); + /** + * Whether or not the item is flipped + */ + bool flipped() const { return b_flipped; } + /** + * Sets whether or not the item is flipped + */ + void setFlipped( bool flipped ); + /** + * After calculating nodal voltages, each component will be + * called to tell its nodes what the current flowing *into* + * the component is. + */ + void setNodalCurrents(); + /** + * @return pointer to the CircuitDocument that we're in. + */ + CircuitDocument * circuitDocument() const { return m_pCircuitDocument; } + void initElements( const uint stage ); + virtual void finishedCreation(); + /** + * If reinherit (and use) the stepNonLogic function, then you must also + * reinherit this function so that it returns true. Else your component + * will not get called. + */ + virtual bool doesStepNonLogic() const { return false; } + virtual void stepNonLogic() {}; + /** + * Returns the translation matrix used for painting et al + * @param orientation The orientation to use + * @param x x co-ordinate of the center of the object to be mapped + * @param y y co-ordinate of the center of the object to be mapped + * @param inverse If false, maps the unrotated item to a rotated one, else mapped->unmapped + */ + static QWMatrix transMatrix( int angleDegrees, bool flipped, int x, int y, bool inverse = false ); + /** + * @return Information about the component in an ItemData struct. + */ + virtual ItemData itemData() const; + /** + * Restores the state of the component from the ItemData struct. + */ + virtual void restoreFromItemData( const ItemData &itemData ); + + BJT * createBJT( Pin *c, Pin *b, Pin *e, bool isNPN = true ); + BJT * createBJT( ECNode *c, ECNode *b, ECNode *e, bool isNPN = true ); + + Capacitance * createCapacitance( Pin *n0, Pin *n1, double capacitance ); + Capacitance * createCapacitance( ECNode *n0, ECNode *n1, double capacitance ); + + CCCS * createCCCS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ); + CCCS * createCCCS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ); + + CCVS * createCCVS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ); + CCVS * createCCVS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ); + + CurrentSignal * createCurrentSignal( Pin *n0, Pin *n1, double current ); + CurrentSignal * createCurrentSignal( ECNode *n0, ECNode *n1, double current ); + + CurrentSource * createCurrentSource( Pin *n0, Pin *n1, double current ); + CurrentSource * createCurrentSource( ECNode *n0, ECNode *n1, double current ); + + Diode * createDiode( Pin *n0, Pin *n1 ); + Diode * createDiode( ECNode *n0, ECNode *n1 ); + + Inductance * createInductance( Pin *n0, Pin *n1, double inductance ); + Inductance * createInductance( ECNode *n0, ECNode *n1, double inductance ); + + LogicIn * createLogicIn( Pin *node ); + LogicIn * createLogicIn( ECNode *node ); + + LogicOut * createLogicOut( Pin *node, bool isHigh ); + LogicOut * createLogicOut( ECNode *node, bool isHigh ); + + OpAmp * createOpAmp( Pin * nonInverting, Pin * out, Pin * inverting ); + OpAmp * createOpAmp( ECNode * nonInverting, ECNode * out, ECNode * inverting ); + + Resistance * createResistance( Pin *n0, Pin *n1, double resistance ); + Resistance * createResistance( ECNode *n0, ECNode *n1, double resistance ); + + Switch * createSwitch( Pin *n0, Pin *n1, bool open ); + Switch * createSwitch( ECNode *n0, ECNode *n1, bool open ); + + VCCS * createVCCS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ); + VCCS * createVCCS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ); + + VCVS * createVCVS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ); + VCVS * createVCVS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ); + + VoltagePoint * createVoltagePoint( Pin *n0, double voltage ); + VoltagePoint * createVoltagePoint( ECNode *n0, double voltage ); + + VoltageSignal * createVoltageSignal( Pin *n0, Pin *n1, double voltage ); + VoltageSignal * createVoltageSignal( ECNode *n0, ECNode *n1, double voltage ); + + VoltageSource * createVoltageSource( Pin *n0, Pin *n1, double voltage ); + VoltageSource * createVoltageSource( ECNode *n0, ECNode *n1, double voltage ); + + + ECNode* ecNodeWithID( const QString &ecNodeId ); + + /** + * Safely delete an element - in this case, calls element->componentDeleted, + * and removes it from the element list. + * @param setPinsInterIndependent whether to call + * setPinsInterIndependent. The call is time-consuming, and unnecessary + * if the pins from which the element was originally attached will be/ + * were removed, or they will become interdependent again. + */ + void removeElement( Element * element, bool setPinsInterIndependent ); + /** + * Safely remove a switch. + */ + void removeSwitch( Switch * sw ); + /** + * Removes all elements and switches. + * @param setPinsInterIndependent whether to bother calling + * setPinsInterIndependent. This is false when calling from the + * destructor, or when the dependency information is the same. + */ + void removeElements( bool setPinsInterIndependent = false ); + /** + * @return the list of switches that this component uses. + */ + SwitchList switchList() const { return m_switchList; } + + signals: + /** + * Emitted when an element is created. + */ + void elementCreated( Element * element ); + /** + * Emitted when an element is destroyed. + */ + void elementDestroyed( Element * element ); + /** + * Emitted when a switch. is created + */ + void switchCreated( Switch * sw ); + /** + * Emitted when a switch is destroyed. + */ + void switchDestroyed( Switch * sw ); + + public slots: + virtual void slotUpdateConfiguration(); + virtual void removeItem(); + + protected: + /** + * Convenience functionality provided for components in a port shape + * (such as ParallelPortComponent and SerialPortComponent). + */ + void drawPortShape( QPainter & p ); + virtual void itemPointsChanged(); + virtual void updateAttachedPositioning(); + virtual void initPainter( QPainter &p ); + /** + * Untranforms the painter from the matrix. This *must* be called after doing + * initPainter( QPainter &p ); + */ + virtual void deinitPainter( QPainter &p ); + /** + * This creates a set of nodes with their internal IDs set to those in QStringList pins. + * The pins are in a DIP arrangement, and are spaced width() apart. + */ + void initDIP( const QStringList & pins ); + /** + * Creates the DIP symbol: + * @li constructs rectangular shape + * @li puts on text labels in appropriate positions from QStringList pins + */ + void initDIPSymbol( const QStringList & pins, int width ); + /** + * Create 1 pin on the left of the component, placed half way down if h1 is + * -1 - else at the position of h1. + */ + void init1PinLeft( int h1 = -1 ); + /** + * Create 2 pins on the left of the component, either spread out, or at the + * given heights. + */ + void init2PinLeft( int h1 = -1, int h2 = -1 ); + /** + * Create 3 pins on the left of the component, either spread out, or at the + * given heights. + */ + void init3PinLeft( int h1 = -1, int h2 = -1, int h3 = -1 ); + /** + * Create 4 pins on the left of the component, either spread out, or at the + * given heights. + */ + void init4PinLeft( int h1 = -1, int h2 = -1, int h3 = -1, int h4 = -1 ); + /** + * Create 1 pin on the right of the component, placed half way down if h1 is + * -1 - else at the position of h1. + */ + void init1PinRight( int h1 = -1 ); + /** + * Create 2 pins on the right of the component, either spread out, or at the + * given heights. + */ + void init2PinRight( int h1 = -1, int h2 = -1 ); + /** + * Create 3 pins on the right of the component, either spread out, or at the + * given heights. + */ + void init3PinRight( int h1 = -1, int h2 = -1, int h3 = -1 ); + /** + * Create 4 pins on the right of the component, either spread out, or at the + * given heights. + */ + void init4PinRight( int h1 = -1, int h2 = -1, int h3 = -1, int h4 = -1 ); + /** + * When we remove an element, we have to rebuild the list of inter-dependent + * nodes. (when adding elements, we just call setInterDependent). + */ + void rebuildPinInterDepedence(); + + // Pointers to commonly used nodes + ECNode * m_pPNode[4]; + ECNode * m_pNNode[4]; + + QGuardedPtr m_pCircuitDocument; + int m_angleDegrees; + bool b_flipped; + + private: + /** + * Convenience function for calling both setInterCircuitDependent and + * setInterGroundDependent. + * @param it Which pins are inter-dependent needs to be recorded in case + * this information is later needed in rebuildPinInterDependence. + */ + void setInterDependent( ElementMapList::iterator it, const QValueList & pins ); + /** + * Sets all pins independent of each other. + */ + void setAllPinsInterIndependent(); + /** + * The given pins will affect the simulation of each other. Therefore, they + * will need to be simulated in the same circuit. + */ + void setInterCircuitDependent( ElementMapList::iterator it, const QValueList & pins ); + /** + * If any of the given pins are ground, then that will affect whether + * any of the other pins can be ground. + */ + void setInterGroundDependent( ElementMapList::iterator it, const QValueList & pins ); + /** + * List of ElementMaps; which contain information on the pins associated + * with the element as well as the dependence between the pins for that + * element. + * @see ElementMap + */ + ElementMapList m_elementMapList; + /** + * The switches used by the component. + */ + SwitchList m_switchList; + /** + * @return an iterator to the element in m_elementMapList + */ + ElementMapList::iterator handleElement( Element *e, const QValueList & pins ); +}; + +#endif diff --git a/src/electronics/components/Makefile.am b/src/electronics/components/Makefile.am new file mode 100644 index 0000000..c388cf6 --- /dev/null +++ b/src/electronics/components/Makefile.am @@ -0,0 +1,33 @@ +INCLUDES = -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/electronics -I$(top_srcdir)/src/electronics/components \ + -I$(top_srcdir)/src/electronics/simulation -I$(top_srcdir)/src/gui -I$(top_srcdir)/src/languages \ + -I$(top_srcdir)/src/micro $(glib_cflags) $(all_includes) + +METASOURCES = AUTO +noinst_HEADERS = ecresistor.h ecled.h ecdiode.h ecsevensegment.h eckeypad.h \ + eccapacitor.h ec555.h eccurrentsource.h ecfixedvoltage.h ecbcdto7segment.h \ + ecsignallamp.h ecclockinput.h ecpotentiometer.h ecopamp.h ecvoltagesource.h \ + eccurrentsignal.h ecvoltagesignal.h ecground.h multiinputgate.h fulladder.h multiplexer.h \ + demultiplexer.h externalconnection.h ecsubcircuit.h meter.h probe.h resistordip.h \ + addac.h dependentsource.h flipflop.h toggleswitch.h pushswitch.h ram.h \ + discretelogic.h piccomponent.h piccomponentpin.h binarycounter.h bidirled.h \ + matrixdisplay.h bussplitter.h matrixdisplaydriver.h magnitudecomparator.h \ + serialportcomponent.h parallelportcomponent.h inductor.h ecbjt.h rotoswitch.h + +noinst_LTLIBRARIES = libcomponents.la +libcomponents_la_SOURCES = ecresistor.cpp ecled.cpp ecdiode.cpp \ + ecsevensegment.cpp eckeypad.cpp eccapacitor.cpp ec555.cpp eccurrentsource.cpp \ + ecfixedvoltage.cpp ecbcdto7segment.cpp ecsignallamp.cpp ecclockinput.cpp \ + ecpotentiometer.cpp ecopamp.cpp ecvoltagesource.cpp eccurrentsignal.cpp ecvoltagesignal.cpp \ + ecground.cpp multiinputgate.cpp fulladder.cpp multiplexer.cpp demultiplexer.cpp \ + externalconnection.cpp ecsubcircuit.cpp meter.cpp probe.cpp resistordip.cpp addac.cpp \ + dependentsource.cpp flipflop.cpp toggleswitch.cpp pushswitch.cpp ram.cpp discretelogic.cpp \ + piccomponent.cpp piccomponentpin.cpp binarycounter.cpp bidirled.cpp matrixdisplay.cpp \ + bussplitter.cpp matrixdisplaydriver.cpp magnitudecomparator.cpp serialportcomponent.cpp \ + parallelportcomponent.cpp inductor.cpp ecbjt.cpp rotoswitch.cpp + +libcomponents_la_PCH = AUTO + + +libcomponents_la_LIBADD =\ + $(top_builddir)/src/electronics/simulation/libelements.la diff --git a/src/electronics/components/addac.cpp b/src/electronics/components/addac.cpp new file mode 100644 index 0000000..a58e2d8 --- /dev/null +++ b/src/electronics/components/addac.cpp @@ -0,0 +1,281 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "addac.h" +#include "ecnode.h" +#include "logic.h" +#include "libraryitem.h" +#include "pin.h" +#include "voltagepoint.h" + +#include +#include +#include + + +Item* ADC::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ADC( (ICNDocument*)itemDocument, newItem, id ); +} + + +Item* DAC::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new DAC( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* ADC::libraryItem() +{ + return new LibraryItem( + "ec/adc", + i18n("Analog-Digital"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + ADC::construct + ); +} + + +LibraryItem* DAC::libraryItem() +{ + return new LibraryItem( + "ec/dac", + i18n("Digital-Analog"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + DAC::construct + ); +} + + +//BEGIN class ADDAC +ADDAC::ADDAC( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ) +{ + m_numBits = 0; + m_range = 0; + + createProperty( "numBits", Variant::Type::Int ); + property("numBits")->setCaption( i18n("Number Bits") ); + property("numBits")->setMinValue(2); + property("numBits")->setMaxValue(max_ADDAC_bits); + property("numBits")->setValue(2); + + createProperty( "range", Variant::Type::Double ); + property("range")->setCaption( i18n("Input Range") ); + property("range")->setUnit("V"); + property("range")->setMinValue(-1e12); + property("range")->setMaxValue(1e12); + property("range")->setValue(5); +} + +ADDAC::~ADDAC() +{ +} + + +void ADDAC::dataChanged() +{ + m_range = dataDouble("range"); + initPins(); +} + +//END class ADDAC + + + + +//BEGIN class ADC +ADC::ADC( ICNDocument *icnDocument, bool newItem, const char *id ) + : ADDAC( icnDocument, newItem, (id) ? id : "adc" ) +{ + m_name = i18n("ADC"); + m_desc = i18n("Converts an analog signal into a digital output."); + + for ( int i=0; ipin()->voltage() * (std::pow( 2, double(m_numBits) )-1.) / m_range; + double roundBitValue = std::floor( floatBitValue+0.5 ); + + if ( roundBitValue < 0 ) + { + for ( int i = 0; isetHigh(false); + return; + } + + uint roundedBitValue = uint(roundBitValue); + for ( int i = 0; isetHigh( roundedBitValue & ( 1 << i ) ); +} + + +void ADC::initPins() +{ + int numBits = dataInt("numBits"); + + if ( numBits < 2 ) + numBits = 2; + else if ( numBits > max_ADDAC_bits ) + numBits = max_ADDAC_bits; + + if ( numBits == m_numBits ) + return; + + QStringList pins; + + int inPos = (numBits-1+(numBits%2))/2; + for ( int i=0; i=0; --i ) + pins += QString::number(i); + + initDIPSymbol( pins, 64 ); + initDIP(pins); + + if (!m_realNode) + m_realNode = ecNodeWithID("In"); + + + if ( numBits > m_numBits ) + { + for ( int i=m_numBits; iisHigh() ? 1 : 0 ) << i; + +// double valueAsDouble = double(value); +// double powChange = std::pow( double(m_numBits), 2 )-1.; +// m_voltagePoint->setVoltage( m_range * valueAsDouble / powChange ); + m_voltagePoint->setVoltage( m_range * double(value) / (std::pow( 2, double(m_numBits) )-1.) ); +} + + +void DAC::initPins() +{ + int numBits = dataInt("numBits"); + + if ( numBits < 2 ) + numBits = 2; + else if ( numBits > max_ADDAC_bits ) + numBits = max_ADDAC_bits; + + if ( numBits == m_numBits ) + return; + + QStringList pins; + + for ( int i=0; i=inPos; --i ) + pins += ""; + + pins += "Out"; + + for ( int i=inPos-2; i>=0; --i ) + pins += ""; + + initDIPSymbol( pins, 64 ); + initDIP(pins); + + if (!m_voltagePoint) + m_voltagePoint = createVoltagePoint( ecNodeWithID("Out"), 0. ); + + if ( numBits > m_numBits ) + { + for ( int i=m_numBits; i +#include + +Item* BiDirLED::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new BiDirLED( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* BiDirLED::libraryItem() +{ + return new LibraryItem ( + "ec/bidir_led", + i18n("Bidirectional LED"), + i18n("Outputs"), + "bidirled.png", + LibraryItem::lit_component, + BiDirLED::construct + ); +} + +BiDirLED::BiDirLED( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "bidir_led" ) +{ + m_name = i18n("Bidirectional LED"); + m_desc = i18n("Bidrectional Light Emitting Diode"); + m_bDynamicContent = true; + + setSize( -8, -16, 16, 32 ); + init1PinLeft(); + init1PinRight(); + setSize( -8, -24, 24, 40 ); + + m_pDiode[0] = createDiode( m_pNNode[0], m_pPNode[0] ); + m_pDiode[1] = createDiode( m_pPNode[0], m_pNNode[0] ); + + avg_brightness[0] = avg_brightness[1] = 255; + lastUpdatePeriod = 0.; + r[0]=r[1]=g[0]=g[1]=b[0]=b[1]=0; + last_brightness[0] = last_brightness[1] = 255; + + createProperty( "0-color1", Variant::Type::Color ); + property("0-color1")->setCaption( i18n("Color 1") ); + property("0-color1")->setColorScheme( ColorCombo::LED ); + + createProperty( "0-color2", Variant::Type::Color ); + property("0-color2")->setCaption( i18n("Colour 2") ); + property("0-color2")->setColorScheme( ColorCombo::LED ); +} + +BiDirLED::~BiDirLED() +{ +} + +void BiDirLED::dataChanged() +{ + QString colors[] = { "0-color1", "0-color2" }; + for ( unsigned i = 0; i < 2; i++ ) + { + QColor color = dataColor(colors[i]); + r[i] = color.red(); + g[i] = color.green(); + b[i] = color.blue(); + r[i] /= 0x100; + g[i] /= 0x100; + b[i] /= 0x100; + } +} + +void BiDirLED::stepNonLogic() +{ + double interval = 1./LINEAR_UPDATE_RATE; + lastUpdatePeriod += interval; + + for ( unsigned i = 0; i < 2; i++ ) + avg_brightness[i] += ECLed::brightness(m_pDiode[i]->current())*interval; +} + +void BiDirLED::drawShape( QPainter &p ) +{ + initPainter(p); + + for ( unsigned i = 0; i < 2; i++ ) + { + uint _b; + if ( lastUpdatePeriod == 0. ) + _b = last_brightness[i]; + + else + { + _b = uint(avg_brightness[i]/lastUpdatePeriod); + last_brightness[i] = _b; + } + avg_brightness[i] = 0.; + + p.setBrush( QColor( uint(255-(255-_b)*(1-r[i])), uint(255-(255-_b)*(1-g[i])), uint(255-(255-_b)*(1-b[i])) ) ); + + + QPointArray pa(3); + if ( i == 0 ) + { + pa[0] = QPoint( 8, -8 ); + pa[1] = QPoint( -8, -16 ); + pa[2] = QPoint( -8, 0 ); + } + else + { + pa[0] = QPoint( -8, 8 ); + pa[1] = QPoint( 8, 0 ); + pa[2] = QPoint( 8, 16 ); + } + + pa.translate( int(x()), int(y()) ); + p.drawPolygon(pa); + p.drawPolyline(pa); + } + lastUpdatePeriod = 0.; + + // Draw the arrows indicating it's a LED + int _x = (int)x()-2; + int _y = (int)y()-21; + + p.drawLine( _x+9, _y+3, _x+12, _y ); // Tail of left arrow + p.drawLine( _x+12, _y, _x+10, _y ); // Left edge of left arrow tip + p.drawLine( _x+12, _y, _x+12, _y+2 ); // Right edge of left arrow tip + + p.drawLine( _x+12, _y+6, _x+15, _y+3 ); // Tail of right arrow + p.drawLine( _x+15, _y+3, _x+13, _y+3 ); // Left edge of right arrow tip + p.drawLine( _x+15, _y+3, _x+15, _y+5 ); // Right edge of right arrow tip + + p.drawLine( _x+10, _y, _x+15, _y+5 ); // Diagonal line that forms base of both arrow tips + + _x = int(x()); + _y = int(y()); + p.drawLine( _x+8, _y-16, _x+8, _y ); + p.drawLine( _x-8, _y, _x-8, _y+16 ); + + deinitPainter(p); +} + diff --git a/src/electronics/components/bidirled.h b/src/electronics/components/bidirled.h new file mode 100644 index 0000000..e80f4e0 --- /dev/null +++ b/src/electronics/components/bidirled.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef BIDIRLED_H +#define BIDIRLED_H + +#include + +/** +@author David Saxton +*/ +class BiDirLED : public Component +{ + public: + BiDirLED( ICNDocument * icnDocument, bool newItem, const char *id = 0L ); + ~BiDirLED(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void dataChanged(); + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + + private: + virtual void drawShape( QPainter &p ); + + double r[2]; + double g[2]; + double b[2]; + + double avg_brightness[2]; + uint last_brightness[2]; + double lastUpdatePeriod; + Diode *m_pDiode[2]; +}; + +#endif diff --git a/src/electronics/components/binarycounter.cpp b/src/electronics/components/binarycounter.cpp new file mode 100644 index 0000000..f278104 --- /dev/null +++ b/src/electronics/components/binarycounter.cpp @@ -0,0 +1,186 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "binarycounter.h" + +#include "logic.h" +#include "libraryitem.h" + +#include +#include + +Item* BinaryCounter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new BinaryCounter( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* BinaryCounter::libraryItem() +{ + QStringList ids; + ids << "ec/binary_counter" << "ec/4_bit_binary_counter"; + return new LibraryItem( + ids, + i18n("Binary Counter"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + BinaryCounter::construct + ); +} + +BinaryCounter::BinaryCounter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "binary_counter" ) +{ + m_name = i18n("Binary Counter"); + m_desc = i18n("Holds an internal count, which changes when the clock input > pin is pulsed.

    " + "Normal operation: en (Enable) and u/d (Up/Down) are held high, r (Reset) is low."); + + enLogic = inLogic = rLogic = udLogic = 0L; + + b_reset = false; + b_triggerHigh = true; + b_oldIn = false; + m_value = 0; + b_en = false; + b_ud = false; + m_numBits = 0; + m_maxValue = false; + m_bDoneLogicIn = false; + + createProperty( "trig", Variant::Type::Select ); + property("trig")->setCaption( i18n("Trigger Edge") ); + property("trig")->setAllowed( QStringList::split( ',', "Rising,Falling" ) ); + property("trig")->setValue("Rising"); + + createProperty( "bitcount", Variant::Type::Int ); + property("bitcount")->setCaption( i18n("Bit Count") ); + property("bitcount")->setMinValue(1); + property("bitcount")->setMaxValue(26); + property("bitcount")->setValue(4); +} + + +BinaryCounter::~BinaryCounter() +{ +} + + +void BinaryCounter::dataChanged() +{ + initPins( dataInt("bitcount") ); + + b_triggerHigh = dataString("trig") == "Rising"; + setDisplayText( ">", b_triggerHigh ? "^>" : "_>" ); +} + + +void BinaryCounter::initPins( unsigned numBits ) +{ + if ( m_numBits == numBits ) + return; + + QStringList pins; + pins << "en" << ">" << "u/d" << "r"; + + for ( int i = 0; i < QABS(4-int(numBits)); i++ ) + pins << ""; + + for ( int i = numBits-1; i >= 0; i-- ) + pins << QChar('A'+i); + + initDIPSymbol( pins, 64 ); + initDIP(pins); + + if ( m_numBits < numBits ) + { + for ( unsigned i = m_numBits; i < numBits; i++ ) + m_pLogicOut[i] = createLogicOut( ecNodeWithID( QChar('A'+i) ), false ); + } + else + { + for ( unsigned i = numBits; i < m_numBits; i++ ) + { + QString id = QChar('A'+i); + removeElement( m_pLogicOut[i], false ); + removeDisplayText(id); + removeNode(id); + } + } + + m_numBits = numBits; + m_maxValue = (1<") ); + rLogic = createLogicIn( ecNodeWithID("r") ); + udLogic = createLogicIn( ecNodeWithID("u/d") ); + + enLogic->setCallback( this, (CallbackPtr)(&BinaryCounter::enStateChanged) ); + inLogic->setCallback( this, (CallbackPtr)(&BinaryCounter::inStateChanged) ); + rLogic->setCallback( this, (CallbackPtr)(&BinaryCounter::rStateChanged) ); + udLogic->setCallback( this, (CallbackPtr)(&BinaryCounter::udStateChanged) ); + + m_bDoneLogicIn = true; + } + + outputValue(); +} + + +void BinaryCounter::inStateChanged( bool state ) +{ + if ( (state != b_oldIn) && b_en && !b_reset && state == b_triggerHigh ) + { + m_value += (b_ud) ? 1 : -1; + + if ( m_value < 0 ) + m_value = m_maxValue; + + else if ( m_value > m_maxValue ) + m_value = 0; + + outputValue(); + } + + b_oldIn = state; +} + + +void BinaryCounter::rStateChanged( bool state ) +{ + b_reset = state; + if (b_reset) + { + m_value = 0; + outputValue(); + } +} + + +void BinaryCounter::enStateChanged( bool state ) +{ + b_en = state; +} + + +void BinaryCounter::udStateChanged( bool state ) +{ + b_ud = state; +} + + +void BinaryCounter::outputValue() +{ + for ( unsigned i = 0; i < m_numBits; i++ ) + m_pLogicOut[i]->setHigh( m_value & (1 << i) ); +} + diff --git a/src/electronics/components/binarycounter.h b/src/electronics/components/binarycounter.h new file mode 100644 index 0000000..b15762d --- /dev/null +++ b/src/electronics/components/binarycounter.h @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef EC4BITCOUNTER_H +#define EC4BITCOUNTER_H + +#include "component.h" +#include "logic.h" + +/** +Simple logic counter. 4 Inputs, 4 Outputs. + +Outputs (A-D) represent the stored value (0-15). +The inputs are: +@li en - Enable incrementing of value +@li in - Input (trigger high) +@li r - Reset stored value to 0 +@li ud - Up/Down increment + +@short 4 Bit Binary Counter +@author David Saxton +*/ +class BinaryCounter : public CallbackClass, public Component +{ +public: + BinaryCounter( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~BinaryCounter(); + + virtual bool canFlip() const { return true; } + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void inStateChanged( bool state ); // Input + void rStateChanged( bool state ); // Reset + void enStateChanged( bool state ); // Enable + void udStateChanged( bool state ); // Up/Down + void outputValue(); + void dataChanged(); + void initPins( unsigned numBits ); + + LogicIn *enLogic, *inLogic, *rLogic, *udLogic; + LogicOut * m_pLogicOut[26]; + + unsigned m_numBits; + bool b_triggerHigh; + bool b_en; // Enable + bool b_ud; // Up/Down + bool b_oldIn; + bool b_reset; + long m_value; + long m_maxValue; + bool m_bDoneLogicIn; +}; + +#endif diff --git a/src/electronics/components/bussplitter.cpp b/src/electronics/components/bussplitter.cpp new file mode 100644 index 0000000..62fbb39 --- /dev/null +++ b/src/electronics/components/bussplitter.cpp @@ -0,0 +1,133 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "bussplitter.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "wire.h" + +#include +#include + +Item* BusSplitter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new BusSplitter( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* BusSplitter::libraryItem() +{ + return new LibraryItem( + "ec/bus", + i18n("Bus"), + i18n("Connections"), + "bus.png", + LibraryItem::lit_component, + BusSplitter::construct ); +} + + +const unsigned MAX_BUS_SIZE = 10000; + + +BusSplitter::BusSplitter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "Bus" ) +{ + m_name = i18n("Bus Splitter"); + m_desc = i18n("Merges several connections into one."); + + m_busSize = 0; + init1PinLeft(); + m_pInNode = m_pNNode[0]; + + createProperty( "size", Variant::Type::Int ); + property("size")->setCaption( i18n("Size") ); + property("size")->setMinValue(1); + property("size")->setMaxValue(MAX_BUS_SIZE); + property("size")->setValue(8); +} + + +BusSplitter::~BusSplitter() +{ +} + + +void BusSplitter::dataChanged() +{ + unsigned busSize = dataInt("size"); + + if ( busSize < 1 ) + busSize = 1; + + else if ( busSize > MAX_BUS_SIZE ) + busSize = MAX_BUS_SIZE; + + if ( busSize == m_busSize ) + return; + + m_pInNode->setNumPins(busSize); + + if ( busSize > m_busSize ) + { + m_pWires.resize(busSize); + for ( unsigned i = m_busSize; i < unsigned(busSize); i++ ) + { + Pin * pin = createPin( 16, 0, 180, outNodeID(i) )->pin(); + m_pWires[i] = new Wire( m_pInNode->pin(i), pin ); + } + } + else + { + for ( unsigned i = busSize; i < unsigned(m_busSize); i++ ) + { + removeNode( outNodeID(i) ); + delete m_pWires[i]; + } + m_pWires.resize(busSize); + } + m_busSize = busSize; + + // Position pins + setSize( 0, -int(m_busSize+1)*8, 8, int(m_busSize+1)*16, true ); + for ( int i = 0; i < int(m_busSize); i++ ) + m_nodeMap[ outNodeID(i) ].y = 16*i - int(m_busSize+1)*8 + 24; + m_nodeMap["n1"].y = -int(m_busSize+1)*8 + 8; + + updateAttachedPositioning(); +} + + +QString BusSplitter::outNodeID( unsigned node ) const +{ + return QString("out_%1").arg(QString::number(node)); +} + + +void BusSplitter::drawShape( QPainter &p ) +{ + initPainter(p); + +// QPen pen(p.pen()); +// pen.setWidth(); +// p.setPen(pen); + + int _x = int(x()); + int _y = int(y()); + + QRect r = m_sizeRect; + r.moveBy( _x, _y ); + p.drawRect(r); + + deinitPainter(p); +} + + + diff --git a/src/electronics/components/bussplitter.h b/src/electronics/components/bussplitter.h new file mode 100644 index 0000000..ccd1994 --- /dev/null +++ b/src/electronics/components/bussplitter.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef BUSSPLITTER_H +#define BUSSPLITTER_H + +#include + +#include +#include + +class Wire; + +/** +@author David Saxton +*/ +class BusSplitter : public Component +{ + public: + BusSplitter( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~BusSplitter(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual bool canFlip() const { return true; } + + protected: + QString outNodeID( unsigned node ) const; + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + unsigned m_busSize; + QValueVector > m_pWires; + ECNode * m_pInNode; +}; + +#endif diff --git a/src/electronics/components/demultiplexer.cpp b/src/electronics/components/demultiplexer.cpp new file mode 100644 index 0000000..8a01808 --- /dev/null +++ b/src/electronics/components/demultiplexer.cpp @@ -0,0 +1,175 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "demultiplexer.h" + +#include "logic.h" +#include "libraryitem.h" + +#include +#include + +#include + +Item* Demultiplexer::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Demultiplexer( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Demultiplexer::libraryItem() +{ + return new LibraryItem( + "ec/demultiplexer", + i18n("Demultiplexer"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + Demultiplexer::construct + ); +} + +Demultiplexer::Demultiplexer( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "demultiplexer" ) +{ + m_name = i18n("Demultiplexer"); + m_desc = i18n("Seperates the input data stream into components. The value of the input is passed to the \"X\" output selected by the binary number given by the \"A\" inputs."); + + m_input = 0l; + + createProperty( "addressSize", Variant::Type::Int ); + property("addressSize")->setCaption( i18n("Address Size") ); + property("addressSize")->setMinValue(1); + property("addressSize")->setMaxValue(8); + property("addressSize")->setValue(1); + + // For backwards compatibility + createProperty( "numInput", Variant::Type::Int ); + property("numInput")->setMinValue(-1); + property("numInput")->setValue(-1); + property("numInput")->setHidden(true); +} + +Demultiplexer::~Demultiplexer() +{ +} + + +void Demultiplexer::dataChanged() +{ + if ( hasProperty("numInput") && dataInt("numInput") != -1 ) + { + int addressSize = int( std::ceil( std::log( (double)dataInt("numInput") ) / std::log(2.0) ) ); + property("numInput")->setValue(-1); + + if ( addressSize < 1 ) + addressSize = 1; + else if ( addressSize > 8 ) + addressSize = 8; + + // This function will get called again when we set the value of numInput + property("addressSize")->setValue(addressSize); + return; + } + + if ( hasProperty("numInput") ) + { + m_variantData["numInput"]->deleteLater(); + m_variantData.remove("numInput"); + } + + initPins( unsigned(dataInt("addressSize")) ); +} + + +void Demultiplexer::inStateChanged( bool /*state*/ ) +{ + unsigned long long pos = 0; + for ( unsigned i = 0; i < m_aLogic.size(); ++i ) + { + if ( m_aLogic[i]->isHigh() ) + pos += 1 << i; + } + for ( unsigned i = 0; i < m_xLogic.size(); ++i ) + m_xLogic[i]->setHigh( (pos == i) && m_input->isHigh() ); +} + + +void Demultiplexer::initPins( unsigned newAddressSize ) +{ + unsigned oldAddressSize = m_aLogic.size(); + unsigned long long oldXLogicCount = m_xLogic.size(); + unsigned long long newXLogicCount = 1 << newAddressSize; + + if ( newXLogicCount == oldXLogicCount ) + return; + + QStringList pins; + + for ( unsigned i=0; i=0; --i ) + pins += "X"+QString::number(i); + + initDIPSymbol( pins, 64 ); + initDIP(pins); + + ECNode *node; + + if (!m_input) + { + node = ecNodeWithID("X"); + m_input = createLogicIn(node); + m_input->setCallback( this, (CallbackPtr)(&Demultiplexer::inStateChanged) ); + } + + if ( newXLogicCount > oldXLogicCount ) + { + m_xLogic.resize(newXLogicCount); + for ( unsigned i = oldXLogicCount; i < newXLogicCount; ++i ) + { + node = ecNodeWithID("X"+QString::number(i)); + m_xLogic.insert( i, createLogicOut(node,false) ); + } + + m_aLogic.resize(newAddressSize); + for ( unsigned i = oldAddressSize; i < newAddressSize; ++i ) + { + node = ecNodeWithID("A"+QString::number(i)); + m_aLogic.insert( i, createLogicIn(node) ); + m_aLogic[i]->setCallback( this, (CallbackPtr)(&Demultiplexer::inStateChanged) ); + } + } + else + { + for ( unsigned i = newXLogicCount; i < oldXLogicCount; ++i ) + { + QString id = "X"+QString::number(i); + removeDisplayText(id); + removeElement( m_xLogic[i], false ); + removeNode(id); + } + m_xLogic.resize(newXLogicCount); + + for ( unsigned i = newAddressSize; i < oldAddressSize; ++i ) + { + QString id = "A"+QString::number(i); + removeDisplayText(id); + removeElement( m_aLogic[i], false ); + removeNode(id); + } + m_aLogic.resize(newAddressSize); + } +} + diff --git a/src/electronics/components/demultiplexer.h b/src/electronics/components/demultiplexer.h new file mode 100644 index 0000000..a2b52dd --- /dev/null +++ b/src/electronics/components/demultiplexer.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef DEMULTIPLEXER_H +#define DEMULTIPLEXER_H + +#include "component.h" +#include "logic.h" + +#include + +/** +@author David Saxton +*/ +class Demultiplexer : public CallbackClass, public Component +{ +public: + Demultiplexer( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Demultiplexer(); + + virtual bool canFlip() const { return true; } + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void dataChanged(); + /** + * Add / remove pins according to the number of inputs the user has requested + */ + void initPins( unsigned addressSize ); + + void inStateChanged( bool newState ); + + QPtrVector m_aLogic; + QPtrVector m_xLogic; + LogicIn * m_input; +}; + +#endif diff --git a/src/electronics/components/dependentsource.cpp b/src/electronics/components/dependentsource.cpp new file mode 100644 index 0000000..764cc53 --- /dev/null +++ b/src/electronics/components/dependentsource.cpp @@ -0,0 +1,314 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "dependentsource.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "pin.h" + +#include "cccs.h" +#include "ccvs.h" +#include "vccs.h" +#include "vcvs.h" + +#include +#include + +//BEGIN class DependentSource +DependentSource::DependentSource( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ) +{ + setSize( -16, -16, 32, 32 ); + + init2PinLeft(); + init2PinRight(); + + createProperty( "gain", Variant::Type::Double ); + property("gain")->setCaption( i18n("Gain") ); + property("gain")->setValue(1.0); + + addDisplayText( "gain", QRect( -16, -32, 32, 16 ), "" ); +} + + +DependentSource::~DependentSource() +{ +} + + +void DependentSource::drawOutline( QPainter & p ) +{ + const int _x = (int)x()-16; + const int _y = (int)y()-32; + + // Top rectangle + p.drawRect( _x, _y+19, width(), 11 ); + + p.save(); + bool canSetCol = (p.pen().color() != Qt::color0) && (p.pen().color() != Qt::color1); + + // Bottom lines + if (canSetCol) + p.setPen( m_pNNode[1]->isSelected() ? m_selectedCol : Qt::black ); + p.drawLine( _x, _y+40, _x+8, _y+40 ); // Left inny + + if (canSetCol) + p.setPen( m_pPNode[1]->isSelected() ? m_selectedCol : Qt::black ); + p.drawLine( _x+width(), _y+40, _x+24, _y+40 ); // Right inny + + p.restore(); + + // Bottom diamond + QPointArray pa4(4); + pa4[0] = QPoint( _x+6, _y+40 ); + pa4[1] = QPoint( _x+16, _y+32 ); + pa4[2] = QPoint( _x+26, _y+40 ); + pa4[3] = QPoint( _x+16, _y+48 ); + p.drawPolygon(pa4); +} + + +void DependentSource::drawTopArrow( QPainter & p ) +{ + const int _x = (int)x()-16; + const int _y = (int)y()-32; + + if ( p.pen().color() == m_selectedCol ) + p.setPen(Qt::black); + + if ( p.brush().color() == m_brushCol ) + p.setBrush(Qt::black); + + p.drawLine( _x+8, _y+24, _x+24, _y+24 ); + + QPointArray pa3(3); + pa3[0] = QPoint( _x+24, _y+24 ); + pa3[1] = QPoint( _x+19, _y+21 ); + pa3[2] = QPoint( _x+19, _y+27 ); + p.drawPolygon(pa3); +} + + +void DependentSource::drawBottomArrow( QPainter & p ) +{ + const int _x = (int)x()-16; + const int _y = (int)y()-32; + + if ( p.pen().color() == m_selectedCol ) + p.setPen(Qt::black); + + if ( p.brush().color() == m_brushCol ) + p.setBrush(Qt::black); + + p.drawLine( _x+11, _y+40, _x+21, _y+40 ); + + QPointArray pa3(3); + pa3[0] = QPoint( _x+21, _y+40 ); + pa3[1] = QPoint( _x+16, _y+37 ); + pa3[2] = QPoint( _x+16, _y+43 ); + p.drawPolygon(pa3); +} +//END class DependentSource + + +//BEGIN class ECCCCS +Item* ECCCCS::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECCCCS( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECCCCS::libraryItem() +{ + return new LibraryItem( + QString("ec/cccs"), + i18n("CCCS"), + i18n("Sources"), + "cccs.png", + LibraryItem::lit_component, + ECCCCS::construct ); +} + +ECCCCS::ECCCCS( ICNDocument *icnDocument, bool newItem, const char *id ) + : DependentSource( icnDocument, newItem, id ? id : "cccs" ) +{ + m_name = i18n("Current Controlled Currrent Source"); + m_cccs = createCCCS( m_pNNode[0], m_pPNode[0], m_pNNode[1], m_pPNode[1], 1. ); + m_pNNode[1]->pin()->setGroundType( Pin::gt_medium ); +} + +ECCCCS::~ECCCCS() +{ +} + +void ECCCCS::dataChanged() +{ + double gain = dataDouble("gain"); + + QString display = QString::number( gain / getMultiplier(gain), 'g', 3 ) + getNumberMag(gain) + QChar(' '); + setDisplayText( "gain", display ); + + m_cccs->setGain(gain); +} + +void ECCCCS::drawShape( QPainter &p ) +{ + initPainter(p); + drawOutline(p); + drawTopArrow(p); + drawBottomArrow(p); + deinitPainter(p); +} +//END class ECCCCS + + +//BEGIN class ECCCVS +Item* ECCCVS::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECCCVS( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECCCVS::libraryItem() +{ + return new LibraryItem( + QString("ec/ccvs"), + i18n("CCVS"), + i18n("Sources"), + "ccvs.png", + LibraryItem::lit_component, + ECCCVS::construct ); +} + +ECCCVS::ECCCVS( ICNDocument *icnDocument, bool newItem, const char *id ) + : DependentSource( icnDocument, newItem, id ? id : "ccvs" ) +{ + m_name = i18n("Current Controlled Voltage Source"); + m_ccvs = createCCVS( m_pNNode[0], m_pPNode[0], m_pNNode[1], m_pPNode[1], 1. ); + m_pNNode[1]->pin()->setGroundType( Pin::gt_medium ); +} + +ECCCVS::~ECCCVS() +{ +} + +void ECCCVS::dataChanged() +{ + double gain = dataDouble("gain"); + + QString display = QString::number( gain / getMultiplier(gain), 'g', 3 ) + getNumberMag(gain) + QChar(' '); + setDisplayText( "gain", display ); + + m_ccvs->setGain(gain); +} + +void ECCCVS::drawShape( QPainter &p ) +{ + initPainter(p); + drawOutline(p); + drawTopArrow(p); + deinitPainter(p); +} +//END class ECCCVS + + +//BEGIN class ECVCCS +Item* ECVCCS::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECVCCS( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECVCCS::libraryItem() +{ + return new LibraryItem( + QString("ec/vccs"), + i18n("VCCS"), + i18n("Sources"), + "vccs.png", + LibraryItem::lit_component, + ECVCCS::construct ); +} + +ECVCCS::ECVCCS( ICNDocument *icnDocument, bool newItem, const char *id ) + : DependentSource( icnDocument, newItem, id ? id : "vccs" ) +{ + m_name = i18n("Voltage Controlled Current Source"); + m_vccs = createVCCS( m_pNNode[0], m_pPNode[0], m_pNNode[1], m_pPNode[1], 1. ); + m_pNNode[1]->pin()->setGroundType( Pin::gt_medium ); +} + +ECVCCS::~ECVCCS() +{ +} + +void ECVCCS::dataChanged() +{ + double gain = dataDouble("gain"); + + QString display = QString::number( gain / getMultiplier(gain), 'g', 3 ) + getNumberMag(gain) + QChar(' '); + setDisplayText( "gain", display ); + + m_vccs->setGain(gain); +} + +void ECVCCS::drawShape( QPainter &p ) +{ + initPainter(p); + drawOutline(p); + drawBottomArrow(p); + deinitPainter(p); +} +//END class ECVCCS + + +//BEGIN class ECVCVS +Item* ECVCVS::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECVCVS( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECVCVS::libraryItem() +{ + return new LibraryItem( + QString("ec/vcvs"), + i18n("VCVS"), + i18n("Sources"), + "vcvs.png", + LibraryItem::lit_component, + ECVCVS::construct ); +} + +ECVCVS::ECVCVS( ICNDocument *icnDocument, bool newItem, const char *id ) + : DependentSource( icnDocument, newItem, id ? id : "vcvs" ) +{ + m_name = i18n("Voltage Controlled Voltage Source"); + m_vcvs = createVCVS( m_pNNode[0], m_pPNode[0], m_pNNode[1], m_pPNode[1], 1. ); + m_pNNode[1]->pin()->setGroundType( Pin::gt_medium ); +} + +ECVCVS::~ECVCVS() +{ +} + +void ECVCVS::dataChanged() +{ + double gain = dataDouble("gain"); + + QString display = QString::number( gain / getMultiplier(gain), 'g', 3 ) + getNumberMag(gain) + QChar(' '); + setDisplayText( "gain", display ); + + m_vcvs->setGain(gain); +} + +void ECVCVS::drawShape( QPainter &p ) +{ + initPainter(p); + drawOutline(p); + deinitPainter(p); +} +//END class ECVCVS diff --git a/src/electronics/components/dependentsource.h b/src/electronics/components/dependentsource.h new file mode 100644 index 0000000..2bccbb7 --- /dev/null +++ b/src/electronics/components/dependentsource.h @@ -0,0 +1,112 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef DEPENDENTSOURCE_H +#define DEPENDENTSOURCE_H + +#include "component.h" + +/** +@author David Saxton +*/ +class DependentSource : public Component +{ + public: + DependentSource( ICNDocument *icnDocument, bool newItem, const char *id ); + ~DependentSource(); + virtual bool canFlip() const { return true; } + + protected: + void drawOutline( QPainter & p ); + void drawTopArrow( QPainter & p ); + void drawBottomArrow( QPainter & p ); +}; + +/** +@short Current Controlled Current Source +@author David Saxton +*/ +class ECCCCS : public DependentSource +{ + public: + ECCCCS( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECCCCS(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + CCCS *m_cccs; +}; + +/** +@short Current Controlled Voltage Source +@author David Saxton +*/ +class ECCCVS : public DependentSource +{ + public: + ECCCVS( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECCCVS(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + CCVS *m_ccvs; +}; + +/** +@short Voltage Controlled Current Source +@author David Saxton +*/ +class ECVCCS : public DependentSource +{ + public: + ECVCCS( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECVCCS(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + VCCS *m_vccs; +}; + +/** +@short Voltage Controlled Voltage Source +@author David Saxton +*/ +class ECVCVS : public DependentSource +{ + public: + ECVCVS( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECVCVS(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + VCVS *m_vcvs; +}; + +#endif diff --git a/src/electronics/components/discretelogic.cpp b/src/electronics/components/discretelogic.cpp new file mode 100644 index 0000000..e2e284e --- /dev/null +++ b/src/electronics/components/discretelogic.cpp @@ -0,0 +1,308 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasitemparts.h" +#include "discretelogic.h" +#include "ecnode.h" +#include "logic.h" +#include "libraryitem.h" +#include "simulator.h" + +#include +#include + + +//BEGIN class Inverter +Item* Inverter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Inverter( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Inverter::libraryItem() +{ + QStringList ids; + ids << "ec/inverter" << "ec/not"; + return new LibraryItem( + ids, + i18n("Inverter"), + i18n("Logic"), + "not.png", + LibraryItem::lit_component, + Inverter::construct ); +} + +Inverter::Inverter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "not" ) +{ + m_name = i18n("Inverter"); + m_desc = i18n("The output is the logical inverse of the logic-input state."); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_pIn = createLogicIn(m_pNNode[0]); + m_pOut = createLogicOut( m_pPNode[0], true ); + + m_pIn->setCallback( this, (CallbackPtr)(&Inverter::inStateChanged) ); + inStateChanged(false); +} + + +Inverter::~Inverter() +{ +} + + +void Inverter::inStateChanged( bool newState ) +{ + (static_cast(m_pOut))->setHigh( !newState ); +} + + +void Inverter::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()-8; + int _y = (int)y()-8; + QPointArray pa(3); + pa[0] = QPoint( _x, _y ); + pa[1] = QPoint( _x+width()-6, _y+(height()/2) ); + pa[2] = QPoint( _x, _y+height() ); + p.drawPolygon(pa); + p.drawPolyline(pa); + p.drawEllipse( _x+width()-6, _y+(height()/2)-3, 7, 7 ); + deinitPainter(p); +} +//END class Inverter + + +//BEGIN class Buffer +Item* Buffer::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Buffer( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Buffer::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/buffer"), + i18n("Buffer"), + i18n("Logic"), + "buffer.png", + LibraryItem::lit_component, + Buffer::construct ); +} + +Buffer::Buffer( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "buffer" ) +{ + m_name = i18n("Buffer"); + m_desc = i18n("Cleans the logic input, with the output high or low depending on input trigger levels."); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_pIn = createLogicIn(m_pNNode[0]); + m_pOut = createLogicOut( m_pPNode[0], true ); + + m_pIn->setCallback( this, (CallbackPtr)(&Buffer::inStateChanged) ); + inStateChanged(false); +} + + +Buffer::~Buffer() +{ +} + + +void Buffer::inStateChanged( bool newState ) +{ + m_pOut->setHigh(newState); +} + + +void Buffer::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()-8; + int _y = (int)y()-8; + QPointArray pa(3); + pa[0] = QPoint( _x, _y ); + pa[1] = QPoint( _x+width(), _y+(height()/2) ); + pa[2] = QPoint( _x, _y+height() ); + p.drawPolygon(pa); + p.drawPolyline(pa); + deinitPainter(p); +} +//END class Buffer + + +//BEGIN class ECLogicInput +Item* ECLogicInput::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECLogicInput( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECLogicInput::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/logic_input"), + i18n("Logic Input"), + i18n("Logic"), + "logic_input.png", + LibraryItem::lit_component, + ECLogicInput::construct ); +} + +ECLogicInput::ECLogicInput( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "logic_input" ) +{ + m_name = i18n("Logic Input"); + m_desc = i18n("Provides a user-adjustable logic state.

    " + "Click to pulse high, or drag the mouse off to keep the output high."); + setSize( -8, -8, 16, 16 ); + + b_state = false; + addButton( "button", QRect( -24, -8, 16, 16 ), "", true ); + + createProperty( "useToggle", Variant::Type::Bool ); + property("useToggle")->setCaption( i18n("Use Toggle") ); + property("useToggle")->setValue(true); + + init1PinRight(); + + m_pOut = createLogicOut( m_pPNode[0], false ); +} + + +ECLogicInput::~ECLogicInput() +{ +} + + +void ECLogicInput::dataChanged() +{ + button("button")->setToggle( dataBool("useToggle") ); +} + + +void ECLogicInput::drawShape( QPainter &p ) +{ + initPainter(p); + if (b_state) + p.setBrush( QColor( 255, 166, 0 ) ); + else + p.setBrush( Qt::white ); + p.drawEllipse( (int)x()-4, (int)y()-6, 12, 12 ); + deinitPainter(p); +} + + +void ECLogicInput::buttonStateChanged( const QString &, bool state ) +{ + b_state = state; + m_pOut->setHigh(b_state); +} +//END class ECLogicInput + + +//BEGIN class ECLogicOutput +Item* ECLogicOutput::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECLogicOutput( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECLogicOutput::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/logic_output"), + i18n("Logic Output"), + i18n("Logic"), + "logic_output.png", + LibraryItem::lit_component, + ECLogicOutput::construct ); +} + +ECLogicOutput::ECLogicOutput( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "logic_output" ) +{ + m_name = i18n("Logic Output"); + m_desc = i18n("Shows the logic-state of the input."); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + m_pIn = createLogicIn(m_pNNode[0]); + + m_pSimulator = Simulator::self(); + + m_lastDrawState = 0.0; + m_lastSwitchTime = m_lastDrawTime = m_pSimulator->time(); + m_highTime = 0; + m_bLastState = false; + m_bDynamicContent = true; + + m_pIn->setCallback( this, (CallbackPtr)(&ECLogicOutput::inStateChanged) ); +} + +ECLogicOutput::~ECLogicOutput() +{ +} + +void ECLogicOutput::inStateChanged( bool newState ) +{ + if ( m_bLastState == newState ) + return; + + unsigned long long newTime = m_pSimulator->time(); + unsigned long long dt = newTime - m_lastSwitchTime; + + m_lastSwitchTime = newTime; + + m_bLastState = newState; + if (!newState) + { + // Gone from high to low + m_highTime += dt; + } +} + + +void ECLogicOutput::drawShape( QPainter &p ) +{ + unsigned long long newTime = m_pSimulator->time(); + unsigned long long runTime = newTime - m_lastDrawTime; + m_lastDrawTime = newTime; + + if (m_bLastState) + { + // Logic in is currently high + m_highTime += newTime - m_lastSwitchTime; + } + + double state; + + if ( runTime == 0 ) + state = m_lastDrawState; + + else + state = m_lastDrawState = double(m_highTime)/double(runTime); + + initPainter(p); + p.setBrush( QColor( 255, uint(255-state*(255-166)), uint((1-state)*255) ) ); + p.drawEllipse( int(x()-8), int(y()-8), width(), height() ); + deinitPainter(p); + + m_lastSwitchTime = newTime; + m_highTime = 0; +} +//END class ECLogicOutput + diff --git a/src/electronics/components/discretelogic.h b/src/electronics/components/discretelogic.h new file mode 100644 index 0000000..82775bf --- /dev/null +++ b/src/electronics/components/discretelogic.h @@ -0,0 +1,110 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef DISCRETELOGIC_H +#define DISCRETELOGIC_H + +#include "component.h" +#include "logic.h" + +class Simulator; + +/** +@short Boolean NOT +@author David Saxton +*/ +class Inverter : public CallbackClass, public Component +{ + public: + Inverter( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Inverter(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); + + LogicIn * m_pIn; + LogicOut * m_pOut; +}; + +/** +@short Buffer +@author David Saxton +*/ +class Buffer : public CallbackClass, public Component +{ +public: + Buffer( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Buffer(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); + + LogicIn * m_pIn; + LogicOut * m_pOut; +}; + +/** +@short Boolean logic input +@author David Saxton +*/ +class ECLogicInput : public Component +{ +public: + ECLogicInput( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECLogicInput(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + +private: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + LogicOut * m_pOut; + bool b_state; +}; + +/** +@short Boolean logic output +@author David Saxton +*/ +class ECLogicOutput : public CallbackClass, public Component +{ + public: + ECLogicOutput( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECLogicOutput(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); + + unsigned long long m_lastDrawTime; + unsigned long long m_lastSwitchTime; + unsigned long long m_highTime; + bool m_bLastState; + + double m_lastDrawState; + LogicIn * m_pIn; + Simulator * m_pSimulator; +}; + +#endif diff --git a/src/electronics/components/ec555.cpp b/src/electronics/components/ec555.cpp new file mode 100644 index 0000000..eccf2bd --- /dev/null +++ b/src/electronics/components/ec555.cpp @@ -0,0 +1,172 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "ec555.h" + +#include "ecnode.h" +#include "libraryitem.h" +#include "pin.h" +#include "resistance.h" + +#include +#include +#include + +Item* EC555::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new EC555( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* EC555::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/555"), + i18n("555"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + EC555::construct + ); +} + +EC555::EC555( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "555" ) +{ + m_name = i18n("555"); + m_desc = i18n("Common timer IC"); +// m_pins = QStringList::split( ',', "Gnd,Trg,Out,Res,CV,Th,Dis,Vcc" ); +// m_pins = QStringList::split( ',', "Dis,Th,Trg,Gnd,CV,Out,Res,Vcc" ); + + old_com1 = false; + old_com2 = false; + old_q = false; + + setSize( -32, -32, 64, 64 ); + + + // Pins down left + + // Pin 7 + discharge = createPin( -40, -16, 0, "Dis" )->pin(); + addDisplayText( "dis", QRect( -32, -24, 24, 16 ), "Dis" ); + + // Pin 6 + threshold = createPin( -40, 0, 0, "Th" )->pin(); + addDisplayText( "th", QRect( -32, -8, 24, 16 ), "Th" ); + + // Pin 2 + trigger = createPin( -40, 16, 0, "Trg" )->pin(); + addDisplayText( "trg", QRect( -32, 8, 24, 16 ), "Trg" ); + + + + // Top two + + // Pin 8 + vcc = createPin( -16, -40, 90, "Vcc" )->pin(); + addDisplayText( "vcc", QRect( -24, -32, 16, 8 ), "+" ); + + // Pin 4 + reset = createPin( 16, -40, 90, "Res" )->pin(); + addDisplayText( "res", QRect( 8, -28, 16, 16 ), "Res" ); + + + + // Bottom two + + // Pin 1 + ground = createPin( -16, 40, 270, "Gnd" )->pin(); + addDisplayText( "gnd", QRect( -24, 20, 16, 8 ), "-" ); + + // Pin 5 + control = createPin( 16, 40, 270, "CV" )->pin(); + addDisplayText( "cv", QRect( 8, 12, 16, 16 ), "CV" ); + + + + // Output on right + + // Pin 3 + output = createPin( 40, 0, 180, "Out" )->pin(); + addDisplayText( "out", QRect( 8, -8, 16, 16 ), "Out" ); + + + + m_r1 = createResistance( vcc, control, 5e3 ); + m_r23 = createResistance( control, ground, 1e4 ); + m_po_sink = createResistance( output, ground, 0. ); + m_po_source = createResistance( output, vcc, 0. ); + m_po_source->setConductance(0.); + m_r_discharge = createResistance( discharge, ground, 0. ); +} + + +EC555::~EC555() +{ +} + +void EC555::stepNonLogic() +{ + double v_threshold = threshold->voltage(); + double v_control = control->voltage(); + double v_ground = ground->voltage(); + double v_trigger = trigger->voltage(); + double v_reset = reset->voltage(); + double v_vcc = vcc->voltage(); + + double v_r = (v_control+v_ground)/2; + + bool com1 = ( v_threshold == v_control ) ? old_com1 : ( v_threshold < v_control ); + bool com2 = ( v_r == v_trigger ) ? old_com2 : ( v_r > v_trigger ); + bool reset = ( v_reset >= (v_control-v_ground)/2 + v_ground ); + old_com1 = com1; + old_com2 = com2; + + bool r = ( !reset || !com1 ); + bool s = com2; + + bool q = old_q; + if ( v_vcc - v_ground >= 2.5 ) + { + if ( s && !r ) + { + q = true; + } + else if ( r && !s ) + { + q = false; + } + } + else + { + q = false; + } + old_q = q; + + + m_r_discharge->setConductance(0.); + + if (q) + { + m_po_source->setResistance(10.); + m_po_sink->setConductance(0.); + } + else + { + m_po_source->setConductance(0.); + m_po_sink->setResistance(10.); + if ( v_ground+0.7 <= v_vcc ) + { + m_r_discharge->setResistance(10.); + } + } +} + + diff --git a/src/electronics/components/ec555.h b/src/electronics/components/ec555.h new file mode 100644 index 0000000..edeb2a5 --- /dev/null +++ b/src/electronics/components/ec555.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef EC555_H +#define EC555_H + +#include "component.h" + +#include + +/** +@short 555 IC +@author David Saxton +*/ +class EC555 : public Component +{ +public: + EC555( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~EC555(); + + virtual bool canFlip() const { return true; } + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + +private: + Pin * ground; + Pin * trigger; + Pin * output; + Pin * reset; + Pin * control; + Pin * threshold; + Pin * discharge; + Pin * vcc; + + Resistance *m_r1; + Resistance *m_r23; + Resistance *m_po_sink; + Resistance *m_po_source; + Resistance *m_r_discharge; + + bool old_com1; + bool old_com2; + bool old_q; +}; + +#endif diff --git a/src/electronics/components/ecbcdto7segment.cpp b/src/electronics/components/ecbcdto7segment.cpp new file mode 100644 index 0000000..fb210ea --- /dev/null +++ b/src/electronics/components/ecbcdto7segment.cpp @@ -0,0 +1,158 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "ecbcdto7segment.h" + +#include "logic.h" +#include "libraryitem.h" + +#include +#include + +// Values for a,b,c,d,e,f,g of common-anode 7 segment display +bool numbers[16][7] = + { { 1, 1, 1, 1, 1, 1, 0 }, // 0 + { 0, 1, 1, 0, 0, 0, 0 }, // 1 + { 1, 1, 0, 1, 1, 0, 1 }, // 2 + { 1, 1, 1, 1, 0, 0, 1 }, // 3 + { 0, 1, 1, 0 ,0, 1, 1 }, // 4 + { 1, 0, 1, 1, 0, 1, 1 }, // 5 + { 1, 0, 1, 1, 1, 1, 1 }, // 6 + { 1, 1, 1, 0, 0, 0, 0 }, // 7 + { 1, 1, 1, 1, 1, 1, 1 }, // 8 + { 1, 1, 1, 0, 0, 1, 1 }, // 9 + { 1, 1, 1, 0, 1, 1, 1 }, // A + { 0, 0, 1, 1, 1, 1, 1 }, // b + { 1, 0, 0, 1, 1, 1, 0 }, // C + { 0, 1, 1, 1, 1, 0, 1 }, // d + { 1, 0, 0, 1, 1, 1, 1 }, // E + { 1, 0, 0, 0, 1, 1, 1 } }; // F + +Item* ECBCDTo7Segment::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECBCDTo7Segment( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECBCDTo7Segment::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/bcd_to_seven_segment"), + i18n("BCD to 7 Segment"), + i18n("Integrated Circuits"), + "ic2.png", + LibraryItem::lit_component, + ECBCDTo7Segment::construct + ); +} + +ECBCDTo7Segment::ECBCDTo7Segment( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "bcd_to_seven_segment" ) +{ + m_name = i18n("BCD to Seven Segment"); + m_desc = i18n("Converts a binary-coded-input to a form displayable by a seven segment display.

    " + "Normal operation: lt (Lamp Test) and the rb (Ripple Blanking) are held high, en (Enable) is held low."); + + ALogic = BLogic = CLogic = DLogic = 0L; + ltLogic = rbLogic = enLogic = 0L; + + for ( int i=0; i<7; i++ ) + { + outLogic[i] = 0L; + oldOut[i] = false; + } + + QStringList pins = QStringList::split( ',', "A,B,C,D,,lt,rb,en,d,e,f,g,,a,b,c", true ); + initDIPSymbol( pins, 48 ); + initDIP(pins); + + ALogic = createLogicIn( ecNodeWithID("A") ); + BLogic = createLogicIn( ecNodeWithID("B") ); + CLogic = createLogicIn( ecNodeWithID("C") ); + DLogic = createLogicIn( ecNodeWithID("D") ); + ltLogic = createLogicIn( ecNodeWithID("lt") ); + rbLogic = createLogicIn( ecNodeWithID("rb") ); + enLogic = createLogicIn( ecNodeWithID("en") ); + + ALogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + BLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + CLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + DLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + ltLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + rbLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + enLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + + for ( uint i=0; i<7; ++i ) + { + outLogic[i] = createLogicOut( ecNodeWithID( QChar('a'+i) ), false ); + outLogic[i]->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + } + inStateChanged(false); +} + +ECBCDTo7Segment::~ECBCDTo7Segment() +{ +} + +void ECBCDTo7Segment::inStateChanged(bool) +{ + bool A = ALogic->isHigh(); + bool B = BLogic->isHigh(); + bool C = CLogic->isHigh(); + bool D = DLogic->isHigh(); + bool lt = ltLogic->isHigh(); // Lamp test + bool rb = rbLogic->isHigh(); // Ripple Blank + bool en = enLogic->isHigh(); // Enable (store) + + int n = A + 2*B + 4*C + 8*D; +// if ( n > 9 ) n = 0; + + bool out[7]; + + if (lt) // Lamp test + { + if (rb) // Ripple blanking + { + if (en) // Enable (store) + { + for ( int i=0; i<7; i++ ) + { + out[i] = oldOut[i]; + } + } + else + { + for ( int i=0; i<7; i++ ) + { + out[i] = numbers[n][i]; + oldOut[i] = out[i]; + } + } + } + else + { + for ( int i=0; i<7; i++ ) + { + out[i] = false; + } + } + } + else + { + for ( int i=0; i<7; i++ ) + { + out[i] = true; + } + } + + for ( int i=0; i<7; i++ ) + { + outLogic[i]->setHigh( out[i] ); + } +} diff --git a/src/electronics/components/ecbcdto7segment.h b/src/electronics/components/ecbcdto7segment.h new file mode 100644 index 0000000..03d4c2b --- /dev/null +++ b/src/electronics/components/ecbcdto7segment.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECBCDTO7SEGMENT_H +#define ECBCDTO7SEGMENT_H + +#include "component.h" +#include "logic.h" + +/** +@short Converts a BCD input to 7-Segment Output +@author David Saxton +*/ +class ECBCDTo7Segment : public CallbackClass, public Component +{ +public: + ECBCDTo7Segment( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECBCDTo7Segment(); + + virtual bool canFlip() const { return true; } + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + LogicIn *ALogic, *BLogic, *CLogic, *DLogic; + LogicIn *ltLogic, *rbLogic, *enLogic; + LogicOut *outLogic[7]; + + // Old values + bool oldOut[7]; +}; + +#endif diff --git a/src/electronics/components/ecbjt.cpp b/src/electronics/components/ecbjt.cpp new file mode 100644 index 0000000..b4b59f2 --- /dev/null +++ b/src/electronics/components/ecbjt.cpp @@ -0,0 +1,153 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "bjt.h" +#include "ecbjt.h" +#include "ecnode.h" +#include "libraryitem.h" + +#include +#include +#include + +Item * ECBJT::constructNPN( ItemDocument * itemDocument, bool newItem, const char * id ) +{ + return new ECBJT( true, (ICNDocument*)itemDocument, newItem, id ); +} + + +Item * ECBJT::constructPNP( ItemDocument * itemDocument, bool newItem, const char * id ) +{ + return new ECBJT( false, (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* ECBJT::libraryItemNPN() +{ + return new LibraryItem( + "ec/npnbjt", + i18n("NPN"), + i18n("Discrete"), + "npn.png", + LibraryItem::lit_component, + ECBJT::constructNPN ); +} + + +LibraryItem* ECBJT::libraryItemPNP() +{ + return new LibraryItem( + "ec/pnpbjt", + i18n("PNP"), + i18n("Discrete"), + "pnp.png", + LibraryItem::lit_component, + ECBJT::constructPNP ); +} + + +ECBJT::ECBJT( bool isNPN, ICNDocument * icnDocument, bool newItem, const char * id ) + : Component( icnDocument, newItem, id ? id : (isNPN ? "npnbjt" : "pnpbjt") ) +{ + m_bIsNPN = isNPN; + if ( m_bIsNPN ) + m_name = i18n("NPN Transistor"); + else + m_name = i18n("PNP Transistor"); + + setSize( -8, -8, 16, 16 ); + m_pBJT = createBJT( createPin( 8, -16, 90, "c" ), createPin( -16, 0, 0, "b" ), createPin( 8, 16, 270, "e" ), m_bIsNPN ); + + BJTSettings s; // will be created with the default settings + + Variant * v = createProperty( "I_S", Variant::Type::Double ); + v->setCaption("Saturation Current"); + v->setUnit("A"); + v->setMinValue(1e-20); + v->setMaxValue(1e-0); + v->setValue( s.I_S ); + v->setAdvanced(true); + + v = createProperty( "N_F", Variant::Type::Double ); + v->setCaption( i18n("Forward Coefficient") ); + v->setMinValue(1e0); + v->setMaxValue(1e1); + v->setValue( s.N_F ); + v->setAdvanced(true); + + v = createProperty( "N_R", Variant::Type::Double ); + v->setCaption( i18n("Reverse Coefficient") ); + v->setMinValue(1e0); + v->setMaxValue(1e1); + v->setValue( s.N_R ); + v->setAdvanced(true); + + v = createProperty( "B_F", Variant::Type::Double ); + v->setCaption( i18n("Forward Beta") ); + v->setMinValue(1e-1); + v->setMaxValue(1e3); + v->setValue( s.B_F ); + v->setAdvanced(true); + + v = createProperty( "B_R", Variant::Type::Double ); + v->setCaption( i18n("Reverse Beta") ); + v->setMinValue(1e-1); + v->setMaxValue(1e3); + v->setValue( s.B_R ); + v->setAdvanced(true); +} + +ECBJT::~ECBJT() +{ +} + + +void ECBJT::dataChanged() +{ + BJTSettings s; + s.I_S = dataDouble( "I_S" ); + s.N_F = dataDouble( "N_F" ); + s.N_R = dataDouble( "N_R" ); + s.B_F = dataDouble( "B_F" ); + s.B_R = dataDouble( "B_R" ); + + m_pBJT->setBJTSettings( s ); +} + + +void ECBJT::drawShape( QPainter &p ) +{ + const int _x = int(x()); + const int _y = int(y()); + + initPainter(p); + + p.drawLine( _x-8, _y-8, _x-8, _y+8 ); + p.drawLine( _x+8, _y-8, _x-8, _y ); + p.drawLine( _x+8, _y+8, _x-8, _y ); + + QPointArray pa(3); + if ( m_bIsNPN ) + { + pa[0] = QPoint( _x+6, _y+7 ); + pa[1] = QPoint( _x+2, _y+8 ); + pa[2] = QPoint( _x+6, _y+3 ); + } + else + { + pa[0] = QPoint( _x-7, _y+1 ); + pa[1] = QPoint( _x-4, _y+5 ); + pa[2] = QPoint( _x-2, _y ); + } + p.setBrush( p.pen().color() ); + p.drawPolygon(pa); + + deinitPainter(p); +} diff --git a/src/electronics/components/ecbjt.h b/src/electronics/components/ecbjt.h new file mode 100644 index 0000000..17a63e9 --- /dev/null +++ b/src/electronics/components/ecbjt.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECBJT_H +#define ECBJT_H + +#include "component.h" + +class BJT; + +/** +@short Simulates a BJT +@author David Saxton +*/ +class ECBJT : public Component +{ + public: + ECBJT( bool isNPN, ICNDocument *icnDocument, bool newItem, const char * id = 0L ); + ~ECBJT(); + virtual bool canFlip() const { return true; } + + static Item * constructNPN( ItemDocument * itemDocument, bool newItem, const char * id ); + static Item * constructPNP( ItemDocument * itemDocument, bool newItem, const char * id ); + static LibraryItem * libraryItemNPN(); + static LibraryItem * libraryItemPNP(); + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + bool m_bIsNPN; + BJT * m_pBJT; +}; + +#endif diff --git a/src/electronics/components/eccapacitor.cpp b/src/electronics/components/eccapacitor.cpp new file mode 100644 index 0000000..76a09b0 --- /dev/null +++ b/src/electronics/components/eccapacitor.cpp @@ -0,0 +1,92 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "capacitance.h" +#include "eccapacitor.h" +#include "ecnode.h" +#include "libraryitem.h" + +#include +#include + +Item* ECCapacitor::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECCapacitor( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECCapacitor::libraryItem() +{ + return new LibraryItem( + "ec/capacitor", + i18n("Capacitor"), + i18n("Discrete"), + "capacitor.png", + LibraryItem::lit_component, + ECCapacitor::construct + ); +} + +ECCapacitor::ECCapacitor( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "capacitor" ) +{ + m_name = i18n("Capacitor"); + m_desc = i18n("Stores electrical charge.

    " + "The voltage across the capacitor and capacitance are related by Charge = Capacitance x Voltage."); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_capacitance = createCapacitance( m_pNNode[0], m_pPNode[0], 0.001 ); + + createProperty( "Capacitance", Variant::Type::Double ); + property("Capacitance")->setCaption( i18n("Capacitance") ); + property("Capacitance")->setUnit("F"); + property("Capacitance")->setMinValue(1e-12); + property("Capacitance")->setMaxValue(1e12); + property("Capacitance")->setValue(1e-3); + + addDisplayText( "capacitance", QRect( -8, -24, 16, 16 ), "", false ); +} + +ECCapacitor::~ECCapacitor() +{ +} + +void ECCapacitor::dataChanged() +{ + double capacitance = dataDouble("Capacitance"); + + QString display = QString::number( capacitance / getMultiplier(capacitance), 'g', 3 ) + getNumberMag(capacitance) + "F"; + setDisplayText( "capacitance", display ); + + m_capacitance->setCapacitance(capacitance); +} + +void ECCapacitor::drawShape( QPainter &p ) +{ + initPainter(p); + + int _y = (int)y()-8; + int _x = (int)x()-8; + + QPen pen; + pen.setWidth(1); + pen.setColor( p.pen().color() ); + p.setPen(pen); + p.drawRect( _x, _y, 5, 16 ); + p.drawRect( _x+11, _y, 5, 16 ); + + + deinitPainter(p); +// p.drawPolyline( areaPoints() ); +} + + diff --git a/src/electronics/components/eccapacitor.h b/src/electronics/components/eccapacitor.h new file mode 100644 index 0000000..4dd0ee6 --- /dev/null +++ b/src/electronics/components/eccapacitor.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECCAPACITOR_H +#define ECCAPACITOR_H + +#include "component.h" + +class Capacitance; +class ECNode; + +/** +@short Capacitor +Simple capacitor +@author David Saxton +*/ +class ECCapacitor : public Component +{ +public: + ECCapacitor( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECCapacitor(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void dataChanged(); + virtual void drawShape( QPainter &p ); + + Capacitance * m_capacitance; +}; + +#endif diff --git a/src/electronics/components/ecclockinput.cpp b/src/electronics/components/ecclockinput.cpp new file mode 100644 index 0000000..7f1ec9c --- /dev/null +++ b/src/electronics/components/ecclockinput.cpp @@ -0,0 +1,185 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "ecclockinput.h" + +#include "logic.h" +#include "libraryitem.h" +#include "simulator.h" + +#include +#include + +#include + +static inline uint roundDouble( const double x ) +{ + return uint(std::floor(x+0.5)); +} + +Item* ECClockInput::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECClockInput( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECClockInput::libraryItem() +{ + return new LibraryItem( + QString("ec/clock_input"), + i18n("Clock Input"), + i18n("Logic"), + "clockinput.png", + LibraryItem::lit_component, + ECClockInput::construct ); +} + +ECClockInput::ECClockInput( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "clock_input" ) +{ + m_name = i18n("Clock Input"); + m_desc = i18n("A square-wave generator, outputing logical high/low at repeating time intervals."); + setSize( -16, -8, 32, 16 ); + + m_lastSetTime = 0; + m_time = 0; + m_high_time = 0; + m_low_time = 0; + m_period = 0; + m_bSetStepCallbacks = true; + m_pSimulator = Simulator::self(); + + for ( unsigned i = 0; i < 1000; i++ ) + { + ComponentCallback * ccb = new ComponentCallback( this, (VoidCallbackPtr)(&ECClockInput::stepCallback) ); + m_pComponentCallback[i] = new LinkedList(ccb); + } + + init1PinRight(); + m_pOut = createLogicOut( m_pPNode[0], false ); + + createProperty( "low-time", Variant::Type::Double ); + property("low-time")->setUnit("S"); + property("low-time")->setCaption( i18n("Low Time") ); + property("low-time")->setMinValue(1.0/LOGIC_UPDATE_RATE); + property("low-time")->setValue(0.5); + + createProperty( "high-time", Variant::Type::Double ); + property("high-time")->setUnit("S"); + property("high-time")->setCaption( i18n("High Time") ); + property("high-time")->setMinValue(1.0/LOGIC_UPDATE_RATE); + property("high-time")->setValue(0.5); + + addDisplayText( "freq", QRect( -16, -24, 32, 14 ), "", false ); +} + + +ECClockInput::~ECClockInput() +{ + for ( unsigned i = 0; i < 1000; i++ ) + { + delete m_pComponentCallback[i]->data(); + delete m_pComponentCallback[i]; + } +} + + +void ECClockInput::dataChanged() +{ + m_high_time = roundDouble(dataDouble("high-time")*LOGIC_UPDATE_RATE); + m_low_time = roundDouble(dataDouble("low-time")*LOGIC_UPDATE_RATE); + m_period = m_low_time+m_high_time; + + const double frequency = 1./(dataDouble("high-time")+dataDouble("low-time")); + QString display = QString::number( frequency / getMultiplier(frequency), 'g', 3 ) + getNumberMag(frequency) + "Hz"; + setDisplayText( "freq", display ); + + bool setStepCallbacks = m_period > 100; + if ( setStepCallbacks != m_bSetStepCallbacks ) + { + m_bSetStepCallbacks = setStepCallbacks; + if (setStepCallbacks) + m_pSimulator->detachComponentCallbacks(this); + else + m_pSimulator->attachComponentCallback( this, (VoidCallbackPtr)(&ECClockInput::stepLogic) ); + } + + m_bLastStepCallbackOut = false; + m_lastSetTime = m_pSimulator->time(); +} + + +void ECClockInput::stepLogic() +{ + m_pOut->setHigh( m_time>m_low_time ); + + if ( ++m_time > m_period ) { + m_time -= int(m_time/m_period)*m_period; + } +} + + +void ECClockInput::stepCallback() +{ + m_pOut->setHigh(m_bLastStepCallbackOut); + m_bLastStepCallbackOut = !m_bLastStepCallbackOut; +} + + +void ECClockInput::stepNonLogic() +{ + if (!m_bSetStepCallbacks) + return; + + bool addingHigh = !m_bLastStepCallbackOut; + + //TODO 100 number shouldn't be hard-coded + long long lowerTime = m_pSimulator->time(); + long long upperTime = lowerTime + 100; + + long long upTo = m_lastSetTime; + + while ( upTo + (addingHigh?m_high_time:m_low_time) < upperTime ) + { + upTo += addingHigh ? m_high_time : m_low_time; + addingHigh = !addingHigh; + + long long at = upTo-lowerTime; + if ( at >= 0 && at < 100 ) + m_pSimulator->addStepCallback( at, m_pComponentCallback[at] ); + } + + m_lastSetTime = upTo; +} + + +void ECClockInput::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-10; + int _y = (int)y()-8; + + p.drawRect( _x-6, _y, 32, 16 ); + + p.drawLine( _x, _y+8, _x, _y+4 ); + p.drawLine( _x, _y+4, _x+4, _y+4 ); + p.drawLine( _x+4, _y+4, _x+4, _y+12 ); + p.drawLine( _x+4, _y+12, _x+8, _y+12 ); + p.drawLine( _x+8, _y+12, _x+8, _y+4 ); + p.drawLine( _x+8, _y+4, _x+12, _y+4 ); + p.drawLine( _x+12, _y+4, _x+12, _y+12 ); + p.drawLine( _x+12, _y+12, _x+16, _y+12 ); + p.drawLine( _x+16, _y+12, _x+16, _y+4 ); + p.drawLine( _x+16, _y+4, _x+20, _y+4 ); + p.drawLine( _x+20, _y+4, _x+20, _y+8 ); + + deinitPainter(p); +} + diff --git a/src/electronics/components/ecclockinput.h b/src/electronics/components/ecclockinput.h new file mode 100644 index 0000000..c7f7d14 --- /dev/null +++ b/src/electronics/components/ecclockinput.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECCLOCKINPUT_H +#define ECCLOCKINPUT_H + +#include "component.h" + +class ComponentCallback; +class Simulator; + +template +class LinkedList; + +/** +@short Boolean clock input +@author David Saxton +*/ +class ECClockInput : public Component +{ +public: + ECClockInput( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECClockInput(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + void stepCallback(); + void stepLogic(); + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + +protected: + virtual void drawShape( QPainter &p ); + void dataChanged(); + + uint m_time; + uint m_high_time; + uint m_low_time; + uint m_period; + long long m_lastSetTime; + LogicOut * m_pOut; + bool m_bSetStepCallbacks; + bool m_bLastStepCallbackOut; + Simulator * m_pSimulator; + LinkedList * m_pComponentCallback[1000]; +}; + +#endif diff --git a/src/electronics/components/eccurrentsignal.cpp b/src/electronics/components/eccurrentsignal.cpp new file mode 100644 index 0000000..e6dc351 --- /dev/null +++ b/src/electronics/components/eccurrentsignal.cpp @@ -0,0 +1,92 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "currentsignal.h" +#include "eccurrentsignal.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "pin.h" +#include "simulator.h" + +#include +#include + +Item* ECCurrentSignal::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECCurrentSignal( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECCurrentSignal::libraryItem() +{ + return new LibraryItem( + QString("ec/ac_current"), + i18n("Current Signal"), + i18n("Sources"), + "currentsignal.png", + LibraryItem::lit_component, + ECCurrentSignal::construct ); +} + +ECCurrentSignal::ECCurrentSignal( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "current_signal" ) +{ + m_name = i18n("Current Signal"); + m_desc = i18n("Provides a variety of current signals"); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_pNNode[0]->pin()->setGroundType( Pin::gt_low ); + m_currentSignal = createCurrentSignal( m_pNNode[0], m_pPNode[0], 0. ); + m_currentSignal->setStep( 1./LINEAR_UPDATE_RATE, ElementSignal::st_sinusoidal, 50. ); + + createProperty( "1-frequency", Variant::Type::Double ); + property("1-frequency")->setCaption( i18n("Frequency") ); + property("1-frequency")->setUnit("Hz"); + property("1-frequency")->setMinValue(1e-9); + property("1-frequency")->setMaxValue(1e3); + property("1-frequency")->setValue(50.0); + + createProperty( "1-current", Variant::Type::Double ); + property("1-current")->setCaption( i18n("Current Range") ); + property("1-current")->setUnit("A"); + property("1-current")->setMinValue(-1e12); + property("1-current")->setMaxValue(1e12); + property("1-current")->setValue(0.02); + + addDisplayText( "~", QRect( -8, -8, 16, 16 ), "~" ); + addDisplayText( "current", QRect( -16, -24, 32, 16 ), "" ); +} + + +ECCurrentSignal::~ECCurrentSignal() +{ +} + +void ECCurrentSignal::dataChanged() +{ + const double current = dataDouble("1-current"); + const double frequency = dataDouble("1-frequency"); + + QString display = QString::number( current / getMultiplier(current), 'g', 3 ) + getNumberMag(current) + "A"; + setDisplayText( "current", display ); + + m_currentSignal->setStep( 1./LINEAR_UPDATE_RATE, ElementSignal::st_sinusoidal, frequency ); + m_currentSignal->setCurrent(current); +} + +void ECCurrentSignal::drawShape( QPainter &p ) +{ + initPainter(p); + p.drawEllipse( (int)x()-8, (int)y()-8, width(), height() ); + deinitPainter(p); +} + diff --git a/src/electronics/components/eccurrentsignal.h b/src/electronics/components/eccurrentsignal.h new file mode 100644 index 0000000..88dd276 --- /dev/null +++ b/src/electronics/components/eccurrentsignal.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECCURRENTSIGNAL_H +#define ECCURRENTSIGNAL_H + +#include "component.h" + +/** +@short Provides a current signal (sinusoidal, square, etc) +@author David Saxton +*/ +class ECCurrentSignal : public Component +{ +public: + ECCurrentSignal( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECCurrentSignal(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + virtual void drawShape( QPainter &p ); + void dataChanged(); + + CurrentSignal *m_currentSignal; +}; + +#endif diff --git a/src/electronics/components/eccurrentsource.cpp b/src/electronics/components/eccurrentsource.cpp new file mode 100644 index 0000000..76ecf3e --- /dev/null +++ b/src/electronics/components/eccurrentsource.cpp @@ -0,0 +1,94 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + + +#include "currentsource.h" +#include "eccurrentsource.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "pin.h" + +#include +#include + +Item* ECCurrentSource::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECCurrentSource( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECCurrentSource::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/current_source"), + i18n("Current Source"), + i18n("Sources"), + "current_source.png", + LibraryItem::lit_component, + ECCurrentSource::construct ); +} + +ECCurrentSource::ECCurrentSource( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "current_source" ) +{ + m_name = i18n("Current Source"); + m_desc = i18n("Provides a fixed current source."); + setSize( -16, -8, 24, 24 ); + + init1PinLeft(8); + init1PinRight(8); + m_pNNode[0]->pin()->setGroundType( Pin::gt_low ); + + m_currentSource = createCurrentSource( m_pNNode[0], m_pPNode[0], 0. ); + + createProperty( "current", Variant::Type::Double ); + property("current")->setCaption( i18n("Current") ); + property("current")->setUnit("A"); + property("current")->setMinValue(-1e12); + property("current")->setMaxValue(1e12); + property("current")->setValue(0.02); + + addDisplayText("current", QRect( -16, -16, 24, 0 ), "" ); +} + + +ECCurrentSource::~ECCurrentSource() +{ +} + +void ECCurrentSource::dataChanged() +{ + double current = dataDouble("current"); + m_currentSource->setCurrent(current); + + QString display = QString::number( current / getMultiplier(current), 'g', 3 ) + getNumberMag(current) + "A"; + setDisplayText("current", display ); +} + +void ECCurrentSource::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-24; + + // Top arrow indicating current direction + p.drawLine( _x+width(), _y+19, _x, _y+19 ); + p.drawLine( _x+width(), _y+19, _x+width()-3, _y+16 ); + p.drawLine( _x+width(), _y+19, _x+width()-3, _y+22 ); + + // Double circules + p.drawEllipse( _x, _y+24, 16, 16 ); + p.drawEllipse( _x+8, _y+24, 16, 16 ); + + deinitPainter(p); +} + + + diff --git a/src/electronics/components/eccurrentsource.h b/src/electronics/components/eccurrentsource.h new file mode 100644 index 0000000..6332eba --- /dev/null +++ b/src/electronics/components/eccurrentsource.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECCURRENTSOURCE_H +#define ECCURRENTSOURCE_H + +#include "component.h" + +/** +@short Fixed current source +@author David Saxton +*/ +class ECCurrentSource : public Component +{ +public: + ECCurrentSource( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECCurrentSource(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + virtual void drawShape( QPainter &p ); + void dataChanged(); + + CurrentSource *m_currentSource; +}; + +#endif diff --git a/src/electronics/components/ecdiode.cpp b/src/electronics/components/ecdiode.cpp new file mode 100644 index 0000000..1d63bce --- /dev/null +++ b/src/electronics/components/ecdiode.cpp @@ -0,0 +1,120 @@ +/*************************************************************************** + * Copyright (C) 2003,2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "diode.h" +#include "ecdiode.h" +#include "ecnode.h" +#include "libraryitem.h" + +#include +#include + +Item* ECDiode::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECDiode( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECDiode::libraryItem() +{ + return new LibraryItem( + "ec/diode", + i18n("Diode"), + i18n("Discrete"), + "diode.png", + LibraryItem::lit_component, + ECDiode::construct ); +} + +ECDiode::ECDiode( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "diode" ) +{ + m_name = i18n("Diode"); + m_desc = i18n("Allows current to flow in the direction indicated by the arrow when a certain voltage difference has been reached."); + + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_diode = createDiode( m_pNNode[0], m_pPNode[0] ); + + DiodeSettings ds; // it will have the default properties that we use + + createProperty( "I_S", Variant::Type::Double ); + property("I_S")->setCaption("Saturation Current"); + property("I_S")->setUnit("A"); + property("I_S")->setMinValue(1e-20); + property("I_S")->setMaxValue(1e-0); + property("I_S")->setValue( ds.I_S ); + property("I_S")->setAdvanced(true); + + createProperty( "N", Variant::Type::Double ); + property("N")->setCaption( i18n("Emission Coefficient") ); + property("N")->setMinValue(1e0); + property("N")->setMaxValue(1e1); + property("N")->setValue( ds.N ); + property("N")->setAdvanced(true); + + createProperty( "V_B", Variant::Type::Double ); + property("V_B")->setCaption( i18n("Breakdown Voltage") ); + property("V_B")->setUnit("V"); + property("V_B")->setMinAbsValue(1e-5); + property("V_B")->setMaxValue(1e10); + property("V_B")->setValue( ds.V_B ); + property("V_B")->setAdvanced(true); + +// createProperty( "R", Variant::Type::Double ); +// property("R")->setCaption( i18n("Series Resistance") ); +// property("R")->setUnit( QChar(0x3a9) ); +// property("R")->setMinValue(1e-5); +// property("R")->setMaxValue(1e0); +// property("R")->setValue( ds.R ); +// property("R")->setAdvanced(true); +} + + +ECDiode::~ECDiode() +{ +} + + +void ECDiode::dataChanged() +{ + DiodeSettings ds; + + ds.I_S = dataDouble("I_S"); + ds.V_B = dataDouble("V_B"); + ds.N = dataDouble("N"); +// ds.R = dataDouble("R"); + + m_diode->setDiodeSettings( ds ); +} + + +void ECDiode::drawShape( QPainter & p ) +{ + initPainter(p); + + int _x = int(x()); + int _y = int(y()); + + QPointArray pa(3); + pa[0] = QPoint( 8, 0 ); + pa[1] = QPoint( -8, -8 ); + pa[2] = QPoint( -8, 8 ); + pa.translate( _x, _y ); + p.drawPolygon(pa); + p.drawPolyline(pa); + + p.drawLine( _x+8, _y-8, _x+8, _y+8 ); + + deinitPainter(p); +} + diff --git a/src/electronics/components/ecdiode.h b/src/electronics/components/ecdiode.h new file mode 100644 index 0000000..fa8d034 --- /dev/null +++ b/src/electronics/components/ecdiode.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003,2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECDIODE_H +#define ECDIODE_H + +#include "component.h" + +/** +@short Simple diode +@author David Saxton +*/ +class ECDiode : public Component +{ +public: + ECDiode( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECDiode(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void drawShape( QPainter & p ); + void dataChanged(); + Diode *m_diode; +}; + +#endif diff --git a/src/electronics/components/ecfixedvoltage.cpp b/src/electronics/components/ecfixedvoltage.cpp new file mode 100644 index 0000000..06eb707 --- /dev/null +++ b/src/electronics/components/ecfixedvoltage.cpp @@ -0,0 +1,77 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "ecfixedvoltage.h" + +#include "ecnode.h" +#include "voltagepoint.h" +#include "libraryitem.h" + +#include +#include + +Item* ECFixedVoltage::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECFixedVoltage( (ICNDocument*)itemDocument, newItem, id ); +} +LibraryItem* ECFixedVoltage::libraryItem() +{ + return new LibraryItem( + "ec/fixed_voltage", + i18n("Fixed Voltage"), + i18n("Sources"), + "voltage.png", + LibraryItem::lit_component, + ECFixedVoltage::construct ); +} + +ECFixedVoltage::ECFixedVoltage( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "fixed_voltage" ) +{ + m_name = i18n("Fixed Voltage"); + m_desc = i18n("Provides a fixed voltage point to connect components to."); + setSize( -8, -8, 16, 16 ); + + init1PinRight(); + m_voltagePoint = createVoltagePoint( m_pPNode[0], 5.0 ); + + addDisplayText( "voltage", QRect( -24, -20, width()+32, 12 ), "" ); + + createProperty( "voltage", Variant::Type::Double ); + property("voltage")->setUnit("V"); + property("voltage")->setCaption( i18n("Voltage") ); + property("voltage")->setMinValue(-1e15); + property("voltage")->setMaxValue(1e15); + property("voltage")->setValue(5.0); +} + +ECFixedVoltage::~ECFixedVoltage() +{ +} + +void ECFixedVoltage::dataChanged() +{ + const double voltage = dataDouble("voltage"); + QString display = QString::number( voltage / getMultiplier(voltage), 'g', 3 ) + getNumberMag(voltage) + "V"; + setDisplayText( "voltage", display ); + m_voltagePoint->setVoltage(voltage); +} + +void ECFixedVoltage::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = int(x()); + int _y = int(y()); + p.drawEllipse( _x-4, _y-4, 8, 8 ); + p.setPen( m_pPNode[0]->isSelected() ? m_selectedCol : Qt::black ); + p.drawLine( _x+4, _y, _x+8, _y ); + deinitPainter(p); +} + diff --git a/src/electronics/components/ecfixedvoltage.h b/src/electronics/components/ecfixedvoltage.h new file mode 100644 index 0000000..ba20358 --- /dev/null +++ b/src/electronics/components/ecfixedvoltage.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECFIXEDVOLTAGE_H +#define ECFIXEDVOLTAGE_H + +#include "component.h" + +/** +@short Fixed voltage source +@author David Saxton +*/ +class ECFixedVoltage : public Component +{ +public: + ECFixedVoltage( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECFixedVoltage(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + virtual void drawShape( QPainter &p ); + void dataChanged(); + VoltagePoint *m_voltagePoint; +}; + +#endif diff --git a/src/electronics/components/ecground.cpp b/src/electronics/components/ecground.cpp new file mode 100644 index 0000000..efbfc41 --- /dev/null +++ b/src/electronics/components/ecground.cpp @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "ecground.h" + +#include "ecnode.h" +#include "libraryitem.h" +#include "pin.h" + +#include +#include + +Item* ECGround::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECGround( (ICNDocument*)itemDocument, newItem, id ); +} +LibraryItem* ECGround::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/ground"), + i18n("Ground (0V)"), + i18n("Sources"), + "ground.png", + LibraryItem::lit_component, + ECGround::construct ); +} + +ECGround::ECGround( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "ground" ) +{ + m_name = i18n("Ground"); + m_desc = i18n("Ground (0V) point"); + setSize( -8, -8, 16, 16 ); + init1PinRight(); + m_pPNode[0]->pin()->setGroundType( Pin::gt_always ); + setAngleDegrees(270); +} + +ECGround::~ECGround() +{ +} + +void ECGround::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()-8; + int _y = (int)y()-8; + QPen pen; + pen.setWidth(2); + pen.setColor( p.pen().color() ); + p.setPen(pen); + p.drawLine( _x+15, _y, _x+15, _y+16 ); + p.drawLine( _x+10, _y+3, _x+10, _y+13 ); + p.drawLine( _x+5, _y+6, _x+5, _y+10 ); + deinitPainter(p); +} + + + diff --git a/src/electronics/components/ecground.h b/src/electronics/components/ecground.h new file mode 100644 index 0000000..0cf97bc --- /dev/null +++ b/src/electronics/components/ecground.h @@ -0,0 +1,33 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECGROUND_H +#define ECGROUND_H + +#include "component.h" + +/** +@short Fixed voltage source +@author David Saxton +*/ +class ECGround : public Component +{ +public: + ECGround( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECGround(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + virtual void drawShape( QPainter &p ); +}; + +#endif diff --git a/src/electronics/components/eckeypad.cpp b/src/electronics/components/eckeypad.cpp new file mode 100644 index 0000000..89d2659 --- /dev/null +++ b/src/electronics/components/eckeypad.cpp @@ -0,0 +1,199 @@ +/*************************************************************************** + * Copyright (C) 2003,2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasitemparts.h" +#include "eckeypad.h" +#include "libraryitem.h" +#include "switch.h" + +#include "ecnode.h" +#include + +Item* ECKeyPad::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECKeyPad( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECKeyPad::libraryItem() +{ + return new LibraryItem( + QString("ec/keypad"), + i18n("Keypad"), + i18n("Switches"), + "keypad.png", + LibraryItem::lit_component, + ECKeyPad::construct ); +} + +const QString text[4][9] = + { { "1","2","3","A","E","I","M","Q","U" }, + { "4","5","6","B","F","J","N","R","V" }, + { "7","8","9","C","G","K","O","S","W" }, + { "*","0","#","D","H","L","P","T","X" } }; + +ECKeyPad::ECKeyPad( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "keypad" ) +{ + m_name = i18n("Keypad"); + m_desc = i18n("Provides a numeric array of Push-to-Make switches, with 4 rows and a configurable number of columns."); + + createProperty( "useToggles", Variant::Type::Bool ); + property("useToggles")->setCaption( i18n("Use Toggles") ); + property("useToggles")->setValue(false); + + createProperty( "numCols", Variant::Type::Int ); + property("numCols")->setCaption( i18n("Columns") ); + property("numCols")->setMinValue(3); + property("numCols")->setMaxValue(9); + property("numCols")->setValue(3); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + for ( int i = 0; i < 4; i++ ) + createPin( 0, -32+i*24, 0, QString("row_%1").arg(QString::number(i)) ); + + m_numCols = 0; +} + + +ECKeyPad::~ECKeyPad() +{ +} + + +QString ECKeyPad::buttonID( int row, int col ) const +{ + return QString("b_%1_%2").arg(QString::number(row)).arg(QString::number(col)); +} + + +int ECKeyPad::sideLength( unsigned numButtons ) const +{ + return 8 + 24*numButtons; +} + + +void ECKeyPad::dataChanged() +{ + initPins( dataInt("numCols") ); + + bool useToggle = dataBool("useToggles"); + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + + for ( unsigned i = 0; i < 4; i++ ) + { + for ( unsigned j = 0; j < m_numCols; j++ ) + { + button( buttonID(i,j) )->setToggle(useToggle); + m_switch[i][j]->setBounce( bounce, bouncePeriod_ms ); + } + } +} + + +void ECKeyPad::initPins( unsigned numCols ) +{ + if ( numCols < 3 ) + numCols = 3; + else if ( numCols > 9 ) + numCols = 9; + + if ( numCols == m_numCols ) + return; + + int w = sideLength(numCols); + int h = sideLength(4); + setSize( -int(w/16)*8, -int(h/16)*8, w, h, true ); + + if ( numCols > m_numCols ) + { + // Adding columns + + for ( unsigned i = 0; i < 4; i++ ) + { + for ( unsigned j = m_numCols; j < numCols; j++ ) + addButton( buttonID(i,j), QRect( 0, 0, 20, 20 ), text[i][j] ); + } + + ECNode * cols[numCols]; + + for ( unsigned j = m_numCols; j < numCols; j++ ) + cols[j] = createPin( 0, 64, 270, "col_" + QString::number(j) ); + + for ( unsigned i = 0; i < 4; i++ ) + { + ECNode * row = ecNodeWithID("row_"+QString::number(i)); + for ( unsigned j = m_numCols; j < numCols; j++ ) + m_switch[i][j] = createSwitch( cols[j], row, true ); + } + } + else + { + // Remove columns + + for ( unsigned i = 0; i < 4; i++ ) + { + for ( unsigned j = numCols; j < m_numCols; j++ ) + removeWidget( buttonID(i,j) ); + } + + for ( unsigned j = numCols; j < m_numCols; j++ ) + removeNode( "col_" + QString::number(j) ); + + for ( unsigned i = 0; i < 4; i++ ) + { + for ( unsigned j = m_numCols; j < numCols; j++ ) + removeSwitch( m_switch[i][j] ); + } + } + + //BEGIN Update Positions + m_numCols = numCols; + + for ( int i = 0; i < 4; i++ ) + { + for ( int j = 0; j < int(m_numCols); j++ ) + { + widgetWithID( buttonID(i,j) )->setOriginalRect( + QRect( offsetX() + 6 + 24*j, offsetY() + 6 + 24*i, 20, 20 ) ); + } + } + + for ( int i = 0; i < 4; i++ ) + m_nodeMap["row_" + QString::number(i)].x = width()+offsetX(); + + for ( int j = 0; j < int(m_numCols); j++ ) + m_nodeMap["col_" + QString::number(j)].x = 24*j+offsetX()+16; + + updateAttachedPositioning(); + //END Update Positions +} + + +void ECKeyPad::buttonStateChanged( const QString &id, bool state ) +{ + if ( !id.startsWith("b_") ) + return; + + QStringList tags = QStringList::split( '_', id ); + const int i = tags[1].toInt(); + const int j = tags[2].toInt(); + m_switch[i][j]->setState( state ? Switch::Closed : Switch::Open ); +} diff --git a/src/electronics/components/eckeypad.h b/src/electronics/components/eckeypad.h new file mode 100644 index 0000000..18a497c --- /dev/null +++ b/src/electronics/components/eckeypad.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2003,2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECKEYPAD_H +#define ECKEYPAD_H + +#include "component.h" + +/** +@short 4x3 PTM Keypad +@author David Saxton +*/ +class ECKeyPad : public Component +{ + public: + ECKeyPad( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECKeyPad(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual bool canFlip() const { return true; } + + protected: + virtual void dataChanged(); + void initPins( unsigned numCols); + QString buttonID( int row, int col ) const; + int sideLength( unsigned numButtons ) const; + + Switch *m_switch[4][11]; + unsigned m_numCols; +}; + +#endif diff --git a/src/electronics/components/ecled.cpp b/src/electronics/components/ecled.cpp new file mode 100644 index 0000000..c865de6 --- /dev/null +++ b/src/electronics/components/ecled.cpp @@ -0,0 +1,134 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "colorcombo.h" +#include "diode.h" +#include "ecled.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "simulator.h" + +#include +#include + +Item* ECLed::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECLed( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECLed::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/led"), + i18n("LED"), + i18n("Outputs"), + "led.png", + LibraryItem::lit_component, + ECLed::construct + ); +} + +ECLed::ECLed( ICNDocument *icnDocument, bool newItem, const char *id ) + : ECDiode( icnDocument, newItem, (id) ? id : "led" ) +{ + m_bDynamicContent = true; + m_name = i18n("LED"); + m_desc = i18n("Light Emitting Diode"); + setSize( -8, -16, 24, 24, true ); + avg_brightness = 255; + lastUpdatePeriod = 0.; + r=g=b=0; + last_brightness = 255; + + createProperty( "0-color", Variant::Type::Color ); + property("0-color")->setCaption( i18n("Color") ); + property("0-color")->setColorScheme( ColorCombo::LED ); +} + +ECLed::~ECLed() +{ +} + +void ECLed::dataChanged() +{ + QColor color = dataColor("0-color"); + r = color.red(); + g = color.green(); + b = color.blue(); + r /= 0x100; + g /= 0x100; + b /= 0x100; +} + +void ECLed::stepNonLogic() +{ + double interval = 1./LINEAR_UPDATE_RATE; + avg_brightness += brightness(m_diode->current())*interval; + lastUpdatePeriod += interval; +} + +void ECLed::drawShape( QPainter &p ) +{ + int _x = int(x()); + int _y = int(y()); + + initPainter(p); + + //BEGIN draw "Diode" part + uint _b; + if ( lastUpdatePeriod == 0. ) + _b = last_brightness; + else + { + _b = (uint)(avg_brightness/lastUpdatePeriod); + last_brightness = _b; + } + avg_brightness = 0.; + lastUpdatePeriod = 0.; + + p.setBrush( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ) ); + + QPointArray pa(3); + pa[0] = QPoint( 8, 0 ); + pa[1] = QPoint( -8, -8 ); + pa[2] = QPoint( -8, 8 ); + pa.translate( _x, _y ); + p.drawPolygon(pa); + p.drawPolyline(pa); + + p.drawLine( _x+8, _y-8, _x+8, _y+8 ); + //END draw "Diode" part + + + + //BEGIN draw "Arrows" part + p.drawLine( _x+7, _y-10, _x+10, _y-13 ); // Tail of left arrow + p.drawLine( _x+10, _y-13, _x+8, _y-13 ); // Left edge of left arrow tip + p.drawLine( _x+10, _y-13, _x+10, _y-11 ); // Right edge of left arrow tip + + p.drawLine( _x+10, _y-7, _x+13, _y-10 ); // Tail of right arrow + p.drawLine( _x+13, _y-10, _x+11, _y-10 ); // Left edge of right arrow tip + p.drawLine( _x+13, _y-10, _x+13, _y-8 ); // Right edge of right arrow tip + + p.drawLine( _x+8, _y-13, _x+13, _y-8 ); // Diagonal line that forms base of both arrow tips + //END draw "Arrows" part1 + + + deinitPainter(p); +} + + +uint ECLed::brightness( double i ) +{ + if ( i > 0.018 ) return 0; + if ( i < 0.002 ) return 255; + return (uint)(255*(1-((i-0.002)/0.016))); +} + diff --git a/src/electronics/components/ecled.h b/src/electronics/components/ecled.h new file mode 100644 index 0000000..ce24598 --- /dev/null +++ b/src/electronics/components/ecled.h @@ -0,0 +1,48 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECLED_H +#define ECLED_H + +#include "component.h" +#include "ecdiode.h" + +/** +@short Simulates a LED +@author David Saxton +*/ +class ECLed : public ECDiode +{ +public: + ECLed( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECLed(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + /** + * Returns the brightness for the given current, from 255 (off) -> 0 (on) + */ + static uint brightness( double i ); + + virtual void dataChanged(); + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + +private: + virtual void drawShape( QPainter &p ); + + double r, g, b; + + double avg_brightness; + uint last_brightness; + double lastUpdatePeriod; +}; + +#endif diff --git a/src/electronics/components/ecopamp.cpp b/src/electronics/components/ecopamp.cpp new file mode 100644 index 0000000..dbb7457 --- /dev/null +++ b/src/electronics/components/ecopamp.cpp @@ -0,0 +1,85 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "ecopamp.h" + +#include "ecnode.h" +#include "libraryitem.h" + +#include +#include + +Item* ECOpAmp::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECOpAmp( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* ECOpAmp::libraryItem() +{ + return new LibraryItem( + "ec/opamp", + i18n("Op Amp"), + i18n("Integrated Circuits"), + "opamp.png", + LibraryItem::lit_component, + ECOpAmp::construct ); +} + + +ECOpAmp::ECOpAmp( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "opamp" ) +{ + m_name = i18n("Operational Amplifier"); + m_desc = i18n("Ideal amplifier"); + + QPointArray pa(3); + pa[0] = QPoint( -16, -16 ); + pa[1] = QPoint( 16, 0 ); + pa[2] = QPoint( -16, 16 ); + setItemPoints( pa, true ); + + init2PinLeft( -8, 8 ); + init1PinRight(); + createOpAmp( m_pNNode[0], m_pPNode[0], m_pNNode[1] ); +} + + +ECOpAmp::~ECOpAmp() +{ +} + + +void ECOpAmp::drawShape( QPainter & p ) +{ + initPainter(p); + + int _x = int(x()); + int _y = int(y()); + + QPointArray pa(3); + pa[0] = QPoint( _x-16, _y-16 ); + pa[1] = QPoint( _x+16, _y ); + pa[2] = QPoint( _x-16, _y+16 ); + + p.drawPolygon(pa); + p.drawPolyline(pa); + + // Plus symbol + p.drawLine( _x-9, _y-8, _x-9, _y-2 ); + p.drawLine( _x-12, _y-5, _x-6, _y-5 ); + + // Minus symbol + p.drawLine( _x-11, _y+6, _x-7, _y+6 ); + + deinitPainter(p); +} + + diff --git a/src/electronics/components/ecopamp.h b/src/electronics/components/ecopamp.h new file mode 100644 index 0000000..6b6b147 --- /dev/null +++ b/src/electronics/components/ecopamp.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECOPAMP_H +#define ECOPAMP_H + +#include "component.h" + +/** +@short Operational Amplifier +@author David Saxton +*/ +class ECOpAmp : public Component +{ + public: + ECOpAmp( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECOpAmp(); + + virtual bool canFlip() const { return true; } + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void drawShape( QPainter & p ); +}; + +#endif diff --git a/src/electronics/components/ecpotentiometer.cpp b/src/electronics/components/ecpotentiometer.cpp new file mode 100644 index 0000000..db0fedd --- /dev/null +++ b/src/electronics/components/ecpotentiometer.cpp @@ -0,0 +1,119 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasitemparts.h" +#include "ecnode.h" +#include "ecpotentiometer.h" +#include "libraryitem.h" +#include "resistance.h" + +#include +#include +#include + +Item* ECPotentiometer::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECPotentiometer( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECPotentiometer::libraryItem() +{ + return new LibraryItem( + "ec/potentiometer", + i18n("Potentiometer"), + i18n("Discrete"), + "potentiometer.png", + LibraryItem::lit_component, + ECPotentiometer::construct ); +} + +ECPotentiometer::ECPotentiometer( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "potentiometer" ) +{ + m_name = i18n("Potentiometer"); + m_desc =i18n("Consists of a resistor connected to the end pins, with a central pin connected at an adjustable point along the resistor"); + setSize( -16, -16, 40, 32 ); + + m_p1 = createPin( 32, 0, 180, "p1" ); + + m_sliderProp = 0.0; + m_resistance = 5000.; + m_r1 = createResistance( createPin( -8, -24, 90, "n1" ), m_p1, 1. ); + m_r2 = createResistance( createPin( -8, 24, 270, "n2" ), m_p1, 1. ); + + Slider * s = addSlider( "slider", 0, 100, 5, 50, Qt::Vertical, QRect( 0, -16, 16, 32 ) ); + m_pSlider = static_cast(s->widget()); + + createProperty( "resistance", Variant::Type::Double ); + property("resistance")->setCaption( i18n("Resistance") ); + property("resistance")->setUnit( QChar(0x3a9) ); + property("resistance")->setMinValue(1e-6); + property("resistance")->setValue(1e5); + + addDisplayText( "res", QRect( -56, -8, 40, 16 ), "" ); +} + +ECPotentiometer::~ECPotentiometer() +{ +} + +void ECPotentiometer::dataChanged() +{ + m_resistance = dataDouble("resistance"); + + QString display = QString::number( m_resistance / getMultiplier(m_resistance), 'g', 3 ) + getNumberMag(m_resistance) + QChar(0x3a9); + setDisplayText( "res", display ); + + sliderValueChanged( "slider", slider("slider")->value() ); +} + +void ECPotentiometer::sliderValueChanged( const QString &id, int newValue ) +{ + if ( id != "slider" ) + return; + + m_sliderProp = (newValue-50.0)/100.0; + + m_r1->setResistance( m_resistance*(double)newValue/100. ); + m_r2->setResistance( m_resistance*(double)(100.-newValue)/100. ); +} + +void ECPotentiometer::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = int(x()); + int _y = int(y()); + + p.drawRect( _x-14, _y-16, 12, 32 ); + + QPointArray pa(3); + pa[0] = QPoint( 0, 0 ); + pa[1] = QPoint( 4, -3 ); + pa[2] = QPoint( 4, 3 ); + + int space = m_pSlider->style().pixelMetric( QStyle::PM_SliderSpaceAvailable, m_pSlider ); + int base_y = _y + (( angleDegrees() == 0 || angleDegrees() == 270 ) ? 1 : -1) * int( space * m_sliderProp ); + + pa.translate( _x+16, base_y ); + + QColor c = m_p1->isSelected() ? m_selectedCol : black; + + p.setPen(c); + p.setBrush(c); + p.drawPolygon(pa); + + p.drawLine( _x+20, base_y, _x+24, base_y ); + p.drawLine( _x+24, base_y, _x+24, _y ); + + deinitPainter(p); +} + + + diff --git a/src/electronics/components/ecpotentiometer.h b/src/electronics/components/ecpotentiometer.h new file mode 100644 index 0000000..e7ca83b --- /dev/null +++ b/src/electronics/components/ecpotentiometer.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECPOTENTIOMETER_H +#define ECPOTENTIOMETER_H + +#include "component.h" + +class QSlider; + +/** +@short Potentiometer +@author David Saxton +*/ +class ECPotentiometer : public Component +{ +public: + ECPotentiometer( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECPotentiometer(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void sliderValueChanged( const QString &id, int newValue ); + +private: + void dataChanged(); + virtual void drawShape( QPainter &p ); + + ECNode * m_p1; + Resistance *m_r1, *m_r2; + double m_resistance; + double m_sliderProp; + QSlider * m_pSlider; +}; +#endif diff --git a/src/electronics/components/ecresistor.cpp b/src/electronics/components/ecresistor.cpp new file mode 100644 index 0000000..e4ee7a3 --- /dev/null +++ b/src/electronics/components/ecresistor.cpp @@ -0,0 +1,76 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "ecresistor.h" + +#include "libraryitem.h" +#include "resistance.h" + +#include +#include + +Item* ECResistor::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECResistor( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECResistor::libraryItem() +{ + return new LibraryItem( + "ec/resistor", + i18n("Resistor"), + i18n("Discrete"), + "resistor.png", + LibraryItem::lit_component, + ECResistor::construct ); +} + +ECResistor::ECResistor( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "resistor" ) +{ + m_name = i18n("Resistor"); + m_desc = i18n("Limits the flow of current, obeying Ohms Law"); + setSize( -16, -8, 32, 16 ); + + init1PinLeft(); + init1PinRight(); + m_resistance = createResistance( m_pPNode[0], m_pNNode[0], 1. ); + + createProperty( "resistance", Variant::Type::Double ); + property("resistance")->setCaption( i18n("Resistance") ); + property("resistance")->setUnit( QChar(0x3a9) ); + property("resistance")->setValue(1e4); + property("resistance")->setMinValue(1e-6); + + addDisplayText( "res", QRect( -16, -22, 32, 12 ), "", false ); +} + +ECResistor::~ECResistor() +{ +} + +void ECResistor::dataChanged() +{ + double resistance = dataDouble("resistance"); + + QString display = QString::number( resistance / getMultiplier(resistance), 'g', 3 ) + getNumberMag(resistance) + QChar(0x3a9); + setDisplayText( "res", display ); + + m_resistance->setResistance(resistance); +} + +void ECResistor::drawShape( QPainter &p ) +{ + initPainter(p); + p.drawRect( (int)x()-16, (int)y()-6, width(), 12 ); + deinitPainter(p); +} + + diff --git a/src/electronics/components/ecresistor.h b/src/electronics/components/ecresistor.h new file mode 100644 index 0000000..17e799e --- /dev/null +++ b/src/electronics/components/ecresistor.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECRESISTOR_H +#define ECRESISTOR_H + +#include "component.h" + +/** +@short Simple resistor +@author David Saxton +*/ +class ECResistor : public Component +{ + public: + ECResistor( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECResistor(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter & p ); + + Resistance * m_resistance; +}; + +#endif diff --git a/src/electronics/components/ecsevensegment.cpp b/src/electronics/components/ecsevensegment.cpp new file mode 100644 index 0000000..ec35776 --- /dev/null +++ b/src/electronics/components/ecsevensegment.cpp @@ -0,0 +1,210 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "colorcombo.h" +#include "diode.h" +#include "ecled.h" +#include "ecnode.h" +#include "ecsevensegment.h" +#include "libraryitem.h" +#include "simulator.h" + +#include +#include +#include + +Item* ECSevenSegment::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECSevenSegment( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECSevenSegment::libraryItem() +{ + return new LibraryItem( + "ec/seven_segment", + i18n("Seven Segment"), + i18n("Outputs"), + "seven_segment.png", + LibraryItem::lit_component, + ECSevenSegment::construct ); +} + +ECSevenSegment::ECSevenSegment( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "seven_segment" ) +{ + m_name = i18n("Seven Segment LED"); + m_desc = i18n("A seven segment display with a decimal point. This can be configured to either have a common cathode or a common anode."); + m_bDynamicContent = true; + + QStringList pins = QStringList::split( ',', "g,f,e,d,"+QString(QChar(0xB7))+",c,b,a" ); + + createProperty( "0-color", Variant::Type::Color ); + property("0-color")->setCaption( i18n("Color") ); + property("0-color")->setColorScheme( ColorCombo::LED ); + + createProperty( "diode-polarity", Variant::Type::Select ); + property("diode-polarity")->setCaption( i18n("Configuration") ); + property("diode-polarity")->setAllowed( QStringList::split(',',"Common Cathode,Common Anode") ); + property("diode-polarity")->setValue("Common Cathode"); + + for ( int i=0; i<8; i++ ) + { + m_diodes[i] = 0L; + m_nodes[i] = 0L; + avg_brightness[i] = 0.; + last_brightness[i] = 255; + } + m_nNode = 0L; + + lastUpdatePeriod = 0.; + + initDIPSymbol( pins, 64 ); + initDIP(pins); + + m_nNode = createPin( width()/2+offsetX(), height()+8+offsetY(), 270, "-v" ); + + for ( int i=0; i<7; i++ ) + m_nodes[i] = ecNodeWithID( QChar('a'+i) ); + + m_nodes[7] = ecNodeWithID(QChar(0xB7)); + + m_bCommonCathode = false; // Force update +} + + +ECSevenSegment::~ECSevenSegment() +{ +} + + +void ECSevenSegment::dataChanged() +{ + QColor color = dataColor("0-color"); + r = color.red(); + g = color.green(); + b = color.blue(); + r /= 0x100; + g /= 0x100; + b /= 0x100; + + bool commonCathode = dataString("diode-polarity") == "Common Cathode"; + if ( commonCathode != m_bCommonCathode ) + { + m_bCommonCathode = commonCathode; + for ( int i=0; i<7; i++ ) + { + removeElement( m_diodes[i], false ); + if (commonCathode) + m_diodes[i] = createDiode( m_nodes[i], m_nNode ); + else + m_diodes[i] = createDiode( m_nNode, m_nodes[i] ); + } + + removeElement( m_diodes[7], false ); + if (commonCathode) + m_diodes[7] = createDiode( m_nodes[7], m_nNode ); + else + m_diodes[7] = createDiode( m_nNode, m_nodes[7] ); + } + + update(); +} + + +void ECSevenSegment::stepNonLogic() +{ + double interval = 1./LINEAR_UPDATE_RATE; + + for ( int i=0; i<8; i++ ) { + avg_brightness[i] += ECLed::brightness( m_diodes[i]->current() )*interval; + } + + lastUpdatePeriod += interval; +} + +void ECSevenSegment::drawShape( QPainter &p ) +{ + CNItem::drawShape(p); + + initPainter(p); + + const int _width = 20; + const int _height = 32; + + const int x1 = (int)x()+offsetX() + (width()-_width)/2 - 1; + const int x2 = x1 + _width; + const int y1 = (int)y()+offsetY() + (height()-_height)/2; + const int y2 = y1 + _height/2; + const int y3 = y1 + _height; + const int ds = 2; // "Slope" + +// QPen pen; +// pen.setWidth(2); +// pen.setCapStyle(Qt::RoundCap); +// p.setPen(pen); + + if ( lastUpdatePeriod != 0. ) + { + for ( uint i=0; i<8; ++i ) + { + last_brightness[i] = (uint)(avg_brightness[i]/lastUpdatePeriod); + } + } + + double _b; + + // Top + _b = last_brightness[0]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x1+3+ds, y1+0, x2-3+ds, y1+0 ); + + // Top right + _b = last_brightness[1]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x2+0+ds, y1+3, x2+0, y2-3 ); + + // Bottom right + _b = last_brightness[2]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x2+0, y2+3, x2+0-ds, y3-3 ); + + // Bottom + _b = last_brightness[3]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x2-3-ds, y3+0, x1+3-ds, y3+0 ); + + // Bottom left + _b = last_brightness[4]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x1+0-ds, y3-3, x1+0, y2+3 ); + + // Top left + _b = last_brightness[5]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x1+0, y2-3, x1+0+ds, y1+3 ); + + // Middle + _b = last_brightness[6]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x1+3, y2+0, x2-3, y2+0 ); + + // Decimal point + _b = last_brightness[7]; + p.setBrush( QBrush( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ) ) ); + p.setPen( Qt::NoPen ); + p.drawPie( x2+3, y3-2, 3, 3, 0, 16*360 ); + + lastUpdatePeriod = 0.; + for ( uint i=0; i<8; ++i ) { + avg_brightness[i] = 0.; + } + + deinitPainter(p); +} diff --git a/src/electronics/components/ecsevensegment.h b/src/electronics/components/ecsevensegment.h new file mode 100644 index 0000000..7041c9a --- /dev/null +++ b/src/electronics/components/ecsevensegment.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECSEVENSEGMENT_H +#define ECSEVENSEGMENT_H + +#include "component.h" + +class Diode; +class ECNode; + +/** +@short Seven segment display component +@author David Saxton +*/ +class ECSevenSegment : public Component +{ +public: + ECSevenSegment( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECSevenSegment(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + virtual void dataChanged(); + virtual bool canFlip() const { return true; } + +private: + virtual void drawShape( QPainter &p ); + + bool m_bCommonCathode; + double lastUpdatePeriod; + double avg_brightness[8]; + uint last_brightness[8]; + Diode *m_diodes[8]; + ECNode *m_nodes[8]; + ECNode *m_nNode; + double r, g, b; +}; + +#endif diff --git a/src/electronics/components/ecsignallamp.cpp b/src/electronics/components/ecsignallamp.cpp new file mode 100644 index 0000000..c7034f7 --- /dev/null +++ b/src/electronics/components/ecsignallamp.cpp @@ -0,0 +1,86 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + + +#include "ecnode.h" +#include "ecsignallamp.h" +#include "element.h" +#include "libraryitem.h" +#include "pin.h" + +#include +#include + +Item* ECSignalLamp::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECSignalLamp( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECSignalLamp::libraryItem() +{ + return new LibraryItem( + QString("ec/signal_lamp"), + i18n("Signal Lamp"), + i18n("Outputs"), + "signal_lamp.png", + LibraryItem::lit_component, + ECSignalLamp::construct ); +} + +ECSignalLamp::ECSignalLamp( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "signal_lamp" ) +{ + m_name = i18n("Signal Lamp"); + m_desc = i18n("A simple filament signal lamp, with a 100 ohms series resistance."); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + createResistance( m_pPNode[0], m_pNNode[0], 100. ); + + advanceSinceUpdate = 0; + avgPower = 0.; + m_bDynamicContent = true; +} + +ECSignalLamp::~ECSignalLamp() +{ +} + +void ECSignalLamp::stepNonLogic() +{ + const double voltage = m_pPNode[0]->pin()->voltage()-m_pNNode[0]->pin()->voltage(); + avgPower = QABS(avgPower*advanceSinceUpdate + (voltage*voltage/100))/++advanceSinceUpdate; +} + +void ECSignalLamp::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = int(x()); + int _y = int(y()); + + // Calculate the brightness as a linear function of power, bounded below by + // 25 milliWatts and above by 500 milliWatts. + int brightness = (avgPower<0.025) ? 255 : ((avgPower>0.5) ? 0 : (int)(255*(1-((avgPower-0.025)/0.475)))); + advanceSinceUpdate = 0; + + p.setBrush( QColor( 255, 255, brightness ) ); + p.drawEllipse( _x-8, _y-8, 16, 16 ); + + // 2*sqrt(2) = 2.828427125... + int pos = 8 - int(16/2.828); + + p.drawLine( _x-8+pos, _y-8+pos, _x+8-pos, _y+8-pos ); + p.drawLine( _x+8-pos, _y-8+pos, _x-8+pos, _y+8-pos ); + + deinitPainter(p); +} diff --git a/src/electronics/components/ecsignallamp.h b/src/electronics/components/ecsignallamp.h new file mode 100644 index 0000000..e56d724 --- /dev/null +++ b/src/electronics/components/ecsignallamp.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECSIGNALLAMP_H +#define ECSIGNALLAMP_H + +#include "component.h" + +class Resistance; + +/** +@short Signal Lamp - glows when current flows +@author David Saxton +*/ +class ECSignalLamp : public Component +{ +public: + ECSignalLamp( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECSignalLamp(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + +private: + void drawShape( QPainter &p ); + double avgPower; + uint advanceSinceUpdate; +}; + +#endif diff --git a/src/electronics/components/ecsubcircuit.cpp b/src/electronics/components/ecsubcircuit.cpp new file mode 100644 index 0000000..a69e720 --- /dev/null +++ b/src/electronics/components/ecsubcircuit.cpp @@ -0,0 +1,130 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasitemparts.h" +#include "circuitdocument.h" +#include "ecsubcircuit.h" +#include "node.h" +#include "libraryitem.h" +#include "subcircuits.h" + +#include +#include +#include + +Item* ECSubcircuit::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECSubcircuit( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECSubcircuit::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/subcircuit"), + QString::null, + QString::null, + QString::null, + LibraryItem::lit_subcircuit, + ECSubcircuit::construct ); +} + +ECSubcircuit::ECSubcircuit( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "subcircuit" ) +{ + m_name = i18n("Subcircuit"); + + createProperty( "id", Variant::Type::Int ); + property("id")->setMinValue(1); + property("id")->setMaxValue(1<<15); + property("id")->setValue(1); + property("id")->setHidden(true); +} + + +ECSubcircuit::~ECSubcircuit() +{ +} + + +void ECSubcircuit::removeItem() +{ + emit subcircuitDeleted(); + Component::removeItem(); +} + + +void ECSubcircuit::setNumExtCon( unsigned numExtCon ) +{ + m_conNames.resize(numExtCon); + + // Remove old pins + const NodeMap::iterator nodeMapEnd = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != nodeMapEnd; ++it ) + { + p_icnDocument->appendDeleteList( p_icnDocument->nodeWithID(it.data().id) ); + } + p_icnDocument->flushDeleteList(); + m_nodeMap.clear(); + + QStringList pins; + for ( unsigned i=0; i m_conNames.size() ) + return; + + m_conNames[numId] = name; +} + + +void ECSubcircuit::doneSCInit() +{ + QStringList pins; + for ( unsigned i = 0; i < m_conNames.size(); ++i ) + pins << m_conNames[i]; + initDIPSymbol( pins, 80 ); +} + + +void ECSubcircuit::drawShape( QPainter &p ) +{ + Component::drawShape(p); +} + + +#include "ecsubcircuit.moc" + + + diff --git a/src/electronics/components/ecsubcircuit.h b/src/electronics/components/ecsubcircuit.h new file mode 100644 index 0000000..eaf21ec --- /dev/null +++ b/src/electronics/components/ecsubcircuit.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECSUBCIRCUIT_H +#define ECSUBCIRCUIT_H + +#include + +#include + +/** +"Container" component for subcircuits +@author David Saxton +*/ +class ECSubcircuit : public Component +{ +Q_OBJECT +public: + ECSubcircuit( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECSubcircuit(); + virtual bool canFlip() const { return true; } + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + /** + * Create numExtCon nodes, deleting any old ones + */ + void setNumExtCon( unsigned numExtCon ); + /** + * Give the connecting node at position numId the given name + */ + void setExtConName( unsigned numId, const QString & name ); + /** + * Called from SubcircuitData once the subcircuit has been fully attached + */ + void doneSCInit(); + +public slots: + virtual void removeItem(); + +signals: + /** + * Emitted when the current subcircuit is deleted + */ + void subcircuitDeleted(); + +protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + QValueVector m_conNames; +}; + +#endif diff --git a/src/electronics/components/ecvoltagesignal.cpp b/src/electronics/components/ecvoltagesignal.cpp new file mode 100644 index 0000000..c338f36 --- /dev/null +++ b/src/electronics/components/ecvoltagesignal.cpp @@ -0,0 +1,95 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "ecnode.h" +#include "ecvoltagesignal.h" +#include "libraryitem.h" +#include "pin.h" +#include "simulator.h" +#include "voltagesignal.h" + +#include +#include + +const double conductance = 1e5; // Internal resistance + +Item* ECVoltageSignal::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECVoltageSignal( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECVoltageSignal::libraryItem() +{ + return new LibraryItem( + QString("ec/voltage_signal"), + i18n("Voltage Signal"), + i18n("Sources"), + "voltagesignal.png", + LibraryItem::lit_component, + ECVoltageSignal::construct ); +} + +ECVoltageSignal::ECVoltageSignal( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "voltage_signal" ) +{ + m_name = i18n("Voltage Signal"); + m_desc = i18n("Provides a variety of voltage signals."); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_pNNode[0]->pin()->setGroundType( Pin::gt_medium ); + m_voltageSignal = createVoltageSignal( m_pNNode[0], m_pPNode[0], 0. ); + m_voltageSignal->setStep( 1./LINEAR_UPDATE_RATE, ElementSignal::st_sinusoidal, 50. ); + + createProperty( "frequency", Variant::Type::Double ); + property("frequency")->setCaption( i18n("Frequency") ); + property("frequency")->setUnit("Hz"); + property("frequency")->setMinValue(1e-9); + property("frequency")->setMaxValue(1e3); + property("frequency")->setValue(50.0); + + createProperty( "voltage", Variant::Type::Double ); + property("voltage")->setCaption( i18n("Voltage Range") ); + property("voltage")->setUnit("V"); + property("voltage")->setMinValue(-1e12); + property("voltage")->setMaxValue(1e12); + property("voltage")->setValue(5.0); + + addDisplayText( "~", QRect( -8, -8, 16, 16 ), "~" ); + addDisplayText( "voltage", QRect( -16, -24, 32, 16 ), "" ); +} + + +ECVoltageSignal::~ECVoltageSignal() +{ +} + +void ECVoltageSignal::dataChanged() +{ + const double voltage = dataDouble("voltage"); + const double frequency = dataDouble("frequency"); + + QString display = QString::number( voltage / getMultiplier(voltage), 'g', 3 ) + getNumberMag(voltage) + "V"; + setDisplayText( "voltage", display ); + + m_voltageSignal->setStep( 1./LINEAR_UPDATE_RATE, ElementSignal::st_sinusoidal, frequency ); + m_voltageSignal->setVoltage(voltage); +} + + +void ECVoltageSignal::drawShape( QPainter &p ) +{ + initPainter(p); + p.drawEllipse( (int)x()-8, (int)y()-8, width(), height() ); + deinitPainter(p); +} + diff --git a/src/electronics/components/ecvoltagesignal.h b/src/electronics/components/ecvoltagesignal.h new file mode 100644 index 0000000..7102132 --- /dev/null +++ b/src/electronics/components/ecvoltagesignal.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECVOLTAGESIGNAL_H +#define ECVOLTAGESIGNAL_H + +#include "component.h" + +/** +@short Provides an alternating voltage source +@author David Saxton +*/ +class ECVoltageSignal : public Component +{ +public: + ECVoltageSignal( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECVoltageSignal(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + virtual void drawShape( QPainter &p ); + void dataChanged(); + + VoltageSignal *m_voltageSignal; +}; + +#endif diff --git a/src/electronics/components/ecvoltagesource.cpp b/src/electronics/components/ecvoltagesource.cpp new file mode 100644 index 0000000..4b8c543 --- /dev/null +++ b/src/electronics/components/ecvoltagesource.cpp @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "ecvoltagesource.h" + +#include "ecnode.h" +#include "voltagesource.h" +#include "libraryitem.h" +#include "pin.h" + +#include +#include + +const double conductance = 1e5; // Internal resistance + +Item* ECCell::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECCell( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECCell::libraryItem() +{ + QStringList ids; + ids << "ec/battery" << "ec/cell"; + return new LibraryItem( + ids, + i18n("Battery"), + i18n("Sources"), + "cell.png", + LibraryItem::lit_component, + ECCell::construct ); +} + +ECCell::ECCell( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "cell" ) +{ + m_name = i18n("Battery"); + m_desc = i18n("Provides a potential-difference."); + setSize( -8, -8, 16, 16 ); + voltage = 0; + + init1PinLeft(); + init1PinRight(); + + m_pNNode[0]->pin()->setGroundType( Pin::gt_medium ); + m_voltageSource = createVoltageSource( m_pNNode[0], m_pPNode[0], voltage ); + + createProperty( "voltage", Variant::Type::Double ); + property("voltage")->setUnit("V"); + property("voltage")->setCaption( i18n("Voltage") ); + property("voltage")->setMinValue(-1e12); + property("voltage")->setMaxValue(1e12); + property("voltage")->setValue(5.0); + + addDisplayText( "voltage", QRect( -16, -24, 32, 16 ), "" ); +} + +ECCell::~ECCell() +{ +} + +void ECCell::dataChanged() +{ + voltage = dataDouble("voltage"); + m_voltageSource->setVoltage(voltage); + + QString display = QString::number( voltage / getMultiplier(voltage), 'g', 3 ) + getNumberMag(voltage) + "V"; + setDisplayText( "voltage", display ); +} + +void ECCell::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-8; + int _y = (int)y()-24; + + p.drawLine( _x, _y+20, _x, _y+28 ); + p.drawLine( _x+5, _y+16, _x+5, _y+32 ); + p.drawLine( _x+10, _y+20, _x+10, _y+28 ); + p.drawLine( _x+15, _y+16, _x+15, _y+32 ); + + deinitPainter(p); +// p.drawPolyline( areaPoints() ); +} + diff --git a/src/electronics/components/ecvoltagesource.h b/src/electronics/components/ecvoltagesource.h new file mode 100644 index 0000000..4ba87ef --- /dev/null +++ b/src/electronics/components/ecvoltagesource.h @@ -0,0 +1,37 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECCELL_H +#define ECCELL_H + +#include "component.h" + +/** +@short Electrical cell +Simple electrical cell that simulates a PD and internal resistance +@author David Saxton +*/ +class ECCell : public Component +{ +public: + ECCell( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECCell(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void dataChanged(); + virtual void drawShape( QPainter &p ); + VoltageSource *m_voltageSource; + double voltage; +}; + +#endif diff --git a/src/electronics/components/externalconnection.cpp b/src/electronics/components/externalconnection.cpp new file mode 100644 index 0000000..596727a --- /dev/null +++ b/src/electronics/components/externalconnection.cpp @@ -0,0 +1,78 @@ +/*************************************************************************** + * Copyright (C) 2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "externalconnection.h" +#include "libraryitem.h" + +#include +#include + +Item* ExternalConnection::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ExternalConnection( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ExternalConnection::libraryItem() +{ + return new LibraryItem( + "ec/external_connection", + i18n("External Connection"), + i18n("Connections"), + "external_connection.png", + LibraryItem::lit_component, + ExternalConnection::construct ); +} + +ExternalConnection::ExternalConnection( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "external_connection" ) +{ + m_name = i18n("External Connection"); + m_desc = i18n("Point to connect the circuit to an external entity - e.g. a mechanical component or as part of a subcircuit."); + setSize( -8, -8, 16, 16 ); + + createProperty( "name", Variant::Type::Combo ); + property("name")->setCaption( i18n("Name") ); + property("name")->setValue("ExtCon"); + + init1PinLeft(); + + addDisplayText( "name", QRect( -24, 8, 3*width(), 16 ), "ExtCon" ); +} + +ExternalConnection::~ExternalConnection() +{ +} + + +void ExternalConnection::dataChanged() +{ + QString name = dataString("name"); + + QRect r( -width(), 16, 3*width(), 16 ); + setDisplayText( "name", name ); +} + + +void ExternalConnection::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()-8; + int _y = (int)y()-8; + p.drawEllipse( _x, _y, width(), height() ); + + p.drawLine( _x+3, _y+6, _x+12, _y+6 ); + p.drawLine( _x+8, _y+3, _x+12, _y+6 ); + + p.drawLine( _x+3, _y+9, _x+12, _y+9 ); + p.drawLine( _x+3, _y+9, _x+8, _y+12 ); + + deinitPainter(p); +} + diff --git a/src/electronics/components/externalconnection.h b/src/electronics/components/externalconnection.h new file mode 100644 index 0000000..9b733fc --- /dev/null +++ b/src/electronics/components/externalconnection.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef EXTERNALCONNECTION_H +#define EXTERNALCONNECTION_H + +#include + +/** +For connecting to something "outside" - e.g. a mechanical component, or as part +of a circuit part +@author David Saxton +*/ +class ExternalConnection : public Component +{ +public: + ExternalConnection( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ExternalConnection(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void dataChanged(); + virtual void drawShape( QPainter &p ); +}; + +#endif diff --git a/src/electronics/components/flipflop.cpp b/src/electronics/components/flipflop.cpp new file mode 100644 index 0000000..5c55baf --- /dev/null +++ b/src/electronics/components/flipflop.cpp @@ -0,0 +1,347 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "flipflop.h" +#include "icndocument.h" +#include "logic.h" +#include "libraryitem.h" +#include "node.h" +#include "simulator.h" + +#include +#include +#include + + +//BEGIN class ECDFlipFlop +Item* ECDFlipFlop::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECDFlipFlop( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECDFlipFlop::libraryItem() +{ + return new LibraryItem( + "ec/d_flipflop", + i18n("D Flip-Flop"), + i18n("Integrated Circuits"), + "ic3.png", + LibraryItem::lit_component, + ECDFlipFlop::construct ); +} + +ECDFlipFlop::ECDFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "d_flipflop" ) +{ + m_name = i18n("D-Type Flip-Flop"); + m_desc = i18n("The output state is set from the input state when the clock is pulsed."); + + setSize( -32, -24, 64, 48 ); + + init2PinLeft( -8, 8 ); + init2PinRight( -8, 8 ); + + m_prevD[0] = m_prevD[1] = false; + m_whichPrevD = 0; + m_prevDSimTime = 0; + m_pSimulator = Simulator::self(); + + m_bPrevClock = false; + m_pD = createLogicIn( m_pNNode[0] ); + m_pClock = createLogicIn( m_pNNode[1] ); + m_pQ = createLogicOut( m_pPNode[0], false ); + m_pQBar = createLogicOut( m_pPNode[1], false ); + + setp = createLogicIn( createPin( 0, -32, 90, "set" ) ); + rstp = createLogicIn( createPin( 0, 32, 270, "rst" ) ); + + addDisplayText( "D", QRect( -32, -16, 20, 16 ), "D" ); + addDisplayText( ">", QRect( -32, 0, 20, 16 ), ">" ); + addDisplayText( "Q", QRect( 12, -16, 20, 16 ), "Q" ); + addDisplayText( "Q'", QRect( 12, 0, 20, 16 ), "Q'" ); + addDisplayText( "Set", QRect( -16, -20, 32, 16 ), "Set" ); + addDisplayText( "Rst", QRect( -16, 4, 32, 16 ), "Rst" ); + + m_pD->setCallback( this, (CallbackPtr)(&ECDFlipFlop::inputChanged) ); + m_pClock->setCallback( this, (CallbackPtr)(&ECDFlipFlop::clockChanged) ); + setp->setCallback( this, (CallbackPtr)(&ECDFlipFlop::asyncChanged) ); + rstp->setCallback( this, (CallbackPtr)(&ECDFlipFlop::asyncChanged) ); + + inStateChanged(false); +} + +ECDFlipFlop::~ECDFlipFlop() +{ +} + +void ECDFlipFlop::asyncChanged(bool) +{ + bool set = setp->isHigh(); + bool rst = rstp->isHigh(); + if(set || rst) + { + m_pQ->setHigh(set); + m_pQBar->setHigh(rst); + } +} + +void ECDFlipFlop::inputChanged( bool newState ) +{ + unsigned long long simTime = m_pSimulator->time(); + if ( (simTime == m_prevDSimTime) && (newState == m_prevD[m_whichPrevD]) ) + return; + + m_prevDSimTime = simTime; + m_whichPrevD = 1-m_whichPrevD; + m_prevD[m_whichPrevD] = newState; +} + +void ECDFlipFlop::clockChanged( bool newState ) +{ + bool set = setp->isHigh(); + bool rst = rstp->isHigh(); + + bool fallingEdge = m_bPrevClock && !newState; + m_bPrevClock = newState; + + if( set || rst ) return; + + if (fallingEdge) + { + unsigned long long simTime = m_pSimulator->time(); + bool d = ( simTime == m_prevDSimTime ) ? m_prevD[1-m_whichPrevD] : m_prevD[m_whichPrevD]; + + m_pQ->setHigh(d); + m_pQBar->setHigh(!d); + } +} + +void ECDFlipFlop::inStateChanged(bool) +{ + // Only called when the flipflop is created. + m_pQ->setHigh(false); + m_pQBar->setHigh(true); +} +//END class ECDFlipFlop + + +//BEGIN class ECJKFlipFlop +Item* ECJKFlipFlop::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECJKFlipFlop( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECJKFlipFlop::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/jk_flipflop"), + i18n("JK Flip-Flop"), + i18n("Integrated Circuits"), + "ic3.png", + LibraryItem::lit_component, + ECJKFlipFlop::construct ); +} + +ECJKFlipFlop::ECJKFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "jk_flipflop" ) +{ + m_name = i18n("JK-Type Flip-Flop"); + m_desc = i18n("The output state is set according to J and K when the clock is pulsed."); + + setSize( -32, -32, 64, 64 ); + + init3PinLeft( -16, 0, 16 ); + init2PinRight( -16, 16 ); + + m_pJ = createLogicIn( m_pNNode[0] ); + m_pClock = createLogicIn( m_pNNode[1] ); + m_pK = createLogicIn( m_pNNode[2] ); + + m_pQ = createLogicOut( m_pPNode[0], false ); + m_pQBar = createLogicOut( m_pPNode[1], false ); + + setp = createLogicIn( createPin( 0, -40, 90, "set" ) ); + rstp = createLogicIn( createPin( 0, 40, 270, "rst" ) ); + + addDisplayText( "J", QRect( -32, -24, 20, 16 ), "J" ); + addDisplayText( ">", QRect( -32, -8, 20, 16 ), ">" ); + addDisplayText( "K", QRect( -32, 8, 20, 16 ), "K" ); + addDisplayText( "Q", QRect( 12, -24, 20, 16 ), "Q" ); + addDisplayText( "Q'", QRect( 12, 8, 20, 16 ), "Q'" ); + addDisplayText( "Set", QRect( -16, -28, 32, 16 ), "Set" ); + addDisplayText( "Rst", QRect( -16, 12, 32, 16 ), "Rst" ); + + m_pClock->setCallback( this, (CallbackPtr)(&ECJKFlipFlop::clockChanged) ); + setp->setCallback( this, (CallbackPtr)(&ECJKFlipFlop::asyncChanged) ); + rstp->setCallback( this, (CallbackPtr)(&ECJKFlipFlop::asyncChanged) ); + + inStateChanged(false); +} + +ECJKFlipFlop::~ECJKFlipFlop() +{ +} + +void ECJKFlipFlop::clockChanged(bool newvalue) +{ + bool j = m_pJ->isHigh(); + bool k = m_pK->isHigh(); + bool set = setp->isHigh(); + bool rst = rstp->isHigh(); + + if( set || rst ) return; + +// a JK flip-flop change state when clock do 1->0 + if (!newvalue && (j || k)) { + if ( j && k ) { + m_pQ->setHigh(!prev_state); + m_pQBar->setHigh(prev_state); + prev_state = !prev_state; + } else { + // (J=1 && K=0) || (J=0 && K=1) + m_pQ->setHigh(j); + m_pQBar->setHigh(k); + prev_state = j; + } + } +} + +void ECJKFlipFlop::asyncChanged(bool) +{ + bool set = setp->isHigh(); + bool rst = rstp->isHigh(); + + if (set || rst) { + m_pQ->setHigh(set); + m_pQBar->setHigh(rst); + prev_state = set; + } +} + +void ECJKFlipFlop::inStateChanged(bool) +{ + m_pQBar->setHigh(true); + m_pQ->setHigh(false); + prev_state = false; +} +//END class ECJKFlipFlop + + +//BEGIN class ECSRFlipFlop +Item* ECSRFlipFlop::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECSRFlipFlop( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECSRFlipFlop::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/sr_flipflop"), + i18n("SR Flip-Flop"), + i18n("Integrated Circuits"), + "ic3.png", + LibraryItem::lit_component, + ECSRFlipFlop::construct ); +} + +ECSRFlipFlop::ECSRFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "sr_flipflop" ) +{ + m_name = i18n("SR Flip-Flop"); + m_desc = i18n("The output is made high by holding set high, and low by holding reset high."); + + setSize( -24, -24, 48, 48 ); + + init2PinLeft( -8, 8 ); + init2PinRight( -8, 8 ); + + m_pS = createLogicIn( m_pNNode[0] ); + m_pR = createLogicIn( m_pNNode[1] ); + m_pQ = createLogicOut( m_pPNode[0], true ); + m_pQBar = createLogicOut( m_pPNode[1], false ); + + old_q1 = true; + old_q2 = false; + m_pQ->setHigh(old_q1); + m_pQBar->setHigh(old_q2); + + addDisplayText( "S", QRect( -24, -16, 20, 16 ), "S" ); + addDisplayText( "R", QRect( -24, 0, 20, 16 ), "R" ); + addDisplayText( "Q", QRect( 4, -16, 20, 16 ), "Q" ); + addDisplayText( "Q'", QRect( 4, 0, 20, 16 ), "Q'" ); + + m_pS->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) ); + m_pR->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) ); + m_pQ->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) ); + m_pQBar->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) ); +} + +ECSRFlipFlop::~ECSRFlipFlop() +{ +} + +void ECSRFlipFlop::inStateChanged(bool) +{ + // Q = v_q1, Q-bar = v_q2 + bool new_q1 = false; + bool new_q2 = false; + + bool s = m_pS->isHigh(); + bool r = m_pR->isHigh(); + bool q1 = m_pQ->isHigh(); + bool q2 = m_pQBar->isHigh(); + + // Easy ones to do :-) + if (!q1) new_q2 = true; + if (!q2) new_q1 = true; + + if ( q1 && q2 ) + { + if ( s && !r ) + { + new_q1 = true; + new_q2 = false; + } + else if ( !s && r ) + { + new_q1 = false; + new_q2 = true; + } + else if ( s && r ) + { + new_q1 = old_q1; + new_q2 = old_q2; + } + else if ( !s && !r ) + { + new_q1 = false; + new_q2 = false; + } + } + else if ( q1 && !q2 ) + { + // Note: We only need to set the value of v_q2 + if ( r && !s ) new_q2 = true; + else new_q2 = false; + } + else if ( !q1 && q2 ) + { + // Note: We only need to set the value of v_q1 + if ( s && !r ) new_q1 = true; + else new_q1 = false; + } + + old_q1 = new_q1; + old_q2 = new_q2; + + m_pQ->setHigh(new_q1); + m_pQBar->setHigh(new_q2); +} +//END class ECSRFlipFlop diff --git a/src/electronics/components/flipflop.h b/src/electronics/components/flipflop.h new file mode 100644 index 0000000..7b9d5b7 --- /dev/null +++ b/src/electronics/components/flipflop.h @@ -0,0 +1,107 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef FLIPFLOP_H +#define FLIPFLOP_H + +#include "component.h" +#include "logic.h" + +class Simulator; + +/** +@short Boolean D-Type Flip-Flop +@author David Saxton +*/ +class ECDFlipFlop : public CallbackClass, public Component +{ +public: + ECDFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECDFlipFlop(); + virtual bool canFlip() const { return true; } + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inputChanged( bool newState ); + void inStateChanged( bool newState ); + void asyncChanged(bool newState ); + void clockChanged(bool newState ); + + LogicIn *m_pD; + LogicIn *m_pClock; + LogicOut *m_pQ; + LogicOut *m_pQBar; + LogicIn *setp; + LogicIn *rstp; + bool m_bPrevClock; + + bool m_prevD[2]; + unsigned m_whichPrevD:1; + unsigned long long m_prevDSimTime; + Simulator * m_pSimulator; +}; + + +/** +@short Boolean JK-Type Flip-Flop +@author Couriousous +*/ +class ECJKFlipFlop : public CallbackClass, public Component +{ +public: + ECJKFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECJKFlipFlop(); + virtual bool canFlip() const { return true; } + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + void asyncChanged(bool newState ); + void clockChanged(bool newState ); + bool prev_state; + LogicIn *m_pJ; + LogicIn *m_pClock; + LogicIn *m_pK; + LogicIn *setp; + LogicIn *rstp; + LogicOut *m_pQ; + LogicOut *m_pQBar; +}; + + +/** +@short Boolean Set-Reset Flip-Flop +@author David Saxton +*/ +class ECSRFlipFlop : public CallbackClass, public Component +{ +public: + ECSRFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECSRFlipFlop(); + virtual bool canFlip() const { return true; } + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void inStateChanged( bool newState ); + LogicIn * m_pS; + LogicIn * m_pR; + LogicOut * m_pQ; + LogicOut * m_pQBar; + bool old_q1; + bool old_q2; +}; + +#endif diff --git a/src/electronics/components/fulladder.cpp b/src/electronics/components/fulladder.cpp new file mode 100644 index 0000000..ad5e40c --- /dev/null +++ b/src/electronics/components/fulladder.cpp @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright (C) 2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "fulladder.h" + +#include "logic.h" +#include "libraryitem.h" + +#include +#include + + +Item* FullAdder::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new FullAdder( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* FullAdder::libraryItem() +{ + return new LibraryItem( + QString("ec/adder"), + i18n("Adder"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + FullAdder::construct + ); +} + +FullAdder::FullAdder( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "adder" ) +{ + m_name = i18n("Adder"); +// m_desc = i18n("Insert missing adder help here."); + + ALogic = BLogic = inLogic = 0l; + outLogic = SLogic = 0l; + + QStringList pins = QStringList::split( ',', "A,B,>,,S,C", true ); + initDIPSymbol( pins, 48 ); + initDIP(pins); + + ECNode *node; + + node = ecNodeWithID("S"); + SLogic = createLogicOut( node, false ); + + node = ecNodeWithID("C"); + outLogic = createLogicOut( node, false ); + + node = ecNodeWithID("A"); + ALogic = createLogicIn(node); + + node = ecNodeWithID("B"); + BLogic = createLogicIn(node); + + node = ecNodeWithID(">"); + inLogic = createLogicIn(node); + + + ALogic->setCallback( this, (CallbackPtr)(&FullAdder::inStateChanged) ); + BLogic->setCallback( this, (CallbackPtr)(&FullAdder::inStateChanged) ); + inLogic->setCallback( this, (CallbackPtr)(&FullAdder::inStateChanged) ); +} + +FullAdder::~FullAdder() +{ +} + + +void FullAdder::inStateChanged( bool /*state*/ ) +{ + const bool A = ALogic->isHigh(); + const bool B = BLogic->isHigh(); + const bool in = inLogic->isHigh(); + + const bool out = (!A && B && in) || (A && !B && in) || (A && B); + const bool S = (!A && !B && in) || (!A && B && !in) || (A && !B && !in) || (A && B && in); + + SLogic->setHigh(S); + outLogic->setHigh(out); +} + + diff --git a/src/electronics/components/fulladder.h b/src/electronics/components/fulladder.h new file mode 100644 index 0000000..d4277e5 --- /dev/null +++ b/src/electronics/components/fulladder.h @@ -0,0 +1,37 @@ +/*************************************************************************** + * Copyright (C) 2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECFullAdder_H +#define ECFullAdder_H + +#include "component.h" +#include "logic.h" + +/** +@author David Saxton +*/ +class FullAdder : public CallbackClass, public Component +{ +public: + FullAdder( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~FullAdder(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + virtual bool canFlip() const { return true; } + +protected: + void inStateChanged( bool newState ); + + LogicIn *ALogic, *BLogic, *inLogic; + LogicOut *outLogic, *SLogic; +}; + +#endif diff --git a/src/electronics/components/inductor.cpp b/src/electronics/components/inductor.cpp new file mode 100644 index 0000000..9e30b34 --- /dev/null +++ b/src/electronics/components/inductor.cpp @@ -0,0 +1,84 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "inductance.h" +#include "inductor.h" +#include "libraryitem.h" + +#include +#include + +Item* Inductor::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Inductor( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Inductor::libraryItem() +{ + return new LibraryItem( + "ec/inductor", + i18n("Inductor"), + i18n("Discrete"), + "inductor.png", + LibraryItem::lit_component, + Inductor::construct + ); +} + +Inductor::Inductor( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "inductor" ) +{ + m_name = i18n("Inductor"); +// m_desc = i18n("Stores electrical charge.

    " +// "The voltage across the inductor and inductance are related by Charge = Inductance x Voltage."); + setSize( -16, -8, 32, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_pInductance = createInductance( m_pNNode[0], m_pPNode[0], 0.001 ); + + createProperty( "Inductance", Variant::Type::Double ); + property("Inductance")->setCaption( i18n("Inductance") ); + property("Inductance")->setUnit("H"); + property("Inductance")->setMinValue(1e-12); + property("Inductance")->setMaxValue(1e12); + property("Inductance")->setValue(1e-3); + + addDisplayText( "inductance", QRect( -8, -24, 16, 16 ), "", false ); +} + +Inductor::~Inductor() +{ +} + +void Inductor::dataChanged() +{ + double inductance = dataDouble("Inductance"); + + QString display = QString::number( inductance / getMultiplier(inductance), 'g', 3 ) + getNumberMag(inductance) + "H"; + setDisplayText( "inductance", display ); + + m_pInductance->setInductance(inductance); +} + +void Inductor::drawShape( QPainter &p ) +{ + initPainter(p); + int _y = int(y()); + int _x = int(x()); + + p.drawArc( _x-16, _y-5, 11, 11, 0, 180*16 ); + p.drawArc( _x-5, _y-5, 11, 11, 0, 180*16 ); + p.drawArc( _x+6, _y-5, 11, 11, 0, 180*16 ); + + deinitPainter(p); +} + diff --git a/src/electronics/components/inductor.h b/src/electronics/components/inductor.h new file mode 100644 index 0000000..abb4eec --- /dev/null +++ b/src/electronics/components/inductor.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef INDUCTOR_H +#define INDUCTOR_H + +#include + +/** +@author David Saxton +*/ +class Inductor : public Component +{ + public: + Inductor( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Inductor(); + + static Item * construct( ItemDocument * itemDocument, bool newItem, const char * id ); + static LibraryItem * libraryItem(); + + private: + void dataChanged(); + virtual void drawShape( QPainter & p ); + + Inductance * m_pInductance; +}; + +#endif diff --git a/src/electronics/components/magnitudecomparator.cpp b/src/electronics/components/magnitudecomparator.cpp new file mode 100644 index 0000000..2659122 --- /dev/null +++ b/src/electronics/components/magnitudecomparator.cpp @@ -0,0 +1,206 @@ +/*************************************************************************** + * Copyright (C) 2005 by Fredy Yanardi * + * * + * 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 "libraryitem.h" +#include "logic.h" +#include "magnitudecomparator.h" +#include "variant.h" + +#include +#include + +Item* MagnitudeComparator::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new MagnitudeComparator( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* MagnitudeComparator::libraryItem() +{ + return new LibraryItem( + QString("ec/magnitudecomparator"), + i18n("Magnitude Comparator"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + MagnitudeComparator::construct + ); +} + +MagnitudeComparator::MagnitudeComparator( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "magnitudecomparator" ) +{ + m_name = i18n("Magnitude Comparator"); +// m_desc = i18n("Compares to two binary number and generates input to indicate which binary number has greater magnitude. It has 3 cascading inputs: I0 for IA > B, I1 for IA < B, and I2 for IA = B and 3 outputs: O0 for OA > B, O1 for OA < B, and O2 for OA = B"); + m_desc = i18n("Compares two binary numbers and generates output to indicate which binary number has the greater magnitude. It has 3 cascading inputs:" + "
    • I: A > B
    • " + "
    • I: A < B
    • " + "
    • I: A = B
    " + "and 3 outputs:" + "
    • O: A > B
    • " + "
    • O: A < B
    • " + "
    • O: A = B
    "); + + createProperty( "numInput", Variant::Type::Int ); + property("numInput")->setCaption( i18n("Number Inputs") ); + property("numInput")->setMinValue(1); + property("numInput")->setMaxValue(8); + property("numInput")->setValue(4); + + m_oldABLogicCount = 0; + cascadingInputs = 3; + outputs = 3; + + firstTime = true; +} + +MagnitudeComparator::~MagnitudeComparator() +{ +} + + +void MagnitudeComparator::dataChanged() +{ + initPins(); +} + + +void MagnitudeComparator::inStateChanged() +{ + int i; + + for ( i = 0; i < 3; i++ ) + m_output[i]->setHigh(false); + +// for ( i = dataInt("numInput")-1; i >= 0; i-- ) { + for ( i = m_oldABLogicCount-1; i >= 0; i-- ) { + if (m_aLogic[i]->isHigh() && !m_bLogic[i]->isHigh()) + { + m_output[0]->setHigh(true); + return; + } + else if ( !m_aLogic[i]->isHigh() && m_bLogic[i]->isHigh() ) { + m_output[1]->setHigh(true); + return; + } + } + + if ( m_cLogic[2]->isHigh() ) + m_output[2]->setHigh(true); + else if ( m_cLogic[0]->isHigh() ) + if ( !m_cLogic[1]->isHigh() ) + m_output[0]->setHigh(true); + else + ; + else if ( m_cLogic[1]->isHigh() ) + m_output[1]->setHigh(true); + else { + m_output[0]->setHigh(true); + m_output[1]->setHigh(true); + } +} + + +void MagnitudeComparator::initPins() +{ + const double numInputs = dataInt("numInput"); + int newABLogicCount = (int)numInputs; + + if ( newABLogicCount == m_oldABLogicCount ) + return; + + QStringList leftPins; + int space = 3 - newABLogicCount; + for ( int i = 0; i < space; i++ ) + leftPins << ""; + for ( int i = 0; i < newABLogicCount; i++ ) + leftPins << QString("A%1").arg( QString::number(i) ); + for ( int i = 0; i < newABLogicCount; i++ ) + leftPins << QString("B%1").arg( QString::number(i) ); + for ( int i = 0; i < space; i++ ) + leftPins << ""; + + QStringList rightPins; + space = -space; + for ( int i = 0; i < space; i++ ) + rightPins << ""; + QString inNames[] = { "I: A>B", "I: AB", "O: AsetCallback( this, (CallbackPtr)(&MagnitudeComparator::inStateChanged)); + } + + m_output.resize(3); + for ( int i = 0; i < outputs; i++ ) + { + node = ecNodeWithID( outNames[i] ); + m_output.insert( i, createLogicOut(node,false) ); + } + firstTime = false; + } + + if ( newABLogicCount > m_oldABLogicCount ) + { + m_aLogic.resize(newABLogicCount); + for ( int i=m_oldABLogicCount; isetCallback( this, (CallbackPtr)(&MagnitudeComparator::inStateChanged) ); + } + + m_bLogic.resize(newABLogicCount); + for ( int i=m_oldABLogicCount; isetCallback( this, (CallbackPtr)(&MagnitudeComparator::inStateChanged) ); + } + } + else + { + for ( int i=newABLogicCount; i +#include + +/** +@author Fredy Yanardi + */ +class MagnitudeComparator : public CallbackClass, public Component +{ + public: + MagnitudeComparator( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~MagnitudeComparator(); + + virtual bool canFlip() const { return true; } + static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem * libraryItem(); + + protected: + void initPins(); + virtual void dataChanged(); + void inStateChanged(); + + int m_oldABLogicCount; + int cascadingInputs; + int outputs; + bool firstTime; + + QBitArray m_data; + + QPtrVector m_aLogic; + QPtrVector m_bLogic; + QPtrVector m_cLogic; + QPtrVector m_output; +}; + +#endif diff --git a/src/electronics/components/matrixdisplay.cpp b/src/electronics/components/matrixdisplay.cpp new file mode 100644 index 0000000..dd40b6a --- /dev/null +++ b/src/electronics/components/matrixdisplay.cpp @@ -0,0 +1,291 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "colorcombo.h" +#include "diode.h" +#include "ecled.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "matrixdisplay.h" +#include "simulator.h" + +#include +#include +#include +#include + +Item* MatrixDisplay::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new MatrixDisplay( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* MatrixDisplay::libraryItem() +{ + return new LibraryItem( + "ec/matrix_display", + i18n("Matrix Display"), + i18n("Outputs"), + "matrixdisplay.png", + LibraryItem::lit_component, + MatrixDisplay::construct ); +} + + +MatrixDisplay::MatrixDisplay( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "matrix_display" ) +{ + m_name = i18n("Matrix Display"); + m_desc = i18n("A matrix display of LEDs with a configurable number of columns and rows."); + m_bDynamicContent = true; + + //BEGIN Reset members + for ( unsigned i = 0; i < max_md_height; i++ ) + m_pRowNodes[i] = 0l; + for ( unsigned i = 0; i < max_md_width; i++ ) + m_pColNodes[i] = 0l; + + m_lastUpdatePeriod = 0.0; + m_r = m_g = m_b = 0.0; + m_bRowCathode = true; + m_numRows = 0; + m_numCols = 0; + //END Reset members + + createProperty( "0-rows", Variant::Type::Int ); + property("0-rows")->setCaption( i18n("Rows") ); + property("0-rows")->setMinValue(1); + property("0-rows")->setMaxValue(max_md_height); + property("0-rows")->setValue(7); + + createProperty( "1-cols", Variant::Type::Int ); + property("1-cols")->setCaption( i18n("Columns") ); + property("1-cols")->setMinValue(1); + property("1-cols")->setMaxValue(max_md_width); + property("1-cols")->setValue(5); + + createProperty( "color", Variant::Type::Color ); + property("color")->setCaption( i18n("Color") ); + property("color")->setColorScheme( ColorCombo::LED ); + + createProperty( "diode-configuration", Variant::Type::Select ); + property("diode-configuration")->setCaption( i18n("Configuration") ); + property("diode-configuration")->setAllowed( QStringList::split(',',"Row Cathode,Column Cathode") ); + property("diode-configuration")->setValue("Row Cathode"); + property("diode-configuration")->setAdvanced(true); +} + + +MatrixDisplay::~MatrixDisplay() +{ +} + + +void MatrixDisplay::dataChanged() +{ + QColor color = dataColor("color"); + m_r = double(color.red()) / double(0x100); + m_g = double(color.green()) / double(0x100); + m_b = double(color.blue()) / double(0x100); + + int numRows = dataInt("0-rows"); + int numCols = dataInt("1-cols"); + + bool ledsChanged = (numRows != int(m_numRows)) || (numCols != int(m_numCols)); + + if (ledsChanged) + initPins( numRows, numCols ); + + bool rowCathode = dataString("diode-configuration") == "Row Cathode"; + if ( (rowCathode != m_bRowCathode) || ledsChanged) + { + m_bRowCathode = rowCathode; + + for ( unsigned i = 0; i < m_numCols; i++ ) + { + for ( unsigned j = 0; j < m_numRows; j++ ) + { + removeElement( m_pDiodes[i][j], false ); + if (rowCathode) + m_pDiodes[i][j] = createDiode( m_pColNodes[i], m_pRowNodes[j] ); + else + m_pDiodes[i][j] = createDiode( m_pRowNodes[j], m_pColNodes[i] ); + } + } + } +} + + +void MatrixDisplay::initPins( unsigned numRows, unsigned numCols ) +{ + if ( (numRows == m_numRows) && (numCols == m_numCols) ) + return; + + if ( numRows > max_md_height ) + numRows = max_md_height; + + if ( numCols > max_md_width ) + numCols = max_md_width; + + m_lastUpdatePeriod = 0.0; + + //BEGIN Remove diodes + // All the diodes are going to be readded from dataChanged (where this + // function is called from), so easiest just to delete the diodes now and + // resize. + + for ( unsigned i = 0; i < m_numCols; i++ ) + { + for ( unsigned j = 0; j < m_numRows; j++ ) + removeElement( m_pDiodes[i][j], false ); + } + + m_avgBrightness.resize(numCols); + m_lastBrightness.resize(numCols); + m_pDiodes.resize(numCols); + + for ( unsigned i = 0; i < numCols; i++ ) + { + m_avgBrightness[i].resize(numRows); + m_lastBrightness[i].resize(numRows); + m_pDiodes[i].resize(numRows); + + for ( unsigned j = 0; j < numRows; j++ ) + { + m_avgBrightness[i][j] = 0.0; + m_lastBrightness[i][j] = 255; + m_pDiodes[i][j] = 0l; + } + + } + //END Remove diodes + + + //BEGIN Create or destroy pins + if ( numCols >= m_numCols ) + { + for ( unsigned i = m_numCols; i < numCols; i++ ) + m_pColNodes[i] = createPin( 0, 0, 270, colPinID(i) ); + } + else + { + for ( unsigned i = numCols; i < m_numCols; i++ ) + { + removeNode( colPinID(i) ); + m_pColNodes[i] = 0l; + } + } + m_numCols = numCols; + + if ( numRows >= m_numRows ) + { + for ( unsigned i = m_numRows; i < numRows; i++ ) + m_pRowNodes[i] = createPin( 0, 0, 0, rowPinID(i) ); + } + else + { + for ( unsigned i = numRows; i < m_numRows; i++ ) + { + removeNode( rowPinID(i) ); + m_pRowNodes[i] = 0l; + } + } + m_numRows = numRows; + //END Create or destroy pins + + + //BEGIN Position pins et al + setSize( -int(numCols+1)*8, -int(numRows+1)*8, int(numCols+1)*16, int(numRows+1)*16, true ); + + for ( int i = 0; i < int(m_numCols); i++ ) + { + m_nodeMap[colPinID(i)].x = offsetX() + 16 + 16*i; + m_nodeMap[colPinID(i)].y = offsetY() + height() + 8; + } + + for ( int i = 0; i < int(m_numRows); i++ ) + { + m_nodeMap[rowPinID(i)].x = offsetX() - 8; + m_nodeMap[rowPinID(i)].y = offsetY() + 16 + 16*i; + } + + updateAttachedPositioning(); + //END Position pins et al +} + + +QString MatrixDisplay::colPinID( int col ) const +{ + return QString("col_%1").arg(QString::number(col)); +} +QString MatrixDisplay::rowPinID( int row ) const +{ + return QString("row_%1").arg(QString::number(row)); +} + + +void MatrixDisplay::stepNonLogic() +{ + double interval = 1./LINEAR_UPDATE_RATE; + + for ( unsigned i = 0; i < m_numCols; i++ ) + { + for ( unsigned j = 0; j < m_numRows; j++ ) + m_avgBrightness[i][j] += ECLed::brightness( m_pDiodes[i][j]->current() )*interval; + } + + m_lastUpdatePeriod += interval; +} + + +void MatrixDisplay::drawShape( QPainter &p ) +{ + if ( isSelected() ) + p.setPen(m_selectedCol); + p.drawRect( boundingRect() ); + + initPainter(p); + + const int _x = int(x()+offsetX()); + const int _y = int(y()+offsetY()); + + // To avoid flicker, require at least a 10 ms sample before changing + // the brightness + double minUpdatePeriod = 0.0099; + + for ( int i = 0; i < int(m_numCols); i++ ) + { + for ( int j = 0; j < int(m_numRows); j++ ) + { + if ( m_lastUpdatePeriod > minUpdatePeriod ) + m_lastBrightness[i][j] = unsigned(m_avgBrightness[i][j]/m_lastUpdatePeriod); + + double _b = m_lastBrightness[i][j]; + + QColor brush = QColor( uint(255-(255-_b)*(1-m_r)), uint(255-(255-_b)*(1-m_g)), uint(255-(255-_b)*(1-m_b)) ); + p.setBrush(brush); + p.setPen( Qt::NoPen ); + p.drawEllipse( _x+10+i*16, _y+10+j*16, 12, 12 ); + } + } + + if ( m_lastUpdatePeriod > minUpdatePeriod ) + { + m_lastUpdatePeriod = 0.0; + + for ( unsigned i = 0; i < m_numCols; i++ ) + { + for ( unsigned j = 0; j < m_numRows; j++ ) + m_avgBrightness[i][j] = 0.0; + } + } + + deinitPainter(p); +} diff --git a/src/electronics/components/matrixdisplay.h b/src/electronics/components/matrixdisplay.h new file mode 100644 index 0000000..4851817 --- /dev/null +++ b/src/electronics/components/matrixdisplay.h @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef MATRIXDISPLAY_H +#define MATRIXDISPLAY_H + +#include +#include + +const unsigned max_md_width = 100; +const unsigned max_md_height = 20; + +/** +@author David Saxton +*/ +class MatrixDisplay : public Component +{ + public: + MatrixDisplay( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~MatrixDisplay(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual bool canFlip() const { return true; } + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + + protected: + virtual void drawShape( QPainter &p ); + virtual void dataChanged(); + void initPins( unsigned numRows, unsigned numCols ); + QString colPinID( int col ) const; + QString rowPinID( int row ) const; + + + QValueVector< QValueVector > m_avgBrightness; + QValueVector< QValueVector > m_lastBrightness; + QValueVector< QValueVector > m_pDiodes; + + ECNode * m_pRowNodes[max_md_height]; + ECNode * m_pColNodes[max_md_width]; + + double m_lastUpdatePeriod; + + double m_r, m_g, m_b; + bool m_bRowCathode; + + unsigned m_numRows; + unsigned m_numCols; +}; + +#endif diff --git a/src/electronics/components/matrixdisplaydriver.cpp b/src/electronics/components/matrixdisplaydriver.cpp new file mode 100644 index 0000000..da00bb7 --- /dev/null +++ b/src/electronics/components/matrixdisplaydriver.cpp @@ -0,0 +1,380 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "libraryitem.h" +#include "logic.h" +#include "matrixdisplaydriver.h" + +#include +#include +#include + +#include + +// Thank you Scott Dattalo! +// http://www.dattalo.com/gnupic/lcdfont.inc + +static char characterMap[256][5] = { +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //0 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //1 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //2 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //3 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //4 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //5 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //6 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //7 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //8 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //9 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //10 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //11 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //12 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //13 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //14 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //15 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //16 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //17 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //18 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //19 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //20 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //21 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //22 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //23 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //24 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //25 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //26 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //27 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //28 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //29 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //30 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //31 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //32 +{ 0x00, 0x00, 0x7d, 0x00, 0x00 }, //33 +{ 0x00, 0x70, 0x00, 0x70, 0x00 }, //34 +{ 0x14, 0x7f, 0x14, 0x7f, 0x14 }, //35 +{ 0x12, 0x2a, 0x7f, 0x2a, 0x24 }, //36 +{ 0x62, 0x64, 0x08, 0x13, 0x23 }, //37 +{ 0x36, 0x49, 0x55, 0x22, 0x05 }, //38 +{ 0x00, 0x50, 0x60, 0x00, 0x00 }, //39 +{ 0x00, 0x1c, 0x22, 0x41, 0x00 }, //40 +{ 0x00, 0x41, 0x22, 0x1c, 0x00 }, //41 +{ 0x14, 0x08, 0x3e, 0x08, 0x14 }, //42 +{ 0x08, 0x08, 0x3e, 0x08, 0x08 }, //43 +{ 0x00, 0x05, 0x06, 0x00, 0x00 }, //44 +{ 0x08, 0x08, 0x08, 0x08, 0x08 }, //45 +{ 0x00, 0x03, 0x03, 0x00, 0x00 }, //46 +{ 0x02, 0x04, 0x08, 0x10, 0x20 }, //47 +{ 0x3e, 0x45, 0x49, 0x51, 0x3e }, //48 +{ 0x00, 0x21, 0x7f, 0x01, 0x00 }, //49 +{ 0x21, 0x43, 0x45, 0x49, 0x31 }, //50 +{ 0x42, 0x41, 0x51, 0x69, 0x46 }, //51 +{ 0x0c, 0x14, 0x24, 0x7f, 0x04 }, //52 +{ 0x72, 0x51, 0x51, 0x51, 0x4e }, //53 +{ 0x1e, 0x29, 0x49, 0x49, 0x06 }, //54 +{ 0x40, 0x47, 0x48, 0x50, 0x60 }, //55 +{ 0x36, 0x49, 0x49, 0x49, 0x36 }, //56 +{ 0x30, 0x49, 0x49, 0x4a, 0x3c }, //57 +{ 0x00, 0x36, 0x36, 0x00, 0x00 }, //58 +{ 0x00, 0x35, 0x36, 0x00, 0x00 }, //59 +{ 0x08, 0x14, 0x22, 0x41, 0x00 }, //60 +{ 0x14, 0x14, 0x14, 0x14, 0x14 }, //61 +{ 0x41, 0x22, 0x14, 0x08, 0x00 }, //62 +{ 0x20, 0x40, 0x45, 0x48, 0x30 }, //63 +{ 0x26, 0x49, 0x4f, 0x41, 0x3e }, //64 +{ 0x3f, 0x44, 0x44, 0x44, 0x3f }, //65 +{ 0x7f, 0x49, 0x49, 0x49, 0x36 }, //66 +{ 0x3e, 0x41, 0x41, 0x41, 0x22 }, //67 +{ 0x7f, 0x41, 0x41, 0x41, 0x3e }, //68 +{ 0x7f, 0x49, 0x49, 0x49, 0x41 }, //69 +{ 0x7f, 0x48, 0x48, 0x48, 0x40 }, //70 +{ 0x3e, 0x41, 0x49, 0x49, 0x2f }, //71 +{ 0x7f, 0x08, 0x08, 0x08, 0x7f }, //72 +{ 0x00, 0x41, 0x7f, 0x41, 0x00 }, //73 +{ 0x02, 0x01, 0x41, 0x7e, 0x40 }, //74 +{ 0x7f, 0x08, 0x14, 0x22, 0x41 }, //75 +{ 0x7f, 0x01, 0x01, 0x01, 0x01 }, //76 +{ 0x7f, 0x40, 0x20, 0x40, 0x7f }, //77 +{ 0x7f, 0x10, 0x08, 0x04, 0x7f }, //78 +{ 0x3e, 0x41, 0x41, 0x41, 0x3e }, //79 +{ 0x7f, 0x48, 0x48, 0x48, 0x30 }, //80 +{ 0x3e, 0x41, 0x45, 0x42, 0x3d }, //81 +{ 0x7f, 0x48, 0x4c, 0x4a, 0x31 }, //82 +{ 0x31, 0x49, 0x49, 0x49, 0x46 }, //83 +{ 0x40, 0x40, 0x7f, 0x40, 0x40 }, //84 +{ 0x7e, 0x01, 0x01, 0x01, 0x7e }, //85 +{ 0x7c, 0x02, 0x01, 0x02, 0x7c }, //86 +{ 0x7e, 0x01, 0x0e, 0x01, 0x7e }, //87 +{ 0x63, 0x14, 0x08, 0x14, 0x63 }, //88 +{ 0x70, 0x08, 0x07, 0x08, 0x70 }, //89 +{ 0x43, 0x45, 0x49, 0x51, 0x61 }, //90 +{ 0x00, 0x7f, 0x41, 0x41, 0x00 }, //91 +{ 0x54, 0x34, 0x1f, 0x34, 0x54 }, //92 +{ 0x00, 0x41, 0x41, 0x7f, 0x00 }, //93 +{ 0x10, 0x20, 0x40, 0x20, 0x10 }, //94 +{ 0x01, 0x01, 0x01, 0x01, 0x01 }, //95 +{ 0x00, 0x40, 0x20, 0x10, 0x00 }, //96 +{ 0x02, 0x15, 0x15, 0x15, 0x0f }, //97 +{ 0x7f, 0x09, 0x11, 0x11, 0x0e }, //98 +{ 0x0e, 0x11, 0x11, 0x11, 0x02 }, //99 +{ 0x0e, 0x11, 0x11, 0x09, 0x7f }, //100 +{ 0x0e, 0x15, 0x15, 0x15, 0x0c }, //101 +{ 0x08, 0x3f, 0x48, 0x40, 0x20 }, //102 +{ 0x30, 0x49, 0x49, 0x49, 0x7e }, //103 +{ 0x7f, 0x08, 0x10, 0x10, 0x0f }, //104 +{ 0x00, 0x11, 0x5f, 0x01, 0x00 }, //105 +{ 0x02, 0x01, 0x21, 0x7e, 0x00 }, //106 +{ 0x7f, 0x04, 0x0a, 0x11, 0x00 }, //107 +{ 0x00, 0x41, 0x7f, 0x01, 0x00 }, //108 +{ 0x1f, 0x10, 0x0c, 0x10, 0x0f }, //109 +{ 0x1f, 0x08, 0x10, 0x10, 0x0f }, //110 +{ 0x0e, 0x11, 0x11, 0x11, 0x0e }, //111 +{ 0x1f, 0x14, 0x14, 0x14, 0x08 }, //112 +{ 0x08, 0x14, 0x14, 0x0c, 0x1f }, //113 +{ 0x1f, 0x08, 0x10, 0x10, 0x08 }, //114 +{ 0x09, 0x15, 0x15, 0x15, 0x12 }, //115 +{ 0x20, 0x7e, 0x21, 0x01, 0x02 }, //116 +{ 0x1e, 0x01, 0x01, 0x02, 0x1f }, //117 +{ 0x1c, 0x02, 0x01, 0x02, 0x1c }, //118 +{ 0x1e, 0x01, 0x06, 0x01, 0x1e }, //119 +{ 0x11, 0x0a, 0x04, 0x0a, 0x11 }, //120 +{ 0x18, 0x05, 0x05, 0x05, 0x1e }, //121 +{ 0x11, 0x13, 0x15, 0x19, 0x11 }, //122 +{ 0x00, 0x08, 0x36, 0x41, 0x00 }, //123 +{ 0x00, 0x00, 0x7f, 0x00, 0x00 }, //124 +{ 0x00, 0x41, 0x36, 0x08, 0x00 }, //125 +{ 0x08, 0x08, 0x2a, 0x1c, 0x08 }, //126 +{ 0x08, 0x1c, 0x2a, 0x08, 0x08 }, //127 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //128 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //129 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //130 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //131 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //132 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //133 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //134 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //135 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //136 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //137 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //138 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //139 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //140 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //141 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //142 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //143 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //144 +{ 0x07, 0x05, 0x07, 0x00, 0x00 }, //145 +{ 0x00, 0x00, 0x78, 0x40, 0x40 }, //146 +{ 0x01, 0x01, 0x0f, 0x00, 0x00 }, //147 +{ 0x04, 0x02, 0x01, 0x00, 0x00 }, //148 +{ 0x00, 0x0c, 0x0c, 0x00, 0x00 }, //149 +{ 0x28, 0x28, 0x29, 0x2a, 0x3c }, //150 +{ 0x10, 0x11, 0x16, 0x14, 0x18 }, //151 +{ 0x02, 0x04, 0x0f, 0x10, 0x00 }, //152 +{ 0x0c, 0x08, 0x19, 0x09, 0x0e }, //153 +{ 0x09, 0x09, 0x0f, 0x09, 0x09 }, //154 +{ 0x09, 0x0a, 0x0c, 0x1f, 0x08 }, //155 +{ 0x08, 0x1f, 0x08, 0x0a, 0x0c }, //156 +{ 0x01, 0x09, 0x09, 0x0f, 0x01 }, //157 +{ 0x15, 0x15, 0x15, 0x1f, 0x00 }, //158 +{ 0x0c, 0x00, 0x0d, 0x01, 0x0e }, //159 +{ 0x04, 0x04, 0x04, 0x04, 0x04 }, //160 +{ 0x40, 0x41, 0x5e, 0x48, 0x70 }, //161 +{ 0x04, 0x08, 0x1f, 0x20, 0x40 }, //162 +{ 0x38, 0x20, 0x61, 0x22, 0x3c }, //163 +{ 0x11, 0x11, 0x1f, 0x11, 0x11 }, //164 +{ 0x22, 0x24, 0x28, 0x7f, 0x20 }, //165 +{ 0x21, 0x7e, 0x20, 0x21, 0x3e }, //166 +{ 0x28, 0x28, 0x7f, 0x28, 0x28 }, //167 +{ 0x08, 0x31, 0x21, 0x22, 0x3c }, //168 +{ 0x10, 0x60, 0x21, 0x3e, 0x20 }, //169 +{ 0x21, 0x21, 0x21, 0x21, 0x3f }, //170 +{ 0x20, 0x79, 0x22, 0x7c, 0x20 }, //171 +{ 0x29, 0x29, 0x01, 0x02, 0x1c }, //172 +{ 0x21, 0x22, 0x24, 0x2a, 0x31 }, //173 +{ 0x20, 0x7e, 0x21, 0x29, 0x31 }, //174 +{ 0x30, 0x09, 0x01, 0x02, 0x3c }, //175 +{ 0x08, 0x31, 0x29, 0x26, 0x3c }, //176 +{ 0x28, 0x29, 0x3e, 0x48, 0x08 }, //177 +{ 0x30, 0x00, 0x31, 0x02, 0x3c }, //178 +{ 0x10, 0x51, 0x5e, 0x50, 0x10 }, //179 +{ 0x00, 0x7f, 0x08, 0x04, 0x00 }, //180 +{ 0x11, 0x12, 0x7c, 0x10, 0x10 }, //181 +{ 0x01, 0x21, 0x21, 0x21, 0x01 }, //182 +{ 0x21, 0x2a, 0x24, 0x2a, 0x30 }, //183 +{ 0x22, 0x24, 0x6f, 0x34, 0x22 }, //184 +{ 0x00, 0x01, 0x02, 0x7c, 0x00 }, //185 +{ 0x0f, 0x00, 0x20, 0x10, 0x0f }, //186 +{ 0x7e, 0x11, 0x11, 0x11, 0x11 }, //187 +{ 0x20, 0x21, 0x21, 0x22, 0x3c }, //188 +{ 0x10, 0x20, 0x10, 0x08, 0x06 }, //189 +{ 0x26, 0x20, 0x7f, 0x20, 0x26 }, //190 +{ 0x20, 0x24, 0x22, 0x25, 0x38 }, //191 +{ 0x00, 0x2a, 0x2a, 0x2a, 0x01 }, //192 +{ 0x0e, 0x12, 0x22, 0x02, 0x07 }, //193 +{ 0x01, 0x0a, 0x04, 0x0a, 0x30 }, //194 +{ 0x28, 0x3e, 0x29, 0x29, 0x29 }, //195 +{ 0x10, 0x7f, 0x10, 0x14, 0x18 }, //196 +{ 0x01, 0x21, 0x21, 0x3f, 0x01 }, //197 +{ 0x29, 0x29, 0x29, 0x29, 0x3f }, //198 +{ 0x10, 0x50, 0x51, 0x52, 0x1c }, //199 +{ 0x78, 0x01, 0x02, 0x7c, 0x00 }, //200 +{ 0x1f, 0x00, 0x3f, 0x01, 0x06 }, //201 +{ 0x3f, 0x01, 0x02, 0x04, 0x08 }, //202 +{ 0x3f, 0x21, 0x21, 0x21, 0x3f }, //203 +{ 0x38, 0x20, 0x21, 0x22, 0x3c }, //204 +{ 0x21, 0x21, 0x01, 0x02, 0x0c }, //205 +{ 0x20, 0x10, 0x40, 0x20, 0x00 }, //206 +{ 0x70, 0x50, 0x70, 0x00, 0x00 }, //207 +{ 0x0e, 0x11, 0x09, 0x06, 0x19 }, //208 +{ 0x02, 0x55, 0x15, 0x55, 0x0f }, //209 +{ 0x1f, 0x2a, 0x2a, 0x2a, 0x14 }, //210 +{ 0x0a, 0x15, 0x15, 0x11, 0x02 }, //211 +{ 0x3f, 0x02, 0x02, 0x04, 0x3e }, //212 +{ 0x0e, 0x11, 0x19, 0x15, 0x12 }, //213 +{ 0x0f, 0x12, 0x22, 0x22, 0x1c }, //214 +{ 0x1c, 0x22, 0x22, 0x22, 0x3f }, //215 +{ 0x02, 0x01, 0x1e, 0x10, 0x10 }, //216 +{ 0x20, 0x20, 0x00, 0x70, 0x00 }, //217 +{ 0x00, 0x00, 0x10, 0x5f, 0x00 }, //218 +{ 0x28, 0x10, 0x28, 0x00, 0x00 }, //219 +{ 0x18, 0x24, 0x7e, 0x24, 0x08 }, //220 +{ 0x14, 0x7f, 0x15, 0x01, 0x01 }, //221 +{ 0x1f, 0x48, 0x50, 0x50, 0x0f }, //222 +{ 0x0e, 0x51, 0x11, 0x51, 0x0e }, //223 +{ 0x3f, 0x12, 0x22, 0x22, 0x1c }, //224 +{ 0x1c, 0x22, 0x22, 0x12, 0x3f }, //225 +{ 0x3c, 0x52, 0x52, 0x52, 0x3c }, //226 +{ 0x03, 0x05, 0x02, 0x05, 0x06 }, //227 +{ 0x1a, 0x26, 0x20, 0x26, 0x1a }, //228 +{ 0x1e, 0x41, 0x01, 0x42, 0x1f }, //229 +{ 0x63, 0x55, 0x49, 0x41, 0x41 }, //230 +{ 0x22, 0x3c, 0x20, 0x3e, 0x22 }, //231 +{ 0x51, 0x4a, 0x44, 0x4a, 0x51 }, //232 +{ 0x3c, 0x02, 0x02, 0x02, 0x3f }, //233 +{ 0x28, 0x28, 0x3e, 0x28, 0x48 }, //234 +{ 0x22, 0x3c, 0x28, 0x28, 0x2e }, //235 +{ 0x3e, 0x28, 0x38, 0x28, 0x3e }, //236 +{ 0x04, 0x04, 0x15, 0x04, 0x04 }, //237 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //238 +{ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f }, //239 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //240 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //241 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //242 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //243 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //244 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //245 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //246 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //247 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //248 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //249 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //250 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //251 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //252 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //253 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //254 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //255 + }; + + +inline static bool displayBit( unsigned value, unsigned row, unsigned column ) +{ + assert( value < 256 ); + assert( row < 7 ); + assert( column < 5 ); + return characterMap[value][column] & (1 << row); +}; + + +Item* MatrixDisplayDriver::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new MatrixDisplayDriver( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem * MatrixDisplayDriver::libraryItem() +{ + return new LibraryItem( + "ec/matrix_display_driver", + i18n("Matrix Display Driver"), + i18n("Integrated Circuits"), + "ic2.png", + LibraryItem::lit_component, + MatrixDisplayDriver::construct ); +} + + +MatrixDisplayDriver::MatrixDisplayDriver( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "Matrix Display Driver" ) +{ + m_name = i18n("Matrix Display Driver"); + + m_prevCol = 0; + m_nextCol = 0; + m_scanCount = 2; + + createProperty( "diode-configuration", Variant::Type::Select ); + property("diode-configuration")->setCaption( i18n("Configuration") ); + property("diode-configuration")->setAllowed( QStringList::split(',',"Row Cathode,Column Cathode") ); + property("diode-configuration")->setValue("Row Cathode"); + property("diode-configuration")->setAdvanced(true); + + QStringList pins = QStringList::split( ',', "D0,D1,D2,D3,D4,D5,D6,D7,,,,,,C4,C3,C2,C1,C0,,R0,R1,R2,R3,R4,R5,R6", true ); + initDIPSymbol( pins, 64 ); + initDIP(pins); + + m_pValueLogic.resize( 8, 0l ); + for ( unsigned i = 0; i < 8; ++i ) + m_pValueLogic[i] = createLogicIn( ecNodeWithID("D"+QString::number(i)) ); + + m_pRowLogic.resize( 7, 0l ); + for ( unsigned i = 0; i < 7; ++i ) + { + m_pRowLogic[i] = createLogicOut( ecNodeWithID("R"+QString::number(i)), false ); + m_pRowLogic[i]->setOutputLowConductance( 1.0 ); + m_pRowLogic[i]->setOutputHighVoltage(5.0); + } + + m_pColLogic.resize( 5, 0l ); + for ( unsigned i = 0; i < 5; ++i ) + { + m_pColLogic[i] = createLogicOut( ecNodeWithID("C"+QString::number(i)), false ); + m_pColLogic[i]->setOutputHighVoltage(5.0); + } +} + + +MatrixDisplayDriver::~MatrixDisplayDriver() +{ +} + + +void MatrixDisplayDriver::stepNonLogic() +{ + if ( ++m_scanCount < 5 ) + return; + m_scanCount = 0; + + m_pColLogic[m_prevCol]->setHigh(false); + m_pColLogic[m_nextCol]->setHigh(true); + + unsigned value = 0; + for ( unsigned i = 0; i < 8; ++i ) + value |= ( m_pValueLogic[i]->isHigh() ) ? (1 << i) : 0; + + for ( unsigned row = 0; row < 7; row++ ) + { + m_pRowLogic[row]->setHigh( !displayBit( value, row, m_nextCol) ); + } + + m_prevCol = m_nextCol; + + m_nextCol++; + if ( m_nextCol >= 5 ) + m_nextCol = 0; +} + diff --git a/src/electronics/components/matrixdisplaydriver.h b/src/electronics/components/matrixdisplaydriver.h new file mode 100644 index 0000000..e6b01cc --- /dev/null +++ b/src/electronics/components/matrixdisplaydriver.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef MATRIXDISPLAYDRIVER_H +#define MATRIXDISPLAYDRIVER_H + +#include "matrixdisplay.h" + +/** +@author David Saxton + */ +class MatrixDisplayDriver : public Component +{ + public: + MatrixDisplayDriver( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~MatrixDisplayDriver(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual bool canFlip() const { return true; } + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + + protected: + QValueVector m_pValueLogic; + QValueVector m_pRowLogic; + QValueVector m_pColLogic; + + unsigned m_prevCol; + unsigned m_nextCol; + unsigned m_scanCount; +}; + +#endif diff --git a/src/electronics/components/meter.cpp b/src/electronics/components/meter.cpp new file mode 100644 index 0000000..4437794 --- /dev/null +++ b/src/electronics/components/meter.cpp @@ -0,0 +1,265 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasitemparts.h" +#include "ecnode.h" +#include "element.h" +#include "libraryitem.h" +#include "meter.h" +#include "variant.h" +#include "voltagesource.h" +#include "pin.h" +#include "simulator.h" + +#include +#include +#include + + +//BEGIN class Meter +Meter::Meter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ) +{ + m_bDynamicContent = true; + b_timerStarted = false; + m_timeSinceUpdate = 0.; + m_old_value = 0.; + m_avgValue = 0.; + b_firstRun = true; + setSize( -16, -16, 32, 32 ); + + p_displayText = addDisplayText( "meter", QRect( -16, 16, 32, 16 ), displayText() ); + + createProperty( "0-minValue", Variant::Type::Double ); + property("0-minValue")->setCaption( i18n("Minimum Value") ); + property("0-minValue")->setMinValue(1e-12); + property("0-minValue")->setMaxValue(1e12); + property("0-minValue")->setValue(1e-3); + + createProperty( "1-maxValue", Variant::Type::Double ); + property("1-maxValue")->setCaption( i18n("Maximum Value") ); + property("1-maxValue")->setMinValue(1e-12); + property("1-maxValue")->setMaxValue(1e12); + property("1-maxValue")->setValue(1e3); +} + + +Meter::~Meter() +{ +} + + +void Meter::dataChanged() +{ + m_minValue = dataDouble("0-minValue"); + m_maxValue = dataDouble("1-maxValue"); + setChanged(); +} + +void Meter::stepNonLogic() +{ + if (b_firstRun) + { + p_displayText->setText(displayText()); + updateAttachedPositioning(); + setChanged(); + property("0-minValue")->setUnit(m_unit); + property("1-maxValue")->setUnit(m_unit); + b_firstRun = false; + } + + const double v = meterValue(); + if ( !b_timerStarted && std::abs(((v-m_old_value)/m_old_value)) > 1e-6 ) { + b_timerStarted = true; + } + + if (b_timerStarted) + { + m_timeSinceUpdate += 1./LINEAR_UPDATE_RATE; + m_avgValue += v/LINEAR_UPDATE_RATE; +// setChanged(); + if ( m_timeSinceUpdate > 0.05 ) + { + if ( p_displayText->setText(displayText()) ); + updateAttachedPositioning(); + } + } +} + +void Meter::drawShape( QPainter &p ) +{ + initPainter(p); + p.drawEllipse( (int)x()-16, (int)y()-16, width(), width() ); + p.setPen(QPen(Qt::black,2)); + p.setBrush(Qt::black); + + // The proportion between 0.1mV and 10KV, on a logarithmic scale + double prop; + const double abs_value = std::abs(m_old_value); + if ( abs_value <= m_minValue ) + prop = 0.; + else if ( abs_value >= m_maxValue ) + prop = 1.; + else + prop = std::log10( abs_value/m_minValue ) / std::log10( m_maxValue/m_minValue ); + if ( m_old_value>0 ) + prop *= -1; + double sin_prop = 10*std::sin(prop*1.571); // 1.571 = pi/2 + double cos_prop = 10*std::cos(prop*1.571); // 1.571 = pi/2 + + int cx = int(x()-16+(width()/2)); + int cy = int(y()-16+(height()/2)); + p.drawLine( int(cx-sin_prop), int(cy-cos_prop), int(cx+sin_prop), int(cy+cos_prop) ); + + QPointArray pa(3); + pa[0] = QPoint( int(cx-sin_prop), int(cy-cos_prop) ); // Arrow head + pa[1] = QPoint( int(cx-sin_prop + 8*std::sin(1.571*(-0.3+prop))), int(cy-cos_prop + 8*std::cos(1.571*(-0.3+prop))) ); + pa[2] = QPoint( int(cx-sin_prop + 8*std::sin(1.571*(0.3+prop))), int(cy-cos_prop + 8*std::cos(1.571*(0.3+prop))) ); + p.drawPolygon(pa); + + deinitPainter(p); +} + + +QString Meter::displayText() +{ + double value = m_avgValue/m_timeSinceUpdate; + if ( !std::isfinite(value) ) value = m_old_value; + if ( std::abs((value)) < 1e-9 ) value = 0.; + m_old_value = value; + m_avgValue = 0.; + m_timeSinceUpdate = 0.; + b_timerStarted = false; + return QString::number( value/CNItem::getMultiplier(value), 'g', 3 ) + CNItem::getNumberMag(value) + m_unit; +} +//END class Meter + + +//BEGIN class FrequencyMeter +Item* FrequencyMeter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new FrequencyMeter( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* FrequencyMeter::libraryItem() +{ + return new LibraryItem( + QString("ec/frequencymeter"), + i18n("Frequency Meter (TODO)"), + i18n("Outputs"), + "frequencymeter.png", + LibraryItem::lit_component, + FrequencyMeter::construct ); +} + +FrequencyMeter::FrequencyMeter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Meter( icnDocument, newItem, (id) ? id : "frequencymeter" ) +{ + m_name = i18n("Frequency Meter"); + m_desc = i18n("Place this at the point where frequency is to be measured."); + m_unit = "Hz"; + + m_probeNode = createPin( 0, -24, 90, "n1" ); +} + +FrequencyMeter::~FrequencyMeter() +{ +} + +double FrequencyMeter::meterValue() +{ + return 0; +} +//END class FrequencyMeter + + +//BEGIN class ECAmmeter +Item* ECAmmeter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECAmmeter( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECAmmeter::libraryItem() +{ + QStringList ids; + ids << "ec/ammeter" << "ec/ammmeter"; + return new LibraryItem( + ids, + i18n("Ammeter"), + i18n("Outputs"), + "ammeter.png", + LibraryItem::lit_component, + ECAmmeter::construct + ); +} + +ECAmmeter::ECAmmeter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Meter( icnDocument, newItem, (id) ? id : "ammeter" ) +{ + m_name = i18n("Ammeter"); + m_desc = i18n("Place this in series in the circuit to measure the current flowing."); + setSize( -16, -16, 32, 32 ); + m_unit = "A"; + + init1PinLeft(0); + init1PinRight(0); + + m_voltageSource = createVoltageSource( m_pNNode[0], m_pPNode[0], 0. ); +} + +ECAmmeter::~ECAmmeter() +{ +} + +double ECAmmeter::meterValue() +{ + return -m_voltageSource->cbranchCurrent(0); +} +//END class ECAmmeter + + +//BEGIN class ECVoltmeter +Item* ECVoltMeter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECVoltMeter( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECVoltMeter::libraryItem() +{ + return new LibraryItem( + QString("ec/voltmeter"), + i18n("Voltmeter"), + i18n("Outputs"), + "voltmeter.png", + LibraryItem::lit_component, + ECVoltMeter::construct ); +} + +ECVoltMeter::ECVoltMeter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Meter( icnDocument, newItem, (id) ? id : "voltmeter" ) +{ + m_name = i18n("Voltmeter"); + m_desc = i18n("Place this in parallel in the circuit to meaure the voltage between two points."); + m_unit = "V"; + + init1PinLeft(0); + init1PinRight(0); +} + +ECVoltMeter::~ECVoltMeter() +{ +} + +double ECVoltMeter::meterValue() +{ + return m_pNNode[0]->pin()->voltage() - m_pPNode[0]->pin()->voltage(); +} +//END class ECVoltMeter + diff --git a/src/electronics/components/meter.h b/src/electronics/components/meter.h new file mode 100644 index 0000000..fa52e95 --- /dev/null +++ b/src/electronics/components/meter.h @@ -0,0 +1,103 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef METER_H +#define METER_H + +#include + +/** +@author David Saxton +*/ +class Meter : public Component +{ +public: + Meter( ICNDocument *icnDocument, bool newItem, const char *id ); + ~Meter(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + virtual void drawShape( QPainter &p ); + +protected: + QString displayText(); + virtual void dataChanged(); + /** + * Return the value / current, or whatever the meter is measuring + */ + virtual double meterValue() = 0; + + bool b_firstRun; // If true, then update the text dispalyed + bool b_timerStarted; // The timer to change the text is started on change + double m_timeSinceUpdate; + double m_avgValue; + double m_old_value; + double m_minValue; + double m_maxValue; + Text *p_displayText; + QString m_unit; +}; + +/** +@short Measures the frequency at a point in the circuit +@author David Saxton +*/ +class FrequencyMeter : public Meter +{ +public: + FrequencyMeter( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~FrequencyMeter(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + virtual double meterValue(); + ECNode *m_probeNode; +}; + +/** +@short Simple resistor +@author David Saxton +*/ +class ECAmmeter : public Meter +{ +public: + ECAmmeter( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECAmmeter(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + virtual double meterValue(); + +private: + VoltageSource *m_voltageSource; +}; + +/** +@short Displays voltage across terminals +@author David Saxton +*/ +class ECVoltMeter : public Meter +{ +public: + ECVoltMeter( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECVoltMeter(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + virtual double meterValue(); +}; + +#endif diff --git a/src/electronics/components/multiinputgate.cpp b/src/electronics/components/multiinputgate.cpp new file mode 100644 index 0000000..7453845 --- /dev/null +++ b/src/electronics/components/multiinputgate.cpp @@ -0,0 +1,530 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "ecnode.h" +#include "icndocument.h" +#include "libraryitem.h" +#include "multiinputgate.h" +#include "logic.h" + +#include +#include +#include + +//BEGIN class MultiInputGate +MultiInputGate::MultiInputGate( ICNDocument *icnDocument, bool newItem, const char *id, int baseWidth ) + : Component( icnDocument, newItem, id ) +{ + b_doneInit = false; + m_numInputs = 0; + if ( baseWidth == -1 ) { + baseWidth = 32; + } + m_baseWidth = baseWidth; + + for ( int i=0; isetCaption( i18n("Number Inputs") ); + property("numInput")->setMinValue(2); + property("numInput")->setMaxValue(maxGateInput); + property("numInput")->setValue(2); + + b_doneInit = true; +} + + +MultiInputGate::~MultiInputGate() +{ +} + + +void MultiInputGate::dataChanged() +{ + updateInputs( QMIN( maxGateInput, dataInt("numInput") ) ); +} + + +void MultiInputGate::updateInputs( int newNum ) +{ + if ( newNum == m_numInputs ) { + return; + } + + if ( newNum < 2 ) { + newNum = 2; + } + else if ( newNum > maxGateInput ) { + newNum = maxGateInput; + } + + const int newWidth = m_baseWidth; + + setSize( -newWidth/2, -8*newNum, newWidth, 16*newNum, true ); + + const bool added = ( newNum > m_numInputs ); + if (added) + { + for ( int i = m_numInputs; isetCallback( this, (CallbackPtr)(&MultiInputGate::inStateChanged) ); + } + } + else + { + for ( int i=newNum; iisHigh() ) + highCount++; + } + + m_pOut->setHigh( highCount != 1 ); +} + +void ECXnor::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()+offsetX(); + int _y = (int)y()+offsetY(); + + p.save(); + p.setPen( Qt::NoPen ); + p.drawChord( _x-width()+22, _y, 2*width()-28, height(), -16*81, 16*162 ); + p.restore(); + + p.drawArc( _x-width()+22, _y, 2*width()-28, height(), -16*90, 16*180 ); + p.drawArc( _x-8, _y, 16, height(), -16*90, 16*180 ); + p.drawArc( _x, _y, 16, height(), -16*90, 16*180 ); + + p.drawEllipse( _x+width()-6, _y+(height()/2)-3, 6, 6 ); + + const int n = m_numInputs; + for ( int i=0; iisSelected() ? m_selectedCol : Qt::black ); + int pin_x = (int)std::sqrt((double)(64*n*n - (8*n-8-16*i)*(8*n-8-16*i)))/n; + p.drawLine( _x, _y+16*i+8, _x+pin_x, _y+16*i+8 ); + } + + deinitPainter(p); +} +//END class ECXnor + + +//BEGIN class ECXor +Item* ECXor::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECXor( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECXor::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/xor"), + i18n("XOR gate"), + i18n("Logic"), + "xor.png", + LibraryItem::lit_component, + ECXor::construct ); +} + +ECXor::ECXor( ICNDocument *icnDocument, bool newItem, const char *id ) + : MultiInputGate( icnDocument, newItem, (id) ? id : "xor", 48 ) +{ + m_name = i18n("XOR gate"); + m_desc = i18n("Exclusive OR gate. Output is high when exactly one input is high."); + + inStateChanged(false); +} + +ECXor::~ECXor() +{ +} + +void ECXor::inStateChanged(bool) +{ + int highCount = 0; + for ( int i=0; iisHigh() ) + highCount++; + } + + m_pOut->setHigh( highCount == 1 ); +} + +void ECXor::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()+offsetX(); + int _y = (int)y()+offsetY(); + + p.save(); + p.setPen( Qt::NoPen ); + p.drawChord( _x-width()+16, _y, 2*width()-16, height(), -16*81, 16*162 ); + p.restore(); + + p.drawArc( _x-width()+16, _y, 2*width()-16, height(), -16*90, 16*180 ); + p.drawArc( _x-8, _y, 16, height(), -16*90, 16*180 ); + p.drawArc( _x, _y, 16, height(), -16*90, 16*180 ); + + const int n = m_numInputs; + for ( int i=0; iisSelected() ? m_selectedCol : Qt::black ); + int pin_x = (int)std::sqrt((double)(64*n*n - (8*n-8-16*i)*(8*n-8-16*i)))/n; + p.drawLine( _x, _y+16*i+8, _x+pin_x, _y+16*i+8 ); + } + + deinitPainter(p); +} +//END class ECXor + + +//BEGIN class EXOr +Item* ECOr::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECOr( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECOr::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/or"), + i18n("OR gate"), + i18n("Logic"), + "or.png", + LibraryItem::lit_component, + ECOr::construct ); +} + +ECOr::ECOr( ICNDocument *icnDocument, bool newItem, const char *id ) + : MultiInputGate( icnDocument, newItem, (id) ? id : "or", 48 ) +{ + m_name = i18n("OR gate"); + m_desc = i18n("The output is high when at least one of the inputs is high; or low when all of the inputs are off"); + + inStateChanged(false); +} + +ECOr::~ECOr() +{ +} + +void ECOr::inStateChanged(bool) +{ + bool allLow = true; + for ( int i=0; iisHigh() ) + allLow = false; + } + + m_pOut->setHigh(!allLow); +} + +void ECOr::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()+offsetX(); + int _y = (int)y()+offsetY(); + + p.save(); + p.setPen( Qt::NoPen ); +// p.setBrush( Qt::red ); + p.drawChord( _x-width(), _y, 2*width(), height(), -16*81, 16*162 ); +// p.drawPie( _x-width()+16, _y, 2*width()-16, height(), -16*100, 16*200 ); + p.restore(); + + p.drawArc( _x-width(), _y, 2*width(), height(), -16*90, 16*180 ); + p.drawArc( _x-8, _y, 16, height(), -16*90, 16*180 ); + + const int n = m_numInputs; + for ( int i=0; iisSelected() ? m_selectedCol : Qt::black ); + int pin_x = (int)std::sqrt((double)(64*n*n - (8*n-8-16*i)*(8*n-8-16*i)))/n; + p.drawLine( _x, _y+16*i+8, _x+pin_x, _y+16*i+8 ); + } + + deinitPainter(p); +} +//END class ECOr + + +//BEGIN class ECNor +Item* ECNor::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECNor( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECNor::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/nor"), + i18n("NOR gate"), + i18n("Logic"), + "nor.png", + LibraryItem::lit_component, + ECNor::construct ); +} + +ECNor::ECNor( ICNDocument *icnDocument, bool newItem, const char *id ) + : MultiInputGate( icnDocument, newItem, (id) ? id : "nor", 48 ) +{ + m_name = i18n("NOR Gate"); + m_desc = i18n("The output is high when all inputs are low."); + + inStateChanged(false); +} + +ECNor::~ECNor() +{ +} + +void ECNor::inStateChanged(bool) +{ + bool allLow = true; + for ( int i=0; iisHigh() ) + allLow = false; + } + + m_pOut->setHigh(allLow); +} + +void ECNor::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()+offsetX(); + int _y = (int)y()+offsetY(); + + p.save(); + p.setPen( Qt::NoPen ); + p.drawChord( _x-width()+6, _y, 2*width()-12, height(), -16*81, 16*162 ); + p.restore(); + + p.drawArc( _x-width()+6, _y, 2*width()-12, height(), -16*90, 16*180 ); + p.drawArc( _x-8, _y, 16, height(), -16*90, 16*180 ); + + p.drawEllipse( _x+width()-6, _y+(height()/2)-3, 6, 6 ); + + const int n = m_numInputs; + for ( int i=0; iisSelected() ? m_selectedCol : Qt::black ); + int pin_x = (int)std::sqrt((double)(64*n*n - (8*n-8-16*i)*(8*n-8-16*i)))/n; + p.drawLine( _x, _y+16*i+8, _x+pin_x, _y+16*i+8 ); + } + + deinitPainter(p); +} +//END class ECNor + + +//BEGIN class ECNand +Item* ECNand::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECNand( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECNand::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/nand"), + i18n("NAND gate"), + i18n("Logic"), + "nand.png", + LibraryItem::lit_component, + ECNand::construct ); +} + +ECNand::ECNand( ICNDocument *icnDocument, bool newItem, const char *id ) + : MultiInputGate( icnDocument, newItem, id ? id : "nand" ) +{ + m_name = i18n("NAND Gate"); + m_desc = i18n("The output is low only when all of the inputs are high."); + + inStateChanged(false); +} + +ECNand::~ECNand() +{ +} + +void ECNand::inStateChanged(bool) +{ + bool allHigh = true; + for ( int i=0; iisHigh() ) + allHigh = false; + } + + m_pOut->setHigh(!allHigh); +} + +void ECNand::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()+offsetX(); + int _y = (int)y()+offsetY(); + p.drawChord( _x-width()+6, _y, 2*width()-12, height(), -16*90, 16*180 ); + p.drawEllipse( _x+width()-6, _y+(height()/2)-3, 6, 6 ); + deinitPainter(p); +} +//END class ECNand + + +//BEGIN class ECAnd +Item* ECAnd::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECAnd( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECAnd::libraryItem() +{ + QStringList idList; + idList << "ec/and" << "ec/and_2"; + return new LibraryItem( + idList, + i18n("AND gate"), + i18n("Logic"), + "and.png", + LibraryItem::lit_component, + ECAnd::construct ); +} + +ECAnd::ECAnd( ICNDocument *icnDocument, bool newItem, const char *id ) + : MultiInputGate( icnDocument, newItem, id ? id : "and" ) +{ + m_name = i18n("AND Gate"); + m_desc = i18n("The output is high if and only if all of the inputs are high."); + + inStateChanged(false); +} + +ECAnd::~ECAnd() +{ +} + +void ECAnd::inStateChanged(bool) +{ + bool allHigh = true; + for ( int i=0; iisHigh() ) + allHigh = false; + } + + m_pOut->setHigh(allHigh); +} + +void ECAnd::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()+offsetX(); + int _y = (int)y()+offsetY(); + p.drawChord( _x-width(), _y, 2*width(), height(), -16*90, 16*180 ); + + deinitPainter(p); +} +//END class ECAnd diff --git a/src/electronics/components/multiinputgate.h b/src/electronics/components/multiinputgate.h new file mode 100644 index 0000000..1981217 --- /dev/null +++ b/src/electronics/components/multiinputgate.h @@ -0,0 +1,160 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef MULTIINPUTGATE_H +#define MULTIINPUTGATE_H + +#include "component.h" +#include "logic.h" + +const int maxGateInput = 256; + +/** +@author David Saxton +*/ +class MultiInputGate : public CallbackClass, public Component +{ +public: + MultiInputGate( ICNDocument *icnDocument, bool newItem, const char *id, int baseWidth = -1 ); + ~MultiInputGate(); + +protected: + virtual void inStateChanged( bool newState ) = 0; + void dataChanged(); + void updateInputs( int newNum ); + + int m_numInputs; + int m_baseWidth; + + LogicIn *inLogic[maxGateInput]; + ECNode *inNode[maxGateInput]; + + LogicOut * m_pOut; + + virtual void updateAttachedPositioning(); + +private: + bool b_doneInit; +}; + + +/** +@short Boolean XNOR +@author David Saxton +*/ +class ECXnor : public MultiInputGate +{ +public: + ECXnor( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECXnor(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); +}; + + +/** +@short Boolean XOR +@author David Saxton +*/ +class ECXor : public MultiInputGate +{ +public: + ECXor( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECXor(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); +}; + + +/** +@short Boolean OR +@author David Saxton +*/ +class ECOr : public MultiInputGate +{ +public: + ECOr( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECOr(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); +}; + +/** +@short Boolean NOR +@author David Saxton +*/ +class ECNor : public MultiInputGate +{ +public: + ECNor( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECNor(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); +}; + +/** +@short Boolean NAND +@author David Saxton +*/ +class ECNand : public MultiInputGate +{ +public: + ECNand( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECNand(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); +}; + +/** +@short Boolean AND +@author David Saxton +*/ +class ECAnd : public MultiInputGate +{ +public: + ECAnd( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECAnd(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); +}; + + + +#endif diff --git a/src/electronics/components/multiplexer.cpp b/src/electronics/components/multiplexer.cpp new file mode 100644 index 0000000..e421fee --- /dev/null +++ b/src/electronics/components/multiplexer.cpp @@ -0,0 +1,176 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "multiplexer.h" + +#include "logic.h" +#include "libraryitem.h" + +#include +#include + +#include + +Item* Multiplexer::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Multiplexer( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Multiplexer::libraryItem() +{ + return new LibraryItem( + QString("ec/multiplexer"), + i18n("Multiplexer"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + Multiplexer::construct + ); +} + +Multiplexer::Multiplexer( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "multiplexer" ) +{ + m_name = i18n("Multiplexer"); + m_desc = i18n("Combines the input data stream into one single stream. The value of the input selected by the \"A\" inputs is passed to the output."); + + m_output = 0l; + + createProperty( "addressSize", Variant::Type::Int ); + property("addressSize")->setCaption( i18n("Address Size") ); + property("addressSize")->setMinValue(1); + property("addressSize")->setMaxValue(8); + property("addressSize")->setValue(1); + + // For backwards compatibility + createProperty( "numInput", Variant::Type::Int ); + property("numInput")->setMinValue(-1); + property("numInput")->setValue(-1); + property("numInput")->setHidden(true); +} + +Multiplexer::~Multiplexer() +{ +} + + +void Multiplexer::dataChanged() +{ + if ( hasProperty("numInput") && dataInt("numInput") != -1 ) + { + int addressSize = int( std::ceil( std::log( (double)dataInt("numInput") ) / std::log(2.0) ) ); + property("numInput")->setValue(-1); + + if ( addressSize < 1 ) + addressSize = 1; + else if ( addressSize > 8 ) + addressSize = 8; + + // This function will get called again when we set the value of numInput + property("addressSize")->setValue(addressSize); + return; + } + + if ( hasProperty("numInput") ) + { + m_variantData["numInput"]->deleteLater(); + m_variantData.remove("numInput"); + } + + initPins( unsigned(dataInt("addressSize")) ); +} + + +void Multiplexer::inStateChanged( bool /*state*/ ) +{ + unsigned long long pos = 0; + for ( unsigned i = 0; i < m_aLogic.size(); ++i ) + { + if ( m_aLogic[i]->isHigh() ) + pos += 1 << i; + } + m_output->setHigh( m_xLogic[pos]->isHigh() ); +} + + +void Multiplexer::initPins( unsigned newAddressSize ) +{ + unsigned oldAddressSize = m_aLogic.size(); + unsigned long long oldXLogicCount = m_xLogic.size(); + unsigned long long newXLogicCount = 1 << newAddressSize; + + if ( newXLogicCount == oldXLogicCount ) + return; + + QStringList pins; + + const int length = newAddressSize + newXLogicCount; + + for ( unsigned i=0; i oldXLogicCount ) + { + m_xLogic.resize(newXLogicCount); + for ( unsigned i=oldXLogicCount; isetCallback( this, (CallbackPtr)(&Multiplexer::inStateChanged) ); + } + + m_aLogic.resize(newAddressSize); + for ( unsigned i=oldAddressSize; isetCallback( this, (CallbackPtr)(&Multiplexer::inStateChanged) ); + } + } + else + { + for ( unsigned i = newXLogicCount; i < oldXLogicCount; ++i ) + { + QString id = "X"+QString::number(i); + removeDisplayText(id); + removeElement( m_xLogic[i], false ); + removeNode(id); + } + m_xLogic.resize(newXLogicCount); + + for ( unsigned i = newAddressSize; i < oldAddressSize; ++i ) + { + QString id = "A"+QString::number(i); + removeDisplayText(id); + removeElement( m_aLogic[i], false ); + removeNode(id); + } + m_aLogic.resize(newAddressSize); + } +} + diff --git a/src/electronics/components/multiplexer.h b/src/electronics/components/multiplexer.h new file mode 100644 index 0000000..42bcfc1 --- /dev/null +++ b/src/electronics/components/multiplexer.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef MULTIPLEXER_H +#define MULTIPLEXER_H + +#include "component.h" +#include "logic.h" + +#include + +/** +@author David Saxton +*/ +class Multiplexer : public CallbackClass, public Component +{ +public: + Multiplexer( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Multiplexer(); + + virtual bool canFlip() const { return true; } + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void dataChanged(); + /** + * Add / remove pins according to the number of inputs the user has requested + */ + void initPins( unsigned addressSize ); + + void inStateChanged( bool newState ); + + QPtrVector m_aLogic; + QPtrVector m_xLogic; + LogicOut * m_output; +}; + +#endif diff --git a/src/electronics/components/parallelportcomponent.cpp b/src/electronics/components/parallelportcomponent.cpp new file mode 100644 index 0000000..9bc17b4 --- /dev/null +++ b/src/electronics/components/parallelportcomponent.cpp @@ -0,0 +1,241 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "port.h" +#include "parallelportcomponent.h" + +#include "ecnode.h" +#include "itemdocument.h" +#include "libraryitem.h" +#include "pin.h" +#include "resistance.h" + +#include +#include +#include + +#include +#include + +Item* ParallelPortComponent::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ParallelPortComponent( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ParallelPortComponent::libraryItem() +{ + return new LibraryItem( + "ec/parallel_port", + i18n("Parallel Port"), + i18n("Connections"), + "ic1.png", + LibraryItem::lit_component, + ParallelPortComponent::construct + ); +} + +ParallelPortComponent::ParallelPortComponent( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "parallel_port" ) +{ + m_name = i18n("Parallel Port"); + m_desc = i18n("The pins are divided into 3 registers.

    " + "Data Pins

    " + "The data pins can be configured as either all input or all output. They are:" + "
      " + "
    • D[0..7]
    • " + "

    " + "Status Pins

    " + "The status pins are read-only. They area:" + "
      " + "
    • ERR - Error
    • " + "
    • ON - Online
    • " + "
    • PE - Paper End
    • " + "
    • ACK - Acknowledge
    • " + "
    • BUSY - Busy
    • " + "

    " + "Control Pins" + "
      " + "
    • STR - Strobe
    • " + "
    • AUT - Auto Feed
    • " + "
    • INIT - Init
    • " + "
    • SEL - Select
    • " + "

    " + "The remaining pins are all ground." + ); + + QPointArray pa( 4 ); + pa[0] = QPoint( -32, -112 ); + pa[1] = QPoint( 32, -104 ); + pa[2] = QPoint( 32, 104 ); + pa[3] = QPoint( -32, 112 ); + setItemPoints( pa ); + + m_pParallelPort = new ParallelPort(); + + for ( unsigned i = 0; i < 24; ++i ) + m_pLogic[i] = 0; + + ECNode * pin = 0; + + //BEGIN Data register + for ( int i = 0; i < 8; ++i ) + { + QString id = QString("D%1").arg(i); + QString name = id; + + pin = createPin( -40, -80 + 16*i, 0, id ); + addDisplayText( id, QRect( -28, -88 + 16*i, 28, 16 ), name, true, Qt::AlignLeft | Qt::AlignVCenter ); + + m_pLogic[i] = createLogicOut( pin, false ); + m_pLogic[i]->setCallback( this, (CallbackPtr)(&ParallelPortComponent::dataCallback) ); + } + //END Data register + + + //BEGIN Status register + QString statusNames[] = { "ERR", "ON", "PE", "ACK", "BUSY" }; + + // The statusIDs are referenced in the save file and must not change + QString statusIDs[] = { "ERROR", "ONLINE", "PE", "ACK", "BUSY" }; + + // Bits 0...2 in the Status register are not used + for ( int i = 3; i < 8; ++i ) + { + QString id = statusIDs[i-3]; + QString name = statusNames[i-3]; + + // Bit 3 (pin 15) doesn't not follow the same positioning pattern as + // the other pins in the Status register. + if ( i == 3 ) + { + pin = createPin( 40, -72, 180, id ); + addDisplayText( id, QRect( 0, -80, 28, 16 ), name, true, Qt::AlignRight | Qt::AlignVCenter ); + } + else + { + pin = createPin( -40, -16 + 16*i, 0, id ); + addDisplayText( id, QRect( -28, -24 + 16*i, 28, 16 ), name, true, Qt::AlignLeft | Qt::AlignVCenter ); + } + + m_pLogic[i+8] = createLogicOut( pin, false ); + } + //END Status register + + + //BEGIN Control register + QString controlNames[] = { "STR", "AUT", "INIT", "SEL" }; + + // The controlIDs are referenced in the save file and must not change + QString controlIDs[] = { "STROBE", "AUTO", "INIT", "SELECT" }; + + // Bits 4..7 are not used (well; bit 5 is, but not as a pin) + for ( int i = 0; i < 4; ++i ) + { + QString id = controlIDs[i]; + QString name = controlNames[i]; + + if ( i == 0 ) + { + pin = createPin( -40, -96, 0, id ); + addDisplayText( id, QRect( -28, -104, 28, 16 ), name, true, Qt::AlignLeft | Qt::AlignVCenter ); + } + else if ( i == 1 ) + { + pin = createPin( 40, -88, 180, id ); + addDisplayText( id, QRect( 0, -96, 28, 16 ), name, true, Qt::AlignRight | Qt::AlignVCenter ); + } + else + { + pin = createPin( 40, -88 + i*16, 180, id ); + addDisplayText( id, QRect( 0, -96 + i*16, 28, 16 ), name, true, Qt::AlignRight | Qt::AlignVCenter ); + } + + m_pLogic[i+16] = createLogicOut( pin, false ); + m_pLogic[i+16]->setCallback( this, (CallbackPtr)(&ParallelPortComponent::controlCallback) ); + } + //END Control register + + +#if 0 + // And make the rest of the pins ground + for ( int i = 0; i < 8; ++i ) + { + pin = createPin( 40, -24 + i*16, 180, QString("GND%1").arg( i ) ); + pin->pin()->setGroundType( Pin::gt_always ); + } +#endif + + Variant * v = createProperty( "port", Variant::Type::Combo ); + v->setAllowed( ParallelPort::ports( Port::ExistsAndRW ) ); + v->setCaption( i18n("Port") ); +} + + +ParallelPortComponent::~ParallelPortComponent() +{ + delete m_pParallelPort; +} + + +void ParallelPortComponent::dataChanged() +{ + initPort( dataString("port") ); +} + + +void ParallelPortComponent::initPort( const QString & port ) +{ + if ( port.isEmpty() ) + { + m_pParallelPort->closePort(); + return; + } + + if ( ! m_pParallelPort->openPort( port ) ) + { + p_itemDocument->canvas()->setMessage( i18n("Could not open port %1").arg( port ) ); + return; + } +} + + +void ParallelPortComponent::dataCallback( bool ) +{ + uchar value = 0; + for ( unsigned i = 0; i < 8; ++ i ) + value |= m_pLogic[ i + 0 ]->isHigh() ? 0 : (1 << i); + + m_pParallelPort->writeToData( value ); +} + + +void ParallelPortComponent::controlCallback( bool ) +{ + uchar value = 0; + for ( unsigned i = 0; i < 4; ++ i ) + value |= m_pLogic[ i + 16 ]->isHigh() ? 0 : (1 << i); + + m_pParallelPort->writeToControl( value ); +} + + +void ParallelPortComponent::stepNonLogic() +{ + uchar status = m_pParallelPort->readFromRegister( ParallelPort::Status ); + // Bits 0...2 in the Status register are not used + for ( int i = 3; i < 8; ++i ) + m_pLogic[i + 8]->setHigh( status | (1 << i) ); +} + + +void ParallelPortComponent::drawShape( QPainter & p ) +{ + drawPortShape( p ); +} diff --git a/src/electronics/components/parallelportcomponent.h b/src/electronics/components/parallelportcomponent.h new file mode 100644 index 0000000..89ead80 --- /dev/null +++ b/src/electronics/components/parallelportcomponent.h @@ -0,0 +1,49 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PARALLELPORTCOMPONENT_H +#define PARALLELPORTCOMPONENT_H + +#include "logic.h" +#include "component.h" + +class ParallelPort; + +/** +@author David Saxton + */ +class ParallelPortComponent : public CallbackClass, public Component +{ + public: + ParallelPortComponent( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ParallelPortComponent(); + + virtual bool canFlip() const { return true; } + static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem * libraryItem(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + + protected: + void initPort( const QString & port ); + virtual void dataChanged(); + virtual void drawShape( QPainter & p ); + + void dataCallback( bool ); + void controlCallback( bool ); + + /// Registers: { Data[0...7], Status[0...5], 0[6...7], Control[0...4], 0[5...7] } + LogicOut * m_pLogic[24]; + + ParallelPort * m_pParallelPort; +}; + +#endif diff --git a/src/electronics/components/piccomponent.cpp b/src/electronics/components/piccomponent.cpp new file mode 100644 index 0000000..47320bb --- /dev/null +++ b/src/electronics/components/piccomponent.cpp @@ -0,0 +1,437 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "config.h" +#ifndef NO_GPSIM + +#include "canvasitemparts.h" +#include "circuitdocument.h" +#include "docmanager.h" +#include "gpsimprocessor.h" +#include "libraryitem.h" +#include "logic.h" +#include "ktechlab.h" +#include "micropackage.h" +#include "picinfo.h" +#include "microlibrary.h" +#include "piccomponent.h" +#include "piccomponentpin.h" +#include "projectmanager.h" + +#include +#include +#include +#include +#include +#include + +#include "gpsim/ioports.h" +#include "gpsim/pic-processor.h" + +const QString _def_PICComponent_fileName = i18n(""); + + +Item* PICComponent::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new PICComponent( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* PICComponent::libraryItem() +{ + QStringList IDs; + IDs << "ec/pic" << "ec/picitem" << "ec/picitem_18pin"; + + return new LibraryItem( + IDs, + "PIC", + i18n("Integrated Circuits"), + "ic2.png", + LibraryItem::lit_component, + PICComponent::construct ); +} + +PICComponent::PICComponent( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "pic" ) +{ + m_name = i18n("PIC Micro"); + m_desc = i18n("The PIC component allows the simulation of a PIC program.

    " + "The loadable PIC program must be one of the following formats:" + "
    • Assembly (.asm)
    • " + "
    • FlowCode (.flowcode)
    • " + "
    • Symbol file (.cod)
    • " + "
    • Microbe (.microbe, .basic)
    • " + "
    • C source (.c)
    " + "Doubleclick on the PIC component to open up the program source file.

    " + "If the program source file is of type assembly, then the the opened text file will automatically be linked to the simulation. " + "You can control the program from the text document using the debug controls.

    " + "Explanation of buttons:" + "
    • Play - Run the PIC program from the point at which it was paused, or from the start otherwise.
    • " + "
    • Pause - Pause the simulation at the current execution point.
    • " + "
    • Stop - Reset all parts of the simulation.
    • " + "
    • Reload - Reread the PIC program from disk and restart gpsim.
    "); + + m_bCreatedInitialPackage = false; + m_bLoadingProgram = false; + m_pGpsim = 0L; + + addButton( "run", QRect(), KGlobal::iconLoader()->loadIcon( "player_play", KIcon::Small ) ); + addButton( "pause", QRect(), KGlobal::iconLoader()->loadIcon( "player_pause", KIcon::Small ) ); + addButton( "reset", QRect(), KGlobal::iconLoader()->loadIcon( "stop", KIcon::Small ) ); + addButton( "reload", QRect(), KGlobal::iconLoader()->loadIcon( "reload", KIcon::Small ) ); + + if ( icnDocument->ktechlab() ) + connect( icnDocument->ktechlab(), SIGNAL(recentFileAdded(const KURL &)), this, SLOT(slotUpdateFileList()) ); + + connect( ProjectManager::self(), SIGNAL(projectOpened()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(projectClosed()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(projectCreated()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(subprojectCreated()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(filesAdded()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(filesRemoved()), this, SLOT(slotUpdateFileList()) ); + + createProperty( "program", Variant::Type::FileName ); + property("program")->setCaption( i18n("Program") ); + property("program")->setFilter("*.flowcode *.asm *.cod *.basic|All Supported Files\n*.flowcode|FlowCode (*.flowcode)\n*.cod|Symbol File (*.cod)\n*.asm|Assembly Code (*.asm)\n*.basic *.microbe|Microbe (*.basic, *.microbe)\n*.c|C (*.c)*|All Files"); + + // Used for restoring the pins on file loading before we have had a change + // to compile the PIC program + createProperty( "lastPackage", Variant::Type::String ); + property("lastPackage")->setHidden( true ); + +// //HACK This is to enable loading with pre-0.3 files (which didn't set a "lastPackage" +// // property). This will allow a P16F84 PIC to be initialized (which agrees with pre-0.3 +// // behaviour), but it will also load it if + + // This to allow loading of the PIC component from pre-0.3 files (which didn't set a + // "lastPackage" property). + if ( !newItem ) + property("lastPackage")->setValue("P16F84"); + + slotUpdateFileList(); + slotUpdateBtns(); + + initPackage( 0 ); +} + + +PICComponent::~PICComponent() +{ + deletePICComponentPins(); + delete m_pGpsim; +} + + +void PICComponent::dataChanged() +{ + initPIC(false); +} + + +void PICComponent::initPIC( bool forceReload ) +{ + if ( !m_bCreatedInitialPackage ) + { + // We are still being created, so other connectors will be expecting us to + // have grown pins soonish. + MicroInfo * microInfo = MicroLibrary::self()->microInfoWithID( dataString("lastPackage") ); + if ( microInfo ) + initPackage( microInfo ); + } + + QString newProgram = KURL( dataString("program") ).path(); + bool newFile = (m_picFile != newProgram); + if ( !newFile && !forceReload ) + return; + + delete m_pGpsim; + m_pGpsim = 0L; + + switch ( GpsimProcessor::isValidProgramFile(newProgram) ) + { + case GpsimProcessor::DoesntExist: + if ( newProgram == _def_PICComponent_fileName && !newProgram.isEmpty() ) + break; + KMessageBox::sorry( 0l, i18n("The file \"%1\" does not exist.").arg( newProgram ) ); + m_picFile = QString::null; + break; + + case GpsimProcessor::IncorrectType: + if ( newProgram == _def_PICComponent_fileName && !newProgram.isEmpty() ) + break; + KMessageBox::sorry( 0L, i18n("\"%1\" is not a valid PIC program.\nThe file must exist, and the extension should be \".cod\", \".asm\", \".flowcode\", \".basic\", \".microbe\" or \".c\".\n\".hex\" is allowed, provided that there is a corresponding \".cod\" file.").arg(newProgram) ); + m_picFile = QString::null; + break; + + case GpsimProcessor::Valid: + m_picFile = newProgram; + m_symbolFile = createSymbolFile(); + break; + } + + slotUpdateBtns(); +} + + +void PICComponent::deletePICComponentPins() +{ + const PICComponentPinMap::iterator picComponentMapEnd = m_picComponentPinMap.end(); + for ( PICComponentPinMap::iterator it = m_picComponentPinMap.begin(); it != picComponentMapEnd; ++it ) + delete it.data(); + m_picComponentPinMap.clear(); +} + + +void PICComponent::initPackage( MicroInfo * microInfo ) +{ + MicroPackage * microPackage = microInfo ? microInfo->package() : 0l; + + if ( microPackage ) + { + m_bCreatedInitialPackage = true; + + //BEGIN Get pin IDs + QStringList allPinIDs = microPackage->pinIDs(); + QStringList ioPinIDs = microPackage->pinIDs( PicPin::type_bidir | PicPin::type_input | PicPin::type_open ); + + // Now, we make the unwanted pin ids blank, so a pin is not created for them + const QStringList::iterator allPinIDsEnd = allPinIDs.end(); + for ( QStringList::iterator it = allPinIDs.begin(); it != allPinIDsEnd; ++it ) + { + if ( !ioPinIDs.contains(*it) ) + *it = ""; + } + //END Get pin IDs + + + //BEGIN Remove old stuff + // Remove old text + TextMap textMapCopy = m_textMap; + const TextMap::iterator textMapEnd = textMapCopy.end(); + for ( TextMap::iterator it = textMapCopy.begin(); it != textMapEnd; ++it ) + removeDisplayText(it.key()); + + // Remove the old pins + deletePICComponentPins(); + + // Remove old nodes + NodeMap nodeMapCopy = m_nodeMap; + const NodeMap::iterator nodeMapEnd = nodeMapCopy.end(); + for ( NodeMap::iterator it = nodeMapCopy.begin(); it != nodeMapEnd; ++it ) + { + if ( !ioPinIDs.contains(it.key()) ) + removeNode( it.key() ); + } + + removeElements(); + //END Remove old stuff + + + + //BEGIN Create new stuff + initDIPSymbol( allPinIDs, 80 ); + initDIP(allPinIDs); + + PicPinMap picPinMap = microPackage->pins( PicPin::type_bidir | PicPin::type_input | PicPin::type_open ); + const PicPinMap::iterator picPinMapEnd = picPinMap.end(); + for ( PicPinMap::iterator it = picPinMap.begin(); it != picPinMapEnd; ++it ) + m_picComponentPinMap[it.key()] = new PICComponentPin( this, it.data() ); + //END Create new stuff + + + removeDisplayText( "no_file" ); + addDisplayText( "picid", QRect(offsetX(), offsetY()-16, width(), 16), microInfo->id() ); + } + else + { + setSize( -48, -72, 96, 144 ); + removeDisplayText( "picid" ); + addDisplayText( "no_file", sizeRect(), i18n("(No\nprogram\nloaded)") ); + } + + + //BEGIN Update button positions + int leftpos = (width()-88)/2+offsetX(); + button("run")->setOriginalRect( QRect( leftpos, height()+4+offsetY(), 20, 20 ) ); + button("pause")->setOriginalRect( QRect( leftpos+23, height()+4+offsetY(), 20, 20 ) ); + button("reset")->setOriginalRect( QRect( leftpos+46, height()+4+offsetY(), 20, 20 ) ); + button("reload")->setOriginalRect( QRect( leftpos+69, height()+4+offsetY(), 20, 20 ) ); + updateAttachedPositioning(); + //END Update button positions +} + + +void PICComponent::attachPICComponentPins() +{ + if ( !m_pGpsim || !m_pGpsim->picProcessor() ) + return; + + pic_processor * picProcessor = m_pGpsim->picProcessor(); + + const PICComponentPinMap::iterator end = m_picComponentPinMap.end(); + for ( PICComponentPinMap::iterator it = m_picComponentPinMap.begin(); it != end; ++it ) + it.data()->attach( picProcessor->get_pin( it.key() ) ); +} + + +void PICComponent::slotUpdateFileList() +{ + QStringList preFileList; + if ( p_icnDocument && p_icnDocument->ktechlab() ) + preFileList += p_icnDocument->ktechlab()->recentFiles(); + + QStringList fileList; + + if ( ProjectInfo * info = ProjectManager::self()->currentProject() ) + { + const KURL::List urls = info->childOutputURLs( ProjectItem::AllTypes, ProjectItem::ProgramOutput ); + KURL::List::const_iterator urlsEnd = urls.end(); + for ( KURL::List::const_iterator it = urls.begin(); it != urlsEnd; ++it ) + fileList << (*it).path(); + } + + const QStringList::iterator end = preFileList.end(); + for ( QStringList::iterator it = preFileList.begin(); it != end; ++it ) + { + QString file = KURL(*it).path(); + if ( (file.endsWith(".flowcode") || file.endsWith(".asm") || file.endsWith(".cod") || file.endsWith(".basic") || file.endsWith(".microbe") ) && !fileList.contains(file) ) { + fileList.append(file); + } + } + + QString fileName = dataString("program"); + + property("program")->setAllowed(fileList); + property("program")->setValue( fileName.isEmpty() ? _def_PICComponent_fileName : fileName ); +} + + +void PICComponent::buttonStateChanged( const QString &id, bool state ) +{ + if (!state) + return; + + if ( id == "reload" ) + { + programReload(); + return; + } + + if (!m_pGpsim) + return; + + if ( id == "run" ) + m_pGpsim->setRunning(true); + + else if ( id == "pause" ) + m_pGpsim->setRunning(false); + + else if ( id == "reset" ) + { + m_pGpsim->reset(); + + // Set all pin outputs to low + const PICComponentPinMap::iterator end = m_picComponentPinMap.end(); + for ( PICComponentPinMap::iterator it = m_picComponentPinMap.begin(); it != end; ++it ) + it.data()->resetOutput(); + } + + slotUpdateBtns(); +} + + +bool PICComponent::mouseDoubleClickEvent ( const EventInfo &eventInfo ) +{ + Q_UNUSED(eventInfo); + if ( m_picFile.isEmpty() || (m_picFile == _def_PICComponent_fileName) ) + return false; + + (void) DocManager::self()->openURL(m_picFile); + + return true; +} + + +QString PICComponent::createSymbolFile() +{ + m_bLoadingProgram = true; + slotUpdateBtns(); + + return GpsimProcessor::generateSymbolFile( dataString("program"), this, SLOT(slotCODCreationSucceeded()), SLOT(slotCODCreationFailed()) ); +} + + +void PICComponent::slotCODCreationSucceeded() +{ + m_bLoadingProgram = false; + + delete m_pGpsim; + m_pGpsim = new GpsimProcessor(m_symbolFile); + + if ( m_pGpsim->codLoadStatus() == GpsimProcessor::CodSuccess ) + { + MicroInfo * microInfo = m_pGpsim->microInfo(); + property("lastPackage")->setValue( microInfo->id() ); + initPackage( microInfo ); + + connect( m_pGpsim, SIGNAL(runningStatusChanged(bool )), this, SLOT(slotUpdateBtns()) ); + attachPICComponentPins(); + } + + else + { + m_pGpsim->displayCodLoadStatus(); + delete m_pGpsim; + m_pGpsim = 0l; + } + + slotUpdateBtns(); +} + + +void PICComponent::slotCODCreationFailed() +{ + m_bLoadingProgram = false; + slotUpdateBtns(); +} + + +void PICComponent::programReload() +{ + delete m_pGpsim; + m_pGpsim = 0L; + + initPIC(true); + + slotUpdateBtns(); +} + + +void PICComponent::slotUpdateBtns() +{ + // We can get called by the destruction of gpsim after our canvas has been set to NULL + if (!canvas()) + return; + + button("run")->setEnabled( m_pGpsim && !m_pGpsim->isRunning() ); + button("pause")->setEnabled( m_pGpsim && m_pGpsim->isRunning() ); + button("reset")->setEnabled( m_pGpsim ); + button("reload")->setEnabled( !m_bLoadingProgram && (dataString("program") != _def_PICComponent_fileName) ); + + canvas()->setChanged( button("run")->boundingRect() ); + canvas()->setChanged( button("pause")->boundingRect() ); + canvas()->setChanged( button("reset")->boundingRect() ); + canvas()->setChanged( button("reload")->boundingRect() ); +} + + +#include "piccomponent.moc" + +#endif diff --git a/src/electronics/components/piccomponent.h b/src/electronics/components/piccomponent.h new file mode 100644 index 0000000..165fbf6 --- /dev/null +++ b/src/electronics/components/piccomponent.h @@ -0,0 +1,97 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PICCOMPONENT_H +#define PICCOMPONENT_H + +#include "config.h" +#ifndef NO_GPSIM + +#include "component.h" + +#include +#include + +class Document; +class ECNode; +class GpsimProcessor; +class IOPIN; +class KTechlab; +class MicroInfo; +class MicroPackage; +class PIC_IOPORT; +class PICComponent; +class PICComponentPin; +class PicPin; +class TextDocument; + +typedef QMap< int, PICComponentPin * > PICComponentPinMap; + +/** +@short Electronic PIC device +@author David Saxton +*/ +class PICComponent : public Component +{ + Q_OBJECT + public: + PICComponent( ICNDocument * icnDocument, bool newItem, const char *id = 0L ); + ~PICComponent(); + + virtual bool canFlip() const { return true; } + static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem * libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual bool mouseDoubleClickEvent( const EventInfo &eventInfo ); + + void programReload(); + /** + * Sets up the pins, text, etc for the given PIC type. If info is null, + * then a generic rectangle is displayed (used when no file has been + * loaded yet). + */ + void initPackage( MicroInfo * info ); + + public slots: + void slotUpdateFileList(); + void slotUpdateBtns(); + + protected slots: + void slotCODCreationSucceeded(); + void slotCODCreationFailed(); + + protected: + /** + * Attaches all PICComponentPins to the current instance of gpsim. + */ + void attachPICComponentPins(); + void deletePICComponentPins(); + /** + * Attempts to compile the program to a symbol file, and connects the assembly + * finish signal to loadGpsim + */ + QString createSymbolFile(); + virtual void dataChanged(); + /** + * Initializes the PIC from the options the user has selected. + */ + void initPIC( bool forceReload ); + + QGuardedPtr m_pGpsim; + QString m_picFile; ///< The input program that the user selected + QString m_symbolFile; ///< The symbol file that was generated from m_picFile + bool m_bLoadingProgram; ///< True between createSymbolFile being called and the file being created + PICComponentPinMap m_picComponentPinMap; + bool m_bCreatedInitialPackage; ///< Set true once the initial package is loaded; until then, will load a package from the lastPackage data +}; + +#endif +#endif diff --git a/src/electronics/components/piccomponentpin.cpp b/src/electronics/components/piccomponentpin.cpp new file mode 100644 index 0000000..47ef6cb --- /dev/null +++ b/src/electronics/components/piccomponentpin.cpp @@ -0,0 +1,172 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "config.h" +#ifndef NO_GPSIM + +#include "micropackage.h" +#include "piccomponent.h" +#include "piccomponentpin.h" + +#include + +PICComponentPin::PICComponentPin( PICComponent * picComponent, PicPin picPin ) + : m_id( picPin.pinID ) +{ + m_gOutHigh = 0.0; + m_gOutLow = 0.0; + m_picPin = picPin; + m_pPICComponent = picComponent; + m_pLogicOut = 0l; + m_pLogicIn = 0l; + m_pIOPIN = 0l; + m_pStimulusNode = 0l; + Zth = 0.0; + Vth = 0.0; + + switch ( picPin.type ) + { + case PicPin::type_input: + { + m_pLogicIn = picComponent->createLogicIn( picComponent->ecNodeWithID(picPin.pinID) ); + break; + } + case PicPin::type_bidir: + { + m_pLogicOut = picComponent->createLogicOut( picComponent->ecNodeWithID(picPin.pinID), false ); + m_gOutHigh = 0.004; + m_gOutLow = 0.004; + break; + } + case PicPin::type_open: + { + m_pLogicOut = picComponent->createLogicOut( picComponent->ecNodeWithID(picPin.pinID), false ); + m_pLogicOut->setOutputHighVoltage(0.0); + m_pLogicOut->setOutputHighConductance(0.0); + m_gOutHigh = 0.0; + m_gOutLow = 0.004; + break; + } + case PicPin::type_vss: + case PicPin::type_vdd: + case PicPin::type_mclr: + case PicPin::type_osc: + default: + break; + } + + if (m_pLogicIn) + m_pLogicIn->setCallback( this, (CallbackPtr)(&PICComponentPin::logicCallback) ); + if (m_pLogicOut) + m_pLogicOut->setCallback( this, (CallbackPtr)(&PICComponentPin::logicCallback) ); +} + + +PICComponentPin::~PICComponentPin() +{ + delete m_pStimulusNode; +} + + +void PICComponentPin::attach( IOPIN * iopin ) +{ + if (!iopin) + { + kdWarning() << k_funcinfo << " iopin is NULL" << endl; + return; + } + + if (m_pStimulusNode) + { + kdWarning() << k_funcinfo << " Already have a node stimulus" << endl; + return; + } + + if (m_pIOPIN) + { + kdWarning() << k_funcinfo << " Already have an iopin" << endl; + return; + } + + m_pIOPIN = iopin; + m_pStimulusNode = new Stimulus_Node(m_id.ascii()); + m_pStimulusNode->attach_stimulus(iopin); + m_pStimulusNode->attach_stimulus(this); + + + // We need to tell the iopin whether or not we are high + if (m_pLogicOut) + logicCallback( m_pLogicOut->isHigh() ); + else if (m_pLogicIn) + logicCallback( m_pLogicIn->isHigh() ); +} + + +double PICComponentPin::get_Vth( ) +{ + if (!m_pIOPIN) + return 0.0; + + if ( m_pIOPIN->get_direction() == IOPIN::DIR_INPUT ) + return Vth; + else + return m_pIOPIN->get_Vth(); +} + + +void PICComponentPin::set_nodeVoltage( double v ) +{ + Q_UNUSED(v); + + if ( !m_pLogicOut || !m_pIOPIN ) + return; + + if ( m_pIOPIN->get_direction() == IOPIN::DIR_INPUT ) + { + m_pLogicOut->setOutputHighConductance(0.0); + m_pLogicOut->setOutputLowConductance(0.0); + return; + } + + m_pLogicOut->setHigh( m_pIOPIN->getDrivingState() ); + m_pLogicOut->setOutputHighConductance(m_gOutHigh); + m_pLogicOut->setOutputLowConductance(m_gOutLow); +} + + +void PICComponentPin::logicCallback( bool state ) +{ + if (!m_pIOPIN) + return; + + Vth = state ? 5e10 : 0; + bDrivingState = state; + + if ( m_pIOPIN->get_direction() == IOPIN::DIR_INPUT ) + { + Zth = 1e5; + + m_pIOPIN->setDrivenState(state); + if (m_pStimulusNode) + m_pStimulusNode->update(); + } + else + Zth = 0; +} + + +void PICComponentPin::resetOutput() +{ + if ( m_pLogicOut ) + m_pLogicOut->setHigh( false ); +} + +#endif + diff --git a/src/electronics/components/piccomponentpin.h b/src/electronics/components/piccomponentpin.h new file mode 100644 index 0000000..0fc433d --- /dev/null +++ b/src/electronics/components/piccomponentpin.h @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PICCOMPONENTPIN_H +#define PICCOMPONENTPIN_H + +#include "config.h" +#ifndef NO_GPSIM + +#include "logic.h" +#include "gpsim/stimuli.h" + +#include + +/** +@short Controls a pin on the PIC component +@author David Saxton + */ +class PICComponentPin : public CallbackClass, public stimulus +{ + public: + PICComponentPin( PICComponent * picComponent, PicPin picPin ); + ~PICComponentPin(); + /** + * Attach this to gpsim + */ + void attach( IOPIN * iopin ); + /** + * Called when the IOPIN this class is associated with changes state. + * Updates the associated LogicOut / LogicIn / etc according to what + * type of pin this is. + */ + virtual void set_nodeVoltage( double v ); + /** + * Called from our logic pin when the logic changes state. + */ + void logicCallback( bool state ); + /** + * Sets the output (if has one) to low. Called when the user stops the + * PIC. + */ + void resetOutput(); + + virtual double get_Vth(); + + protected: + // Conductance of pin in different configurations + double m_gOutHigh; + double m_gOutLow; + + PicPin m_picPin; + IOPIN * m_pIOPIN; + LogicOut * m_pLogicOut; + LogicIn * m_pLogicIn; + PICComponent * m_pPICComponent; + Stimulus_Node * m_pStimulusNode; + const QString m_id; +}; + +#endif +#endif diff --git a/src/electronics/components/probe.cpp b/src/electronics/components/probe.cpp new file mode 100644 index 0000000..db6725e --- /dev/null +++ b/src/electronics/components/probe.cpp @@ -0,0 +1,291 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "ecnode.h" +#include "libraryitem.h" +#include "logic.h" +#include "pin.h" +#include "probe.h" //HACK: This has to be included before the oscilloscope headers +#include "oscilloscope.h" +#include "oscilloscopedata.h" +#include "simulator.h" +#include "voltagesource.h" + +#include +#include + +//BEGIN class Probe +Probe::Probe( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ) +{ + p_probeData = 0l; + setSize( -16, -8, 32, 16 ); + + createProperty( "color", Variant::Type::Color ); + property("color")->setCaption( i18n("Color") ); + property("color")->setValue( Qt::black ); +} + + +Probe::~ Probe() +{ + delete p_probeData; +} + + +void Probe::dataChanged() +{ + m_color = dataColor("color"); + if (p_probeData) + p_probeData->setColor(m_color); + setChanged(); +} +//END class Probe + + + +//BEGIN class FloatingProbe +FloatingProbe::FloatingProbe( ICNDocument *icnDocument, bool newItem, const char *id ) + : Probe( icnDocument, newItem, id ) +{ + p_probeData = m_pFloatingProbeData = static_cast(registerProbe(this)); + property("color")->setValue( p_probeData->color() ); + + createProperty( "scaling", Variant::Type::Select ); + property("scaling")->setCaption( i18n("Scaling") ); + property("scaling")->setAllowed( QStringList::split( ',', "Linear,Logarithmic") ); + property("scaling")->setValue("Linear"); + property("scaling")->setAdvanced( true ); + + createProperty( "upper_abs_value", Variant::Type::Double ); + property("upper_abs_value")->setCaption( i18n("Upper Absolute Value") ); + property("upper_abs_value")->setValue(10.0); + property("upper_abs_value")->setMinValue(0.0); + property("upper_abs_value")->setUnit("V"); + property("upper_abs_value")->setAdvanced(true); + + createProperty( "lower_abs_value", Variant::Type::Double ); + property("lower_abs_value")->setCaption( i18n("Lower Absolute Value") ); + property("lower_abs_value")->setValue(0.1); + property("lower_abs_value")->setMinValue(0.0); + property("lower_abs_value")->setUnit("V"); + property("lower_abs_value")->setAdvanced(true); +} + + +FloatingProbe::~FloatingProbe() +{ +} + + +void FloatingProbe::dataChanged() +{ + Probe::dataChanged(); + + if ( dataString("scaling") == "Linear" ) + m_pFloatingProbeData->setScaling( FloatingProbeData::Linear ); + else + m_pFloatingProbeData->setScaling( FloatingProbeData::Logarithmic ); + + m_pFloatingProbeData->setUpperAbsValue( dataDouble("upper_abs_value") ); + m_pFloatingProbeData->setLowerAbsValue( dataDouble("lower_abs_value") ); +} + + +void FloatingProbe::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = int(x())-16; + int _y = int(y())-8; + + p.drawRect( _x, _y, 32, 16 ); + + QPointArray bezier(4); + + bezier[0] = QPoint( _x+4, _y+10 ); + bezier[1] = QPoint( _x+12, _y-6 ); + bezier[2] = QPoint( _x+20, _y+24 ); + bezier[3] = QPoint( _x+28, _y+4 ); + + p.setPen( QPen( m_color, 2 ) ); + p.drawCubicBezier(bezier); + + deinitPainter(p); +} +//END class FloatingProbe + + + +//BEGIN class VoltageProbe +Item* VoltageProbe::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new VoltageProbe( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* VoltageProbe::libraryItem() +{ + return new LibraryItem( + "ec/voltageprobe", + i18n("Voltage Probe"), + i18n("Outputs"), + "floatingprobe.png", + LibraryItem::lit_component, + VoltageProbe::construct ); +} + +VoltageProbe::VoltageProbe( ICNDocument *icnDocument, bool newItem, const char *id ) + : FloatingProbe( icnDocument, newItem, id ? id : "voltageprobe" ) +{ + m_name = i18n("Voltage Probe"); + m_desc = i18n("Displays the voltage at the probe point on the oscilloscope."); + + init1PinLeft(); + init1PinRight(); + m_pPin1 = m_pNNode[0]->pin(); + m_pPin2 = m_pPNode[0]->pin(); +} + + +VoltageProbe::~VoltageProbe() +{ +} + + +void VoltageProbe::stepNonLogic() +{ + m_pFloatingProbeData->addDataPoint( m_pPin1->voltage() - m_pPin2->voltage() ); +} +//END class VoltageProbe + + + +//BEGIN class CurrentProbe +Item* CurrentProbe::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new CurrentProbe( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* CurrentProbe::libraryItem() +{ + return new LibraryItem( + "ec/currentprobe", + i18n("Current Probe"), + i18n("Outputs"), + "floatingprobe.png", + LibraryItem::lit_component, + CurrentProbe::construct ); +} + +CurrentProbe::CurrentProbe( ICNDocument *icnDocument, bool newItem, const char *id ) + : FloatingProbe( icnDocument, newItem, id ? id : "currentprobe" ) +{ + m_name = i18n("Current Probe"); + m_desc = i18n("Displays the current at the probe point on the oscilloscope."); + + + init1PinLeft(0); + init1PinRight(0); + + m_voltageSource = createVoltageSource( m_pNNode[0], m_pPNode[0], 0. ); +} + + +CurrentProbe::~CurrentProbe() +{ +} + + +void CurrentProbe::stepNonLogic() +{ + m_pFloatingProbeData->addDataPoint( -m_voltageSource->cbranchCurrent(0) ); +} +//END class CurrentProbe + + + + +//BEGIN class LogicProbe +Item* LogicProbe::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new LogicProbe( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* LogicProbe::libraryItem() +{ + QStringList ids; + ids << "ec/probe" << "ec/logicprobe"; + return new LibraryItem( + ids, + i18n("Logic Probe"), + i18n("Outputs"), + "logicprobe.png", + LibraryItem::lit_component, + LogicProbe::construct ); +} + +LogicProbe::LogicProbe( ICNDocument *icnDocument, bool newItem, const char *id ) + : Probe( icnDocument, newItem, id ? id : "probe" ) +{ + m_name = i18n("Logic Probe"); + m_desc = i18n("Connect this probe the the point in the circuit to measure the logic value. The output will be displayed in the Oscilloscope view."); + + init1PinRight(); + m_pIn = createLogicIn( m_pPNode[0] ); + + p_probeData = p_logicProbeData = static_cast(registerProbe(this)); + property("color")->setValue( p_probeData->color() ); + + m_pSimulator = Simulator::self(); + m_pIn->setCallback( this, (CallbackPtr)(&LogicProbe::logicCallback) ); + logicCallback(false); +} + + +LogicProbe::~LogicProbe() +{ +} + + +void LogicProbe::logicCallback( bool value ) +{ + p_logicProbeData->addDataPoint( LogicDataPoint( value, m_pSimulator->time() ) ); +} + + +void LogicProbe::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = int(x())-16; + int _y = int(y())-8; + + p.drawRect( _x, _y, 32, 16 ); + + p.setPen( QPen( m_color, 2 ) ); + + p.drawLine( _x+4, _y+11, _x+6, _y+11 ); + p.drawLine( _x+6, _y+11, _x+6, _y+4 ); + p.drawLine( _x+6, _y+4, _x+10, _y+4 ); + p.drawLine( _x+10, _y+4, _x+10, _y+11 ); + p.drawLine( _x+10, _y+11, _x+16, _y+11 ); + p.drawLine( _x+16, _y+11, _x+16, _y+4 ); + p.drawLine( _x+16, _y+4, _x+23, _y+4 ); + p.drawLine( _x+23, _y+4, _x+23, _y+11 ); + p.drawLine( _x+23, _y+11, _x+28, _y+11 ); +// p.drawLine( _x+23, _y+11, _x+26, _y+11 ); +// p.drawLine( _x+26, _y+11, _x+26, _y+4 ); +// p.drawLine( _x+26, _y+4, _x+28, _y+4 ); + + deinitPainter(p); +} +//END class LogicProbe + + diff --git a/src/electronics/components/probe.h b/src/electronics/components/probe.h new file mode 100644 index 0000000..9beb62e --- /dev/null +++ b/src/electronics/components/probe.h @@ -0,0 +1,113 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PROBE_H +#define PROBE_H + +#include + +class LogicProbeData; +class ProbeData; +class FloatingProbeData; + +/** +@author David Saxton +*/ +class Probe : public Component +{ + public: + Probe( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Probe(); + + protected: + virtual void dataChanged(); + + ProbeData * p_probeData; // As obtained via registering with the oscilloscope + QColor m_color; +}; + +/** +@author David Saxton + */ +class FloatingProbe : public Probe +{ + public: + FloatingProbe( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~FloatingProbe(); + + virtual bool doesStepNonLogic() const { return true; } + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + FloatingProbeData * m_pFloatingProbeData; +}; + +/** +@author David Saxton + */ +class VoltageProbe : public FloatingProbe +{ + public: + VoltageProbe( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~VoltageProbe(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void stepNonLogic(); + + protected: + Pin * m_pPin1; + Pin * m_pPin2; +}; + +/** +@author David Saxton + */ +class CurrentProbe : public FloatingProbe +{ + public: + CurrentProbe( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~CurrentProbe(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void stepNonLogic(); + + protected: + VoltageSource *m_voltageSource; +}; + +/** +@author David Saxton + */ +class LogicProbe : public CallbackClass, public Probe +{ + public: + LogicProbe( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~LogicProbe(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + void logicCallback( bool value ); + + protected: + virtual void drawShape( QPainter &p ); + + LogicProbeData * p_logicProbeData; + LogicIn * m_pIn; + Simulator * m_pSimulator; +}; + +#endif diff --git a/src/electronics/components/pushswitch.cpp b/src/electronics/components/pushswitch.cpp new file mode 100644 index 0000000..b7b38b7 --- /dev/null +++ b/src/electronics/components/pushswitch.cpp @@ -0,0 +1,204 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasitemparts.h" +#include "libraryitem.h" +#include "pushswitch.h" +#include "switch.h" + +#include +#include +#include +#include +#include + +//BEGIN class ECPTBSwitch +Item* ECPTBSwitch::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECPTBSwitch( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECPTBSwitch::libraryItem() +{ + return new LibraryItem( + QString("ec/ptb_switch"), + i18n("Push-to-Break"), + i18n("Switches"), + "ptb.png", + LibraryItem::lit_component, + ECPTBSwitch::construct ); +} + +ECPTBSwitch::ECPTBSwitch( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "ptb_switch" ) +{ + m_name = i18n("Push to Break"); + setSize( -16, -16, 32, 24 ); + + addButton( "button", QRect( -16, 8, 32, 20 ), "" ); + + createProperty( "button_text", Variant::Type::String ); + property("button_text")->setCaption( i18n("Button Text") ); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption( i18n("Bounce") ); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption( i18n("Bounce Period") ); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + init1PinLeft(0); + init1PinRight(0); + + m_switch = createSwitch( m_pPNode[0], m_pNNode[0], false ); + pressed = false; +} + +ECPTBSwitch::~ECPTBSwitch() +{ +} + + +void ECPTBSwitch::dataChanged() +{ + button("button")->setText( dataString("button_text") ); + + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + m_switch->setBounce( bounce, bouncePeriod_ms ); +} + + +void ECPTBSwitch::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-8; + const int radius = 2; + const int _height = height()-8; + + int dy = pressed ? 6 : 4; + + p.drawLine( _x+width()/4, _y+dy, _x+(3*width())/4, _y+dy ); // Top horizontal line + p.drawLine( _x, _y+(_height/2)-radius+dy, _x+width(), _y+(_height/2)-radius+dy ); // Bottom horizontal line + p.drawLine( _x+width()/2, _y+dy, _x+width()/2, _y+(_height/2)-radius+dy ); // Vertical line + + p.drawEllipse( _x, _y+(_height/2)-radius, 2*radius, 2*radius ); // Left circle + p.drawEllipse( _x+width()-2*radius+1, _y+(_height/2)-radius, 2*radius, 2*radius ); // Right circle + + deinitPainter(p); +} + +void ECPTBSwitch::buttonStateChanged( const QString &id, bool state ) +{ + if ( id != "button" ) + return; + m_switch->setState( state ? Switch::Open : Switch::Closed ); + pressed = state; +} +//END class ECPTBSwitch + + +//BEGIN class ECPTMSwitch +Item* ECPTMSwitch::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECPTMSwitch( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECPTMSwitch::libraryItem() +{ + return new LibraryItem( + QString("ec/ptm_switch"), + i18n("Push-to-Make"), + i18n("Switches"), + "ptm.png", + LibraryItem::lit_component, + ECPTMSwitch::construct ); +} + +ECPTMSwitch::ECPTMSwitch( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "ptm_switch" ) +{ + m_name = i18n("Push to Make"); + setSize( -16, -16, 32, 24 ); + + addButton( "button", QRect( -16, 8, 32, 20 ), "" ); + + createProperty( "button_text", Variant::Type::String ); + property("button_text")->setCaption( i18n("Button Text") ); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + init1PinLeft(0); + init1PinRight(0); + + m_switch = createSwitch( m_pPNode[0], m_pNNode[0], true ); + pressed = false; +} + + +ECPTMSwitch::~ECPTMSwitch() +{ +} + + +void ECPTMSwitch::dataChanged() +{ + button("button")->setText( dataString("button_text") ); + + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + m_switch->setBounce( bounce, bouncePeriod_ms ); +} + + +void ECPTMSwitch::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-8; + const int radius = 2; + const int _height = height()-8; + + int dy = pressed ? 1 : 3; + + p.drawLine( _x+width()/4, _y-dy, _x+(3*width())/4, _y-dy ); // Top horizontal line + p.drawLine( _x, _y+(_height/2)-radius-dy, _x+width(), _y+(_height/2)-radius-dy ); // Bottom horizontal line + p.drawLine( _x+width()/2, _y-dy, _x+width()/2, _y+(_height/2)-radius-dy ); // Vertical line + + p.drawEllipse( _x, _y+(_height/2)-radius, 2*radius, 2*radius ); // Left circle + p.drawEllipse( _x+width()-2*radius+1, _y+(_height/2)-radius, 2*radius, 2*radius ); // Right circle + + deinitPainter(p); +} + +void ECPTMSwitch::buttonStateChanged( const QString &id, bool state ) +{ + if ( id != "button" ) return; + m_switch->setState( state ? Switch::Closed : Switch::Open ); + pressed = state; +} +//END class ECPTMSwitch + diff --git a/src/electronics/components/pushswitch.h b/src/electronics/components/pushswitch.h new file mode 100644 index 0000000..c22ea93 --- /dev/null +++ b/src/electronics/components/pushswitch.h @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PUSHSWITCH_H +#define PUSHSWITCH_H + +#include "component.h" + +/** +@short Push-to-Break switch component +@author David Saxton +*/ +class ECPTBSwitch : public Component +{ +public: + ECPTBSwitch( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECPTBSwitch(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + +private: + virtual void drawShape( QPainter &p ); + Switch *m_switch; + bool pressed; +}; + + +/** +@short Push-to-make switch +@author David Saxton +*/ +class ECPTMSwitch : public Component +{ +public: + ECPTMSwitch( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECPTMSwitch(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + +private: + virtual void drawShape( QPainter &p ); + Switch *m_switch; + bool pressed; +}; + + +#endif diff --git a/src/electronics/components/ram.cpp b/src/electronics/components/ram.cpp new file mode 100644 index 0000000..add745a --- /dev/null +++ b/src/electronics/components/ram.cpp @@ -0,0 +1,232 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "libraryitem.h" +#include "logic.h" +#include "ram.h" +#include "variant.h" + +#include +#include + +Item* RAM::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new RAM( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* RAM::libraryItem() +{ + return new LibraryItem( + QString("ec/ram"), + i18n("RAM"), + i18n("Integrated Circuits"), + "ic2.png", + LibraryItem::lit_component, + RAM::construct + ); +} + +RAM::RAM( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "ram" ) +{ + m_name = i18n("RAM"); + m_desc = i18n("This RAM stores data as a collection of words; each of which contains word size bits of data.

    To read data, set the CS (chip select) and the OE (output enable) pins high, and select the word using the address pins A*. The word is outputted on the data-out pins: DO*.

    To write data, set the CS (chip select) and the WE (write enable) pins high, and select the address to write to with the A* pins. Write to the selected word using the data-in pins: DI*.

    The Address Size is the number of bits that determine an address; so the total number of words stored will be 2^Address Size."); + + m_data = 0l; + m_pCS = 0l; + m_pOE = 0l; + m_pWE = 0l; + m_wordSize = 0; + m_addressSize = 0; + + createProperty( "wordSize", Variant::Type::Int ); + property("wordSize")->setCaption( i18n("Word Size") ); + property("wordSize")->setMinValue(1); + property("wordSize")->setMaxValue(256); + property("wordSize")->setValue(2); + + createProperty( "addressSize", Variant::Type::Int ); + property("addressSize")->setCaption( i18n("Address Size") ); + property("addressSize")->setMinValue(1); + property("addressSize")->setMaxValue(32); + property("addressSize")->setValue(4); + + m_data = createProperty( "data", Variant::Type::Raw )->value().asBitArray(); +} + +RAM::~RAM() +{ +} + + +void RAM::dataChanged() +{ + m_wordSize = dataInt("wordSize"); + m_addressSize = dataInt("addressSize"); + + int newSize = int( m_wordSize * std::pow( 2., m_addressSize ) ); + m_data.resize(newSize); + + initPins(); +} + + +void RAM::inStateChanged( bool newState ) +{ + Q_UNUSED(newState); + + bool cs = m_pCS->isHigh(); + bool oe = m_pOE->isHigh(); + bool we = m_pWE->isHigh(); + + if ( !cs || !oe ) + { + for ( int i = 0; i < m_wordSize; ++i ) + m_dataOut[i]->setHigh(false); + } + + if ( !cs || (!oe && !we) ) + return; + + unsigned address = 0; + for ( int i = 0; i < m_addressSize; ++i ) + address += (m_address[i]->isHigh() ? 1 : 0) << i; + + if (we) + { + for ( int i = 0; i < m_wordSize; ++i ) + m_data[ m_wordSize * address + i ] = m_dataIn[i]->isHigh(); + } + + if (oe) + { + for ( int i = 0; i < m_wordSize; ++i ) + m_dataOut[i]->setHigh( m_data[ m_wordSize * address + i ] ); + } +} + + +void RAM::initPins() +{ + int oldWordSize = m_dataIn.size(); + int oldAddressSize = m_address.size(); + + int newWordSize = dataInt("wordSize"); + int newAddressSize = dataInt("addressSize"); + + if ( newAddressSize == oldAddressSize && + newWordSize == oldWordSize ) + return; + + QStringList leftPins; // Pins on left of IC + leftPins << "CS" << "OE" << "WE"; + for ( int i = 0; i < newAddressSize; ++i ) + leftPins << QString("A%1").arg( QString::number(i) ); + + QStringList rightPins; // Pins on right of IC + for ( unsigned i = newWordSize; i > 0; --i ) + rightPins << QString("DI%1").arg( QString::number(i-1) ); + for ( unsigned i = newWordSize; i > 0; --i ) + rightPins << QString("DO%1").arg( QString::number(i-1) ); + + // Make pin lists of consistent sizes + for ( unsigned i = leftPins.size(); i < rightPins.size(); ++i ) + leftPins.append(""); + for ( unsigned i = rightPins.size(); i < leftPins.size(); ++i ) + rightPins.prepend(""); + + QStringList pins = leftPins + rightPins; + + initDIPSymbol( pins, 72 ); + initDIP(pins); + + ECNode *node; + + if (!m_pCS) + { + node = ecNodeWithID("CS"); + m_pCS = createLogicIn(node); + m_pCS->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + } + + if (!m_pOE) + { + node = ecNodeWithID("OE"); + m_pOE = createLogicIn(node); + m_pOE->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + } + + if (!m_pWE) + { + node = ecNodeWithID("WE"); + m_pWE = createLogicIn(node); + m_pWE->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + } + + if ( newWordSize > oldWordSize ) + { + m_dataIn.resize(newWordSize); + m_dataOut.resize(newWordSize); + + for ( int i = oldWordSize; i < newWordSize; ++i ) + { + node = ecNodeWithID( QString("DI%1").arg( QString::number(i) ) ); + m_dataIn.insert( i, createLogicIn(node) ); + m_dataIn[i]->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + + node = ecNodeWithID( QString("DO%1").arg( QString::number(i) ) ); + m_dataOut.insert( i, createLogicOut(node, false) ); + } + } + else if ( newWordSize < oldWordSize ) + { + for ( int i = newWordSize; i < oldWordSize; ++i ) + { + QString id = QString("DO%1").arg( QString::number(i) ); + removeDisplayText(id); + removeElement( m_dataIn[i], false ); + removeNode(id); + + id = QString("DI%1").arg( QString::number(i) ); + removeDisplayText(id); + removeElement( m_dataOut[i], false ); + removeNode(id); + } + + m_dataIn.resize(newWordSize); + m_dataOut.resize(newWordSize); + } + + if ( newAddressSize > oldAddressSize ) + { + m_address.resize(newAddressSize); + + for ( int i = oldAddressSize; i < newAddressSize; ++i ) + { + node = ecNodeWithID( QString("A%1").arg( QString::number(i) ) ); + m_address.insert( i, createLogicIn(node) ); + m_address[i]->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + } + } + else if ( newAddressSize < oldAddressSize ) + { + for ( int i = newAddressSize; i < oldAddressSize; ++i ) + { + QString id = QString("A%1").arg( QString::number(i) ); + removeDisplayText(id); + removeElement( m_address[i], false ); + removeNode(id); + } + + m_address.resize(newAddressSize); + } +} + + diff --git a/src/electronics/components/ram.h b/src/electronics/components/ram.h new file mode 100644 index 0000000..7b78ee9 --- /dev/null +++ b/src/electronics/components/ram.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef RAM_H +#define RAM_H + +#include "component.h" +#include "logic.h" + +#include +#include + +/** +@author David Saxton +*/ +class RAM : public CallbackClass, public Component +{ + public: + RAM( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~RAM(); + + virtual bool canFlip() const { return true; } + static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem * libraryItem(); + + protected: + void initPins(); + virtual void dataChanged(); + void inStateChanged( bool newState ); + + QBitArray m_data; + LogicIn * m_pCS; // Chip select + LogicIn * m_pOE; // Output enable + LogicIn * m_pWE; // Write enable + + int m_wordSize; + int m_addressSize; + + QPtrVector m_address; + QPtrVector m_dataIn; + QPtrVector m_dataOut; +}; + +#endif diff --git a/src/electronics/components/resistordip.cpp b/src/electronics/components/resistordip.cpp new file mode 100644 index 0000000..d2c5bdb --- /dev/null +++ b/src/electronics/components/resistordip.cpp @@ -0,0 +1,132 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "libraryitem.h" +#include "node.h" +#include "resistance.h" +#include "resistordip.h" + +#include +#include +#include + +Item* ResistorDIP::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ResistorDIP( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ResistorDIP::libraryItem() +{ + return new LibraryItem( + "ec/resistordip", + i18n("Resistor DIP"), + i18n("Discrete"), + "resistordip.png", + LibraryItem::lit_component, + ResistorDIP::construct + ); +} + +ResistorDIP::ResistorDIP( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "multiplexer" ) +{ + m_name = i18n("Resistor DIP"); + m_desc = i18n("Set of resistors with identical values in a Dual Inline Package."); + + m_resistorCount = 0; + for ( int i=0; isetCaption( i18n("Resistance") ); + property("resistance")->setUnit( QChar(0x3a9) ); + property("resistance")->setValue(1e4); + property("resistance")->setMinValue(1e-6); + + createProperty( "count", Variant::Type::Int ); + property("count")->setCaption( i18n("Count") ); + property("count")->setMinValue(2); + property("count")->setMaxValue(maxCount); + property("count")->setValue(8); +} + +ResistorDIP::~ResistorDIP() +{ +} + + +void ResistorDIP::dataChanged() +{ + initPins(); + const double resistance = dataDouble("resistance"); + for ( int i=0; isetResistance(resistance); + + const QString display = QString::number( resistance / getMultiplier(resistance), 'g', 3 ) + getNumberMag(resistance) + QChar(0x3a9); + addDisplayText( "res", QRect( offsetX(), offsetY()-16, 32, 12 ), display ); +} + + +void ResistorDIP::initPins() +{ + const int count = dataInt("count"); + const double resistance = dataDouble("resistance"); + + if ( count == m_resistorCount ) + return; + + if ( count < m_resistorCount ) + { + for ( int i=count; i +#include +#include +#include + +#include + +//BEGIN class ECRotoSwitch +Item* ECRotoSwitch::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECRotoSwitch( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECRotoSwitch::libraryItem() +{ + return new LibraryItem( + QString("ec/roto_switch"), + i18n("Rotary"), + i18n("Switches"), + "rotary.png", + LibraryItem::lit_component, + ECRotoSwitch::construct ); +} + + +ECRotoSwitch::ECRotoSwitch( ICNDocument *icnDocument, bool newItem, const char *id ) +: Component( icnDocument, newItem, id ? id : "roto_switch" ), +m_numPositions(0) +{ +// m_name = i18n("Rotary Switch(WIP)"); + m_name = i18n("Rotary Switch"); + m_desc = i18n("Rotary Switch"); ///< \todo better description for rotoswitch + QPointArray pa; + pa.makeArc( -_pinInnerRadius, -_pinInnerRadius, 2*_pinInnerRadius, 2*_pinInnerRadius , 0, 16*360 ); + setItemPoints( pa ); + //setSize( -64, -64, 128, 128 ); + + //half the side length of the buttons + int buttonRadius = 10; + addButton( "go_left", QRect( -_pinOuterRadius/3-buttonRadius, _pinOuterRadius-3*buttonRadius, 2*buttonRadius, 2*buttonRadius ), "<", false ); + addButton( "go_right", QRect(_pinOuterRadius/3-buttonRadius, _pinOuterRadius-3*buttonRadius, 2*buttonRadius, 2*buttonRadius ), ">", false ); + + /*Variant * v = createProperty( "button_map", Variant::Type::String ); + v->setCaption( i18n("Button Map") ); + v->setAdvanced(true); + const QString defButtonMap("SSSSSSSSSSSM"); + v->setValue(defButtonMap); + */ + Variant * v = createProperty( "num_positions", Variant::Type::Int ); + v->setCaption( i18n("Number of Positions") ); + v->setAdvanced(false); + v->setValue(6); + v->setMinValue(3); + m_inNode = createPin(0,height()/2,270,"in"); + + v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + + v = createProperty( "cur_position", Variant::Type::Int ); + v->setHidden( true ); + v->setValue( 0 ); + + //v = createProperty( "left_momentary", Variant::Type::Bool ); + //v->setCaption(i18n("Left Momentary" ) ); + //v->setValue(false); +} + + +ECRotoSwitch::~ECRotoSwitch() +{ +} + + +void ECRotoSwitch::dataChanged() +{ + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + m_curPosition = dataInt( "cur_position" ); + setUpSwitches(); + if(m_positions[m_curPosition].posSwitch->state() != Switch::Closed) + { + m_positions[m_curPosition].posSwitch->setState(Switch::Closed); + } + for(int i = 0; i < m_numPositions; i++) + { + m_positions[i].posSwitch->setBounce( bounce, bouncePeriod_ms ); + } +} + +inline int roundTo10(int a){return ((a/10)+(a%10<5?0:1))*10;} +void ECRotoSwitch::drawShape( QPainter &p ) +{ + initPainter(p); + + + int cx = static_cast(x()); + int cy = static_cast(y()); + + const int rotorRadius = 5; + + + //draw the rotor + p.drawEllipse(cx - rotorRadius, cy-rotorRadius, 2*rotorRadius, 2*rotorRadius); + //and its connection + p.drawLine(cx, cy+rotorRadius, cx, cy+_pinInnerRadius); + + //draw the output positions + double angleBetweenPositions = (4*M_PI/3)/(m_numPositions - 1); + //kdDebug() << "drawShape: " << bigRadius << " " << angleBetweenPositions << endl; + + /// \internal \brief Round to the nearest multiple of 8 +#define round_8(a) (((a) > 0) ? int(((a)+4)/8)*8 : int(((a)-4)/8)*8) + for(int i = 0; i < m_numPositions ; i++) + { + double angle = (7*M_PI/6) - (i * angleBetweenPositions); + int contactX = static_cast(_contactRingRadius * cos(angle)); + int contactY = static_cast(_contactRingRadius * sin(angle)); + + p.drawEllipse(cx+contactX-_contactRadius, cy-contactY-_contactRadius, 2*_contactRadius, 2*_contactRadius); + int pinX, pinY; + switch(m_positions[i].pinAngle) + { + case 180: + pinX = _pinInnerRadius; + pinY = round_8(contactY); + break; + case 90: + pinX = round_8(contactX); + pinY = _pinInnerRadius; + break; + case 0: + pinX = -_pinInnerRadius; + pinY = round_8(contactY); + break; + default: + assert(!"Bad pin angle"); + } + p.drawLine(cx+contactX, cy-contactY, cx+pinX, cy-pinY); + //kdDebug() << contactX <<", "<< contactY <(_contactRingRadius * cos(angle)); + int contactY = static_cast(_contactRingRadius * sin(angle)); + int rotorX = static_cast(rotorRadius * cos(angle)); + int rotorY = static_cast(rotorRadius * sin(angle)); + p.drawLine(cx+rotorX, cy-rotorY, cx+contactX, cy-contactY); + + + deinitPainter(p); +} + +void ECRotoSwitch::buttonStateChanged( const QString & id, bool state ) +{ + SwitchPosition& curSP = m_positions[m_curPosition]; + int nextPos = m_curPosition; + if(m_numPositions < 2) + { + return; + } + if(!state) //release + { + if(!curSP.isMomentary) + { + return; + } + + if(m_curPosition == 0) + { + nextPos = m_curPosition + 1; + } + else if(m_curPosition == m_numPositions - 1) + { + nextPos = m_curPosition - 1; + } + + } + else //press + { + if(id == "go_left" && m_curPosition > 0) + { + nextPos = m_curPosition - 1; + } + else if(id == "go_right" && m_curPosition < m_numPositions - 1) + { + nextPos = m_curPosition + 1; + } + + } + if(nextPos != m_curPosition) + { + SwitchPosition& nextSP = m_positions[nextPos]; + + curSP.posSwitch->setState(Switch::Open); + nextSP.posSwitch->setState(Switch::Closed); + + m_curPosition = nextPos; + + property( "cur_position" )->setValue( m_curPosition ); + } +} + + +/*! + Set up the switches according to the button_map + * + * + */ +void ECRotoSwitch::setUpSwitches() +{ + if( dataInt("num_positions") == m_numPositions ) + { + // number of positions didn't change, so we don't have to do anything. + return; + } + //this uses the _old_ value of m_numPositions! + for(int i=0; i= m_numPositions ) + { + setActivePosition( m_numPositions - 1 ); + } + m_positions.clear();///\todo readjust old pins + m_positions.reserve(m_numPositions); + double angleBetweenPositions = (4*M_PI/3)/(m_numPositions - 1); + //kdDebug() << "setUpSwitches: " << bigRadius << " " << angleBetweenPositions << endl; + for( int i = 0; i < m_numPositions; i++) + { + double angle = (7*M_PI/6) - (i * angleBetweenPositions); + int contactX = static_cast(_contactRingRadius * cos(angle)); + int contactY = static_cast(_contactRingRadius * sin(angle)); + + SwitchPosition sp; + if(angle > 3*M_PI/4) + { + sp.pinAngle = 0; + contactX = -_pinOuterRadius; + } + else if(angle > M_PI/4) + { + sp.pinAngle = 90; + contactY=_pinOuterRadius; + } + else + { + sp.pinAngle = 180; + contactX = _pinOuterRadius; + } + // kdDebug() << contactX <<", "<< contactY <setState(Switch::Open); + nextSP.posSwitch->setState(Switch::Closed); + + m_curPosition = newPosition; + + property( "cur_position" )->setValue( m_curPosition ); + +} +//END class ECRotoSwitch diff --git a/src/electronics/components/rotoswitch.h b/src/electronics/components/rotoswitch.h new file mode 100644 index 0000000..909c0ea --- /dev/null +++ b/src/electronics/components/rotoswitch.h @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (C) 2005 by John Myers * + * electronerd@electronerdia.net * + * * + * 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 ROTOSWITCH_H +#define ROTOSWITCH_H + +#include "component.h" +#include + +struct SwitchPosition +{ + ECNode* node; + Switch* posSwitch; + bool isMomentary; + int pinAngle; +}; + +/** + * A rotary switch + * \author John Myers + */ +class ECRotoSwitch : public Component +{ +public: + ECRotoSwitch( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECRotoSwitch(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + +private: + virtual void drawShape( QPainter &p ); + + int m_numPositions; + int m_curPosition; + + ///Half the total width of the component including pins + static const int _pinOuterRadius = 64; + ///The width of the pins + static const int _pinWidth = 8; + ///the radius of the circle centered at the origin and tangent to the inner edge of the rows of pins + static const int _pinInnerRadius = _pinOuterRadius - _pinWidth; + ///gap between pins and contact circles + static const int _wireGap = 7; + ///The radius of the largest circle tangent to the pin circles + static const int _contactOuterRadius = _pinInnerRadius - _wireGap; + ///The radius of the circles used to show positions + static const int _contactRadius = 2; + ///The radius of the ring of positions + static const int _contactRingRadius = _contactOuterRadius - _contactRadius; + + QValueVector m_positions; + ECNode* m_inNode; + +protected: + void setUpSwitches(); +protected: + void setActivePosition(int newPosition); +}; +#endif //ROTOSWITCH_H diff --git a/src/electronics/components/serialportcomponent.cpp b/src/electronics/components/serialportcomponent.cpp new file mode 100644 index 0000000..c8e6a4e --- /dev/null +++ b/src/electronics/components/serialportcomponent.cpp @@ -0,0 +1,242 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "port.h" +#include "serialportcomponent.h" + +#include "ecnode.h" +#include "itemdocument.h" +#include "libraryitem.h" +#include "pin.h" +#include "resistance.h" + +#include +#include +#include + +#include +#include + +Item* SerialPortComponent::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new SerialPortComponent( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* SerialPortComponent::libraryItem() +{ + return new LibraryItem( + "ec/serial_port", + i18n("Serial Port"), + i18n("Connections"), + "ic1.png", + LibraryItem::lit_component, + SerialPortComponent::construct + ); +} + +SerialPortComponent::SerialPortComponent( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "serial_port" ) +{ + m_name = i18n("Serial Port"); + m_desc = i18n("Interface to a serial port. The pins are:
    " + "
      " + "
    • CD - Carrier Detect (control; output)
    • " + "
    • RD - Received Data (data; output)
    • " + "
    • TD - Transmitted Data (data; input)
    • " + "
    • DTR - Data Terminal Ready (control; input)
    • " + "
    • GND - Signal Ground (ground)
    • " + "
    • DSR - Data Set Ready (control; input)
    • " + "
    • RTS - Request to Send (control; input)
    • " + "
    • CTS - Clear to Send (control; output)
    • " + "
    • RI - Ring Indicator (control; output)
    • " + "
    "); + + QPointArray pa( 4 ); + pa[0] = QPoint( -32, -48 ); + pa[1] = QPoint( 32, -40 ); + pa[2] = QPoint( 32, 40 ); + pa[3] = QPoint( -32, 48 ); + + setItemPoints( pa ); + + m_pSerialPort = new SerialPort(); + + ECNode * pin = 0; + + // Works + pin = createPin( -40, 32, 0, "CD" ); + addDisplayText( "CD", QRect( -28, 24, 28, 16 ), "CD", true, Qt::AlignLeft | Qt::AlignVCenter ); + m_pCD = createLogicOut( pin, false ); + + // Doesn't work +// pin = createPin( -40, 16, 0, "RD" ); + addDisplayText( "RD", QRect( -28, 8, 28, 16 ), "RD", true, Qt::AlignLeft | Qt::AlignVCenter ); +// m_pRD = createLogicOut( pin, false ); + + // Works + pin = createPin( -40, 0, 0, "TD" ); + addDisplayText( "TD", QRect( -28, -8, 28, 16 ), "TD", true, Qt::AlignLeft | Qt::AlignVCenter ); + m_pTD = createLogicIn( pin); + m_pTD->setCallback( this, (CallbackPtr)(&SerialPortComponent::tdCallback) ); + + // Works + pin = createPin( -40, -16, 0, "DTR" ); + addDisplayText( "DTR", QRect( -28, -24, 28, 16 ), "DTR", true, Qt::AlignLeft | Qt::AlignVCenter ); + m_pDTR = createLogicIn( pin ); + m_pDTR->setCallback( this, (CallbackPtr)(&SerialPortComponent::dtrCallback) ); + + // N/A + pin = createPin( -40, -32, 0, "GND" ); + addDisplayText( "GND", QRect( -28, -40, 28, 16 ), "GND", true, Qt::AlignLeft | Qt::AlignVCenter ); + pin->pin()->setGroundType( Pin::gt_always ); + + // Doesn't work +// pin = createPin( 40, 24, 180, "DSR" ); + addDisplayText( "DSR", QRect( 0, 16, 28, 16 ), "DSR", true, Qt::AlignRight | Qt::AlignVCenter ); +// m_pDSR = createLogicIn( pin ); +// m_pDSR->setCallback( this, (CallbackPtr)(&SerialPortComponent::dsrCallback) ); + + // Doesn't work +// pin = createPin( 40, 8, 180, "RTS" ); + addDisplayText( "RTS", QRect( 0, 0, 28, 16 ), "RTS", true, Qt::AlignRight | Qt::AlignVCenter ); +// m_pRTS = createLogicIn( pin ); +// m_pRTS->setCallback( this, (CallbackPtr)(&SerialPortComponent::rtsCallback) ); + + // Works + pin = createPin( 40, -8, 180, "CTS" ); + addDisplayText( "CTS", QRect( 0, -16, 28, 16 ), "CTS", true, Qt::AlignRight | Qt::AlignVCenter ); + m_pCTS = createLogicOut( pin, false ); + + // Works + pin = createPin( 40, -24, 180, "RI" ); + addDisplayText( "RI", QRect( 0, -32, 28, 16 ), "RI", true, Qt::AlignRight | Qt::AlignVCenter ); + m_pRI = createLogicOut( pin, false ); + + Variant * v = createProperty( "port", Variant::Type::Combo ); + v->setAllowed( SerialPort::ports( Port::ExistsAndRW ) ); + v->setCaption( i18n("Port") ); + +// v = createProperty( "baudRate", Variant::Type::Select ); +// v->setAllowed( QStringList::split( ",", "B0,B50,B75,B110,B134,B150,B200,B300,B600,B1200,B1800,B2400,B4800,B9600,B19200,B38400" ) ); +// v->setCaption( i18n("Baud rate") ); +// v->setValue("B9600"); +} + + +SerialPortComponent::~SerialPortComponent() +{ + delete m_pSerialPort; +} + + +void SerialPortComponent::dataChanged() +{ +#if 0 + QString baudString = dataString("baudRate"); + unsigned baudRate = 0; + + if ( baudString == "B0" ) + baudRate = B0; + else if ( baudString == "B50" ) + baudRate = B50; + else if ( baudString == "B75" ) + baudRate = B75; + else if ( baudString == "B110" ) + baudRate = B110; + else if ( baudString == "B134" ) + baudRate = B134; + else if ( baudString == "B150" ) + baudRate = B150; + else if ( baudString == "B200" ) + baudRate = B200; + else if ( baudString == "B300" ) + baudRate = B300; + else if ( baudString == "B600" ) + baudRate = B600; + else if ( baudString == "B1200" ) + baudRate = B1200; + else if ( baudString == "B1800" ) + baudRate = B1800; + else if ( baudString == "B2400" ) + baudRate = B2400; + else if ( baudString == "B4800" ) + baudRate = B4800; + else if ( baudString == "B9600" ) + baudRate = B9600; + else if ( baudString == "B19200" ) + baudRate = B19200; + else if ( baudString == "B38400" ) + baudRate = B38400; + else + { + kdError() << k_funcinfo << "Unknown baud rate = \""<closePort(); + return; + } + + if ( ! m_pSerialPort->openPort( port, baudRate ) ) + { + p_itemDocument->canvas()->setMessage( i18n("Could not open port %1").arg( port ) ); + return; + } +} + + +void SerialPortComponent::stepNonLogic() +{ + m_pCD->setHigh( m_pSerialPort->pinState( SerialPort::CD ) ); +// m_pRD->setHigh( m_pSerialPort->pinState( SerialPort::RD ) ); + m_pCTS->setHigh( m_pSerialPort->pinState( SerialPort::CTS ) ); + m_pRI->setHigh( m_pSerialPort->pinState( SerialPort::RI ) ); +} + + +void SerialPortComponent::tdCallback( bool isHigh ) +{ + m_pSerialPort->setPinState( SerialPort::TD, isHigh ); +} + + +void SerialPortComponent::dtrCallback( bool isHigh ) +{ + m_pSerialPort->setPinState( SerialPort::DTR, isHigh ); +} + + +void SerialPortComponent::dsrCallback( bool isHigh ) +{ + m_pSerialPort->setPinState( SerialPort::DSR, isHigh ); +} + + +void SerialPortComponent::rtsCallback( bool isHigh ) +{ + m_pSerialPort->setPinState( SerialPort::RTS, isHigh ); +} + + +void SerialPortComponent::drawShape( QPainter & p ) +{ + drawPortShape( p ); +} diff --git a/src/electronics/components/serialportcomponent.h b/src/electronics/components/serialportcomponent.h new file mode 100644 index 0000000..4f9bc9a --- /dev/null +++ b/src/electronics/components/serialportcomponent.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef SERIALPORTCOMPONENT_H +#define SERIALPORTCOMPONENT_H + +#include "logic.h" +#include "component.h" + +class SerialPort; + +/** +@author David Saxton +*/ +class SerialPortComponent : public CallbackClass, public Component +{ + public: + SerialPortComponent( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~SerialPortComponent(); + + virtual bool canFlip() const { return true; } + static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem * libraryItem(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + + protected: + /** + * @param baudRate as defined in + */ + void initPort( const QString & port, unsigned baudRate ); + virtual void dataChanged(); + virtual void drawShape( QPainter & p ); + + void tdCallback( bool isHigh ); + void dtrCallback( bool isHigh ); + void dsrCallback( bool isHigh ); + void rtsCallback( bool isHigh ); + + LogicIn * m_pTD; + LogicIn * m_pDTR; +// LogicIn * m_pDSR; +// LogicIn * m_pRTS; + + LogicOut * m_pCD; +// LogicOut * m_pRD; + LogicOut * m_pCTS; + LogicOut * m_pRI; + + SerialPort * m_pSerialPort; +}; + +#endif diff --git a/src/electronics/components/toggleswitch.cpp b/src/electronics/components/toggleswitch.cpp new file mode 100644 index 0000000..4efe9ab --- /dev/null +++ b/src/electronics/components/toggleswitch.cpp @@ -0,0 +1,407 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "toggleswitch.h" + +#include "canvasitemparts.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "switch.h" + +#include +#include + +//BEGIN class ECDPDT +Item* ECDPDT::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECDPDT( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECDPDT::libraryItem() +{ + return new LibraryItem( + QString("ec/dpdt_toggle"), + i18n("DPDT"), + i18n("Switches"), + "dpdt.png", + LibraryItem::lit_component, + ECDPDT::construct ); +} + + +ECDPDT::ECDPDT( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "dpdt_toggle" ) +{ + m_name = i18n("DPDT Toggle"); + m_desc = i18n("Double-Pole Double-Throw switch."); + setSize( -16, -32, 32, 64 ); + + addButton( "button", QRect( -16, 32, 32, 20 ), "", true ); + + createProperty( "button_text", Variant::Type::String ); + property("button_text")->setCaption( i18n("Button Text") ); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + init4PinRight( -24, -8, 8, 24 ); + + init2PinLeft( -16, 16 ); + + m_switch1 = createSwitch( m_pNNode[0], m_pPNode[0], false ); + m_switch2 = createSwitch( m_pNNode[0], m_pPNode[1], true ); + m_switch3 = createSwitch( m_pNNode[1], m_pPNode[2], false ); + m_switch4 = createSwitch( m_pNNode[1], m_pPNode[3], true ); + pressed = false; +} + + +ECDPDT::~ECDPDT() +{ +} + + +void ECDPDT::dataChanged() +{ + button("button")->setText( dataString("button_text") ); + + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + + m_switch1->setBounce( bounce, bouncePeriod_ms ); + m_switch2->setBounce( bounce, bouncePeriod_ms ); + m_switch3->setBounce( bounce, bouncePeriod_ms ); + m_switch4->setBounce( bounce, bouncePeriod_ms ); +} + + +void ECDPDT::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-32; + const int radius = 2; + + p.drawEllipse( _x, _y+15, 2*radius, 2*radius ); + p.drawEllipse( _x, _y+47, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+7, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+23, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+39, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+55, 2*radius, 2*radius ); + + const int dy = pressed ? 6 : -6; + + p.drawLine( _x+2*radius, _y+16, _x+width()-2*radius+2, _y+16+dy ); + p.drawLine( _x+2*radius, _y+48, _x+width()-2*radius+2, _y+48+dy ); + + deinitPainter(p); +} + +void ECDPDT::buttonStateChanged( const QString &, bool state ) +{ + pressed = state; + m_switch1->setState( state ? Switch::Open : Switch::Closed ); + m_switch2->setState( state ? Switch::Closed : Switch::Open ); + m_switch3->setState( state ? Switch::Open : Switch::Closed ); + m_switch4->setState( state ? Switch::Closed : Switch::Open ); +} +//END class ECDPDT + + +//BEGIN class ECDPST +Item* ECDPST::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECDPST( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECDPST::libraryItem() +{ + return new LibraryItem( + QString("ec/dpst_toggle"), + i18n("DPST"), + i18n("Switches"), + "dpst.png", + LibraryItem::lit_component, + ECDPST::construct ); +} + +ECDPST::ECDPST( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "dpst_toggle" ) +{ + m_name = i18n("DPST Toggle"); + m_desc = i18n("Double-Pole Single-Throw switch."); + setSize( -16, -16, 32, 32 ); + + addButton( "button", QRect( -16, 16, 32, 20 ), "", true ); + + createProperty( "button_text", Variant::Type::String ); + property("button_text")->setCaption( i18n("Button Text") ); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + init2PinLeft( -8, 8 ); + init2PinRight( -8, 8 ); + + m_switch1 = createSwitch( m_pPNode[0], m_pNNode[0], true ); + m_switch2 = createSwitch( m_pPNode[1], m_pNNode[1], true ); + pressed = false; +} + + +ECDPST::~ECDPST() +{ +} + + +void ECDPST::dataChanged() +{ + button("button")->setText( dataString("button_text") ); + + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + + m_switch1->setBounce( bounce, bouncePeriod_ms ); + m_switch2->setBounce( bounce, bouncePeriod_ms ); +} + + +void ECDPST::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-16; + const int radius = 2; + + p.drawEllipse( _x, _y+6, 2*radius, 2*radius ); + p.drawEllipse( _x, _y+22, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+6, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+22, 2*radius, 2*radius ); + + const int dy = pressed ? 6 : 0; + + p.drawLine( _x+2*radius,_y+7,_x+width()-2*radius,_y+1+dy ); + p.drawLine( _x+2*radius,_y+24,_x+width()-2*radius,_y+18+dy ); + + deinitPainter(p); +} + +void ECDPST::buttonStateChanged( const QString &, bool state ) +{ + m_switch1->setState( state ? Switch::Closed : Switch::Open ); + m_switch2->setState( state ? Switch::Closed : Switch::Open ); + pressed = state; +} +//END class ECDPST + + +//BEGIN class ECSPDT +Item* ECSPDT::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECSPDT( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECSPDT::libraryItem() +{ + return new LibraryItem( + QString("ec/spdt_toggle"), + i18n("SPDT"), + i18n("Switches"), + "spdt.png", + LibraryItem::lit_component, + ECSPDT::construct ); +} + + +ECSPDT::ECSPDT( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "spdt_toggle" ) +{ + m_name = i18n("SPDT Toggle"); + m_desc = i18n("Single-Pole Double-Throw switch."); + setSize( -16, -16, 32, 32 ); + + addButton( "button", QRect( -16, 16, width(), 20 ), "", true ); + + createProperty( "button_text", Variant::Type::String ); + property("button_text")->setCaption( i18n("Button Text") ); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + init1PinLeft( 0 ); + init2PinRight( -8, 8 ); + + m_switch1 = createSwitch( m_pNNode[0], m_pPNode[0], false ); + m_switch2 = createSwitch( m_pNNode[0], m_pPNode[1], true ); + + pressed = false; +} + + +ECSPDT::~ECSPDT() +{ +} + + +void ECSPDT::dataChanged() +{ + button("button")->setText( dataString("button_text") ); + + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + + m_switch1->setBounce( bounce, bouncePeriod_ms ); + m_switch2->setBounce( bounce, bouncePeriod_ms ); +} + + +void ECSPDT::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-16; + const int radius = 2; + + p.drawEllipse( _x, _y+15, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+6, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+22, 2*radius, 2*radius ); + + const int dy = pressed ? 21 : 10; + p.drawLine( _x+2*radius, _y+16, _x+width()-2*radius+2, _y+dy ); + + deinitPainter(p); +} + +void ECSPDT::buttonStateChanged( const QString &, bool state ) +{ + pressed = state; + m_switch1->setState( state ? Switch::Open : Switch::Closed ); + m_switch2->setState( state ? Switch::Closed : Switch::Open ); +} +//END class ECSPDT + + +//BEGIN class ECSPST +Item* ECSPST::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECSPST( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECSPST::libraryItem() +{ + return new LibraryItem( + QString("ec/spst_toggle"), + i18n("SPST"), + i18n("Switches"), + "spst.png", + LibraryItem::lit_component, + ECSPST::construct + ); +} + + +ECSPST::ECSPST( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "spst_toggle" ) +{ + m_name = i18n("SPST Toggle"); + m_desc = i18n("Single-Pole Single-Throw switch."); + setSize( -16, -8, 32, 16 ); + pressed = false; + + addButton( "button", QRect( -16, 8, width(), 20 ), "", true ); + + createProperty( "button_text", Variant::Type::String ); + property("button_text")->setCaption( i18n("Button Text") ); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + button("button")->setState(pressed); + + init1PinLeft(); + init1PinRight(); + + m_switch = createSwitch( m_pNNode[0], m_pPNode[0], !pressed ); +} + + +ECSPST::~ECSPST() +{ +} + + +void ECSPST::dataChanged() +{ + button("button")->setText( dataString("button_text") ); + + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + m_switch->setBounce( bounce, bouncePeriod_ms ); +} + + +void ECSPST::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-8; + const int radius = 2; + + p.drawEllipse( _x, _y+7, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+7, 2*radius, 2*radius ); + const int dy = pressed ? 0 : -6; + p.drawLine( _x+2*radius, _y+8, _x+width()-2*radius, _y+8+dy ); + + deinitPainter(p); +} + +void ECSPST::buttonStateChanged( const QString &, bool state ) +{ + pressed = state; + m_switch->setState( state ? Switch::Closed : Switch::Open ); +} +//END class ECSPST + diff --git a/src/electronics/components/toggleswitch.h b/src/electronics/components/toggleswitch.h new file mode 100644 index 0000000..80fd064 --- /dev/null +++ b/src/electronics/components/toggleswitch.h @@ -0,0 +1,116 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef TOGGLESWITCH_H +#define TOGGLESWITCH_H + +#include "component.h" + +/** +@short Double Pole Double Throw +@author David Saxton +*/ +class ECDPDT : public Component +{ +public: + ECDPDT( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECDPDT(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + virtual bool canFlip() const { return true; } + +private: + virtual void drawShape( QPainter &p ); + Switch *m_switch1; + Switch *m_switch2; + Switch *m_switch3; + Switch *m_switch4; + bool pressed; +}; + + +/** +@short Double Pole Single Throw +@author David Saxton +*/ +class ECDPST : public Component +{ +public: + ECDPST( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECDPST(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + virtual bool canFlip() const { return true; } + +private: + virtual void drawShape( QPainter &p ); + Switch *m_switch1; + Switch *m_switch2; + bool pressed; +}; + + +/** +@short Single Pole Double Throw +@author David Saxton +*/ +class ECSPDT : public Component +{ +public: + ECSPDT( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECSPDT(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + virtual bool canFlip() const { return true; } + +private: + virtual void drawShape( QPainter &p ); + Switch *m_switch1; + Switch *m_switch2; + bool pressed; +}; + + +/** +@short Single-Pole Single-Throw Switch +@author David Saxton +*/ +class ECSPST : public Component +{ +public: + ECSPST( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECSPST(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + virtual bool canFlip() const { return true; } + +private: + virtual void drawShape( QPainter &p ); + Switch *m_switch; + bool pressed; +}; + +#endif diff --git a/src/electronics/ecnode.cpp b/src/electronics/ecnode.cpp new file mode 100644 index 0000000..0fb2801 --- /dev/null +++ b/src/electronics/ecnode.cpp @@ -0,0 +1,239 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "circuitdocument.h" +#include "src/core/ktlconfig.h" +#include "component.h" +#include "connector.h" +#include "ecnode.h" +#include "pin.h" + +#include +#include + +#include + +// The voltage at the middle of the voltage indicator +const double vMidPoint = 5.; + +// The maximum length of the voltage indiactor +const int vLength = 8; + +// The current at the middle of the current indicator +const double iMidPoint = 0.03; + +// The maximum thicnkess of the current indicator +const int iLength = 6; + +inline double calcVProp( const double v ) +{ + return 1 - vMidPoint/(vMidPoint+std::abs(v)); +} + +inline double calcIProp( const double i ) +{ + return 1 - iMidPoint/(iMidPoint+std::abs(i)); +} + +inline int calcThickness( const double prop ) +{ + return (int)((iLength-2)*prop+2); +} + +inline int calcLength( const double prop, const double v ) +{ + return (v>0) ? -int(vLength*prop) : int(vLength*prop); +} + +ECNode::ECNode( ICNDocument *icnDocument, Node::node_type _type, node_dir dir, const QPoint &pos, QString *_id ) + : Node( icnDocument, _type, dir, pos, _id ) +{ + m_prevV = 0; + m_prevI = 0; + m_pinPoint = 0l; + m_bShowVoltageBars = KTLConfig::showVoltageBars(); + + icnDocument->registerItem(this); + + if ( type() == ec_pin ) + { + m_pinPoint = new QCanvasRectangle( 0, 0, 3, 3, canvas() ); + m_pinPoint->setBrush(Qt::black); + m_pinPoint->setPen(Qt::black); + } + + m_pins.resize(1); + m_pins[0] = new Pin(this); +} + + +ECNode::~ECNode() +{ + if (m_pinPoint) + m_pinPoint->setCanvas(0l); + delete m_pinPoint; + m_pinPoint = 0l; + + for ( unsigned i = 0; i < m_pins.size(); i++ ) + delete m_pins[i]; + m_pins.resize(0); +} + + +void ECNode::setNumPins( unsigned num ) +{ + unsigned oldNum = m_pins.size(); + + if ( num == oldNum ) + return; + + if ( num > oldNum ) + { + m_pins.resize(num); + for ( unsigned i = oldNum; i < num; i++ ) + m_pins[i] = new Pin(this); + } + else + { + for ( unsigned i = num; i < oldNum; i++ ) + delete m_pins[i]; + m_pins.resize(num); + } + + emit numPinsChanged(num); +} + + +void ECNode::setNodeChanged() +{ + if ( !canvas() || numPins() != 1 ) + return; + + Pin * pin = m_pins[0]; + + double v = pin->voltage(); + double i = pin->current(); + + if ( v != m_prevV || i != m_prevI ) + { + QRect r = boundingRect(); + r.setCoords( r.left()+(r.width()/2)-1, r.top()+(r.height()/2)-1, r.right()-(r.width()/2)+1, r.bottom()-(r.height()/2)+1 ); + canvas()->setChanged(r); + m_prevV = v; + m_prevI = i; + } +} + + +void ECNode::setParentItem( CNItem * parentItem ) +{ + Node::setParentItem(parentItem); + + if ( Component * component = dynamic_cast(parentItem) ) + { + connect( component, SIGNAL(elementDestroyed(Element* )), this, SLOT(removeElement(Element* )) ); + connect( component, SIGNAL(switchDestroyed( Switch* )), this, SLOT(removeSwitch( Switch* )) ); + } +} + + +void ECNode::removeElement( Element * e ) +{ + for ( unsigned i = 0; i < m_pins.size(); i++ ) + m_pins[i]->removeElement(e); +} + + +void ECNode::removeSwitch( Switch * sw ) +{ + for ( unsigned i = 0; i < m_pins.size(); i++ ) + m_pins[i]->removeSwitch( sw ); +} + + +void ECNode::drawShape( QPainter &p ) +{ + const int _x = int(x()); + const int _y = int(y()); + + if ( type() == ec_junction ) + { +// p.drawRect( _x-2, _y-1, 5, 3 ); +// p.drawRect( _x-1, _y-2, 3, 5 ); + p.drawRect( _x-1, _y-1, 3, 3 ); + return; + } + + if (m_pinPoint) + { + bool drawDivPoint; + QPoint divPoint = findConnectorDivergePoint(&drawDivPoint); + m_pinPoint->setVisible(drawDivPoint); + m_pinPoint->move( divPoint.x()-1, divPoint.y()-1 ); + } + + // Now to draw on our current/voltage bar indicators + + if ( numPins() == 1 ) + { + double v = pin()->voltage(); + double vProp = calcVProp(v); + int length = calcLength( vProp, v ); + + if ( m_bShowVoltageBars && length != 0 ) + { + // we can assume that v != 0 as length != 0 + + QPen oldPen = p.pen(); + + double i = pin()->current(); + double iProp = calcIProp(i); + int thickness = calcThickness(iProp); + + if ( v > 0 ) + p.setPen( QPen( QColor( 255, 166, 0 ), thickness ) ); + + else + p.setPen( QPen( QColor( 0, 136, 255 ), thickness ) ); + + // The node line (drawn at the end of this function) will overdraw + // some of the voltage bar, so we need to adapt the length + if ( v > 0 && (m_dir == Node::dir_up || m_dir == Node::dir_down) ) + length--; + else if ( v < 0 && (m_dir == Node::dir_left || m_dir == Node::dir_right) ) + length++; + + if ( m_dir == Node::dir_right ) + p.drawLine( _x+3, _y, _x+3, _y+length ); + + else if ( m_dir == Node::dir_down ) + p.drawLine( _x, _y+3, _x-length, _y+3 ); + + else if ( m_dir == Node::dir_left ) + p.drawLine( _x-3, _y, _x-3, _y+length ); + + else if ( m_dir == Node::dir_up ) + p.drawLine( _x, _y-3, _x-length, _y-3 ); + + p.setPen(oldPen); + } + } + + QPen pen( p.pen() ); + pen.setWidth( (numPins() > 1) ? 2 : 1 ); + p.setPen(pen); + + if ( m_dir == Node::dir_right ) p.drawLine( _x, _y, _x+8, _y ); + else if ( m_dir == Node::dir_down ) p.drawLine( _x, _y, _x, _y+8 ); + else if ( m_dir == Node::dir_left ) p.drawLine( _x, _y, _x-8, _y ); + else if ( m_dir == Node::dir_up ) p.drawLine( _x, _y, _x, _y-8 ); +} + +#include "ecnode.moc" diff --git a/src/electronics/ecnode.h b/src/electronics/ecnode.h new file mode 100644 index 0000000..6f8f36e --- /dev/null +++ b/src/electronics/ecnode.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ECNODE_H +#define ECNODE_H + +#include "node.h" + +#include + +class ECNode; +class Element; +class Pin; +class Switch; +class QTimer; + +typedef QValueList ECNodeList; +typedef QValueList ElementList; +typedef QValueVector PinVector; + +/** +@short Electrical node with voltage / current / etc properties +@author David Saxton +*/ +class ECNode : public Node +{ + Q_OBJECT + public: + ECNode( ICNDocument *icnDocument, Node::node_type type, node_dir dir, const QPoint &pos, QString *id = 0L ); + ~ECNode(); + + virtual void setParentItem( CNItem *parentItem ); + virtual void drawShape( QPainter &p ); + /** + * Set the number of pins "contained" in this node. + */ + void setNumPins( unsigned num ); + /** + * @return the number of pins in this node. + * @see setNumPins + */ + unsigned numPins() const { return m_pins.size(); } + PinVector pins() const { return m_pins; } + Pin * pin( unsigned num = 0 ) const { return (num < m_pins.size()) ? m_pins[num] : 0l; } + bool showVoltageBars() const { return m_bShowVoltageBars; } + void setShowVoltageBars( bool show ) { m_bShowVoltageBars = show; } + void setNodeChanged(); + + signals: + void numPinsChanged( unsigned newNum ); + + protected slots: + void removeElement( Element * e ); + void removeSwitch( Switch * sw ); + + protected: + bool m_bShowVoltageBars; + double m_prevV; + double m_prevI; + QCanvasRectangle * m_pinPoint; + PinVector m_pins; +}; + +#endif + + + diff --git a/src/electronics/gpsimprocessor.cpp b/src/electronics/gpsimprocessor.cpp new file mode 100644 index 0000000..1a3b862 --- /dev/null +++ b/src/electronics/gpsimprocessor.cpp @@ -0,0 +1,880 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "config.h" +#ifndef NO_GPSIM + +#include "asmparser.h" +#include "debugmanager.h" +#include "flowcodedocument.h" +#include "gpsimprocessor.h" +#include "language.h" +#include "languagemanager.h" +#include "microlibrary.h" +#include "processchain.h" +#include "simulator.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gpsim/cod.h" +#include "gpsim/interface.h" +#include "gpsim/gpsim_classes.h" +#include "gpsim/pic-processor.h" +#include "gpsim/registers.h" +#include "gpsim/14bit-registers.h" +#include "gpsim/symbol.h" +#include "gpsim/sim_context.h" + +bool bDoneGpsimInit = false; +bool bUseGUI = true; +// extern "C" void initialize_gpsim(); +// void initialize_gpsim(void); +extern void initialize_commands(); +void initialize_ConsoleUI(); +extern void initialize_readline(); +extern void gui_main(void); +extern void cli_main(); +void gpsim_version() {}; +void quit_gui() {}; + + +//BEGIN class GpsimProcessor +/** +Work around a bug in gpsim: the directory in a filename is recorded twice, e.g. +"/home/david/afile.asm" is recorded as "/home/david//home/david/afile.asm". This +function will remove the duplicated directory path (by searching for a "//"). +*/ +QString sanitizeGpsimFile( QString file ) +{ + int pos = file.find("//"); + if ( pos != -1 ) + { + file.remove( 0, pos + 1 ); + } + return file; +} + + +GpsimProcessor::GpsimProcessor( QString symbolFile, QObject *parent ) + : QObject(parent), + m_symbolFile(symbolFile) +{ + if (!bDoneGpsimInit) + { +#ifndef GPSIM_0_21_4 + initialize_ConsoleUI(); +#endif + initialize_gpsim_core(); + initialization_is_complete(); + + bDoneGpsimInit = true; + } + + m_bCanExecuteNextCycle = true; + m_bIsRunning = false; + m_pPicProcessor = 0l; + m_codLoadStatus = CodUnknown; + m_pRegisterMemory = 0l; + m_debugMode = GpsimDebugger::AsmDebugger; + m_pDebugger[0] = m_pDebugger[1] = 0l; + + Processor * tempProcessor = 0l; + const char * fileName = symbolFile.ascii(); + +#ifdef GPSIM_0_21_4 + switch ( (cod_errors)load_symbol_file( &tempProcessor, fileName ) ) + { + case COD_SUCCESS: + m_codLoadStatus = CodSuccess; + break; + case COD_FILE_NOT_FOUND: + m_codLoadStatus = CodFileNotFound; + break; + case COD_UNRECOGNIZED_PROCESSOR: + m_codLoadStatus = CodUnrecognizedProcessor; + break; + case COD_FILE_NAME_TOO_LONG: + m_codLoadStatus = CodFileNameTooLong; + break; + case COD_LST_NOT_FOUND: + m_codLoadStatus = CodLstNotFound; + break; + case COD_BAD_FILE: + m_codLoadStatus = CodBadFile; + break; + default: + m_codLoadStatus = CodUnknown; + } +#else // GPSIM_0_21_11+ + FILE * pFile = fopen( fileName, "r" ); + if ( !pFile ) + m_codLoadStatus = CodFileUnreadable; + else + m_codLoadStatus = ( ProgramFileTypeList::GetList().LoadProgramFile( & tempProcessor, fileName, pFile ) ) ? CodSuccess : CodFailure; +#endif + + m_pPicProcessor = dynamic_cast(tempProcessor); + + if ( codLoadStatus() == CodSuccess ) + { + m_pRegisterMemory = new RegisterSet( m_pPicProcessor ); + m_pDebugger[0] = new GpsimDebugger( GpsimDebugger::AsmDebugger, this ); + m_pDebugger[1] = new GpsimDebugger( GpsimDebugger::HLLDebugger, this ); + Simulator::self()->attachGpsimProcessor(this); + DebugManager::self()->registerGpsim(this); + } +} + + +GpsimProcessor::~GpsimProcessor() +{ + Simulator::self()->detachGpsimProcessor(this); + delete m_pRegisterMemory; + + if ( m_pDebugger[0] ) + m_pDebugger[0]->deleteLater(); + if ( m_pDebugger[1] ) + m_pDebugger[1]->deleteLater(); +} + + +void GpsimProcessor::displayCodLoadStatus( ) +{ + switch (m_codLoadStatus) + { + case CodSuccess: + break; + case CodFileNotFound: + KMessageBox::sorry( 0l, i18n("The cod file \"%1\" was not found.").arg(m_symbolFile), i18n("File Not Found") ); + break; + case CodUnrecognizedProcessor: + KMessageBox::sorry( 0l, i18n("The processor for cod file \"%1\" is unrecognized.").arg(m_symbolFile), i18n("Unrecognized Processor") ); + break; + case CodFileNameTooLong: + KMessageBox::sorry( 0l, i18n("The file name \"%1\" is too long.").arg(m_symbolFile), i18n("Filename Too Long") ); + break; + case CodLstNotFound: + KMessageBox::sorry( 0l, i18n("The lst file associated with the cod file \"%1\" was not found.").arg(m_symbolFile), i18n("LST File Not Found") ); + break; + case CodBadFile: + KMessageBox::sorry( 0l, i18n("The cod file \"%1\" is bad.").arg(m_symbolFile), i18n("Bad File") ); + break; + case CodFileUnreadable: + KMessageBox::sorry( 0l, i18n("The cod file \"%1\" could not be read from.").arg(m_symbolFile), i18n("Unreadable File") ); + break; + case CodFailure: + case CodUnknown: + KMessageBox::sorry( 0l, i18n("An error occured with the cod file \"%1\".").arg(m_symbolFile), i18n("Error") ); + break; + } +} + + +unsigned GpsimProcessor::programMemorySize() const +{ + return m_pPicProcessor->program_memory_size(); +} + + +QStringList GpsimProcessor::sourceFileList() +{ + QStringList files; + + // Work around nasty bug in gpsim 0.21.4 where nsrc_files value might be used uninitiazed + int max = m_pPicProcessor->files.nsrc_files(); +#ifdef GPSIM_0_21_4 + if ( max > 10 ) + max = 10; +#endif + + for ( int i = 0; i < max; ++i ) + { + if ( !m_pPicProcessor->files[i] ) + continue; + + files << sanitizeGpsimFile( m_pPicProcessor->files[i]->name().c_str() ); + } + + return files; +} + + +void GpsimProcessor::emitLineReached() +{ + m_pDebugger[0]->emitLineReached(); + m_pDebugger[1]->emitLineReached(); +} + + +void GpsimProcessor::setRunning( bool run ) +{ + if ( m_bIsRunning == run ) + return; + + m_bIsRunning = run; + emit runningStatusChanged(run); +} + + +void GpsimProcessor::executeNext() +{ + if ( !m_bIsRunning ) + return; + + if ( !m_bCanExecuteNextCycle ) + { + m_bCanExecuteNextCycle = true; + return; + } + + unsigned long long beforeExecuteCount = get_cycles().get(); + + m_pPicProcessor->step_one(false); // Don't know what the false is for; gpsim ignores its value anyway + + // Some instructions take more than one cycle to execute, so ignore next cycle if this was the case + if ( (get_cycles().get() - beforeExecuteCount) > 1 ) + m_bCanExecuteNextCycle = false; + + currentDebugger()->checkForBreak(); + + // Let's also update the values of RegisterInfo every 50 milliseconds + if ( (beforeExecuteCount % 20000) == 0 ) + registerMemory()->update(); +} + + +void GpsimProcessor::reset() +{ + bool wasRunning = isRunning(); + m_pPicProcessor->reset(SIM_RESET); + setRunning(false); + if (!wasRunning) + { + // If we weren't running before, then the next signal won't have been emitted + emitLineReached(); + } +} + + +MicroInfo * GpsimProcessor::microInfo( ) const +{ + if ( !m_pPicProcessor ) + return 0l; + + return MicroLibrary::self()->microInfoWithID( m_pPicProcessor->name().c_str() ); +} + + +int GpsimProcessor::operandRegister( unsigned address ) +{ + instruction * ins = m_pPicProcessor->program_memory[ address ]; + if ( Register_op * reg = dynamic_cast(ins) ) + return reg->register_address; + return -1; +} + + +int GpsimProcessor::operandLiteral( unsigned address ) +{ + instruction * ins = m_pPicProcessor->program_memory[ address ]; + if ( Literal_op * lit = dynamic_cast(ins) ) + return lit->L; + return -1; +} + + +GpsimProcessor::ProgramFileValidity GpsimProcessor::isValidProgramFile( const QString & programFile ) +{ + if ( !KStandardDirs::exists(programFile) ) + return DoesntExist; + + QString extension = programFile.right( programFile.length() - programFile.findRev('.') - 1 ).lower(); + + if ( extension == "flowcode" || + extension == "asm" || + extension == "cod" || + extension == "basic" || extension == "microbe" || + extension == "c" ) + return Valid; + + if ( extension == "hex" && QFile::exists( QString(programFile).replace(".hex",".cod") ) ) + return Valid; + + return IncorrectType; +} + + +QString GpsimProcessor::generateSymbolFile( const QString &fileName, QObject *receiver, const char *successMember, const char * failMember ) +{ + if ( !isValidProgramFile(fileName) ) + return QString::null; + + QString extension = fileName.right( fileName.length() - fileName.findRev('.') - 1 ).lower(); + + if ( extension == "cod" ) + { + QTimer::singleShot( 0, receiver, successMember ); + return fileName; + } + if ( extension == "hex" ) + { + QTimer::singleShot( 0, receiver, successMember ); + // We've already checked for the existance of the ".cod" file in GpsimProcessor::isValidProgramFile + return QString(fileName).replace(".hex",".cod"); + } + + else if ( extension == "basic" || extension == "microbe" ) + { + compileMicrobe( fileName, receiver, successMember, failMember ); + return QString(fileName).replace( "."+extension, ".cod" ); + } + else if ( extension == "flowcode" ) + { + const QString hexFile = KTempFile( QString::null, ".hex" ).name(); + + ProcessOptions o; + o.b_addToProject = false; + o.setTargetFile( hexFile ); + o.setInputFiles( fileName ); + o.setMethod( ProcessOptions::Method::Forget ); + o.setProcessPath( ProcessOptions::ProcessPath::FlowCode_Program ); + + ProcessChain * pc = LanguageManager::self()->compile(o); + if (receiver) + { + if (successMember) + connect( pc, SIGNAL(successful()), receiver, successMember ); + if (failMember) + connect( pc, SIGNAL(failed()), receiver, failMember ); + } + + return QString(hexFile).replace( ".hex", ".cod" ); + } + else if ( extension == "asm" ) + { + ProcessOptions o; + o.b_addToProject = false; + o.setTargetFile( QString(fileName).replace(".asm",".hex")); + o.setInputFiles(fileName); + o.setMethod( ProcessOptions::Method::Forget ); + o.setProcessPath( ProcessOptions::ProcessPath::path( ProcessOptions::guessMediaType(fileName), ProcessOptions::ProcessPath::Program ) ); + + ProcessChain *pc = LanguageManager::self()->compile(o); + if (receiver) + { + if (successMember) + connect( pc, SIGNAL(successful()), receiver, successMember ); + if (failMember) + connect( pc, SIGNAL(failed()), receiver, failMember ); + } + + return QString(fileName).replace(".asm",".cod"); + } + else if ( extension == "c" ) + { + ProcessOptions o; + o.b_addToProject = false; + o.setTargetFile( QString(fileName).replace(".c",".hex")); + o.setInputFiles(fileName); + o.setMethod( ProcessOptions::Method::Forget ); + o.setProcessPath( ProcessOptions::ProcessPath::C_Program ); + + ProcessChain *pc = LanguageManager::self()->compile(o); + if (receiver) + { + if (successMember) + connect( pc, SIGNAL(successful()), receiver, successMember ); + if (failMember) + connect( pc, SIGNAL(failed()), receiver, failMember ); + } + + return QString(fileName).replace(".c",".cod"); + } + + if ( failMember ) + QTimer::singleShot( 0, receiver, failMember ); + return QString::null; +} + + +void GpsimProcessor::compileMicrobe( const QString &filename, QObject *receiver, const char * successMember, const char * failMember ) +{ + ProcessOptions o; + o.b_addToProject = false; + o.setTargetFile( QString(filename).replace(".microbe",".hex") ); + o.setInputFiles(filename); + o.setMethod( ProcessOptions::Method::Forget ); + o.setProcessPath( ProcessOptions::ProcessPath::Microbe_Program ); + ProcessChain * pc = LanguageManager::self()->compile(o); + if (receiver) + { + if (successMember) + connect( pc, SIGNAL(successful()), receiver, successMember ); + if (failMember) + connect( pc, SIGNAL(failed()), receiver, failMember ); + } +} +//END class GpsimProcessor + + + +//BEGIN class GpsimDebugger +GpsimDebugger::GpsimDebugger( Type type, GpsimProcessor * gpsim ) + : QObject() +{ + m_pGpsim = gpsim; + m_type = type; + m_pBreakFromOldLine = 0l; + m_addressToLineMap = 0l; + m_stackLevelLowerBreak = -1; + m_addressSize = 0; + + connect( m_pGpsim, SIGNAL(runningStatusChanged(bool )), this, SLOT(gpsimRunningStatusChanged(bool )) ); + + if ( type == HLLDebugger ) + { + const QStringList sourceFileList = m_pGpsim->sourceFileList(); + QStringList::const_iterator sflEnd = sourceFileList.end(); + for ( QStringList::const_iterator it = sourceFileList.begin(); it != sflEnd; ++it ) + { + AsmParser p(*it); + p.parse(this); + } + } + + initAddressToLineMap(); +} + + +GpsimDebugger::~GpsimDebugger() +{ + QValueList debugLinesToDelete; + + for ( unsigned i = 0; i < m_addressSize; ++i ) + { + DebugLine * dl = m_addressToLineMap[i]; + if ( !dl || dl->markedAsDeleted() ) + continue; + + dl->markAsDeleted(); + debugLinesToDelete += dl; + } + + const QValueList::iterator end = debugLinesToDelete.end(); + for ( QValueList::iterator it = debugLinesToDelete.begin(); it != end; ++it ) + delete *it; + + delete [] m_addressToLineMap; +} + + +void GpsimDebugger::gpsimRunningStatusChanged( bool isRunning ) +{ + if (!isRunning) + { + m_stackLevelLowerBreak = -1; + m_pBreakFromOldLine = 0l; + emitLineReached(); + } +} + + +void GpsimDebugger::associateLine( const QString & sourceFile, int sourceLine, const QString & assemblyFile, int assemblyLine ) +{ + if ( assemblyLine < 0 || sourceLine < 0 ) + { + kdWarning() << k_funcinfo << "Invalid lines: assemblyLine="<programMemorySize(); + + delete [] m_addressToLineMap; + m_addressToLineMap = new DebugLine*[m_addressSize]; + memset( m_addressToLineMap, 0, m_addressSize * sizeof(DebugLine*) ); + + if ( m_type == AsmDebugger ) + { + for ( unsigned i = 0; i < m_addressSize; ++i ) + { + int line = m_pGpsim->picProcessor()->pma->get_src_line(i) - 1; + int fileID = m_pGpsim->picProcessor()->pma->get_file_id(i); + FileContext * fileContext = m_pGpsim->picProcessor()->files[fileID]; + + if (fileContext) + m_addressToLineMap[i] = new DebugLine( sanitizeGpsimFile( fileContext->name().c_str() ), line ); + } + } + else + { + SourceLineMap::const_iterator slmEnd = m_sourceLineMap.end(); + for ( SourceLineMap::const_iterator it = m_sourceLineMap.begin(); it != slmEnd; ++it ) + { + SourceLineMap::const_iterator next = it; + ++next; + + int asmToLine = ((next == slmEnd) || (next.key().fileName() != it.key().fileName())) ? -1 : next.key().line() - 1; + + QString asmFile = it.key().fileName(); + int asmFromLine = it.key().line(); + SourceLine sourceLine = it.data(); + + + std::string stdAsmFile( asmFile.ascii() ); + int fileID = m_pGpsim->picProcessor()->files.Find( stdAsmFile ); + if ( fileID == -1 ) + { + kdWarning() << k_funcinfo << "Could not find FileContext (asmFile=\""<picProcessor()->files[fileID]->max_line() - 2; + + if ( (asmFromLine < 0) || (asmToLine < asmFromLine) ) + { + kdWarning() << k_funcinfo << "Invalid lines: asmFromLine="<isRunning() ) + return; + + int initialStack = (m_pGpsim->picProcessor()->stack->pointer & m_pGpsim->picProcessor()->stack->stack_mask) + dl; + DebugLine * initialLine = currentDebugLine(); + + if ( initialStack < 0 ) + initialStack = 0; + + // Reset any previous stackStep, and step + m_pBreakFromOldLine = 0l; + m_stackLevelLowerBreak = -1; + m_pGpsim->picProcessor()->step_one(false); + + int currentStack = m_pGpsim->picProcessor()->stack->pointer & m_pGpsim->picProcessor()->stack->stack_mask; + DebugLine * currentLine = currentDebugLine(); + + if ( (initialStack >= currentStack) && (initialLine != currentLine) ) + emitLineReached(); + + else + { + // Looks like we stepped into something or haven't gone onto the next + // instruction, wait until we step back out.... + m_stackLevelLowerBreak = initialStack; + m_pBreakFromOldLine = initialLine; + m_pGpsim->setRunning(true); + } +} +//END class Debugger + + + +//BEGIN class RegisterSet +RegisterSet::RegisterSet( pic_processor * picProcessor ) +{ + unsigned numRegisters = picProcessor->rma.get_size(); + m_registers.resize( numRegisters, 0l ); + for ( unsigned i = 0; i < numRegisters; ++i ) + { + RegisterInfo * info = new RegisterInfo( & picProcessor->rma[i] ); + m_registers[i] = info; + m_nameToRegisterMap[ info->name() ] = info; + } + + RegisterInfo * info = new RegisterInfo( picProcessor->W ); + m_registers.append( info ); + m_nameToRegisterMap[ info->name() ] = info; +} + + +RegisterSet::~RegisterSet() +{ + for ( unsigned i = 0; i < m_registers.size(); ++i ) + delete m_registers[i]; +} + + +RegisterInfo * RegisterSet::fromAddress( unsigned address ) +{ + return (address < m_registers.size()) ? m_registers[address] : 0l; +} + + +RegisterInfo * RegisterSet::fromName( const QString & name ) +{ + // First try the name as case sensitive, then as case insensitive. + if ( m_nameToRegisterMap.contains( name ) ) + return m_nameToRegisterMap[ name ]; + + QString nameLower = name.lower(); + + RegisterInfoMap::iterator end = m_nameToRegisterMap.end(); + for ( RegisterInfoMap::iterator it = m_nameToRegisterMap.begin(); it != end; ++ it ) + { + if ( it.key().lower() == nameLower ) + return it.data(); + } + + return 0l; +} + + +void RegisterSet::update() +{ + for ( unsigned i = 0; i < m_registers.size(); ++i ) + m_registers[i]->update(); +} +//END class RegisterSet + + + +//BEGIN class RegisterInfo +RegisterInfo::RegisterInfo( Register * reg ) +{ + assert(reg); + m_pRegister = reg; + m_type = Invalid; + m_prevEmitValue = 0; + + switch ( m_pRegister->isa() ) + { + case Register::GENERIC_REGISTER: + m_type = Generic; + break; + case Register::FILE_REGISTER: + m_type = File; + break; + case Register::SFR_REGISTER: + m_type = SFR; + break; + case Register::BP_REGISTER: + m_type = Breakpoint; + break; + case Register::INVALID_REGISTER: + m_type = Invalid; + break; + } + + m_name = m_pRegister->baseName(); +} + + +unsigned RegisterInfo::value() const +{ + return m_pRegister->value.data; +} + + +void RegisterInfo::update() +{ + unsigned newValue = value(); + if ( newValue != m_prevEmitValue ) + { + m_prevEmitValue = newValue; + emit valueChanged(newValue); + } +} + + +QString RegisterInfo::toString( RegisterType type ) +{ + switch ( type ) + { + case Generic: + return i18n("Generic"); + + case File: + return i18n("File"); + + case SFR: + return i18n("SFR"); + + case Breakpoint: + return i18n("Breakpoint"); + + case Invalid: + return i18n("Invalid"); + } + + return i18n("Unknown"); +} +//END class RegisterInfo + + + +//BEGIN class DebugLine +DebugLine::DebugLine( const QString & fileName, int line ) + : SourceLine( fileName, line ) +{ + m_bIsBreakpoint = false; + m_bMarkedAsDeleted = false; +} + + +DebugLine::DebugLine() + : SourceLine() +{ + m_bIsBreakpoint = false; + m_bMarkedAsDeleted = false; +} +//END class DebugLine + + +#include "gpsimprocessor.moc" + +#endif diff --git a/src/electronics/gpsimprocessor.h b/src/electronics/gpsimprocessor.h new file mode 100644 index 0000000..0650fd9 --- /dev/null +++ b/src/electronics/gpsimprocessor.h @@ -0,0 +1,393 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "config.h" +#ifndef NO_GPSIM + +#ifndef GPSIMPROCESSOR_H +#define GPSIMPROCESSOR_H + +#include "sourceline.h" + +#include +#include +#include +#include + +class DebugLine; +class GpsimProcessor; +class MicroInfo; +class pic_processor; // from gpsim +class Register; +class RegisterMemoryAccess; + +typedef QMap SourceLineMap; +typedef QMap QStringMap; +typedef QValueList IntList; + + +class DebugLine : public SourceLine +{ + public: + DebugLine(); + DebugLine( const QString & fileName, int line ); + /** + * Whether or not to break when we reach this line. + */ + bool isBreakpoint() const { return m_bIsBreakpoint; } + /** + * Set whether or not to break when we reach this line. + */ + void setBreakpoint( bool breakpoint ) { m_bIsBreakpoint = breakpoint; } + /** + * Used for efficiency purposes by GpsimProcessor. Sets a flag. + */ + void markAsDeleted() { m_bMarkedAsDeleted = true; } + /** + * Used for efficiency purposes by GpsimProcessor. + */ + bool markedAsDeleted() const { return m_bMarkedAsDeleted; } + + protected: + bool m_bIsBreakpoint; + bool m_bMarkedAsDeleted; + + private: + DebugLine( const DebugLine & dl ); + DebugLine & operator = ( const DebugLine & dl ); +}; + + +/** +@short Stores info from gpsim register, used to hide gpsim interface +@author David Saxton +*/ +class RegisterInfo : public QObject +{ + Q_OBJECT + public: + RegisterInfo( Register * reg ); + + enum RegisterType + { + Invalid, + Generic, + File, + SFR, + Breakpoint + }; + + RegisterType type() const { return m_type; } + QString name() const { return m_name; } + unsigned value() const; + static QString toString( RegisterType type ); + + /** + * Checks to see if the value has changed; if so, emit new value. + */ + void update(); + + signals: + void valueChanged( unsigned newValue ); + + protected: + QString m_name; + RegisterType m_type; + Register * m_pRegister; + unsigned m_prevEmitValue; +}; + + +/** +@short Stores information about a set of registers, used to hide gpsim interface. +@author David Saxton +*/ +class RegisterSet +{ + public: + RegisterSet( pic_processor * picProcessor ); + ~RegisterSet(); + + /** + * Calls update for each RegisterInfo in this set. + */ + void update(); + /** + * Returns the number of registers. + */ + unsigned size() const { return m_registers.size(); } + + RegisterInfo * fromAddress( unsigned address ); + RegisterInfo * fromName( const QString & name ); + + protected: + typedef QMap< QString, RegisterInfo * > RegisterInfoMap; + RegisterInfoMap m_nameToRegisterMap; + QValueVector< RegisterInfo * > m_registers; +}; + + +/** +@author David Saxton +*/ +class GpsimDebugger : public QObject +{ + friend class GpsimProcessor; + Q_OBJECT + + public: + enum Type + { + AsmDebugger = 0, + HLLDebugger = 1 + }; + + GpsimDebugger( Type type, GpsimProcessor * gpsim ); + ~GpsimDebugger(); + + GpsimProcessor * gpsim() const { return m_pGpsim; } + + /** + * When an assembly file was generated by a high level language compiler + * like SDCC, it will insert markers like ";#CSRC" that show which line + * of source-code generated the given set of assembly instructions. This + * matches up the assembly file lines with the associated source file + * lines. + */ + void associateLine( const QString & sourceFile, int sourceLine, const QString & assemblyFile, int assemblyLine ); + /** + * Check to see if we've hit a breakpoint or similar; if so, this + * function will stop the execution of the PIC program. + */ + void checkForBreak(); + /** + * Sets the breakpoints used for the given file to exactly those that + * are contained in this list. Breakpoints for other files are not + * affected. + * @param path the location of the file (which gpsim must recognise). + */ + void setBreakpoints( const QString & path, const IntList & lines ); + /** + * Sets / removes the breakpoint at the given line + */ + void setBreakpoint( const QString & path, int line, bool isBreakpoint ); + /** + * Returns the current source line that gpsim is at. By default, this + * will be the corresponding assembly line. That can be overwritten + * using mapAddressBlockToLine. + */ + SourceLine currentLine(); + /** + * Returns a pointer to the debug info for the current line. + */ + DebugLine * currentDebugLine(); + /** + * @return the program address for the given line (or -1 if no such + * line). + */ + int programAddress( const QString & path, int line ); + /** + * Step into the next program line. + */ + void stepInto(); + /** + * Step over the next program instruction. If we are currently running, + * this function will do nothing. Otherwise, it will record the current + * stack level, step, and if the new stack level is <= the initial level + * then return - otherwise, this processor will set a breakpoint for + * stack levels <= initial, and go to running mode. + */ + void stepOver(); + /** + * Similar to stepOver, except we break when the stack level becomes < + * the initial stack level (instead of <= initial). + */ + void stepOut(); + + signals: + /** + * Emitted when a line is reached. By default, this is the line of the + * input assembly file; however, the line associated with an address in + * the PIC memory can be changed with mapAddressBlockToLine. + */ + void lineReached( const SourceLine & sourceLine ); + + protected slots: + void gpsimRunningStatusChanged( bool isRunning ); + + protected: + void initAddressToLineMap(); + void stackStep( int dl ); + void emitLineReached(); + + int m_stackLevelLowerBreak; // Set by step-over, for when the stack level decreases to the one given + SourceLine m_previousAtLineEmit; // Used for working out whether we should emit a new line reached signal + DebugLine ** m_addressToLineMap; + DebugLine * m_pBreakFromOldLine; + GpsimProcessor * m_pGpsim; + Type m_type; + unsigned m_addressSize; + SourceLineMap m_sourceLineMap; // assembly <--> High level language +}; + + +/** +@author David Saxton +*/ +class GpsimProcessor : public QObject +{ + friend class GpsimDebugger; + Q_OBJECT + + public: + /** + * Create a new gpsim processor. After calling this constructor, you + * should always call codLoadStatus() to ensure that the cod file was + * loaded successfully. + */ + GpsimProcessor( QString symbolFile, QObject *parent = 0 ); + ~GpsimProcessor(); + + void setDebugMode( GpsimDebugger::Type mode ) { m_debugMode = mode; } + GpsimDebugger * currentDebugger() const { return m_pDebugger[m_debugMode]; } + + enum CodLoadStatus + { + CodSuccess, + CodFileNotFound, + CodUnrecognizedProcessor, + CodFileNameTooLong, + CodLstNotFound, + CodBadFile, + CodFileUnreadable, + CodFailure, + CodUnknown // Should never be this, but just in case load_symbol_file returns something funny + }; + + enum InstructionType + { + LiteralOp, + BitOp, + RegisterOp, + UnknownOp, + }; + + /** + * @return status of opening the COD file + * @see displayCodLoadStatus + */ + CodLoadStatus codLoadStatus() const { return m_codLoadStatus; } + /** + * Popups a messagebox to the user according to the CodLoadStatus. Will + * only popup a messagebox if the CodLoadStatus wasn't CodSuccess. + */ + void displayCodLoadStatus(); + /** + * Returns a list of source files for the currently running program. + */ + QStringList sourceFileList(); + /** + * Set whether or not to run gpsim. (i.e. whether or not the step + * function should do anything when called with force=false). + */ + void setRunning( bool run ); + /** + * Returns true if running (currently simulating), else gpsim is paused. + */ + bool isRunning() const { return m_bIsRunning; } + /** + * Execute the next program instruction. If we are not in a running + * mode, then this function will do nothing. + */ + void executeNext(); + /** + * Reset all parts of the simulation. Gpsim will not run until + * setRunning(true) is called. Breakpoints are not affected. + */ + void reset(); + /** + * Returns the microinfo describing this processor. + */ + MicroInfo * microInfo() const; + + pic_processor * picProcessor() const { return m_pPicProcessor; } + unsigned programMemorySize() const; + RegisterSet * registerMemory() const { return m_pRegisterMemory; } + /** + * @return the instruction type at the given address. + */ + InstructionType instructionType( unsigned address ); + /** + * @return the address of the operand's register at address if the + * instruction at address is a register operation, and -1 otherwise. + */ + int operandRegister( unsigned address ); + /** + * @return the literal if the instruction at address is a literal + * operation, and -1 otherwise. + */ + int operandLiteral( unsigned address ); + + //BEGIN Convenience functions for PIC files + enum ProgramFileValidity { DoesntExist, IncorrectType, Valid }; + /** + * @return information on the validity of the given program file (either + * DoesntExist, IncorrectType, or Valid). + * @see static QString generateSymbolFile + */ + static ProgramFileValidity isValidProgramFile( const QString & programFile ); + /** + * Converts the file at programFile to a Symbol file for emulation, + * and returns that symbol file's path + * @param programFile The full url to the file + * @param assembled The slot to connect the assembled signal to + * @see static bool isValidProgramFile( const QString &programFile ) + */ + static QString generateSymbolFile( const QString &fileName, QObject *receiver, const char *successMember, const char * failMember = 0l ); + /** + *Compile microbe to output to the given filename + */ + static void compileMicrobe( const QString &filename, QObject *receiver, const char * successMember, const char * failMember = 0l ); + //END convenience functions for PIC files + + signals: + /** + * Emitted when the running status of gpsim changes. + */ + void runningStatusChanged( bool isRunning ); + + protected: + /** + * Calls emitLineReached for each debugger. + */ + void emitLineReached(); + + pic_processor * m_pPicProcessor; + CodLoadStatus m_codLoadStatus; + const QString m_symbolFile; + RegisterSet * m_pRegisterMemory; + GpsimDebugger::Type m_debugMode; + GpsimDebugger * m_pDebugger[2]; // Asm, HLL + + /** + * We are called effectively for each cycle of the cycle of the + * processor. This value is used as some instructions (e.g. goto) take + * two cycles to execute, and so we must ignore one cycle to ensure + * realtime simulation. + */ + bool m_bCanExecuteNextCycle; + + private: + bool m_bIsRunning; +}; + +#endif + +#endif // !NO_GPSIM diff --git a/src/electronics/pin.cpp b/src/electronics/pin.cpp new file mode 100644 index 0000000..56848fc --- /dev/null +++ b/src/electronics/pin.cpp @@ -0,0 +1,175 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "pin.h" + +#include +#include + +Pin::Pin( ECNode * parent ) +{ + assert(parent); + m_pECNode = parent; + m_voltage = 0.; + m_current = 0.; + m_eqId = -2; + m_bCurrentIsKnown = false; + m_groundType = Pin::gt_never; +} + + +Pin::~Pin() +{ + WireList::iterator end = m_inputWireList.end(); + for ( WireList::iterator it = m_inputWireList.begin(); it != end; ++it ) + delete *it; + + end = m_outputWireList.end(); + for ( WireList::iterator it = m_outputWireList.begin(); it != end; ++it ) + delete *it; +} + + +PinList Pin::localConnectedPins( ) const +{ +// kdDebug() << k_funcinfo << "Input wires: "<startPin(); + } + + end = m_outputWireList.end(); + for ( WireList::const_iterator it = m_outputWireList.begin(); it != end; ++it ) + { + if (*it) + pins << (*it)->endPin(); + } + + pins += m_switchConnectedPins; + + return pins; +} + + +void Pin::setSwitchConnected( Pin * pin, bool isConnected ) +{ + if (!pin) + return; + + if (isConnected) + { + if ( !m_switchConnectedPins.contains(pin) ) + m_switchConnectedPins.append(pin); + } + else + m_switchConnectedPins.remove(pin); +} + + +void Pin::addCircuitDependentPin( Pin * pin ) +{ + if ( pin && !m_circuitDependentPins.contains(pin) ) + m_circuitDependentPins.append(pin); +} + + +void Pin::addGroundDependentPin( Pin * pin ) +{ + if ( pin && !m_groundDependentPins.contains(pin) ) + m_groundDependentPins.append(pin); +} + + +void Pin::removeDependentPins() +{ + m_circuitDependentPins.clear(); + m_groundDependentPins.clear(); +} + + +void Pin::addElement( Element * e ) +{ + if ( !e || m_elementList.contains(e) ) + return; + m_elementList.append(e); +} + + +void Pin::removeElement( Element * e ) +{ + m_elementList.remove(e); +} + + +void Pin::addSwitch( Switch * sw ) +{ + if ( !sw || m_switchList.contains( sw ) ) + return; + m_switchList << sw; +} + + +void Pin::removeSwitch( Switch * sw ) +{ + m_switchList.remove( sw ); +} + + +void Pin::addInputWire( Wire * wire ) +{ + if ( wire && !m_inputWireList.contains(wire) ) + m_inputWireList << wire; +} + + +void Pin::addOutputWire( Wire * wire ) +{ + if ( wire && !m_outputWireList.contains(wire) ) + m_outputWireList << wire; +} + + +bool Pin::calculateCurrentFromWires() +{ + m_inputWireList.remove( (Wire*)0l ); + m_outputWireList.remove( (Wire*)0l ); + + const WireList inputs = m_inputWireList; + const WireList outputs = m_outputWireList; + + m_current = 0.0; + + WireList::const_iterator end = inputs.end(); + for ( WireList::const_iterator it = inputs.begin(); it != end; ++it ) + { + if ( !(*it)->currentIsKnown() ) + return false; + + m_current -= (*it)->current(); + } + + end = outputs.end(); + for ( WireList::const_iterator it = outputs.begin(); it != end; ++it ) + { + if ( !(*it)->currentIsKnown() ) + return false; + + m_current += (*it)->current(); + } + + m_bCurrentIsKnown = true; + return true; +} + diff --git a/src/electronics/pin.h b/src/electronics/pin.h new file mode 100644 index 0000000..1e10663 --- /dev/null +++ b/src/electronics/pin.h @@ -0,0 +1,211 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PIN_H +#define PIN_H + +#include "wire.h" + +#include +#include +#include + +class ECNode; +class Element; +class Pin; +class Switch; +class Wire; + +typedef QValueList ElementList; +typedef QValueList > PinList; +typedef QValueList SwitchList; +typedef QValueList > WireList; + + +/** +@author David Saxton +*/ +class Pin : public QObject +{ + public: + /** + * Priorities for ground pin. gt_always will (as expected) always assign + * the given pin as ground, gt_never will never do. If no gt_always pins + * exist, then the pin with the highest priority will be set as ground - + * if there is at least one pin that is not of ground type gt_never. These + * are only predefined recommended values, so if you choose not to use one + * of these, please respect the priorities with respect to the examples, and + * always specify a priority between 0 and 20. + * @see groundLevel + */ + enum GroundType + { + gt_always = 0, // ground + gt_high = 5, // voltage points + gt_medium = 10, // voltage sources + gt_low = 15, // current sources + gt_never = 20 // everything else + }; + Pin( ECNode * parent ); + ~Pin(); + + ECNode * parentECNode() const { return m_pECNode; } + /** + * This function returns the pins that are directly connected to this pins: + * either at the ends of connected wires, or via switches. + */ + PinList localConnectedPins() const; + /** + * Adds/removes the given pin to the list of ones that this pin is/isn't + * connected to via a switch. + */ + void setSwitchConnected( Pin * pin, bool isConnected ); + /** + * After calculating the nodal voltages in the circuit, this function should + * be called to tell the pin what its voltage is. + */ + void setVoltage( double v ) { m_voltage = v; } + /** + * Returns the voltage as set by setVoltage. + */ + double voltage() const { return m_voltage; } + /** + * After calculating nodal voltages, each component will be called to tell + * its pins what the current flowing *into* the component is. This sets it + * to zero in preparation to merging the current. + */ + void resetCurrent() { m_current = 0.0; } + /** + * Adds the given current to that already flowing into the pin. + * @see setCurrent + */ + void mergeCurrent( double i ) { m_current += i; } + /** + * Returns the current as set by mergeCurrent. + */ + double current() const { return m_current; } + /** + * In many cases (such as if this pin is a ground pin), the current + * flowing into the pin has not been calculated, and so the value + * returned by current() cannot be trusted. + */ + void setCurrentKnown( bool isKnown ) { m_bCurrentIsKnown = isKnown; } + /** + * Tell thie Pin that none of the currents from the switches have yet + * been merged. + */ + void setSwitchCurrentsUnknown() { m_switchList.remove( 0l ); m_unknownSwitchCurrents = m_switchList; } + /** + * This returns the value given by setCurrentKnown AND'd with whether + * we know the current from each switch attached to this pin. + * @see setCurrentKnown + */ + bool currentIsKnown() const { return m_bCurrentIsKnown && m_unknownSwitchCurrents.isEmpty(); } + /** + * Tells the Pin that the current from the given switch has been merged. + */ + void setSwitchCurrentKnown( Switch * sw ) { m_unknownSwitchCurrents.remove( sw ); } + /** + * Tries to calculate the Pin current from the input / output wires. + * @return whether was successful. + */ + bool calculateCurrentFromWires(); + /** + * Sets the "ground type" - i.e. the priority that this pin has for being + * ground over other pins in the circuit. Lower gt = higher priority. It's + * recommended to use Pin::GroundType. + */ + void setGroundType( int gt ) { m_groundType = gt; } + /** + * Returns the priority for ground. + */ + int groundType() const { return m_groundType; } + /** + * Adds a dependent pin - one whose voltages will (or might) affect the + * voltage of this pin. This is set by Component. + */ + void addCircuitDependentPin( Pin * pin ); + /** + * Adds a dependent pin - one whose voltages will (or might) affect the + * voltage of this pin. This is set by Component. + */ + void addGroundDependentPin( Pin * pin ); + /** + * Removes all Circuit and Ground dependent pins. + */ + void removeDependentPins(); + /** + * Returns the ids of the pins whose voltages will affect this pin. + * @see void setDependentPins( QStringList ids ) + */ + PinList circuitDependentPins() const { return m_circuitDependentPins; } + /** + * Returns the ids of the pins whose voltages will affect this pin. + * @see void setDependentPins( QStringList ids ) + */ + PinList groundDependentPins() const { return m_groundDependentPins; } + /** + * Use this function to set the pin identifier for equations, + * which should be done every time new pins are registered. + */ + void setEqId( int id ) { m_eqId = id; } + /** + * The equation identifier. + * @see setEqId + */ + int eqId() const { return m_eqId; } + /** + * Returns a list of elements that will affect this pin (e.g. if this + * pin is part of a resistor, then that list will contain a pointer to a + * Resistance element) + */ + ElementList elements() const { return m_elementList; } + /** + * Adds an element to the list of those that will affect this pin. + */ + void addElement( Element *e ); + /** + * Removes an element from the list of those that will affect this pin. + */ + void removeElement( Element *e ); + /** + * Adds an switch to the list of those that will affect this pin. + */ + void addSwitch( Switch *e ); + /** + * Removes an switch from the list of those that will affect this pin. + */ + void removeSwitch( Switch *e ); + + void addInputWire( Wire * wire ); + void addOutputWire( Wire * wire ); + void removeWire( Wire * wire ); + WireList inputWireList() const { return m_inputWireList; } + WireList outputWireList() const { return m_outputWireList; } + int numWires() const { return m_inputWireList.size() + m_outputWireList.size(); } + + protected: + double m_voltage; + double m_current; + int m_eqId; + bool m_bCurrentIsKnown; + PinList m_circuitDependentPins; + PinList m_groundDependentPins; + ElementList m_elementList; + SwitchList m_switchList; + int m_groundType; + PinList m_switchConnectedPins; + WireList m_inputWireList; + WireList m_outputWireList; + ECNode * m_pECNode; + SwitchList m_unknownSwitchCurrents; +}; + +#endif diff --git a/src/electronics/port.cpp b/src/electronics/port.cpp new file mode 100644 index 0000000..541195b --- /dev/null +++ b/src/electronics/port.cpp @@ -0,0 +1,514 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "port.h" + +#include + +#include +#include +#include +#include +#include + +//BEGIN class Port +Port::Port() +{ +} + + +Port::~Port() +{ +} + + +QStringList Port::ports( unsigned probeResult ) +{ + return SerialPort::ports(probeResult) + ParallelPort::ports(probeResult); +} +//END class Port + + + +//BEGIN class SerialPort +SerialPort::SerialPort() +{ + m_file = -1; +} + + +SerialPort::~SerialPort() +{ + closePort(); +} + + +void SerialPort::setPinState( Pin pin, bool state ) +{ + if ( m_file == -1 ) + return; + + int flags = -1; + + switch ( pin ) + { + case TD: + ioctl( m_file, state ? TIOCSBRK : TIOCCBRK, 0 ); + return; + + case DTR: + flags = TIOCM_DTR; + break; + + case DSR: + flags = TIOCM_DSR; + break; + + case RTS: + flags = TIOCM_RTS; + break; + + case CD: + case RD: + case GND: + case CTS: + case RI: + break; + }; + + if ( flags == -1 ) + { + kdError() << k_funcinfo << "Bad pin " << pin << endl; + return; + } + + if ( ioctl( m_file, state ? TIOCMBIS : TIOCMBIC, & flags ) == -1 ) + kdError() << k_funcinfo << "Could not set pin " << pin << " errno = " << errno << endl; +} + + +bool SerialPort::pinState( Pin pin ) +{ + if ( m_file == -1 ) + return false; + + int mask = 0; + + switch ( pin ) + { + case CD: + mask = TIOCM_CD; + break; + + case RD: + mask = TIOCM_SR; + break; + + case CTS: + mask = TIOCM_CTS; + break; + + case RI: + mask = TIOCM_RI; + break; + + case TD: + case DTR: + case GND: + case DSR: + case RTS: + break; + } + + if ( mask == 0 ) + { + kdError() << k_funcinfo << "Bad pin " << pin << endl; + return false; + } + + int bits = 0; + if ( ioctl( m_file, TIOCMGET, & bits ) == -1 ) + { + kdError() << k_funcinfo << "Could not read pin" << pin << " errno = " << errno << endl; + return false; + } + + return bits & mask; +} + + +Port::ProbeResult SerialPort::probe( const QString & port ) +{ + int file = open( port.ascii(), O_NOCTTY | O_NONBLOCK | O_RDONLY ); + if ( file == -1 ) + return Port::DoesntExist; + + close(file); + + file = open( port.ascii(), O_NOCTTY | O_NONBLOCK | O_RDWR ); + if ( file == -1 ) + return Port::ExistsButNotRW; + close(file); + + return Port::ExistsAndRW; +} + + +bool SerialPort::openPort( const QString & port, speed_t baudRate ) +{ + closePort(); + + m_file = open( port.ascii(), O_NOCTTY | O_NONBLOCK | O_RDWR ); + if ( m_file == -1 ) + { + kdError() << k_funcinfo << "Could not open port " << port << endl; + return false; + } + + termios state; + tcgetattr( m_file, & state ); + + // Save the previous state for restoration in close. + m_previousState = state; + + state.c_iflag = IGNBRK | IGNPAR; + state.c_oflag = 0; + state.c_cflag = baudRate | CS8 | CREAD | CLOCAL; + state.c_lflag = 0; + tcsetattr( m_file, TCSANOW, & state ); + + return true; +} + + +void SerialPort::closePort() +{ + if ( m_file == -1 ) + return; + + ioctl( m_file, TIOCCBRK, 0 ); + usleep(1); + tcsetattr( m_file, TCSANOW, & m_previousState ); + close( m_file ); + m_file = -1; +} + + +QStringList SerialPort::ports( unsigned probeResult ) +{ + QStringList list; + + for ( int i = 0; i < 8; ++i ) + { + QString dev = QString("/dev/ttyS%1").arg(i); + if ( probe(dev) & probeResult ) + list << dev; + } + + for ( unsigned i = 0; i < 8; ++i ) + { + QString dev = QString("/dev/tts/%1").arg(i); + if ( probe(dev) & probeResult ) + list << dev; + } + + for ( unsigned i = 0; i < 8; ++i ) + { + QString dev = QString("/dev/ttyUSB%1").arg(i); + if ( probe(dev) & probeResult ) + list << dev; + } + + for ( unsigned i = 0; i < 8; ++i ) + { + QString dev = QString("/dev/usb/tts/%1").arg(i); + if ( probe(dev) & probeResult ) + list << dev; + } + + return list; +} +//END class SerialPort + + + +//BEGIN class ParallelPort +const int IRQ_MODE_BIT = 1 << 20; // Controls if pin 10 (Ack) causes interrupts +const int INPUT_MODE_BIT = 1 << 21; // Controls if the data pins are input or output +const int ALWAYS_INPUT_PINS = ParallelPort::STATUS_PINS; + +const int IOCTL_REG_READ[3] = { + PPRDATA, + PPRSTATUS, + PPRCONTROL, +}; + +const int IOCTL_REG_WRITE[3] = { + PPWDATA, + 0, + PPWCONTROL, +}; + +const int INVERT_MASK[3] = { + 0x0, + 0x80, // 10000000 + 0x0b, // 00001011 +}; + +ParallelPort::ParallelPort() +{ + reset(); +} + + +ParallelPort::~ParallelPort() +{ +} + + +void ParallelPort::reset() +{ + m_file = -1; + m_reg[Data] = 0; + m_reg[Status] = 0; + m_reg[Control] = 0; + m_outputPins = INPUT_MODE_BIT | IRQ_MODE_BIT; + m_inputPins = ALWAYS_INPUT_PINS | INPUT_MODE_BIT | IRQ_MODE_BIT; +} + + +//BEGIN Pin-oriented operations +void ParallelPort::setPinState( int pins, bool state ) +{ + // only allow writing to output pins + pins &= m_outputPins; + + if ( pins & DATA_PINS ) + setDataState( (pins & DATA_PINS) >> 0, state ); + + if ( pins & CONTROL_PINS ) + setControlState( (pins & CONTROL_PINS) >> 16, state ); +} + + +int ParallelPort::pinState( int pins ) +{ + int value = 0; + + // only allow reading from input pins + pins &= m_inputPins; + + if ( pins & DATA_PINS ) + value |= ((readFromRegister( Data ) & ((pins & DATA_PINS) >> 0)) << 0); + + if ( pins & STATUS_PINS ) + value |= ((readFromRegister( Status ) & ((pins & STATUS_PINS) >> 8)) << 8); + + if ( pins & CONTROL_PINS ) + value |= ((readFromRegister( Control ) & ((pins & CONTROL_PINS) >> 16)) << 16); + + return value; +} + + +void ParallelPort::setDataState( uchar pins, bool state ) +{ + uchar value = readFromRegister( Data ); + + if ( state ) + value |= pins; + else + value &= ~pins; + + writeToData( value ); +} + + +void ParallelPort::setControlState( uchar pins, bool state ) +{ + uchar value = readFromRegister( Control ); + + if ( state ) + value |= pins; + else + value &= ~pins; + + writeToControl( value ); +} +//END Pin-oriented operations + + + +//BEGIN Register-oriented operations +uchar ParallelPort::readFromRegister( Register reg ) +{ + if ( m_file == -1 ) + return 0; + +// uchar value = inb( m_lpBase + reg ) ^ INVERT_MASK[reg]; + uchar value = 0; + if ( ioctl( m_file, IOCTL_REG_READ[reg], &value ) ) + kdError() << k_funcinfo << "errno=" << errno << endl; + else + m_reg[reg] = value; + return value; +} + + +void ParallelPort::writeToRegister( Register reg, uchar value ) +{ + if ( m_file == -1 ) + return; + +// outb( value ^ INVERT_MASK[reg], m_lpBase + reg ); + if ( ioctl( m_file, IOCTL_REG_WRITE[reg], & value ) ) + kdError() << k_funcinfo << "errno=" << errno << endl; + else + m_reg[reg] = value; +} + + +void ParallelPort::writeToData( uchar value ) +{ + writeToRegister( Data, value ); +} + + +void ParallelPort::writeToControl( uchar value ) +{ + // Set all inputs to ones + value |= ((m_inputPins & CONTROL_PINS) >> 16); + + writeToRegister( Control, value ); +} +//END Register-oriented operations + + +//BEGIN Changing pin directions +void ParallelPort::setDataDirection( Direction dir ) +{ + if ( dir == Input ) + { + m_inputPins |= DATA_PINS; + m_outputPins &= ~DATA_PINS; + } + else + { + m_inputPins &= DATA_PINS; + m_outputPins |= ~DATA_PINS; + } + + setPinState( INPUT_MODE_BIT, dir == Input ); +} + + +void ParallelPort::setControlDirection( int pins, Direction dir ) +{ + pins &= CONTROL_PINS; + + if ( dir == Input ) + { + m_inputPins |= pins; + m_outputPins &= ~pins; + } + else + { + m_inputPins &= pins; + m_outputPins |= ~pins; + } + + setControlState( 0, true ); +} +//END Changing pin directions + + +Port::ProbeResult ParallelPort::probe( const QString & port ) +{ + int file = open( port.ascii(), O_RDWR ); + if ( file == -1 ) + return Port::DoesntExist; + + if ( ioctl( file, PPCLAIM ) != 0 ) + { + close(file); + return Port::ExistsButNotRW; + } + + ioctl( file, PPRELEASE ); + close(file); + return Port::ExistsAndRW; +} + + +QStringList ParallelPort::ports( unsigned probeResult ) +{ + QStringList list; + + for ( unsigned i = 0; i < 8; ++i ) + { + QString dev = QString("/dev/parport%1").arg(i); + if ( probe(dev) & probeResult ) + list << dev; + } + + for ( unsigned i = 0; i < 8; ++i ) + { + QString dev = QString("/dev/parports/%1").arg(i); + if ( probe(dev) & probeResult ) + list << dev; + } + + return list; +} + + +bool ParallelPort::openPort( const QString & port ) +{ + if ( m_file != -1 ) + { + kdWarning() << k_funcinfo << "Port already open" << endl; + return false; + } + + m_file = open( port.ascii(), O_RDWR ); + + if ( m_file == -1 ) + { + kdError() << k_funcinfo << "Could not open port \"" << port << "\": errno="< +using namespace std; + + +//BEGIN class BJTSettings +BJTSettings::BJTSettings() +{ + I_S = 1e-16; + N_F = 1.0; + N_R = 1.0; + B_F = 100.0; + B_R = 1.0; +} +//END class BJTSettings + + + +//BEGIN class BJTState +BJTState::BJTState() +{ + reset(); +} + + +void BJTState::reset() +{ + for ( unsigned i = 0; i < 3; ++i ) + { + for ( unsigned j = 0; j < 3; ++j ) + A[i][j] = 0.0; + + I[i] = 0.0; + } +} + + +BJTState BJTState::operator-( const BJTState & s ) const +{ + BJTState newState( *this ); + + for ( unsigned i = 0; i < 3; ++i ) + { + for ( unsigned j = 0; j < 3; ++j ) + newState.A[i][j] -= s.A[i][j]; + + newState.I[i] -= s.I[i]; + } + + return newState; +} +//END class BJTState + + + +//BEGIN class BJT +BJT::BJT( const bool isNPN ) + : NonLinear() +{ + V_BE_prev = 0.0; + V_BC_prev = 0.0; + m_pol = isNPN ? 1 : -1; + m_numCNodes = 3; +} + + +BJT::~BJT() +{ +} + + +void BJT::add_map() +{ + if (!b_status) return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse( p_cnode[0]->n(), p_cnode[0]->n(), Map::et_unstable, false ); + } + if ( !p_cnode[1]->isGround ) + { + p_A->setUse( p_cnode[1]->n(), p_cnode[1]->n(), Map::et_unstable, false ); + } + if ( !p_cnode[2]->isGround ) + { + p_A->setUse( p_cnode[2]->n(), p_cnode[2]->n(), Map::et_unstable, false ); + } + + if ( !p_cnode[0]->isGround && !p_cnode[2]->isGround ) + { + p_A->setUse( p_cnode[0]->n(), p_cnode[2]->n(), Map::et_unstable, false ); + p_A->setUse( p_cnode[2]->n(), p_cnode[0]->n(), Map::et_unstable, false ); + } + if ( !p_cnode[1]->isGround && !p_cnode[2]->isGround ) + { + p_A->setUse( p_cnode[2]->n(), p_cnode[1]->n(), Map::et_unstable, false ); + p_A->setUse( p_cnode[1]->n(), p_cnode[2]->n(), Map::et_unstable, false ); + } +} + + +void BJT::add_initial_dc() +{ + V_BE_prev = 0.0; + V_BC_prev = 0.0; + m_os.reset(); + update_dc(); +} + + +void BJT::updateCurrents() +{ + if (!b_status) + return; + + double V_B = p_cnode[0]->v; + double V_C = p_cnode[1]->v; + double V_E = p_cnode[2]->v; + + double V_BE = (V_B - V_E) * m_pol; + double V_BC = (V_B - V_C) * m_pol; + + double I_BE, I_BC, I_T, g_BE, g_BC, g_IF, g_IR; + calcIg( V_BE, V_BC, & I_BE, & I_BC, & I_T, & g_BE, & g_BC, & g_IF, & g_IR ); + + m_cnodeI[1] = I_BC - I_T; + m_cnodeI[2] = I_BE + I_T; + m_cnodeI[0] = -(m_cnodeI[1] + m_cnodeI[2]); +} + + +void BJT::update_dc() +{ + if (!b_status) + return; + + calc_eq(); + + BJTState diff = m_ns - m_os; + for ( unsigned i = 0; i < 3; ++i ) + { + for ( unsigned j = 0 ; j < 3; ++j ) + A_g( i, j ) += diff.A[i][j]; + + b_i( i ) += diff.I[i]; + } + + m_os = m_ns; +} + + +void BJT::calc_eq() +{ + double V_B = p_cnode[0]->v; + double V_C = p_cnode[1]->v; + double V_E = p_cnode[2]->v; + + double V_BE = (V_B - V_E) * m_pol; + double V_BC = (V_B - V_C) * m_pol; + + double I_S = m_bjtSettings.I_S; + double N_F = m_bjtSettings.N_F; + double N_R = m_bjtSettings.N_R; + + // adjust voltage to help convergence + double V_BEcrit = diodeCriticalVoltage( I_S, N_F * V_T ); + double V_BCcrit = diodeCriticalVoltage( I_S, N_R * V_T ); + V_BE_prev = V_BE = diodeVoltage( V_BE, V_BE_prev, V_T * N_F, V_BEcrit ); + V_BC_prev = V_BC = diodeVoltage( V_BC, V_BC_prev, V_T * N_R, V_BCcrit ); + + double I_BE, I_BC, I_T, g_BE, g_BC, g_IF, g_IR; + calcIg( V_BE, V_BC, & I_BE, & I_BC, & I_T, & g_BE, & g_BC, & g_IF, & g_IR ); + + double I_eq_B = I_BE - V_BE * g_BE; + double I_eq_C = I_BC - V_BC * g_BC; + double I_eq_E = I_T - V_BE * g_IF + V_BC * g_IR; + + m_ns.A[0][0] = g_BC + g_BE; + m_ns.A[0][1] = -g_BC; + m_ns.A[0][2] = -g_BE; + + m_ns.A[1][0] = -g_BC + (g_IF - g_IR); + m_ns.A[1][1] = g_IR + g_BC; + m_ns.A[1][2] = -g_IF; + + m_ns.A[2][0] = -g_BE - (g_IF - g_IR); + m_ns.A[2][1] = -g_IR; + m_ns.A[2][2] = g_BE + g_IF; + + m_ns.I[0] = (-I_eq_B - I_eq_C) * m_pol; + m_ns.I[1] = (+I_eq_C - I_eq_E) * m_pol; + m_ns.I[2] = (+I_eq_B + I_eq_E) * m_pol; +} + + +void BJT::calcIg( double V_BE, double V_BC, double * I_BE, double * I_BC, double * I_T, double * g_BE, double * g_BC, double * g_IF, double * g_IR ) +{ + double I_S = m_bjtSettings.I_S; + double N_F = m_bjtSettings.N_F; + double N_R = m_bjtSettings.N_R; + double B_F = m_bjtSettings.B_F; + double B_R = m_bjtSettings.B_R; + + // base-emitter diodes + double g_tiny = (V_BE < (-10 * V_T * N_F)) ? I_S : 0; + + double I_F; + diodeJunction( V_BE, I_S, V_T * N_F, & I_F, g_IF ); + + double I_BEI = I_F / B_F; + double g_BEI = *g_IF / B_F; + double I_BEN = g_tiny * V_BE; + double g_BEN = g_tiny; + *I_BE = I_BEI + I_BEN; + *g_BE = g_BEI + g_BEN; + + // base-collector diodes + g_tiny = (V_BC < (-10 * V_T * N_R)) ? I_S : 0; + + double I_R; + diodeJunction( V_BC, I_S, V_T * N_R, & I_R, g_IR ); + + double I_BCI = I_R / B_R; + double g_BCI = *g_IR / B_R; + double I_BCN = g_tiny * V_BC; + double g_BCN = g_tiny; + *I_BC = I_BCI + I_BCN; + *g_BC = g_BCI + g_BCN; + + *I_T = I_F - I_R; +} + + +void BJT::setBJTSettings( const BJTSettings & settings ) +{ + m_bjtSettings = settings; + + if (p_eSet) + p_eSet->setCacheInvalidated(); +} +//END class BJT + + diff --git a/src/electronics/simulation/bjt.h b/src/electronics/simulation/bjt.h new file mode 100644 index 0000000..52022aa --- /dev/null +++ b/src/electronics/simulation/bjt.h @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef BJT_H +#define BJT_H + +#include "matrix.h" +#include "nonlinear.h" + +class BJTState +{ + public: + BJTState(); + void reset(); + + BJTState operator-( const BJTState & s ) const; + + double A[3][3]; + double I[3]; +}; + + +class BJTSettings +{ + public: + BJTSettings(); + + double I_S; ///< saturation current + double N_F; ///< forward emission coefficient + double N_R; ///< reverse emission coefficient + double B_F; ///< forward beta + double B_R; ///< reverse beta +}; + + +/** +@author David Saxton +*/ +class BJT : public NonLinear +{ + public: + BJT( bool isNPN ); + virtual ~BJT(); + + virtual Type type() const { return Element_BJT; } + virtual void update_dc(); + virtual void add_initial_dc(); + virtual void add_map(); + BJTSettings settings() const { return m_bjtSettings; } + void setBJTSettings( const BJTSettings & settings ); + + protected: + virtual void updateCurrents(); + /** + * Calculates the new BJTState from the voltages on the nodes. + */ + void calc_eq(); + + void calcIg( double V_BE, double V_BC, double * I_BE, double * I_BC, double * I_T, double * g_BE, double * g_BC, double * g_IF, double * g_IR ); + + BJTState m_os; + BJTState m_ns; + int m_pol; + double V_BE_prev, V_BC_prev; + BJTSettings m_bjtSettings; +}; + +#endif diff --git a/src/electronics/simulation/capacitance.cpp b/src/electronics/simulation/capacitance.cpp new file mode 100644 index 0000000..9087c7f --- /dev/null +++ b/src/electronics/simulation/capacitance.cpp @@ -0,0 +1,117 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "capacitance.h" +#include "matrix.h" + +Capacitance::Capacitance( const double capacitance, const double delta ) + : Reactive(delta) +{ + m_cap = capacitance; + g_eq_old = i_eq_old = 0.; + m_numCNodes = 2; + setMethod( Capacitance::m_euler ); +} + +Capacitance::~Capacitance() +{ +} + +void Capacitance::setCapacitance( const double c ) +{ + m_cap = c; +} + +void Capacitance::add_initial_dc() +{ + // We don't need to do anything here, as time_step() will do that for us, + // apart from to make sure our old values are 0 + g_eq_old = i_eq_old = 0.; +} + +void Capacitance::updateCurrents() +{ + if (!b_status) return; + const double r_i = (p_cnode[0]->v-p_cnode[1]->v)*g_eq_old; + m_cnodeI[0] = -i_eq_old-r_i; + m_cnodeI[1] = -m_cnodeI[0]; +} + + +void Capacitance::add_map() +{ + if (!b_status) return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse( p_cnode[0]->n(), p_cnode[0]->n(), Map::et_unstable, false ); + } + if ( !p_cnode[1]->isGround ) + { + p_A->setUse( p_cnode[1]->n(), p_cnode[1]->n(), Map::et_unstable, false ); + } + + if ( !p_cnode[0]->isGround && !p_cnode[1]->isGround ) + { + p_A->setUse( p_cnode[0]->n(), p_cnode[1]->n(), Map::et_unstable, false ); + p_A->setUse( p_cnode[1]->n(), p_cnode[0]->n(), Map::et_unstable, false ); + } +} + + +void Capacitance::time_step() +{ + if (!b_status) return; + + double v = p_cnode[0]->v-p_cnode[1]->v; + double i_eq_new = 0.0, g_eq_new = 0.0; + + if ( m_method == Capacitance::m_euler ) + { + g_eq_new = m_cap/m_delta; + i_eq_new = -v*g_eq_new; + } + else if ( m_method == Capacitance::m_trap ) { + // TODO Implement + test trapezoidal method + g_eq_new = 2.*m_cap/m_delta; + } + + if ( g_eq_old != g_eq_new ) + { + A_g( 0, 0 ) += g_eq_new-g_eq_old; + A_g( 1, 1 ) += g_eq_new-g_eq_old; + A_g( 0, 1 ) -= g_eq_new-g_eq_old; + A_g( 1, 0 ) -= g_eq_new-g_eq_old; + } + + if ( i_eq_new != i_eq_old ) + { + b_i( 0 ) -= i_eq_new-i_eq_old; + b_i( 1 ) += i_eq_new-i_eq_old; + } + + g_eq_old = g_eq_new; + i_eq_old = i_eq_new; +} + +bool Capacitance::updateStatus() +{ + b_status = Reactive::updateStatus(); + if ( m_method == Capacitance::m_none ) b_status = false; + return b_status; +} + +void Capacitance::setMethod( Method m ) +{ + m_method = m; + updateStatus(); +} + + diff --git a/src/electronics/simulation/capacitance.h b/src/electronics/simulation/capacitance.h new file mode 100644 index 0000000..ccc083d --- /dev/null +++ b/src/electronics/simulation/capacitance.h @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef CAPACITANCE_H +#define CAPACITANCE_H + +#include "reactive.h" + +/** +@author David Saxton +@short Capacitance +*/ +class Capacitance : public Reactive +{ +public: + enum Method + { + m_none, // None + m_euler, // Backward Euler + m_trap // Trapezoidal (currently unimplemented) + }; + Capacitance( const double capacitance, const double delta ); + virtual ~Capacitance(); + + virtual Type type() const { return Element_Capacitance; } + /** + * Set the stepping use for numerical integration of capacitance, + * and the interval between successive updates + */ + void setMethod( Method m ); + virtual void time_step(); + virtual void add_initial_dc(); + void setCapacitance( const double c ); + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual bool updateStatus(); + +private: + double m_cap; // Capacitance + Method m_method; // Method of integration + + double g_eq_old; + double i_eq_old; +}; + +#endif diff --git a/src/electronics/simulation/cccs.cpp b/src/electronics/simulation/cccs.cpp new file mode 100644 index 0000000..9725735 --- /dev/null +++ b/src/electronics/simulation/cccs.cpp @@ -0,0 +1,89 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "elementset.h" +#include "matrix.h" +#include "cccs.h" + +CCCS::CCCS( const double gain ) + : Element::Element() +{ + m_g = gain; + m_numCBranches = 2; + m_numCNodes = 4; +} + +CCCS::~CCCS() +{ +} + +void CCCS::setGain( const double g ) +{ + if ( m_g == g ) + return; + + if (p_eSet) + p_eSet->setCacheInvalidated(); + + m_g = g; + add_initial_dc(); +} + + +void CCCS::add_map() +{ + if (!b_status) return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse_b( p_cnode[0]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[0]->n(), Map::et_constant, true ); + } + if ( !p_cnode[1]->isGround ) + { + p_A->setUse_b( p_cnode[1]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[1]->n(), Map::et_constant, true ); + } + if ( !p_cnode[2]->isGround ) + { + p_A->setUse_b( p_cnode[2]->n(), p_cbranch[1]->n(), Map::et_constant, true ); + } + if ( !p_cnode[3]->isGround ) + { + p_A->setUse_b( p_cnode[3]->n(), p_cbranch[1]->n(), Map::et_constant, true ); + } + p_A->setUse_d( p_cbranch[1]->n(), p_cbranch[0]->n(), Map::et_stable, true ); + p_A->setUse_d( p_cbranch[1]->n(), p_cbranch[1]->n(), Map::et_constant, true ); +} + +void CCCS::add_initial_dc() +{ + if (!b_status) + return; + + A_b( 0, 0 ) = 1; + A_c( 0, 0 ) = 1; + A_b( 1, 0 ) = -1; + A_c( 0, 1 ) = -1; + A_b( 2, 1 ) = 1; + A_b( 3, 1 ) = -1; + A_d( 1, 0 ) = -m_g; + A_d( 1, 1 ) = 1; +} + +void CCCS::updateCurrents() +{ + if (!b_status) return; + m_cnodeI[1] = p_cbranch[0]->i; + m_cnodeI[0] = -m_cnodeI[1]; + m_cnodeI[3] = p_cbranch[1]->i; + m_cnodeI[2] = -m_cnodeI[3]; +} + diff --git a/src/electronics/simulation/cccs.h b/src/electronics/simulation/cccs.h new file mode 100644 index 0000000..ba86e9e --- /dev/null +++ b/src/electronics/simulation/cccs.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef CCCS_H +#define CCCS_H + +#include "element.h" + +/** +CNodes n0 and n1 are used for the current control. +CNodes n2 and n3 are used for the current output. +Branches b0 and b1 are for control and output +@short Current Controlled Current Source +@author David Saxton +*/ +class CCCS : public Element +{ +public: + CCCS( const double gain ); + virtual ~CCCS(); + + virtual Type type() const { return Element_CCCS; } + void setGain( const double g ); + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_g; // Conductance +}; + +#endif diff --git a/src/electronics/simulation/ccvs.cpp b/src/electronics/simulation/ccvs.cpp new file mode 100644 index 0000000..fc12bf5 --- /dev/null +++ b/src/electronics/simulation/ccvs.cpp @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "elementset.h" +#include "matrix.h" +#include "ccvs.h" + +CCVS::CCVS( const double gain ) + : Element::Element() +{ + m_g = gain; + m_numCBranches = 2; + m_numCNodes = 4; +} + +CCVS::~CCVS() +{ +} + +void CCVS::setGain( const double g ) +{ + if ( m_g == g ) + return; + + if (p_eSet) + p_eSet->setCacheInvalidated(); + + m_g = g; + add_initial_dc(); +} + + +void CCVS::add_map() +{ + if (!b_status) return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse_b( p_cnode[0]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[0]->n(), Map::et_constant, true ); + } + if ( !p_cnode[1]->isGround ) + { + p_A->setUse_b( p_cnode[1]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[1]->n(), Map::et_constant, true ); + } + if ( !p_cnode[2]->isGround ) + { + p_A->setUse_b( p_cnode[2]->n(), p_cbranch[1]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[1]->n(), p_cnode[2]->n(), Map::et_constant, true ); + } + if ( !p_cnode[3]->isGround ) + { + p_A->setUse_b( p_cnode[3]->n(), p_cbranch[1]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[1]->n(), p_cnode[3]->n(), Map::et_constant, true ); + } + p_A->setUse_d( p_cbranch[1]->n(), p_cbranch[0]->n(), Map::et_stable, true ); +} + + +void CCVS::add_initial_dc() +{ + if (!b_status) return; + + A_b( 0, 0 ) = 1; + A_c( 0, 0 ) = 1; + A_b( 1, 0 ) = -1; + A_c( 0, 1 ) = -1; + A_b( 2, 1 ) = 1; + A_c( 1, 2 ) = 1; + A_b( 3, 1 ) = -1; + A_c( 1, 3 ) = -1; + A_d( 1, 0 ) = -m_g; +} + +void CCVS::updateCurrents() +{ + if (!b_status) return; + m_cnodeI[1] = p_cbranch[0]->i; + m_cnodeI[0] = -m_cnodeI[1]; + m_cnodeI[3] = p_cbranch[0]->i; + m_cnodeI[2] = -m_cnodeI[3]; +} + diff --git a/src/electronics/simulation/ccvs.h b/src/electronics/simulation/ccvs.h new file mode 100644 index 0000000..bcb1ac0 --- /dev/null +++ b/src/electronics/simulation/ccvs.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef CCVS_H +#define CCVS_H + +#include "element.h" + +/** +CNodes n0 and n1 are used for the current control. +CNodes n2 and n3 are used for the voltage output. +Branches b0 and b1 are for control and output +@short Current Controlled Voltage Source +@author David Saxton +*/ +class CCVS : public Element +{ +public: + CCVS( const double gain ); + virtual ~CCVS(); + + virtual Type type() const { return Element_CCVS; } + void setGain( const double g ); + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_g; // Conductance +}; + +#endif diff --git a/src/electronics/simulation/circuit.cpp b/src/electronics/simulation/circuit.cpp new file mode 100644 index 0000000..c152756 --- /dev/null +++ b/src/electronics/simulation/circuit.cpp @@ -0,0 +1,550 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include +#include "circuit.h" +#include "circuitdocument.h" +#include "element.h" +#include "elementset.h" +#include "logic.h" +#include "matrix.h" +#include "nonlinear.h" +#include "pin.h" +#include "reactive.h" +#include "wire.h" + + +#include +#include + +typedef std::multimap PinListMap; + +//BEGIN class Circuit +Circuit::Circuit() +{ + m_bCanAddChanged = true; + m_pNextChanged[0] = m_pNextChanged[1] = 0l; + m_logicOutCount = 0; + m_bCanCache = false; + m_pLogicOut = 0l; + m_elementSet = new ElementSet( this, 0, 0 ); + m_cnodeCount = m_branchCount = -1; + m_prepNLCount = 0; + m_pLogicCacheBase = new LogicCacheNode; +} + +Circuit::~Circuit() +{ + delete m_elementSet; + delete m_pLogicCacheBase; + delete[] m_pLogicOut; +} + + +void Circuit::addPin( Pin *node ) +{ + if ( m_pinList.contains(node) ) return; + m_pinList.append(node); +} + +void Circuit::addElement( Element *element ) +{ + if ( m_elementList.contains(element) ) return; + m_elementList.append(element); +} + +bool Circuit::contains( Pin *node ) +{ + return m_pinList.contains(node); +} + + +// static function +int Circuit::identifyGround( PinList nodeList, int *highest ) +{ + // What this function does: + // We are given a list of pins. First, we divide them into groups of pins + // that are directly connected to each other (e.g. through wires or + // switches). Then, each group of connected pins is looked at to find the + // pin with the highest "ground priority", and this is taken to be + // the priority of the group. The highest ground priority from all the + // groups is recorded. If the highest ground priority found is the maximum, + // then all the pins in groups with this priority are marked as ground + // (their eq-id is set to -1). Otherwise, the first group of pins with the + // highest ground priority found is marked as ground, and all others are + // marked as non ground (their eq-id is set to 0). + + int temp_highest; + if (!highest) + highest = &temp_highest; + + // Now to give all the Pins ids + PinListMap eqs; + while ( !nodeList.isEmpty() ) + { + PinList associated; + PinList nodes; + Pin *node = *nodeList.begin(); + recursivePinAdd( node, &nodeList, &associated, &nodes ); + if ( nodes.size() > 0 ) + { + eqs.insert( std::make_pair( associated.size(), nodes ) ); + } + } + + + // Now, we want to look through the associated Pins, + // to find the ones with the highest "Ground Priority". Anything with a lower + // priority than Pin::gt_never will not be considered + *highest = Pin::gt_never; // The highest priority found so far + int numGround = 0; // The number of node groups found with that priority + const PinListMap::iterator eqsEnd = eqs.end(); + for ( PinListMap::iterator it = eqs.begin(); it != eqsEnd; ++it ) + { + int highPri = Pin::gt_never; // The highest priority found in these group of nodes + const PinList::iterator send = it->second.end(); + for ( PinList::iterator sit = it->second.begin(); sit != send; ++sit ) + { + if ( (*sit)->groundType() < highPri ) + highPri = (*sit)->groundType(); + } + + if ( highPri == *highest ) + numGround++; + + else if ( highPri < *highest ) + { + numGround = 1; + *highest = highPri; + } + } + + if ( *highest == Pin::gt_never ) + { + (*highest)--; + numGround=0; + } + // If there are no Always Ground nodes, then we only want to set one of the nodes as ground + else if ( *highest > Pin::gt_always ) + numGround = 1; + + + // Now, we can give the nodes their cnode ids, or tell them they are ground + bool foundGround = false; // This is only used when we don't have a Always ground node + for ( PinListMap::iterator it = eqs.begin(); it != eqsEnd; ++it ) + { + bool ground = false; + const PinList::iterator send = it->second.end(); + for ( PinList::iterator sit = it->second.begin(); sit != send; ++sit ) + { + ground |= (*sit)->groundType() <= (*highest); + } + if ( ground && (!foundGround || *highest == Pin::gt_always ) ) + { + for ( PinList::iterator sit = it->second.begin(); sit != send; ++sit ) + { + (*sit)->setEqId(-1); + } + foundGround = true; + } + else + { + for ( PinList::iterator sit = it->second.begin(); sit != send; ++sit ) + { + (*sit)->setEqId(0); + } + } + } + + return numGround; +} + + +void Circuit::init() +{ + m_branchCount = 0; + + const ElementList::iterator listEnd = m_elementList.end(); + for ( ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it ) + { + m_branchCount += (*it)->numCBranches(); + } + + // Now to give all the Pins ids + int groundCount = 0; + PinListMap eqs; + PinList unassignedNodes = m_pinList; + while ( !unassignedNodes.isEmpty() ) + { + PinList associated; + PinList nodes; + Pin *node = *unassignedNodes.begin(); + if ( recursivePinAdd( node, &unassignedNodes, &associated, &nodes ) ) { + groundCount++; + } + if ( nodes.size() > 0 ) { + eqs.insert( std::make_pair( associated.size(), nodes ) ); + } + } + + m_cnodeCount = eqs.size() - groundCount; + + delete m_pLogicCacheBase; + m_pLogicCacheBase = 0l; + + delete m_elementSet; + m_elementSet = new ElementSet( this, m_cnodeCount, m_branchCount ); + + // Now, we can give the nodes their cnode ids, or tell them they are ground + Vector *x = m_elementSet->x(); + int i=0; + const PinListMap::iterator eqsEnd = eqs.end(); + for ( PinListMap::iterator it = eqs.begin(); it != eqsEnd; ++it ) + { + bool foundGround = false; + + const PinList::iterator sEnd = it->second.end(); + for ( PinList::iterator sit = it->second.begin(); sit != sEnd; ++sit ) + foundGround |= (*sit)->eqId() == -1; + + if ( foundGround ) + continue; + + bool foundEnergyStoragePin = false; + + for ( PinList::iterator sit = it->second.begin(); sit != sEnd; ++sit ) + { + (*sit)->setEqId(i); + + bool energyStorage = false; + const ElementList elements = (*sit)->elements(); + ElementList::const_iterator elementsEnd = elements.end(); + for ( ElementList::const_iterator it = elements.begin(); it != elementsEnd; ++it ) + { + if ( !*it ) + continue; + + if ( ((*it)->type() == Element::Element_Capacitance) + || ((*it)->type() == Element::Element_Inductance) ) + { + energyStorage = true; + break; + } + } + + // A pin attached to an energy storage pin overrides one that doesn't. + // If the two pins have equal status with in this regard, we pick the + // one with the highest absolute voltage on it. + + if ( foundEnergyStoragePin && !energyStorage ) + continue; + + double v = (*sit)->voltage(); + + if ( energyStorage && !foundEnergyStoragePin ) + { + foundEnergyStoragePin = true; + (*x)[i] = v; + continue; + } + + if ( std::abs(v) > std::abs( (*x)[i] ) ) + (*x)[i] = v; + } + i++; + } + + + // And add the elements to the elementSet + for ( ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it ) + { + // We don't want the element to prematurely try to do anything, + // as it doesn't know its actual cnode ids yet + (*it)->setCNodes(); + (*it)->setCBranches(); + m_elementSet->addElement(*it); + } + // And give the branch ids to the elements + i=0; + for ( ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it ) + { + switch ( (*it)->numCBranches() ) + { + case 0: + break; + case 1: + (*it)->setCBranches( i ); + i += 1; + break; + case 2: + (*it)->setCBranches( i, i+1 ); + i += 2; + break; + case 3: + (*it)->setCBranches( i, i+1, i+2 ); + i += 3; + break; + default: + // What the?! + break; + } + } +} + + +void Circuit::initCache() +{ + m_elementSet->updateInfo(); + + m_bCanCache = true; + m_logicOutCount = 0; + + delete[] m_pLogicOut; + m_pLogicOut = 0l; + + delete m_pLogicCacheBase; + m_pLogicCacheBase = 0l; + + const ElementList::iterator end = m_elementList.end(); + for ( ElementList::iterator it = m_elementList.begin(); it != end && m_bCanCache; ++it ) + { + switch ( (*it)->type() ) + { + case Element::Element_BJT: + case Element::Element_CCCS: + case Element::Element_CCVS: + case Element::Element_CurrentSource: + case Element::Element_Diode: + case Element::Element_LogicIn: + case Element::Element_OpAmp: + case Element::Element_Resistance: + case Element::Element_VCCS: + case Element::Element_VCVS: + case Element::Element_VoltagePoint: + case Element::Element_VoltageSource: + { + break; + } + + case Element::Element_LogicOut: + { + m_logicOutCount++; + break; + } + + case Element::Element_CurrentSignal: + case Element::Element_VoltageSignal: + case Element::Element_Capacitance: + case Element::Element_Inductance: + { + m_bCanCache = false; + break; + } + } + } + + if ( !m_bCanCache ) + return; + + m_pLogicOut = new LogicOut*[m_logicOutCount]; + unsigned i = 0; + for ( ElementList::iterator it = m_elementList.begin(); it != end && m_bCanCache; ++it ) + { + if ( (*it)->type() == Element::Element_LogicOut ) + m_pLogicOut[i++] = static_cast(*it); + } + + m_pLogicCacheBase = new LogicCacheNode; +} + + +void Circuit::setCacheInvalidated() +{ + if (m_pLogicCacheBase) + { + delete m_pLogicCacheBase->high; + m_pLogicCacheBase->high = 0l; + + delete m_pLogicCacheBase->low; + m_pLogicCacheBase->low = 0l; + + delete m_pLogicCacheBase->data; + m_pLogicCacheBase->data = 0l; + } +} + + +void Circuit::cacheAndUpdate() +{ + LogicCacheNode * node = m_pLogicCacheBase; + for ( unsigned i = 0; i < m_logicOutCount; i++ ) + { + if ( m_pLogicOut[i]->outputState() ) + { + if (!node->high) + node->high = new LogicCacheNode; + + node = node->high; + } + else + { + if (!node->low) + node->low = new LogicCacheNode; + + node = node->low; + } + } + + if ( node->data ) + { + (*m_elementSet->x()) = *node->data; + m_elementSet->updateInfo(); + return; + } + + if ( m_elementSet->containsNonLinear() ) + m_elementSet->doNonLinear( 150, 1e-10, 1e-13 ); + else + m_elementSet->doLinear(true); + + node->data = new Vector( m_elementSet->x()->size() ); + *node->data = *m_elementSet->x(); +} + + +void Circuit::createMatrixMap() +{ + m_elementSet->createMatrixMap(); +} + + +bool Circuit::recursivePinAdd( Pin *node, PinList *unassignedNodes, PinList *associated, PinList *nodes ) +{ + if ( !unassignedNodes->contains(node) ) + return false; + unassignedNodes->remove(node); + + bool foundGround = node->eqId() == -1; + + const PinList circuitDependentPins = node->circuitDependentPins(); + const PinList::const_iterator dEnd = circuitDependentPins.end(); + for ( PinList::const_iterator it = circuitDependentPins.begin(); it != dEnd; ++it ) + { + if ( !associated->contains(*it) ) + associated->append(*it); + } + + nodes->append(node); + + const PinList localConnectedPins = node->localConnectedPins(); + const PinList::const_iterator end = localConnectedPins.end(); + for ( PinList::const_iterator it = localConnectedPins.begin(); it != end; ++it ) + foundGround |= recursivePinAdd( *it, unassignedNodes, associated, nodes ); + + return foundGround; +} + + +void Circuit::doNonLogic() +{ + if ( !m_elementSet || m_cnodeCount+m_branchCount <= 0 ) + return; + + if (m_bCanCache) + { + if ( !m_elementSet->b()->isChanged() && !m_elementSet->matrix()->isChanged() ) + return; + cacheAndUpdate(); + updateNodalVoltages(); + m_elementSet->b()->setUnchanged(); + return; + } + + stepReactive(); + if ( m_elementSet->containsNonLinear() ) + { + m_elementSet->doNonLinear( 10, 1e-9, 1e-12 ); + updateNodalVoltages(); + } + else + { + if ( m_elementSet->doLinear(true) ) + updateNodalVoltages(); + } +} + + +void Circuit::stepReactive() +{ + ElementList::iterator listEnd = m_elementList.end(); + for ( ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it ) + { + Element * const e = *it; + if ( e && e->isReactive() ) + (static_cast(e))->time_step(); + } +} + + +void Circuit::updateNodalVoltages() +{ + CNode **_cnodes = m_elementSet->cnodes(); + + const PinList::iterator endIt = m_pinList.end(); + for ( PinList::iterator it = m_pinList.begin(); it != endIt; ++it ) + { + Pin * const node = *it; + int i = node->eqId(); + if ( i == -1 ) + node->setVoltage(0.); + else + { + const double v = _cnodes[i]->v; + node->setVoltage( std::isfinite(v)?v:0. ); + } + } +} + + +void Circuit::updateCurrents() +{ + ElementList::iterator listEnd = m_elementList.end(); + for ( ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it ) + { + (*it)->updateCurrents(); + } +} + +void Circuit::displayEquations() +{ + m_elementSet->displayEquations(); +} +//END class Circuit + + + +//BEGIN class LogicCacheNode +LogicCacheNode::LogicCacheNode() +{ + low = 0l; + high = 0l; + data = 0l; +} + + +LogicCacheNode::~LogicCacheNode() +{ + delete low; + delete high; + delete data; +} +//END class LogicCacheNode + + diff --git a/src/electronics/simulation/circuit.h b/src/electronics/simulation/circuit.h new file mode 100644 index 0000000..2455edc --- /dev/null +++ b/src/electronics/simulation/circuit.h @@ -0,0 +1,137 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef CIRCUIT_H +#define CIRCUIT_H + +#include +#include "qstringlist.h" +#include "qvaluelist.h" + +#include "elementset.h" + +class CircuitDocument; +class Wire; +class Pin; +class Element; +class LogicOut; + +typedef QValueList > PinList; +typedef QValueList ElementList; + + +class LogicCacheNode +{ + public: + LogicCacheNode(); + ~LogicCacheNode(); + + LogicCacheNode * high; + LogicCacheNode * low; + Vector * data; +}; + + +/** +Usage of this class (usually invoked from CircuitDocument): +(1) Add Wires, Pins and Elements to the class as appropriate +(2) Call init to initialize the simulation +(3) Control the simulation with step() + +This class can be considered a bridge between the gui-tainted CircuitDocument - specific +to this implementation, and the pure untainted ElementSet. Please keep it that way. + +@short Simulates a collection of components +@author David Saxton +*/ +class Circuit +{ + public: + Circuit(); + ~Circuit(); + + void addPin( Pin *node ); + void addElement( Element *element ); + + bool contains( Pin *node ); + bool containsNonLinear() const { return m_elementSet->containsNonLinear(); } + + void init(); + /** + * Called after everything else has been setup - before doNonLogic or + * doLogic are called for the first time. Preps the circuit. + */ + void initCache(); + /** + * Marks all cached results as invalidated and removes them. + */ + void setCacheInvalidated(); + /** + * Solves for non-logic elements + */ + void doNonLogic(); + /** + * Solves for logic elements (i.e just does fbSub) + */ + void doLogic() { m_elementSet->doLinear(false); } + + void displayEquations(); + void updateCurrents(); + + void createMatrixMap(); + /** + * This will identify the ground node and non-ground nodes in the given set. + * Ground will be given the eqId -1, non-ground of 0. + * @param highest The highest ground type of the groundnodes found. If no + ground nodes were found, this will be (gt_never-1). + * @returns the number of ground nodes. If all nodes are at or below the + * gt_never threshold, then this will be zero. + */ + static int identifyGround( PinList nodeList, int *highest = 0l ); + + void setNextChanged( Circuit * circuit, unsigned char chain ) { m_pNextChanged[chain] = circuit; } + Circuit * nextChanged( unsigned char chain ) const { return m_pNextChanged[chain]; } + void setCanAddChanged( bool canAdd ) { m_bCanAddChanged = canAdd; } + bool canAddChanged() const { return m_bCanAddChanged; } + + protected: + void cacheAndUpdate(); + /** + * Update the nodal voltages from those calculated in ElementSet + */ + void updateNodalVoltages(); + /** + * Step the reactive elements. + */ + void stepReactive(); + /** + * Returns true if any of the nodes are ground + */ + static bool recursivePinAdd( Pin *node, PinList *unassignedNodes, PinList *associated, PinList *nodes ); + + int m_cnodeCount; + int m_branchCount; + int m_prepNLCount; // Count until next m_elementSet->prepareNonLinear() is called + + PinList m_pinList; + ElementList m_elementList; + ElementSet *m_elementSet; + + //Stuff for caching + bool m_bCanCache; + LogicCacheNode * m_pLogicCacheBase; + unsigned m_logicOutCount; + LogicOut ** m_pLogicOut; + + bool m_bCanAddChanged; + Circuit * m_pNextChanged[2]; +}; + +#endif diff --git a/src/electronics/simulation/currentsignal.cpp b/src/electronics/simulation/currentsignal.cpp new file mode 100644 index 0000000..5e5388d --- /dev/null +++ b/src/electronics/simulation/currentsignal.cpp @@ -0,0 +1,67 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "currentsignal.h" +#include "element.h" +#include "matrix.h" + +CurrentSignal::CurrentSignal( const double delta, const double current ) + : Reactive::Reactive(delta) +{ + m_current = current; + m_oldCurrent = m_newCurrent = 0.; + m_numCNodes = 2; +} + +CurrentSignal::~CurrentSignal() +{ +} + +void CurrentSignal::setCurrent( const double i ) +{ + if ( m_oldCurrent != m_newCurrent ) add_initial_dc(); + m_newCurrent *= i/m_current; // Instead of calling step again, we can just "adjust" what the current should be + m_current = i; + add_initial_dc(); +} + + +void CurrentSignal::add_map() +{ + // We don't need a map for current signal :-) +} + + +void CurrentSignal::add_initial_dc() +{ + if ( !b_status ) + return; + + if ( m_newCurrent == m_oldCurrent ) + return; + + b_i( 0 ) -= m_newCurrent-m_oldCurrent; + b_i( 1 ) += m_newCurrent-m_oldCurrent; + + m_oldCurrent = m_newCurrent; +} + +void CurrentSignal::updateCurrents() +{ + m_cnodeI[1] = m_newCurrent; + m_cnodeI[0] = -m_newCurrent; +} + +void CurrentSignal::time_step() +{ + add_initial_dc(); // Make sure our old and new are synced + m_newCurrent = m_current*advance(); + add_initial_dc(); +} diff --git a/src/electronics/simulation/currentsignal.h b/src/electronics/simulation/currentsignal.h new file mode 100644 index 0000000..b217b79 --- /dev/null +++ b/src/electronics/simulation/currentsignal.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef CURRENTSIGNAL_H +#define CURRENTSIGNAL_H + +#include "reactive.h" +#include "elementsignal.h" + +/** +@short CurrentSignal +@author David saxton +*/ +class CurrentSignal : public Reactive, public ElementSignal +{ +public: + CurrentSignal( const double delta, const double current ); + virtual ~CurrentSignal(); + + virtual Element::Type type() const { return Element_CurrentSignal; } + void setCurrent( const double current ); + double current() { return m_current; } + virtual void time_step(); + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_current; // Current + double m_oldCurrent; // Old calculated current + double m_newCurrent; // New calculated current +}; + +#endif diff --git a/src/electronics/simulation/currentsource.cpp b/src/electronics/simulation/currentsource.cpp new file mode 100644 index 0000000..675b0b7 --- /dev/null +++ b/src/electronics/simulation/currentsource.cpp @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "currentsource.h" +#include "elementset.h" +#include "matrix.h" + +CurrentSource::CurrentSource( const double current ) + : Element::Element() +{ + m_i = current; + m_numCNodes = 2; +} + + +CurrentSource::~CurrentSource() +{ +} + + +void CurrentSource::setCurrent( const double i ) +{ + if ( i == m_i ) return; + + if (p_eSet) + p_eSet->setCacheInvalidated(); + + // Remove the old current + m_i = -m_i; + add_initial_dc(); + + m_i = i; + add_initial_dc(); +} + + +void CurrentSource::add_map() +{ + // We don't need a map for current source :-) +} + + +void CurrentSource::add_initial_dc() +{ + if (!b_status) + return; + + b_i( 0 ) -= m_i; + b_i( 1 ) += m_i; +} + + +void CurrentSource::updateCurrents() +{ + m_cnodeI[0] = -m_i; + m_cnodeI[1] = m_i; +} diff --git a/src/electronics/simulation/currentsource.h b/src/electronics/simulation/currentsource.h new file mode 100644 index 0000000..9b72e0d --- /dev/null +++ b/src/electronics/simulation/currentsource.h @@ -0,0 +1,39 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef CURRENTSOURCE_H +#define CURRENTSOURCE_H + +#include "element.h" + +/** +cnode n0 has current flowing otu of it, cnode n1 has current flowing into it +@author David Saxton +@short Current Source +*/ +class CurrentSource : public Element +{ +public: + CurrentSource( const double current ); + virtual ~CurrentSource(); + + virtual Type type() const { return Element_CurrentSource; } + void setCurrent( const double i ); + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_i; // Current +}; + +#endif diff --git a/src/electronics/simulation/diode.cpp b/src/electronics/simulation/diode.cpp new file mode 100644 index 0000000..e13d478 --- /dev/null +++ b/src/electronics/simulation/diode.cpp @@ -0,0 +1,198 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include +#include "diode.h" +#include "elementset.h" +#include "matrix.h" + +#include + + +//BEGIN class Diode Settings +DiodeSettings::DiodeSettings() +{ + reset(); +} + + +void DiodeSettings::reset() +{ + I_S = 1e-15; + N = 1.0; + V_B = 4.7; +// R = 0.001; +} +//END class Diode Settings + + + +//BEGIN class Diode +Diode::Diode() + : NonLinear() +{ + m_numCNodes = 2; + g_new = g_old = I_new = I_old = V_prev = 0.0; +} + + +Diode::~Diode() +{ +} + + +void Diode::add_map() +{ + if (!b_status) + return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse( p_cnode[0]->n(), p_cnode[0]->n(), Map::et_unstable, false ); + } + if ( !p_cnode[1]->isGround ) + { + p_A->setUse( p_cnode[1]->n(), p_cnode[1]->n(), Map::et_unstable, false ); + } + + if ( !p_cnode[0]->isGround && !p_cnode[1]->isGround ) + { + p_A->setUse( p_cnode[0]->n(), p_cnode[1]->n(), Map::et_unstable, false ); + p_A->setUse( p_cnode[1]->n(), p_cnode[0]->n(), Map::et_unstable, false ); + } +} + + +void Diode::add_initial_dc() +{ + g_new = g_old = I_new = I_old = V_prev = 0.0; + update_dc(); +} + + +double Diode::current() const +{ + if (!b_status) + return 0.0; + + double I; + calcIg( p_cnode[0]->v - p_cnode[1]->v, & I, 0 ); + + return I; +} + + +void Diode::updateCurrents() +{ + if (!b_status) + return; + + m_cnodeI[1] = current(); + m_cnodeI[0] = -m_cnodeI[1]; +} + + +void Diode::update_dc() +{ + if (!b_status) + return; + + calc_eq(); + + A_g( 0, 0 ) += g_new - g_old; + A_g( 1, 1 ) += g_new - g_old; + A_g( 0, 1 ) -= g_new - g_old; + A_g( 1, 0 ) -= g_new - g_old; + + b_i( 0 ) -= I_new - I_old; + b_i( 1 ) += I_new - I_old; + + g_old = g_new; + I_old = I_new; +} + + + +#ifndef MIN +# define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#endif + + + +void Diode::calc_eq() +{ + double I_S = m_diodeSettings.I_S; + double N = m_diodeSettings.N; + double V_B = m_diodeSettings.V_B; +// double R = m_diodeSettings.R; + + double v = p_cnode[0]->v - p_cnode[1]->v; + + // adjust voltage to help convergence + double V_crit = diodeCriticalVoltage( I_S, N * V_T ); + if (V_B != 0 && v < MIN (0, -V_B + 10 * N * V_T)) + { + double V = -(v + V_B); + V = diodeVoltage( V, -(V_prev + V_B), V_T * N, V_crit ); + v = -(V + V_B); + } + else + v = diodeVoltage( v, V_prev, V_T * N, V_crit ); + + V_prev = v; + + double I_D; + calcIg( v, & I_D, & g_new ); + + I_new = I_D - (v * g_new); +} + + +void Diode::calcIg( double V, double * I_D, double * g ) const +{ + double I_S = m_diodeSettings.I_S; + double N = m_diodeSettings.N; + double V_B = m_diodeSettings.V_B; +// double R = m_diodeSettings.R; + + double gtiny = (V < - 10 * V_T * N && V_B != 0) ? I_S : 0; + + if ( V >= (-3 * N * V_T) ) + { + if ( g ) + *g = diodeConductance( V, I_S, V_T * N ) + gtiny; + *I_D = diodeCurrent( V, I_S, V_T * N ) + (gtiny * V); + } + else if ( V_B == 0 || V >= -V_B ) + { + double a = (3 * N * V_T) / (V * M_E); + a = a * a * a; + *I_D = (-I_S * (1 + a)) + (gtiny * V); + if ( g ) + *g = ((I_S * 3 * a) / V) + gtiny; + } + else + { + double a = exp( -(V_B + V) / N / V_T ); + *I_D = (-I_S * a) + (gtiny * V); + if ( g ) + *g = I_S * a / V_T / N + gtiny; + } +} + + +void Diode::setDiodeSettings( const DiodeSettings & settings ) +{ + m_diodeSettings = settings; + if (p_eSet) + p_eSet->setCacheInvalidated(); +} +//END class Diode + diff --git a/src/electronics/simulation/diode.h b/src/electronics/simulation/diode.h new file mode 100644 index 0000000..0b13946 --- /dev/null +++ b/src/electronics/simulation/diode.h @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef DIODE_H +#define DIODE_H + +#include "nonlinear.h" + +class DiodeSettings +{ + public: + DiodeSettings(); + void reset(); + + double I_S; ///< Diode saturation current + double N; ///< Emission coefficient + double V_B; ///< Reverse breakdown +// double R; ///< Series resistance +}; + + +/** +This simulates a diode. The simulated diode characteristics are: + +@li I_s: Diode saturation current +@li V_T: Thermal voltage = kT/4 = 25mV at 20 C +@li n: Emission coefficient, typically between 1 and 2 +@li V_RB: Reverse breakdown (large negative voltage) +@li G_RB: Reverse breakdown conductance +@li R_D: Base resistance of diode + +@short Simulates the electrical property of diode-ness +@author David Saxton +*/ +class Diode : public NonLinear +{ + public: + Diode(); + virtual ~Diode(); + + virtual void update_dc(); + virtual void add_initial_dc(); + virtual void add_map(); + virtual Element::Type type() const { return Element_Diode; } + DiodeSettings settings() const { return m_diodeSettings; } + void setDiodeSettings( const DiodeSettings & settings ); + /** + * Returns the current flowing through the diode + */ + double current() const; + + protected: + virtual void updateCurrents(); + void calc_eq(); + + void calcIg( double V, double * I, double * g ) const; + + double g_new, g_old; + double I_new, I_old; + double V_prev; + + DiodeSettings m_diodeSettings; +}; + +#endif + diff --git a/src/electronics/simulation/element.cpp b/src/electronics/simulation/element.cpp new file mode 100644 index 0000000..2411897 --- /dev/null +++ b/src/electronics/simulation/element.cpp @@ -0,0 +1,193 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "element.h" +#include "elementset.h" + +#include + +#include + +Element::Element() +{ + b_status = false; + p_A = 0l; + p_eSet = 0l; + p_b = 0l; + b_componentDeleted = false; + b_eSetDeleted = true; + + for ( int i=0; i<8; i++ ) + p_cnode[i] = 0l; + + resetCurrents(); + + for ( int i=0; i<4; i++ ) + p_cbranch[i] = 0l; + + m_numCBranches = 0; + m_numCNodes = 0; +} + +Element::~ Element() +{ +} + +void Element::resetCurrents() +{ + for ( int i=0; i<8; i++ ) + m_cnodeI[i] = 0.0; +} + +void Element::setElementSet( ElementSet *c ) +{ + assert(!b_componentDeleted); + assert(!p_eSet); + if (!c) return elementSetDeleted(); + b_eSetDeleted = false; + p_eSet = c; + p_A = p_eSet->matrix(); + p_b = p_eSet->b(); + updateStatus(); +} + +void Element::componentDeleted() +{ +// assert(!b_componentDeleted); + if (b_componentDeleted) + { + // Something strange happened here.... + } + if (b_eSetDeleted) return delete this; + b_componentDeleted = true; + b_status = false; +// kdDebug() << "Element::componentDeleted(): Setting b_status to false, this="<-1)?p_eSet->cnodes()[n0]:(n0==-1?p_eSet->ground():0l); + p_cnode[1] = (n1>-1)?p_eSet->cnodes()[n1]:(n1==-1?p_eSet->ground():0l); + p_cnode[2] = (n2>-1)?p_eSet->cnodes()[n2]:(n2==-1?p_eSet->ground():0l); + p_cnode[3] = (n3>-1)?p_eSet->cnodes()[n3]:(n3==-1?p_eSet->ground():0l); + updateStatus(); +} + +void Element::setCBranches( const int b0, const int b1, const int b2, const int b3 ) +{ + if ( !p_eSet ) + { +// cerr << "Element::setCBranches: can't set branches without circuit!"<-1)?p_eSet->cbranches()[b0]:0l; + p_cbranch[1] = (b1>-1)?p_eSet->cbranches()[b1]:0l; + p_cbranch[2] = (b2>-1)?p_eSet->cbranches()[b2]:0l; + p_cbranch[3] = (b3>-1)?p_eSet->cbranches()[b3]:0l; + updateStatus(); +} + +bool Element::updateStatus() +{ + // First, set status to false if all nodes in use are ground + b_status = false; + for ( int i=0; iisGround:false; + } + + // Set status to false if any of the nodes are not set + for ( int i=0; iisGround || p_cnode[j]->isGround ) + return m_temp; + return p_A->g( p_cnode[i]->n(), p_cnode[j]->n() ); +} + + +double & Element::A_b( uint i, uint j ) +{ + if ( p_cnode[i]->isGround ) + return m_temp; + return p_A->b( p_cnode[i]->n(), p_cbranch[j]->n() ); +} + + +double & Element::A_c( uint i, uint j ) +{ + if ( p_cnode[j]->isGround ) + return m_temp; + return p_A->c( p_cbranch[i]->n(), p_cnode[j]->n() ); +} + + +double & Element::A_d( uint i, uint j ) +{ + return p_A->d( p_cbranch[i]->n(), p_cbranch[j]->n() ); +} + + + +double & Element::b_i( uint i ) +{ + if ( p_cnode[i]->isGround ) + return m_temp; + + return (*p_b)[ p_cnode[i]->n() ]; +} + + +double & Element::b_v( uint i ) +{ + return (*p_b)[ p_eSet->cnodeCount() + p_cbranch[i]->n() ]; +} + +#endif diff --git a/src/electronics/simulation/elementset.cpp b/src/electronics/simulation/elementset.cpp new file mode 100644 index 0000000..25057c2 --- /dev/null +++ b/src/electronics/simulation/elementset.cpp @@ -0,0 +1,253 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "bjt.h" +#include "circuit.h" +#include "elementset.h" +#include "element.h" +#include "logic.h" +#include "matrix.h" +#include "nonlinear.h" +#include "vec.h" + +#include + +#include +#include +#include + +ElementSet::ElementSet( Circuit * circuit, const int n, const int m ) +{ + m_pCircuit = circuit; + m_cn = n; + m_cb = m; + p_logicIn = 0l; + p_A = new Matrix( m_cn, m_cb ); + p_b = new Vector(m_cn+m_cb); + p_x = new Vector(m_cn+m_cb); + p_x_prev = new Vector(m_cn+m_cb); + m_cbranches = new CBranch*[m_cb]; + m_cnodes = new CNode*[m_cn]; + for ( uint i=0; iset_n(i); + } + for ( uint i=0; iset_n(i); + } + m_ground = new CNode(); + m_ground->isGround = true; + b_containsNonLinear = false; +} + +ElementSet::~ElementSet() +{ + const ElementList::iterator end = m_elementList.end(); + for ( ElementList::iterator it = m_elementList.begin(); it != end; ++it ) + { + // Note: By calling setElementSet(0l), we might have deleted it (the Element will commit + // suicide when both the the ElementSet and Component to which it belongs have deleted + // themselves). So be very careful it you plan to do anything with the (*it) pointer + if (*it) (*it)->elementSetDeleted(); + } + for ( uint i=0; isetCacheInvalidated(); +} + + +void ElementSet::addElement( Element *e ) +{ + if ( !e || m_elementList.contains(e) ) return; + e->setElementSet(this); + m_elementList.append(e); + if ( e->isNonLinear() ) + { + b_containsNonLinear = true; + m_cnonLinearList.append( static_cast(e) ); + } +} + + +void ElementSet::createMatrixMap() +{ + p_A->createMap(); + + + // And do our logic as well... + + m_clogic = 0; + ElementList::iterator end = m_elementList.end(); + for ( ElementList::iterator it = m_elementList.begin(); it != end; ++it ) + { + if ( dynamic_cast(*it) ) + m_clogic++; + } + + p_logicIn = new LogicIn*[m_clogic]; + int i=0; + for ( ElementList::iterator it = m_elementList.begin(); it != end; ++it ) + { + if ( LogicIn * in = dynamic_cast(*it) ) + p_logicIn[i++] = in; + } +} + + +void ElementSet::doNonLinear( int maxIterations, double maxErrorV, double maxErrorI ) +{ +// p_x_prev->reset(); + + // And now tell the cnodes and cbranches about their new voltages & currents + updateInfo(); + + const NonLinearList::iterator end = m_cnonLinearList.end(); + + int k = 0; + do + { + // Tell the nonlinear elements to update its J, A and b from the newly calculated x + for ( NonLinearList::iterator it = m_cnonLinearList.begin(); it != end; ++it ) + (*it)->update_dc(); + + *p_x = *p_b; + p_A->performLU(); + p_A->fbSub(p_x); + updateInfo(); + + // Now, check for convergence + bool converged = true; + for ( unsigned i = 0; i < m_cn; ++i ) + { + double diff = std::abs( (*p_x_prev)[i] - (*p_x)[i] ); + if ( diff > maxErrorI ) + { + converged = false; + break; + } + } + if ( converged ) + { + for ( unsigned i = m_cn; i < m_cn+m_cb; ++i ) + { + double diff = std::abs( (*p_x_prev)[i] - (*p_x)[i] ); + if ( diff > maxErrorV ) + { + converged = false; + break; + } + } + } + + *p_x_prev = *p_x; + + if ( converged ) + break; + } + while ( ++k < maxIterations ); +} + + +bool ElementSet::doLinear( bool performLU ) +{ + if ( b_containsNonLinear || (!p_b->isChanged() && ((performLU && !p_A->isChanged()) || !performLU)) ) + return false; + + if (performLU) + p_A->performLU(); + + *p_x = *p_b; + p_A->fbSub(p_x); + updateInfo(); + p_b->setUnchanged(); + + return true; +} + + +void ElementSet::updateInfo() +{ + for ( uint i=0; iv = v; + } else { + (*p_x)[i] = 0.; + m_cnodes[i]->v = 0.; + } + } + for ( uint i=0; ii = I; + } else { + (*p_x)[i+m_cn] = 0.; + m_cbranches[i]->i = 0.; + } + } + + // Tell logic to check themselves + for ( uint i=0; icheck(); + } +} + + +void ElementSet::displayEquations() +{ + std::cout.setf(std::ios_base::fixed); + std::cout.precision(5); + std::cout.setf(std::ios_base::showpoint); + std::cout << "A x = b :"<g(i,j); +// if ( value > 0 ) cout <<"+"; +// else if ( value == 0 ) cout <<" "; + std::cout.width(10); + std::cout << value<<" "; + } + std::cout << ") ( "<<(*p_x)[i]<<" ) = ( "; + std::cout<<(*p_b)[i]<<" )"<displayLU(); +} + + diff --git a/src/electronics/simulation/elementset.h b/src/electronics/simulation/elementset.h new file mode 100644 index 0000000..c7ef7ca --- /dev/null +++ b/src/electronics/simulation/elementset.h @@ -0,0 +1,131 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ELEMENTSET_H +#define ELEMENTSET_H + +#include + +#include + +class CBranch; +class Circuit; +class CNode; +class Element; +class ElementSet; +class LogicIn; +class Matrix; +class NonLinear; +class Vector; + +typedef QValueList ElementList; +typedef QValueList NonLinearList; + +/** +Steps in simulation of a set of elements: +(1) Create this class with given number of nodes "n" and voltage sources "m" +(2) Add the various elements with addElement. +(3) Call performDC() +(4) Get the nodal voltages and voltage currents with x() +(5) Repeat steps 3 and 4 if necessary for further transient analysis. + +This class shouldn't be confused with the Circuit class, but considered a helper class to Circuit. +Circuit will handle the simulation of a set of components over time. This just finds the DC-operating +point of the circuit for a given set of elements. + +@short Handles a set of circuit elements +@author David Saxton +*/ +class ElementSet +{ +public: + /** + * Create a new circuit, with "n" nodes and "m" voltage sources. + * After creating the circuit, you must call setGround to specify + * the ground nodes, before adding any elements. + */ + ElementSet( Circuit * circuit, const int n, const int m ); + /** + * Destructor. Note that only the matrix and supporting data is deleted. + * i.e. Any elements added to the circuit will not be deleted. + */ + ~ElementSet(); + Circuit * circuit() const { return m_pCircuit; } + void addElement( Element *e ); + void setCacheInvalidated(); + /** + * Returns the matrix in use. This is created once on the creation of the ElementSet + * class, and deleted in the destructor, so the pointer returned will never change. + */ + Matrix *matrix() const { return p_A; } + /** + * Returns the vector for b (i.e. the independent currents & voltages) + */ + Vector *b() const { return p_b; } + /** + * Returns the vector for x (i.e. the currents & voltages at the branches and nodes) + */ + Vector *x() const { return p_x; } + /** + * @return if we have any nonlinear elements (e.g. diodes, tranaistors). + */ + bool containsNonLinear() const { return b_containsNonLinear; } + /** + * Solves for nonlinear elements, or just does linear if it doesn't contain + * any nonlinear. + */ + void doNonLinear( int maxIterations, double maxErrorV = 1e-9, double maxErrorI = 1e-12 ); + /** + * Solves for linear and logic elements. + * @returns true if anything changed + */ + bool doLinear( bool performLU ); + CBranch **cbranches() const { return m_cbranches; } + CNode **cnodes() const { return m_cnodes; } + CNode *ground() const { return m_ground; } + /** + * Returns the number of nodes in the circuit (excluding ground 'nodes') + */ + int cnodeCount() const { return m_cn; } + /** + * Returns the number of voltage sources in the circuit + */ + int cbranchCount() const { return m_cb; } + + void createMatrixMap(); + /** + * Displays the matrix equations Ax=b and J(dx)=-r + */ + void displayEquations(); + /** + * Update the nodal voltages and branch currents from the x vector + */ + void updateInfo(); + +private: + Matrix *p_A; + Vector *p_x; + Vector *p_x_prev; + Vector *p_b; + uint m_cn; + uint m_cb; + ElementList m_elementList; + NonLinearList m_cnonLinearList; + CBranch **m_cbranches; // Pointer to an array of cbranches + CNode **m_cnodes; // Pointer to an array of cnodes + CNode *m_ground; + uint m_clogic; + LogicIn **p_logicIn; + bool b_containsNonLinear; + Circuit * m_pCircuit; +}; + +#endif + diff --git a/src/electronics/simulation/elementsignal.cpp b/src/electronics/simulation/elementsignal.cpp new file mode 100644 index 0000000..31d7d78 --- /dev/null +++ b/src/electronics/simulation/elementsignal.cpp @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "elementsignal.h" +#include + +ElementSignal::ElementSignal() +{ + m_type = ElementSignal::st_sinusoidal; + m_time = 0.; + m_frequency = 0.; +} + +ElementSignal::~ElementSignal() +{ +} + +void ElementSignal::setStep( double delta, Type type, double frequency ) +{ + m_type = type; + m_delta = delta; + m_frequency = frequency; + m_omega = 6.283185307179586*m_frequency; + m_time = 1./(4.*m_frequency); +} + +double ElementSignal::advance() +{ + m_time += m_delta; + if ( m_time >= 1./m_frequency ) m_time -= 1./m_frequency; + + switch (m_type) + { + case ElementSignal::st_sawtooth: + { + // TODO Sawtooth signal + return 0.; + } + case ElementSignal::st_square: + { + return (sin(m_time*m_omega)>=0)?1:-1; + } + case ElementSignal::st_triangular: + { + // TODO Triangular signal + return 0.; + } + case ElementSignal::st_sinusoidal: + default: + { + return sin(m_time*m_omega); + } + } +} + + + diff --git a/src/electronics/simulation/elementsignal.h b/src/electronics/simulation/elementsignal.h new file mode 100644 index 0000000..c26bea1 --- /dev/null +++ b/src/electronics/simulation/elementsignal.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ELEMENTSIGNAL_H +#define ELEMENTSIGNAL_H + +/** +@short Provides different signals +@author David Saxton +*/ +class ElementSignal +{ +public: + enum Type + { + st_sinusoidal, + st_square, + st_sawtooth, + st_triangular + }; + ElementSignal(); + ~ElementSignal(); + + void setStep( double delta, Type type, double frequency ); + /** + * Advances the timer, returns amplitude (between -1 and 1) + */ + double advance(); + +protected: + Type m_type; + double m_time; + double m_frequency; + double m_delta; + double m_omega; // Used for sinusoidal signal +}; + +#endif diff --git a/src/electronics/simulation/inductance.cpp b/src/electronics/simulation/inductance.cpp new file mode 100644 index 0000000..22c5f9e --- /dev/null +++ b/src/electronics/simulation/inductance.cpp @@ -0,0 +1,126 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "elementset.h" +#include "inductance.h" +#include "matrix.h" + +Inductance::Inductance( double inductance, double delta ) + : Reactive(delta) +{ + m_inductance = inductance; + r_eq_old = v_eq_old = 0.0; + m_numCNodes = 2; + m_numCBranches = 1; + setMethod( Inductance::m_euler ); +} + + +Inductance::~Inductance() +{ +} + + +void Inductance::setInductance( double i ) +{ + m_inductance = i; +} + + +void Inductance::add_initial_dc() +{ + A_c( 0, 0 ) = 1; + A_b( 0, 0 ) = 1; + A_c( 0, 1 ) = -1; + A_b( 1, 0 ) = -1; + + // The adding of r_eg and v_eq will be done for us by time_step. + // So for now, just reset the constants used. + r_eq_old = v_eq_old = 0.0; +} + + +void Inductance::updateCurrents() +{ + if (!b_status) + return; + m_cnodeI[0] = p_cbranch[0]->i; + m_cnodeI[1] = -m_cnodeI[0]; +} + + +void Inductance::add_map() +{ + if (!b_status) + return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[0]->n(), Map::et_constant, true ); + p_A->setUse_b( p_cnode[0]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + } + + if ( !p_cnode[1]->isGround ) + { + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[1]->n(), Map::et_constant, true ); + p_A->setUse_b( p_cnode[1]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + } + + p_A->setUse_d( p_cbranch[0]->n(), p_cbranch[0]->n(), Map::et_unstable, false ); +} + + +void Inductance::time_step() +{ + if (!b_status) return; + + double i = p_cbranch[0]->i; + double v_eq_new = 0.0, r_eq_new = 0.0; + + if ( m_method == Inductance::m_euler ) + { + r_eq_new = m_inductance/m_delta; + v_eq_new = -i*r_eq_new; + } + else if ( m_method == Inductance::m_trap ) { + // TODO Implement + test trapezoidal method + r_eq_new = 2.0*m_inductance/m_delta; + } + + if ( r_eq_old != r_eq_new ) + { + A_d( 0, 0 ) -= r_eq_new - r_eq_old; + } + + if ( v_eq_new != v_eq_old ) + { + b_v( 0 ) += v_eq_new - v_eq_old; + } + + r_eq_old = r_eq_new; + v_eq_old = v_eq_new; +} + + +bool Inductance::updateStatus() +{ + b_status = Reactive::updateStatus(); + if ( m_method == Inductance::m_none ) + b_status = false; + return b_status; +} + + +void Inductance::setMethod( Method m ) +{ + m_method = m; + updateStatus(); +} + diff --git a/src/electronics/simulation/inductance.h b/src/electronics/simulation/inductance.h new file mode 100644 index 0000000..46ccb09 --- /dev/null +++ b/src/electronics/simulation/inductance.h @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef INDUCTANCE_H +#define INDUCTANCE_H + +#include "reactive.h" + +/** + +@author David Saxton +*/ +class Inductance : public Reactive +{ + public: + enum Method + { + m_none, // None + m_euler, // Backward Euler + m_trap // Trapezoidal (currently unimplemented) + }; + Inductance( double capacitance, double delta ); + virtual ~Inductance(); + + virtual Type type() const { return Element_Inductance; } + /** + * Set the stepping use for numerical integration of inductance, and the + * interval between successive updates. + */ + void setMethod( Method m ); + virtual void time_step(); + virtual void add_initial_dc(); + void setInductance( double i ); + virtual void add_map(); + + protected: + virtual void updateCurrents(); + virtual bool updateStatus(); + + private: + double m_inductance; // Inductance + Method m_method; // Method of integration + + double r_eq_old; + double v_eq_old; +}; + +#endif diff --git a/src/electronics/simulation/logic.cpp b/src/electronics/simulation/logic.cpp new file mode 100644 index 0000000..031dd2e --- /dev/null +++ b/src/electronics/simulation/logic.cpp @@ -0,0 +1,319 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include +#include "circuit.h" +#include "elementset.h" +#include "logic.h" +#include "matrix.h" +#include "simulator.h" +#include "src/core/ktlconfig.h" + +LogicIn::LogicIn( LogicConfig config ) + : Element::Element() +{ + m_config = config; + m_pCallbackFunction = 0l; + m_numCNodes = 1; + m_bLastState = false; + m_pNextLogic = 0l; + setLogic(getConfig()); +} + +LogicIn::~LogicIn() +{ + Simulator::self()->removeLogicInReferences(this); +} + + +void LogicIn::setCallback( CallbackClass * object, CallbackPtr func ) +{ + m_pCallbackFunction = func; + m_pCallbackObject = object; +} + + +void LogicIn::check() +{ + if (!b_status) + return; + + bool newState; + if (m_bLastState) + { + // Was high, will still be high unless voltage is less than falling trigger + newState = p_cnode[0]->v > m_config.fallingTrigger; + } + else + { + // Was low, will still be low unless voltage is more than rising trigger + newState = p_cnode[0]->v > m_config.risingTrigger; + } + + if ( m_pCallbackFunction && (newState != m_bLastState) ) + { + m_bLastState = newState; + (m_pCallbackObject->*m_pCallbackFunction)(newState); + } + m_bLastState = newState; +} + + +void LogicIn::setLogic( LogicConfig config ) +{ + m_config = config; + check(); +} + + +void LogicIn::setElementSet( ElementSet *c ) +{ + if (c) + m_pNextLogic = 0l; + else + m_cnodeI[0] = 0.; + + Element::setElementSet(c); +} + + +void LogicIn::add_initial_dc() +{ +} + + +void LogicIn::updateCurrents() +{ +} + + +LogicConfig LogicIn::getConfig() +{ + LogicConfig c; + c.risingTrigger = KTLConfig::logicRisingTrigger(); + c.fallingTrigger = KTLConfig::logicFallingTrigger(); + c.output = KTLConfig::logicOutputHigh(); + c.highImpedance = KTLConfig::logicOutputHighImpedance(); + c.lowImpedance = KTLConfig::logicOutputLowImpedance(); + return c; +} + + +LogicOut::LogicOut( LogicConfig config, bool _high ) + : LogicIn(config) +{ + m_bCanAddChanged = true; + m_bOutputHighConductanceConst = false; + m_bOutputLowConductanceConst = false; + m_bOutputHighVoltageConst = false; + m_pNextChanged[0] = m_pNextChanged[1] = 0l; + m_pSimulator = 0l; + m_bUseLogicChain = false; + b_state = false; + m_numCNodes = 1; + m_vHigh = m_gHigh = m_gLow = 0.0; + m_old_g_out = m_g_out = 0.0; + m_old_v_out = m_v_out = 0.0; + setHigh(_high); + + // Although we already call this function in LogicIn's constructor, our + // virtual function will not have got called, so we have to call it again. + setLogic(getConfig()); +} + +LogicOut::~LogicOut() +{ + if (!m_pSimulator) + m_pSimulator = Simulator::self(); + + // Note that although this function will get called in the destructor of + // LogicIn, we must call it here as well as it needs to be called before + // removeLogicOutReferences(this) is called. + m_pSimulator->removeLogicInReferences(this); + + m_pSimulator->removeLogicOutReferences(this); +} + + +void LogicOut::setUseLogicChain( bool use ) +{ + if (!m_pSimulator) + m_pSimulator = Simulator::self(); + + m_bUseLogicChain = use; + if (use) + setElementSet(0l); +} + + +void LogicOut::setElementSet( ElementSet *c ) +{ + if (!m_pSimulator) + m_pSimulator = Simulator::self(); + + if (c) + { + m_bUseLogicChain = false; + m_pNextChanged[0] = m_pNextChanged[1] = 0l; + } + + // NOTE Make sure that the next two lines are the same as those in setHigh and setLogic + m_g_out = b_state ? m_gHigh : m_gLow; + m_v_out = b_state ? m_vHigh : 0.0; + + LogicIn::setElementSet(c); +} + + +void LogicOut::setOutputHighConductance( double g ) +{ + m_bOutputHighConductanceConst = true; + if ( g == m_gHigh ) + return; + m_gHigh = g; + configChanged(); +} + + +void LogicOut::setOutputLowConductance( double g ) +{ + m_bOutputLowConductanceConst = true; + if ( g == m_gLow ) + return; + m_gLow = g; + configChanged(); +} + + +void LogicOut::setOutputHighVoltage( double v ) +{ + m_bOutputHighVoltageConst = true; + if ( v == m_vHigh ) + return; + m_vHigh = v; + configChanged(); +} + + +void LogicOut::setLogic( LogicConfig config ) +{ + m_config = config; + + if (!m_bOutputHighConductanceConst) + m_gHigh = 1.0/config.highImpedance; + + if (!m_bOutputLowConductanceConst) + m_gLow = (config.lowImpedance == 0.0) ? 0.0 : 1.0/config.lowImpedance; + + if (!m_bOutputHighVoltageConst) + m_vHigh = config.output; + + configChanged(); +} + + +void LogicOut::configChanged() +{ + if (m_bUseLogicChain) + return; + + if (p_eSet) + p_eSet->setCacheInvalidated(); + + // Re-add the DC stuff using the new values + + m_old_g_out = m_g_out; + m_old_v_out = m_v_out; + + // NOTE Make sure that the next two lines are the same as those in setElementSet and setHigh + m_g_out = b_state ? m_gHigh : m_gLow; + m_v_out = b_state ? m_vHigh : 0.0; + + add_initial_dc(); + + m_old_g_out = 0.; + m_old_v_out = 0.; + + check(); +} + + +void LogicOut::add_map() +{ + if (!b_status) return; + + p_A->setUse( p_cnode[0]->n(), p_cnode[0]->n(), Map::et_variable, false ); +} + + +void LogicOut::add_initial_dc() +{ + if (!b_status) + return; + + A_g( 0, 0 ) += m_g_out-m_old_g_out; + b_i( 0 ) += m_g_out*m_v_out-m_old_g_out*m_old_v_out; +} + +void LogicOut::updateCurrents() +{ + if (m_bUseLogicChain) + { + m_cnodeI[0] = 0.; + return; + } + if (!b_status) { + return; + } + m_cnodeI[0] = (p_cnode[0]->v-m_v_out)*m_g_out; +} + +void LogicOut::setHigh( bool high ) +{ + if ( high == b_state ) + return; + + if (m_bUseLogicChain) + { + b_state = high; + + for ( LogicIn * logic = this; logic; logic = logic->nextLogic() ) + logic->setLastState(high); + + if (m_bCanAddChanged) + { + m_pSimulator->addChangedLogic(this); + m_bCanAddChanged = false; + } + + return; + } + + m_old_g_out = m_g_out; + m_old_v_out = m_v_out; + + // NOTE Make sure that the next two lines are the same as those in setElementSet and setLogic + m_g_out = high ? m_gHigh : m_gLow; + m_v_out = high ? m_vHigh : 0.0; + + add_initial_dc(); + + m_old_g_out = 0.; + m_old_v_out = 0.; + + b_state = high; + + if ( p_eSet && p_eSet->circuit()->canAddChanged() ) + { + m_pSimulator->addChangedCircuit( p_eSet->circuit() ); + p_eSet->circuit()->setCanAddChanged(false); + } +} + diff --git a/src/electronics/simulation/logic.h b/src/electronics/simulation/logic.h new file mode 100644 index 0000000..be8374f --- /dev/null +++ b/src/electronics/simulation/logic.h @@ -0,0 +1,211 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef LOGIC_H +#define LOGIC_H + +#include "element.h" + +#include +#include + +class Component; +class Pin; +class Simulator; + +typedef QValueList > PinList; + +typedef struct +{ + float risingTrigger; // Trigger on rising edge + float fallingTrigger; // Trigger on falling edge + float output; // Output voltage + float highImpedance; // Output impedance when high + float lowImpedance; // Output impedance when low +} LogicConfig; + +class CallbackClass {}; +typedef void(CallbackClass::*CallbackPtr)( bool isHigh ); + +/** +Use this class for Logic Inputs - this will have infinite impedance. +Use isHigh() will return whether the voltage level at the pin +is high than the predetermined voltage threshold, and setHigh() will make the +output high/low, also according to the predetermined logic type / voltages. + +@short Boolean Logic input +*/ +class LogicIn : public Element +{ + public: + LogicIn( LogicConfig config ); + virtual ~LogicIn(); + + virtual Type type() const { return Element_LogicIn; } + virtual void setElementSet( ElementSet *c ); + + /** + * Set logic values from the LogicConfig. + */ + virtual void setLogic( LogicConfig config ); + /** + * Check if the input state has changed, to see if we need to callback. + */ + void check(); + /** + * Returns whether the pin is 'high', as defined for the logic type + * Note: this is defined as the voltage on the pin, as opposed to what the + * state was set to (the two are not necessarily the same). + */ + bool isHigh() const { return m_bLastState; } + /** + * When the logic state on this LogicIn changes, the function passed in this + * function will be called. At most one Callback can be added per LogicIn. + */ + void setCallback( CallbackClass * object, CallbackPtr func ); + /** + * Reads the LogicConfig values in from KTLConfig, and returns them in a + * nice object form. + */ + static LogicConfig getConfig(); + /** + * If this belongs to a logic chain, then this will be called from the chain. + */ + void setLastState( bool state ) { m_bLastState = state; } + /** + * Returns a pointer to the next LogicIn in the chain. + */ + LogicIn * nextLogic() const { return m_pNextLogic; } + /** + * Sets the next LogicIn in the chain. + */ + void setNextLogic( LogicIn * next ) { m_pNextLogic = next; } + /** + * Calls the callback function, if there is one. + */ + void callCallback() + { + if (m_pCallbackFunction) + (m_pCallbackObject->*m_pCallbackFunction)(m_bLastState); + } + + protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + + CallbackPtr m_pCallbackFunction; + CallbackClass * m_pCallbackObject; + bool m_bLastState; + LogicIn * m_pNextLogic; + LogicConfig m_config; +}; + + +/** +@short Logic output/input +*/ +class LogicOut : public LogicIn +{ + public: + LogicOut( LogicConfig config, bool _high ); + virtual ~LogicOut(); + + virtual void setLogic( LogicConfig config ); + virtual void setElementSet( ElementSet *c ); + virtual void add_map(); + virtual Type type() const { return Element_LogicOut; } + + /** + * Call this function to override the logic-high output impedance as set by + * the user. Once set, the impedance will not be changed by the user + * updating the config; only by subsequent calls to this function. + */ + void setOutputHighConductance( double g ); + /** + * Call this function to override the logic-low output impedance as set by + * the user. Once set, the impedance will not be changed by the user + * updating the config; only by subsequent calls to this function. + */ + void setOutputLowConductance( double g ); + /** + * Call this function to override the logic out voltage as set by the + * user. Once set, the impedance will not be changed by the user + * updating the config; only by subsequent calls to this function. + */ + void setOutputHighVoltage( double v ); + /** + * Returns the voltage that this will output when high. + */ + double outputHighVoltage() const { return m_vHigh; } + /** + * Sets the pin to be high/low + */ + void setHigh( bool high ); + /** + * @returns the state that this is outputting (regardless of voltage level on logic) + */ + bool outputState() const { return b_state; } + /** + * Set whether or not this LogicOut is the head of a LogicChain (controls + * itself and a bunch of LogicIns). + */ + void setUseLogicChain( bool use ); + /** + * When a LogicOut configured as the start of a LogicChain changes start, it + * appends a pointer to itself to the list of change LogicOut, starting from + * the Simulator. This functions enables appending the next changed LogicOut + * to this one. + */ + void setNextChanged( LogicOut * logicOut, unsigned char chain ) { m_pNextChanged[chain] = logicOut; } + /** + * To avoid a pointer to this LogicOut being added twice in one + * iteration due to the state changing twice, this LogicOut sets an + * added flag to true after adding it to the list of changed. The flag + * must be reset to false with this function (done by Simulator). + */ + void setCanAddChanged( bool canAdd ) { m_bCanAddChanged = canAdd; } + /** + * Returns the next LogicOut that has changed, when configured as the start + * of a LogicChain. + * @see setNextChanged + */ + LogicOut * nextChanged( unsigned char chain ) const { return m_pNextChanged[chain]; } + PinList pinList; + PinList::iterator pinListBegin; + PinList::iterator pinListEnd; + + protected: + void configChanged(); + virtual void updateCurrents(); + virtual void add_initial_dc(); + + // Pre-initalized levels from config + double m_gHigh; + double m_gLow; + double m_vHigh; + + // Whether to use the user-defined logic values + bool m_bOutputHighConductanceConst; + bool m_bOutputLowConductanceConst; + bool m_bOutputHighVoltageConst; + + double m_g_out; + double m_v_out; + double m_old_g_out; + double m_old_v_out; + bool b_state; + bool m_bCanAddChanged; + LogicOut * m_pNextChanged[2]; + Simulator * m_pSimulator; + bool m_bUseLogicChain; +}; + +#endif + diff --git a/src/electronics/simulation/matrix.cpp b/src/electronics/simulation/matrix.cpp new file mode 100644 index 0000000..fb1248f --- /dev/null +++ b/src/electronics/simulation/matrix.cpp @@ -0,0 +1,546 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "matrix.h" + +#include + +#include + +#include +#include +#include + +/// Minimum value before an entry is deemed "zero" +const double epsilon = 1e-50; + +Matrix::Matrix( uint n, uint m ) +{ + m_n = n; + m_m = m; + m_size = m_n+m_m; + + m_mat = new matrix(m_size); + m_lu = new matrix(m_size); + m_y = new double[m_size]; + m_inMap = new int[m_size]; +// m_outMap = new int[m_size]; + m_map = new Map(m_size); + zero(); +} + + +Matrix::~Matrix() +{ + delete m_map; + delete m_mat; + delete m_lu; + delete [] m_y; + delete [] m_inMap; +// delete [] m_outMap; +} + + +void Matrix::zero() +{ + for ( uint i=0; isetUse( i, j, type, big ); +} + + +void Matrix::createMap() +{ + int newMap[m_size]; + m_map->createMap(newMap); + for ( uint i=0; iswapRows( a, b ); + + const int old = m_inMap[a]; + m_inMap[a] = m_inMap[b]; + m_inMap[b] = old; + + max_k = 0; +} + + +/*void Matrix::genOutMap() +{ + for ( uint i=0; im(i,j); + } + } + + max_k = 0; +} + +void Matrix::operator+=( Matrix *const m ) +{ + for ( uint _i=0; _im(i,j); + } + } + + max_k = 0; +} + +void Matrix::performLU() +{ +// max_k = 0; + uint n = m_size; + if ( n == 0 ) return; + + // Copy the affected segment to LU + for ( uint i=max_k; i 1e-12 ) + { + for ( uint j=std::max(k,max_k)+1; j=0; i-- ) + { + double sum = 0; + for ( uint j=i+1; jreset(); + for ( uint _i=0; _i 0 && (*m_mat)[i][j] >= 0 ) kdDebug() << "+"; + kdDebug() << (*m_mat)[i][j] << "("< 0 && (*m_lu)[i][j] >= 0 ) std::cout << "+"; + std::cout << (*m_lu)[i][j] << "("<"<"<= 0 && map[i] < int(m_size) ); + } + + // Ignore this, for now: + + // Now, we want to order the matrix, with the following priorities: + // (1) How often values change + // (2) How few values there are + // (3) How large the values are + // For each value in the column, +} + + +bool Map::typeCmp( const uint t1, const uint t2 ) +{ + if (!t2) return true; + if (!t1) return false; + + int t1_score = 1; + if ( t1 | Map::et_constant ) t1_score += 64; + else if ( t1 | Map::et_stable ) t1_score += 16; + else if ( t1 | Map::et_variable ) t1_score += 4; + + int t2_score = 1; + if ( t2 | Map::et_constant ) t2_score += 64; + else if ( t2 | Map::et_stable ) t2_score += 16; + else if ( t2 | Map::et_variable ) t2_score += 4; + + if ( t1 | Map::et_big ) t1_score *= 2; + if ( t2 | Map::et_big ) t2_score *= 2; + + return ( t1_score >= t2_score ); +} + + +Matrix22::Matrix22() +{ + reset(); +} + +bool Matrix22::solve() +{ + const double old_x1 = m_x1; + const double old_x2 = m_x2; + + const bool e11 = std::abs((m_a11)) + +class Map; + +typedef std::vector > ETMap; + +/** +@short Handles row-wise permutation of matrixes +*/ +class Map +{ +public: + enum e_type + { + et_none = 0x0, // Default value, none + et_constant = 0x1, // Never changes value in lifetime of matrix + et_stable = 0x2, // Value changes occasionally, e.g. user changing resistance value + et_variable = 0x3, // Rate of changing is unknown, probably average - e.g. logic + et_unstable = 0x4, // Value changes practically every call of performLU + et_big = 0x8 // Ignore this :-) It is used to OR with one of the others, but it should only ever be accessed by the class + }; + Map( const uint size ); + ~Map(); + + void setUse( const uint i, const uint j, Map::e_type type, bool big ); + /** + * Generates an optimal permutation, returned in the given array + */ + void createMap( int *map ); + /** + * Resets the info to a blank pattern + */ + void reset(); + +protected: + /** + * Compares two "types", returning true if t1 >= t2, else false + */ + bool typeCmp( const uint t1, const uint t2 ); + +private: + ETMap *m_map; + uint m_size; +}; + +/** +This class performs matrix storage, lu decomposition, forward and backward +substitution, and a few other useful operations. Steps in using class: +(1) Create an instance of this class with the correct size +(2) Define the matrix pattern as neccessary: + (1) Call zero (unnecessary after initial ceration) to reset the pattern + & matrix + (2) Call setUse to set the use of each element in the matrix + (3) Call createMap to generate the row-wise permutation mapping for use + in partial pivoting +(3) Add the values to the matrix +(4) Call performLU, and get the results with fbSub +(5) Repeat 2, 3, 4 or 5 as necessary. +@todo We need to allow createMap to work while the matrix has already been initalised +@short Matrix manipulation class tailored for circuit equations +@author David Saxton +*/ +class Matrix +{ +public: + /** + * Creates a size x size square matrix m, with all values zero, + * and a right side vector x of size m+n + */ + Matrix( uint n, uint m ); + ~Matrix(); + /** + * Sets all elements to zero + */ + void zero(); + /** + * Sets the type of (matrix-) element at the position i, j. + * @param type Describes how often the value changes + * @param big Set this true if the value is likely to be >= 1, else false + */ + void setUse( const uint i, const uint j, Map::e_type type, bool big ); + void setUse_b( const uint i, const uint j, Map::e_type type, bool big ) + { + setUse( i, j+m_n, type, big ); + } + void setUse_c( const uint i, const uint j, Map::e_type type, bool big ) + { + setUse( i+m_n, j, type, big ); + } + void setUse_d( const uint i, const uint j, Map::e_type type, bool big ) + { + setUse( i+m_n, j+m_n, type, big ); + } + /** + * Generates the row-wise permutation mapping from the values set by setUse + */ + void createMap(); + /** + * Returns true if the matrix is changed since last calling performLU() + * - i.e. if we do need to call performLU again. + */ + inline bool isChanged() const { return max_k < m_size; } + /** + * Performs LU decomposition. Going along the rows, + * the value of the decomposed LU matrix depends only on + * the previous values. + */ + void performLU(); + /** + * Applies the right side vector (x) to the decomposed matrix, + * with the solution returned in x. + */ + void fbSub( Vector* x ); + /** + * Prints the matrix to stdout + */ + void displayMatrix(); + /** + * Prints the LU-decomposed matrix to stdout + */ + void displayLU(); + /** + * Sets the element matrix at row i, col j to value x + */ + double& g( uint i, uint j ) + { + i = m_inMap[i]; + if ( i0 ) max_k--; + + return (*m_mat)[i][j]; + } + double& b( uint i, uint j ) { return g( i, j+m_n ); } + double& c( uint i, uint j ) { return g( i+m_n, j ); } + double& d( uint i, uint j ) { return g( i+m_n, j+m_n ); } + const double g( uint i, uint j ) const { return (*m_mat)[m_inMap[i]][j]; } + const double b( uint i, uint j ) const { return g( i, j+m_n ); } + const double c( uint i, uint j ) const { return g( i+m_n, j ); } + const double d( uint i, uint j ) const { return g( i+m_n, j+m_n ); } + /** + * Returns the value of matrix at row i, col j. + */ + const double m( uint i, uint j ) const + { + return (*m_mat)[m_inMap[i]][j]; + } + /** + * Multiplies this matrix by the Vector rhs, and places the result + * in the vector pointed to by result. Will fail if wrong size. + */ + void multiply( Vector *rhs, Vector *result ); + /** + * Sets the values of this matrix to that of the given matrix + */ + void operator=( Matrix *const m ); + /** + * Adds the values of the given matrix to this matrix + */ + void operator+=( Matrix *const m ); + +private: + /** + * Swaps around the rows in the (a) the matrix; and (b) the mappings + */ + void swapRows( const uint a, const uint b ); + +// // Generates m_outMap from m_inMap +// void genOutMap(); + + uint m_n; + uint m_m; + uint m_size; + uint max_k; + + int *m_inMap; // Rowwise permutation mapping from external reference to internal storage +// int *m_outMap; // Opposite of m_inMap + + matrix *m_mat; + matrix *m_lu; + double *m_y; // Avoids recreating it lots of times + Map *m_map; +}; + + +/** +This class provides a very simple, lightweight, 2x2 matrix solver. +It's fast and reliable. Set the values for the entries of A and b: + +A x = b + +call solve() (which returns true if successful - i.e. exactly one solution to the +matrix), and get the values of x with the appropriate functions. + +@short 2x2 Matrix +@author David Saxton +*/ +class Matrix22 +{ +public: + Matrix22(); + + double &a11() { return m_a11; } + double &a12() { return m_a12; } + double &a21() { return m_a21; } + double &a22() { return m_a22; } + + double &b1() { return m_b1; } + double &b2() { return m_b2; } + + /** + * Solve the matrix. Returns true if successful (i.e. non-singular), else + * false. Get the solution with x1() and x2(). + */ + bool solve(); + /** + * Resets all entries to zero + */ + void reset(); + + double x1() const { return m_x1; } + double x2() const { return m_x2; } + +private: + double m_a11, m_a12, m_a21, m_a22; + double m_b1, m_b2; + double m_x1, m_x2; +}; + + +#endif diff --git a/src/electronics/simulation/nonlinear.cpp b/src/electronics/simulation/nonlinear.cpp new file mode 100644 index 0000000..c975f16 --- /dev/null +++ b/src/electronics/simulation/nonlinear.cpp @@ -0,0 +1,97 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "matrix.h" +#include "nonlinear.h" + +#include +using namespace std; + +const double KTL_MAX_DOUBLE = 1.7976931348623157e+308; ///< 7fefffff ffffffff +const int KTL_MAX_EXPONENT = int( log( KTL_MAX_DOUBLE ) ); + + +NonLinear::NonLinear() + : Element() +{ +} + + +#ifndef MIN +# define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#endif + + +// The function computes the exponential pn-junction current. +double NonLinear::diodeCurrent( double v, double I_S, double Vte ) const +{ + return I_S * (exp( MIN( v / Vte, KTL_MAX_EXPONENT ) ) - 1); +} + + + +double NonLinear::diodeConductance( double v, double I_S, double Vte ) const +{ + return I_S * exp( MIN( v / Vte, KTL_MAX_EXPONENT ) ) / Vte; +} + + + +double NonLinear::diodeVoltage( double V, double V_prev, double V_T, double Vcrit ) const +{ + if ( V > Vcrit && fabs( V - V_prev ) > 2 * V_T ) + { + if ( V_prev > 0 ) + { + double arg = (V - V_prev) / V_T; + if (arg > 0) + V = V_prev + V_T * (2 + log( arg - 2 )); + else + V = V_prev - V_T * (2 + log( 2 - arg )); + } + else + V = (V_prev < 0) ? (V_T * log (V / V_T)) : Vcrit; + } + else + { + if ( V < 0 ) + { + double arg = (V_prev > 0) ? (-1 - V_prev) : (2 * V_prev - 1); + if (V < arg) + V = arg; + } + } + return V; +} + + +double NonLinear::diodeCriticalVoltage( double I_S, double V_Te ) const +{ + return V_Te * log( V_Te / M_SQRT2 / I_S ); +} + + +void NonLinear::diodeJunction( double V, double I_S, double V_Te, double * I, double * g ) const +{ + if (V < -3 * V_Te) + { + double a = 3 * V_Te / (V * M_E); + a = a * a * a; + *I = -I_S * (1 + a); + *g = +I_S * 3 * a / V; + } + else + { + double e = exp( MIN( V / V_Te, KTL_MAX_EXPONENT ) ); + *I = I_S * (e - 1); + *g = I_S * e / V_Te; + } +} + diff --git a/src/electronics/simulation/nonlinear.h b/src/electronics/simulation/nonlinear.h new file mode 100644 index 0000000..422f3a4 --- /dev/null +++ b/src/electronics/simulation/nonlinear.h @@ -0,0 +1,48 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef NONLINEAR_H +#define NONLINEAR_H + +#include "element.h" + +/** +@short Represents a non-linear circuit element (such as a diode) +@author David Saxton +*/ +class NonLinear : public Element +{ + public: + NonLinear(); + + virtual bool isNonLinear() { return true; } + /** + * Newton-Raphson iteration: Update equation system. + */ + virtual void update_dc() = 0; + + protected: + double diodeCurrent( double v, double I_S, double Vte ) const; + /** + * Conductance of the diode - the derivative of Schockley's + * approximation. + */ + double diodeConductance( double v, double I_S, double Vte ) const; + /** + * Limits the diode voltage to prevent divergence in the nonlinear + * iterations. + */ + double diodeVoltage( double v, double V_prev, double Vt, double V_crit ) const; + void diodeJunction( double v, double I_S, double Vte, double * I, double * g ) const; + + double diodeCriticalVoltage( double I_S, double Vte ) const; +}; + +#endif diff --git a/src/electronics/simulation/opamp.cpp b/src/electronics/simulation/opamp.cpp new file mode 100644 index 0000000..45fbf02 --- /dev/null +++ b/src/electronics/simulation/opamp.cpp @@ -0,0 +1,77 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "elementset.h" +#include "matrix.h" +#include "opamp.h" + +OpAmp::OpAmp() + : Element::Element() +{ + m_numCBranches = 1; + m_numCNodes = 3; +} + + +OpAmp::~OpAmp() +{ +} + + +void OpAmp::add_map() +{ + if (!b_status) + return; + + if ( !p_cnode[0]->isGround ) + { + // Non-inverting input + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[0]->n(), Map::et_constant, true ); + } + + if ( !p_cnode[2]->isGround ) + { + // Inverting input + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[2]->n(), Map::et_constant, true ); + } + + if ( !p_cnode[1]->isGround ) + { + // Output + p_A->setUse_b( p_cnode[1]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + } +} + + +void OpAmp::add_initial_dc() +{ + if (!b_status) + return; + + // Non-inverting input + A_c( 0, 0 ) = 1; + + // Inverting input + A_c( 0, 2 ) = -1; + + // Output + A_b( 1, 0 ) = 1; +} + + +void OpAmp::updateCurrents() +{ + if (!b_status) return; + m_cnodeI[0] = m_cnodeI[2] = 0.0; + m_cnodeI[1] = p_cbranch[0]->i; +} + + + diff --git a/src/electronics/simulation/opamp.h b/src/electronics/simulation/opamp.h new file mode 100644 index 0000000..22fe843 --- /dev/null +++ b/src/electronics/simulation/opamp.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef OPAMP_H +#define OPAMP_H + +#include + +/** +node 0: non-inverting input +node 1: output +node 2: inverting input +@author David Saxton +*/ +class OpAmp : public Element +{ + public: + OpAmp(); + virtual ~OpAmp(); + + virtual Type type() const { return Element_OpAmp; } + virtual void add_map(); + + protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); +}; + +#endif diff --git a/src/electronics/simulation/reactive.cpp b/src/electronics/simulation/reactive.cpp new file mode 100644 index 0000000..83fcfd4 --- /dev/null +++ b/src/electronics/simulation/reactive.cpp @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + + +#include "reactive.h" + +Reactive::Reactive( const double delta ) + : Element() +{ + m_delta = delta; +} + + +Reactive::~Reactive() +{ +} + + +void Reactive::setDelta( double delta ) +{ + m_delta = delta; + updateStatus(); +} + + +bool Reactive::updateStatus() +{ + return Element::updateStatus(); +} diff --git a/src/electronics/simulation/reactive.h b/src/electronics/simulation/reactive.h new file mode 100644 index 0000000..1142b34 --- /dev/null +++ b/src/electronics/simulation/reactive.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef REACTIVE_H +#define REACTIVE_H + +#include "element.h" + +/** +@short Represents a reactive element (such as a capacitor) +@author David Saxton +*/ +class Reactive : public Element +{ +public: + Reactive( const double delta ); + virtual ~Reactive(); + + virtual bool isReactive() { return true; } + /** + * Call this function to set the time period (in seconds) + */ + void setDelta( double delta ); + /** + * Called on every time step for the element to update itself + */ + virtual void time_step() = 0; + +protected: + virtual bool updateStatus(); + + double m_delta; // Delta time interval +}; + +#endif diff --git a/src/electronics/simulation/resistance.cpp b/src/electronics/simulation/resistance.cpp new file mode 100644 index 0000000..9c2d25d --- /dev/null +++ b/src/electronics/simulation/resistance.cpp @@ -0,0 +1,95 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "elementset.h" +#include "matrix.h" +#include "resistance.h" + +// #include + +Resistance::Resistance( const double resistance ) + : Element::Element() +{ + m_g = resistance < 1e-9 ? 1e9 : 1./resistance; + m_numCNodes = 2; +// kdDebug() << k_funcinfo << endl; +} + +Resistance::~Resistance() +{ +// kdDebug() << k_funcinfo << endl; +} + +void Resistance::setConductance( const double g ) +{ + if ( g == m_g ) + return; + + if (p_eSet) + p_eSet->setCacheInvalidated(); + + // Remove old resistance + m_g = -m_g; + add_initial_dc(); + + m_g = g; + add_initial_dc(); +} + + +void Resistance::setResistance( const double r ) +{ + setConductance( r < 1e-9 ? 1e9 : 1./r ); +} + + +void Resistance::add_map() +{ + if (!b_status) + return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse( p_cnode[0]->n(), p_cnode[0]->n(), Map::et_stable, false ); + } + if ( !p_cnode[1]->isGround ) { + p_A->setUse( p_cnode[1]->n(), p_cnode[1]->n(), Map::et_stable, false ); + } + + if ( !p_cnode[0]->isGround && !p_cnode[1]->isGround ) + { + p_A->setUse( p_cnode[0]->n(), p_cnode[1]->n(), Map::et_stable, false ); + p_A->setUse( p_cnode[1]->n(), p_cnode[0]->n(), Map::et_stable, false ); + } +} + + +void Resistance::add_initial_dc() +{ + if (!b_status) return; + + A_g( 0, 0 ) += m_g; + A_g( 1, 1 ) += m_g; + A_g( 0, 1 ) -= m_g; + A_g( 1, 0 ) -= m_g; +} + + +void Resistance::updateCurrents() +{ + if (!b_status) return; + const double v=p_cnode[0]->v-p_cnode[1]->v; + m_cnodeI[1] = v*m_g; + m_cnodeI[0] = -m_cnodeI[1]; +} + + + + diff --git a/src/electronics/simulation/resistance.h b/src/electronics/simulation/resistance.h new file mode 100644 index 0000000..7e5a62e --- /dev/null +++ b/src/electronics/simulation/resistance.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef RESISTANCE_H +#define RESISTANCE_H + +#include "element.h" + +/** +@short Resistance +@author David saxton +*/ +class Resistance : public Element +{ +public: + Resistance( const double resistance ); + virtual ~Resistance(); + + virtual Type type() const { return Element_Resistance; } + + void setConductance( const double g ); + void setResistance( const double r ); + + double resistance() { return 1/m_g; } + double conductance() { return m_g; } + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_g; // Conductance +}; + +#endif diff --git a/src/electronics/simulation/vccs.cpp b/src/electronics/simulation/vccs.cpp new file mode 100644 index 0000000..7ff1bc1 --- /dev/null +++ b/src/electronics/simulation/vccs.cpp @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "elementset.h" +#include "matrix.h" +#include "vccs.h" + +VCCS::VCCS( const double gain ) + : Element::Element() +{ + m_g = gain; + m_numCBranches = 1; + m_numCNodes = 4; +} + + +VCCS::~VCCS() +{ +} + + +void VCCS::setGain( const double g ) +{ + if ( g == m_g ) return; + + if (p_eSet) + p_eSet->setCacheInvalidated(); + + // Remove old values + m_g = -m_g; + add_initial_dc(); + + // Add new values + m_g = g; + add_initial_dc(); +} + + +void VCCS::add_map() +{ + if (!b_status) return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[0]->n(), Map::et_stable, false ); + } + if ( !p_cnode[1]->isGround ) + { + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[1]->n(), Map::et_stable, false ); + } + if ( !p_cnode[2]->isGround ) + { + p_A->setUse_b( p_cnode[2]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[2]->n(), Map::et_constant, true ); + } + if ( !p_cnode[3]->isGround ) + { + p_A->setUse_b( p_cnode[3]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[3]->n(), Map::et_constant, true ); + } +} + + +void VCCS::add_initial_dc() +{ + if (!b_status) + return; + + A_g( 2, 0 ) += m_g; + A_g( 3, 0 ) -= m_g; + A_g( 2, 1 ) -= m_g; + A_g( 3, 1 ) += m_g; +} + + +void VCCS::updateCurrents() +{ + if (!b_status) + return; + + m_cnodeI[0] = m_cnodeI[1] = 0.; + m_cnodeI[3] = (p_cnode[0]->v-p_cnode[1]->v)*m_g; + m_cnodeI[2] = -m_cnodeI[3]; +} + + diff --git a/src/electronics/simulation/vccs.h b/src/electronics/simulation/vccs.h new file mode 100644 index 0000000..26f1101 --- /dev/null +++ b/src/electronics/simulation/vccs.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef VCCS_H +#define VCCS_H + +#include "element.h" + +/** +CNodes n0 and n1 are used for the voltage control. +CNodes n2 and n3 are used for the current output. +@short Voltage Controlled Current Source +@author David Saxton +*/ +class VCCS : public Element +{ +public: + VCCS( const double gain ); + virtual ~VCCS(); + + virtual Type type() const { return Element_VCCS; } + void setGain( const double g ); + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_g; // Conductance +}; + +#endif diff --git a/src/electronics/simulation/vcvs.cpp b/src/electronics/simulation/vcvs.cpp new file mode 100644 index 0000000..68604df --- /dev/null +++ b/src/electronics/simulation/vcvs.cpp @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "elementset.h" +#include "matrix.h" +#include "vcvs.h" + +VCVS::VCVS( const double gain ) + : Element::Element() +{ + m_g = gain; + m_numCBranches = 1; + m_numCNodes = 4; +} + + +VCVS::~VCVS() +{ +} + + +void VCVS::setGain( const double g ) +{ + if ( g == m_g ) + return; + + if (p_eSet) + p_eSet->setCacheInvalidated(); + + m_g = -m_g; + add_initial_dc(); + + m_g = g; + add_initial_dc(); +} + + +void VCVS::add_map() +{ + if (!b_status) + return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[0]->n(), Map::et_stable, false ); + } + if ( !p_cnode[1]->isGround ) + { + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[1]->n(), Map::et_stable, false ); + } + if ( !p_cnode[2]->isGround ) + { + p_A->setUse_b( p_cnode[2]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[2]->n(), Map::et_constant, true ); + } + if ( !p_cnode[3]->isGround ) + { + p_A->setUse_b( p_cnode[3]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[3]->n(), Map::et_constant, true ); + } +} + + +void VCVS::add_initial_dc() +{ + if (!b_status) + return; + + A_c( 0, 0 ) -= m_g; + A_c( 0, 1 ) += m_g; + A_b( 2, 0 ) = 1; + A_c( 0, 2 ) = 1; + A_b( 3, 0 ) = -1; + A_c( 0, 3 ) = -1; +} + + +void VCVS::updateCurrents() +{ + if (!b_status) return; + m_cnodeI[0] = m_cnodeI[1] = 0.; + m_cnodeI[3] = p_cbranch[0]->i; + m_cnodeI[2] = -m_cnodeI[3]; +} + + diff --git a/src/electronics/simulation/vcvs.h b/src/electronics/simulation/vcvs.h new file mode 100644 index 0000000..862dea9 --- /dev/null +++ b/src/electronics/simulation/vcvs.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef VCVS_H +#define VCVS_H + +#include "element.h" + +/** +Voltage source between nodes c2 and c3 +Controlling voltage between nodes c0 and c1 +@short Voltage Controlled Voltage Source +@author David Saxton +*/ +class VCVS : public Element +{ +public: + VCVS( const double gain ); + virtual ~VCVS(); + + virtual Type type() const { return Element_VCVS; } + void setGain( const double g ); + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_g; // Conductance +}; + +#endif diff --git a/src/electronics/simulation/vec.cpp b/src/electronics/simulation/vec.cpp new file mode 100644 index 0000000..d45f505 --- /dev/null +++ b/src/electronics/simulation/vec.cpp @@ -0,0 +1,166 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "vec.h" + +#include +#include +#include +using namespace std; + +Vector::Vector( const int size ) +{ + m_size = size; + m_vec = new double[m_size]; + reset(); + b_changed = true; +} + + +Vector::~Vector() +{ + // Hmm...this looks like it's the correct format, although valgrind complains + // about improper memory use. Interesting. "delete m_vec" definitely leaks + // memory, so this seems like the lesser of two evils. I miss C memory allocation + // somtimes, with a nice simple free :p + delete [] m_vec; +} + + +void Vector::reset() +{ + for ( int i=0; isize() == size() ); + + for ( int i = 0; i < m_size; ++i ) + { + double limitAbs = std::abs( limitVector->m_vec[i] ); + if ( limitAbs < 1e-6 ) + limitAbs = 1e-6; + + double thisAbs = std::abs( m_vec[i] ); + if ( thisAbs < 1e-6 ) + thisAbs = 1e-6; + + if ( (thisAbs / limitAbs) > scaleMax ) + m_vec[i] /= (thisAbs / limitAbs); + + else if ( (limitAbs / thisAbs) > scaleMax ) + m_vec[i] /= (limitAbs / thisAbs); + } + b_changed = true; +} + + +void Vector::operator += ( Vector *rhs ) +{ + if (!rhs) return; + for ( int i=0; isetCacheInvalidated(); + + m_voltage = -v; + add_initial_dc(); +} + + +void VoltagePoint::add_map() +{ + if (!b_status) return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse_b( p_cnode[0]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[0]->n(), Map::et_constant, true ); + } +} + + +void VoltagePoint::add_initial_dc() +{ + if (!b_status) return; + + A_b( 0, 0 ) = -1; + A_c( 0, 0 ) = -1; + + b_v( 0 ) = m_voltage; +} + + +void VoltagePoint::updateCurrents() +{ + if (!b_status) return; + m_cnodeI[0] = p_cbranch[0]->i; +} + + + + + diff --git a/src/electronics/simulation/voltagepoint.h b/src/electronics/simulation/voltagepoint.h new file mode 100644 index 0000000..924b0af --- /dev/null +++ b/src/electronics/simulation/voltagepoint.h @@ -0,0 +1,39 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef VOLTAGEPOINT_H +#define VOLTAGEPOINT_H + +#include "element.h" + +/** +@short VoltagePoint +@author David saxton +*/ +class VoltagePoint : public Element +{ +public: + VoltagePoint( const double voltage ); + virtual ~VoltagePoint(); + + virtual Type type() const { return Element_VoltagePoint; } + void setVoltage( const double voltage ); + double voltage() { return m_voltage; } + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_voltage; // Conductance +}; + +#endif diff --git a/src/electronics/simulation/voltagesignal.cpp b/src/electronics/simulation/voltagesignal.cpp new file mode 100644 index 0000000..d7a5839 --- /dev/null +++ b/src/electronics/simulation/voltagesignal.cpp @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "matrix.h" +#include "voltagesignal.h" +#include "elementset.h" + +VoltageSignal::VoltageSignal( const double delta, const double voltage ) + : Reactive::Reactive(delta) +{ + m_voltage = voltage; + m_numCNodes = 2; + m_numCBranches = 1; +} + + +VoltageSignal::~VoltageSignal() +{ +} + + +void VoltageSignal::setVoltage( const double v ) +{ + m_voltage = v; +} + + +void VoltageSignal::add_map() +{ + if (!b_status) return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse_b( p_cnode[0]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[0]->n(), Map::et_constant, true ); + } + + if ( !p_cnode[1]->isGround ) + { + p_A->setUse_b( p_cnode[1]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[1]->n(), Map::et_constant, true ); + } +} + + +void VoltageSignal::add_initial_dc() +{ + if (!b_status) + return; + + A_b( 0, 0 ) = -1; + A_c( 0, 0 ) = -1; + A_b( 1, 0 ) = 1; + A_c( 0, 1 ) = 1; +} + + +void VoltageSignal::time_step() +{ + if (!b_status) return; + b_v( 0 ) = m_voltage*advance(); +} + + +void VoltageSignal::updateCurrents() +{ + if (!b_status) return; + m_cnodeI[1] = p_cbranch[0]->i; + m_cnodeI[0] = -m_cnodeI[1]; +} + + diff --git a/src/electronics/simulation/voltagesignal.h b/src/electronics/simulation/voltagesignal.h new file mode 100644 index 0000000..5e35e72 --- /dev/null +++ b/src/electronics/simulation/voltagesignal.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef VOLTAGESIGNAL_H +#define VOLTAGESIGNAL_H + +#include "reactive.h" +#include "elementsignal.h" + +/** +@short VoltageSignal +@author David saxton +*/ +class VoltageSignal : public Reactive, public ElementSignal +{ +public: + VoltageSignal( const double delta, const double voltage ); + virtual ~VoltageSignal(); + + virtual Element::Type type() const { return Element_VoltageSignal; } + void setVoltage( const double voltage ); + double voltage() { return m_voltage; } + virtual void time_step(); + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_voltage; // Voltage +}; + +#endif diff --git a/src/electronics/simulation/voltagesource.cpp b/src/electronics/simulation/voltagesource.cpp new file mode 100644 index 0000000..b4fca64 --- /dev/null +++ b/src/electronics/simulation/voltagesource.cpp @@ -0,0 +1,77 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "matrix.h" +#include "voltagesource.h" +#include "elementset.h" + +VoltageSource::VoltageSource( const double voltage ) + : Element::Element() +{ + m_v = voltage; + m_numCBranches = 1; + m_numCNodes = 2; +} + +VoltageSource::~VoltageSource() +{ +} + +void VoltageSource::setVoltage( const double v ) +{ + if ( m_v == v ) return; + + if (p_eSet) + p_eSet->setCacheInvalidated(); + + m_v = v; + add_initial_dc(); +} + + +void VoltageSource::add_map() +{ + if (!b_status) return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse_b( p_cnode[0]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[0]->n(), Map::et_constant, true ); + } + + if ( !p_cnode[1]->isGround ) + { + p_A->setUse_b( p_cnode[1]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[1]->n(), Map::et_constant, true ); + } +} + + +void VoltageSource::add_initial_dc() +{ + if (!b_status) + return; + + A_b( 0, 0 ) = -1; + A_c( 0, 0 ) = -1; + A_b( 1, 0 ) = 1; + A_c( 0, 1 ) = 1; + + b_v( 0 ) = m_v; +} + +void VoltageSource::updateCurrents() +{ + if (!b_status) return; + m_cnodeI[0] = p_cbranch[0]->i; + m_cnodeI[1] = -m_cnodeI[0]; +} + + diff --git a/src/electronics/simulation/voltagesource.h b/src/electronics/simulation/voltagesource.h new file mode 100644 index 0000000..9b27b0d --- /dev/null +++ b/src/electronics/simulation/voltagesource.h @@ -0,0 +1,38 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef VOLTAGESOURCE_H +#define VOLTAGESOURCE_H + +#include "element.h" + +/** +CNode n0 is the negative terminal, CNode n1 is the positive terminal +@short Voltage Source +*/ +class VoltageSource : public Element +{ +public: + VoltageSource( const double voltage ); + virtual ~VoltageSource(); + + virtual Type type() const { return Element_VoltageSource; } + void setVoltage( const double v ); + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_v; // Voltage +}; + +#endif diff --git a/src/electronics/subcircuits.cpp b/src/electronics/subcircuits.cpp new file mode 100644 index 0000000..65ae8e3 --- /dev/null +++ b/src/electronics/subcircuits.cpp @@ -0,0 +1,175 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "circuitdocument.h" +#include "ecsubcircuit.h" +#include "itemdocumentdata.h" +#include "itemlibrary.h" +#include "itemselector.h" +#include "subcircuits.h" + +#include +#include +#include +#include +#include +#include +#include + +Subcircuits::Subcircuits() + : QObject() +{ + connect( ComponentSelector::self(), SIGNAL(itemRemoved(const QString& )), this, SLOT(slotItemRemoved(const QString& )) ); +} + + +Subcircuits::~Subcircuits() +{ +} + + +void Subcircuits::initECSubcircuit( int subcircuitId, ECSubcircuit *ecSubcircuit ) +{ + const QString fileName = genFileName(subcircuitId); + if ( !QFile::exists(fileName) ) + { + kdDebug() << "Subcircuits::createSubcircuit: Subcircuit \""<(itemLibrary()->createItem( "ec/subcircuit", circuitDocument, newItem, newId, false )); + ecSubcircuit->property("id")->setValue(id); + return ecSubcircuit; +} + + +void Subcircuits::loadSubcircuits() +{ + KConfig *config = kapp->config(); + config->setGroup("Subcircuits"); + + QValueList idList = config->readIntListEntry("Ids"); + const QValueList::iterator idListEnd = idList.end(); + for ( QValueList::iterator it = idList.begin(); it != idListEnd; ++it ) + { + QFile file( genFileName(*it) ); + if ( file.open(IO_ReadOnly) == false ) + { + // File has mysteriously disappeared.... + *it = -1; + } + else + { + config->setGroup("Subcircuit_"+QString::number(*it)); + updateComponentSelector( *it, config->readEntry("Name") ); + } + file.close(); + } + idList.remove(-1); + + // Update the config file if any ids have been removed + config->setGroup("Subcircuits"); + config->writeEntry( "Ids", idList ); +} + + +QString Subcircuits::genFileName( const int nextId ) +{ + return locateLocal( "appdata", "subcircuit_"+QString::number(nextId)+".circuit" ); +} + + +void Subcircuits::updateComponentSelector( int id, const QString &name ) +{ + if ( name.isEmpty() ) + return; + + ComponentSelector::self()->addItem( name, "sc/"+QString::number(id), "Subcircuits", KGlobal::iconLoader()->loadIcon( "ktechlab_circuit", KIcon::Small ), true ); +} + + +void Subcircuits::addSubcircuit( const QString &name, const QString &subcircuitXml ) +{ + KConfig *config = kapp->config(); + config->setGroup("Subcircuits"); + + int nextId = config->readNumEntry( "NextId", 0 ); + + while ( QFile::exists( genFileName(nextId) ) ) { + nextId++; + } + + const int id = nextId; + + const QString fileName = genFileName(id); + QFile file(fileName); + + if ( file.open(IO_WriteOnly) == false ) + { + kdError() << "Subcircuits::addSubcircuit: couldn't open subcircuit save file: "< idList = config->readIntListEntry("Ids"); + idList += id; + config->writeEntry( "Ids", idList ); + config->writeEntry( "NextId", ++nextId ); + + config->setGroup("Subcircuit_"+QString::number(id)); + config->writeEntry( "Name", name ); + + // It's important that we write the configuration *now*, lest the subcircuits be lost + config->sync(); + + updateComponentSelector( id, name ); +} + + +void Subcircuits::slotItemRemoved( const QString &id ) +{ + if ( !id.startsWith("sc/") ) { + return; + } + + QString temp = id; + temp.remove("sc/"); + const int id_num = temp.toInt(); + const QString fileName = genFileName(id_num); + QFile file(fileName); + file.remove(); + + KConfig *config = kapp->config(); + config->setGroup("Subcircuits"); + QValueList idList = config->readIntListEntry("Ids"); + idList.remove(id_num); + config->writeEntry( "Ids", idList ); +} + + +#include "subcircuits.moc" + + diff --git a/src/electronics/subcircuits.h b/src/electronics/subcircuits.h new file mode 100644 index 0000000..3f08dd9 --- /dev/null +++ b/src/electronics/subcircuits.h @@ -0,0 +1,76 @@ +/*************************************************************************** + * Copyright (C) 2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef SUBCIRCUITS_H +#define SUBCIRCUITS_H + +#include + +class CircuitDocument; +class ECSubcircuit; +class Subcircuits; +inline Subcircuits *subcircuits(); + +/** +Interface for dealing with loading / saving / etc of subcircuits +@author David Saxton +*/ +class Subcircuits : public QObject +{ +Q_OBJECT +public: + ~Subcircuits(); + /** + * Handles subcircuit creation when the user selects the subcircuit to be + * created. + * @param id Id of subcircuit; e.g. "sc/10" + */ + static ECSubcircuit* createSubcircuit( int id, CircuitDocument *circuitDocument, bool newItem, const char *newId ); + /** + * Loads a subcircuit into a subcircuit component + */ + static void initECSubcircuit( int subcircuitId, ECSubcircuit *ecSubcircuit ); + /** + * Reads in the config entries and adds the subcircuits found to the + * component selector + */ + static void loadSubcircuits(); + /** + * Saves the given subcircuit to the appdata dir, updates the appropriate + * config entries, and adds the subcircuit to the component selector. + */ + static void addSubcircuit( const QString &name, const QString &subcircuitXml ); + /** + * returns a path to the appdata dir, e.g. genFileName(2) might return + * ~/.kde/share/apps/ktechlab/subcircuit_2.circuit + */ + static QString genFileName( const int nextId ); + /** + * Adds the given entry to the component selector + */ + static void updateComponentSelector( int id, const QString &name ); + +protected slots: + void slotItemRemoved( const QString &id ); + +private: + Subcircuits(); + + friend Subcircuits* subcircuits(); +}; + + +inline Subcircuits* subcircuits() +{ + static Subcircuits *_subcircuits = new Subcircuits(); + return _subcircuits; +} + +#endif diff --git a/src/electronics/switch.cpp b/src/electronics/switch.cpp new file mode 100644 index 0000000..7cbda70 --- /dev/null +++ b/src/electronics/switch.cpp @@ -0,0 +1,221 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "circuitdocument.h" +#include "component.h" +#include "ecnode.h" +#include "pin.h" +#include "resistance.h" +#include "simulator.h" +#include "switch.h" + +#include +#include + +#include +#include // for rand +#include + +Switch::Switch( Component * parent, Pin * p1, Pin * p2, State state ) +{ + m_bouncePeriod_ms = 5; + m_bBounce = false; + m_bounceStart = 0; + m_pBounceResistance = 0l; + m_pP1 = p1; + m_pP2 = p2; + m_pComponent = parent; + m_pStopBouncingTimer = new QTimer( this ); + connect( m_pStopBouncingTimer, SIGNAL(timeout()), this, SLOT(stopBouncing()) ); + + // Force update + m_state = (state == Open) ? Closed : Open; + setState(state); +} + + +Switch::~ Switch( ) +{ + if (m_pP1) + m_pP1->setSwitchConnected( m_pP2, false ); + + if (m_pP2) + m_pP2->setSwitchConnected( m_pP1, false ); +} + + +void Switch::setState( State state ) +{ + if ( m_state == state ) + return; + + m_state = state; + + if ( m_bBounce ) + startBouncing(); + else + { + // I'm being lazy...calling stopBouncing will connect the stuff + stopBouncing(); + } +} + + +void Switch::setBounce( bool bounce, int msec ) +{ + m_bBounce = bounce; + m_bouncePeriod_ms = msec; +} + + +void Switch::startBouncing() +{ + if ( m_pBounceResistance ) + { + // Already active? + return; + } + + CircuitDocument * cd = m_pComponent->circuitDocument(); + if ( !cd ) + return; + +// kdDebug() << k_funcinfo << endl; + + m_pBounceResistance = m_pComponent->createResistance( m_pP1, m_pP2, 10000 ); + m_bounceStart = Simulator::self()->time(); + Simulator::self()->attachSwitch( this ); +// kdDebug() << "m_bounceStart="< +#include + +class CircuitDocument; +class Component; +class Pin; +class Resistance; +class QTimer; + +/** +@author David Saxton +*/ +class Switch : public QObject +{ + Q_OBJECT + + public: + enum State + { + Open, + Closed, + }; + + Switch( Component * parent, Pin * p1, Pin * p2, State state ); + ~Switch(); + /** + * If bouncing has been set to true, then the state will not switch + * immediately to that given. + */ + void setState( State state ); + State state() const { return m_state; } + /** + * Tell the switch whether to bounce or not, for the given duration, + * when the state is changed. + */ + void setBounce( bool bounce, int msec = 5 ); + /** + * Tell the switch to continue bouncing (updates the resistance value). + * Called from the simulator. + */ + void bounce(); + /** + * Attempts to calculate the current that is flowing through the switch. + * (If all the connectors at one of the ends know their currents, then + * this switch will give the current to the pins at either end). + * @return whether it was successful. + * @see CircuitDocument::calculateConnectorCurrents + */ + bool calculateCurrent(); + + protected slots: + /** + * Called from a QTimer timeout - our bouncing period has come to an + * end. This will then fully disconnect or connect the pins depending + * on the current state. + */ + void stopBouncing(); + + protected: + void startBouncing(); + + bool m_bBounce; + int m_bouncePeriod_ms; + unsigned long long m_bounceStart; // Simulator time that bouncing started + Resistance * m_pBounceResistance; + State m_state; + Component * m_pComponent; + QGuardedPtr m_pP1; + QGuardedPtr m_pP2; + QTimer * m_pStopBouncingTimer; +}; + +#endif diff --git a/src/electronics/wire.cpp b/src/electronics/wire.cpp new file mode 100644 index 0000000..619295d --- /dev/null +++ b/src/electronics/wire.cpp @@ -0,0 +1,146 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "pin.h" +#include "wire.h" +#include + +Wire::Wire( Pin * startPin, Pin * endPin ) +{ + assert(startPin); + assert(endPin); + + m_pStartPin = startPin; + m_pEndPin = endPin; + m_current = 0.; + m_bCurrentIsKnown = false; + + m_pStartPin->addOutputWire(this); + m_pEndPin->addInputWire(this); +} + + +Wire::~Wire() +{ +} + + +bool Wire::calculateCurrent() +{ + if ( m_pStartPin->currentIsKnown() && m_pStartPin->numWires() < 2 ) + { + m_current = m_pStartPin->current(); + m_bCurrentIsKnown = true; + return true; + } + + if ( m_pEndPin->currentIsKnown() && m_pEndPin->numWires() < 2 ) + { + m_current = -m_pEndPin->current(); + m_bCurrentIsKnown = true; + return true; + } + + if ( m_pStartPin->currentIsKnown() ) + { + double i = m_pStartPin->current(); + bool ok = true; + const WireList outlist = m_pStartPin->outputWireList(); + WireList::const_iterator end = outlist.end(); + for ( WireList::const_iterator it = outlist.begin(); it != end && ok; ++it ) + { + if ( *it && (Wire*)*it != this ) + { + if ( (*it)->currentIsKnown() ) + i -= (*it)->current(); + + else + ok = false; + } + } + const WireList inlist = m_pStartPin->inputWireList(); + end = inlist.end(); + for ( WireList::const_iterator it = inlist.begin(); it != end && ok; ++it ) + { + if ( *it && (Wire*)*it != this ) + { + if ( (*it)->currentIsKnown() ) + i += (*it)->current(); + + else + ok = false; + } + } + + if (ok) + { + m_current = i; + m_bCurrentIsKnown = true; + return true; + } + } + + if ( m_pEndPin->currentIsKnown() ) + { + double i = -m_pEndPin->current(); + bool ok = true; + const WireList outlist = m_pEndPin->outputWireList(); + WireList::const_iterator end = outlist.end(); + for ( WireList::const_iterator it = outlist.begin(); it != end && ok; ++it ) + { + if ( *it && (Wire*)*it != this ) + { + if ( (*it)->currentIsKnown() ) + i += (*it)->current(); + + else + ok = false; + } + } + const WireList inlist = m_pEndPin->inputWireList(); + end = inlist.end(); + for ( WireList::const_iterator it = inlist.begin(); it != end && ok; ++it ) + { + if ( *it && (Wire*)*it != this ) + { + if ( (*it)->currentIsKnown() ) + i -= (*it)->current(); + + else + ok = false; + } + } + + if (ok) + { + m_current = i; + m_bCurrentIsKnown = true; + return true; + } + } + + m_bCurrentIsKnown = false; + return false; +} + + +double Wire::voltage() const +{ + return ( m_pStartPin->voltage() + m_pEndPin->voltage() )/2; +} + + +void Wire::setCurrentKnown( bool known ) +{ + m_bCurrentIsKnown = known; + if (!known) + m_current = 0.; +} + diff --git a/src/electronics/wire.h b/src/electronics/wire.h new file mode 100644 index 0000000..368004c --- /dev/null +++ b/src/electronics/wire.h @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef WIRE_H +#define WIRE_H + +#include +#include + +class Pin; + +/** +@author David Saxton +*/ +class Wire : public QObject +{ + public: + Wire( Pin * startPin, Pin * endPin ); + ~Wire(); + + /** + * Attempts to calculate the current that is flowing through + * the connector. Returns true if successfuly, otherwise returns false + */ + bool calculateCurrent(); + /** + * Returns true if the current flowing through the connector is known + */ + bool currentIsKnown() const { return m_bCurrentIsKnown; } + /** + * Set whether the actual current flowing into this node is known (in some + * cases - such as this node being ground - it is not known, and so the + * value returned by current() cannot be relied on. + */ + void setCurrentKnown( bool known ); + /** + * Returns the current flowing through the connector. + * This only applies for electronic connectors + */ + double current() const { return m_current; } + /** + * Returns the voltage at the connector. This is an average of the + * voltages at either end. + */ + double voltage() const; + + Pin * startPin() const { return m_pStartPin; } + Pin * endPin() const { return m_pEndPin; } + + protected: + double m_current; + bool m_bCurrentIsKnown; + QGuardedPtr m_pStartPin; + QGuardedPtr m_pEndPin; +}; + +#endif diff --git a/src/error_messages_en_gb b/src/error_messages_en_gb new file mode 100644 index 0000000..2a208c2 --- /dev/null +++ b/src/error_messages_en_gb @@ -0,0 +1,49 @@ +0#Unknown statement#You have started a line with an unrecognised word. Check the statement is not misspelt, or consult the documentation for a list of available statements. + +1#Missing until statement after repeat statement.#After the closing brace of a section of repeated code, there should be until <expression> on the next line + +2#Port not supported by target PIC#The port referred to is not recognised for the target PIC. Most port names will be of the form PORTX. Check which ports are supported by your PIC.PORTA + +3#Pin identifier was not followed by '='#The pin can accept values of high or low.porta.3 = high
    portb.6 = low
    + +4#Pin state can only be set to 'high' or 'low#A pin cannot be set to a number. Use high or low instead of 1 or 0 respectively.porta.3 = high
    portb.6 = low
    + +5#Port identifier can only be followed by ' = '#A port can be assigned a value between 0 and 255. "PORTA = 6" would output the number 6 on PORTA of the PIC. + +6#Unexpected statement before '{'#There is a mistake in the syntax. + +7#Mismatched brackets#Make sure that every opening bracket ( has a corresponding closing bracket ). + +8#'=' in expression, did you mean '=='?#Use the operator == to test for the equality of two variables. Use the operator = for assignment. Incorrect: if x = 2 then ...
    Correct: if x == 2 then ...
    + +9#Reserved keywords must not be used as a variable name#The word used is a Microbe statement and therefore cannot be used for variable names. + +10#Nothing between operators, did you miss an operand out?#There are two operators in a row, without anything inbetween them. Remember that negative numbers can not be used in this version. Incorrect: 3 + + 5 + +11#Missing operator or space in operand#You may have accidentally placed a space in a variable name, or missed an operator such as plus from between two expressions. + +12#Unknown variable#Make sure that the variable is initialized before first use. Initialising a: a = 0 + +13#Missing 'then' in 'if' statement#The correct syntax for an 'if' statement is:
    if then
    {
    ...
    }
    + +14#Missing argument(s) from 'alias' statement#The alias statement takes 2 arguments: the targetted expression, and the alias name, respectively.

    alias PORTA led

    creates the alias led for PORTA
    + +15#Too many argument(s) in 'alias' statement#The alias statement takes 2 arguments: the targetted expression, and the alias name, respectively.

    alias PORTA led

    creates the alias led for PORTA
    + +16#Could not open included file#Check that the file exists at the path name given in the include statement. + +17#Number too big#Numbers must be integers in the range 0 to 255, this is because Microbe only supports 8-bit numbers. + +18#Unexpected statement after '}'#There is a mistake in the syntax. + +19#A constant expression must follow step#In a for statement, if a step is specified, it must be a constant expression. for i = 0 to 10 step 3
    for i = 30 to 0 step -(10 * 7)
    + +20#Delay argument must be a constant expression#delay takes a single argument, the length of delay required in milliseconds. The length of delay must be a constant expression.delay 7 * 3000
    delay 1
    + +21#High or low expected after pin expression#An expression involving a pic pin should be of the form PORTX.n is high|low.PORTA.3 is high + +22#Comparison operator was not recognised, perhaps you meant <=, >=, or != ?#Be careful to write comparison operators correctly, they should be <=, >= and !=, not =<, => or =!.if a >= 3 then call mysub + +23#Subrountine definition before end of program#Subroutines must be defined after the end statement, and called from the program with call subname. + +255#Internal compiler error#The Microbe compiler has encountered an internal problem. Microbe is still very much in development, and it is likely that this is a genuine bug. Please report this to the authors, as detailed in the Help->About Dialog, so that it can be fixed. diff --git a/src/eventinfo.cpp b/src/eventinfo.cpp new file mode 100644 index 0000000..f6c0746 --- /dev/null +++ b/src/eventinfo.cpp @@ -0,0 +1,132 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "eventinfo.h" +#include "itemdocument.h" +#include "itemview.h" + + +EventInfo::EventInfo() +{ + reset(); +} + + +EventInfo::EventInfo( ItemView *itemView, QEvent *e ) +{ + Q_UNUSED(itemView); + Q_UNUSED(e); + reset(); +} + +EventInfo::EventInfo( ItemView *itemView, QMouseEvent *e ) +{ + pos = e->pos()/itemView->zoomLevel(); + globalPos = e->globalPos(); + isRightClick = e->button() == Qt::RightButton; + ctrlPressed = e->state() & QMouseEvent::ControlButton; + shiftPressed = e->state() & QMouseEvent::ShiftButton; + altPressed = e->state() & QMouseEvent::AltButton; + if ( ItemDocument * id = dynamic_cast(itemView->document()) ) + qcanvasItemClickedOn = id->itemAtTop(pos); + itemRtti = qcanvasItemClickedOn ? qcanvasItemClickedOn->rtti() : ItemDocument::RTTI::None; + scrollDelta = 0; + scrollOrientation = Qt::Vertical; +} + + +EventInfo::EventInfo( ItemView *itemView, QWheelEvent *e ) +{ + pos = e->pos()/itemView->zoomLevel(); + globalPos = e->globalPos(); + isRightClick = false; + ctrlPressed = e->state() & QMouseEvent::ControlButton; + shiftPressed = e->state() & QMouseEvent::ShiftButton; + altPressed = e->state() & QMouseEvent::AltButton; + if ( ItemDocument * id = dynamic_cast(itemView->document()) ) + qcanvasItemClickedOn = id->itemAtTop(pos); + itemRtti = qcanvasItemClickedOn ? qcanvasItemClickedOn->rtti() : ItemDocument::RTTI::None; + scrollDelta = e->delta(); + scrollOrientation = e->orientation(); + +// kdDebug() << "scrollOrientation="< + +class ItemView; + +class QCanvasItem; +class QEvent; +class QMouseEvent; +class QWheelEvent; + +/** +Contains information from for a mouse event that occured on a canvas. Like a +QMouseEvent / QEvent / QWheelEvent, but abstracted to the canvas coordinate +system, as well as holding lots of useful information. +@author David Saxton +*/ +class EventInfo +{ +public: + EventInfo(); + EventInfo( ItemView *itemView, QMouseEvent *e ); + EventInfo( ItemView *itemView, QWheelEvent *e ); + EventInfo( ItemView *itemView, QEvent *e ); + + QMouseEvent *mousePressEvent( int dx, int dy ) const; + QMouseEvent *mouseReleaseEvent( int dx, int dy ) const; + QMouseEvent *mouseDoubleClickEvent( int dx, int dy ) const; + QMouseEvent *mouseMoveEvent( int dx, int dy ) const; + QWheelEvent *wheelEvent( int dx, int dy ) const; + + QPoint pos; + QPoint globalPos; + QCanvasItem *qcanvasItemClickedOn; + int itemRtti; + short scrollDelta; + Qt::Orientation scrollOrientation; + bool isRightClick:1; + bool ctrlPressed:1; + bool shiftPressed:1; + bool altPressed:1; + +protected: + void reset(); +}; + +#endif diff --git a/src/filemetainfo.cpp b/src/filemetainfo.cpp new file mode 100644 index 0000000..34baccd --- /dev/null +++ b/src/filemetainfo.cpp @@ -0,0 +1,198 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "filemetainfo.h" +#include "textdocument.h" +#include "textview.h" + +#include + + +//BEGIN class MetaInfo +MetaInfo::MetaInfo() +{ + m_cursorLine = 0; + m_cursorColumn = 0; +} + + +bool MetaInfo::hasDefaultData() const +{ + return bookmarks().isEmpty() && + breakpoints().isEmpty() && + (m_outputMethodInfo.method() == OutputMethodInfo::Method::Direct ) && + (m_cursorLine == 0) && + (m_cursorColumn == 0); +} + + +void MetaInfo::save( KConfig * conf ) +{ + conf->writeEntry( "Bookmarks", bookmarks() ); + conf->writeEntry( "Breakpoints", breakpoints() ); + conf->writeEntry( "OutputMethod", toID(outputMethodInfo().method()) ); + conf->writePathEntry( "OutputPath", outputMethodInfo().outputFile().prettyURL() ); + conf->writeEntry( "OutputPicID", outputMethodInfo().picID() ); + conf->writeEntry( "CursorLine", cursorLine() ); + conf->writeEntry( "CursorColumn", cursorColumn() ); +} + + +void MetaInfo::load( KConfig * conf ) +{ + setBookmarks( conf->readIntListEntry("Bookmarks") ); + setBreakpoints( conf->readIntListEntry("Breakpoints") ); + m_outputMethodInfo.setMethod( toMethod( conf->readEntry("OutputMethod") ) ); + m_outputMethodInfo.setOutputFile( conf->readPathEntry("OutputPath") ); + m_outputMethodInfo.setPicID( conf->readEntry("OutputPicID") ); + setCursorLine( conf->readNumEntry( "CursorLine", 0 ) ); + setCursorColumn( conf->readNumEntry( "CursorColumn", 0 ) ); +} + + +OutputMethodInfo::Method::Type MetaInfo::toMethod( const QString & id ) +{ + if ( id == "SaveAndLoad" ) + return OutputMethodInfo::Method::SaveAndLoad; + + else if ( id == "SaveAndForget" ) + return OutputMethodInfo::Method::SaveAndForget; + + return OutputMethodInfo::Method::Direct; +} + + +QString MetaInfo::toID( OutputMethodInfo::Method::Type method ) +{ + switch (method) + { + case OutputMethodInfo::Method::SaveAndLoad: + return "SaveAndLoad"; + + case OutputMethodInfo::Method::SaveAndForget: + return "SaveAndForget"; + + case OutputMethodInfo::Method::Direct: + default: + return "Direct"; + } +} +//END class MetaInfo + + +//BEGIN class FileMetaInfo +FileMetaInfo::FileMetaInfo() + : QObject() +{ + m_metaInfoConfig = new KConfig( "metainfo", false, false, "appdata" ); + loadAllMetaInfo(); +} + + +FileMetaInfo::~FileMetaInfo() +{ + saveAllMetaInfo(); + delete m_metaInfoConfig; +} + + +void FileMetaInfo::grabMetaInfo( const KURL & url, TextDocument * textDocument ) +{ + if (!textDocument) + return; + + m_metaInfoMap[url].setBookmarks( textDocument->bookmarkList() ); + m_metaInfoMap[url].setBreakpoints( textDocument->breakpointList() ); +} + + +void FileMetaInfo::initializeFromMetaInfo( const KURL & url, TextDocument * textDocument ) +{ + if (!textDocument) + return; + + textDocument->setBookmarks(m_metaInfoMap[url].bookmarks()); + textDocument->setBreakpoints(m_metaInfoMap[url].breakpoints()); +} + + +void FileMetaInfo::grabMetaInfo( const KURL & url, TextView * textView ) +{ + if (!textView) + return; + + m_metaInfoMap[url].setCursorLine( textView->currentLine() ); + m_metaInfoMap[url].setCursorColumn( textView->currentColumn() ); +} + + +void FileMetaInfo::initializeFromMetaInfo( const KURL & url, TextView * textView ) +{ + if (!textView) + return; + + textView->setCursorPosition( m_metaInfoMap[url].cursorLine(), m_metaInfoMap[url].cursorColumn() ); +} + + +void FileMetaInfo::grabMetaInfo( const KURL & url, OutputMethodDlg * dlg ) +{ + if (!dlg) + return; + + m_metaInfoMap[url].setOutputMethodInfo( dlg->info() ); +} + + +void FileMetaInfo::initializeFromMetaInfo( const KURL & url, OutputMethodDlg * dlg ) +{ + if ( !dlg || url.isEmpty() || !m_metaInfoMap.contains(url) ) + return; + + OutputMethodInfo::Method::Type method = m_metaInfoMap[url].outputMethodInfo().method(); + dlg->setMethod(method); + + if ( method != OutputMethodInfo::Method::Direct ) + dlg->setOutputFile( m_metaInfoMap[url].outputMethodInfo().outputFile() ); + + dlg->setPicID( m_metaInfoMap[url].outputMethodInfo().picID() ); +} + + +void FileMetaInfo::saveAllMetaInfo() +{ + const MetaInfoMap::iterator end = m_metaInfoMap.end(); + for ( MetaInfoMap::iterator it = m_metaInfoMap.begin(); it != end; ++it ) + { + if ( it.data().hasDefaultData() ) + m_metaInfoConfig->deleteGroup(it.key().prettyURL()); + + else + { + m_metaInfoConfig->setGroup( it.key().prettyURL() ); + it.data().save( m_metaInfoConfig ); + } + } +} + + +void FileMetaInfo::loadAllMetaInfo() +{ + QStringList urlList = m_metaInfoConfig->groupList(); + const QStringList::iterator end = urlList.end(); + for ( QStringList::iterator it = urlList.begin(); it != end; ++it ) + { + m_metaInfoConfig->setGroup(*it); + m_metaInfoMap[*it].load(m_metaInfoConfig); + } +} +//END class FileMetaInfo + +#include "filemetainfo.moc" diff --git a/src/filemetainfo.h b/src/filemetainfo.h new file mode 100644 index 0000000..9004217 --- /dev/null +++ b/src/filemetainfo.h @@ -0,0 +1,143 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef FILEMETAINFO_H +#define FILEMETAINFO_H + +#include "outputmethoddlg.h" + + +class TextDocument; +class TextView; +class KConfig; +typedef QValueList IntList; + +class MetaInfo +{ + public: + MetaInfo(); + + /** + * Returns true if all the data stored is default; and therefore does + * not need saving. + */ + bool hasDefaultData() const; + /** + * Writes to the given config the data stored in here. Does not set the + * group. + */ + void save( KConfig * conf ); + /** + * Reads in the data from the config. Does not set the group. + */ + void load( KConfig * conf ); + + IntList bookmarks() const { return m_bookmarks; } + void setBookmarks( IntList bookmarks ) { m_bookmarks = bookmarks; } + + IntList breakpoints() const { return m_breakpoints; } + void setBreakpoints( IntList breakpoints ) { m_breakpoints = breakpoints; } + + OutputMethodInfo & outputMethodInfo() { return m_outputMethodInfo; } + void setOutputMethodInfo( OutputMethodInfo info ) { m_outputMethodInfo = info; } + + unsigned cursorLine() const { return m_cursorLine; } + void setCursorLine( unsigned line ) { m_cursorLine = line; } + + unsigned cursorColumn() const { return m_cursorColumn; } + void setCursorColumn( unsigned column ) { m_cursorColumn = column; } + + protected: + /** + * Convert the id (e.g. "Direct") to a method, used when reading in the + * config file. + */ + OutputMethodInfo::Method::Type toMethod( const QString & id ); + /** + * Conver the method (e.g. OutputMethodInfo::Method::Direct) to an id + * that can be saved in the config file. + */ + QString toID( OutputMethodInfo::Method::Type method ); + + IntList m_bookmarks; + IntList m_breakpoints; + OutputMethodInfo m_outputMethodInfo; + unsigned m_cursorLine; + unsigned m_cursorColumn; +}; +typedef QMap MetaInfoMap; + +/** +Looks after per-file metainfo; e.g. bookmarks, breakpoints, compiling options, etc + +@author David Saxton +*/ +class FileMetaInfo : public QObject +{ + Q_OBJECT + public: + ~FileMetaInfo(); + + /** + * Initialize the TextDocument with the appropriate stored metainfo - e.g. + * setting the appopriate bookmarks, etc + */ + void initializeFromMetaInfo( const KURL & url, TextDocument * textDocument ); + /** + * Initialize the TextView with the appropriate stored metainfo - e.g. + * setting the appopriate cursor position, etc. + */ + void initializeFromMetaInfo( const KURL & url, TextView * textView ); + /** + * Initialize the OutputMethodDlg with the options the user had selected + * for the last time it was used for the given url. + */ + void initializeFromMetaInfo( const KURL & url, OutputMethodDlg * outputMethodDlg ); + /** + * Get the bookmarks, etc from the given TextDocument, and save them + */ + void grabMetaInfo( const KURL & url, TextDocument * textDocument ); + /** + * Get the cursor position, etc from the given TextView, and save them. + */ + void grabMetaInfo( const KURL & url, TextView * textView ); + /** + * Get the output method et al from the given OutputMethodDlg, and save + * them. + */ + void grabMetaInfo( const KURL & url, OutputMethodDlg * outputMethodDlg ); + /** + * Save all metainfo to disk. + */ + void saveAllMetaInfo(); + + protected: + /** + * Load all metainfo from disk (combining that read in with those already + * loaded) + */ + void loadAllMetaInfo(); + + KConfig *m_metaInfoConfig; + + private: + FileMetaInfo(); + friend inline FileMetaInfo* fileMetaInfo(); + + MetaInfoMap m_metaInfoMap; +}; + +inline FileMetaInfo* fileMetaInfo() +{ + static FileMetaInfo *fmi = new FileMetaInfo(); + return fmi; +} + +#endif diff --git a/src/flowcodedocument.cpp b/src/flowcodedocument.cpp new file mode 100644 index 0000000..ad2c346 --- /dev/null +++ b/src/flowcodedocument.cpp @@ -0,0 +1,308 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasmanipulator.h" +#include "documentiface.h" +#include "drawpart.h" +#include "flowcode.h" +#include "flowcodedocument.h" +#include "flowcodeview.h" +#include "flowpart.h" +#include "itemdocumentdata.h" +#include "languagemanager.h" +#include "microinfo.h" +#include "microlibrary.h" +#include "outputmethoddlg.h" +#include "picitem.h" +#include "programmerdlg.h" + +#include +#include +#include + +FlowCodeDocument::FlowCodeDocument( const QString &caption, KTechlab *ktechlab, const char *name ) + : ICNDocument( caption, ktechlab, name ) +{ + m_pDocumentIface = new FlowCodeDocumentIface(this); + m_type = Document::dt_flowcode; + m_microInfo = 0L; + m_microSettings = 0L; + m_picItem = 0L; + m_pLastTextOutputTarget = 0l; + + m_cmManager->addManipulatorInfo( CMSelect::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMDraw::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMRightClick::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMRepeatedItemAdd::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMItemResize::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMItemDrag::manipulatorInfo() ); + + m_fileExtensionInfo = i18n("*.flowcode|FlowCode (*.flowcode)\n*|All Files"); + requestStateSave(); +} + + +FlowCodeDocument::~FlowCodeDocument() +{ + m_bDeleted = true; + if (m_picItem) + m_picItem->removeItem(); + + delete m_microSettings; + m_microSettings = 0l; + + delete m_pDocumentIface; + m_pDocumentIface = 0l; +} + + +View *FlowCodeDocument::createView( ViewContainer *viewContainer, uint viewAreaId, const char *name ) +{ + View* view = new FlowCodeView( this, viewContainer, viewAreaId, name ); + handleNewView(view); + return view; +} + + +void FlowCodeDocument::setPicType( const QString &id ) +{ + if ( m_microSettings && m_microSettings->microInfo() && m_microSettings->microInfo()->id() == id ) + return; + + MicroInfo *microInfo = MicroLibrary::self()->microInfoWithID(id); + + if ( !microInfo ) + { + kdWarning() << "FlowCodeDocument::setPicType: Could not set the pic type to PIC \""<show(); + + emit picTypeChanged(); +} + + +bool FlowCodeDocument::isValidItem( const QString &itemId ) +{ + return itemId.startsWith("flow/") || itemId.startsWith("dp/"); +} + + +bool FlowCodeDocument::isValidItem( Item *item ) +{ + if ( !dynamic_cast(item) && !dynamic_cast(item) ) + return false; + + if ( !item->id().startsWith("START") && !item->id().startsWith("PPEND") ) + return true; + + const ItemList::iterator ciEnd = m_itemList.end(); + + if ( item->id().startsWith("START") ) + { + int count = 0; + + for ( ItemList::iterator it = m_itemList.begin(); it != ciEnd; ++it ) + { + if ( (*it)->id().startsWith("START") ) + count++; + } + if ( count > 1 ) + return false; + } + + else if ( item->id().startsWith("PPEND") ) + { + int count = 0; + for ( ItemList::iterator it = m_itemList.begin(); it != ciEnd; ++it ) + { + if ( (*it)->id().startsWith("PPEND") ) + count++; + } + if ( count > 1 ) + return false; + } + + return true; +} + + +void FlowCodeDocument::setLastTextOutputTarget( TextDocument * target ) +{ + m_pLastTextOutputTarget = target; +} + + +void FlowCodeDocument::slotConvertTo( int target ) +{ + switch ( (ConvertToTarget)target ) + { + case FlowCodeDocument::MicrobeOutput: + convertToMicrobe(); + break; + + case FlowCodeDocument::AssemblyOutput: + convertToAssembly(); + break; + + case FlowCodeDocument::HexOutput: + convertToHex(); + break; + + case FlowCodeDocument::PICOutput: + convertToPIC(); + break; + } +} + + +void FlowCodeDocument::convertToMicrobe() +{ + OutputMethodDlg *dlg = new OutputMethodDlg( i18n("Microbe Code Output"), url(), false, activeView() ); + dlg->setOutputExtension(".microbe"); + dlg->setFilter("*.microbe|Microbe (*.microbe)\n*|All Files"); + dlg->exec(); + if (!dlg->isAccepted()) + { + delete dlg; + return; + } + + ProcessOptions o( dlg->info() ); + o.setTextOutputTarget( m_pLastTextOutputTarget, this, SLOT(setLastTextOutputTarget( TextDocument* )) ); + o.p_flowCodeDocument = this; + o.setProcessPath( ProcessOptions::ProcessPath::FlowCode_Microbe ); + LanguageManager::self()->compile(o); + + delete dlg; +} + + +void FlowCodeDocument::convertToAssembly() +{ + OutputMethodDlg *dlg = new OutputMethodDlg( i18n("Assembly Code Output"), url(), false, activeView() ); + dlg->setOutputExtension(".asm"); + dlg->setFilter("*.asm *.src *.inc|Assembly Code (*.asm, *.src, *.inc)\n*|All Files"); + dlg->exec(); + if (!dlg->isAccepted()) + { + delete dlg; + return; + } + + ProcessOptions o( dlg->info() ); + o.setTextOutputTarget( m_pLastTextOutputTarget, this, SLOT(setLastTextOutputTarget( TextDocument* )) ); + o.p_flowCodeDocument = this; + o.setProcessPath( ProcessOptions::ProcessPath::FlowCode_AssemblyAbsolute ); + LanguageManager::self()->compile(o); + + delete dlg; +} + + +void FlowCodeDocument::convertToHex() +{ + OutputMethodDlg *dlg = new OutputMethodDlg( i18n("Hex Code Output"), url(), false, (QWidget*)p_ktechlab ); + dlg->setOutputExtension(".hex"); + dlg->setFilter("*.hex|Hex (*.hex)\n*|All Files"); + dlg->exec(); + if (!dlg->isAccepted()) + { + delete dlg; + return; + } + + ProcessOptions o( dlg->info() ); + o.setTextOutputTarget( m_pLastTextOutputTarget, this, SLOT(setLastTextOutputTarget( TextDocument* )) ); + o.p_flowCodeDocument = this; + o.setProcessPath( ProcessOptions::ProcessPath::FlowCode_Program ); + LanguageManager::self()->compile(o); + + delete dlg; +} + + +void FlowCodeDocument::convertToPIC() +{ + ProgrammerDlg * dlg = new ProgrammerDlg( microSettings()->microInfo()->id(), (QWidget*)p_ktechlab, "Programmer Dlg" ); + dlg->exec(); + if ( !dlg->isAccepted() ) + { + dlg->deleteLater(); + return; + } + + ProcessOptions o; + dlg->initOptions( & o ); + o.p_flowCodeDocument = this; + o.setProcessPath( ProcessOptions::ProcessPath::FlowCode_PIC ); + LanguageManager::self()->compile( o ); + + dlg->deleteLater(); +} + + +void FlowCodeDocument::varNameChanged( const QString &newValue, const QString &oldValue ) +{ + if (m_bDeleted) + return; + + // Decrease the old variable count + // If none are left after, remove it from microsettings + StringIntMap::iterator it = m_varNames.find(oldValue); + if ( it != m_varNames.end() ) + { + --(it.data()); + if ( it.data() <= 0 ) + { + VariableInfo *info = microSettings()->variableInfo(it.key()); + if ( info && !info->permanent ) microSettings()->deleteVariable(oldValue); + m_varNames.erase(it); + } + } + + // Add the new variable to a count, tell microsettings about it if it is new + if ( !newValue.isEmpty() ) + { + it = m_varNames.find(newValue); + if ( it != m_varNames.end() ) { + ++it.data(); + } else { + m_varNames[newValue] = 1; + microSettings()->setVariable( newValue, QVariant(), false ); + } + } + + // Tell all FlowParts to update their variable lists + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + if ( FlowPart *flowPart = dynamic_cast((Item*)(*it)) ) + flowPart->updateVarNames(); + } +} + + +#include "flowcodedocument.moc" diff --git a/src/flowcodedocument.h b/src/flowcodedocument.h new file mode 100644 index 0000000..bb28ae4 --- /dev/null +++ b/src/flowcodedocument.h @@ -0,0 +1,100 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef FLOWCODEDOCUMENT_H +#define FLOWCODEDOCUMENT_H + +#include "icndocument.h" + +#include + +class KTechlab; +class FlowCode; +class MicroInfo; +class PicItem; +class FlowPart; +class MicroSettings; +class TextDocument; +class QString; + +typedef QValueList FlowPartList; +typedef QMap StringIntMap; + +/** +@short View for editing FlowCode +@author David Saxton +*/ +class FlowCodeDocument : public ICNDocument +{ + Q_OBJECT + public: + FlowCodeDocument( const QString &caption, KTechlab *ktechlab, const char *name = 0L); + ~FlowCodeDocument(); + + virtual View *createView( ViewContainer *viewContainer, uint viewAreaId, const char *name = 0l ); + + /** + * Returns a pointer used for the MicroSettings in this FlowCode document + */ + MicroSettings *microSettings() const { return m_microSettings; } + /** + * Sets the type of PIC to be used. FlowCodeDocument se + virtual void convertToMicrobe();ts the internal MicroInfo pointer to that + * returned by MicroLibrary for the given id. The pic type must be set before anything useful + * (such as compilage) can be done. + */ + void setPicType( const QString &id ); + + enum ConvertToTarget + { + MicrobeOutput, + AssemblyOutput, + HexOutput, + PICOutput + }; + +#define protected public + signals: + void picTypeChanged(); +#undef protected + + signals: + void pinMappingsChanged(); + + public slots: + /** + * @param target as ConvertToTarget + */ + void slotConvertTo( int target ); + void convertToMicrobe(); + void convertToAssembly(); + void convertToHex(); + void convertToPIC(); + /** + * Called when a variable name has changed (from an entry box) + */ + void varNameChanged( const QString &newValue, const QString &oldValue ); + + protected: + virtual bool isValidItem( Item *item ); + virtual bool isValidItem( const QString &itemId ); + + private slots: + void setLastTextOutputTarget( TextDocument * target ); + + private: + QGuardedPtr m_pLastTextOutputTarget; + MicroInfo *m_microInfo; // Stores information about the PIC + MicroSettings *m_microSettings; // Stores initial settings of the PIC + PicItem *m_picItem; // Allows the user to change the PIC settings + StringIntMap m_varNames; +}; + +#endif diff --git a/src/flowcodeview.cpp b/src/flowcodeview.cpp new file mode 100644 index 0000000..8f3cfd1 --- /dev/null +++ b/src/flowcodeview.cpp @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "flowcodedocument.h" +#include "flowcodeview.h" +#include "ktechlab.h" +#include "viewiface.h" + +#include +#include +#include +#include + +FlowCodeView::FlowCodeView( FlowCodeDocument * flowCodeDocument, ViewContainer *viewContainer, uint viewAreaId, const char *name ) + : ICNView( flowCodeDocument, viewContainer, viewAreaId, name ) +{ + KActionCollection * ac = actionCollection(); + + //BEGIN Convert To * Actions + KToolBarPopupAction * pa = new KToolBarPopupAction( i18n("Convert to ..."), "fork", 0, 0, 0, ac, "program_convert" ); + pa->setDelayed(false); + + KPopupMenu * m = pa->popupMenu(); + + m->insertTitle( i18n("Convert to") ); + m->insertItem( KGlobal::iconLoader()->loadIcon( "convert_to_microbe", KIcon::Small ), i18n("Microbe"), FlowCodeDocument::MicrobeOutput ); + m->insertItem( KGlobal::iconLoader()->loadIcon( "convert_to_assembly", KIcon::Small ), i18n("Assembly"), FlowCodeDocument::AssemblyOutput ); + m->insertItem( KGlobal::iconLoader()->loadIcon( "convert_to_hex", KIcon::Small ), i18n("Hex"), FlowCodeDocument::HexOutput ); + m->insertItem( KGlobal::iconLoader()->loadIcon( "convert_to_pic", KIcon::Small ), i18n("PIC (upload)"), FlowCodeDocument::PICOutput ); + connect( m, SIGNAL(activated(int)), flowCodeDocument, SLOT(slotConvertTo(int)) ); + //END Convert To * Actions + + + + +// new KAction( i18n("Convert to Microbe"), "convert_to_microbe", Qt::Key_F7, flowCodeDocument, SLOT(convertToMicrobe()), ac, "tools_to_microbe" ); +// new KAction( i18n("Convert to Assembly"), "convert_to_assembly", Qt::Key_F8, flowCodeDocument, SLOT(convertToAssembly()), ac, "tools_to_assembly" ); +// new KAction( i18n("Convert to Hex"), "convert_to_hex", Qt::Key_F9, flowCodeDocument, SLOT(convertToHex()), ac, "tools_to_hex" ); +// new KAction( i18n("Upload PIC Program"), "convert_to_pic", 0, flowCodeDocument, SLOT(convertToPIC()), ac, "tools_to_pic" ); + + + + + setXMLFile( "ktechlabflowcodeui.rc", true ); + + QWhatsThis::add( this, i18n( + "Construct a FlowCode document by dragging FlowParts from the list on the left. All FlowCharts require an initial \"Start\" part, of which there can only be one.

    " + + "Some FlowParts, such as Subroutines, act as a container element for other FlowParts. Drag the items in or out of a container as appropritate. The container that will become the parent of the part being dragged is indicated by being selected.

    " + + "Note that connections cannot be made between FlowParts in different containers, or at different levels." + ) ); + + m_pViewIface = new FlowCodeViewIface(this); +} + + +FlowCodeView::~FlowCodeView() +{ + delete m_pViewIface; + m_pViewIface = 0l; +} + + + +void FlowCodeView::dragEnterEvent( QDragEnterEvent * e ) +{ + ICNView::dragEnterEvent(e); + if ( e->isAccepted() ) + return; + + e->accept( e->provides("ktechlab/flowpart") ); +} + +#include "flowcodeview.moc" diff --git a/src/flowcodeview.h b/src/flowcodeview.h new file mode 100644 index 0000000..7641e2a --- /dev/null +++ b/src/flowcodeview.h @@ -0,0 +1,33 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef FLOWCODEVIEW_H +#define FLOWCODEVIEW_H + +#include + +class FlowCodeDocument; + +/** +@author David Saxton +*/ +class FlowCodeView : public ICNView +{ + Q_OBJECT + public: + FlowCodeView( FlowCodeDocument *flowCodeDocument, ViewContainer *viewContainer, uint viewAreaId, const char *name = 0l ); + ~FlowCodeView(); + + protected: + virtual void dragEnterEvent( QDragEnterEvent * e ); + FlowCodeDocument *p_flowCodeDocument; +}; + +#endif diff --git a/src/flowcontainer.cpp b/src/flowcontainer.cpp new file mode 100644 index 0000000..32eb20e --- /dev/null +++ b/src/flowcontainer.cpp @@ -0,0 +1,407 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasitemparts.h" +#include "cells.h" +#include "icndocument.h" +#include "flowcontainer.h" +#include "fpnode.h" +#include "nodegroup.h" +#include "resizeoverlay.h" + +#include +#include + +#include + +const int topStrip = 24; +const int botStrip = 16; + +FlowContainer::FlowContainer( ICNDocument *_icnDocument, bool newItem, const QString &id ) + : FlowPart( _icnDocument, newItem, id ) +{ + m_ext_in = m_int_in = m_int_out = m_ext_out = 0l; + b_expanded = true; + + addButton( "expandBtn", QRect( offsetX(), offsetY()+24 - 11, 22, 22 ), KGlobal::iconLoader()->loadIcon( "down", KIcon::Small ), true ); + m_rectangularOverlay = new RectangularOverlay( this, 8, 8 ); + setSize( -160, -120, 320, 240 ); + + + m_int_in = (FPNode*)createNode( width()/2, 8+topStrip, Node::dir_down, "int_in", Node::fp_out ); + m_int_out = (FPNode*)createNode( width()/2, height()-8-botStrip, Node::dir_up, "int_out", Node::fp_in ); + + button("expandBtn")->setState(true); + + updateAttachedPositioning(); + updateNodeLevels(); +} + + +FlowContainer::~FlowContainer() +{ +} + + +void FlowContainer::updateNodeLevels() +{ + FlowPart::updateNodeLevels(); + + int l = level(); + + if (m_ext_in) + m_ext_in->setLevel(l); + if (m_ext_out) + m_ext_out->setLevel(l); + + if (m_int_in) + m_int_in->setLevel(l+1); + if (m_int_out) + m_int_out->setLevel(l+1); +} + + +void FlowContainer::filterEndPartIDs( QStringList *ids ) +{ + // Remove *all* nodes except for very bottom one + if (m_int_out) { + ids->remove(m_int_out->childId()); + } + if (m_ext_in) { + ids->remove(m_ext_in->childId()); + } + if (m_int_in) { + ids->remove(m_int_in->childId()); + } +} + + +void FlowContainer::createTopContainerNode() +{ + m_ext_in = (FPNode*)createNode( width()/2, -8, Node::dir_up, "ext_in", Node::fp_in ); + m_ext_in->setLevel( level() ); + m_rectangularOverlay->removeTopMiddle(); + updateAttachedPositioning(); +} + + +void FlowContainer::createBotContainerNode() +{ + m_ext_out = (FPNode*)createNode( width()/2, height()+8, Node::dir_down, "ext_out", Node::fp_out ); + m_ext_out->setLevel( level() ); + m_rectangularOverlay->removeBotMiddle(); + updateAttachedPositioning(); +} + + +QSize FlowContainer::minimumSize() const +{ + return QSize( 160, 64 ); +} + + +void FlowContainer::drawShape( QPainter &p ) +{ + if (b_deleted) + return; + + if ( !m_sizeRect.isValid() ) + return; + + const int _x = (int)x()+offsetX(); + const int _y = (int)y()+offsetY(); + + int col = 0xef + level()*0x6; + if ( col > 0xff ) col = 0xff; + p.setBrush( QColor( col, 0xff, col ) ); + if( b_expanded ) + { + p.setPen(Qt::DotLine); + p.drawRoundRect( _x, _y, width(), topStrip, 1500/width(), 1500/topStrip ); + p.drawRoundRect( _x, _y+height()-botStrip, width(), botStrip, 1500/width(), 1500/botStrip ); + } + else + { + p.setPen(QPen((isSelected()?m_selectedCol:Qt::black),1,Qt::SolidLine)); + p.drawRoundRect( _x, _y, width(), topStrip, 1500/width(), 1500/topStrip ); + } + + p.setPen( Qt::black ); + p.setFont( font() ); + p.drawText( QRect( 22 + _x+8, _y, width()-8, topStrip ), Qt::AlignLeft | Qt::AlignVCenter, m_caption ); + + if( b_expanded ) + { + p.setPen(Qt::SolidLine); + p.setBrush( Qt::NoBrush ); + p.drawRoundRect( _x, _y, width(), height(), 1500/width(), 1500/height() ); + } +} + + +void FlowContainer::childAdded( Item *child ) +{ + if (!child) + return; + + FlowPart::childAdded(child); + + connect( this, SIGNAL(movedBy(double, double )), child, SLOT(moveBy(double, double )) ); + child->setZ( ICNDocument::Z::Item + child->level() ); + + updateContainedVisibility(); +} + + +void FlowContainer::childRemoved( Item *child ) +{ + FlowPart::childRemoved(child); + + if (!b_expanded) + child->setVisible(true); + + disconnect( this, SIGNAL(movedBy(double, double )), child, SLOT(moveBy(double, double )) ); +} + + +void FlowContainer::updateConnectorPoints( bool add ) +{ + if ( b_deleted || !isVisible() ) + add = false; + + if ( b_pointsAdded == add ) + return; + + b_pointsAdded = add; + + Cells *cells = p_icnDocument->cells(); + if (!cells) return; + + int _x = (int)x()+offsetX(); + int _y = (int)y()+offsetY(); + int w = width(); + int h = b_expanded ? height() : topStrip; + + const int mult = add ? 1 : -1; + + // Top strip + for ( int y=_y; y <_y+24; ++y ) + { + for ( int x = _x; x<=_x+w; x += 8 ) + { + if ( p_icnDocument->isValidCellReference( x/8, y/8 ) ) + { + (*cells)[x/8][y/8].CIpenalty += mult*ICNDocument::hs_item; + } + } + } + + // Bottom strip + for ( int y = _y+h-16; y <= _y+h; ++y ) + { + for ( int x = _x; x<=_x+width(); x += 8 ) + { + if ( p_icnDocument->isValidCellReference( x/8, y/8 ) ) + { + (*cells)[x/8][y/8].CIpenalty += mult*ICNDocument::hs_item; + } + } + } + + // Left strip + int x = _x; + for ( int y = _y+24; y<_y+h-16; y += 8 ) + { + if ( p_icnDocument->isValidCellReference( x/8, y/8 ) ) + { + (*cells)[x/8][y/8].CIpenalty += mult*ICNDocument::hs_item; + } + } + + // Right strip + x = _x+width(); + for ( int y = _y+24; y<_y+h-16; y += 8 ) + { + if ( p_icnDocument->isValidCellReference( x/8, y/8 ) ) + { + (*cells)[x/8][y/8].CIpenalty += mult*ICNDocument::hs_item; + } + } +} + + +void FlowContainer::setFullBounds( bool full ) +{ + if ( full || !b_expanded ) + { + QRect bounds = b_expanded ? m_sizeRect : QRect( m_sizeRect.x(), m_sizeRect.y(), m_sizeRect.width(), topStrip ); + setPoints( QPointArray(bounds) ); + return; + } + +// kdDebug() << k_funcinfo << "width="<setGuiPartSize( 22, 22 ); + button("expandBtn")->move( int(x())+offsetX()+7, int(y())+offsetY()+1 ); +} + + +void FlowContainer::updateContainedVisibility() +{ + if (b_deleted) + return; + + if (m_ext_in) + m_ext_in->setVisible( isVisible() ); + if (m_int_in) + m_int_in->setVisible( isVisible() && b_expanded ); + if (m_int_out) + m_int_out->setVisible( isVisible() && b_expanded ); + if (m_ext_out) + m_ext_out->setVisible( isVisible() ); + + const ItemList::iterator cEnd = m_children.end(); + for ( ItemList::iterator it = m_children.begin(); it != cEnd; ++it ) + { + if (*it) + (*it)->setVisible( isVisible() && b_expanded ); + } + + m_rectangularOverlay->setVisible( isVisible() && b_expanded ); + + NodeGroupList hidableNodeGroups; + p_icnDocument->getTranslatable( children(true) += GuardedItem(this), 0, 0, &hidableNodeGroups ); + + NodeGroupList::iterator hngEnd = hidableNodeGroups.end(); + for ( NodeGroupList::iterator it = hidableNodeGroups.begin(); it != hngEnd; ++it ) + (*it)->setVisible(b_expanded); +} + + +void FlowContainer::setVisible( bool yes ) +{ + if (b_deleted) + { + FlowPart::setVisible(false); + return; + } + + FlowPart::setVisible(yes); + updateContainedVisibility(); +} + +#include "flowcontainer.moc" diff --git a/src/flowcontainer.h b/src/flowcontainer.h new file mode 100644 index 0000000..9afa401 --- /dev/null +++ b/src/flowcontainer.h @@ -0,0 +1,78 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef FLOWCONTAINER_H +#define FLOWCONTAINER_H + +#include "flowpart.h" + +class RectangularOverlay; + +/** +@author David Saxton +*/ +class FlowContainer : public FlowPart +{ +Q_OBJECT +public: + FlowContainer( ICNDocument *_icnView, bool newItem, const QString &id ); + virtual ~FlowContainer(); + + virtual bool canResize() const { return true; } + /** + * Sets the bound to a simple rectangle if true, so that ICNDocument + * can tell whether an item is being dropped into it + */ + void setFullBounds( bool full ); + + virtual void updateConnectorPoints( bool add = true ); + /** + * Returns whether the container is currently expanded or not + */ + bool isExpanded() const { return b_expanded; } + /** + * Returns true if one of this parents is collapsed. + */ + bool parentIsCollapsed() const; + void setExpanded( bool expanded ); + + virtual void setSelected( bool yes ); + virtual void setVisible( bool yes ); + + virtual QSize minimumSize() const; + /** + * Update the visibility of items, connectors, nodes in the flowcontainer + */ + void updateContainedVisibility(); + +protected: + virtual void itemPointsChanged() {}; + virtual void updateNodeLevels(); + virtual void childAdded( Item *child ); + virtual void childRemoved( Item *child ); + virtual void updateAttachedPositioning(); + virtual void postResize(); + virtual void filterEndPartIDs( QStringList *ids ); + virtual void drawShape( QPainter &p ); + void createTopContainerNode(); + void createBotContainerNode(); + + virtual void buttonStateChanged(const QString &id, bool state); + + FPNode *m_ext_in; + FPNode *m_int_in; + FPNode *m_int_out; + FPNode *m_ext_out; + RectangularOverlay *m_rectangularOverlay; + + bool b_expanded; +}; + +#endif diff --git a/src/flowparts/Makefile.am b/src/flowparts/Makefile.am new file mode 100644 index 0000000..44e89fa --- /dev/null +++ b/src/flowparts/Makefile.am @@ -0,0 +1,15 @@ +INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/electronics \ + -I$(top_srcdir)/src/electronics/components -I$(top_srcdir)/src/gui -I$(top_srcdir)/src/languages \ + -I$(top_srcdir)/src/micro $(all_includes) +METASOURCES = AUTO +noinst_LTLIBRARIES = libflowparts.la +noinst_HEADERS = callsub.h delay.h end.h forloop.h readport.h setpin.h start.h \ + testpin.h unary.h varassignment.h varcomparison.h writeport.h repeat.h while.h \ + sub.h inputbutton.h flowpart.h pinmapping.h +libflowparts_la_SOURCES = callsub.cpp delay.cpp end.cpp forloop.cpp \ + readport.cpp setpin.cpp start.cpp testpin.cpp unary.cpp varassignment.cpp \ + varcomparison.cpp writeport.cpp repeat.cpp while.cpp sub.cpp count.cpp embed.cpp \ + interrupt.cpp keypad.cpp pulse.cpp sevenseg.cpp inputbutton.cpp flowpart.cpp \ + pinmapping.cpp + +libflowparts_la_PCH = AUTO diff --git a/src/flowparts/callsub.cpp b/src/flowparts/callsub.cpp new file mode 100644 index 0000000..8487ed0 --- /dev/null +++ b/src/flowparts/callsub.cpp @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "callsub.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* CallSub::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new CallSub( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* CallSub::libraryItem() +{ + return new LibraryItem( + QString("flow/callsub"), + i18n("Sub Call"), + i18n("Common"), + "subcall.png", + LibraryItem::lit_flowpart, + CallSub::construct ); +} + +CallSub::CallSub( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "callsub" ) +{ + m_name = i18n("Sub Call"); + m_desc = i18n("Call a subroutine. When the subroutine returns, the code will continue execution from this point."); + initCallSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "sub", Variant::Type::Combo ); + property("sub")->setCaption( i18n("Subroutine") ); + property("sub")->setValue("MySub"); +} + +CallSub::~CallSub() +{ +} + +void CallSub::dataChanged() +{ + setCaption( i18n("Call %1").arg(dataString("sub")) ); +} + +void CallSub::generateMicrobe( FlowCode *code ) +{ + code->addCode( "call " + dataString("sub") ); + code->addCodeBranch( outputPart("stdoutput" ) ); +} + diff --git a/src/flowparts/callsub.h b/src/flowparts/callsub.h new file mode 100644 index 0000000..5cba4f2 --- /dev/null +++ b/src/flowparts/callsub.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef CALLSUB_H +#define CALLSUB_H + +#include "flowpart.h" + +/** +@short FlowPart that calls a subroutine +@author David Saxton +*/ +class CallSub : public FlowPart +{ +public: + CallSub( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~CallSub(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +private: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/count.cpp b/src/flowparts/count.cpp new file mode 100644 index 0000000..dc0281f --- /dev/null +++ b/src/flowparts/count.cpp @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "count.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* Count::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Count( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Count::libraryItem() +{ + return new LibraryItem( + QString::QString("flow/count"), + i18n("Count"), + i18n("Functions"), + "ppcount.png", + LibraryItem::lit_flowpart, + Count::construct ); +} + +Count::Count( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "count" ) +{ + m_name = i18n("Count"); + m_desc = i18n("Count the number of pulses during a fixed interval. To avoid ambiguity, this increments the counter on either a rising or falling edge, as opposed to a high or a low."); + initProcessSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "0-trigger", Variant::Type::Select ); + property("0-trigger")->setAllowed( QStringList::split(',',"rising,falling") ); + property("0-triger")->setValue("rising"); + property("0-trigger")->setCaption( i18n("Trigger") ); + + createProperty( "1-length", Variant::Type::Double ); + property("1-length")->setUnit("sec"); + property("1-length")->setValue(10.0); + property("1-length")->setCaption("Interval"); +} + +Count::~Count() +{ +} + +void Count::dataChanged() +{ + double count = dataDouble("1-length"); + setCaption( i18n("Count %1 for %2 sec").arg(dataString("0-trigger")).arg(QString::number( count / getMultiplier(count), 'g', 3 ) + getNumberMag(count)) ); +} + +void Count::generateMicrobe( FlowCode *code ) +{ + const double count_ms = dataDouble("1-length")*1e3; + code->addCode( "count "+dataString("0-trigger")+" for "+QString::number(count_ms)+"ms" ); + code->addCodeBranch( outputPart("stdoutput") ); +} + diff --git a/src/flowparts/count.h b/src/flowparts/count.h new file mode 100644 index 0000000..516889d --- /dev/null +++ b/src/flowparts/count.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef COUNT_H +#define COUNT_H + +#include "flowpart.h" + +/** +@short FlowPart that provides a delay +@author David Saxton +*/ +class Count : public FlowPart +{ +public: + Count( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Count(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/delay.cpp b/src/flowparts/delay.cpp new file mode 100644 index 0000000..fa37770 --- /dev/null +++ b/src/flowparts/delay.cpp @@ -0,0 +1,136 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "delay.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* Delay::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Delay( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Delay::libraryItem() +{ + return new LibraryItem( + QString::QString("flow/delay"), + i18n("Delay"), + i18n("Functions"), + "delay.png", + LibraryItem::lit_flowpart, + Delay::construct ); +} + +Delay::Delay( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "delay" ) +{ + m_name = i18n("Delay"); + m_desc = i18n("Delay the program execution for a fixed period of time."); + initProcessSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "delay_length", Variant::Type::Double ); + property("delay_length")->setCaption( i18n("Pause Length") ); + property("delay_length")->setUnit("sec"); + property("delay_length")->setValue(1.0); +} + +Delay::~Delay() +{ +} + +void Delay::dataChanged() +{ + double delay = dataDouble("delay_length"); + setCaption( i18n("Delay for %1 sec").arg(QString::number( delay / getMultiplier(delay), 'g', 3 )+getNumberMag(delay)) ); +} + +void Delay::generateMicrobe( FlowCode *code ) +{ + const double delayLength_ms = dataDouble("delay_length")*1e3; + code->addCode( "delay "+QString::number(delayLength_ms) ); + code->addCodeBranch( outputPart("stdoutput") ); + +// code->addVariable("COUNT_REPEAT"); + +#if 0 + // Code for pauses less than 769uS + if ( pauseLength < 769 ) + { + code->addCodeBlock( id(), "movlw " + QString::number(pauseLength/3) + "\n" + "movwf COUNT_REPEAT\n" + "call count_3uS\n" + + gotoCode("stdoutput") ); + + code->addCodeBlock( "count_3uS", "decfsz COUNT_REPEAT,1\n" + "goto count_3uS\n" + "return" ); + } + else if ( pauseLength < 196609 ) + { + code->addVariable("COUNT_LOOP_1"); + + code->addCodeBlock( id(), "movlw " + QString::number(pauseLength/(3*256)) + "\n" + "movwf COUNT_REPEAT\n" + "call count_768uS\n" + + gotoCode("stdoutput") ); + + code->addCodeBlock( "count_768uS", "decfsz COUNT_LOOP_1,1\n" + "goto count_768uS\n" + "decfsz COUNT_REPEAT,1\n" + "goto count_768uS\n" + "return" ); + } + else if ( pauseLength < 50331649 ) + { + code->addVariable("COUNT_LOOP_1"); + code->addVariable("COUNT_LOOP_2"); + + code->addCodeBlock( id(), "movlw " + QString::number(pauseLength/(3*256*256)) + "\n" + "movwf COUNT_REPEAT\n" + "call count_200mS\n" + + gotoCode("stdoutput") ); + + code->addCodeBlock( "count_200mS", "decfsz COUNT_LOOP_1,1\n" + "goto count_200mS\n" + "decfsz COUNT_LOOP_2,1\n" + "goto count_200mS\n" + "decfsz COUNT_REPEAT,1\n" + "goto count_200mS\n" + "return" ); + } + else/* if ( pauseLength < 12884901889 )*/ + { + code->addVariable("COUNT_LOOP_1"); + code->addVariable("COUNT_LOOP_2"); + code->addVariable("COUNT_LOOP_3"); + + code->addCodeBlock( id(), "movlw " + QString::number(pauseLength/(3*256*256*256)) + "\n" + "movwf COUNT_REPEAT\n" + "call count_50S\n" + + gotoCode("stdoutput") ); + + code->addCodeBlock( "count_50S", "decfsz COUNT_LOOP_1,1\n" + "goto count_50S\n" + "decfsz COUNT_LOOP_2,1\n" + "goto count_50S\n" + "decfsz COUNT_LOOP_3,1\n" + "goto count_50S\n" + "decfsz COUNT_REPEAT,1\n" + "goto count_50S\n" + "return" ); + } +#endif +} + diff --git a/src/flowparts/delay.h b/src/flowparts/delay.h new file mode 100644 index 0000000..fbe6326 --- /dev/null +++ b/src/flowparts/delay.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef DELAY_H +#define DELAY_H + +#include "flowpart.h" + +/** +@short FlowPart that provides a delay +@author David Saxton +*/ +class Delay : public FlowPart +{ +public: + Delay( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Delay(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/embed.cpp b/src/flowparts/embed.cpp new file mode 100644 index 0000000..ca04c65 --- /dev/null +++ b/src/flowparts/embed.cpp @@ -0,0 +1,87 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "embed.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* Embed::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Embed( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Embed::libraryItem() +{ + return new LibraryItem( + QString::QString("flow/embed"), + i18n("Embed"), + i18n("Common"), + "embed.png", + LibraryItem::lit_flowpart, + Embed::construct + ); +} + +Embed::Embed( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "embed" ) +{ + m_name = i18n("Embed"); + m_desc = i18n("Doubleclick on the item to edit the embedded code."); + initProcessSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "type", Variant::Type::Select ); + property("type")->setAllowed( QStringList::split( ',', "Microbe,Assembly" ) ); + property("type")->setValue("Microbe"); + property("type")->setCaption( i18n("Type") ); // TODO: replace this with i18n( "the type", "Type" ); + + createProperty( "code", Variant::Type::Multiline ); + property("code")->setCaption( i18n("Code") ); + property("code")->setValue( i18n("// Embedded code:") ); +} + +Embed::~Embed() +{ +} + + +void Embed::dataChanged() +{ + const QString sample = dataString("code").left(10).replace("\n"," "); + setCaption( i18n("%1: %2...").arg(dataString("type")).arg(sample) ); +} + + +bool Embed::typeIsMicrobe() const +{ + return dataString("type") == "Microbe"; +} + + +void Embed::generateMicrobe( FlowCode *code ) +{ + if ( typeIsMicrobe() ) + code->addCode( dataString("code") ); + + else + { + // Is assembly code, we need to microbe as such + code->addCode("asm\n{"); + code->addCode( dataString("code") ); + code->addCode("}"); + } + + code->addCodeBranch( outputPart("stdoutput") ); +} + diff --git a/src/flowparts/embed.h b/src/flowparts/embed.h new file mode 100644 index 0000000..d891c39 --- /dev/null +++ b/src/flowparts/embed.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef EMBED_H +#define EMBED_H + +#include "flowpart.h" + +/** +@short FlowPart that provides a delay +@author David Saxton +*/ +class Embed : public FlowPart +{ +public: + Embed( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Embed(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + bool typeIsMicrobe() const; + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/end.cpp b/src/flowparts/end.cpp new file mode 100644 index 0000000..37d7e91 --- /dev/null +++ b/src/flowparts/end.cpp @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "end.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* End::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new End( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* End::libraryItem() +{ + return new LibraryItem( + QString("flow/end"), + i18n("End"), + i18n("Common"), + "end.png", + LibraryItem::lit_flowpart, + End::construct ); +} + +End::End( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "END" ) +{ + m_name = i18n("End"); + m_desc = i18n("End the program execution, putting the IC into sleep. Unlike Start, however, this FlowPart is not necessary for proper program execution"); + initRoundedRectSymbol(); + createStdInput(); + setCaption( i18n("End") ); +} + +End::~End() +{ +} + +void End::generateMicrobe( FlowCode */*code*/ ) +{ +} + diff --git a/src/flowparts/end.h b/src/flowparts/end.h new file mode 100644 index 0000000..a2c2a1e --- /dev/null +++ b/src/flowparts/end.h @@ -0,0 +1,32 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef END_H +#define END_H + +#include "flowpart.h" + +/** +@short FlowPart that tells the program where to end +@author David Saxton +*/ +class End : public FlowPart +{ +public: + End( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~End(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode * ); +}; + +#endif diff --git a/src/flowparts/flowpart.cpp b/src/flowparts/flowpart.cpp new file mode 100644 index 0000000..e12213c --- /dev/null +++ b/src/flowparts/flowpart.cpp @@ -0,0 +1,977 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasitemparts.h" +#include "connector.h" +#include "flowcodedocument.h" +#include "flowcode.h" +#include "flowpart.h" +#include "fpnode.h" +#include "itemdocument.h" +#include "itemdocumentdata.h" +#include "microsettings.h" +#include "micropackage.h" +#include "picinfo.h" +#include "pinmapping.h" +#include "variant.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +// The following arrays of numbers represent the positions of nodes in different configurations, +// with the numbers as NodeInfo::Position. + +Node::node_dir diamondNodePositioning[8][3] = { + {Node::dir_up, Node::dir_down, Node::dir_right}, + {Node::dir_up, Node::dir_down, Node::dir_left}, + {Node::dir_up, Node::dir_right,Node::dir_down}, + {Node::dir_up, Node::dir_right,Node::dir_left}, + {Node::dir_left,Node::dir_right,Node::dir_down}, + {Node::dir_left,Node::dir_right,Node::dir_up}, + {Node::dir_left,Node::dir_down, Node::dir_right}, + {Node::dir_left,Node::dir_down, Node::dir_up} }; + +Node::node_dir inOutNodePositioning[8][2] = { + {Node::dir_up,Node::dir_down}, + {Node::dir_up,Node::dir_right}, + {Node::dir_up,Node::dir_left}, + {Node::dir_right,Node::dir_right}, // (invalid) + {Node::dir_left,Node::dir_right}, + {Node::dir_left,Node::dir_down}, + {Node::dir_left,Node::dir_up}, + {Node::dir_right,Node::dir_right} }; // (invalid) + +Node::node_dir inNodePositioning[4] = {Node::dir_up,Node::dir_right,Node::dir_down,Node::dir_left}; + +Node::node_dir outNodePositioning[4] = {Node::dir_down,Node::dir_left,Node::dir_up,Node::dir_right}; + +FlowPart::FlowPart( ICNDocument *icnDocument, bool newItem, const QString &id ) + : CNItem( icnDocument, newItem, id ) +{ + icnDocument->registerItem(this); + m_pFlowCodeDocument = dynamic_cast(icnDocument); + assert( m_pFlowCodeDocument ); + + m_flowSymbol = FlowPart::ps_other; + m_orientation = 0; + m_stdInput = 0l; + m_stdOutput = 0l; + m_altOutput = 0l; + + connect( m_pFlowCodeDocument, SIGNAL(picTypeChanged()), this, SLOT(slotUpdateFlowPartVariables()) ); + connect( m_pFlowCodeDocument, SIGNAL(pinMappingsChanged()), this, SLOT(slotUpdateFlowPartVariables()) ); +} + + +FlowPart::~FlowPart() +{ + // We have to check view, as if the item is deleted before the CNItem constructor + // is called, then there will be no view + if (m_pFlowCodeDocument) + { + const VariantDataMap::iterator end = m_variantData.end(); + for ( VariantDataMap::iterator it = m_variantData.begin(); it != end; ++it ) + { + Variant *v = it.data(); + if (v) + m_pFlowCodeDocument->varNameChanged( "", v->value().toString() ); + } + } +} + + +void FlowPart::setCaption( const QString &caption ) +{ + if ( m_flowSymbol == FlowPart::ps_other ) + { + m_caption = caption; + return; + } + + QWidget *w = new QWidget(); + QPainter p(w); + p.setFont( font() ); + const int text_width = p.boundingRect( boundingRect(), (Qt::SingleLine | Qt::AlignHCenter | Qt::AlignVCenter), caption ).width(); + p.end(); + delete w; + int width = std::max( ((int)(text_width/16))*16, 48 ); + + switch(m_flowSymbol) + { + case FlowPart::ps_call: + { + width += 48; + break; + } + case FlowPart::ps_io: + case FlowPart::ps_round: + { + width += 32; + break; + } + case FlowPart::ps_decision: + { + width += 64; + break; + } + case FlowPart::ps_process: + default: + { + width += 32; + break; + } + } + + bool hasSideConnectors = m_flowSymbol == FlowPart::ps_decision; + if ( hasSideConnectors && (width != this->width()) ) + p_icnDocument->requestRerouteInvalidatedConnectors(); + + initSymbol( m_flowSymbol, width ); + m_caption = caption; +} +void FlowPart::postResize() +{ + updateNodePositions(); + CNItem::postResize(); +} + +void FlowPart::createStdInput() +{ + m_stdInput = (FPNode*)createNode( 0, 0, Node::dir_up, "stdinput", Node::fp_in ); + updateNodePositions(); +} +void FlowPart::createStdOutput() +{ + m_stdOutput = (FPNode*)createNode( 0, 0, Node::dir_down, "stdoutput", Node::fp_out ); + updateNodePositions(); +} +void FlowPart::createAltOutput() +{ + m_altOutput = (FPNode*)createNode( 0, 0, Node::dir_right, "altoutput", Node::fp_out ); + updateNodePositions(); +} + +void FlowPart::initSymbol( FlowPart::FlowSymbol symbol, int width ) +{ + m_flowSymbol = symbol; + + switch(symbol) + { + case FlowPart::ps_other: + { + return; + } + case FlowPart::ps_call: + case FlowPart::ps_process: + { + setItemPoints( QRect( -width/2, -16, width, 24 ) ); + break; + } + + case FlowPart::ps_io: + { + // define parallelogram shape + QPointArray pa(4); + pa[0] = QPoint( -(width-10)/2, -16 ); + pa[1] = QPoint( width/2, -16 ); + pa[2] = QPoint( (width-10)/2, 8 ); + pa[3] = QPoint( -width/2, 8 ); + setItemPoints(pa); + break; + } + + case FlowPart::ps_round: + { + // define rounded rectangles as two semicricles with RP_NUM/2 points with gap inbetween + // These points are not used for drawing; merely for passing to qcanvaspolygonitem for collision detection + // If there is a better way for a rounder rectangle + collision detection, please let me know... + + int halfHeight = 12; + + // Draw semicircle + double x; + const int RP_NUM = 48; + QPointArray pa(RP_NUM); + int point = 0; + for ( double y = -1.0; y <= 1.0; y+= 4.0/(RP_NUM-2) ) + { + x = sqrt(1-y*y)*halfHeight; + pa[point] = QPoint( (int)(width+x)-halfHeight, (int)(halfHeight*y) ); + pa[RP_NUM-1-point] = QPoint ( (int)(halfHeight-x), (int)(halfHeight*y) ); + point++; + } + + pa.translate( -width/2, 4 ); + setItemPoints(pa); + break; + } + + case FlowPart::ps_decision: + { + // define rhombus + QPointArray pa(6); + pa[0] = QPoint( 0, -24 ); + pa[1] = QPoint( width/2, -6 ); + pa[2] = QPoint( width/2, 6 ); + pa[3] = QPoint( 0, 24 ); + pa[4] = QPoint( -width/2, 6 ); + pa[5] = QPoint( -width/2, -6 ); + setItemPoints(pa); + break; + } + default: kdError() << k_funcinfo << "Unknown flowSymbol: "<id(); +} + +FlowPart* FlowPart::outputPart( const QString& internalNodeId ) +{ + Node *node = p_icnDocument->nodeWithID( nodeId(internalNodeId) ); + + FPNode *fpnode = dynamic_cast(node); + if ( !fpnode || fpnode->type() == Node::fp_in ) + return 0l; + + return fpnode->outputFlowPart(); +} + +FlowPartList FlowPart::inputParts( const QString& id ) +{ + Node *node = p_icnDocument->nodeWithID(id); + + if ( FPNode *fpNode = dynamic_cast(node) ) + return fpNode->inputFlowParts(); + + return FlowPartList(); +} + +FlowPartList FlowPart::inputParts() +{ + FlowPartList list; + + const NodeMap::iterator nEnd = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != nEnd; ++it ) + { + Node *node = p_icnDocument->nodeWithID( it.data().id ); + FlowPartList newList; + + if ( FPNode *fpNode = dynamic_cast(node) ) + newList = fpNode->inputFlowParts(); + + const FlowPartList::iterator nlEnd = newList.end(); + for ( FlowPartList::iterator it = newList.begin(); it != nlEnd; ++it ) + { + if (*it) list.append(*it); + } + } + + return list; +} + +FlowPartList FlowPart::outputParts() +{ + FlowPartList list; + + const NodeMap::iterator end = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != end; ++it ) + { + FlowPart *part = outputPart( it.key() ); + if (part) list.append(part); + } + + return list; +} + + +FlowPart* FlowPart::endPart( QStringList ids, FlowPartList *previousParts ) +{ + if ( ids.empty() ) + { + const NodeMap::iterator end = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != end; ++it ) + { + ids.append( it.key() ); + } + filterEndPartIDs( &ids ); + } + + const bool createdList = (!previousParts); + if (createdList) { + previousParts = new FlowPartList; + } else if ( previousParts->contains(this) ) { + return 0l; + } + previousParts->append(this); + + if ( ids.empty() ) { + return 0l; + } + if ( ids.size() == 1 ) { + return outputPart( *(ids.begin()) ); + } + + typedef QValueList ValidPartsList; + ValidPartsList validPartsList; + + const QStringList::iterator idsEnd = ids.end(); + for ( QStringList::iterator it = ids.begin(); it != idsEnd; ++it ) + { + int prevLevel = level(); + FlowPartList validParts; + FlowPart *part = outputPart(*it); + while (part) + { + if ( !validParts.contains(part) ) + { + validParts.append(part); +// if ( part->level() >= level() ) { + const int _l = part->level(); + part = part->endPart( QStringList(), previousParts ); + prevLevel = _l; +// } else { +// part = 0l; +// } + } + else { + part = 0l; + } + } + if ( !validParts.empty() ) { + validPartsList.append(validParts); + } + } + + if (createdList) + { + delete previousParts; + previousParts = 0l; + } + + if ( validPartsList.empty() ) return 0l; + + FlowPartList firstList = *(validPartsList.begin()); + const FlowPartList::iterator flEnd = firstList.end(); + const ValidPartsList::iterator vplEnd = validPartsList.end(); + for ( FlowPartList::iterator it = firstList.begin(); it != flEnd; ++it ) + { + bool ok = true; + for ( ValidPartsList::iterator vplit = validPartsList.begin(); vplit != vplEnd; ++vplit ) + { + if ( !(*vplit).contains(*it) ) ok = false; + } + if (ok) return *it; + } + + return 0l; +} + + +void FlowPart::handleIfElse( FlowCode *code, const QString &case1Statement, const QString &case2Statement, + const QString &case1, const QString &case2 ) +{ + if (!code) return; + + FlowPart *stop = 0l; + FlowPart *part1 = outputPart(case1); + FlowPart *part2 = outputPart(case2); + + if ( part1 && part2 ) stop = endPart( QStringList::split( ',', case1+","+case2 ) ); + + if ( (!part1 && !part2) || (part1 == stop && part2 == stop) ) return; + + code->addStopPart(stop); + + if ( part1 && part1 != stop && code->isValidBranch(part1) ) + { + // Use the case1 statement + code->addCode( "if "+case1Statement+" then "+"\n{" ); + code->addCodeBranch(part1); + code->addCode("}"); + + if ( part2 && part2 != stop && code->isValidBranch(part2) ) + { + code->addCode( "else\n{" ); + code->addCodeBranch(part2); + code->addCode("}"); + } + } + else if ( code->isValidBranch(part2) ) + { + // Use the case2 statement + code->addCode( "if "+case2Statement+" then "+"\n{" ); + code->addCodeBranch(part2); + code->addCode("}"); + } + + code->removeStopPart(stop); + code->addCodeBranch(stop); +} + + +Variant * FlowPart::createProperty( const QString & id, Variant::Type::Value type ) +{ + if ( type != Variant::Type::Port + && type != Variant::Type::Pin + && type != Variant::Type::VarName + && type != Variant::Type::SevenSegment + && type != Variant::Type::KeyPad ) + return CNItem::createProperty( id, type ); + + Variant * v = createProperty( id, Variant::Type::String ); + v->setType(type); + + if ( type == Variant::Type::VarName ) + { + if ( MicroSettings * settings = m_pFlowCodeDocument->microSettings() ) + v->setAllowed( settings->variableNames() ); + connect( property(id), SIGNAL(valueChanged(QVariant, QVariant )), this, SLOT(varNameChanged(QVariant, QVariant )) ); + } + else + slotUpdateFlowPartVariables(); + + return v; +} + + +void FlowPart::slotUpdateFlowPartVariables() +{ + if (!m_pFlowCodeDocument) + return; + + MicroSettings *s = m_pFlowCodeDocument->microSettings(); + if (!s) + return; + + const PinMappingMap pinMappings = s->pinMappings(); + QStringList sevenSegMaps; + QStringList keyPadMaps; + PinMappingMap::const_iterator pEnd = pinMappings.end(); + for ( PinMappingMap::const_iterator it = pinMappings.begin(); it != pEnd; ++it ) + { + switch ( it.data().type() ) + { + case PinMapping::SevenSegment: + sevenSegMaps << it.key(); + break; + + case PinMapping::Keypad_4x3: + case PinMapping::Keypad_4x4: + keyPadMaps << it.key(); + break; + + case PinMapping::Invalid: + break; + } + } + + QStringList ports = s->microInfo()->package()->portNames(); + ports.sort(); + + QStringList pins = s->microInfo()->package()->pinIDs(PicPin::type_bidir | PicPin::type_input | PicPin::type_open); + pins.sort(); + + const VariantDataMap::iterator vEnd = m_variantData.end(); + for ( VariantDataMap::iterator it = m_variantData.begin(); it != vEnd; ++it ) + { + Variant * v = it.data(); + if ( !v ) + continue; + + if ( v->type() == Variant::Type::Port ) + v->setAllowed( ports ); + + else if ( v->type() == Variant::Type::Pin ) + v->setAllowed( pins ); + + else if ( v->type() == Variant::Type::SevenSegment ) + { + v->setAllowed( sevenSegMaps ); + if ( !sevenSegMaps.isEmpty() && !sevenSegMaps.contains( v->value().toString() ) ) + v->setValue( sevenSegMaps.first() ); + } + + else if ( v->type() == Variant::Type::KeyPad ) + { + v->setAllowed( keyPadMaps ); + if ( !keyPadMaps.isEmpty() && !keyPadMaps.contains( v->value().toString() ) ) + v->setValue( keyPadMaps.first() ); + } + } +} + + +void FlowPart::updateVarNames() +{ + if (!m_pFlowCodeDocument) + return; + + MicroSettings *s = m_pFlowCodeDocument->microSettings(); + if (!s) + return; + + const QStringList names = s->variableNames(); + const VariantDataMap::iterator end = m_variantData.end(); + for ( VariantDataMap::iterator it = m_variantData.begin(); it != end; ++it ) + { + Variant *v = it.data(); + if ( v && v->type() == Variant::Type::VarName ) + v->setAllowed(names); + } +} + + +void FlowPart::varNameChanged( QVariant newValue, QVariant oldValue ) +{ + if (!m_pFlowCodeDocument) + return; + m_pFlowCodeDocument->varNameChanged( newValue.asString(), oldValue.asString() ); +} + + +inline int nodeDirToPos( Node::node_dir dir ) +{ + switch (dir) + { + case Node::dir_right: + return 0; + case Node::dir_up: + return 1; + case Node::dir_left: + return 2; + case Node::dir_down: + return 3; + } + return 0; +} + + +void FlowPart::updateAttachedPositioning( ) +{ + if (b_deleted) + return; + + //BEGIN Rearrange text if appropriate + const QRect textPos[4] = { + QRect( offsetX()+width(), 6, 40, 16 ), + QRect( 0, offsetY()-16, 40, 16 ), + QRect( offsetX()-40, 6, 40, 16 ), + QRect( 0, offsetY()+height(), 40, 16 ) }; + + NodeInfo * stdOutputInfo = m_stdOutput ? &m_nodeMap["stdoutput"] : 0; + NodeInfo * altOutputInfo = m_altOutput ? &m_nodeMap["altoutput"] : 0l; + + Text *outputTrueText = m_textMap.contains("output_true") ? m_textMap["output_true"] : 0l; + Text *outputFalseText = m_textMap.contains("output_false") ? m_textMap["output_false"] : 0l; + + if ( stdOutputInfo && outputTrueText ) + outputTrueText->setOriginalRect( textPos[ nodeDirToPos( (Node::node_dir)stdOutputInfo->orientation ) ] ); + + if ( altOutputInfo && outputFalseText ) + outputFalseText->setOriginalRect( textPos[ nodeDirToPos( (Node::node_dir)altOutputInfo->orientation ) ] ); + + const TextMap::iterator textMapEnd = m_textMap.end(); + for ( TextMap::iterator it = m_textMap.begin(); it != textMapEnd; ++it ) + { + QRect pos = it.data()->recommendedRect(); + it.data()->move( pos.x() + x(), pos.y() + y() ); + it.data()->setGuiPartSize( pos.width(), pos.height() ); + } + //END Rearrange text if appropriate + + const NodeMap::iterator end = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != end; ++it ) + { + if ( !it.data().node ) + { + kdError() << k_funcinfo << "Node in nodemap is null" << endl; + continue; + } + + double nx = it.data().x; + double ny = it.data().y; + +#define round_8(x) (((x) > 0) ? int(((x)+4)/8)*8 : int(((x)-4)/8)*8) + nx = round_8(nx); + ny = round_8(ny); +#undef round_8 + + it.data().node->move( int(nx+x()), int(ny+y()) ); + it.data().node->setOrientation( (Node::node_dir)it.data().orientation ); + } +} + + +ItemData FlowPart::itemData( ) const +{ + ItemData itemData = CNItem::itemData(); + itemData.orientation = m_orientation; + return itemData; +} + + +void FlowPart::restoreFromItemData( const ItemData & itemData ) +{ + CNItem::restoreFromItemData(itemData); + if ( itemData.orientation >= 0 ) + setOrientation( uint(itemData.orientation) ); +} + + +void FlowPart::updateNodePositions() +{ + if ( m_orientation > 7 ) + { + kdWarning() << k_funcinfo << "Invalid orientation: "<orientation = diamondNodePositioning[m_orientation][0]; + stdOutputInfo->orientation = diamondNodePositioning[m_orientation][1]; + altOutputInfo->orientation = diamondNodePositioning[m_orientation][2]; + } + else if ( m_stdInput && m_stdOutput ) + { + stdInputInfo->orientation = inOutNodePositioning[m_orientation][0]; + stdOutputInfo->orientation = inOutNodePositioning[m_orientation][1]; + } + else if ( m_orientation < 4 ) + { + if (stdInputInfo) + stdInputInfo->orientation = inNodePositioning[m_orientation]; + else if (stdOutputInfo) + stdOutputInfo->orientation = outNodePositioning[m_orientation]; + } + else + { + kdWarning() << k_funcinfo << "Invalid orientation: "<requestRerouteInvalidatedConnectors(); +} + + +uint FlowPart::allowedOrientations( ) const +{ + // The bit positions shown here represent whether or not that orientation is allowed, the orientation being + // what is displayed in the i'th position (0 to 3 on top, 4 to 7 on bottom) of orientation widget + + if ( m_stdInput && m_stdOutput && m_altOutput ) + return 255; + + if ( m_stdInput && m_stdOutput ) + return 119; + + if ( m_stdInput || m_stdOutput ) + return 15; + + return 0; +} + +void FlowPart::orientationPixmap( uint orientation, QPixmap & pm ) const +{ + const QSize size = pm.size(); + + if ( ! ( allowedOrientations() & ( 1 << orientation ) ) ) + { + kdWarning() << k_funcinfo << "Requesting invalid orientation of " << orientation << endl; + return; + } + + QBitmap mask( 50, 50 ); + QPainter maskPainter(&mask); + mask.fill( Qt::color0 ); + maskPainter.setBrush(Qt::color1); + maskPainter.setPen(Qt::color1); + + QPainter p(&pm); + p.setBrush(m_brushCol); + p.setPen( Qt::black ); + + // In order: right corner, top corner, left corner, bottom corner + + QPoint c[4] = { + QPoint( int(0.7*size.width()), int(0.5*size.height()) ), + QPoint( int(0.5*size.width()), int(0.4*size.height()) ), + QPoint( int(0.3*size.width()), int(0.5*size.height()) ), + QPoint( int(0.5*size.width()), int(0.6*size.height()) ) }; + + QPoint d[4]; + d[0] = c[0] + QPoint( 7, 0 ); + d[1] = c[1] + QPoint( 0, -7 ); + d[2] = c[2] + QPoint( -7, 0 ); + d[3] = c[3] + QPoint( 0, 7 ); + + if ( m_stdInput && m_stdOutput && m_altOutput ) + { + //BEGIN Draw diamond outline + QPointArray diamond(4); + for ( uint i=0; i<4; ++i ) + diamond[i] = c[i]; + + p.drawPolygon(diamond); + maskPainter.drawPolygon(diamond); + //END Draw diamond outline + + + //BEGIN Draw input + int pos0 = nodeDirToPos( diamondNodePositioning[orientation][0] ); + p.drawLine( c[pos0], d[pos0] ); + maskPainter.drawLine( c[pos0], d[pos0] ); + //END Draw input + + + //BEGIN Draw "true" output as a tick + QPointArray tick(4); + tick[0] = QPoint( -3, 0 ); + tick[1] = QPoint( 0, 2 ); + tick[2] = QPoint( 0, 2 ); + tick[3] = QPoint( 4, -2 ); + + int pos1 = nodeDirToPos( diamondNodePositioning[orientation][1] ); + tick.translate( d[pos1].x(), d[pos1].y() ); + p.drawLineSegments(tick); + maskPainter.drawLineSegments(tick); + //END Draw "true" output as a tick + + + //BEGIN Draw "false" output as a cross + QPointArray cross(4); + cross[0] = QPoint( -2, -2 ); + cross[1] = QPoint( 2, 2 ); + cross[2] = QPoint( -2, 2 ); + cross[3] = QPoint( 2, -2 ); + + int pos2 = nodeDirToPos( diamondNodePositioning[orientation][2] ); + cross.translate( d[pos2].x(), d[pos2].y() ); + p.drawLineSegments(cross); + maskPainter.drawLineSegments(cross); + //END Draw "false" output as a cross + } + + else if ( m_stdInput || m_stdOutput ) + { + p.drawRoundRect( int(0.3*size.width()), int(0.4*size.height()), int(0.4*size.width()), int(0.2*size.height()) ); + maskPainter.drawRoundRect( int(0.3*size.width()), int(0.4*size.height()), int(0.4*size.width()), int(0.2*size.height()) ); + + int hal = 5; // half arrow length + int haw = 3; // half arrow width + + QPoint arrows[4][6] = { + { QPoint( hal, 0 ), QPoint( 0, -haw ), + QPoint( hal, 0 ), QPoint( -hal, 0 ), + QPoint( hal, 0 ), QPoint( 0, haw ) }, + + { QPoint( 0, -hal ), QPoint( -haw, 0 ), + QPoint( 0, -hal ), QPoint( 0, hal ), + QPoint( 0, -hal ), QPoint( haw, 0 ) }, + + { QPoint( -hal, 0 ), QPoint( 0, -haw ), + QPoint( -hal, 0 ), QPoint( hal, 0 ), + QPoint( -hal, 0 ), QPoint( 0, haw ) }, + + { QPoint( 0, hal ), QPoint( -haw, 0 ), + QPoint( 0, hal ), QPoint( 0, -hal ), + QPoint( 0, hal ), QPoint( haw, 0 ) } }; + + int inPos = -1; + int outPos = -1; + + if ( m_stdInput && m_stdOutput ) + { + inPos = nodeDirToPos( inOutNodePositioning[orientation][0] ); + outPos = nodeDirToPos( inOutNodePositioning[orientation][1] ); + } + else if ( m_stdInput ) + { + inPos = nodeDirToPos( inNodePositioning[orientation] ); + } + else if ( m_stdOutput ) + { + outPos = nodeDirToPos( outNodePositioning[orientation] ); + } + + if ( inPos != -1 ) + { + QPointArray inArrow(6); + for ( int i=0; i<6; ++i ) + { + inArrow[i] = arrows[(inPos+2)%4][i]; + } + inArrow.translate( d[inPos].x(), d[inPos].y() ); + p.drawPolygon(inArrow); + maskPainter.drawPolygon(inArrow); + } + + if ( outPos != -1 ) + { + QPointArray outArrow(6); + for ( int i=0; i<6; ++i ) + { + outArrow[i] = arrows[outPos][i]; + } + outArrow.translate( d[outPos].x(), d[outPos].y() ); + p.drawPolygon(outArrow); + maskPainter.drawPolygon(outArrow); + } + } + + pm.setMask(mask); +} + + +#include "flowpart.moc" + + diff --git a/src/flowparts/flowpart.h b/src/flowparts/flowpart.h new file mode 100644 index 0000000..d689ebf --- /dev/null +++ b/src/flowparts/flowpart.h @@ -0,0 +1,197 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef FLOWPART_H +#define FLOWPART_H + +#include "cnitem.h" + +class ICNDocument; +class Node; +class FlowCode; +class FlowCodeDocument; +class FlowPart; +class FPNode; +class QPixmap; +class QSize; + +typedef QValueList FlowPartList; + +/** +All flow parts (eg 'CallSub', 'Read from Port' ,etc) should inherit from this class. +It provides basic functionality for creating commonly used nodes, as well as a virtual function +that you should reinherit for generating the assembly code. +@short Base class for all FlowParts +@author David Saxton +*/ +class FlowPart : public CNItem +{ +Q_OBJECT +public: + enum FlowSymbol + { + ps_process, // Process - Plain rectangular box + ps_call, // Call - Rectangular box with double vertical lines at either end + ps_io, // I/O - Slanter rectangular box + ps_round, // Start/End - Rounded rectangular box + ps_decision, // Decision - Diamond shape + ps_other // Custom shape, which is ignored by FlowPart + }; + FlowPart( ICNDocument *icnDocument, bool newItem, const QString &id ); + virtual ~FlowPart(); + + virtual void generateMicrobe( FlowCode */*code*/ ) = 0; + /** + * Set a preset "orientation" of this item - 0 through 7 + */ + void setOrientation( uint orientation ); + uint orientation() const { return m_orientation; } + /** + * The allowed orientations, as bit positions of 0 through 7 + */ + uint allowedOrientations() const; + virtual ItemData itemData() const; + virtual void restoreFromItemData( const ItemData &itemData ); + /** + * Sets the caption displayed in the flowpart, resizes the item as necessary + */ + virtual void setCaption( const QString &caption ); + /** + * Traces the FlowCode document route from the nodes with the given internal + * ids, and returns the FlowPart to which: + * @li all the routes from the given nodes are eventually connected to downwards + * @li their exists one (possibly internally branched) route for each node to that part + * @param ids The list of internal ids of the nodes for the paths to begin from - if empty, + * all nodes internal nodes are used + * @param previousParts A list of parts in the calling tree. This avoids infinite recursion. + * @returns The first FlowPart satisfying these conditions, or NULL if no such part exists + */ + FlowPart* endPart( QStringList ids, FlowPartList *previousParts = 0l ); + /** + * Handles the addition of a if-else statement to the given FlowCode. This will + * order the code as necessary, adding the branches in the appropriate places + * @param code The FlowCode where the if-else will be added + * @param case1Statement The statement (e.g. "PORTA.0 is high") used for the first case + * @param case2Statement The logically opposite statement (e.g. "PORTA.0 is low") (note + that only one of the two statements will be used. + * @param case1 The internal node id for case1 + * @param case2 The internal node id for case2 + */ + void handleIfElse( FlowCode *code, const QString &case1Statement, const QString &case2Statement, + const QString &case1, const QString &case2 ); + /** + * Returns a pointer to the FlowPart that is connected to the node with the + * given internal id, or NULL if no such node / no connected part + */ + FlowPart* outputPart( const QString& internalNodeId ); + /** + * Returns the FlowParts connected to the given node + * @see outputPart + */ + FlowPartList inputParts( const QString& id ); + /** + * Returns a list of parts that are connected to *all* input parts + */ + FlowPartList inputParts(); + /** + * Returns a list of parts that are connected to *all* output parts. Note that if + * the same FlowPart is connected to more than one output, that flowpart will appear + * in the FlowPartList the number of times it is connected. + */ + FlowPartList outputParts(); + /** + * Draw the picture of the flowpart in the given orientation onto the pixmap + */ + void orientationPixmap( uint orientation, QPixmap & pm ) const; + virtual Variant * createProperty( const QString & id, Variant::Type::Value type ); + +public slots: + /** + * Called when variable name data for MicroSettings changes, and so our + * data needs updating + */ + void updateVarNames(); + /** + * Called when a variable name has changed (from an entry box) + */ + void varNameChanged( QVariant newValue, QVariant oldValue ); + /** + * Called when some of the FlowPart-specific variables (e.g. Pin or + * SevenSegment) requiring updating, such as when the PIC type changes + * or the list of Pin Maps changes. + */ + void slotUpdateFlowPartVariables(); + +protected: + virtual void updateAttachedPositioning(); + /** + * Removes the node ids that shouldn't be used for finding the end part + */ + virtual void filterEndPartIDs( QStringList *ids ) { Q_UNUSED(ids); } + /** + * Normally just passes the paint request onto CNItem::drawShape, + * although in the case of some FlowSymbols (e.g. decision), it will handle + * the drawing itself + */ + virtual void drawShape( QPainter &p ); + /** + * Returns the goto instruction that will goto the FlowPart that is connected + * to the node with the given internal id. + * For example, gotoCode("stdOutput") might return "goto delay__13" + */ + QString gotoCode( const QString& internalNodeId ); + /** + * Creates a FPNode with an internal id of "stdinput". + * The node is positioned half-way along the top of the FlowPart, + * as determined by width(), height(), x() and y() + */ + void createStdInput(); + /** + * Creates a FPNode with an internal id of "stdoutput". + * The node is positioned half-way along the bottom of the FlowPart, + * as determined by width(), height(), x() and y() + */ + void createStdOutput(); + /** + * Creates a FPNode with an internal id of "altoutput". + * The node is positioned half-way along the right of the FlowPart, + * as determined by width(), height(), x() and y() + */ + void createAltOutput(); + /** + * Initialises a symbol, by calling setItemPoints with the shape + */ + void initSymbol( FlowPart::FlowSymbol symbol, int width = 48 ); + + void initProcessSymbol() { initSymbol( FlowPart::ps_process ); } + void initCallSymbol() { initSymbol( FlowPart::ps_call ); } + void initIOSymbol() { initSymbol( FlowPart::ps_io ); } + void initRoundedRectSymbol() { initSymbol( FlowPart::ps_round ); } + void initDecisionSymbol() { initSymbol( FlowPart::ps_decision ); } + + QString m_caption; + uint m_orientation; + FPNode *m_stdInput; + FPNode *m_stdOutput; + FPNode *m_altOutput; + QGuardedPtr m_pFlowCodeDocument; + + virtual void postResize(); + void updateNodePositions(); + +private: + FlowSymbol m_flowSymbol; +}; +typedef QValueList FlowPartList; + +#endif + + + diff --git a/src/flowparts/forloop.cpp b/src/flowparts/forloop.cpp new file mode 100644 index 0000000..d2fe88b --- /dev/null +++ b/src/flowparts/forloop.cpp @@ -0,0 +1,84 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "forloop.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* ForLoop::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ForLoop( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ForLoop::libraryItem() +{ + return new LibraryItem( + QString("flow/forloop"), + i18n("For"), + i18n("Loops"), + "for.png", + LibraryItem::lit_flowpart, + ForLoop::construct ); +} + +ForLoop::ForLoop( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowContainer( icnDocument, newItem, (id) ? id : "forloop" ) +{ + m_name = i18n("For Loop"); + m_desc = i18n("The code contained in the foor loop is repeatedly executed. By default, the variable used will be incremented every time. This can be changed by entering a value other than 1 into Step.

    The for loop will exit when the value contained in the variable is equal to the end value."); + + createTopContainerNode(); + createBotContainerNode(); + + createProperty( "0-var", Variant::Type::Combo ); + property("0-var")->setToolbarCaption("for"); + property("0-var")->setEditorCaption( i18n("Variable") ); + property("0-var")->setValue("x"); + + createProperty( "1-initial", Variant::Type::Combo ); + property("1-initial")->setToolbarCaption("="); + property("1-initial")->setEditorCaption( i18n("Initial Value") ); + property("1-initial")->setValue("1"); + + createProperty( "2-end", Variant::Type::Combo ); + property("2-end")->setToolbarCaption("to"); + property("2-end")->setEditorCaption( i18n("End Value") ); + property("2-end")->setValue("10"); + + createProperty( "3-step", Variant::Type::Combo ); + property("3-step")->setToolbarCaption("step"); + property("3-step")->setEditorCaption( i18n("Step") ); + property("3-step")->setValue("1"); + property("3-step")->setAdvanced(true); +} + +ForLoop::~ForLoop() +{ +} + +void ForLoop::dataChanged() +{ + if( dataString("3-step").toInt() == 1 ) + setCaption( "for " + dataString("0-var") + " = " + dataString("1-initial") + " to " + dataString("2-end") ); + else setCaption( "for " + dataString("0-var") + " = " + dataString("1-initial") + " to " + dataString("2-end") + " step " + dataString("3-step")); +} + +void ForLoop::generateMicrobe( FlowCode *code ) +{ + if( dataString("3-step").toInt() == 1 ) code->addCode( "for " + dataString("0-var") + " = " + dataString("1-initial") + " to " + dataString("2-end") + "\n{" ); + else code->addCode( "for " + dataString("0-var") + " = " + dataString("1-initial") + " to " + dataString("2-end") + " step " + dataString("3-step") +"\n{" ); + code->addCodeBranch( outputPart("int_in") ); + code->addCode("}"); + code->addCodeBranch( outputPart("ext_out") ); +} + diff --git a/src/flowparts/forloop.h b/src/flowparts/forloop.h new file mode 100644 index 0000000..c6b61b0 --- /dev/null +++ b/src/flowparts/forloop.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef FORLOOP_H +#define FORLOOP_H + +#include "flowcontainer.h" + +/** +@author David Saxton +*/ +class ForLoop : public FlowContainer +{ +public: + ForLoop( ICNDocument *icnDocument, bool newItem, const char *id ); + ~ForLoop(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode * ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/inputbutton.cpp b/src/flowparts/inputbutton.cpp new file mode 100644 index 0000000..a0564d4 --- /dev/null +++ b/src/flowparts/inputbutton.cpp @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "inputbutton.h" +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* InputButton::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new InputButton( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* InputButton::libraryItem() +{ + return new LibraryItem( + "flow/inputbutton", + i18n("InputButton"), + i18n("Functions"), + "ppinputbutton.png", + LibraryItem::lit_flowpart, + InputButton::construct + ); +} + + +InputButton::InputButton( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "inputbutton" ) +{ + m_name = i18n("InputButton"); + m_desc = i18n("Pauses program execution until a inputbutton has been pressed or released (i.e. on rising or falling input), after performing debouncing."); + initProcessSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "0-trigger", Variant::Type::Select ); + property("0-trigger")->setCaption( i18n("Trigger") ); + property("0-trigger")->setAllowed( QStringList::split(',',"rising,falling") ); + property("0-trigger")->setValue("rising"); + + createProperty( "1-pin", Variant::Type::Pin ); + property("1-pin")->setCaption( i18n("Pin") ); + property("1-pin")->setValue("RA0"); +} + +InputButton::~InputButton() +{ +} + + +void InputButton::dataChanged() +{ + setCaption( i18n("Continue on %1 %2").arg(dataString("0-trigger")).arg(dataString("1-pin")) ); +} + + +void InputButton::generateMicrobe( FlowCode *code ) +{ + code->addCodeBranch( outputPart("stdoutput") ); +} + diff --git a/src/flowparts/inputbutton.h b/src/flowparts/inputbutton.h new file mode 100644 index 0000000..7467b42 --- /dev/null +++ b/src/flowparts/inputbutton.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef INPUTBUTTON_H +#define INPUTBUTTON_H + +#include "flowpart.h" + +/** +@short InputButton - does debouncing of input +@author David Saxton +*/ +class InputButton : public FlowPart +{ +public: + InputButton( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~InputButton(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/interrupt.cpp b/src/flowparts/interrupt.cpp new file mode 100644 index 0000000..5e8c42f --- /dev/null +++ b/src/flowparts/interrupt.cpp @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "interrupt.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* Interrupt::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Interrupt( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Interrupt::libraryItem() +{ + return new LibraryItem( + "flow/interrupt", + i18n("Interrupt"), + i18n("Common"), + "interrupt.png", + LibraryItem::lit_flowpart, + Interrupt::construct ); +} + +Interrupt::Interrupt( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowContainer( icnDocument, newItem, id ? id : "interrupt" ) +{ + m_name = i18n("Interrupt"); + m_desc = i18n("Defines the starting point of a interrupt handler."); + + QStringList interruptTypes; + interruptTypes.append("changed"); + interruptTypes.append("external"); + interruptTypes.append("timer"); + interruptTypes.append("trigger"); + + createProperty( "interrupt", Variant::Type::Select ); + property("interrupt")->setAllowed(interruptTypes); + property("interrupt")->setCaption( i18n("Interrupt") ); + property("interrupt")->setValue("trigger"); +} + +Interrupt::~Interrupt() +{ +} + +void Interrupt::dataChanged() +{ + setCaption( i18n("Interrupt %1").arg(dataString("interrupt")) ); +} + +void Interrupt::generateMicrobe( FlowCode *code ) +{ + code->addCode( "\ninterrupt "+dataString("interrupt")+"\n{" ); + code->addCodeBranch( outputPart("int_in") ); + code->addCode("}"); +} + + diff --git a/src/flowparts/interrupt.h b/src/flowparts/interrupt.h new file mode 100644 index 0000000..807cc30 --- /dev/null +++ b/src/flowparts/interrupt.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef INTERRUPT_H +#define INTERRUPT_H + +#include "flowcontainer.h" + +/** +@short FlowPart that defines the start of a interrupt +@author David Saxton +*/ +class Interrupt : public FlowContainer +{ +public: + Interrupt( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Interrupt(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/keypad.cpp b/src/flowparts/keypad.cpp new file mode 100644 index 0000000..f0d7136 --- /dev/null +++ b/src/flowparts/keypad.cpp @@ -0,0 +1,67 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "keypad.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* Keypad::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Keypad( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Keypad::libraryItem() +{ + return new LibraryItem( + "flow/keypad", + i18n("Keypad"), + i18n("Functions"), + "keypad.png", + LibraryItem::lit_flowpart, + Keypad::construct + ); +} + +Keypad::Keypad( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, id ? id : "keypad" ) +{ + m_name = i18n("Keypad"); + m_desc = i18n("Gets a key from a keypad connected to the PIC."); + initProcessSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "variable", Variant::Type::VarName ); + property("variable")->setValue("x"); + property("variable")->setCaption( i18n("Variable") ); + + Variant * v = createProperty( "keypad", Variant::Type::KeyPad ); + v->setCaption( i18n("Pin map") ); +} + +Keypad::~Keypad() +{ +} + +void Keypad::dataChanged() +{ + setCaption( i18n("Read %1 to %2").arg( dataString( "keypad" ) ).arg( dataString( "variable" ) ) ); +} + +void Keypad::generateMicrobe( FlowCode *code ) +{ + code->addCode( QString("%1 = %2").arg( dataString("variable") ).arg( dataString("keypad") ) ); + code->addCodeBranch( outputPart("stdoutput") ); +} + + diff --git a/src/flowparts/keypad.h b/src/flowparts/keypad.h new file mode 100644 index 0000000..e2ddba8 --- /dev/null +++ b/src/flowparts/keypad.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef KEYPAD_H +#define KEYPAD_H + +#include "flowpart.h" + +/** +@short FlowPart that provides a keypad +@author David Saxton +*/ +class Keypad : public FlowPart +{ +public: + Keypad( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Keypad(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/pinmapping.cpp b/src/flowparts/pinmapping.cpp new file mode 100644 index 0000000..3b85b46 --- /dev/null +++ b/src/flowparts/pinmapping.cpp @@ -0,0 +1,398 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasmanipulator.h" +#include "cnitemgroup.h" +#include "eckeypad.h" +#include "ecsevensegment.h" +#include "libraryitem.h" +#include "microinfo.h" +#include "micropackage.h" +#include "node.h" +#include "pinmapping.h" +#include "viewcontainer.h" + +#include +#include +#include + +#include +#include +#include +#include + + +//BEGIN class PinMapping +PinMapping::PinMapping( Type type ) +{ + m_type = type; +} + + +PinMapping::PinMapping() +{ + m_type = Invalid; +} + + +PinMapping::~PinMapping() +{ +} +//END class PinMapping + + + +//BEGIN class PinMapEditor +PinMapEditor::PinMapEditor( PinMapping * pinMapping, MicroInfo * picInfo, QWidget * parent, const char * name ) + : KDialogBase( parent, name, true, i18n("Pin Map Editor"), Ok|Apply|Cancel, KDialogBase::Ok, true ) +{ + m_pPinMapping = pinMapping; + + m_pPinMapDocument = new PinMapDocument(); + + QAccel * accel = new QAccel( this ); + accel->connectItem( accel->insertItem( Key_Delete ), + m_pPinMapDocument, + SLOT(deleteSelection()) ); + + accel->connectItem( accel->insertItem( KStdAccel::selectAll().keyCodeQt() ), + m_pPinMapDocument, + SLOT(selectAll()) ); + + accel->connectItem( accel->insertItem( KStdAccel::undo().keyCodeQt() ), + m_pPinMapDocument, + SLOT(undo()) ); + + accel->connectItem( accel->insertItem( KStdAccel::redo().keyCodeQt() ), + m_pPinMapDocument, + SLOT(redo()) ); + + + QFrame * f = new QFrame(this); + f->setMinimumWidth( 480 ); + f->setMinimumHeight( 480 ); + + f->setFrameShape( QFrame::Box ); + f->setFrameShadow( QFrame::Plain ); + QVBoxLayout * fLayout = new QVBoxLayout( f, 1, 0, "fLayout" ); + + ViewContainer * vc = new ViewContainer( 0, 0, f ); + fLayout->addWidget( vc ); + + m_pPinMapView = static_cast(m_pPinMapDocument->createView( vc, 0 )); + + qApp->processEvents(); + + m_pPinMapDocument->init( *m_pPinMapping, picInfo ); + + enableButtonSeparator( false ); + setMainWidget(f); +} + + +void PinMapEditor::slotApply() +{ + savePinMapping(); + KDialogBase::slotApply(); +} + + +void PinMapEditor::slotOk() +{ + savePinMapping(); + KDialogBase::slotOk(); +} + + +void PinMapEditor::savePinMapping() +{ + *m_pPinMapping = m_pPinMapDocument->pinMapping(); +} +//END class PinMapEditor + + + +//BEGIN class PinMapDocument +PinMapDocument::PinMapDocument() + : ICNDocument( 0, 0, 0 ) +{ + m_pPicComponent = 0l; + m_pKeypad = 0l; + m_pSevenSegment = 0l; + m_type = dt_pinMapEditor; + + m_cmManager->addManipulatorInfo( CMSelect::manipulatorInfo() ); +} + + +PinMapDocument::~PinMapDocument() +{ +} + + +void PinMapDocument::init( const PinMapping & pinMapping, MicroInfo * microInfo ) +{ + m_pinMappingType = pinMapping.type(); + + m_pPicComponent = static_cast( addItem( "PIC_IC", QPoint( 336, 224 ), true ) ); + m_pPicComponent->initPackage( microInfo ); + + const QStringList pins = pinMapping.pins(); + const QStringList::const_iterator end = pins.end(); + + int keypadCols = -1; // -1 means no keypad + + switch ( m_pinMappingType ) + { + case PinMapping::SevenSegment: + { + m_pSevenSegment = static_cast( addItem( "ec/seven_segment", QPoint( 144, 232 ), true ) ); + + char ssPin = 'a'; + for ( QStringList::const_iterator it = pins.begin(); it != end; ++it ) + { + createConnector( m_pSevenSegment->childNode( QChar(ssPin) ), m_pPicComponent->childNode(*it) ); + ssPin++; + } + + break; + } + + case PinMapping::Keypad_4x3: + m_pKeypad = static_cast( addItem( "ec/keypad", QPoint( 144, 232 ), true ) ); + m_pKeypad->property("numCols")->setValue(3); + keypadCols = 3; + break; + + case PinMapping::Keypad_4x4: + m_pKeypad = static_cast( addItem( "ec/keypad", QPoint( 144, 232 ), true ) ); + m_pKeypad->property("numCols")->setValue(4); + keypadCols = 4; + break; + + case PinMapping::Invalid: + kdDebug() << k_funcinfo << "m_pinMappingType == Invalid" << endl; + break; + } + + if ( keypadCols != -1 ) + { + QStringList::const_iterator it = pins.begin(); + for ( unsigned row = 0; (row < 4) && (it != end); ++row, ++it ) + createConnector( m_pKeypad->childNode( QString("row_%1").arg( row ) ), m_pPicComponent->childNode( *it ) ); + + for ( unsigned col = 0; (col < keypadCols) && (it != end); ++col, ++it ) + createConnector( m_pKeypad->childNode( QString("col_%1").arg( col ) ), m_pPicComponent->childNode( *it ) ); + } + + clearHistory(); // Don't allow undoing of initial creation of stuff +} + + +bool PinMapDocument::isValidItem( Item * item ) +{ + return isValidItem( item->type() ); +} + + +bool PinMapDocument::isValidItem( const QString & id ) +{ + if ( !m_pPicComponent && id == "PIC_IC" ) + return true; + + switch ( m_pinMappingType ) + { + case PinMapping::SevenSegment: + return ( !m_pSevenSegment && id == "ec/seven_segment" ); + + case PinMapping::Keypad_4x3: + return ( !m_pKeypad && id == "ec/keypad" ); + + case PinMapping::Keypad_4x4: + return ( !m_pKeypad && id == "ec/keypad" ); + + case PinMapping::Invalid: + return false; + } + + return false; +} + + +void PinMapDocument::deleteSelection() +{ + m_selectList->removeQCanvasItem( m_pPicComponent ); + m_selectList->removeQCanvasItem( m_pSevenSegment ); + m_selectList->removeQCanvasItem( m_pKeypad ); + + ICNDocument::deleteSelection(); +} + + +PinMapping PinMapDocument::pinMapping() const +{ + const NodeMap picNodeMap = m_pPicComponent->nodeMap(); + const NodeMap::const_iterator picNodeMapEnd = picNodeMap.end(); + + QStringList picPinIDs; + QStringList attachedIDs; + Component * attached = 0l; + + switch ( m_pinMappingType ) + { + case PinMapping::SevenSegment: + for ( unsigned i = 0; i < 7; ++i ) + attachedIDs << QChar('a'+i); + attached = m_pSevenSegment; + break; + + case PinMapping::Keypad_4x3: + for ( unsigned i = 0; i < 4; ++i ) + attachedIDs << QString("row_%1").arg(i); + for ( unsigned i = 0; i < 3; ++i ) + attachedIDs << QString("col_%1").arg(i); + attached = m_pKeypad; + break; + + case PinMapping::Keypad_4x4: + for ( unsigned i = 0; i < 4; ++i ) + attachedIDs << QString("row_%1").arg(i); + for ( unsigned i = 0; i < 4; ++i ) + attachedIDs << QString("col_%1").arg(i); + attached = m_pKeypad; + break; + + case PinMapping::Invalid: + break; + } + + if ( !attached ) + return PinMapping(); + + QStringList::iterator end = attachedIDs.end(); + for ( QStringList::iterator attachedIt = attachedIDs.begin(); attachedIt != end; ++ attachedIt ) + { + Node * node = attached->childNode( *attachedIt ); + QString pinID; + + for ( NodeMap::const_iterator it = picNodeMap.begin(); it != picNodeMapEnd; ++it ) + { + if ( it.data().node->isConnected( node ) ) + { + pinID = it.key(); + break; + } + } + + picPinIDs << pinID; + } + + PinMapping pinMapping( m_pinMappingType ); + pinMapping.setPins( picPinIDs ); + + return pinMapping; +} +//END class PinMapDocument + + + +//BEGIN class PinMapView +PinMapView::PinMapView( PinMapDocument * pinMapDocument, ViewContainer * viewContainer, uint viewAreaId, const char * name ) + : ICNView( pinMapDocument, viewContainer, viewAreaId, name ) +{ +} + + +PinMapView::~PinMapView() +{ +} +//END class PinMapView + + + +//BEGIN class PIC_IC +Item* PIC_IC::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new PIC_IC( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* PIC_IC::libraryItem() +{ + return new LibraryItem( "PIC_IC", 0, 0, LibraryItem::lit_other, PIC_IC::construct ); +} + + +PIC_IC::PIC_IC( ICNDocument * icnDocument, bool newItem, const char * id ) + : Component( icnDocument, newItem, id ? id : "PIC_IC" ) +{ +} + + +PIC_IC::~PIC_IC() +{ +} + + +void PIC_IC::initPackage( MicroInfo * microInfo ) +{ + // The code in this function is a stripped down version of that in PICComponent::initPackage + + if (!microInfo) + return; + + MicroPackage * microPackage = microInfo->package(); + if (!microPackage) + return; + + //BEGIN Get pin IDs + QStringList allPinIDs = microPackage->pinIDs(); + QStringList ioPinIDs = microPackage->pinIDs( PicPin::type_bidir | PicPin::type_input | PicPin::type_open ); + + // Now, we make the unwanted pin ids blank, so a pin is not created for them + const QStringList::iterator allPinIDsEnd = allPinIDs.end(); + for ( QStringList::iterator it = allPinIDs.begin(); it != allPinIDsEnd; ++it ) + { + if ( !ioPinIDs.contains(*it) ) + *it = ""; + } + //END Get pin IDs + + + //BEGIN Remove old stuff + // Remove old text + TextMap textMapCopy = m_textMap; + const TextMap::iterator textMapEnd = textMapCopy.end(); + for ( TextMap::iterator it = textMapCopy.begin(); it != textMapEnd; ++it ) + removeDisplayText(it.key()); + + // Remove old nodes + NodeMap nodeMapCopy = m_nodeMap; + const NodeMap::iterator nodeMapEnd = nodeMapCopy.end(); + for ( NodeMap::iterator it = nodeMapCopy.begin(); it != nodeMapEnd; ++it ) + { + if ( !ioPinIDs.contains(it.key()) ) + removeNode( it.key() ); + } + //END Remove old stuff + + + + //BEGIN Create new stuff + initDIPSymbol( allPinIDs, 80 ); + initDIP(allPinIDs); + //END Create new stuff + + + addDisplayText( "picid", QRect(offsetX(), offsetY()-16, width(), 16), microInfo->id() ); +} +//END class PIC_IC + +#include "pinmapping.moc" diff --git a/src/flowparts/pinmapping.h b/src/flowparts/pinmapping.h new file mode 100644 index 0000000..6131e45 --- /dev/null +++ b/src/flowparts/pinmapping.h @@ -0,0 +1,142 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PINMAPPING_H +#define PINMAPPING_H + +#include "component.h" +#include "icndocument.h" +#include "icnview.h" + +#include + +class ECKeyPad; +class ECSevenSegment; +class MicroInfo; +class PIC_IC; +class PinMapDocument; +class PinMapView; + + +/** +Stores a pin mapping Pic <--> [component] where component is set by the Type +(e.g. Keypad or Seven Segment). Used for FlowCode. +@author David Saxton +*/ +class PinMapping +{ + public: + enum Type + { + SevenSegment, + Keypad_4x3, + Keypad_4x4, + Invalid + }; + + /** + * Creates an invalid PinMapping, required by Qt templates. + */ + PinMapping(); + /** + * Creates a PinMapping with the given type. + */ + PinMapping( Type type ); + ~PinMapping(); + + Type type() const { return m_type; } + + QStringList pins() const { return m_pins; } + void setPins( const QStringList & pins ) { m_pins = pins; } + + protected: + QStringList m_pins; + Type m_type; +}; +typedef QMap< QString, PinMapping > PinMappingMap; + + + +/** +Dialog for editing a Pin Mapping +@author David Saxton +*/ +class PinMapEditor : public KDialogBase +{ + Q_OBJECT + public: + PinMapEditor( PinMapping * PinMapping, MicroInfo * Info, QWidget * parent, const char * name ); + + protected: + virtual void slotApply(); + virtual void slotOk(); + void savePinMapping(); + + PinMapping * m_pPinMapping; + PinMapDocument * m_pPinMapDocument; + PinMapView * m_pPinMapView; +}; + + + +/** +For use with FlowParts that require a pin map (e.g. Keypad and Seven Segment). +@author David Saxton +*/ +class PinMapDocument : public ICNDocument +{ + Q_OBJECT + public: + PinMapDocument(); + ~PinMapDocument(); + + void init( const PinMapping & PinMapping, MicroInfo * microInfo ); + + virtual bool isValidItem( Item * item ); + virtual bool isValidItem( const QString &itemId ); + + PinMapping pinMapping() const; + + virtual void deleteSelection(); + + protected: + PinMapping::Type m_pinMappingType; + ECKeyPad * m_pKeypad; + ECSevenSegment * m_pSevenSegment; + PIC_IC * m_pPicComponent; +}; + + +/** +@author David Saxton +*/ +class PinMapView : public ICNView +{ + Q_OBJECT + public: + PinMapView( PinMapDocument * pinMapDocument, ViewContainer * viewContainer, uint viewAreaId, const char * name = 0l ); + ~PinMapView(); +}; + + +class PIC_IC : public Component +{ + public: + PIC_IC( ICNDocument * icnDocument, bool newItem, const char *id = 0L ); + virtual ~PIC_IC(); + + virtual bool canFlip() const { return true; } + static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem * libraryItem(); + + void initPackage( MicroInfo * info ); +}; + +#endif diff --git a/src/flowparts/pulse.cpp b/src/flowparts/pulse.cpp new file mode 100644 index 0000000..2037d2f --- /dev/null +++ b/src/flowparts/pulse.cpp @@ -0,0 +1,85 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "libraryitem.h" +#include "flowcode.h" +#include "pulse.h" + +#include + +Item* Pulse::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Pulse( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Pulse::libraryItem() +{ + return new LibraryItem( + QString::QString("flow/pulse"), + i18n("Pulse"), + i18n("Functions"), + "pppulse.png", + LibraryItem::lit_flowpart, + Pulse::construct + ); +} + +Pulse::Pulse( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "pulse" ) +{ + m_name = i18n("Pulse"); + m_desc = i18n("Pulse a pin high/low for a given duration."); + initProcessSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "0-duration", Variant::Type::Double ); + property("0-duration")->setCaption( i18n("Duration") ); + property("0-duration")->setUnit("sec"); + property("0-duration")->setValue(2.0); + + createProperty( "1-high", Variant::Type::Double ); + property("1-high")->setCaption( i18n("High Time") ); + property("1-high")->setUnit("sec"); + property("1-high")->setValue(0.5); + + createProperty( "2-low", Variant::Type::Double ); + property("2-low")->setCaption( i18n("High Time") ); + property("2-low")->setUnit("sec"); + property("2-low")->setValue(0.5); + + createProperty( "3-pin", Variant::Type::Pin ); + property("3-pin")->setCaption( i18n("Pin") ); + property("3-pin")->setValue("RA0"); +} + +Pulse::~Pulse() +{ +} + + +void Pulse::dataChanged() +{ + double pulse = dataDouble("0-duration"); + setCaption( i18n("Pulse %1 for %2 sec").arg(dataString("3-pin")).arg(QString::number( pulse / getMultiplier(pulse), 'f', 1 ) + getNumberMag(pulse)) ); +} + +void Pulse::generateMicrobe( FlowCode *code ) +{ + const double duration_ms = dataDouble("0-duration")*1e3; + const double high_ms = dataDouble("1-high")*1e3; + const double low_ms = dataDouble("2-low")*1e3; + const QString pin = dataString("3-pin"); + + // TODO Do we want to change the format for pulsing? + code->addCode( "pulse "+pin+" "+QString::number(duration_ms)+" "+QString::number(high_ms)+" "+QString::number(low_ms) ); + code->addCodeBranch( outputPart("stdoutput") ); +} + diff --git a/src/flowparts/pulse.h b/src/flowparts/pulse.h new file mode 100644 index 0000000..db40aee --- /dev/null +++ b/src/flowparts/pulse.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PULSE_H +#define PULSE_H + +#include "flowpart.h" + +/** +@short FlowPart that provides a pulse +@author David Saxton +*/ +class Pulse : public FlowPart +{ +public: + Pulse( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Pulse(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/readport.cpp b/src/flowparts/readport.cpp new file mode 100644 index 0000000..d87fe85 --- /dev/null +++ b/src/flowparts/readport.cpp @@ -0,0 +1,69 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "readport.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* ReadPort::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ReadPort( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ReadPort::libraryItem() +{ + return new LibraryItem( + QString("flow/readport"), + i18n("Read from Port"), + i18n("I\\/O"), + "portread.png", + LibraryItem::lit_flowpart, + ReadPort::construct ); +} + +ReadPort::ReadPort( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "readport" ) +{ + m_name = i18n("Read from Port"); + m_desc = i18n("Assign the value of a port to a variable."); + initIOSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "0-port", Variant::Type::Port ); + property("0-port")->setToolbarCaption( i18n("Read") ); + property("0-port")->setEditorCaption( i18n("Port") ); + property("0-port")->setValue("PORTA"); + + createProperty( "1-var", Variant::Type::VarName ); + property("1-var")->setToolbarCaption( "to" ); + property("1-var")->setEditorCaption( i18n("Variable") ); + property("1-var")->setValue("x"); +} + + +ReadPort::~ReadPort() +{ +} + +void ReadPort::dataChanged() +{ + setCaption( i18n("Read %1 to %2").arg(dataString("0-port")).arg(dataString("1-var")) ); +} + +void ReadPort::generateMicrobe( FlowCode *code ) +{ + code->addCode( dataString("1-var")+" = "+dataString("0-port") ); + code->addCodeBranch( outputPart("stdoutput") ); +} + diff --git a/src/flowparts/readport.h b/src/flowparts/readport.h new file mode 100644 index 0000000..a150f64 --- /dev/null +++ b/src/flowparts/readport.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef READPORT_H +#define READPORT_H + +#include "flowpart.h" + +/** +@short FlowPart that reads from a port +@author David Saxton +*/ +class ReadPort : public FlowPart +{ +public: + ReadPort( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ReadPort(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode * ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/repeat.cpp b/src/flowparts/repeat.cpp new file mode 100644 index 0000000..562bb03 --- /dev/null +++ b/src/flowparts/repeat.cpp @@ -0,0 +1,80 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "repeat.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* Repeat::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Repeat( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Repeat::libraryItem() +{ + return new LibraryItem( + QString("flow/repeat"), + i18n("Repeat"), + i18n("Loops"), + "repeat.png", + LibraryItem::lit_flowpart, + Repeat::construct ); +} + +Repeat::Repeat( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowContainer( icnDocument, newItem, (id) ? id : "repeatloop" ) +{ + m_name = i18n("Repeat"); + m_desc = i18n("Repeatedly execute code, until the given condition is false. The condition is checked after the code has been executed.

    This is different from \"While\", which checks for the condition to be true before the code is executed."); + createTopContainerNode(); + createBotContainerNode(); + + createProperty( "0var1", Variant::Type::Combo ); + property("0var1")->setToolbarCaption( "repeat until" ); + property("0var1")->setEditorCaption( i18n("Variable") ); + property("0var1")->setValue("x"); + + createProperty( "1op", Variant::Type::Select ); + property("1op")->setToolbarCaption(" "); + property("1op")->setEditorCaption( i18n("Operation") ); + property("1op")->setAllowed( QStringList::split( ',', "==,<,>,<=,>=,!=" ) ); + property("1op")->setValue("=="); + + createProperty( "2var2", Variant::Type::Combo ); + property("2var2")->setToolbarCaption(" "); + property("2var2")->setEditorCaption( i18n("Value") ); + property("2var2")->setValue("0"); +} + +Repeat::~Repeat() +{ +} + +void Repeat::dataChanged() +{ + setCaption( i18n("repeat until %1 %2 %3").arg(dataString("0var1")).arg(dataString("1op")).arg(dataString("2var2")) ); +} + +void Repeat::generateMicrobe( FlowCode *code ) +{ + code->addCode("repeat\n{\n"); + code->addCodeBranch( outputPart("int_in") ); + code->addCode("}\n"); + code->addCode("until "+dataString("0var1")+" "+dataString("1op")+" " + dataString("2var2") ); + code->addCodeBranch( outputPart("ext_out") ); +} + + + + + diff --git a/src/flowparts/repeat.h b/src/flowparts/repeat.h new file mode 100644 index 0000000..c363275 --- /dev/null +++ b/src/flowparts/repeat.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef REPEAT_H +#define REPEAT_H + +#include "flowcontainer.h" + +/** +@author David Saxton +*/ +class Repeat : public FlowContainer +{ +public: + Repeat( ICNDocument *icnDocument, bool newItem, const char *id ); + ~Repeat(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode * ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/setpin.cpp b/src/flowparts/setpin.cpp new file mode 100644 index 0000000..b92ac8d --- /dev/null +++ b/src/flowparts/setpin.cpp @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "setpin.h" + +#include "libraryitem.h" +#include "flowcode.h" +#include "picinfo.h" +#include "flowcodedocument.h" +#include "microsettings.h" + +#include + +Item* SetPin::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new SetPin( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* SetPin::libraryItem() +{ + return new LibraryItem( + QString("flow/setpin"), + i18n("Set Pin State"), + i18n("I\\/O"), + "pinwrite.png", + LibraryItem::lit_flowpart, + SetPin::construct ); +} + +SetPin::SetPin( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "setpin" ) +{ + m_name = i18n("Set Pin State"); + m_desc = i18n("Set a pin on a port high or low. The pin needs to be set as an output pin."); + initIOSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "state", Variant::Type::Select ); + property("state")->setCaption( i18n("State") ); + property("state")->setAllowed( QStringList::split( ',', "high,low" ) ); + property("state")->setValue("high"); + + createProperty( "pin", Variant::Type::Pin ); + property("pin")->setCaption( i18n("Pin") ); + property("pin")->setValue("RA0"); +} + +SetPin::~SetPin() +{ +} + +void SetPin::dataChanged() +{ + setCaption( i18n("Set %1 %2").arg(dataString("pin")).arg(dataString("state")) ); +} + +void SetPin::generateMicrobe( FlowCode *code ) +{ + const QString pin = dataString("pin"); + const QString port = "PORT" + QString((QChar)pin[1]); + const QString bit = (QChar)pin[2]; + code->addCode( port+"."+bit+" = "+dataString("state") ); + code->addCodeBranch( outputPart("stdoutput") ); + +#if 0 + const QString pin = dataString("pin"); + const bool isHigh = (dataString("state") == "High"); + const QString port = "PORT" + QString((QChar)pin[1]); + const QString bit = (QChar)pin[2]; + + QString newCode; + if (isHigh) + { + newCode += "bsf " + port + "," + bit + " ; Set bit high\n"; + } + else + { + newCode += "bcf " + port + "," + bit + " ; Set bit low\n"; + } + + code->addCodeBlock( id(), newCode ); +#endif +} diff --git a/src/flowparts/setpin.h b/src/flowparts/setpin.h new file mode 100644 index 0000000..0e662bc --- /dev/null +++ b/src/flowparts/setpin.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef SETPIN_H +#define SETPIN_H + +#include "flowpart.h" + +/** +@short FlowPart that writes a high/low to a pin +@author David Saxton +*/ +class SetPin : public FlowPart +{ +public: + SetPin( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~SetPin(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode * ); + +private: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/sevenseg.cpp b/src/flowparts/sevenseg.cpp new file mode 100644 index 0000000..c376f00 --- /dev/null +++ b/src/flowparts/sevenseg.cpp @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "sevenseg.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* SevenSeg::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new SevenSeg( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* SevenSeg::libraryItem() +{ + return new LibraryItem( + "flow/sevenseg", + i18n("Seven Segment"), + "Functions", + "seven_segment.png", + LibraryItem::lit_flowpart, + SevenSeg::construct + ); +} + + +SevenSeg::SevenSeg( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, id ? id : "sevenseg" ) +{ + m_name = i18n("SevenSeg"); + m_desc = i18n("Output to a Seven Segment display."); + initProcessSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "expression", Variant::Type::Combo ); + property("expression")->setValue("x"); + property("expression")->setCaption( i18n("Variable") ); + + createProperty( "sevenseg", Variant::Type::SevenSegment ); + property("sevenseg")->setCaption( i18n("Pin map") ); +} + + +SevenSeg::~SevenSeg() +{ +} + + +void SevenSeg::dataChanged() +{ + setCaption( i18n("Display %1 on %2").arg( dataString("expression") ).arg( dataString("sevenseg") ) ); +} + + +void SevenSeg::generateMicrobe( FlowCode *code ) +{ + code->addCode( QString("%1 = %2").arg( dataString("sevenseg") ).arg( dataString("expression") ) ); + code->addCodeBranch( outputPart("stdoutput") ); +} + diff --git a/src/flowparts/sevenseg.h b/src/flowparts/sevenseg.h new file mode 100644 index 0000000..47b2979 --- /dev/null +++ b/src/flowparts/sevenseg.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef SEVENSEG_H +#define SEVENSEG_H + +#include "flowpart.h" + +/** +@short Allows a configurable output to a seven segment display +@author David Saxton +*/ +class SevenSeg : public FlowPart +{ +public: + SevenSeg( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~SevenSeg(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/start.cpp b/src/flowparts/start.cpp new file mode 100644 index 0000000..6fd8af0 --- /dev/null +++ b/src/flowparts/start.cpp @@ -0,0 +1,52 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "start.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* Start::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Start( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Start::libraryItem() +{ + return new LibraryItem( + QString::QString("flow/start"), + i18n("Start"), + i18n("Common"), + "start.png", + LibraryItem::lit_flowpart, + Start::construct ); +} + +Start::Start( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "START" ) +{ + m_name = i18n("Start"); + m_desc = i18n("Determines the initial program execution point."); + initRoundedRectSymbol(); + createStdOutput(); + setCaption( i18n("Start") ); +} + +Start::~Start() +{ +} + +void Start::generateMicrobe( FlowCode *code ) +{ + code->addCodeBranch( outputPart("stdoutput") ); +} + diff --git a/src/flowparts/start.h b/src/flowparts/start.h new file mode 100644 index 0000000..8585b4a --- /dev/null +++ b/src/flowparts/start.h @@ -0,0 +1,32 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef START_H +#define START_H + +#include "flowpart.h" + +/** +@short FlowPart that tells the program where to start +@author David Saxton +*/ +class Start : public FlowPart +{ +public: + Start( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Start(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode * ); +}; + +#endif diff --git a/src/flowparts/sub.cpp b/src/flowparts/sub.cpp new file mode 100644 index 0000000..222b167 --- /dev/null +++ b/src/flowparts/sub.cpp @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "sub.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* Sub::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Sub( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Sub::libraryItem() +{ + return new LibraryItem( + QString("flow/sub"), + i18n("Subroutine"), + i18n("Common"), + "sub.png", + LibraryItem::lit_flowpart, + Sub::construct ); +} + +Sub::Sub( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowContainer( icnDocument, newItem, (id) ? id : "sub" ) +{ + m_name = i18n("Sub"); + m_desc = i18n("Defines the starting point of a subroutine. Call this subroutine using \"Call Sub\""); + + createProperty( "sub", Variant::Type::Combo ); + property("sub")->setCaption( i18n("Subroutine") ); + property("sub")->setValue("MySub"); +} + +Sub::~Sub() +{ +} + +void Sub::dataChanged() +{ + setCaption( "Sub " + dataString("sub") ); +} + +void Sub::generateMicrobe( FlowCode *code ) +{ + code->addCode( "\nsub "+dataString("sub")+"\n{" ); + code->addCodeBranch( outputPart("int_in") ); + code->addCode("}"); +} + + +// #include "sub.moc" diff --git a/src/flowparts/sub.h b/src/flowparts/sub.h new file mode 100644 index 0000000..aca2005 --- /dev/null +++ b/src/flowparts/sub.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef SUB_H +#define SUB_H + +#include "flowcontainer.h" + +/** +@short FlowPart that defines the start of a subroutine +@author David Saxton +*/ +class Sub : public FlowContainer +{ +public: + Sub( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Sub(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/testpin.cpp b/src/flowparts/testpin.cpp new file mode 100644 index 0000000..85fdb37 --- /dev/null +++ b/src/flowparts/testpin.cpp @@ -0,0 +1,83 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "testpin.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* TestPin::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new TestPin( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* TestPin::libraryItem() +{ + return new LibraryItem( + QString("flow/testpin"), + i18n("Test Pin State"), + i18n("I\\/O"), + "pinread.png", + LibraryItem::lit_flowpart, + TestPin::construct ); +} + +TestPin::TestPin( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "testpin" ) +{ + m_name = i18n("Test Pin State"); + m_desc = i18n("Conditional branch point, depending on the high/low state of a pin."); + initDecisionSymbol(); + createStdInput(); + createStdOutput(); + createAltOutput(); + + createProperty( "pin", Variant::Type::Pin ); + property("pin")->setCaption( i18n("Pin") ); + property("pin")->setValue("RA0"); + + addDisplayText( "output_false", QRect( offsetX()+width(), 2, 40, 20 ), "Low" ); + addDisplayText( "output_true", QRect( 0, offsetY()+height(), 50, 20 ), "High" ); +} + + +TestPin::~TestPin() +{ +} + + +void TestPin::dataChanged() +{ + setCaption( "Test " + dataString("pin") ); +} + + +void TestPin::generateMicrobe( FlowCode *code ) +{ + const QString pin = dataString("pin"); + const QString port = "PORT" + QString((QChar)pin[1]); + const QString bit = (QChar)pin[2]; + + handleIfElse( code, port+"."+bit+" is high", port+"."+bit+" is low", "stdoutput", "altoutput" ); + +#if 0 + QString newCode; + + newCode += "btfss "+port+","+bit+" ; Check if pin is clear\n"; + newCode += gotoCode("altoutput") + " ; Pin is low\n"; + newCode += gotoCode("stdoutput") + " ; Pin is high, continue on from this point\n"; + + code->addCodeBlock( id(), newCode ); +#endif +} + + diff --git a/src/flowparts/testpin.h b/src/flowparts/testpin.h new file mode 100644 index 0000000..72a1411 --- /dev/null +++ b/src/flowparts/testpin.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef TESTPIN_H +#define TESTPIN_H + +#include "flowpart.h" + +/** +@short FlowPart that tests a pin to see if it's high +@author David Saxton +*/ +class TestPin : public FlowPart +{ +public: + TestPin( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~TestPin(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/unary.cpp b/src/flowparts/unary.cpp new file mode 100644 index 0000000..fe0b549 --- /dev/null +++ b/src/flowparts/unary.cpp @@ -0,0 +1,90 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "unary.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* Unary::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Unary( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Unary::libraryItem() +{ + return new LibraryItem( + QString("flow/unary"), + i18n("Unary"), + i18n("Variables"), + "unary.png", + LibraryItem::lit_flowpart, + Unary::construct ); +} + +Unary::Unary( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "unary" ) +{ + m_name = i18n("Unary"); + m_desc = i18n("A unary operation involves only one variable. Suppo operations are:
    • Rotate Left rotates the binary bits of the variable left (discarding the end bits).
    • Rotate Right rotates the binary bits right (discarding the start bits).
    • Increment increases the value of the variable by 1. A value of 255 wraps around to 0.
    • Decrement decreases the value of a variable by 1. A value of 0 wraps around to 255.
    "); + initProcessSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "0-var", Variant::Type::VarName ); + property("0-var")->setValue("x"); + property("0-var")->setCaption( i18n("Variable") ); + + createProperty( "1-op", Variant::Type::Select ); + property("1-op")->setCaption( i18n("Operation") ); + property("1-op")->setAllowed( QStringList::split( ',', "Rotate Left,Rotate Right,Increment,Decrement" ) ); + property("1-op")->setValue("Rotate Left"); +} + +Unary::~Unary() +{ +} + +void Unary::dataChanged() +{ + setCaption( dataString("0-var") + " " + dataString("1-op") ); +} + +void Unary::generateMicrobe( FlowCode *code ) +{ + const QString var = dataString("0-var"); + const QString op = dataString("1-op"); + + if ( op == "Rotate Left" ) code->addCode( "rotateleft "+var ); + else if ( op == "Rotate Right" ) code->addCode( "rotateright "+var ); + else if ( op == "Increment" ) code->addCode( "increment "+var ); + else if ( op == "Decrement" ) code->addCode( "decrement "+var ); + else; // Hmm... + code->addCodeBranch( outputPart("stdoutput") ); + +#if 0 + QString rot = dataString("1-rot"); + + if ( FlowCode::isLiteral(var) ) return; + + QString newCode; + + code->addVariable(var); + if ( rot == "Left" ) newCode += "rlf " + var + ",1 ; Unary " + var + " left through Carry, place result back in " + var + "\n"; + else newCode += "rrf " + var + ",1 ; Unary " + var + " right through Carry, place result back in " + var + "\n"; + + newCode += gotoCode("stdoutput"); + code->addCodeBlock( id(), newCode ); +#endif +} + + diff --git a/src/flowparts/unary.h b/src/flowparts/unary.h new file mode 100644 index 0000000..ec830d6 --- /dev/null +++ b/src/flowparts/unary.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ROTATE_H +#define ROTATE_H + +#include "flowpart.h" + +/** +@short FlowPart that rotates a variable +@author David Saxton +*/ +class Unary : public FlowPart +{ +public: + Unary( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Unary(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/varassignment.cpp b/src/flowparts/varassignment.cpp new file mode 100644 index 0000000..44b76fd --- /dev/null +++ b/src/flowparts/varassignment.cpp @@ -0,0 +1,100 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "varassignment.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* VarAssignment::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new VarAssignment( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* VarAssignment::libraryItem() +{ + return new LibraryItem( + QString::QString("flow/varassignment"), + i18n("Assignment"), + i18n("Variables"), + "assignment.png", + LibraryItem::lit_flowpart, + VarAssignment::construct ); +} + +VarAssignment::VarAssignment( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "varassignment" ) +{ + m_name = i18n("Variable Assignment"); + m_desc = i18n("Assigns the evaluation of an expression to a variable. The expression can take many forms. For example:
    • x = 2
    • x = y + 3
    • x = y + z
    • x = 2 * y
    "); + initProcessSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "0-var1", Variant::Type::VarName ); + property("0-var1")->setCaption( i18n("Variable") ); + property("0-var1")->setValue("x"); + + createProperty( "2-var2", Variant::Type::Combo ); + property("2-var2")->setToolbarCaption(" = "); + property("2-var2")->setEditorCaption( i18n("Value") ); + property("2-var2")->setValue("0"); + +} + +VarAssignment::~VarAssignment() +{ +} + +void VarAssignment::dataChanged() +{ + setCaption( dataString("0-var1") + " " + "=" /*dataString("1-op")*/ + " " + dataString("2-var2") ); +} + +void VarAssignment::generateMicrobe( FlowCode *code ) +{ + code->addCode( dataString("0-var1")+" "+"="/*dataString("1-op")*/+" "+dataString("2-var2") ); + code->addCodeBranch( outputPart("stdoutput") ); + +#if 0 + QString var1 = dataString("0-var1"); + QString var2 = dataString("2-var2"); + QString op = dataString("1-op"); + + if ( FlowCode::isLiteral(var1) ) return; + code->addVariable(var1); + + QString newCode; + + if ( !FlowCode::isLiteral(var1) ) + { + if ( FlowCode::isLiteral(var2) ) newCode += "movlw " + var2 + " ; Assign " + var2 + " to w register\n"; + } + + if ( !FlowCode::isLiteral(var2) ) + { + code->addVariable(var2); + newCode += "movf " + var2 + ",0 ; Move " + var2 + " to w register\n"; + } + + if ( op == "=" ) newCode += "movwf " + var1 + " ; Move contents of w register to " + var1 + "\n"; + else if ( op == "+=" ) newCode += "addwf " + var1 + ",1 ; Add contents of w register to " + var1 + " and place result back in " + var1 + "\n"; + else if ( op == "-=" ) newCode += "subwf " + var1 + ",1 ; Subtract contents of w register from " + var1 + " and place result back in " + var1 + "\n"; + else if ( op == "&=" ) newCode += "andwf " + var1 + ",1 ; Binary AND contents of w register with " + var1 + " and place result back in " + var1 + "\n"; + else if ( op == "or=" ) newCode += "iorwf " + var1 + ",1 ; Binary inclusive OR contents of w register with " + var1 + " and place result back in " + var1 + "\n"; + else if ( op == "xor=" ) newCode += "xorwf " + var1 + ",1 ; Binary exclusive OR contents of w register with " + var1 + " and place result back in " + var1 + "\n"; + + newCode += gotoCode("stdoutput"); + + code->addCodeBlock( id(), newCode ); +#endif +} diff --git a/src/flowparts/varassignment.h b/src/flowparts/varassignment.h new file mode 100644 index 0000000..25cb78c --- /dev/null +++ b/src/flowparts/varassignment.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef VARASSIGNMENT_H +#define VARASSIGNMENT_H + +#include "flowpart.h" + +/** +@short FlowPart that assigns a value to a variable +@author David Saxton +*/ +class VarAssignment : public FlowPart +{ +public: + VarAssignment( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~VarAssignment(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/varcomparison.cpp b/src/flowparts/varcomparison.cpp new file mode 100644 index 0000000..e01ebf2 --- /dev/null +++ b/src/flowparts/varcomparison.cpp @@ -0,0 +1,170 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "varcomparison.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* VarComparison::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new VarComparison( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* VarComparison::libraryItem() +{ + return new LibraryItem( + QString("flow/varcomparison"), + i18n("Comparison"), + i18n("Variables"), + "branch.png", + LibraryItem::lit_flowpart, + VarComparison::construct ); +} + +VarComparison::VarComparison( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "varcomparison" ) +{ + m_name = i18n("Variable Comparison"); + m_desc = i18n("Conditional branch point, depending on the comparison of two values. The supported comparisons are:
    • x == y - Equality: true if x has the same value as y.
    • x < y - Less than: true if x is smaller than y.
    • x > y - Greater than: true if x is bigger than y.
    • x <= y - Less than or equal: true if x is less than or equal to y.
    • x >= y - Greater than or equal: true if x is greater than or equal to y.
    • x != y - Does not equal: true if x does not have the same value as y.
    "); + initDecisionSymbol(); + createStdInput(); + createStdOutput(); + createAltOutput(); + + createProperty( "0var1", Variant::Type::Combo ); + property("0var1")->setCaption( i18n("Variable") ); + property("0var1")->setValue("x"); + + createProperty( "1op", Variant::Type::Select ); + property("1op")->setAllowed( QStringList::split( ',', "==,<,>,<=,>=,!=" ) ); + property("1op")->setValue("=="); + property("1op")->setToolbarCaption(" "); + property("1op")->setEditorCaption( i18n("Operation") ); + + createProperty( "2var2", Variant::Type::Combo ); + property("2var2")->setToolbarCaption(" "); + property("2var2")->setEditorCaption( i18n("Value") ); + property("2var2")->setValue("0"); + + addDisplayText( "output_false", QRect( offsetX()+width(), 2, 40, 20 ), "No" ); + addDisplayText( "output_true", QRect( 0, offsetY()+height(), 50, 20 ), "Yes" ); +} + +VarComparison::~VarComparison() +{ +} + +void VarComparison::dataChanged() +{ + setCaption( dataString("0var1") + " " + dataString("1op") + " " + dataString("2var2") + " ?" ); +} + +QString VarComparison::oppOp( const QString &op ) +{ + if ( op == "==" ) return "!="; + if ( op == "!=" ) return "=="; + else if ( op == "<" ) return ">="; + else if ( op == ">=" ) return "<"; + else if ( op == ">" ) return "<="; + else if ( op == "<=" ) return ">"; + else return "__UNKNOWN_OP__"; +} + +void VarComparison::generateMicrobe( FlowCode *code ) +{ + QString var1 = dataString("0var1"); + QString var2 = dataString("2var2"); + QString test = dataString("1op"); + + handleIfElse( code, var1+" "+test+" "+var2, var1+" "+oppOp(test)+" "+var2, "stdoutput", "altoutput" ); + +#if 0 + code->addCode( "if "+var1+" "+test+" "+var2+"\n{\n" ); + code->addCodeBranch( outputPart("stdoutput") ); + code->addCode("}"); + if ( outputPart("altoutput") ) + { + code->addCode("else\n{"); + code->addCodeBranch( outputPart("altoutput") ); + code->addCode("}"); + } +#endif + +#if 0 + QString newCode; + + if ( FlowCode::isLiteral(var2) ) newCode += "movlw " + var2 + " ; Move literal to register w\n"; + else + { + code->addVariable(var2); + newCode += "movf " + var2 + ",0 ; Move " + var2 + " to register w\n"; + } + + if ( FlowCode::isLiteral(var1) ) newCode += "sublw " + var1 + " ; Subtract register w from " + var1 + ", placing result in w\n"; + else + { + code->addVariable(var1); + newCode += "subwf " + var1 + ",0 ; Subtract register w from " + var1 + ", placing result in w\n"; + } + + + if ( test == "==" ) + { + // check: works + newCode += "btfss STATUS,2 ; Check if zero flag is set\n"; + newCode += gotoCode("altoutput") + " ; Result from calculation was non-zero; hence comparison is false\n"; + newCode += gotoCode("stdoutput") + " ; Ouput was zero; hence comparison is true, so continue from this point\n"; + } + else if ( test == "!=" ) + { + // check: works + newCode += "btfsc STATUS,2 ; Check if zero flag is clear\n"; + newCode += gotoCode("altoutput") + " ; Result from calculation was zero; hence comparison is false\n"; + newCode += gotoCode("stdoutput") + " ; Output was non-zero; hence comparison is true, so continue from this point\n"; + } + else if ( test == ">=" ) + { + // check: works + newCode += "btfss STATUS,0 ; Check if carry flag is set\n"; + newCode += gotoCode("altoutput") + " ; Result from calculation is negative; hence comparison is false\n"; + newCode += gotoCode("stdoutput") + " ; Result from calculation is positive or zero; so continue from this point\n"; + } + else if ( test == ">" ) + { + // check: works + newCode += "btfss STATUS,0 ; Check if carry flag is set\n"; + newCode += gotoCode("altoutput") + " ; Result is negative; hence comparison is false\n"; + newCode += "btfsc STATUS,2 ; Check if zero flag is set\n"; + newCode += gotoCode("altoutput") + " ; Result is zero; hence comparison is false\n"; + newCode += gotoCode("stdoutput") + " ; Comparison is true, so continue from this point\n"; + } + else if ( test == "<" ) + { + // check: works + newCode += "btfsc STATUS,0 ; Check if carry flag is set\n"; + newCode += gotoCode("altoutput"); + newCode += gotoCode("stdoutput"); + } + else if ( test == "<=" ) + { + // check: works + newCode += "btfsc STATUS,2 ; Check if result is zero\n"; + newCode += gotoCode("stdoutput") + " ; Result is zero; hence comparison is true\n"; + newCode += "btfsc STATUS,0 ; Check if carry flag is set\n"; + newCode += gotoCode("altoutput") + " ; Result is positive (not zero, has already tested for this); hence comparison is false\n"; + newCode += gotoCode("stdoutput") + " ; Result is negative, hence comparison is true\n"; + } + + code->addCodeBlock( id(), newCode ); +#endif +} diff --git a/src/flowparts/varcomparison.h b/src/flowparts/varcomparison.h new file mode 100644 index 0000000..b1220c8 --- /dev/null +++ b/src/flowparts/varcomparison.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef VARCOMPARISON_H +#define VARCOMPARISON_H + +#include "flowpart.h" + +/** +@short FlowPart that compares two values +@author David Saxton +*/ +class VarComparison : public FlowPart +{ +public: + VarComparison( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~VarComparison(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); + /** + * Use this to find the logically opposite comparison (e.g. "==" returns "!=", + * ">=" returns "<", etc). Supoorted ops: != == <= >= < > + */ + QString oppOp( const QString &op ); +}; + +#endif diff --git a/src/flowparts/while.cpp b/src/flowparts/while.cpp new file mode 100644 index 0000000..b0461df --- /dev/null +++ b/src/flowparts/while.cpp @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "while.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* While::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new While( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* While::libraryItem() +{ + return new LibraryItem( + QString("flow/while"), + i18n("While"), + i18n("Loops"), + "while.png", + LibraryItem::lit_flowpart, + While::construct ); +} + +While::While( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowContainer( icnDocument, newItem, (id) ? id : "whileloop" ) +{ + m_name = i18n("While"); + m_desc = i18n("Repeatedly execute code, until the given condition is false. The condition is checked before the code has been executed.

    This is different from \"Repeat\", which checks for the condition to be true after the code is executed."); + createTopContainerNode(); + createBotContainerNode(); + + createProperty( "0var1", Variant::Type::Combo ); + property("0var1")->setToolbarCaption( "while" ); + property("0var1")->setEditorCaption( i18n("Variable") ); + property("0var1")->setValue("x"); + + createProperty( "1op", Variant::Type::Select ); + property("1op")->setToolbarCaption(" "); + property("1op")->setEditorCaption( i18n("Operation") ); + property("1op")->setAllowed( QStringList::split( ',', "==,<,>,<=,>=,!=" ) ); + property("1op")->setValue("=="); + + createProperty( "2var2", Variant::Type::Combo ); + property("2var2")->setToolbarCaption(" "); + property("2var2")->setEditorCaption( i18n("Value") ); + property("2var2")->setValue("0"); +} + +While::~While() +{ +} + +void While::dataChanged() +{ + setCaption( i18n("while %1 %2 %3").arg(dataString("0var1")).arg(dataString("1op")).arg(dataString("2var2")) ); +} + +void While::generateMicrobe( FlowCode *code ) +{ + code->addCode("while "+dataString("0var1")+" "+dataString("1op")+" " + dataString("2var2")+"\n{" ); + code->addCodeBranch( outputPart("int_in") ); + code->addCode("}"); + code->addCodeBranch( outputPart("ext_out") ); +} + + + + + diff --git a/src/flowparts/while.h b/src/flowparts/while.h new file mode 100644 index 0000000..51f851a --- /dev/null +++ b/src/flowparts/while.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef WHILE_H +#define WHILE_H + +#include "flowcontainer.h" + +/** +@author David Saxton +*/ +class While : public FlowContainer +{ +public: + While( ICNDocument *icnDocument, bool newItem, const char *id ); + ~While(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/writeport.cpp b/src/flowparts/writeport.cpp new file mode 100644 index 0000000..dede6f1 --- /dev/null +++ b/src/flowparts/writeport.cpp @@ -0,0 +1,95 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "writeport.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include + +Item* WritePort::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new WritePort( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* WritePort::libraryItem() +{ + return new LibraryItem( + QString("flow/writeport"), + i18n("Write to Port"), + i18n("I\\/O"), + "portwrite.png", + LibraryItem::lit_flowpart, + WritePort::construct ); +} + +WritePort::WritePort( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "writeport" ) +{ + m_name = i18n("Write to Port"); + m_desc = i18n("Sets the port's pins state to high/low from the given value. Only pins that have been configured as output pins will take on the value assigned to them."); + initIOSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "0-var", Variant::Type::Combo ); + property("0-var")->setToolbarCaption( i18n("Write") ); + property("0-var")->setEditorCaption( i18n("Variable") ); + property("0-var")->setValue("x"); + + createProperty( "1-port", Variant::Type::Port ); + property("1-port")->setToolbarCaption( "to" ); + property("1-port")->setEditorCaption( i18n("Port") ); + property("1-port")->setValue("PORTA"); +} + + +WritePort::~WritePort() +{ +} + + +void WritePort::dataChanged() +{ + setCaption( i18n("Write %1 to %2").arg(dataString("0-var")).arg(dataString("1-port")) ); +} + + +void WritePort::generateMicrobe( FlowCode *code ) +{ + code->addCode( dataString("1-port")+" = "+dataString("0-var") ); + code->addCodeBranch( outputPart("stdoutput") ); + +#if 0 + QString var = dataString("var"); + QString port = dataString("port"); + + // WTF? I don't want to do this! +// QString newCode = "bsf STATUS,5 ; Move to bank 1\n"; + QString newCode; + + if ( FlowCode::isLiteral(var) ) newCode += "movlw " + var + " ; Move " + var + " to working register w\n"; + else + { + code->addVariable(var); + newCode += "movf " + var + ",0 ; Move " + var + " to working register w\n"; + } + + newCode += "movwf " + port + " ; Move register w to port\n"; + + // Same for below as for above +// newCode += "bcf STATUS,5 ; Come back to bank 0\n"; + + newCode += gotoCode("stdoutput") + "\n"; + + code->addCodeBlock( id(), newCode ); +#endif +} diff --git a/src/flowparts/writeport.h b/src/flowparts/writeport.h new file mode 100644 index 0000000..335db3b --- /dev/null +++ b/src/flowparts/writeport.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef WRITEPORT_H +#define WRITEPORT_H + +#include "flowpart.h" + +/** +@short FlowPart that writes to a port +@author David Saxton +*/ +class WritePort : public FlowPart +{ +public: + WritePort( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~WritePort(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +private: + void dataChanged(); +}; + +#endif diff --git a/src/fpnode.cpp b/src/fpnode.cpp new file mode 100644 index 0000000..39901c6 --- /dev/null +++ b/src/fpnode.cpp @@ -0,0 +1,212 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "icndocument.h" +#include "connector.h" +#include "flowpart.h" +#include "fpnode.h" + +#include +#include + +FPNode::FPNode( ICNDocument *icnDocument, Node::node_type type, node_dir dir, const QPoint &pos, QString *id ) + : Node( icnDocument, type, dir, pos, id ) +{ + icnDocument->registerItem(this); +} + + +FPNode::~FPNode() +{ +} + + +FlowPart *FPNode::outputFlowPart() const +{ + FlowPart *flowPart = dynamic_cast(parentItem()); + + if ( type() == fp_in ) + return flowPart; + + if ( m_outputConnectorList.size() > 1 ) + kdError() << "FpNode::outputFlowPart(): outputConnectorList() size is greater than 1"<endNode() ) + return 0L; + + return (dynamic_cast((*it)->endNode()))->outputFlowPart(); +} + + +FlowPartList FPNode::inputFlowParts() const +{ + FlowPartList list; + FlowPart *flowPart = dynamic_cast(parentItem()); + if ( type() != fp_in && flowPart ) + { + list.append(flowPart); + return list; + } + const ConnectorList::const_iterator end = m_inputConnectorList.end(); + for ( ConnectorList::const_iterator it = m_inputConnectorList.begin(); it != end; ++it ) + { + if (*it) + { + Node *startNode = (*it)->startNode(); + FlowPart *flowPart = startNode ? dynamic_cast(startNode->parentItem()) : 0l; + if (flowPart) + list.append(flowPart); + } + } + return list; +} + + +inline QPointArray arrowPoints( Node::node_dir dir ) +{ + QPointArray pa(3); + switch (dir) + { + case Node::dir_right: + pa[0] = QPoint( 3, 0 ); + pa[1] = QPoint( 0, 2 ); + pa[2] = QPoint( 0, -2 ); + break; + case Node::dir_left: + pa[0] = QPoint( -3, 0 ); + pa[1] = QPoint( 0, 2 ); + pa[2] = QPoint( 0, -2 ); + break; + case Node::dir_down: + pa[0] = QPoint( 2, 0 ); + pa[1] = QPoint( -2, 0 ); + pa[2] = QPoint( 0, 3 ); + break; + case Node::dir_up: + pa[0] = QPoint( 2, 0 ); + pa[1] = QPoint( -2, 0 ); + pa[2] = QPoint( 0, -3 ); + break; + }; + return pa; +} + + +void FPNode::drawShape( QPainter &p ) +{ + const int _x = (int)x(); + const int _y = (int)y(); + + if ( type() == fp_junction && !m_inputConnectorList.isEmpty() ) + { + const ConnectorList::iterator end = m_inputConnectorList.end(); + for ( ConnectorList::iterator it = m_inputConnectorList.begin(); it != end; ++ it) + { + Connector * connector = *it; + if (!connector) + continue; + + // Work out the direction of the connector + const QPointList points = connector->connectorPoints(false); + + const int count = points.size(); + if ( count < 2 ) + continue; + + QPoint end_0 = points[count-1]; + QPoint end_1 = points[count-2]; + + QPointArray pa; + if ( end_0.x() < end_1.x() ) + { + pa = arrowPoints( Node::dir_left ); + pa.translate( 4, 0 ); + } + else if ( end_0.x() > end_1.x() ) + { + pa = arrowPoints( Node::dir_right ); + pa.translate( -4, 0 ); + } + else if ( end_0.y() < end_1.y() ) + { + pa = arrowPoints( Node::dir_up ); + pa.translate( 0, 4 ); + } + else if ( end_0.y() > end_1.y() ) + { + pa = arrowPoints( Node::dir_down ); + pa.translate( 0, -4 ); + } + else + continue; + + pa.translate( _x, _y ); + p.setPen( connector->isSelected() ? m_selectedColor : Qt::black ); + p.drawPolygon(pa); + } + return; + } + + if ( m_dir == Node::dir_right ) p.drawLine( _x, _y, _x-8, _y ); + else if ( m_dir == Node::dir_down ) p.drawLine( _x, _y, _x, _y-8 ); + else if ( m_dir == Node::dir_left ) p.drawLine( _x, _y, _x+8, _y ); + else if ( m_dir == Node::dir_up ) p.drawLine( _x, _y, _x, _y+8 ); + + QPointArray pa(3); + + // Right facing arrow + if ( (type() == fp_out && m_dir == Node::dir_right) || + (type() == fp_in && m_dir == Node::dir_left ) ) + pa = arrowPoints( Node::dir_right ); + + // Left facing arrow + else if ( (type() == fp_out && m_dir == Node::dir_left) || + (type() == fp_in && m_dir == Node::dir_right) ) + pa = arrowPoints( Node::dir_left ); + + // Down facing arrow + else if ( (type() == fp_out && m_dir == Node::dir_down) || + (type() == fp_in && m_dir == Node::dir_up) ) + pa = arrowPoints( Node::dir_down ); + + // Up facing arrow + else + pa = arrowPoints( Node::dir_up ); + + + // Note: I have not tested the positioning of the arrows for all combinations. + // In fact, most almost definitely do not work. So feel free to change the code + // as you see fit if necessary. + + if ( type() == fp_out ) + { + if ( m_dir == Node::dir_right ) pa.translate( -5, 0 ); + else if ( m_dir == Node::dir_down ) pa.translate( 0, -5 ); + else if ( m_dir == Node::dir_left ) pa.translate( 5, 0 ); + else if ( m_dir == Node::dir_up ) pa.translate( 0, 5 ); + } + else if ( type() == fp_in ) + { + if ( m_dir == Node::dir_right ); + else if ( m_dir == Node::dir_down ); + else if ( m_dir == Node::dir_left ) pa.translate( 3, 0 ); + else if ( m_dir == Node::dir_up ) pa.translate( 0, 3 ); + } + else return; + + pa.translate( _x, _y ); + p.drawPolygon(pa); +} + +#include "fpnode.moc" diff --git a/src/fpnode.h b/src/fpnode.h new file mode 100644 index 0000000..43d1834 --- /dev/null +++ b/src/fpnode.h @@ -0,0 +1,53 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef FPNODE_H +#define FPNODE_H + +#include "node.h" + + +class FlowPart; +typedef QValueList FlowPartList; + +/** +You should use this node for all FlowParts. It ensures that connections between FlowParts are +always valid (eg not more than two outputs from one node, which makes no sense) +@short FlowPart node +@author David Saxton +*/ +class FPNode : public Node +{ +Q_OBJECT +public: + FPNode( ICNDocument *_icnView, Node::node_type type, node_dir dir, const QPoint &pos, QString *id = 0L ); + ~FPNode(); + + /** + * Returns a pointer to the FlowPart attached to this node if this node isInput, or + * to the other end of the connector (if one exists) if it isOutput() + */ + FlowPart *outputFlowPart() const; + /** + * Returns a list of FlowParts attached to the node - either a single-item list containing + * the FlowPart attached to this node if isOutput, or a list of FlowParts connected to the + * input (?) connectors + */ + FlowPartList inputFlowParts() const; + +protected: + virtual void drawShape( QPainter & p ); + +private: + bool m_isInput; +}; + +#endif + diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am new file mode 100644 index 0000000..07b9dbb --- /dev/null +++ b/src/gui/Makefile.am @@ -0,0 +1,23 @@ +INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/core \ + -I$(top_srcdir)/src/electronics -I$(top_srcdir)/src/electronics/components \ + -I$(top_srcdir)/src/electronics/simulation -I$(top_srcdir)/src/flowparts -I$(top_srcdir)/src/gui \ + -I$(top_srcdir)/src/languages -I$(top_srcdir)/src/mechanics -I$(top_srcdir)/src/micro \ + -I$(top_srcdir)/gpsim-interface $(all_includes) +METASOURCES = AUTO +noinst_LTLIBRARIES = libgui.la +libgui_la_SOURCES = contexthelp.cpp doublespinbox.cpp itemeditor.cpp \ + itemselector.cpp microsettingsdlg.cpp newfiledlg.cpp orientationwidget.cpp \ + outputmethoddlg.cpp pieditor.cpp plvitem.cpp propertieslistview.cpp asmformattingwidget.ui \ + gpasmsettingswidget.ui logicwidget.ui newfilewidget.ui newprojectwidget.ui \ + outputmethodwidget.ui microsettingswidget.ui settingsdlg.cpp oscilloscope.cpp \ + oscilloscopewidget.ui oscilloscopeview.cpp probepositioner.cpp generaloptionswidget.ui \ + logview.cpp createsubprojectwidget.ui processingoptionswidget.ui \ + sdccoptionswidget.ui projectdlgs.cpp linkeroptionswidget.ui microselectwidget.cpp \ + symbolviewer.cpp picprogrammerconfigwidget.ui newpinmappingwidget.ui programmerwidget.ui \ + programmerdlg.cpp colorcombo.cpp + +libgui_la_PCH = AUTO + +noinst_HEADERS = settingsdlg.h oscilloscope.h oscilloscopeview.h \ + probepositioner.h projectdlgs.h microselectwidget.h symbolviewer.h programmerdlg.h \ + colorcombo.h diff --git a/src/gui/asmformattingwidget.ui b/src/gui/asmformattingwidget.ui new file mode 100644 index 0000000..ecfa529 --- /dev/null +++ b/src/gui/asmformattingwidget.ui @@ -0,0 +1,213 @@ + +AsmFormattingWidget + + + AsmFormattingWidget + + + + 0 + 0 + 425 + 219 + + + + Asm Formatting + + + The values control the indentation from the left margin of the various types of assembly code. + + + + unnamed + + + 0 + + + + groupBox64 + + + Output Code Indentation + + + + unnamed + + + + textLabel11 + + + 'equ' Value + + + + + textLabel8 + + + Instruction Data + + + + + textLabel9 + + + Comment + + + + + textLabel10 + + + 'equ' + + + + + textLabel7 + + + Instruction Name + + + + + kcfg_IndentAsmName + + + + 5 + 0 + 0 + 0 + + + + 4 + + + + + + + + kcfg_IndentAsmData + + + + 5 + 0 + 0 + 0 + + + + 14 + + + + + kcfg_IndentEqu + + + + 5 + 0 + 0 + 0 + + + + 14 + + + + + kcfg_IndentEquValue + + + + 5 + 0 + 0 + 0 + + + + 20 + + + + + kcfg_IndentComment + + + + 5 + 0 + 0 + 0 + + + + -1 + + + 40 + + + + + + + kcfg_AutoFormatMBOutput + + + &Automatically format Microbe output + + + Alt+A + + + + + spacer57 + + + Vertical + + + Expanding + + + + 20 + 484 + + + + + + + kcfg_IndentAsmName + kcfg_IndentAsmData + kcfg_IndentEquValue + kcfg_IndentEqu + kcfg_IndentComment + kcfg_AutoFormatMBOutput + + + + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + + diff --git a/src/gui/colorcombo.cpp b/src/gui/colorcombo.cpp new file mode 100644 index 0000000..aec39ae --- /dev/null +++ b/src/gui/colorcombo.cpp @@ -0,0 +1,194 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "colorcombo.h" + +#include +#include +#include + +bool ColorCombo::createdPalettes = false; +QColor * ColorCombo::palette[ NumberOfSchemes ]; +int ColorCombo::paletteSize[ NumberOfSchemes ]; + +ColorCombo::ColorCombo( ColorScheme colorScheme, QWidget *parent, const char *name ) + : QComboBox( parent, name ) +{ + m_colorScheme = colorScheme; + + customColor.setRgb( 255, 255, 255 ); + internalColor.setRgb( 255, 255, 255 ); + + createPalettes(); + + addColors(); + + connect( this, SIGNAL( activated(int) ), SLOT( slotActivated(int) ) ); + connect( this, SIGNAL( highlighted(int) ), SLOT( slotHighlighted(int) ) ); +} + + +ColorCombo::~ColorCombo() +{ +} + + +void ColorCombo::createPalettes() +{ + if ( createdPalettes ) + return; + createdPalettes = true; + + paletteSize[ QtStandard ] = 17; + palette[ QtStandard ] = new QColor[ paletteSize[ QtStandard ] ]; + + int i = 0; + + palette[ QtStandard ][i++] = Qt::red; + palette[ QtStandard ][i++] = Qt::green; + palette[ QtStandard ][i++] = Qt::blue; + palette[ QtStandard ][i++] = Qt::cyan; + palette[ QtStandard ][i++] = Qt::magenta; + palette[ QtStandard ][i++] = Qt::yellow; + palette[ QtStandard ][i++] = Qt::darkRed; + palette[ QtStandard ][i++] = Qt::darkGreen; + palette[ QtStandard ][i++] = Qt::darkBlue; + palette[ QtStandard ][i++] = Qt::darkCyan; + palette[ QtStandard ][i++] = Qt::darkMagenta; + palette[ QtStandard ][i++] = Qt::darkYellow; + palette[ QtStandard ][i++] = Qt::white; + palette[ QtStandard ][i++] = Qt::lightGray; + palette[ QtStandard ][i++] = Qt::gray; + palette[ QtStandard ][i++] = Qt::darkGray; + palette[ QtStandard ][i++] = Qt::black; + + + paletteSize[ LED ] = 6; + palette[ LED ] = new QColor[ paletteSize[ LED ] ]; + + i = 0; + palette[ LED ][i++] = "#f62a2a"; + palette[ LED ][i++] = "#ff7733"; + palette[ LED ][i++] = "#ffbb33"; + palette[ LED ][i++] = "#eeee22"; + palette[ LED ][i++] = "#4cc308"; + palette[ LED ][i++] = "#22aaee"; +} + + +void ColorCombo::setColor( const QColor &col ) +{ + internalColor = col; + addColors(); +} + + +void ColorCombo::resizeEvent( QResizeEvent *re ) +{ + QComboBox::resizeEvent( re ); + addColors(); +} + + +void ColorCombo::slotActivated( int index ) +{ + if ( index == 0 ) + { + if ( KColorDialog::getColor( customColor, this ) == QDialog::Accepted ) + { + QPainter painter; + QPen pen; + QRect rect( 0, 0, width(), QFontMetrics(painter.font()).height()+4); + QPixmap pixmap( rect.width(), rect.height() ); + + if ( qGray( customColor.rgb() ) < 128 ) + pen.setColor( white ); + else + pen.setColor( black ); + + painter.begin( &pixmap ); + QBrush brush( customColor ); + painter.fillRect( rect, brush ); + painter.setPen( pen ); + painter.drawText( 2, QFontMetrics(painter.font()).ascent()+2, i18n("Custom...") ); + painter.end(); + + changeItem( pixmap, 0 ); + pixmap.detach(); + } + + internalColor = customColor; + } + else + internalColor = palette[ m_colorScheme ][ index - 1 ]; + + emit activated( internalColor ); +} + +void ColorCombo::slotHighlighted( int index ) +{ + if ( index == 0 ) + internalColor = customColor; + else + internalColor = palette[ m_colorScheme ][ index - 1 ]; + + emit highlighted( internalColor ); +} + +void ColorCombo::addColors() +{ + QPainter painter; + QPen pen; + QRect rect( 0, 0, width(), QFontMetrics(painter.font()).height()+4 ); + QPixmap pixmap( rect.width(), rect.height() ); + int i; + + clear(); + + createPalettes(); + + for ( i = 0; i < paletteSize[ m_colorScheme ]; i++ ) + if ( palette[ m_colorScheme ][i] == internalColor ) break; + + if ( i == paletteSize[ m_colorScheme ] ) + customColor = internalColor; + + if ( qGray( customColor.rgb() ) < 128 ) + pen.setColor( white ); + else + pen.setColor( black ); + + painter.begin( &pixmap ); + QBrush brush( customColor ); + painter.fillRect( rect, brush ); + painter.setPen( pen ); + painter.drawText( 2, QFontMetrics(painter.font()).ascent()+2, i18n("Custom...") ); + painter.end(); + + insertItem( pixmap ); + pixmap.detach(); + + for ( i = 0; i < paletteSize[ m_colorScheme ]; i++ ) + { + painter.begin( &pixmap ); + QBrush brush( palette[ m_colorScheme ][i] ); + painter.fillRect( rect, brush ); + painter.end(); + + insertItem( pixmap ); + pixmap.detach(); + + if ( palette[ m_colorScheme ][i] == internalColor ) + setCurrentItem( i + 1 ); + } +} + + +#include "colorcombo.moc" diff --git a/src/gui/colorcombo.h b/src/gui/colorcombo.h new file mode 100644 index 0000000..65b2714 --- /dev/null +++ b/src/gui/colorcombo.h @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef COLORCOMBO_H +#define COLORCOMBO_H + +#include +#include + +/** +Based on KColorCombo, Copyright (C) 1997 Martin Jones (mjones@kde.org). Allows +which colours are displayed to be changed. + +@author David Saxton +*/ +class ColorCombo : public QComboBox +{ + Q_OBJECT + Q_PROPERTY( QColor color READ color WRITE setColor ) + + public: + enum ColorScheme + { + QtStandard = 0, + LED = 1, + NumberOfSchemes = 2, ///< for internal usage; this should be one less than the number of items in the enum + }; + + /** + * Constructs a color combo box. + */ + ColorCombo( ColorScheme colorScheme, QWidget *parent, const char *name = 0L ); + ~ColorCombo(); + + /** + * Selects the color @p col. + */ + void setColor( const QColor & col ); + /** + * Returns the currently selected color. + **/ + QColor color() const { return internalColor; } + + signals: + /** + * Emitted when a new color box has been selected. + */ + void activated( const QColor &col ); + /** + * Emitted when a new item has been highlighted. + */ + void highlighted( const QColor &col ); + + protected slots: + void slotActivated( int index ); + void slotHighlighted( int index ); + + protected: + virtual void resizeEvent( QResizeEvent *re ); + void addColors(); + void createPalettes(); + + QColor customColor; + QColor internalColor; + ColorScheme m_colorScheme; + + static bool createdPalettes; + static QColor * palette[ NumberOfSchemes ]; + static int paletteSize[ NumberOfSchemes ]; +}; + +#endif diff --git a/src/gui/contexthelp.cpp b/src/gui/contexthelp.cpp new file mode 100644 index 0000000..3444737 --- /dev/null +++ b/src/gui/contexthelp.cpp @@ -0,0 +1,107 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "cnitem.h" +#include "cnitemgroup.h" +#include "contexthelp.h" +#include "itemlibrary.h" +#include "katemdi.h" + +#include + +#include +#include +#include +#include +#include + +#include + +ContextHelp * ContextHelp::m_pSelf = 0l; + +ContextHelp * ContextHelp::self( KateMDI::ToolView * parent ) +{ + if (!m_pSelf) + { + assert(parent); + m_pSelf = new ContextHelp(parent); + } + return m_pSelf; +} + + +ContextHelp::ContextHelp( KateMDI::ToolView * parent ) + : QWidget( parent, "Context Help" ) +{ + QWhatsThis::add( this, i18n("Provides context-sensitive help relevant to the current editing being performed.") ); + + QVBoxLayout *vlayout = new QVBoxLayout( this, 0, 6 ); + + m_nameLbl = new QLabel( this, "" ); + vlayout->addWidget(m_nameLbl); + vlayout->addSpacing(8); + + m_info = new QTextBrowser( this, "" ); + vlayout->addWidget(m_info); + m_info->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding ); + + QSpacerItem *spacer3 = new QSpacerItem( 1, 1, QSizePolicy::Preferred, QSizePolicy::Preferred ); + vlayout->addItem(spacer3); + + slotClear(); +} + + +ContextHelp::~ContextHelp() +{ +} + + +void ContextHelp::slotUpdate( Item *item ) +{ + if (!item) + { + slotClear(); + return; + } + m_nameLbl->setText("

    "+item->name()+"

    "); + m_info->setText( ""+item->description() ); +} + + +void ContextHelp::slotClear() +{ + m_nameLbl->setText(i18n("

    No Item Selected

    ")); + m_info->setText(""); +} + + +void ContextHelp::slotMultipleSelected() +{ + m_nameLbl->setText(i18n("

    Multiple Items

    ")); + m_info->setText(""); +} + + +void ContextHelp::setContextHelp(const QString& name, const QString& help) +{ + m_nameLbl->setText("

    "+name+"

    "); + QString parsed = help; + parseInfo(parsed); + m_info->setText( ""+parsed ); +} + +void ContextHelp::parseInfo( QString &info ) +{ + info.replace("","

    Example:
    "); + info.replace("","
    "); +} + +#include "contexthelp.moc" diff --git a/src/gui/contexthelp.h b/src/gui/contexthelp.h new file mode 100644 index 0000000..90159b7 --- /dev/null +++ b/src/gui/contexthelp.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef CONTEXTHELP_H +#define CONTEXTHELP_H + +#include + +class Item; +class ContextHelp; +class QLabel; +class QTextBrowser; +namespace KateMDI { class ToolView; } + +/** +Sidebar that provides context-sensitive help for whatever the user is currently +helping (e.g. pinouts, command references, etc). Not to be confused with +ItemEditor, which which allows editing of data specific to the selected CNItem +in a ICNDocument. + +@author David Saxton +*/ +class ContextHelp : public QWidget +{ + Q_OBJECT + public: + static ContextHelp * self( KateMDI::ToolView * parent = 0l ); + static QString toolViewIdentifier() { return "ContextHelp"; } + + ~ContextHelp(); + /** + * Replace special tags with appropriate html formatting code. + */ + void parseInfo( QString &info ); + + public slots: + void slotClear(); + void slotMultipleSelected(); + void slotUpdate( Item *item ); + void setContextHelp(const QString& name, const QString &help); + + private: + ContextHelp( KateMDI::ToolView * parent ); + + QLabel *m_nameLbl; + QTextBrowser *m_info; + static ContextHelp * m_pSelf; +}; + +#endif + diff --git a/src/gui/createsubprojectwidget.ui b/src/gui/createsubprojectwidget.ui new file mode 100644 index 0000000..267739e --- /dev/null +++ b/src/gui/createsubprojectwidget.ui @@ -0,0 +1,99 @@ + +CreateSubprojectWidget + + + CreateSubprojectWidget + + + + 0 + 0 + 489 + 82 + + + + Create Subproject + + + + unnamed + + + 0 + + + + textLabel1 + + + + 1 + + + + Subproject Details + + + + + textLabel2 + + + Target File: + + + + + textLabel1_2 + + + Type: + + + + + + Program + + + + + Library + + + + m_typeCombo + + + + + m_targetFile + + + + + spacer3 + + + Vertical + + + Expanding + + + + 20 + 20 + + + + + + + + kurlrequester.h + klineedit.h + kpushbutton.h + + diff --git a/src/gui/doublespinbox.cpp b/src/gui/doublespinbox.cpp new file mode 100644 index 0000000..b8672b5 --- /dev/null +++ b/src/gui/doublespinbox.cpp @@ -0,0 +1,278 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "cnitem.h" +#include "doublespinbox.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +using namespace std; + + +inline int roundDouble( double val ) +{ + return (val > 0) ? int(val+0.5) : int(val-0.5); +} + + +DoubleSpinBox::DoubleSpinBox( double lower, double upper, double minAbs, double value, const QString &unit, QWidget * parent ) + : QSpinBox( parent ) +{ + m_lastEmittedValue = value; + m_unit = unit; + m_minValue = lower; + m_maxValue = upper; + m_minAbsValue = minAbs; + m_queuedSuffix = QString::null; + + editor()->setAlignment( Qt::AlignRight ); + + connect( this, SIGNAL(valueChanged(int)), this, SLOT(checkIfChanged()) ); + QSpinBox::setMinValue( -(1<<30) ); + QSpinBox::setMaxValue( +(1<<30) ); + setValue( value ); + + setValidator( 0 ); +} + + +DoubleSpinBox::~DoubleSpinBox() +{ +} + + +double DoubleSpinBox::value() +{ + return getDisplayedNumber( 0 ) * getMult(); +} + + +void DoubleSpinBox::setValue( double value ) +{ + if ( value > maxValue() ) + value = maxValue(); + + else if ( value < minValue() ) + value = minValue(); + + if ( std::abs(value) < m_minAbsValue*0.9999 ) + value = 0.0; + + updateSuffix( value ); + + QSpinBox::setValue( roundDouble( (value / Item::getMultiplier( value )) * 100 ) ); +} + + +void DoubleSpinBox::setUnit( const QString & unit ) +{ + updateSuffix( value() ); + m_unit = unit; +} + + +void DoubleSpinBox::updateSuffix( double value ) +{ + m_queuedSuffix = " " + CNItem::getNumberMag( value ) + m_unit; + + // Set suffix to be empty if it is nothing but white space + if ( m_queuedSuffix.stripWhiteSpace().isEmpty() ) + m_queuedSuffix = ""; + + QTimer::singleShot( 0, this, SLOT(setQueuedSuffix()) ); +} + + +void DoubleSpinBox::setQueuedSuffix() +{ + bool changed = false; + if ( !m_queuedSuffix.isNull() && suffix() != m_queuedSuffix ) + { + setSuffix( m_queuedSuffix ); + changed = true; + } + m_queuedSuffix = QString::null; + + if ( changed ) + emit valueChanged( value() ); +} + + +double DoubleSpinBox::getMult() +{ + QString text = this->text().stripWhiteSpace(); + if ( !m_queuedSuffix.isNull() ) + { + QString nsSuffix = suffix().stripWhiteSpace(); + + if ( nsSuffix.isEmpty() ) + text.append( m_queuedSuffix ); + else + text.replace( nsSuffix, m_queuedSuffix ); + } + + if ( text.length() == 0 ) + return 1.0; + + if ( text.endsWith( m_unit, false ) ) + text = text.remove( text.length() - m_unit.length(), m_unit.length() ); + + text.stripWhiteSpace(); + + QChar siExp = text[ text.length()-1 ]; + + if ( siExp.isLetter() || siExp.isSymbol() ) + return CNItem::getMultiplier((QString)siExp); + + else + return 1; +} + + +double DoubleSpinBox::getDisplayedNumber( bool * ok ) +{ + KLocale * locale = KGlobal::locale(); + + // Fetch the characters that we don't want to discard + const QString exclude = locale->decimalSymbol() + + locale->thousandsSeparator() + + locale->positiveSign() + + locale->negativeSign(); + + QString number = cleanText().remove( QRegExp("[^"+exclude+"\\d]") ); + + return locale->readNumber( number, ok ); +} + + +int DoubleSpinBox::mapTextToValue( bool * ok ) +{ + (void)ok; + + double value = this->value(); + + if ( value > maxValue() ) + value = maxValue(); + + else if ( value < minValue() ) + value = minValue(); + + if ( std::abs(value) < m_minAbsValue*0.9999 ) + value = 0.0; + + updateSuffix( value ); + + value /= Item::getMultiplier( value ); + + // Precision of 2 extra digits + return int( value * 100 ); +} + + +QString DoubleSpinBox::mapValueToText( int v ) +{ + double val = double(v)/100.0; + + int leftDigits = (int)floor( log10( abs(val) ) ) + 1; + if ( leftDigits < 0 ) + leftDigits = 0; + else if ( leftDigits > 3 ) + leftDigits = 3; + + KLocale * locale = KGlobal::locale(); + return locale->formatNumber( val, 3-leftDigits ); +} + + +void DoubleSpinBox::checkIfChanged() +{ + double newValue = value(); + + if ( m_lastEmittedValue == newValue ) + return; + + m_lastEmittedValue = newValue; + emit valueChanged( m_lastEmittedValue ); +} + + +double DoubleSpinBox::roundToOneSF( double value ) +{ + if ( value == 0.0 ) + return 0.0; + + value *= 1.000001; + double tens = pow( 10.0, floor(log10( abs(value) )) ); + + return int ( value / tens ) * tens; +} + + +void DoubleSpinBox::stepUp() +{ + double value = roundToOneSF( this->value() ); + + if ( value == 0 ) + value = m_minAbsValue; + + else if ( value > 0 ) + value += std::pow( 10., std::floor( std::log10(value) ) ); + + else + { + double sub = std::pow(10., std::floor( std::log10(std::abs(value))-1) ); + value += std::pow( 10., std::floor( std::log10(std::abs(value)-sub) ) ); + } + + value *= 1.00001; + + if ( std::abs(value) < m_minAbsValue ) + value = 0.; + + setValue( value ); +} + + +void DoubleSpinBox::stepDown() +{ + double value = roundToOneSF( this->value() ); + + if ( value == 0 ) + value = -m_minAbsValue; + + else if ( value > 0 ) + { + double sub = std::pow(10., std::floor( std::log10(value)-1) ); + value -= std::pow( 10., std::floor( std::log10(value-sub) ) ); + } + else + { + double add = std::pow(10., std::floor( std::log10(std::abs(value))-1) ); + value -= std::pow( 10., std::floor( std::log10(std::abs(value)+add) ) ); + } + + value *= 1.00001; + + if ( std::abs(value) < m_minAbsValue ) + value = 0.; + + setValue( value ); +} + +#include "doublespinbox.moc" + diff --git a/src/gui/doublespinbox.h b/src/gui/doublespinbox.h new file mode 100644 index 0000000..75f6c90 --- /dev/null +++ b/src/gui/doublespinbox.h @@ -0,0 +1,131 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef DOUBLESPINBOX_H +#define DOUBLESPINBOX_H + +#include + +/** +Where appropriate, function names with value in them should +be prefixed with "real" - e.g. realValue() - to get the value stored in the +spin box plus the SI magnitude symbol it is showing + +@author David Saxton +*/ +class DoubleSpinBox : public QSpinBox +{ + Q_OBJECT + public: + DoubleSpinBox( double lower, double upper, double minAbs, double value, const QString & unit, QWidget * parent = 0 ); + virtual ~DoubleSpinBox(); + + /** + * The minimum value is the lowest number that the user can enter. + */ + double minValue() const { return m_minValue; } + /** + * @see minValue + */ + void setMinValue( double minValue ) { m_minValue = minValue; } + /** + * The minimum value is the lowest number that the user can enter. + */ + void setMinValue( int minValue ) { m_minValue = minValue; } + /** + * The maximum value is the highest number that the user can enter. + */ + double maxValue() const { return m_maxValue; } + /** + * @see maxValue + */ + void setMaxValue( double maxValue ) { m_maxValue = maxValue; } + /** + * @see maxValue + */ + void setMaxValue( int maxValue ) { m_maxValue = maxValue; } + /** + * The minimum absolute value is the smallest value that the user can + * enter before the value is considered 0. + */ + void setMinAbsValue( double minAbsValue ) { m_minAbsValue = minAbsValue; } + /** + * The actual value that the user has entered - e.g. if the spinbox + * displays "100 kF", then the value returned will be 1e5. + */ + double value(); + /** + * Set the value to be displayed - e.g. if value is 1e5, then the + * spinbox might display "100 kF". + */ + void setValue( double value ); + /** + * Sets the unit used, e.g. "F" + */ + void setUnit( const QString & unit ); + + public slots: + virtual void stepUp(); + virtual void stepDown(); + + signals: + /** + * This value is emitted whenever the value of the spinbox changes. + */ + void valueChanged( double value ); + + protected slots: + /** + * Checks if the value has changed - and if so, emits a valueChanged + * signal. + */ + void checkIfChanged(); + /** + * Sets the suffix from m_queuedSuffix. Called from QTimer::singleShot + * to avoid strange recursion problems. + */ + void setQueuedSuffix(); + + protected: + /** + * Updates the suffix using m_unit and value. + */ + void updateSuffix( double value ); + /** + * Returns the multiplication number from what is displayed + * in the box, e.g. "10 kV" will return "1000" due to the letter "k" presence + */ + double getMult(); + /** + * Returns the number currently displayed in the spin box. + */ + double getDisplayedNumber( bool * ok ); + /** + * Overloaded the method in QSpinxBox to allow SI prefixes to be entered + */ + virtual int mapTextToValue( bool * ok ); + /** + * Overloaded the method in QSpinxBox to allow SI prefixes to be entered + */ + virtual QString mapValueToText( int v ); + /** + * Returns value rounded off to one significant figure. + */ + double roundToOneSF( double value ); + + QString m_queuedSuffix; ///< Used + QString m_unit; + double m_minValue; + double m_maxValue; + double m_minAbsValue; + double m_lastEmittedValue; +}; + +#endif diff --git a/src/gui/generaloptionswidget.ui b/src/gui/generaloptionswidget.ui new file mode 100644 index 0000000..0f3ee2a --- /dev/null +++ b/src/gui/generaloptionswidget.ui @@ -0,0 +1,269 @@ + +GeneralOptionsWidget + + + GeneralOptionsWidget + + + + 0 + 0 + 456 + 488 + + + + General Options + + + + unnamed + + + 0 + + + + kcfg_ReuseSameViewForOutput + + + Reuse the same output view for code generation + + + + + + + + kcfg_ShowVoltageBars + + + Show voltage bars &on electronic components + + + Alt+O + + + + + kcfg_GridColor + + + Grid Colour + + + The grid color in the work area. + + + + + kcfg_ShowGrid + + + Show &grid: + + + Alt+G + + + + + kcfg_MaxUndo + + + + 5 + 0 + 0 + 0 + + + + 100000 + + + + + textLabel1 + + + Maximum undo steps for work area: + + + Maximum undo steps for work area. This doesn't apply to text documents - that is configurable seperately under Configure Editor. + + + + + groupBox4 + + + Convenience + + + + unnamed + + + + kcfg_RestoreDocumentsOnStartup + + + Restore opened doc&uments on startup + + + Alt+U + + + + + kcfg_RaiseItemSelectors + + + Raise the &appropriate item selector on creating a new document + + + Alt+A + + + + + kcfg_RaiseMessagesLog + + + Raise the &Messages log when compiling + + + Alt+M + + + + + + + groupBox21 + + + Display Refresh Rate + + + + unnamed + + + + layout8_2 + + + + unnamed + + + + refreshRateSlider + + + 4 + + + 1 + + + 2 + + + Horizontal + + + Below + + + + + textLabel3_2 + + + Refresh rate: + + + + + refreshRateLabel + + + Medium (50 FPS) + + + + + + + textLabel9_2 + + + + 5 + 1 + 0 + 0 + + + + This is the number of times per second that the work area view is updated; a compromise between CPU usage and smoothness of display. + + + PlainText + + + false + + + WordBreak|AlignVCenter + + + + + + + spacer3 + + + Vertical + + + Expanding + + + + 20 + 40 + + + + + + + + kcfg_ShowGrid + toggled(bool) + kcfg_GridColor + setEnabled(bool) + + + + kcfg_ReuseSameViewForOutput + kcfg_ShowVoltageBars + kcfg_ShowGrid + kcfg_GridColor + kcfg_MaxUndo + kcfg_RestoreDocumentsOnStartup + kcfg_RaiseItemSelectors + kcfg_RaiseMessagesLog + refreshRateSlider + + + + kcolorbutton.h + knuminput.h + + diff --git a/src/gui/gpasmsettingswidget.ui b/src/gui/gpasmsettingswidget.ui new file mode 100644 index 0000000..069711f --- /dev/null +++ b/src/gui/gpasmsettingswidget.ui @@ -0,0 +1,288 @@ + +GpasmSettingsWidget + + + GpasmSettingsWidget + + + + 0 + 0 + 278 + 168 + + + + Gpasm Settings + + + + + + + unnamed + + + 0 + + + + textLabel2 + + + Radix (-r): + + + + + textLabel3 + + + Warning level (-w): + + + + + textLabel1 + + + Hex Format (-a): + + + + + kcfg_IgnoreCase + + + Ign&ore case (-i) + + + Alt+O + + + All user defined symbols and macros are case sensitive. This option makes them case insensitive. + + + + + kcfg_DosFormat + + + Generate DOS-formated hex file (-&n) + + + Alt+N + + + By default, gpasm generates hex files using ISO format. However, some device programmers required a DOS formatted file. This option will cause gpasm to generate a DOS formatted hex file. + + + + + spacer18 + + + Vertical + + + Expanding + + + + 20 + 16 + + + + + + + inhx32 + + + + + inhx8m + + + + + inhx8s + + + + + inhx16 + + + + kcfg_HexFormat + + + + 1 + 0 + 0 + 0 + + + + AtBottom + + + GPASM supports inhx8m, inhx8s, inhx16, and inhx32 hex file formats. This option controls which hex file format is used. + + + + + + Decimal + + + + + Binary + + + + + Octal + + + + + Hexadecimal + + + + kcfg_Radix + + + + 1 + 0 + 0 + 0 + + + + + + + All + + + + + Warnings + + + + + Errors + + + + kcfg_GpasmWarningLevel + + + + 1 + 0 + 0 + 0 + + + + This sets the threshold of messages displayed in the log view.<ul><li>"All" will display all output - information, warnings and errors.<li>"Warnings" will supress messages. <li>"Errors" will supress both messages and warnings.</ul> + + + + + spacer10 + + + Horizontal + + + Expanding + + + + 40 + 20 + + + + + + spacer11 + + + Horizontal + + + Expanding + + + + 40 + 20 + + + + + + spacer12 + + + Horizontal + + + Expanding + + + + 40 + 20 + + + + + + textLabel1_2 + + + Other options: + + + + + kcfg_MiscGpasmOptions + + + + 7 + 0 + 0 + 0 + + + + + + + kcfg_HexFormat + kcfg_Radix + kcfg_GpasmWarningLevel + kcfg_IgnoreCase + kcfg_DosFormat + + + + kcombobox.h + kcombobox.h + kcombobox.h + klineedit.h + + diff --git a/src/gui/itemeditor.cpp b/src/gui/itemeditor.cpp new file mode 100644 index 0000000..bdfe539 --- /dev/null +++ b/src/gui/itemeditor.cpp @@ -0,0 +1,156 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "cnitem.h" +#include "cnitemgroup.h" +#include "itemeditor.h" +#include "orientationwidget.h" +#include "propertieslistview.h" + +#include +#include + +#include +#include +#include +#include + +#include + +ItemEditor * ItemEditor::m_pSelf = 0l; + +ItemEditor * ItemEditor::self( KateMDI::ToolView * parent ) +{ + if (!m_pSelf) + { + assert(parent); + m_pSelf = new ItemEditor(parent); + } + return m_pSelf; +} + + +ItemEditor::ItemEditor( KateMDI::ToolView * parent ) + : QWidget( (QWidget*)parent, "Item Editor" ) +{ + QWhatsThis::add( this, i18n("This allows editing of advanced properties of the selected item(s). Right click on the picture of the item to set the orientation.") ); + + QVBoxLayout *vlayout = new QVBoxLayout( this, 0, 6 ); + + m_nameLbl = new QLabel( this, "" ); + vlayout->addWidget(m_nameLbl); + vlayout->addSpacing(8); + + propList = new PropertiesListView(this); + vlayout->addWidget(propList); + QWhatsThis::add(propList,i18n("Shows properties associated with the currently selected item(s).

    Select a property to change its value. If multiple items are selected with different values then the property will appear greyed out, use ""Merge Properties"" to make them the same.

    Select ""Defaults to set all properties to their default values""")); + + QHBoxLayout *h1Layout = new QHBoxLayout( vlayout, 4 ); + QSpacerItem *spacer1 = new QSpacerItem( 1, 1 ); + h1Layout->addItem(spacer1); + + m_defaultsBtn = new QPushButton( i18n("Defaults"), this); + m_defaultsBtn->setEnabled(false); + connect(m_defaultsBtn,SIGNAL(clicked()),propList,SLOT(slotSetDefaults())); + h1Layout->addWidget(m_defaultsBtn); + + m_mergeBtn = new QPushButton( i18n("Merge properties"), this ); + m_mergeBtn->setEnabled(false); + connect(m_mergeBtn,SIGNAL(clicked()),this,SLOT(mergeProperties())); + h1Layout->addWidget(m_mergeBtn); + + // Orientation widget stuff + QHBoxLayout *h2Layout = new QHBoxLayout( vlayout, 6 ); + QSpacerItem *spacer2 = new QSpacerItem( 1, 1 ); + h2Layout->addItem(spacer2); + m_orientationWidget = new OrientationWidget(this); + h2Layout->addWidget(m_orientationWidget); + QWhatsThis::add(m_orientationWidget,i18n("Change the orientation of the selected item by selecting the appropriate button")); + QSpacerItem *spacer3 = new QSpacerItem( 1, 1 ); + h2Layout->addItem(spacer3); + + slotClear(); +} + + +ItemEditor::~ItemEditor() +{ +} + + +void ItemEditor::mergeProperties() +{ + propList->slotMergeProperties(); + m_mergeBtn->setEnabled(false); +} + + +void ItemEditor::slotClear() +{ + propList->slotClear(); + m_orientationWidget->slotClear(); + m_defaultsBtn->setEnabled(false); + m_mergeBtn->setEnabled(false); + updateNameLabel(0l); +} + + +void ItemEditor::slotMultipleSelected() +{ + slotClear(); + m_nameLbl->setText( i18n("

    Multiple Items

    ") ); +} + + +void ItemEditor::slotUpdate( ItemGroup *itemGroup ) +{ + if (!itemGroup) { + slotClear(); + return; + } + + updateMergeDefaults(itemGroup); + propList->slotCreate(itemGroup); + updateNameLabel(itemGroup->activeItem()); +} + + +void ItemEditor::updateMergeDefaults( ItemGroup *itemGroup ) +{ + if (!itemGroup) + { + m_defaultsBtn->setEnabled(false); + m_mergeBtn->setEnabled(false); + return; + } + + m_mergeBtn->setEnabled( !itemGroup->itemsHaveSameData() ); + m_defaultsBtn->setEnabled( !itemGroup->itemsHaveDefaultData() ); + propList->slotUpdate(itemGroup); +} + + +void ItemEditor::slotUpdate( CNItem *item ) +{ + m_orientationWidget->slotUpdate(item); +} + + +void ItemEditor::updateNameLabel( Item *item ) +{ + if (item) { + m_nameLbl->setText( "

    " + item->name() + "

    " ); + } else { + m_nameLbl->setText( i18n("

    No Item Selected

    ") ); + } +} + + +#include "itemeditor.moc" diff --git a/src/gui/itemeditor.h b/src/gui/itemeditor.h new file mode 100644 index 0000000..8c21e49 --- /dev/null +++ b/src/gui/itemeditor.h @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ITEMEDITOR_H +#define ITEMEDITOR_H + +#include +#include + +class ItemEditor; + +class CNItem; +class CNItemGroup; +class Item; +class CNItemGroup; +class ICNDocument; +class ItemGroup; +class OrientationWidget; +class PropertiesListView; +class QPushButton; +class QLabel; + +namespace KateMDI { class ToolView; } + +/** +@author Daniel Clarke +@author David Saxton +*/ +class ItemEditor : public QWidget +{ + Q_OBJECT + public: + static ItemEditor * self( KateMDI::ToolView * parent = 0l ); + ~ItemEditor(); + static QString toolViewIdentifier() { return "ItemEditor"; } + + public slots: + /** + * Update the Properties Editor + */ + void slotUpdate( ItemGroup *itemGroup ); + /** + * Update the orientation widget + */ + void slotUpdate( CNItem *item ); + /** + * Clear the properties editor and orientation widget + */ + void slotClear(); + void slotMultipleSelected(); + /** + * Updates the merge / reset data parts (e.g. enabling or disabling the + * "Defaults" button) + */ + void updateMergeDefaults( ItemGroup *itemGroup ); + + protected: + void updateNameLabel( Item *item ); + PropertiesListView * propList; + static ItemEditor * m_pSelf; + + private slots: + void mergeProperties(); + + private: + ItemEditor( KateMDI::ToolView * parent ); + + QLabel *m_nameLbl; + QPushButton *m_defaultsBtn; + QPushButton *m_mergeBtn; + OrientationWidget *m_orientationWidget; +}; + + +#endif diff --git a/src/gui/itemselector.cpp b/src/gui/itemselector.cpp new file mode 100644 index 0000000..f85756e --- /dev/null +++ b/src/gui/itemselector.cpp @@ -0,0 +1,372 @@ +/*************************************************************************** + * Copyright (C) 2003,2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include // Temporay fix for pthread.h problem +#include "circuitdocument.h" +#include "docmanager.h" +#include "flowcodedocument.h" +#include "itemdocument.h" +#include "itemlibrary.h" +#include "itemselector.h" +#include "libraryitem.h" +#include "mechanicsdocument.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +ILVItem::ILVItem( QListView* parent, const QString &id ) + : KListViewItem( parent, 0 ) +{ + m_id = id; + b_isRemovable = false; + m_pProjectItem = 0l; +} + +ILVItem::ILVItem( QListViewItem* parent, const QString &id ) + : KListViewItem( parent, 0 ) +{ + m_id = id; + b_isRemovable = false; + m_pProjectItem = 0l; +} + + +ItemSelector::ItemSelector( QWidget *parent, const char *name ) + : KListView( parent, name ) +{ + addColumn( i18n( "Component" ) ); + setFullWidth(true); + setSorting( -1, FALSE ); + setRootIsDecorated(true); + setDragEnabled(true); + +// connect( this, SIGNAL(executed(QListViewItem*) ), this, SLOT(slotItemExecuted(QListViewItem*)) ); + connect( this, SIGNAL(clicked(QListViewItem*)), this, SLOT(slotItemClicked(QListViewItem*)) ); + connect( this, SIGNAL(doubleClicked(QListViewItem*)), this, SLOT(slotItemDoubleClicked(QListViewItem*)) ); + connect( this, SIGNAL(contextMenuRequested(QListViewItem*, const QPoint&, int )), this, SLOT(slotContextMenuRequested(QListViewItem*, const QPoint&, int )) ); +} + +ItemSelector::~ItemSelector() +{ + writeOpenStates(); +} + + +void ItemSelector::clear() +{ + m_categories.clear(); + KListView::clear(); +} + + +void ItemSelector::addItem( const QString & caption, const QString & id, const QString & _category, const QPixmap & icon, bool removable ) +{ + ILVItem *parentItem = 0L; + + QString category = _category; + if ( !category.startsWith("/") ) { + category.prepend('/'); + } + + do + { + category.remove(0,1); + QString cat; + category.replace( "\\/", "|" ); + int pos = category.find('/'); + if ( pos == -1 ) cat = category; + else cat = category.left( pos ); + + cat.replace( "|", "/" ); + + if ( m_categories.findIndex(cat) == -1 ) + { + m_categories.append(cat); + + if (parentItem) { + parentItem = new ILVItem( parentItem, "" ); + } + else { + parentItem = new ILVItem( this, "" ); + } + parentItem->setOpen( readOpenState(cat) ); + + parentItem->setExpandable(true); + parentItem->setText( 0, cat ); + } + else + { + parentItem = (ILVItem*)findItem( cat, 0 ); + } + + category.remove( 0, pos ); + } while ( category.contains('/') ); + + if ( !parentItem ) + { + kdError() << "Unexpected error in finding parent item for category list"<setPixmap( 0, icon ); + item->setText( 0, caption ); + item->setRemovable(removable); +} + + +void ItemSelector::writeOpenStates() +{ + KConfig *config = kapp->config(); + config->setGroup( name() ); + + const QStringList::iterator end = m_categories.end(); + for ( QStringList::iterator it = m_categories.begin(); it != end; ++it ) + { + QListViewItem *item = findItem( *it, 0 ); + if (item) { + config->writeEntry( *it+"IsOpen", item->isOpen() ); + } + } +} + + +bool ItemSelector::readOpenState( const QString &id ) +{ + KConfig *config = kapp->config(); + config->setGroup( name() ); + + return config->readBoolEntry( id+"IsOpen", true ); +} + + +void ItemSelector::slotContextMenuRequested( QListViewItem* item, const QPoint& pos, int /*col*/ ) +{ + if ( !item || !(static_cast(item))->isRemovable() ) { + return; + } + + QPopupMenu *menu = new QPopupMenu(this); + menu->insertItem( i18n("Remove %1").arg(item->text(0)), this, SLOT(slotRemoveSelectedItem()), Qt::Key_Delete ); + menu->popup(pos); +} + + +void ItemSelector::slotRemoveSelectedItem() +{ + ILVItem *item = dynamic_cast(selectedItem()); + if (!item) + return; + + emit itemRemoved( item->key( 0, 0 ) ); + ILVItem *parent = dynamic_cast(item->QListViewItem::parent()); + delete item; + // Get rid of the category as well if it has no children + if ( parent && !parent->firstChild() ) + { + m_categories.remove(parent->text(0)); + delete parent; + } +} + + +void ItemSelector::setListCaption( const QString &caption ) +{ + setColumnText( 0, caption ); +} + + + +void ItemSelector::slotItemClicked( QListViewItem *item ) +{ + if (!item) + return; + + if ( ItemDocument * itemDocument = dynamic_cast(DocManager::self()->getFocusedDocument()) ) + itemDocument->slotUnsetRepeatedItemId(); + + emit itemClicked( item->key( 0, 0 ) ); +} + + +void ItemSelector::slotItemDoubleClicked( QListViewItem *item ) +{ + if (!item) + return; + + QString id = item->key( 0, 0 ); + + if ( Document * doc = DocManager::self()->getFocusedDocument() ) + { + if ( doc->type() == Document::dt_flowcode && id.startsWith("flow/") ) + (static_cast(doc))->slotSetRepeatedItemId(id); + + else if ( doc->type() == Document::dt_circuit && (id.startsWith("ec/") || id.startsWith("sc/")) ) + (static_cast(doc))->slotSetRepeatedItemId(id); + + else if ( doc->type() == Document::dt_mechanics && id.startsWith("mech/") ) + (static_cast(doc))->slotSetRepeatedItemId(id); + } + + emit itemDoubleClicked(id); +} + + +QDragObject* ItemSelector::dragObject() +{ + const QString id = currentItem()->key(0,0); + + QStoredDrag * d = 0l; + + if ( id.startsWith("flow/") ) + d = new QStoredDrag( "ktechlab/flowpart", this ); + + else if ( id.startsWith("ec/") ) + d = new QStoredDrag( "ktechlab/component", this ); + + else if ( id.startsWith("sc/") ) + d = new QStoredDrag( "ktechlab/subcircuit", this ); + + else if ( id.startsWith("mech/") ) + d = new QStoredDrag( "ktechlab/mechanical", this ); + + if (d) + { + QByteArray data; + QDataStream stream( data, IO_WriteOnly ); + stream << id; + d->setEncodedData(data); + } + + // A pixmap cursor is often hard to make out +// QPixmap *pixmap = const_cast(currentItem()->pixmap(0)); +// if (pixmap) d->setPixmap(*pixmap); + + return d; +} + + + +//BEGIN class ComponentSelector +ComponentSelector * ComponentSelector::m_pSelf = 0l; + + +ComponentSelector * ComponentSelector::self( KateMDI::ToolView * parent ) +{ + if (!m_pSelf) + { + assert(parent); + m_pSelf = new ComponentSelector(parent); + } + return m_pSelf; +} + + +ComponentSelector::ComponentSelector( KateMDI::ToolView * parent ) + : ItemSelector( (QWidget*)parent, "Component Selector" ) +{ + QWhatsThis::add( this, i18n( + "Add components to the circuit diagram by dragging them into the circuit.

    " + + "To add more than one component of the same type, doubleclick on a component, and click repeatedly in the circuit to place the component. Right click to stop placement.

    " + + "Some components (such as subcircuits) can be removed by right clicking on the item and selecting \"Remove\"." + ) ); + + setListCaption( i18n("Component") ); + + LibraryItemList *items = itemLibrary()->items(); + const LibraryItemList::iterator end = items->end(); + for ( LibraryItemList::iterator it = items->begin(); it != end; ++it ) + { + if ( (*it)->type() == LibraryItem::lit_component ) + addItem( (*it)->name(), (*it)->activeID(), (*it)->category(), (*it)->icon16() ); + } +} +//END class ComponentSelector + + + +//BEGIN class FlowPartSelector +FlowPartSelector * FlowPartSelector::m_pSelf = 0l; + + +FlowPartSelector * FlowPartSelector::self( KateMDI::ToolView * parent ) +{ + if (!m_pSelf) + { + assert(parent); + m_pSelf = new FlowPartSelector(parent); + } + return m_pSelf; +} + + +FlowPartSelector::FlowPartSelector( KateMDI::ToolView * parent ) + : ItemSelector( (QWidget*)parent, "Part Selector" ) +{ + QWhatsThis::add( this, i18n("Add FlowPart to the FlowCode document by dragging them there.

    To add more than one FlowPart of the same type, doubleclick on a FlowPart, and click repeatedly in the FlowChart to place the component. Right click to stop placement.") ); + + setListCaption( i18n("Flow Part") ); + + LibraryItemList *items = itemLibrary()->items(); + const LibraryItemList::iterator end = items->end(); + for ( LibraryItemList::iterator it = items->begin(); it != end; ++it ) + { + if ( (*it)->type() == LibraryItem::lit_flowpart ) + addItem( (*it)->name(), (*it)->activeID(), (*it)->category(), (*it)->icon16() ); + } +} +//END class FlowPartSelector + + +//BEGIN class MechanicsSelector +MechanicsSelector * MechanicsSelector::m_pSelf = 0l; + + +MechanicsSelector * MechanicsSelector::self( KateMDI::ToolView * parent ) +{ + if (!m_pSelf) + { + assert(parent); + m_pSelf = new MechanicsSelector( (QWidget*)parent ); + } + return m_pSelf; +} + + +MechanicsSelector::MechanicsSelector( QWidget *parent ) + : ItemSelector( (QWidget*)parent, "Mechanics Selector" ) +{ + QWhatsThis::add( this, i18n("Add mechanical parts to the mechanics work area by dragging them there.") ); + + LibraryItemList *items = itemLibrary()->items(); + const LibraryItemList::iterator end = items->end(); + for ( LibraryItemList::iterator it = items->begin(); it != end; ++it ) + { + if ( (*it)->type() == LibraryItem::lit_mechanical ) + { + addItem( (*it)->name(), (*it)->activeID(), (*it)->category(), (*it)->icon16() ); + } + } +} +//END class MechanicsSelector + + +#include "itemselector.moc" diff --git a/src/gui/itemselector.h b/src/gui/itemselector.h new file mode 100644 index 0000000..ab9c11c --- /dev/null +++ b/src/gui/itemselector.h @@ -0,0 +1,167 @@ +/*************************************************************************** + * Copyright (C) 2003,2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ITEMSELECTOR_H +#define ITEMSELECTOR_H + +#include + +#include +#include + +class ProjectItem; +class QStoredDrag; +namespace KateMDI { class ToolView; } + +/** +@short Contains info about item for ItemSelector +@author David Saxton +*/ +class ILVItem : public QObject, public KListViewItem +{ + public: + ILVItem( QListView *parent, const QString &id ); + ILVItem( QListViewItem *parent, const QString &id ); + + void setProjectItem( ProjectItem * projectItem ) { m_pProjectItem = projectItem; } + ProjectItem * projectItem() const { return m_pProjectItem; } + + QString id() const { return m_id; } + + QString key( int, bool ) const { return m_id; } + /** + * Set whether the item can be removed from the listview by the user + */ + void setRemovable( bool isRemovable ) { b_isRemovable = isRemovable; } + /** + * Whether the item can be removed from the listview by the user + */ + bool isRemovable() const { return b_isRemovable; } + + protected: + QString m_id; + bool b_isRemovable; + ProjectItem * m_pProjectItem; +}; + +/** +@short Allows selection of generic items for dragging / clicking +@author David Saxton +*/ +class ItemSelector : public KListView +{ + Q_OBJECT + public: + ItemSelector( QWidget *parent, const char *name ); + ~ItemSelector(); + /** + * Adds a listview item to the ListView + * @param caption The displayed text + * @param id A unique identification for when it is dragged or activated + * @param category The category it is in, eg "Integrated Circuits + * @param icon The icon to be displayed to the left of the text + * @param removable Whether the user can right-click on the item and select Remove + */ + void addItem( const QString & caption, const QString & id, const QString & category, const QPixmap & icon = QPixmap(), bool removable = false ); + + public slots: + virtual void slotContextMenuRequested( QListViewItem *item, const QPoint &pos, int col ); + virtual void clear(); + void slotRemoveSelectedItem(); + + signals: + /** + * Emitted when a user selects an item and removes it + */ + void itemRemoved( const QString &id ); + void itemDoubleClicked( const QString &id ); + void itemClicked( const QString &id ); + + protected: + /** + * Sets the caption of the ListView (eg 'Components' or 'Files') + */ + void setListCaption( const QString &caption ); + /** + * Writes the open status (folded or unfolded) of "parent" items in the view + * to the config file. + */ + void writeOpenStates(); + /** + * Reads the open status (folded or unfolded) of the given item. The default + * status for non-existant items is true. + */ + bool readOpenState( const QString &id ); + + private slots: + void slotItemClicked( QListViewItem *item ); + void slotItemDoubleClicked( QListViewItem *item ); + + private: + /** + * @return a dragobject encoding the currently selected component item. + */ + QDragObject * dragObject(); + + QStringList m_categories; +}; + + +/** +@short Allows selection of electrical components +@author David Saxton + */ +class ComponentSelector : public ItemSelector +{ + Q_OBJECT + public: + static ComponentSelector * self( KateMDI::ToolView * parent = 0l ); + static QString toolViewIdentifier() { return "ComponentSelector"; } + + private: + ComponentSelector( KateMDI::ToolView * parent ); + static ComponentSelector * m_pSelf; +}; + + +/** +@short Allows selection of PIC parts (eg 'Pause') +@author David Saxton + */ +class FlowPartSelector : public ItemSelector +{ + Q_OBJECT + public: + static FlowPartSelector * self( KateMDI::ToolView * parent = 0l ); + static QString toolViewIdentifier() { return "FlowPartSelector"; } + + private: + FlowPartSelector( KateMDI::ToolView * parent ); + static FlowPartSelector * m_pSelf; +}; + + +/** +@author David Saxton + */ +class MechanicsSelector : public ItemSelector +{ + Q_OBJECT + public: + static MechanicsSelector * self( KateMDI::ToolView * parent = 0l ); + static QString toolViewIdentifier() { return "MechanicsSelector"; } + + private: + MechanicsSelector( QWidget *parent = 0L ); + static MechanicsSelector * m_pSelf; +}; + + +#endif diff --git a/src/gui/linkeroptionswidget.ui b/src/gui/linkeroptionswidget.ui new file mode 100644 index 0000000..e2c48d8 --- /dev/null +++ b/src/gui/linkeroptionswidget.ui @@ -0,0 +1,179 @@ + +LinkerOptionsWidget + + + LinkerOptionsWidget + + + + 0 + 0 + 401 + 475 + + + + Linker Options + + + + unnamed + + + 0 + + + + + inhx32 + + + + + inhx8m + + + + + inhx8s + + + + + inhx16 + + + + m_pHexFormat + + + AtBottom + + + GPASM supports inhx8m, inhx8s, inhx16, and inhx32 hex file formats. This option controls which hex file format is used. + + + + + textLabel3 + + + Library Directory (-I): + + + + + m_pLibraryDir + + + + + textLabel1 + + + Hex Format (-a): + + + + + m_pOutputMap + + + &Output a map file (-m) + + + Alt+O + + + + + textLabel8 + + + Linker Script (-s): + + + + + m_pLinkerScript + + + + + m_pOther + + + + + textLabel4 + + + Other: + + + + + groupBox2 + + + Link libraries inside project + + + + unnamed + + + + + Library + + + true + + + true + + + + m_pInternalLibraries + + + NoSelection + + + LastColumn + + + 0 + + + + + + + m_pExternalLibraries + + + + + + + + + m_pHexFormat + m_pOutputMap + m_pLibraryDir + m_pLinkerScript + m_pOther + m_pInternalLibraries + + + + kcombobox.h + klineedit.h + klineedit.h + klistview.h + keditlistbox.h + klineedit.h + + diff --git a/src/gui/logicwidget.ui b/src/gui/logicwidget.ui new file mode 100644 index 0000000..18c1860 --- /dev/null +++ b/src/gui/logicwidget.ui @@ -0,0 +1,276 @@ + +LogicWidget + + + LogicWidget + + + + 0 + 0 + 338 + 347 + + + + Logic + + + + unnamed + + + 0 + + + + groupBox3 + + + Input + + + + unnamed + + + + kcfg_LogicRisingTrigger + + + 0.3 + + + 0.1 + + + 1.5 + + + V + + + 1 + + + Required voltage level before the input will be considered high. + + + + + + + + textLabel2_2 + + + Falling Trigger Threshold: + + + Required voltage level before an input will be considered low. + + + + + kcfg_LogicFallingTrigger + + + 0.2 + + + 0.1 + + + 1.6 + + + V + + + 1 + + + Required voltage level before an input will be considered low. + + + + + + + + textLabel1 + + + Rising Trigger Threshold: + + + Required voltage level before the input will be considered high. + + + + + + + groupBox4 + + + Output + + + + unnamed + + + + textLabel2 + + + Output High: + + + Voltage level for high on logic components. + + + + + kcfg_LogicOutputHigh + + + 0.5 + + + 0.1 + + + 1.6 + + + V + + + 1 + + + Voltage level for high on logic components. + + + + + + + + textLabel4 + + + High Output Impedance: + + + This is the output impedance when the output is high. + + + + + textLabel1_2 + + + Low Output Impedance: + + + This is the output impedance when the output is low. + + + + + kcfg_LogicOutputHighImpedance + + + + + + 1000000000 + + + 1 + + + 15 + + + This is the output impedance when the output is high. + + + + + + + + kcfg_LogicOutputLowImpedance + + + + + + Floating + + + 1000000000 + + + 0 + + + 0 + + + This is the output impedance when the output is low. + + + + + + + + + + textLabel2_3 + + + Here, you can configure the behaviour of logic components. + +These values will apply to all components, apart from the PIC, whose pins' impedances depend on the pin in use. + + + WordBreak|AlignVCenter + + + + + spacer10 + + + Vertical + + + Expanding + + + + 20 + 16 + + + + + + + + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + + diff --git a/src/gui/logview.cpp b/src/gui/logview.cpp new file mode 100644 index 0000000..fcb8caf --- /dev/null +++ b/src/gui/logview.cpp @@ -0,0 +1,132 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "logview.h" + +#include +#include +#include +#include +#include + + +//BEGIN class LogView +LogView::LogView( KateMDI::ToolView * parent, const char *name ) + : KTextEdit( parent, name ) +{ + setReadOnly(true); + setPaper( Qt::white ); + setTextFormat( LogText ); + setWordWrap( WidgetWidth ); + + // Connect up signal emitted when the user doubleclicks on a paragraph in the log view + connect( this, SIGNAL(clicked(int,int)), this, SLOT(slotParaClicked(int,int)) ); +} + + +LogView::~LogView() +{ +} + + +void LogView::clear() +{ + m_messageInfoMap.clear(); + KTextEdit::clear(); +} + + +void LogView::addOutput( QString text, OutputType outputType, MessageInfo messageInfo ) +{ + tidyText(text); + switch(outputType) + { + case LogView::ot_important: + append( QString("%1").arg(text) ); + break; + + case LogView::ot_info: + append( QString("%1").arg(text) ); + break; + + case LogView::ot_message: + append( QString("%1").arg(text) ); + break; + + case LogView::ot_warning: + append( QString("%1").arg(text) ); + break; + + case LogView::ot_error: + append( QString("%1").arg(text) ); + break; + } + + m_messageInfoMap[ paragraphs()-1 ] = messageInfo; +} + + +void LogView::slotParaClicked( int para, int /*pos*/ ) +{ + QString t = text(para); + untidyText(t); + emit paraClicked( t, m_messageInfoMap[para] ); +} + + +void LogView::tidyText( QString &t ) +{ + t.replace( "&", "&" ); + t.replace( "<", "<" ); + t.replace( ">", ">" ); +} + + +void LogView::untidyText( QString &t ) +{ + t.replace( "<", "<" ); + t.replace( ">", ">" ); + t.replace( "&", "&" ); +} + + +QPopupMenu * LogView::createPopupMenu( const QPoint & pos ) +{ + QPopupMenu * menu = KTextEdit::createPopupMenu( pos ); + + menu->insertSeparator(); + int id = menu->insertItem( i18n("Clear All"), this, SLOT(clear()) ); + + // "an empty textedit is always considered to have one paragraph" - qt documentation + // although this does not always seem to be the case, so I don't know... + menu->setItemEnabled( id, paragraphs() > 1 ); + + return menu; +} +//END class LogView + + + +//BEGIN class MessageInfo +MessageInfo::MessageInfo() +{ + m_fileLine = -1; +} + + +MessageInfo::MessageInfo( QString fileURL, int fileLine ) +{ + m_fileURL = fileURL; + m_fileLine = fileLine; +} +//END class MessageInfo + + +#include "logview.moc" diff --git a/src/gui/logview.h b/src/gui/logview.h new file mode 100644 index 0000000..c568da8 --- /dev/null +++ b/src/gui/logview.h @@ -0,0 +1,85 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef LOGVIEW_H +#define LOGVIEW_H + +class KTechlab; + +#include +#include + +namespace KateMDI { class ToolView; } + +class MessageInfo +{ + public: + MessageInfo(); + MessageInfo( QString fileURL, int fileLine ); + + QString fileURL() const { return m_fileURL; } + int fileLine() const { return m_fileLine; } + + protected: + QString m_fileURL; + int m_fileLine; +}; +typedef QMap MessageInfoMap; + + +/** +Base class for logviews (eg GpasmInterface) which output information, warnings, errors to a viewable log +@short Dockable logview +@author David Saxton +*/ +class LogView : public KTextEdit +{ + Q_OBJECT + public: + LogView( KateMDI::ToolView * parent, const char *name = 0 ); + ~LogView(); + + enum OutputType + { + ot_important, // Bold + ot_info, // Italic + ot_message, // Plain + ot_warning, // Grey + ot_error // Red + }; + + signals: + /** + * Emitted when the user clicks on a paragraph in the log view + */ + void paraClicked( const QString &text, MessageInfo messageInfo ); + + public slots: + virtual void clear(); + void addOutput( QString text, OutputType outputType, MessageInfo messageInfo = MessageInfo() ); + + protected: + virtual QPopupMenu * createPopupMenu( const QPoint & pos ); + /** + * Replaces "&" with &, "<" with <, etc + */ + void tidyText( QString &t ); + /** + * Replaces "<" with "<", "&" with "&", etc + */ + void untidyText( QString &t ); + + MessageInfoMap m_messageInfoMap; + + private slots: + void slotParaClicked( int para, int pos ); +}; + +#endif diff --git a/src/gui/microselectwidget.cpp b/src/gui/microselectwidget.cpp new file mode 100644 index 0000000..1c4150b --- /dev/null +++ b/src/gui/microselectwidget.cpp @@ -0,0 +1,129 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "asminfo.h" +#include "microinfo.h" +#include "microlibrary.h" +#include "microselectwidget.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +MicroSelectWidget::MicroSelectWidget( QWidget* parent, const char* name, WFlags ) + : QGroupBox( 4, Qt::Horizontal, i18n("Microprocessor"), parent, name ) +{ + m_allowedAsmSet = AsmInfo::AsmSetAll; + m_allowedGpsimSupport = m_allowedFlowCodeSupport = m_allowedMicrobeSupport = MicroInfo::AllSupport; + + if ( !name ) + setName( "MicroSelectWidget" ); + + m_pMicroFamilyLabel = new QLabel( this, "m_pMicroFamilyLabel" ); + m_pMicroFamilyLabel->setText( i18n("Family") ); + + m_pMicroFamily = new KComboBox( FALSE, this, "m_pMicroFamily" ); + m_pMicroFamily->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred ); + + m_pMicroLabel = new QLabel( this, "m_pMicroLabel" ); + m_pMicroLabel->setText( i18n("Micro") ); + + m_pMicro = new KComboBox( FALSE, this, "m_pMicro" ); + m_pMicro->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred ); + m_pMicro->setEditable( TRUE ); + m_pMicro->setAutoCompletion(true); + updateFromAllowed(); + setMicro("P16F84"); + connect( m_pMicroFamily, SIGNAL(activated(const QString & )), this, SLOT(microFamilyChanged(const QString& )) ); +} + + +MicroSelectWidget::~MicroSelectWidget() +{ +} + +void MicroSelectWidget::setAllowedAsmSet( unsigned allowed ) +{ + m_allowedAsmSet = allowed; + updateFromAllowed(); +} +void MicroSelectWidget::setAllowedGpsimSupport( unsigned allowed ) +{ + m_allowedGpsimSupport = allowed; + updateFromAllowed(); +} +void MicroSelectWidget::setAllowedFlowCodeSupport( unsigned allowed ) +{ + m_allowedFlowCodeSupport = allowed; + updateFromAllowed(); +} +void MicroSelectWidget::setAllowedMicrobeSupport( unsigned allowed ) +{ + m_allowedMicrobeSupport = allowed; + updateFromAllowed(); +} + + +void MicroSelectWidget::updateFromAllowed() +{ + QString oldFamily = m_pMicroFamily->currentText(); + + m_pMicroFamily->clear(); + +#define CHECK_ADD(family) if ( (m_allowedAsmSet & AsmInfo::family) && !MicroLibrary::self()->microIDs( AsmInfo::family, m_allowedGpsimSupport, m_allowedFlowCodeSupport, m_allowedMicrobeSupport ).isEmpty() ) m_pMicroFamily->insertItem( AsmInfo::setToString(AsmInfo::family) ); + CHECK_ADD(PIC12) + CHECK_ADD(PIC14) + CHECK_ADD(PIC16); +#undef CHECK_ADD + + if ( m_pMicroFamily->contains(oldFamily) ) + m_pMicroFamily->setCurrentText(oldFamily); + + microFamilyChanged(oldFamily); +} + + +void MicroSelectWidget::setMicro( const QString & id ) +{ + MicroInfo * info = MicroLibrary::self()->microInfoWithID(id); + if (!info) + return; + + m_pMicro->clear(); + m_pMicro->insertStringList( MicroLibrary::self()->microIDs( info->instructionSet()->set() ) ); + m_pMicro->setCurrentText(id); + + m_pMicroFamily->setCurrentText( AsmInfo::setToString( info->instructionSet()->set() ) ); +} + + +QString MicroSelectWidget::micro() const +{ + return m_pMicro->currentText(); +} + + +void MicroSelectWidget::microFamilyChanged( const QString & family ) +{ + QString oldID = m_pMicro->currentText(); + + m_pMicro->clear(); + m_pMicro->insertStringList( MicroLibrary::self()->microIDs( AsmInfo::stringToSet(family), m_allowedGpsimSupport, m_allowedFlowCodeSupport, m_allowedMicrobeSupport ) ); + + if ( m_pMicro->contains(oldID) ) + m_pMicro->setCurrentText(oldID); +} + +#include "microselectwidget.moc" diff --git a/src/gui/microselectwidget.h b/src/gui/microselectwidget.h new file mode 100644 index 0000000..3730c8f --- /dev/null +++ b/src/gui/microselectwidget.h @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef MICROSELECTWIDGET_H +#define MICROSELECTWIDGET_H + +#include + +class QVBoxLayout; +class QHBoxLayout; +class QGridLayout; +class QSpacerItem; +class QGroupBox; +class QLabel; +class KComboBox; + +/** +@author David Saxton +*/ +class MicroSelectWidget : public QGroupBox +{ + Q_OBJECT + + public: + MicroSelectWidget( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 ); + ~MicroSelectWidget(); + + void setMicro( const QString & id ); + QString micro() const; + + /** + * @see MicroLibrary::microIDs + */ + void setAllowedAsmSet( unsigned allowed ); + /** + * @see MicroLibrary::microIDs + */ + void setAllowedGpsimSupport( unsigned allowed ); + /** + * @see MicroLibrary::microIDs + */ + void setAllowedFlowCodeSupport( unsigned allowed ); + /** + * @see MicroLibrary::microIDs + */ + void setAllowedMicrobeSupport( unsigned allowed ); + + protected slots: + void microFamilyChanged( const QString & family ); + + protected: + void updateFromAllowed(); + + unsigned int m_allowedAsmSet; + unsigned int m_allowedGpsimSupport; + unsigned int m_allowedFlowCodeSupport; + unsigned int m_allowedMicrobeSupport; + + QHBoxLayout * m_pWidgetLayout; + QLabel * m_pMicroFamilyLabel; + KComboBox * m_pMicroFamily; + QLabel * m_pMicroLabel; + KComboBox * m_pMicro; +}; + +#endif diff --git a/src/gui/microsettingsdlg.cpp b/src/gui/microsettingsdlg.cpp new file mode 100644 index 0000000..c3915e8 --- /dev/null +++ b/src/gui/microsettingsdlg.cpp @@ -0,0 +1,437 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "microinfo.h" +#include "microsettings.h" +#include "microsettingsdlg.h" +#include "microsettingswidget.h" +#include "micropackage.h" +#include "newpinmappingwidget.h" +#include "pinmapping.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +MicroSettingsDlg::MicroSettingsDlg( MicroSettings * microSettings, QWidget *parent, const char *name ) + : KDialogBase( parent, name, true, i18n("PIC Settings"), KDialogBase::Ok|KDialogBase::Apply|KDialogBase::Cancel, KDialogBase::Ok, true ) +{ + m_pMicroSettings = microSettings; + m_pNewPinMappingWidget = 0l; + m_pNewPinMappingDlg = 0l; + m_pWidget = new MicroSettingsWidget(this); + + QWhatsThis::add( this, i18n("This dialog allows editing of the initial properties of the PIC") ); + QWhatsThis::add( m_pWidget->portsGroupBox, i18n("Edit the initial value of the ports here. For each binary number, the order from right-to-left is pins 0 through 7.

    The \"Type (TRIS)\" edit shows the initial input/output state of the ports; 1 represents an input, and 0 an output.

    The \"State (PORT)\" edit shows the initial high/low state of the ports; 1 represents a high, and 0 a low.") ); + QWhatsThis::add( m_pWidget->variables, i18n("Edit the initial value of the variables here.

    Note that the value of the variable can only be in the range 0->255. These variables will be initialized before any other code is executed.") ); + + + //BEGIN Initialize initial port settings + m_portNames = microSettings->microInfo()->package()->portNames(); + + m_portTypeEdit.resize( m_portNames.size(), 0 ); + m_portStateEdit.resize( m_portNames.size(), 0 ); + + uint row = 0; + QStringList::iterator end = m_portNames.end(); + for ( QStringList::iterator it = m_portNames.begin(); it != end; ++it, ++row ) + { + //BEGIN Get current Type / State text + QString portType = QString::number( microSettings->portType(*it), 2 ); + QString portState = QString::number( microSettings->portState(*it), 2 ); + + QString fill; + fill.fill( '0', 8-portType.length() ); + portType.prepend(fill); + fill.fill( '0', 8-portState.length() ); + portState.prepend(fill); + //END Get current Type / State text + + + QGroupBox * groupBox = new QGroupBox( *it, m_pWidget->portsGroupBox ); + + groupBox->setColumnLayout(0, Qt::Vertical ); + groupBox->layout()->setSpacing( 6 ); + groupBox->layout()->setMargin( 11 ); + QGridLayout * groupBoxLayout = new QGridLayout( groupBox->layout() ); + groupBoxLayout->setAlignment( Qt::AlignTop ); + + // TODO: replace this with i18n( "the type", "Type (TRIS register):" ); + groupBoxLayout->addWidget( new QLabel( i18n("Type (TRIS register):"), groupBox ), 0, 0 ); + groupBoxLayout->addWidget( new QLabel( i18n("State (PORT register):"), groupBox ), 1, 0 ); + + m_portTypeEdit[row] = new KLineEdit( portType, groupBox ); + groupBoxLayout->addWidget( m_portTypeEdit[row], 0, 1 ); + + m_portStateEdit[row] = new KLineEdit( portState, groupBox ); + groupBoxLayout->addWidget( m_portStateEdit[row], 1, 1 ); + +// (dynamic_cast(m_pWidget->portsGroupBox->layout()))->insertWidget( row, groupBox ); + (dynamic_cast(m_pWidget->portsGroupBox->layout()))->addWidget( groupBox ); + } + //END Initialize initial port settings + + + + //BEGIN Initialize initial variable settings + // Hide row headers + m_pWidget->variables->setLeftMargin(0); + + // Make columns as thin as possible + m_pWidget->variables->setColumnStretchable( 0, true ); + m_pWidget->variables->setColumnStretchable( 1, true ); + + QStringList variables = microSettings->variableNames(); + row = 0; + end = variables.end(); + for ( QStringList::iterator it = variables.begin(); it != end; ++it ) + { + VariableInfo *info = microSettings->variableInfo(*it); + if (info) + { + m_pWidget->variables->insertRows( row, 1 ); + m_pWidget->variables->setText( row, 0, *it ); + m_pWidget->variables->setText( row, 1, info->valueAsString() ); + ++row; + } + } + m_pWidget->variables->insertRows( row, 1 ); + + connect( m_pWidget->variables, SIGNAL(valueChanged(int,int)), this, SLOT(checkAddVariableRow()) ); + //END Initialize initial variable settings + + + + //BEGIN Initialize pin maps + connect( m_pWidget->pinMapAdd, SIGNAL(clicked()), this, SLOT(slotCreatePinMap()) ); + connect( m_pWidget->pinMapModify, SIGNAL(clicked()), this, SLOT(slotModifyPinMap()) ); + connect( m_pWidget->pinMapRename, SIGNAL(clicked()), this, SLOT(slotRenamePinMap()) ); + connect( m_pWidget->pinMapRemove, SIGNAL(clicked()), this, SLOT(slotRemovePinMap()) ); + + m_pinMappings = microSettings->pinMappings(); + m_pWidget->pinMapCombo->insertStringList( m_pinMappings.keys() ); + + updatePinMapButtons(); + //END Initialize pin maps + + + enableButtonSeparator( false ); + setMainWidget(m_pWidget); + m_pWidget->adjustSize(); + adjustSize(); + + connect( this, SIGNAL(applyClicked()), this, SLOT(slotSaveStuff()) ); +} + + +MicroSettingsDlg::~MicroSettingsDlg() +{ +} + + +void MicroSettingsDlg::accept() +{ + hide(); + slotSaveStuff(); + deleteLater(); +} + + +void MicroSettingsDlg::slotSaveStuff() +{ + for ( unsigned i = 0; i < m_portNames.size(); i++ ) + savePort(i); + + m_pMicroSettings->removeAllVariables(); + for ( int i=0; i< m_pWidget->variables->numRows(); i++ ) + saveVariable(i); + + m_pMicroSettings->setPinMappings( m_pinMappings ); +} + + +void MicroSettingsDlg::reject() +{ + deleteLater(); +} + + +QValidator::State MicroSettingsDlg::validatePinMapName( QString & name ) const +{ + name.replace( ' ', '_' ); + + if ( name.isEmpty() ) + return QValidator::Intermediate; + + for ( unsigned i = 0; i < name.length(); ++i ) + { + if ( !name[i].isLetterOrNumber() && name[i] != '_' ) + return QValidator::Invalid; + } + + if ( name[0].isNumber() ) + return QValidator::Intermediate; + + if ( m_pWidget->pinMapCombo->contains( name ) ) + return QValidator::Intermediate; + + return QValidator::Acceptable; +} + + +class PinMappingNameValidator : public QValidator +{ + public: + /** + * Create a validator. If oldName is not empty, then the input is + * allowed to be oldName. + */ + PinMappingNameValidator( MicroSettingsDlg * dlg, const QString & oldName = 0 ) + : QValidator(0) + { + m_pDlg = dlg; + m_oldName = oldName; + } + + virtual State validate( QString & input, int & ) const + { + if ( (!m_oldName.isEmpty()) && (input == m_oldName) ) + return QValidator::Acceptable; + + return m_pDlg->validatePinMapName( input ); + } + + protected: + MicroSettingsDlg * m_pDlg; + QString m_oldName; +}; + + +void MicroSettingsDlg::slotCheckNewPinMappingName( const QString & name ) +{ + // Validate name might change the name so that it is valid + QString newName = name; + + if ( m_pNewPinMappingWidget ) + m_pNewPinMappingDlg->enableButtonOK( validatePinMapName( newName ) == QValidator::Acceptable ); + + if ( newName != name ) + m_pNewPinMappingWidget->nameEdit->setText( newName ); +} + + +void MicroSettingsDlg::slotCreatePinMap() +{ + m_pNewPinMappingDlg = new KDialogBase( this, "New Pin Mapping Dlg", true, i18n("New Pin Mapping"), Ok | Cancel ); + m_pNewPinMappingDlg->setButtonText( Ok, i18n("Create") ); + m_pNewPinMappingWidget = new NewPinMappingWidget( m_pNewPinMappingDlg ); + m_pNewPinMappingDlg->setMainWidget( m_pNewPinMappingWidget ); + + PinMappingNameValidator * validator = new PinMappingNameValidator( this ); + m_pNewPinMappingWidget->nameEdit->setValidator( validator ); + + connect( m_pNewPinMappingWidget->nameEdit, SIGNAL(textChanged(const QString &)), this, SLOT(slotCheckNewPinMappingName(const QString &)) ); + slotCheckNewPinMappingName( 0 ); + + int accepted = m_pNewPinMappingDlg->exec(); + unsigned selectedType = m_pNewPinMappingWidget->typeCombo->currentItem(); + QString name = m_pNewPinMappingWidget->nameEdit->text(); + + delete m_pNewPinMappingDlg; + delete validator; + m_pNewPinMappingDlg = 0l; + m_pNewPinMappingWidget = 0l; + if ( accepted != QDialog::Accepted ) + return; + + PinMapping::Type type = PinMapping::Invalid; + + switch ( selectedType ) + { + case 0: + type = PinMapping::SevenSegment; + break; + + case 1: + type = PinMapping::Keypad_4x3; + break; + + case 2: + type = PinMapping::Keypad_4x4; + break; + + default: + kdError() << k_funcinfo << "Unknown selected type " << type << endl; + break; + } + + m_pinMappings[name] = PinMapping( type ); + m_pWidget->pinMapCombo->insertItem( name ); + m_pWidget->pinMapCombo->setCurrentItem( m_pWidget->pinMapCombo->count() - 1 ); + + updatePinMapButtons(); + slotModifyPinMap(); +} + + +void MicroSettingsDlg::slotRenamePinMap() +{ + KComboBox * combo = m_pWidget->pinMapCombo; + + QString oldName = combo->currentText(); + if ( oldName.isEmpty() ) + return; + + PinMappingNameValidator * validator = new PinMappingNameValidator( this, oldName ); + + bool ok = false; + QString newName = KInputDialog::getText( i18n("New Pin Map Name"), i18n("Name"), oldName, & ok, this, 0, validator ); + + delete validator; + + if ( !ok ) + return; + + if ( newName == oldName ) + return; + + m_pinMappings[ newName ] = m_pinMappings[ oldName ]; + m_pinMappings.remove( oldName ); + + combo->setCurrentText( newName ); +} + + +void MicroSettingsDlg::slotModifyPinMap() +{ + QString name = m_pWidget->pinMapCombo->currentText(); + PinMapping pinMapping = m_pinMappings[ name ]; + + PinMapEditor * pinMapEditor = new PinMapEditor( & pinMapping, m_pMicroSettings->microInfo(), this, "PinMapEditor" ); + int accepted = pinMapEditor->exec(); + + delete pinMapEditor; + + if ( accepted != QDialog::Accepted ) + return; + + m_pinMappings[ name ] = pinMapping; +} + + +void MicroSettingsDlg::slotRemovePinMap() +{ + KComboBox * combo = m_pWidget->pinMapCombo; + + QString pinMapID = combo->currentText(); + if ( pinMapID.isEmpty() ) + return; + + m_pinMappings.remove( pinMapID ); + combo->removeItem( combo->currentItem() ); + + updatePinMapButtons(); +} + + +void MicroSettingsDlg::updatePinMapButtons() +{ + bool havePinMaps = (m_pWidget->pinMapCombo->count() != 0); + + m_pWidget->pinMapModify->setEnabled( havePinMaps ); + m_pWidget->pinMapRename->setEnabled( havePinMaps ); + m_pWidget->pinMapRemove->setEnabled( havePinMaps ); +} + + +void MicroSettingsDlg::savePort( int row ) +{ + QString port = m_portNames[row]; + + int type, state; + + QString typeText = m_portTypeEdit[row]->text(); + bool typeOk = true; + if ( typeText.startsWith( "0x", false ) ) type = typeText.remove(0,2).toInt( &typeOk, 16 ); + else if ( typeText.contains( QRegExp("[^01]") ) ) type = typeText.toInt( &typeOk, 10 ); + else type = typeText.toInt( &typeOk, 2 ); + + if ( !typeOk ) + { +// KMessageBox::sorry( this, i18n("Unregnised Port Type: %1").arg(typeText) ); + return; + } + + + QString stateText = m_portStateEdit[row]->text(); + bool stateOk = true; + if ( stateText.startsWith( "0x", false ) ) state = stateText.remove(0,2).toInt( &stateOk, 16 ); + else if ( stateText.contains( QRegExp("[^01]") ) ) state = stateText.toInt( &stateOk, 10 ); + else state = stateText.toInt( &stateOk, 2 ); + + if ( !stateOk ) + { +// KMessageBox::sorry( this, i18n("Unregnised Port State: %1").arg(stateText) ); + return; + } + + m_pMicroSettings->setPortState( port, state ); + m_pMicroSettings->setPortType( port, type ); +} + + +void MicroSettingsDlg::saveVariable( int row ) +{ + QString name = m_pWidget->variables->text( row, 0 ); + if ( name.isEmpty() ) return; + + QString valueText = m_pWidget->variables->text( row, 1 ); + int value; + bool ok = true; + if ( valueText.startsWith( "0x", false ) ) value = valueText.remove(0,2).toInt( &ok, 16 ); + else value = valueText.toInt( &ok, 10 ); + + if (!ok) + { + KMessageBox::sorry( this, i18n("Invalid variable value: %1").arg(valueText) ); + return; + } + + m_pMicroSettings->setVariable( name, value, true ); + VariableInfo *info = m_pMicroSettings->variableInfo(name); + if ( info && info->valueAsString().toInt() != value ) + { +// info->setValue(value); +// info->permanent = true; + info->initAtStart = true; + } +} + + +void MicroSettingsDlg::checkAddVariableRow() +{ + int lastRow = m_pWidget->variables->numRows()-1; + if ( !m_pWidget->variables->text( lastRow, 0 ).isEmpty() ) m_pWidget->variables->insertRows( lastRow+1, 1 ); +} + + + +#include "microsettingsdlg.moc" diff --git a/src/gui/microsettingsdlg.h b/src/gui/microsettingsdlg.h new file mode 100644 index 0000000..54582dd --- /dev/null +++ b/src/gui/microsettingsdlg.h @@ -0,0 +1,105 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef MICROSETTINGSDLG_H +#define MICROSETTINGSDLG_H + +#include + +#include +#include +#include + +class KLineEdit; +class MicroSettings; +class MicroSettingsWidget; +class NewPinMappingWidget; +class PinMapping; + +typedef QMap< QString, PinMapping > PinMappingMap; + +/** +@author David Saxton +*/ +class MicroSettingsDlg : public KDialogBase +{ + Q_OBJECT + public: + MicroSettingsDlg( MicroSettings *_microSettings, QWidget *parent = 0L, const char *name = 0L ); + ~MicroSettingsDlg(); + + void reject(); + void accept(); + + /** + * @param pinMapName the pinMapName; may be changed to make it valid + * (e.g. spaces replaced with underscores). + * @returns Invalid for a pinMapName containing a non-variable name, + * Intermediate for a pinMapName that starts with a number or is already + * in use, and Acceptable otherwise. + */ + QValidator::State validatePinMapName( QString & pinMapName ) const; + + public slots: + /** + * Saves the port details in the given row to the MicroSettings class. + * Usually called when the value is changed, or on 'Apply' of the + * dialog. + */ + void savePort( int row ); + /** + * Saves the variable details to the MicroSettings class. + */ + void saveVariable( int row ); + /** + * Adds an extra row to the list of variable if one is required. + */ + void checkAddVariableRow(); + /** + * Called when the pinMapAdd button is pressed. + */ + void slotCreatePinMap(); + /** + * Called when the pinMapModify button is pressed. + */ + void slotModifyPinMap(); + /** + * Called when the pinMapRename button is pressed. + */ + void slotRenamePinMap(); + /** + * Called when the pinMapRemove button is pressed. + */ + void slotRemovePinMap(); + /** + * Called when the dialog is Applied or OK'd. + */ + void slotSaveStuff(); + + protected slots: + void slotCheckNewPinMappingName( const QString & name ); + + protected: + /** + * Set each button enabled / disabled as appropriate. + */ + void updatePinMapButtons(); + + NewPinMappingWidget * m_pNewPinMappingWidget; // Used for checking that the variable name is ok + KDialogBase * m_pNewPinMappingDlg; + MicroSettingsWidget * m_pWidget; + MicroSettings * m_pMicroSettings; + PinMappingMap m_pinMappings; + QValueVector< KLineEdit * > m_portTypeEdit; + QValueVector< KLineEdit * > m_portStateEdit; + QStringList m_portNames; +}; + +#endif diff --git a/src/gui/microsettingswidget.ui b/src/gui/microsettingswidget.ui new file mode 100644 index 0000000..5c63a1b --- /dev/null +++ b/src/gui/microsettingswidget.ui @@ -0,0 +1,197 @@ + +MicroSettingsWidget + + + MicroSettingsWidget + + + + 0 + 0 + 447 + 401 + + + + + 1 + 1 + 0 + 0 + + + + PIC Settings + + + + unnamed + + + 0 + + + + portsGroupBox + + + Initial Port Settings + + + + unnamed + + + + textLabel1 + + + + 3 + 1 + 0 + 0 + + + + Tip: Toggle the initial state (high/low) of a pin by clicking its picture. +Drag it to set the type (input/output). + + + PlainText + + + + + + + groupBox6 + + + + 1 + 1 + 0 + 0 + + + + Initial Variable Values + + + + unnamed + + + + + Variable + + + + + Value + + + + variables + + + + 0 + 64 + + + + 0 + + + 2 + + + + + + + groupBox3 + + + Pin Map Definitions + + + + unnamed + + + + pinMapCombo + + + + + pinMapRemove + + + Remove + + + + + spacer3 + + + Horizontal + + + Expanding + + + + 60 + 20 + + + + + + pinMapAdd + + + Create + + + + + pinMapModify + + + Modif&y + + + Alt+Y + + + + + pinMapRename + + + Rename + + + + + + + + + + + + kcombobox.h + kpushbutton.h + kpushbutton.h + kpushbutton.h + kpushbutton.h + + diff --git a/src/gui/newfiledlg.cpp b/src/gui/newfiledlg.cpp new file mode 100644 index 0000000..485b3bf --- /dev/null +++ b/src/gui/newfiledlg.cpp @@ -0,0 +1,151 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "config.h" +#include "document.h" +#include "microinfo.h" +#include "newfiledlg.h" +#include "newfilewidget.h" +#include "microlibrary.h" +#include "microselectwidget.h" +#include "projectmanager.h" +#include "textdocument.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +NewFileDlg::NewFileDlg( QWidget *parent ) + : KDialogBase( parent, "newfiledlg", true, "New File", KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true ) +{ + m_pMainParent = parent; + m_bAccepted = false; + m_pNewFileWidget = new NewFileWidget(this); + + m_pNewFileWidget->typeIconView->setSelectionMode(QIconView::Single); + m_pNewFileWidget->typeIconView->setMode(KIconView::Select); + + KIconLoader *loader = KGlobal::iconLoader(); + + QValueList items; + + items << new QIconViewItem(m_pNewFileWidget->typeIconView,"Assembly Code (.asm)", loader->loadIcon( "source", KIcon::NoGroup, KIcon::SizeHuge ) ); + items << new QIconViewItem(m_pNewFileWidget->typeIconView,"C (.c)", loader->loadIcon( "source_c", KIcon::NoGroup, KIcon::SizeHuge ) ); + items << new QIconViewItem(m_pNewFileWidget->typeIconView,"Circuit (.circuit)", loader->loadIcon( "ktechlab_circuit", KIcon::NoGroup, KIcon::SizeHuge ) ); + items << new QIconViewItem(m_pNewFileWidget->typeIconView,"FlowCode (.flowcode)", loader->loadIcon( "ktechlab_flowcode", KIcon::NoGroup, KIcon::SizeHuge ) ); +#ifdef MECHANICS + items << new QIconViewItem(m_pNewFileWidget->typeIconView,"Mechanics (.mechanics)", loader->loadIcon( "exec", KIcon::NoGroup, KIcon::SizeHuge ) ); +#endif + items << new QIconViewItem(m_pNewFileWidget->typeIconView,"Microbe (.microbe)", loader->loadIcon( "ktechlab_microbe", KIcon::NoGroup, KIcon::SizeHuge ) ); + + unsigned minWidth = 20 + m_pNewFileWidget->typeIconView->spacing() * items.size(); + int minHeight = 0; + + const QValueList::iterator end = items.end(); + for ( QValueList::iterator it = items.begin(); it != end; ++it ) + { + (*it)->setDragEnabled(false); + minWidth += (*it)->width(); + minHeight = QMAX( minHeight, (*it)->height()+20 ); + } + + m_pNewFileWidget->typeIconView->setMinimumSize( minWidth, minHeight ); + m_pNewFileWidget->typeIconView->setCurrentItem(items[3]); + m_pNewFileWidget->addToProjectCheck->setChecked( ProjectManager::self()->currentProject() ); + m_pNewFileWidget->addToProjectCheck->setEnabled( ProjectManager::self()->currentProject() ); + microSelectWidget()->setAllowedFlowCodeSupport( MicroInfo::FullSupport | MicroInfo::PartialSupport ); + + setMainWidget(m_pNewFileWidget); + + // Our behaviour is to have single click selects and double click accepts the dialog + connect( m_pNewFileWidget->typeIconView, SIGNAL(selectionChanged(QIconViewItem*)), this, SLOT(fileTypeChanged(QIconViewItem*)) ); + connect( m_pNewFileWidget->typeIconView, SIGNAL(doubleClicked(QIconViewItem*)), this, SLOT(accept())); + + setAcceptDrops(true); + + m_pNewFileWidget->typeIconView->adjustSize(); + m_pNewFileWidget->adjustSize(); + adjustSize(); +} + +void NewFileDlg::accept() +{ + hide(); + m_bAccepted = true; + + const QString fileText = m_pNewFileWidget->typeIconView->currentItem()->text(); + + if ( fileText.contains(".flowcode") ) + m_fileType = Document::dt_flowcode; + + else if ( fileText.contains(".circuit") ) + m_fileType = Document::dt_circuit; + + else if ( fileText.contains(".mechanics") ) + m_fileType = Document::dt_mechanics; + + else if ( fileText.contains(".asm") ) + { + m_fileType = Document::dt_text; + m_codeType = TextDocument::ct_asm; + } + + else if ( fileText.contains(".basic") || fileText.contains(".microbe") ) + { + m_fileType = Document::dt_text; + m_codeType = TextDocument::ct_microbe; + } + + else if (fileText.contains(".c") ) + { + m_fileType = Document::dt_text; + m_codeType = TextDocument::ct_c; + } + + else + m_fileType = Document::dt_text; + + m_bAddToProject = m_pNewFileWidget->addToProjectCheck->isChecked(); + + m_microID = m_pNewFileWidget->m_pMicroSelect->micro(); +} + + +void NewFileDlg::reject() +{ + m_bAccepted = false; +} + + +void NewFileDlg::fileTypeChanged( QIconViewItem *item ) +{ + m_pNewFileWidget->m_pMicroSelect->setEnabled( + item->text().contains(".flowcode") ); +} + + +MicroSelectWidget * NewFileDlg::microSelectWidget() const +{ + return m_pNewFileWidget->m_pMicroSelect; +} + + +#include "newfiledlg.moc" diff --git a/src/gui/newfiledlg.h b/src/gui/newfiledlg.h new file mode 100644 index 0000000..fc20800 --- /dev/null +++ b/src/gui/newfiledlg.h @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef NEWFILEDLG_H +#define NEWFILEDLG_H + +#include + +class MicroSelectWidget; +class NewFileWidget; +class QIconViewItem; + +/** +A standard dialog for getting file details from the user for a new project +@short Dialog for new file details +@author David Saxton +*/ +class NewFileDlg : public KDialogBase +{ + Q_OBJECT + public: + NewFileDlg( QWidget *parent ); + + void reject(); + void accept(); + + bool accepted() const { return m_bAccepted; } + int fileType() const { return m_fileType; } + int codeType() const { return m_codeType; } + bool addToProject() const { return m_bAddToProject; } + QString microID() const { return m_microID; } + MicroSelectWidget * microSelectWidget() const; + + public slots: + void fileTypeChanged( QIconViewItem *item ); + + protected: + bool m_bAccepted; + int m_fileType; + int m_codeType; + bool m_bAddToProject; + QString m_microID; + + NewFileWidget * m_pNewFileWidget; + QWidget * m_pMainParent; +}; + +#endif diff --git a/src/gui/newfilewidget.ui b/src/gui/newfilewidget.ui new file mode 100644 index 0000000..0e02524 --- /dev/null +++ b/src/gui/newfilewidget.ui @@ -0,0 +1,195 @@ + +NewFileWidget + + + NewFileWidget + + + + 0 + 0 + 600 + 213 + + + + New File + + + Select the type of file you wish to create.<br> +<p> +<b>Pic Program</b><br> +Creates a new PIC program, with flow chart editor. Select the target device for your program below. +<p> +<b>Circuit</b><br> +Creates a new circuit, with drag and drop editor. Real time simulation of the circuit occurs automatically. + + + + unnamed + + + 0 + + + + textLabel1 + + + + 5 + 4 + 0 + 0 + + + + + 1 + + + + New File Details + + + + + textLabel1_2_2 + + + File Type: + + + AlignVCenter + + + + + typeIconView + + + + 1 + 1 + 0 + 0 + + + + + 500 + 150 + + + + false + + + AutoOneFit + + + true + + + false + + + + + addToProjectCheck + + + + 1 + 0 + 0 + 0 + + + + &Add to project + + + Alt+A + + + true + + + + + m_pMicroSelect + + + + 5 + 5 + 0 + 0 + + + + + 0 + 0 + + + + + 32767 + 32767 + + + + + + spacer1 + + + Vertical + + + Expanding + + + + 20 + 0 + + + + + + + + MicroSelectWidget +
    microselectwidget.h
    + + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image0 +
    +
    + + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000042949444154388db5954d6c545514c77ff7de37eff1a6a550da994e5ba798868f948fc847a2a2911816c436b0a02ed0083161a1981877ee10d90aa94656063491882c5cd4c4b8103f20cd806909a98604da8482341de80cb69de9bcd799799d79efba980f1da3a80b4f727273939bdff99f9b93f3175a6b6a21849080020c4002a29a8f0a5dcd002803bed63a1035f0d0d0504b6f6fef51d7758fa4d3e98d8ee3fc03af128ee3303939399548242eb8aefb09300f78464de9f0f0f0d148cc7caf3d5424de97a7ec17104220242805520a44557bbd4b21f083801d33e63a6d1bc7bf19c6064e0319a35a58b9ae7ba43d54e4d7c54b64dc097c7f09d30ef04b36736983cc7c11b4456b9b492c5e20dc54a6540e00896a8268a7017010f8bcae1830d2e9f4c69ebe3c197782b2ce60d94ddc9b30f9feeb45ae5d7181c5ead35636ef08d3ffe26a76ee3208b4031a56d80aa00768fda362e9380e25bf80ef3b587613d7afc099533380a4b5dda46fcb5aa42998b9eb7173dce5e6788e434763ec7fc942532008ea436003660d2caa7f8d69c3bd8910674e4d033e83877ad8d36fb0aa4d6058658ac5358c5df6383bf480f31fdda5a3632bbbfb6da4ccd5c00a10b2012cc12fd97cfb5516f0187c25cee0619396480ec3ca909d0f3372d1e5f9fe66de3ad605587c712ec55256a2540d5519d19ae24a29057329839f7ecc138944d833102290f3184ae1e6d6f0e98739c61229e6d21eafbed1c9c8c5558c8f3ee4ceed76946a1c43d97091828585223e2eebfbc295f60d45de89707628cb58224577bc85a79e5d4d786581cddb9b0148259711b20145836221400416e0232d1f6595c9ce4538773ac7b54406f0b15784e8e80aa1ac2594190220d021e49f2437960156b70ba095e95f96f18acd8c263cc6122962b1167a7ba34cdd7ec8c977a699bed546722a8fc2a02b6e2185fff78ab586ce78894ddb9ab9f5738ed14b1e030756929d8ff2e4ae5544632b38f96e89a99b298ebd6950cc2d12ed0eb3618b26f520788462ad09877df60db600f0f1fb49c646f21c7ebd836dcf94e9d9b4c0db27d6d3bd36c6426a96bce731703046d7da129a4670836284a054869d4f1b1c7e2dca67676ef3c1898091ef5ad8bc358c3205c93bf7c9a40ad4c660f4728edd7bbb3142ea2fc1da711cfc200011e08b45f6bd1c261adbce9717928c5f9d63fc6a19f0014567773303073790f8214bd6f5282dfbb8b9fa1f6b40d7c1939393533b92e63ad9240990484aec7e41b27d579cbb531e0f67023492d86316ebb768ba1e0f786e6f37e56550c62237aee7011e54abd7c1412291b8a06de378b4d3c0b215da9708e5a3a442192085404a83d4accfecac067c0c43e13a70e3fa12e96409e0325000966bbb354465339d04a6f9dd15fe6dde07ce030780278088d05ad72cc9a6b2f2daaaa74d75a1f0e8d0d5f60b40868a8364ead6248430000b0857a126ffcdf396abf03ce089ffcb4c7f033046c6b4a995e7a00000000049454e44ae426082 + + + + typeIconView + addToProjectCheck + + + + kiconview.h + microselectwidget.h + +
    diff --git a/src/gui/newpinmappingwidget.ui b/src/gui/newpinmappingwidget.ui new file mode 100644 index 0000000..4ac5932 --- /dev/null +++ b/src/gui/newpinmappingwidget.ui @@ -0,0 +1,130 @@ + +NewPinMappingWidget + + + NewPinMappingWidget + + + + 0 + 0 + 350 + 80 + + + + New Pin Mapping + + + + unnamed + + + 0 + + + + textLabel2 + + + Type: + + + + + textLabel1 + + + Name: + + + + + textLabel3 + + + + 1 + + + + New Pin Mapping + + + PlainText + + + + + spacer6 + + + Vertical + + + Expanding + + + + 20 + 21 + + + + + + nameEdit + + + + 3 + 0 + 0 + 0 + + + + + 300 + 0 + + + + The variable name of the pin mapping - this must be a valid Microbe variable name. + + + + + + Seven Segment + + + + + Keypad (4x3) + + + + + Keypad (4x4) + + + + typeCombo + + + + 200 + 0 + + + + + + + + + + klineedit.h + + diff --git a/src/gui/newprojectwidget.ui b/src/gui/newprojectwidget.ui new file mode 100644 index 0000000..9d8648f --- /dev/null +++ b/src/gui/newprojectwidget.ui @@ -0,0 +1,110 @@ + +NewProjectWidget + + + NewProjectWidget + + + + 0 + 0 + 532 + 103 + + + + New Project + + + + unnamed + + + 0 + + + + textLabel8 + + + Final location: + + + + + locationLabel + + + / + + + + + spacer2 + + + Vertical + + + Expanding + + + + 20 + 16 + + + + + + textLabel4 + + + Location: + + + + + textLabel1 + + + + 1 + + + + New Project Details + + + + + textLabel10 + + + Project Name: + + + + + projectNameEdit + + + + + projectLocationURL + + + + + + projectNameEdit + projectLocationURL + + + + klineedit.h + kurlrequester.h + klineedit.h + kpushbutton.h + + diff --git a/src/gui/orientationwidget.cpp b/src/gui/orientationwidget.cpp new file mode 100644 index 0000000..28e10c7 --- /dev/null +++ b/src/gui/orientationwidget.cpp @@ -0,0 +1,255 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "cnitem.h" +#include "cnitemgroup.h" +#include "component.h" +#include "flowpart.h" +#include "iteminterface.h" +#include "itemlibrary.h" +#include "orientationwidget.h" +#include "node.h" + +#include +#include +#include +#include +#include +#include +#include + +const int _size = 44; + +OrientationWidget::OrientationWidget(QWidget *parent, const char *name) + : QWidget(parent, name) +{ + QGridLayout *layout = new QGridLayout( this, 2, 4, 0, 4 ); + p_activeFlowPart = 0l; + + for ( int row=0; row<2; ++row ) + { + for ( int col=0; col<4; ++col ) + { + QPushButton *btn = new QPushButton(this); + m_toolBtn[row][col] = btn; + layout->addWidget( btn, row, col ); + btn->setFixedSize( _size+6, _size+6 ); +// btn->setFlat(true); + btn->setEnabled(false); + } + } + + connect( m_toolBtn[0][0], SIGNAL(clicked()), this, SLOT(set_cio_noflip_0()) ); + connect( m_toolBtn[0][1], SIGNAL(clicked()), this, SLOT(set_cio_noflip_90()) ); + connect( m_toolBtn[0][2], SIGNAL(clicked()), this, SLOT(set_cio_noflip_180()) ); + connect( m_toolBtn[0][3], SIGNAL(clicked()), this, SLOT(set_cio_noflip_270()) ); + connect( m_toolBtn[1][0], SIGNAL(clicked()), this, SLOT(set_cio_flip_0()) ); + connect( m_toolBtn[1][1], SIGNAL(clicked()), this, SLOT(set_cio_flip_90()) ); + connect( m_toolBtn[1][2], SIGNAL(clicked()), this, SLOT(set_cio_flip_180()) ); + connect( m_toolBtn[1][3], SIGNAL(clicked()), this, SLOT(set_cio_flip_270()) ); +} + + +OrientationWidget::~OrientationWidget() +{ +} + +void OrientationWidget::slotUpdate( CNItem *activeCNItem ) +{ + p_activeFlowPart = dynamic_cast(activeCNItem); + if (p_activeFlowPart) + { + initFromFlowPart(p_activeFlowPart); + return; + } + + Component *activeComponent = dynamic_cast(activeCNItem); + + if ( activeComponent && (activeComponent->canRotate() || activeComponent->canFlip()) ) + { + initFromComponent(activeComponent); + return; + } + + slotClear(); +} + + +void OrientationWidget::initFromFlowPart( FlowPart *flowPart ) +{ + if (!flowPart) + return; + + uint valid = flowPart->allowedOrientations(); + +// m_toolBtn[0][0]->setText("b00"); + for ( uint i=0; i<2; ++i ) + { + for ( uint j=0; j<4; ++j ) + { + uint o = j + 4*i; + if ( valid & (1<setEnabled(true); + QPixmap pm( 50, 50 ); + flowPart->orientationPixmap( o, pm ); + m_toolBtn[i][j]->setPixmap(pm); + } + } + } +} + + +void OrientationWidget::initFromComponent( Component *component ) +{ + const QImage im = itemLibrary()->itemImage(component); + + QRect bound = component->boundingRect(); + + // We want a nice square bounding rect + const int dy = bound.width() - bound.height(); + if ( dy > 0 ) + { + bound.setTop( bound.top()-(dy/2) ); + bound.setBottom( bound.bottom()+(dy/2) ); + } + else if ( dy < 0 ) + { + bound.setLeft( bound.left()+(dy/2) ); + bound.setRight( bound.right()-(dy/2) ); + } + + + QPixmap tbPm; + tbPm.convertFromImage(im); + m_toolBtn[0][0]->setPixmap(tbPm); + m_toolBtn[0][0]->setEnabled(true); + + if ( component->canRotate() ) + { +// QPixmap tbPm; + tbPm.convertFromImage( im.xForm( Component::transMatrix( 90, false, bound.width()/2, bound.height()/2 ) ) ); + m_toolBtn[0][1]->setPixmap(tbPm); + m_toolBtn[0][1]->setEnabled(true); + +// QPixmap tbPm; + tbPm.convertFromImage( im.xForm( Component::transMatrix( 180, false, bound.width()/2, bound.height()/2 ) ) ); + m_toolBtn[0][2]->setPixmap(tbPm); + m_toolBtn[0][2]->setEnabled(true); + +// QPixmap tbPm; + tbPm.convertFromImage( im.xForm( Component::transMatrix( 270, false, bound.width()/2, bound.height()/2 ) ) ); + m_toolBtn[0][3]->setPixmap(tbPm); + m_toolBtn[0][3]->setEnabled(true); + } + + if ( component->canFlip() ) + { +// QPixmap tbPm; + tbPm.convertFromImage( im.xForm( Component::transMatrix( 0, true, bound.width()/2, bound.height()/2 ) ) ); + m_toolBtn[1][0]->setPixmap(tbPm); + m_toolBtn[1][0]->setEnabled(true); + + if ( component->canRotate() ) + { +// QPixmap tbPm; + tbPm.convertFromImage( im.xForm( Component::transMatrix( 90, true, bound.width()/2, bound.height()/2 ) ) ); + m_toolBtn[1][1]->setPixmap(tbPm); + m_toolBtn[1][1]->setEnabled(true); + +// QPixmap tbPm; + tbPm.convertFromImage( im.xForm( Component::transMatrix( 180, true, bound.width()/2, bound.height()/2 ) ) ); + m_toolBtn[1][2]->setPixmap(tbPm); + m_toolBtn[1][2]->setEnabled(true); + +// QPixmap tbPm; + tbPm.convertFromImage( im.xForm( Component::transMatrix( 270, true, bound.width()/2, bound.height()/2 ) ) ); + m_toolBtn[1][3]->setPixmap(tbPm); + m_toolBtn[1][3]->setEnabled(true); + } + } +} + + +void OrientationWidget::slotClear() +{ + for ( int row=0; row<2; ++row ) + { + for ( int col=0; col<4; ++col ) + { + // Hmm...this line has crashed before + m_toolBtn[row][col]->setPixmap( QPixmap::QPixmap() ); + m_toolBtn[row][col]->setEnabled(false); + } + } +} + + +void OrientationWidget::set_cio_noflip_0() +{ + if (p_activeFlowPart) + ItemInterface::self()->setFlowPartOrientation(0); + else + ItemInterface::self()->setComponentOrientation( 0, false ); +} +void OrientationWidget::set_cio_noflip_90() +{ + if (p_activeFlowPart) + ItemInterface::self()->setFlowPartOrientation(1); + else + ItemInterface::self()->setComponentOrientation( 90, false ); +} +void OrientationWidget::set_cio_noflip_180() +{ + if (p_activeFlowPart) + ItemInterface::self()->setFlowPartOrientation(2); + else + ItemInterface::self()->setComponentOrientation( 180, false ); +} +void OrientationWidget::set_cio_noflip_270() +{ + if (p_activeFlowPart) + ItemInterface::self()->setFlowPartOrientation(3); + else + ItemInterface::self()->setComponentOrientation( 270, false ); +} +void OrientationWidget::set_cio_flip_0() +{ + if (p_activeFlowPart) + ItemInterface::self()->setFlowPartOrientation(4); + else + ItemInterface::self()->setComponentOrientation( 0, true ); +} +void OrientationWidget::set_cio_flip_90() +{ + if (p_activeFlowPart) + ItemInterface::self()->setFlowPartOrientation(5); + else + ItemInterface::self()->setComponentOrientation( 90, true ); +} +void OrientationWidget::set_cio_flip_180() +{ + if (p_activeFlowPart) + ItemInterface::self()->setFlowPartOrientation(6); + else + ItemInterface::self()->setComponentOrientation( 180, true ); +} +void OrientationWidget::set_cio_flip_270() +{ + if (p_activeFlowPart) + ItemInterface::self()->setFlowPartOrientation(7); + else + ItemInterface::self()->setComponentOrientation( 270, true ); +} + +#include "orientationwidget.moc" + + + diff --git a/src/gui/orientationwidget.h b/src/gui/orientationwidget.h new file mode 100644 index 0000000..6a6b6ce --- /dev/null +++ b/src/gui/orientationwidget.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ORIENTATIONWIDGET_H +#define ORIENTATIONWIDGET_H + +#include +#include + +class CNItem; +class CNItemGroup; +class FlowPart; +class QPushButton; + +/** +@author David Saxton +*/ +class OrientationWidget : public QWidget +{ +Q_OBJECT +public: + OrientationWidget( QWidget *parent = 0l, const char *name = 0l ); + ~OrientationWidget(); + +public slots: + void slotUpdate( CNItem *item ); + void slotClear(); + + void set_cio_noflip_0(); + void set_cio_noflip_90(); + void set_cio_noflip_180(); + void set_cio_noflip_270(); + void set_cio_flip_0(); + void set_cio_flip_90(); + void set_cio_flip_180(); + void set_cio_flip_270(); + +signals: + void orientationSelected( uint orientation ); + +protected: + void initFromComponent( Component *component ); + void initFromFlowPart( FlowPart *flowPart ); + + QPushButton *m_toolBtn[2][4]; + QGuardedPtr p_activeFlowPart; +}; + +#endif diff --git a/src/gui/oscilloscope.cpp b/src/gui/oscilloscope.cpp new file mode 100644 index 0000000..e969f72 --- /dev/null +++ b/src/gui/oscilloscope.cpp @@ -0,0 +1,354 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "oscilloscope.h" +#include "oscilloscopedata.h" +#include "oscilloscopeview.h" +#include "probe.h" +#include "probepositioner.h" +#include "simulator.h" +#include "ktechlab.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//BEGIN Oscilloscope Class +QColor probeColors[9] = { + QColor( 0x52, 0x22, 0x00 ), + QColor( 0xB5, 0x00, 0x2F ), + QColor( 0xF9, 0xBA, 0x07 ), + QColor( 0x53, 0x93, 0x16 ), + QColor( 0x00, 0x66, 0x2F ), + QColor( 0x00, 0x41, 0x88 ), + QColor( 0x1B, 0x2D, 0x83 ), + QColor( 0x55, 0x12, 0x7B ), + QColor( 0x7B, 0x0C, 0x82 ) }; + +Oscilloscope * Oscilloscope::m_pSelf = 0l; + +Oscilloscope * Oscilloscope::self( KateMDI::ToolView * parent ) +{ + if ( !m_pSelf ) + { + assert(parent); + m_pSelf = new Oscilloscope(parent); + } + return m_pSelf; +} + + +Oscilloscope::Oscilloscope( KateMDI::ToolView * parent ) + : OscilloscopeWidget(parent) +{ + m_nextColor = 0; + m_nextId = 1; + m_oldestId = -1; + m_oldestProbe = 0l; +// b_isPaused = false; + m_zoomLevel = 0.5; + m_pSimulator = Simulator::self(); + + horizontalScroll->setLineStep(32); + horizontalScroll->setPageStep( oscilloscopeView->width() ); + + connect( resetBtn, SIGNAL(clicked()), this, SLOT(reset()) ); + connect( zoomSlider, SIGNAL(valueChanged(int)), this, SLOT(slotZoomSliderChanged(int)) ); + connect( horizontalScroll, SIGNAL(valueChanged(int )), this, SLOT(slotSliderValueChanged(int )) ); + +// connect( pauseBtn, SIGNAL(clicked()), this, SLOT(slotTogglePause()) ); + + QTimer * updateScrollTmr = new QTimer(this); + connect( updateScrollTmr, SIGNAL(timeout()), this, SLOT(updateScrollbars()) ); + updateScrollTmr->start(20); + + KGlobal::config()->setGroup("Oscilloscope"); + setZoomLevel( KGlobal::config()->readDoubleNumEntry( "ZoomLevel", 0.5 ) ); + + connect( this, SIGNAL(probeRegistered(int, ProbeData *)), probePositioner, SLOT(slotProbeDataRegistered(int, ProbeData *)) ); + connect( this, SIGNAL(probeUnregistered(int )), probePositioner, SLOT(slotProbeDataUnregistered(int )) ); +} + + +Oscilloscope::~Oscilloscope() +{ +} + + +void Oscilloscope::slotTogglePause() +{ +// b_isPaused = !b_isPaused; +// pauseBtn->setText( b_isPaused ? i18n("Resume") : i18n("Pause") ); +// const ProbeDataMap::iterator end = m_probeDataMap.end(); +// for ( ProbeDataMap::iterator it = m_probeDataMap.begin(); it != end; ++it ) +// (*it)->setPaused(b_isPaused); +} + + +int Oscilloscope::sliderTicksPerSecond() const +{ + return int(1e4); +} + + +void Oscilloscope::setZoomLevel( double zoomLevel ) +{ + if ( zoomLevel < 0.0 ) + zoomLevel = 0.0; + + else if ( zoomLevel > 1.0 ) + zoomLevel = 1.0; + + KGlobal::config()->setGroup("Oscilloscope"); + KGlobal::config()->writeEntry( "ZoomLevel", zoomLevel ); + + // We want to maintain the position of the *center* of the view, not the + // left edge, so have to record time at center of view... We also have to + // handle the case where the scroll is at the end separately. + bool wasAtUpperEnd = horizontalScroll->maxValue() == horizontalScroll->value(); + int pageLength = int(oscilloscopeView->width()*sliderTicksPerSecond()/pixelsPerSecond()); + int at_ticks = horizontalScroll->value() + (pageLength/2); + + m_zoomLevel = zoomLevel; + zoomSlider->setValue( int((double(zoomSlider->maxValue())*zoomLevel)+0.5) ); + updateScrollbars(); + + // And restore the center position of the slider + if (!wasAtUpperEnd) + { + int pageLength = int(oscilloscopeView->width()*sliderTicksPerSecond()/pixelsPerSecond()); + horizontalScroll->setValue( at_ticks - (pageLength/2) ); + oscilloscopeView->updateView(); + } +} + + +void Oscilloscope::slotZoomSliderChanged( int value ) +{ + setZoomLevel( double(value)/double(zoomSlider->maxValue()) ); +} + + +ProbeData * Oscilloscope::registerProbe( Probe * probe ) +{ + if (!probe) + return 0l; + + const uint id = m_nextId++; + + ProbeData * probeData = 0l; + + if ( dynamic_cast(probe) ) + { + probeData = new LogicProbeData(id); + m_logicProbeDataMap[id] = static_cast(probeData); + } + + else + { + probeData = new FloatingProbeData(id); + m_floatingProbeDataMap[id] = static_cast(probeData); + } + + m_probeDataMap[id] = probeData; + + if (!m_oldestProbe) + { + m_oldestProbe = probeData; + m_oldestId = id; + } + + probeData->setColor( probeColors[m_nextColor] ); + m_nextColor = (m_nextColor+1)%9; +// probeData->setPaused(b_isPaused); + + emit probeRegistered( id, probeData ); + return probeData; +} + + +void Oscilloscope::unregisterProbe( int id ) +{ + ProbeDataMap::iterator it = m_probeDataMap.find(id); + + if ( it == m_probeDataMap.end() ) + return; + + m_logicProbeDataMap.remove(id); + m_floatingProbeDataMap.remove(id); + + bool oldestDestroyed = it.data() == m_oldestProbe; + + if ( it != m_probeDataMap.end() ) + m_probeDataMap.erase(it); + + if (oldestDestroyed) + getOldestProbe(); + + emit probeUnregistered(id); +} + + +ProbeData * Oscilloscope::probeData( int id ) const +{ + const ProbeDataMap::const_iterator bit = m_probeDataMap.find(id); + if ( bit != m_probeDataMap.end() ) + return bit.data(); + + return 0l; +} + + +int Oscilloscope::probeNumber( int id ) const +{ + const ProbeDataMap::const_iterator end = m_probeDataMap.end(); + int i=0; + for ( ProbeDataMap::const_iterator it = m_probeDataMap.begin(); it != end; ++it ) + { + if ( it.key() == id ) + return i; + i++; + } + return -1; +} + + +int Oscilloscope::numberOfProbes() const +{ + return m_probeDataMap.size(); +} + + +void Oscilloscope::getOldestProbe() +{ + if ( m_probeDataMap.isEmpty() ) + { + m_oldestProbe = 0l; + m_oldestId = -1; + return; + } + + m_oldestProbe = m_probeDataMap.begin().data(); + m_oldestId = m_probeDataMap.begin().key(); +} + + +void Oscilloscope::reset() +{ + const ProbeDataMap::iterator end = m_probeDataMap.end(); + for ( ProbeDataMap::iterator it = m_probeDataMap.begin(); it != end; ++it ) + (*it)->eraseData(); + + oscilloscopeView->updateView(); +} + + +void Oscilloscope::slotSliderValueChanged( int value ) +{ + Q_UNUSED(value); + oscilloscopeView->updateView(); +} + + +void Oscilloscope::updateScrollbars() +{ + bool wasAtUpperEnd = horizontalScroll->maxValue() == horizontalScroll->value(); + + const float pps = pixelsPerSecond(); + + int pageLength = int(oscilloscopeView->width()*sliderTicksPerSecond()/pps); + llong timeAsTicks = time()*sliderTicksPerSecond()/LOGIC_UPDATE_RATE; + llong upper = (timeAsTicks > pageLength) ? (timeAsTicks - pageLength) : 0; + horizontalScroll->setRange( 0, upper ); + + horizontalScroll->setPageStep( ullong(oscilloscopeView->width()*sliderTicksPerSecond()/pps) ); + + if (wasAtUpperEnd) + { + horizontalScroll->setValue( horizontalScroll->maxValue() ); + oscilloscopeView->updateView(); + } +} + + +ullong Oscilloscope::time() const +{ + if (!m_oldestProbe) + return 0; + + return ullong( m_pSimulator->time() - m_oldestProbe->resetTime() ); +} + + +llong Oscilloscope::scrollTime() const +{ +// if ( b_isPaused || numberOfProbes() == 0 ) +// return 0; + + if ( numberOfProbes() == 0 ) + return 0; + + if ( horizontalScroll->maxValue() == 0 ) + { + llong lengthAsTime = llong( oscilloscopeView->width() * LOGIC_UPDATE_RATE / pixelsPerSecond() ); + return m_pSimulator->time() - lengthAsTime; + } + + else + return llong( m_oldestProbe->resetTime() + (llong(horizontalScroll->value()) * LOGIC_UPDATE_RATE / sliderTicksPerSecond()) ); +} + + +double Oscilloscope::pixelsPerSecond() const +{ + return 2 * MIN_BITS_PER_S * std::pow( 2.0, m_zoomLevel * MIN_MAX_LOG_2_DIFF ); +} +//END Oscilloscope Class + + + +void addOscilloscopeAsToolView( KTechlab *ktechlab ) +{ + KateMDI::ToolView * tv; + tv = ktechlab->createToolView( Oscilloscope::toolViewIdentifier(), + KMultiTabBar::Bottom, + KGlobal::iconLoader()->loadIcon( "oscilloscope", KIcon::Small ), + i18n("Oscilloscope") ); + + Oscilloscope::self(tv); +} + + +ProbeData * registerProbe( Probe * probe ) +{ + return Oscilloscope::self()->registerProbe(probe); +} + + +void unregisterProbe( int id ) +{ + Oscilloscope::self()->unregisterProbe(id); +} + + +#include "oscilloscope.moc" diff --git a/src/gui/oscilloscope.h b/src/gui/oscilloscope.h new file mode 100644 index 0000000..79e0dbd --- /dev/null +++ b/src/gui/oscilloscope.h @@ -0,0 +1,192 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef OSCILLOSCOPE_H +#define OSCILLOSCOPE_H + +#ifndef PROBE_H +#ifndef KTECHLAB_H +#ifndef OSCILLOSCOPEDATA_H +#include "oscilloscopewidget.h" +#endif +#endif +#endif + +#include "simulator.h" +#include + +class FloatingProbeData; +class LogicProbe; +class LogicProbeData; +class KTechlab; +class Oscilloscope; +class Probe; +class ProbeData; +class VoltageProbe; +class QTimer; +namespace KateMDI { class ToolView; } + +typedef QMap< int, ProbeData * > ProbeDataMap; +typedef QMap< int, LogicProbeData * > LogicProbeDataMap; +typedef QMap< int, FloatingProbeData * > FloatingProbeDataMap; + +typedef unsigned long long ullong; +typedef long long llong; + + +#if 0 +const double MAX_BITS_PER_S = 100000; + +// NOTE: The 10 has to agree with the 2^10 = 1024.0 +const int MIN_MAX_LOG_2_DIFF = 10; +const double MIN_BITS_PER_S = MAX_BITS_PER_S / 1024.0; +#else +const double MAX_BITS_PER_S = LOGIC_UPDATE_RATE * 4; + +// NOTE: The 18 has to agree with the 2^18 = 262144.0 +const int MIN_MAX_LOG_2_DIFF = 18; +const double MIN_BITS_PER_S = MAX_BITS_PER_S / 262144.0; +#endif + + +/* +Due to strangeness with generation of .[cpp/h] files from .ui files (that is, +my inability to sort it out neatly), files other than those in /src/gui can't +see header files such as "oscilloscopewidget.h", so we have to provide some +interface functions for accessing the functionality in this class +*/ +ProbeData * registerProbe( Probe * probe ); +void unregisterProbe( int id ); +void addOscilloscopeAsToolView( KTechlab *ktechlab ); + + +#ifndef PROBE_H +#ifndef KTECHLAB_H +#ifndef OSCILLOSCOPEDATA_H +/** +@author David Saxton +*/ +class Oscilloscope : public OscilloscopeWidget +{ + Q_OBJECT + public: + static Oscilloscope * self( KateMDI::ToolView * parent = 0l ); + static QString toolViewIdentifier() { return "Oscilloscope"; } + virtual ~Oscilloscope(); + + /** + * Register a probe (that outputs boolean data) with the oscilloscope. + * Returns a unique id that the probe can use to add data points + */ + ProbeData * registerProbe( Probe * probe ); + void unregisterProbe( int id ); + /** + * Returns the Simulator time since recording started. + */ + ullong time() const; + /** + * Returns how much of an increment in value of the oscilloscope slider + * is equivalent to one second. + */ + int sliderTicksPerSecond() const; + /** + * Returns the number of pixels per second the user has requested to be + * displayed. + */ + double pixelsPerSecond() const; + /** + * Zoom level; a value between 0 and 1. 0 is maximum zoom out, and 1 is + * maximum zoom in. + */ + double zoomLevel() const { return m_zoomLevel; } + /** + * Sets the zoom level (and in the process, checks that it is within the + * bounds allowed). + */ + void setZoomLevel( double zoomLevel ); + /** + * Returns the Simulator time as given by the current scrollbar + * position. + */ + llong scrollTime() const; + /** + * @returns pointer to probe with given id, or NULL if no such probe exists + */ + ProbeData * probeData( int id ) const; + /** + * @returns the total number of probes + */ + int numberOfProbes() const; + /** + * @returns number of the probe with the given id, starting from 0, or -1 if no such probe + */ + int probeNumber( int id ) const; + + signals: + /** + * Emitted when a probe is registered + */ + void probeRegistered( int id, ProbeData * probe ); + /** + * Emitted when a probe is unregistered + */ + void probeUnregistered( int id ); + + public slots: + /** + * Resets all recorded data + */ + void reset(); + /** + * Called when the zoom slider value was changed. + */ + void slotZoomSliderChanged( int value ); + /** + * Called when the horizontal scrollbar was scrolled by the user + */ + void slotSliderValueChanged( int value ); + /** + * Pause the data capture (e.g. user clicked on pause button) + */ + void slotTogglePause(); + + protected: + void getOldestProbe(); + +// bool b_isPaused; + int m_nextId; + ProbeData * m_oldestProbe; + int m_oldestId; + int m_nextColor; // For giving the probes colours + + ProbeDataMap m_probeDataMap; + LogicProbeDataMap m_logicProbeDataMap; + FloatingProbeDataMap m_floatingProbeDataMap; + + Simulator * m_pSimulator; + + protected slots: + void updateScrollbars(); + + private: + Oscilloscope( KateMDI::ToolView * parent ); + + static Oscilloscope * m_pSelf; + double m_zoomLevel; + + friend class OscilloscopeView; + friend class ProbePositioner; +}; + +#endif // OSCILLOSCOPEDATA_H +#endif // KTECHLAB_H +#endif // PROBE_H + +#endif // OSCILLOSCOPE_H diff --git a/src/gui/oscilloscopeview.cpp b/src/gui/oscilloscopeview.cpp new file mode 100644 index 0000000..3d2a40a --- /dev/null +++ b/src/gui/oscilloscopeview.cpp @@ -0,0 +1,431 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "oscilloscope.h" +#include "oscilloscopedata.h" +#include "oscilloscopeview.h" +#include "probepositioner.h" +#include "simulator.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +inline ullong min( ullong a, ullong b ) +{ + return a < b ? a : b; +} + + +OscilloscopeView::OscilloscopeView( QWidget *parent, const char *name ) + : QFrame( parent, name, WNoAutoErase ), + b_needRedraw(true), + m_pixmap(0l), + m_fps(10), + m_sliderValueAtClick(-1), + m_clickOffsetPos(-1), + m_pSimulator( Simulator::self() ), + m_halfOutputHeight(0.0) +{ + KGlobal::config()->setGroup("Oscilloscope"); + m_fps = KGlobal::config()->readNumEntry( "FPS", 25 ); + + setBackgroundMode(NoBackground); + setMouseTracking(true); + + m_updateViewTmr = new QTimer(this); + connect( m_updateViewTmr, SIGNAL(timeout()), this, SLOT(updateViewTimeout()) ); +} + + +OscilloscopeView::~OscilloscopeView() +{ + delete m_pixmap; + m_pixmap = 0l; +} + + +void OscilloscopeView::updateView() +{ + if (m_updateViewTmr->isActive() ) + return; + + m_updateViewTmr->start( 1000/m_fps, true ); +} + + +void OscilloscopeView::updateViewTimeout() +{ + b_needRedraw = true; + repaint(false); + updateTimeLabel(); +} + + +void OscilloscopeView::updateTimeLabel() +{ + if ( hasMouse() ) + { + int x = mapFromGlobal( QCursor::pos() ).x(); + double time = (double(Oscilloscope::self()->scrollTime()) / LOGIC_UPDATE_RATE) + (x / Oscilloscope::self()->pixelsPerSecond()); + Oscilloscope::self()->timeLabel->setText( QString::number( time, 'f', 6 ) ); + } + + else + Oscilloscope::self()->timeLabel->setText( QString::null ); +} + + +void OscilloscopeView::resizeEvent( QResizeEvent *e ) +{ + delete m_pixmap; + m_pixmap = new QPixmap( e->size() ); + b_needRedraw = true; + QFrame::resizeEvent(e); +} + + +void OscilloscopeView::mousePressEvent( QMouseEvent *event ) +{ + switch ( event->button() ) + { + case Qt::LeftButton: + { + event->accept(); + m_clickOffsetPos = event->pos().x(); + m_sliderValueAtClick = Oscilloscope::self()->horizontalScroll->value(); + setCursor( Qt::SizeAllCursor ); + return; + } + + case Qt::RightButton: + { + event->accept(); + + KPopupMenu fpsMenu; + fpsMenu.insertTitle( i18n("Framerate") ); + + const int fps[] = { 10, 25, 50, 75, 100 }; + + for ( uint i=0; i<5; ++i ) + { + const int num = fps[i]; + fpsMenu.insertItem( i18n("%1 fps").arg(num), num ); + fpsMenu.setItemChecked( num, num == m_fps ); + } + + connect( &fpsMenu, SIGNAL(activated(int )), this, SLOT(slotSetFrameRate(int )) ); + fpsMenu.exec( event->globalPos() ); + return; + } + + default: + { + QFrame::mousePressEvent(event); + return; + } + } +} + + +void OscilloscopeView::mouseMoveEvent( QMouseEvent *event ) +{ + event->accept(); + updateTimeLabel(); + + if ( m_sliderValueAtClick != -1 ) + { + int dx = event->pos().x() - m_clickOffsetPos; + int dTick = int( dx * Oscilloscope::self()->sliderTicksPerSecond() / Oscilloscope::self()->pixelsPerSecond() ); + Oscilloscope::self()->horizontalScroll->setValue( m_sliderValueAtClick - dTick ); + } +} + + +void OscilloscopeView::mouseReleaseEvent( QMouseEvent *event ) +{ + if ( m_sliderValueAtClick == -1 ) + return QFrame::mouseReleaseEvent(event); + + event->accept(); + m_sliderValueAtClick = -1; + setCursor( Qt::ArrowCursor ); +} + + +void OscilloscopeView::slotSetFrameRate( int fps ) +{ + m_fps = fps; + KGlobal::config()->setGroup("Oscilloscope"); + KGlobal::config()->writeEntry( "FPS", m_fps ); +} + + +// returns a % b +static double lld_modulus( llong a, double b ) +{ + return double(a) - llong(a/b)*b; +} + + +void OscilloscopeView::paintEvent( QPaintEvent *e ) +{ + QRect r = e->rect(); + + if (b_needRedraw) + { + updateOutputHeight(); + const double pixelsPerSecond = Oscilloscope::self()->pixelsPerSecond(); + + QPainter p; + m_pixmap->fill( paletteBackgroundColor() ); + p.begin(m_pixmap); + p.setClipRegion(e->region()); + + //BEGIN Draw vertical marker lines + const double divisions = 5.0; + const double min_sep = 10.0; + + double spacing = pixelsPerSecond/(std::pow( divisions, std::floor(std::log(pixelsPerSecond/min_sep)/std::log(divisions)) )); + + // Pixels offset is the number of pixels that the view is scrolled along + const llong pixelsOffset = llong(Oscilloscope::self()->scrollTime()*pixelsPerSecond/LOGIC_UPDATE_RATE); + double linesOffset = - lld_modulus( pixelsOffset, spacing ); + + int blackness = 256 - int(184.0 * spacing / (min_sep*divisions*divisions)); + p.setPen( QColor( blackness, blackness, blackness ) ); + + for ( double i = linesOffset; i <= frameRect().width(); i += spacing ) + p.drawLine( int(i), 1, int(i), frameRect().height()-2 ); + + + + spacing *= divisions; + linesOffset = - lld_modulus( pixelsOffset, spacing ); + + blackness = 256 - int(184.0 * spacing / (min_sep*divisions*divisions)); + p.setPen( QColor( blackness, blackness, blackness ) ); + + for ( double i = linesOffset; i <= frameRect().width(); i += spacing ) + p.drawLine( int(i), 1, int(i), frameRect().height()-2 ); + + + + spacing *= divisions; + linesOffset = - lld_modulus( pixelsOffset, spacing ); + + blackness = 256 - int(184.0); + p.setPen( QColor( blackness, blackness, blackness ) ); + + for ( double i = linesOffset; i <= frameRect().width(); i += spacing ) + p.drawLine( int(i), 1, int(i), frameRect().height()-2 ); + //END Draw vertical marker lines + + drawLogicData(p); + drawFloatingData(p); + + p.setPen(Qt::black); + p.drawRect( frameRect() ); + + b_needRedraw = false; + } + + bitBlt( this, r.x(), r.y(), m_pixmap, r.x(), r.y(), r.width(), r.height() ); +} + + +void OscilloscopeView::updateOutputHeight() +{ + m_halfOutputHeight = int((Oscilloscope::self()->probePositioner->probeOutputHeight() - (probeArrowWidth/Oscilloscope::self()->numberOfProbes()))/2)-1; +} + + +void OscilloscopeView::drawLogicData( QPainter & p ) +{ + const double pixelsPerSecond = Oscilloscope::self()->pixelsPerSecond(); + + const LogicProbeDataMap::iterator end = Oscilloscope::self()->m_logicProbeDataMap.end(); + for ( LogicProbeDataMap::iterator it = Oscilloscope::self()->m_logicProbeDataMap.begin(); it != end; ++it ) + { + // When searching for the next logic value to display, we look along + // until there is a recorded point which is at least one pixel along + // If we are zoomed out far, there might be thousands of data points + // between each pixel. It is time consuming searching for the next point + // to display one at a time, so we record the average number of data points + // between pixels ( = deltaAt / totalDeltaAt ) + llong deltaAt = 1; + int totalDeltaAt = 1; + + LogicProbeData * probe = it.data(); + StoredData * data = &(probe->m_data); + + if ( data->allocatedUpTo() == 0 ) + continue; + + const int midHeight = Oscilloscope::self()->probePositioner->probePosition(probe); + const llong timeOffset = Oscilloscope::self()->scrollTime(); + + // Draw the horizontal line indicating the midpoint of our output + p.setPen( QColor( 228, 228, 228 ) ); + p.drawLine( 0, midHeight, width(), midHeight ); + + // Set the pen colour according to the colour the user has selected for the probe + p.setPen( probe->color() ); + + // The smallest time step that will display in our oscilloscope + const int minTimeStep = int(LOGIC_UPDATE_RATE/pixelsPerSecond); + + llong at = probe->findPos(timeOffset); + const llong maxAt = probe->insertPos(); + llong prevTime = data->dataAt(at).time; + int prevX = (at > 0) ? 0 : int((prevTime - timeOffset)*(pixelsPerSecond/LOGIC_UPDATE_RATE)); + bool prevHigh = data->dataAt(at).value; + int prevY = midHeight + int(prevHigh ? -m_halfOutputHeight : +m_halfOutputHeight); + while ( at < maxAt ) + { + // Search for the next pos which will show up at our zoom level + llong previousAt = at; + llong dAt = deltaAt / totalDeltaAt; + + while ( (dAt > 1) && (at < maxAt) && ( (llong(data->dataAt(at).time) - prevTime) != minTimeStep ) ) + { + // Search forwards until we overshoot + while ( at < maxAt && ( llong(data->dataAt(at).time) - prevTime ) < minTimeStep ) + at += dAt; + dAt /= 2; + + // Search backwards until we undershoot + while ( (at < maxAt) && ( llong(data->dataAt(at).time) - prevTime ) > minTimeStep ) + { + at -= dAt; + if ( at < 0 ) + at = 0; + } + dAt /= 2; + } + + // Possibly increment the value of at found by one (or more if this is the first go) + while ( (previousAt == at) || ((at < maxAt) && ( llong(data->dataAt(at).time) - prevTime ) < minTimeStep) ) + at++; + + if ( at >= maxAt ) + break; + + // Update the average values + deltaAt += at - previousAt; + totalDeltaAt++; + + bool nextHigh = data->dataAt(at).value; + if ( nextHigh == prevHigh ) + continue; + llong nextTime = data->dataAt(at).time; + int nextX = int((nextTime - timeOffset)*(pixelsPerSecond/LOGIC_UPDATE_RATE)); + int nextY = midHeight + int(nextHigh ? -m_halfOutputHeight : +m_halfOutputHeight); + + p.drawLine( prevX, prevY, nextX, prevY ); + p.drawLine( nextX, prevY, nextX, nextY ); + + prevHigh = nextHigh; + prevTime = nextTime; + prevX = nextX; + prevY = nextY; + + if ( nextX > width() ) + break; + }; + + // If we could not draw right to the end; it is because we exceeded + // maxAt + if ( prevX < width() ) + p.drawLine( prevX, prevY, width(), prevY ); + } +} + + +#define v_to_y int(midHeight - (logarithmic ? ( (v>0) ? log(v/lowerAbsValue) : -log(-v/lowerAbsValue) ) : v) * sf) + + +void OscilloscopeView::drawFloatingData( QPainter & p ) +{ + const double pixelsPerSecond = Oscilloscope::self()->pixelsPerSecond(); + + const FloatingProbeDataMap::iterator end = Oscilloscope::self()->m_floatingProbeDataMap.end(); + for ( FloatingProbeDataMap::iterator it = Oscilloscope::self()->m_floatingProbeDataMap.begin(); it != end; ++it ) + { + FloatingProbeData * probe = it.data(); + StoredData * data = &(probe->m_data); + + if ( data->allocatedUpTo() == 0 ) + continue; + + bool logarithmic = probe->scaling() == FloatingProbeData::Logarithmic; + double lowerAbsValue = probe->lowerAbsValue(); + double sf = m_halfOutputHeight / (logarithmic ? log(probe->upperAbsValue()/lowerAbsValue) : probe->upperAbsValue()); + + const int midHeight = Oscilloscope::self()->probePositioner->probePosition(probe); + const llong timeOffset = Oscilloscope::self()->scrollTime(); + + // Draw the horizontal line indicating the midpoint of our output + p.setPen( QColor( 228, 228, 228 ) ); + p.drawLine( 0, midHeight, width(), midHeight ); + + // Set the pen colour according to the colour the user has selected for the probe + p.setPen( probe->color() ); + + llong at = probe->findPos(timeOffset); + const llong maxAt = probe->insertPos(); + llong prevTime = probe->toTime(at); + + double v = data->dataAt((at>0)?at:0); + int prevY = v_to_y; + int prevX = int((prevTime - timeOffset)*(pixelsPerSecond/LOGIC_UPDATE_RATE)); + + while ( at < maxAt-1 ) + { + at++; + + ullong nextTime = prevTime + ullong(LOGIC_UPDATE_RATE/LINEAR_UPDATE_RATE); + + double v = data->dataAt((at>0)?at:0); + int nextY = v_to_y; + int nextX = int((nextTime - timeOffset)*(pixelsPerSecond/LOGIC_UPDATE_RATE)); + + p.drawLine( prevX, prevY, nextX, nextY ); + + prevTime = nextTime; + prevX = nextX; + prevY = nextY; + + if ( nextX > width() ) + break; + }; + + // If we could not draw right to the end; it is because we exceeded + // maxAt + if ( prevX < width() ) + p.drawLine( prevX, prevY, width(), prevY ); + } +} + + +#include "oscilloscopeview.moc" diff --git a/src/gui/oscilloscopeview.h b/src/gui/oscilloscopeview.h new file mode 100644 index 0000000..97cb595 --- /dev/null +++ b/src/gui/oscilloscopeview.h @@ -0,0 +1,65 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef OSCILLOSCOPEVIEW_H +#define OSCILLOSCOPEVIEW_H + +#include + +class Oscilloscope; +class Simulator; +class QMouseEvent; +class QPaintEvent; +class QPixmap; +class QTimer; + +/** +@author David Saxton +*/ +class OscilloscopeView : public QFrame +{ + Q_OBJECT + public: + OscilloscopeView( QWidget *parent, const char *name = 0 ); + virtual ~OscilloscopeView(); + + public slots: + /** + * Sets the needRedraw flag to true, and then class repaint + */ + void updateView(); + void slotSetFrameRate( int fps ); + + protected slots: + void updateViewTimeout(); + + protected: + virtual void mousePressEvent( QMouseEvent *event ); + virtual void mouseMoveEvent( QMouseEvent *event ); + virtual void mouseReleaseEvent( QMouseEvent *event ); + virtual void paintEvent( QPaintEvent *event ); + virtual void resizeEvent( QResizeEvent *event ); + + void drawLogicData( QPainter & p ); + void drawFloatingData( QPainter & p ); + void updateOutputHeight(); + void updateTimeLabel(); + + bool b_needRedraw; + QPixmap *m_pixmap; + QTimer *m_updateViewTmr; + int m_fps; + int m_sliderValueAtClick; + int m_clickOffsetPos; + Simulator * m_pSimulator; + double m_halfOutputHeight; +}; + +#endif diff --git a/src/gui/oscilloscopewidget.ui b/src/gui/oscilloscopewidget.ui new file mode 100644 index 0000000..eb8002b --- /dev/null +++ b/src/gui/oscilloscopewidget.ui @@ -0,0 +1,289 @@ + +OscilloscopeWidget + + + OscilloscopeWidget + + + + 0 + 0 + 563 + 195 + + + + Form1 + + + + unnamed + + + 0 + + + 0 + + + + layout7 + + + + unnamed + + + 0 + + + + oscilloscopeView + + + + 3 + 3 + 0 + 0 + + + + + 0 + 0 + 0 + + + + + 255 + 255 + 255 + + + + + + probePositioner + + + + 16 + 0 + + + + + 16 + 32767 + + + + + + horizontalScroll + + + Horizontal + + + + + + + layout9 + + + + unnamed + + + 0 + + + 0 + + + + textLabel1 + + + Zoom + + + AlignCenter + + + + + zoomSlider + + + + 4 + 0 + 0 + 0 + + + + 1000 + + + 10 + + + 50 + + + Horizontal + + + + + spacer1 + + + Vertical + + + MinimumExpanding + + + + 20 + 30 + + + + + + timeLabel + + + + + + AlignCenter + + + + + spacer1_2 + + + Vertical + + + Fixed + + + + 20 + 6 + + + + + + resetBtn + + + + 1 + 1 + 0 + 0 + + + + Reset + + + + + + + + + + spacer2_3 + + + Horizontal + + + Fixed + + + + 6 + 6 + + + + + + spacer2_2 + + + Vertical + + + Fixed + + + + 6 + 6 + + + + + + + + OscilloscopeView +
    oscilloscopeview.h
    + + -1 + -1 + + 0 + + 1 + 3 + 0 + 0 + + image0 +
    + + ProbePositioner +
    probepositioner.h
    + + 14 + -1 + + 0 + + 0 + 5 + 0 + 0 + + image0 +
    +
    + + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000042c49444154388db5954f6c14551cc73fefcd7476b65bdaae4bb78bb5502a14d404e4801c88182d1c4c2c693da847400f9c24c68b878684238660e2b1e01f12c19493012ef2478c814412d354a46017a8a564bb6da5bbedccee767776e63d0ffb073751d483bfe49799974c3eeffb7ebf37df9fd05a530b2184040cc0042420aaf9a4d0d554800f045a6b256ae0e1e1e1d6bebebe838ee31c48a7d39b5cd7fd075e251cc7617272f2ded8d8d819cff33e0316819259537aead4a9839d5dd6d1784f91f55b0a94830242088404d304292bef68a89f520802a598fecddaa04f1a876f5c250c7c0a64cdeac686e33807e23d45e6b297c8b877f1831542614550b6599835c83c2a81b6786a75134faf2f1169f12997350881d9021d0903e06de0745d3160a6d3e94dbd5b0a64dcbb94b5831d0e3375ab892b1772dcf9790528543f8dd0d367b36768153b5e31503a0f1aecb004580b44ffac58baae8b1714f0833c7638cc8dab303a320f4822ab4c7a37c69196203de3319d5ce1c4d13c733331dedc67a129a154fd128401ab0616d55a130ac3d42d93d1913940d13fd0c9ee0183685c60da01c5421bd72f7a8c8efccef9afd374267ad93d642365be0636a0d28ec7600941d9e6f23917f0e97f23ce5bef35d19ec863da0ed9059b2be70bec196c66dfa10ec0e49b338f7017258651bf95021035c595429bb0903248fe52a2b5b595dd7b4d945cc2340cdca536be389ee3f67886c5798f773fe8e0dac508c989659277a2180da4ca4ff07821058b8b251445d63d6b13ed1098a6417e39cac85197dbe31962ab9bd9f1f22a226d45366f6d0620fdb08c900d281af6110284b20085b414861d905d88f2e52739ee8cbb8022143259d3dd84691730aa2d52da441a8de0c6958068870022a41e9629ad3473fd3b8fdbe319dadb9b4924da994d2d716c7896fbe35152f78b48245d6b2da4507faf582be8eaf159b721cc837b05ae7debb1f79d08cb8b515edad942a22bc4b1c33eb3d34b1c797f06af90a72d16e2f96d9a74aa11dca8586b222d01af0fb60070f6c402d72f15d97f28c6f6d7027a5f5ce6c3233dc4e2ede496b278be4fff608cee8d3e1add806aeca51094cbb06397c1ecc328e746537c7e3ccdb5cb1136bf60635882d4d41c6ec6836ab37efa214f72208ed9f4d7cdd38ee310280542e38b1c43fb6de26b3672e1ec3cc99bcb246f66a938a3241ab3e91f7c861fbf77710b1e5e49915bae974203ba0e9e9c9cbc373d6d6d305a040a89c2a77f50b27d5782bbbf7acccf28349235dd16cf6dd374f7295e1de8a45c02d37499182b01cc0201a085d61a2144d8b2ac8fb6ed340e77240c4261890e04c250185262546d534a032154b59e0ad394e41c98182bf268ce6721ed9f064e0253356f6da2e24c1f030f783c15fe6da680af8021602bd051532ca9b8521488559f61aa86c29343578fbf0264a94c906c7d3409214c20043457a116ff6de6795578012889ff6b98fe016ea0ce1c6a2573410000000049454e44ae426082 + + + + + oscilloscopeview.h + probepositioner.h + +
    diff --git a/src/gui/outputmethoddlg.cpp b/src/gui/outputmethoddlg.cpp new file mode 100644 index 0000000..bcb189e --- /dev/null +++ b/src/gui/outputmethoddlg.cpp @@ -0,0 +1,162 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "docmanager.h" +#include "filemetainfo.h" +#include "textdocument.h" +#include "outputmethodwidget.h" +#include "outputmethoddlg.h" +#include "microlibrary.h" +#include "microselectwidget.h" +#include "projectmanager.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + + +//BEGIN class OutputMethodInfo +OutputMethodInfo::OutputMethodInfo() +{ + m_method = Method::Direct; + m_bAddToProject = false; +} + + +void OutputMethodInfo::initialize( OutputMethodDlg * dlg ) +{ + if ( dlg->m_widget->displayDirectCheck->isChecked() ) + { + m_method = Method::Direct; + KTempFile f( QString::null, dlg->m_outputExtension ); + f.close(); + m_outputFile = f.name(); + m_bAddToProject = false; + } + + else + { + if ( dlg->m_widget->loadFileCheck->isChecked() ) + m_method = Method::SaveAndLoad; + + else + m_method = Method::SaveAndForget; + + m_outputFile = dlg->m_widget->outputFileURL->url(); + m_bAddToProject = dlg->m_widget->addToProjectCheck->isChecked(); + } + + m_picID = dlg->m_widget->m_pMicroSelect->micro(); +} +//END class OutputMethodInfo + + + +//BEGIN class OutputMethodDlg +OutputMethodDlg::OutputMethodDlg( const QString &caption, const KURL & inputURL, bool showPICSelect, QWidget *parent, const char *name ) + : KDialogBase( parent, name, true, caption, Ok|Cancel ) +{ + m_inputURL = inputURL; + m_bAccepted = false; + m_widget = new OutputMethodWidget(this); + + m_widget->addToProjectCheck->setEnabled( ProjectManager::self()->currentProject() ); + + if (!showPICSelect) + { + m_widget->m_pMicroSelect->hide(); + m_widget->adjustSize(); + } + + fileMetaInfo()->initializeFromMetaInfo( m_inputURL, this ); + + setMainWidget(m_widget); +} + + +OutputMethodDlg::~OutputMethodDlg() +{ +} + + +void OutputMethodDlg::setOutputExtension( const QString & extension ) +{ + m_outputExtension = extension; +} + + +void OutputMethodDlg::setFilter( const QString &filter ) +{ + m_widget->outputFileURL->setFilter(filter); +} + + +void OutputMethodDlg::setMethod( OutputMethodInfo::Method::Type m ) +{ + switch (m) + { + case OutputMethodInfo::Method::Direct: + m_widget->displayDirectCheck->setChecked(true); + break; + + case OutputMethodInfo::Method::SaveAndForget: + m_widget->saveFileCheck->setChecked(true); + m_widget->loadFileCheck->setChecked(false); + break; + + case OutputMethodInfo::Method::SaveAndLoad: + m_widget->saveFileCheck->setChecked(true); + m_widget->loadFileCheck->setChecked(true); + break; + }; +} + + +void OutputMethodDlg::setPicID( const QString & id ) +{ + m_widget->m_pMicroSelect->setMicro(id); +} + + +void OutputMethodDlg::setOutputFile( const KURL & out ) +{ + m_widget->outputFileURL->setURL(out.prettyURL()); +} + + +void OutputMethodDlg::accept() +{ + m_bAccepted = true; + m_outputMethodInfo.initialize(this); + fileMetaInfo()->grabMetaInfo( m_inputURL, this ); + hide(); +} + + +void OutputMethodDlg::reject() +{ + m_bAccepted = false; +} + + +MicroSelectWidget * OutputMethodDlg::microSelect() const +{ + return m_widget->m_pMicroSelect; +} +//END class OutputMethodDlg + + +#include "outputmethoddlg.moc" diff --git a/src/gui/outputmethoddlg.h b/src/gui/outputmethoddlg.h new file mode 100644 index 0000000..14dff25 --- /dev/null +++ b/src/gui/outputmethoddlg.h @@ -0,0 +1,98 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef OUTPUTMETHODDLG_H +#define OUTPUTMETHODDLG_H + +#include +#include + +class TextDocument; +class KTechlab; +class MicroSelectWidget; +class OutputMethodDlg; +class OutputMethodWidget; + +class OutputMethodInfo +{ + public: + class Method + { + public: + enum Type + { + Direct, + SaveAndForget, + SaveAndLoad + }; + }; + + OutputMethodInfo(); + void initialize( OutputMethodDlg * dlg ); + + Method::Type method() const { return m_method; } + void setMethod( Method::Type method ) { m_method = method; } + + bool addToProject() const { return m_bAddToProject; } + void setAddToProject( bool add ) { m_bAddToProject = add; } + + QString picID() const { return m_picID; } + void setPicID( const QString & id ) { m_picID = id; } + + KURL outputFile() const { return m_outputFile; } + void setOutputFile( const KURL & outputFile ) { m_outputFile = outputFile; } + + protected: + Method::Type m_method; + bool m_bAddToProject; + QString m_picID; + KURL m_outputFile; +}; + +/** +@author David Saxton +*/ +class OutputMethodDlg : public KDialogBase +{ + Q_OBJECT + public: + /** + * @param Caption The caption of the dialog window + * @param inputURL Used for saving/restoring previous options the user has selected for this file; set this to null if temporary file + * @param showPICSelect Whether to show the combo boxes for selecting a PIC + */ + OutputMethodDlg( const QString & caption, const KURL & inputURL, bool showPICSelect = false, QWidget *parent = 0, const char *name = 0); + ~OutputMethodDlg(); + + void setOutputExtension( const QString & outputExtension ); + void setFilter( const QString &filter ); + void setMethod( OutputMethodInfo::Method::Type m ); + void setOutputFile( const KURL & out ); + void setPicID( const QString & id ); + + virtual void reject(); + virtual void accept(); + bool isAccepted() const { return m_bAccepted; } + + OutputMethodInfo info() const { return m_outputMethodInfo; } + + MicroSelectWidget * microSelect() const; + + protected: + OutputMethodWidget *m_widget; + QString m_outputExtension; + KURL m_inputURL; + OutputMethodInfo m_outputMethodInfo; + bool m_bAccepted; + + friend class OutputMethodInfo; +}; + +#endif diff --git a/src/gui/outputmethodwidget.ui b/src/gui/outputmethodwidget.ui new file mode 100644 index 0000000..0182105 --- /dev/null +++ b/src/gui/outputmethodwidget.ui @@ -0,0 +1,182 @@ + +OutputMethodWidget + + + OutputMethodWidget + + + + 0 + 0 + 450 + 208 + + + + + 5 + 5 + 0 + 0 + + + + + 450 + 0 + + + + Output Method + + + + unnamed + + + 0 + + + + buttonGroup2 + + + Output Method + + + false + + + + unnamed + + + + displayDirectCheck + + + Displa&y directly + + + true + + + + + saveFileCheck + + + Save to file + + + false + + + + + groupBox16 + + + false + + + Output File Options + + + + unnamed + + + + outputFileURL + + + + + loadFileCheck + + + Load File in &New View + + + + + addToProjectCheck + + + &Add to Project + + + + + + + + + m_pMicroSelect + + + + 0 + 0 + + + + + + spacer14 + + + Vertical + + + Expanding + + + + 20 + 0 + + + + + + + + MicroSelectWidget +
    microselectwidget.h
    + + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image0 +
    +
    + + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000042949444154388db5954d6c545514c77ff7de37eff1a6a550da994e5ba798868f948fc847a2a2911816c436b0a02ed0083161a1981877ee10d90aa94656063491882c5cd4c4b8103f20cd806909a98604da8482341de80cb69de9bcd799799d79efba980f1da3a80b4f727273939bdff99f9b93f3175a6b6a21849080020c4002a29a8f0a5dcd002803bed63a1035f0d0d0504b6f6fef51d7758fa4d3e98d8ee3fc03af128ee3303939399548242eb8aefb09300f78464de9f0f0f0d148cc7caf3d5424de97a7ec17104220242805520a44557bbd4b21f083801d33e63a6d1bc7bf19c6064e0319a35a58b9ae7ba43d54e4d7c54b64dc097c7f09d30ef04b36736983cc7c11b4456b9b492c5e20dc54a6540e00896a8268a7017010f8bcae1830d2e9f4c69ebe3c197782b2ce60d94ddc9b30f9feeb45ae5d7181c5ead35636ef08d3ffe26a76ee3208b4031a56d80aa00768fda362e9380e25bf80ef3b587613d7afc099533380a4b5dda46fcb5aa42998b9eb7173dce5e6788e434763ec7fc942532008ea436003660d2caa7f8d69c3bd8910674e4d033e83877ad8d36fb0aa4d6058658ac5358c5df6383bf480f31fdda5a3632bbbfb6da4ccd5c00a10b2012cc12fd97cfb5516f0187c25cee0619396480ec3ca909d0f3372d1e5f9fe66de3ad605587c712ec55256a2540d5519d19ae24a29057329839f7ecc138944d833102290f3184ae1e6d6f0e98739c61229e6d21eafbed1c9c8c5558c8f3ee4ceed76946a1c43d97091828585223e2eebfbc295f60d45de89707628cb58224577bc85a79e5d4d786581cddb9b0148259711b20145836221400416e0232d1f6595c9ce4538773ac7b54406f0b15784e8e80aa1ac2594190220d021e49f2437960156b70ba095e95f96f18acd8c263cc6122962b1167a7ba34cdd7ec8c977a699bed546722a8fc2a02b6e2185fff78ab586ce78894ddb9ab9f5738ed14b1e030756929d8ff2e4ae5544632b38f96e89a99b298ebd6950cc2d12ed0eb3618b26f520788462ad09877df60db600f0f1fb49c646f21c7ebd836dcf94e9d9b4c0db27d6d3bd36c6426a96bce731703046d7da129a4670836284a054869d4f1b1c7e2dca67676ef3c1898091ef5ad8bc358c3205c93bf7c9a40ad4c660f4728edd7bbb3142ea2fc1da711cfc200011e08b45f6bd1c261adbce9717928c5f9d63fc6a19f0014567773303073790f8214bd6f5282dfbb8b9fa1f6b40d7c1939393533b92e63ad9240990484aec7e41b27d579cbb531e0f67023492d86316ebb768ba1e0f786e6f37e56550c62237aee7011e54abd7c1412291b8a06de378b4d3c0b215da9708e5a3a442192085404a83d4accfecac067c0c43e13a70e3fa12e96409e0325000966bbb354465339d04a6f9dd15fe6dde07ce030780278088d05ad72cc9a6b2f2daaaa74d75a1f0e8d0d5f60b40868a8364ead6248430000b0857a126ffcdf396abf03ce089ffcb4c7f033046c6b4a995e7a00000000049454e44ae426082 + + + + + saveFileCheck + toggled(bool) + groupBox16 + setEnabled(bool) + + + + + kurlrequester.h + klineedit.h + kpushbutton.h + microselectwidget.h + +
    diff --git a/src/gui/picprogrammerconfigwidget.ui b/src/gui/picprogrammerconfigwidget.ui new file mode 100644 index 0000000..64c5ac8 --- /dev/null +++ b/src/gui/picprogrammerconfigwidget.ui @@ -0,0 +1,285 @@ + +PicProgrammerConfigWidget + + + PicProgrammerConfigWidget + + + + 0 + 0 + 464 + 493 + + + + PIC Programmer Config + + + + unnamed + + + 0 + + + + groupBox3 + + + Programmer Configuration + + + + unnamed + + + + spacer3 + + + Horizontal + + + Expanding + + + + 295 + 20 + + + + + + addButton + + + &Add ... + + + Alt+A + + + + + removeButton + + + Re&move + + + Alt+M + + + + + textLabel1_3 + + + Program: + + + + + kcfg_PicProgrammerProgram + + + + 1 + 0 + 1 + 0 + + + + false + + + + + m_pProgrammerDescription + + + (Program Description) + + + + + + + commandsGroupBox + + + Commands + + + + unnamed + + + + textLabel1_2 + + + Initialization: + + + + + verifyCommand + + + + + writeCommand + + + + + readCommand + + + + + initCommand + + + + + textLabel4 + + + Read: + + + + + textLabel3 + + + Write: + + + + + blankCheckCommand + + + + + eraseCommand + + + + + textLabel2 + + + The following strings will be replaced when the command is run: +<ul> +<li><b>%port</b> - Port that the programmer is connected to</li> +<li><b>%device</b> - PIC device</li> +<li><b>%file</b> - File to read from or write to</li> +</ul> + + + RichText + + + + + textLabel5 + + + Erase: + + + + + textLabel2_3 + + + Verify: + + + + + textLabel1_4 + + + Blank Check: + + + + + + + layout5 + + + + unnamed + + + + textLabel1 + + + Default port: + + + + + kcfg_PicProgrammerPort + + + true + + + + + + + spacer2 + + + Vertical + + + Expanding + + + + 20 + 16 + + + + + + + kcfg_PicProgrammerProgram + addButton + removeButton + initCommand + readCommand + writeCommand + verifyCommand + blankCheckCommand + eraseCommand + kcfg_PicProgrammerPort + + + + kpushbutton.h + kpushbutton.h + kcombobox.h + klineedit.h + klineedit.h + klineedit.h + klineedit.h + klineedit.h + klineedit.h + + diff --git a/src/gui/pieditor.cpp b/src/gui/pieditor.cpp new file mode 100644 index 0000000..b7ca0e5 --- /dev/null +++ b/src/gui/pieditor.cpp @@ -0,0 +1,294 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "colorcombo.h" +#include "doublespinbox.h" +#include "pieditor.h" +#include "variant.h" + +#include +#include +#include +#include +#include +#include + +//BEGIN class PIEditor +PIEditor::PIEditor(QString id, Variant *data, QWidget *parent, const char *name) + : QWidget(parent, name) +{ + m_id = id; + m_data = data; + connect(m_data,SIGNAL(valueChanged(QVariant, QVariant )),this,SLOT(valueChanged(QVariant))); + setFocus(); + update(); + //show(); +} + +PIEditor::~PIEditor() +{ +} + +void PIEditor::valueChanged( QVariant /*variant*/ ) +{ +} +//END class PIEditor + + +//BEGIN class PIBool +PIBool::PIBool(QString id, Variant *data, QWidget *parent, const char *name ) + : PIEditor( id, data, parent, name ) +{ + QHBoxLayout *layout = new QHBoxLayout(this); + layout->setAutoAdd(true); + + m_comboBox = new KComboBox(this); + m_comboBox->insertItem( i18n("True"), 0 ); + m_comboBox->insertItem( i18n("False"), 1 ); + m_comboBox->setCurrentItem( m_data->value().toBool() ? 0 : 1 ); + + connect( m_comboBox, SIGNAL(activated(int )), this, SLOT(selectChanged(int )) ); +} + +PIBool::~PIBool() +{ +} + +void PIBool::popup() +{ + m_comboBox->popup(); +} + +void PIBool::selectChanged( int index ) +{ + emit editorDataChanged( m_id, QVariant( index == 0 ) ); +} + +void PIBool::valueChanged( QVariant /*variant*/ ) +{ + m_comboBox->setCurrentItem( m_data->value().toBool() ? 0 : 1 ); +} +//END class PIBool + + +//BEGIN class PIColor +PIColor::PIColor(QString id, Variant *data, QWidget *parent, const char *name ) + : PIEditor(id,data,parent, name) +{ + QHBoxLayout *layout = new QHBoxLayout(this); + layout->setAutoAdd(true); + + m_combo = new ColorCombo( (ColorCombo::ColorScheme)m_data->colorScheme(), this ); + m_combo->setColor(m_data->value().toColor()); + + connect(m_combo,SIGNAL(activated(const QColor&)),this,SLOT(colorChanged(const QColor&))); +// connect(m_combo,SIGNAL(highlighted(const QColor&)),this,SLOT(colorChanged(const QColor&))); +} + +PIColor::~PIColor() +{ +} + +void PIColor::popup() +{ + m_combo->popup(); +} + +void PIColor::colorChanged(const QColor &col) +{ + emit editorDataChanged(m_id,QVariant(col)); +} + +void PIColor::valueChanged( QVariant /*variant*/ ) +{ + m_combo->setColor(m_data->value().toColor()); +} +//END class PIColor + + +//BEGIN class PIDouble +PIDouble::PIDouble(QString id, Variant *data, QWidget *parent, const char *name ) + : PIEditor(id,data,parent, name) +{ + QHBoxLayout *layout = new QHBoxLayout(this); + layout->setAutoAdd(true); + + spin = new DoubleSpinBox(m_data->minValue(),m_data->maxValue(),m_data->minAbsValue(),m_data->value().toDouble(),m_data->unit(),this); + + connect(spin,SIGNAL(valueChanged(double)),this,SLOT(spinValueChanged(double))); +} + +PIDouble::~PIDouble() +{ +} + +void PIDouble::spinValueChanged(double value) +{ + emit editorDataChanged(m_id,QVariant(value)); +} + +void PIDouble::valueChanged( QVariant /*variant*/ ) +{ + spin->setValue(m_data->value().toDouble()); +} +//END class PIDouble + + +//BEGIN class PIFileName +PIFilename::PIFilename(QString id, Variant *data, QWidget *parent, const char *name ) + : PIEditor(id,data,parent, name) +{ + QHBoxLayout *layout = new QHBoxLayout(this); + layout->setAutoAdd(true); + + m_combo = 0L; + if( m_data->allowed().count() == 0 ) + { + m_combo = new KComboBox(this); + m_combo->insertStringList( m_data->allowed() ); + m_urlreq = new KURLRequester(m_combo, this); + } + else m_urlreq = new KURLRequester(this); + + m_urlreq->setURL( m_data->value().toString() ); + m_urlreq->setFilter( m_data->filter() ); + + connect(m_urlreq,SIGNAL(urlSelected(const QString&)),this,SLOT(slotURLChanged(const QString&))); + //connect(m_urlreq,SIGNAL(openFileDialog(KURLRequester*)),this,SLOT(slotOpenFileDialog(KURLRequester* ))); +} + +PIFilename::~PIFilename() +{ +} + +void PIFilename::slotURLChanged(const QString &url) +{ + emit editorDataChanged(m_id,QVariant(url)); +} + +void PIFilename::valueChanged( QVariant /*variant*/ ) +{ + if(m_combo) m_combo->setCurrentItem( m_data->value().toString() ); + m_urlreq->setURL( m_data->value().toString() ); +} + +/* //FIXME Reintroduce this code if deciding not to go with dropping cod files + onto the PIC componenent ?? */ +// +// void PIFilename::slotOpenFileDialog(KURLRequester *kurlreq) +// { +// // If no file has been selected so far then it seems +// // to make most sense to open the dialog at the directory +// // of the current project if open. +// if(kurlreq->url() == m_data->defaultValue().toString() && !ProjectManager::self()->directory().isEmpty() ) kurlreq->setURL(ProjectManager::self()->directory()); +// } +//END class PIFileName + + +//BEGIN class PIInt +PIInt::PIInt( const QString &id, Variant *data, QWidget *parent, const char *name ) + : PIEditor( id, data, parent, name ) +{ + QHBoxLayout *layout = new QHBoxLayout(this); + layout->setAutoAdd(true); + + spin = new KIntSpinBox( (int)m_data->minValue(), (int)m_data->maxValue(), 1, m_data->value().toInt(), 10, this ); + + connect( spin, SIGNAL(valueChanged(int)), this, SLOT(spinValueChanged(int))); +} + +PIInt::~PIInt() +{ +} + +void PIInt::spinValueChanged( int value ) +{ + emit editorDataChanged( m_id, QVariant(value) ); +} + +void PIInt::valueChanged( QVariant /*variant*/ ) +{ + spin->setValue( m_data->value().toInt() ); +} +//END class PIInt + + +//BEGIN class PILineEdit +PILineEdit::PILineEdit(QString id, Variant *data, QWidget *parent, const char *name) + : PIEditor( id, data, parent, name) +{ + QHBoxLayout *layout = new QHBoxLayout(this); + layout->setAutoAdd(true); + m_edit = new KLineEdit( m_data->value().toString() , this ); + connect(m_edit,SIGNAL(textChanged(const QString&)),this,SLOT(slotEditTextChanged())); +} + + +PILineEdit::~PILineEdit() +{ +} + +void PILineEdit::slotEditTextChanged() +{ + emit editorDataChanged(m_id,QVariant(m_edit->text())); +} + +void PILineEdit::valueChanged( QVariant /*variant*/ ) +{ + m_edit->setText(m_data->value().toString()); +} +//END class PILineEdit + + +//BEGIN class PIStringCombo +PIStringCombo::PIStringCombo(QString id, Variant *data, QWidget *parent, const char *name) + : PIEditor( id, data, parent, name) +{ + QHBoxLayout *layout = new QHBoxLayout(this); + layout->setAutoAdd(true); + + m_combo = new KComboBox( this ); + m_combo->insertStringList(m_data->allowed()); + m_combo->setCurrentItem(m_data->value().toString()); + const Variant::Type::Value type = m_data->type(); + m_combo->setEditable( type == Variant::Type::Combo || + type == Variant::Type::FileName || + type == Variant::Type::VarName ); + + connect(m_combo,SIGNAL(highlighted(const QString&)),this,SLOT(slotComboChanged())); + connect(m_combo,SIGNAL(activated(const QString&)),this,SLOT(slotComboChanged())); +} + + +PIStringCombo::~PIStringCombo() +{ +} + +void PIStringCombo::popup() +{ + m_combo->popup(); +} + +void PIStringCombo::slotComboChanged() +{ + emit editorDataChanged(m_id,QVariant(m_combo->currentText())); +} + +void PIStringCombo::valueChanged( QVariant /*variant*/ ) +{ + m_combo->setCurrentItem(m_data->value().toString()); +} +//END class PIStringCombo + + + + +#include "pieditor.moc" + diff --git a/src/gui/pieditor.h b/src/gui/pieditor.h new file mode 100644 index 0000000..8423c7d --- /dev/null +++ b/src/gui/pieditor.h @@ -0,0 +1,188 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PIEDITOR_H +#define PIEDITOR_H + +#include +#include +#include + +class DoubleSpinBox; +class ColorCombo; +class KComboBox; +class KIntSpinBox; +class KLineEdit; +class KURLRequester; +class Variant; + + +/** +@author Daniel Clarke +*/ +class PIEditor : public QWidget +{ + Q_OBJECT + public: + PIEditor(QString id, Variant *data, QWidget *parent = 0, const char *name = 0); + ~PIEditor(); + + public slots: + virtual void valueChanged( QVariant variant ); + + signals: + void editorDataChanged(const QString &id, QVariant data); + + protected: + QString m_id; + Variant *m_data; +}; + + +/** +@author David Saxton + */ +class PIBool : public PIEditor +{ + Q_OBJECT + public: + PIBool( QString id, Variant *data, QWidget *parent = 0, const char *name = 0 ); + ~PIBool(); + + void popup(); + + protected slots: + void selectChanged( int index ); + virtual void valueChanged( QVariant variant ); + + protected: + KComboBox *m_comboBox; +}; + +/** +@author Daniel Clarke + */ +class PIColor : public PIEditor +{ + Q_OBJECT + public: + PIColor(QString id, Variant *data, QWidget *parent = 0, const char *name = 0); + ~PIColor(); + void popup(); + + protected slots: + void colorChanged(const QColor &col); + virtual void valueChanged( QVariant variant ); + + protected: + ColorCombo *m_combo; +}; + + +/** +Allows the editing of double precision numerical values, using the DoubleNum widget +@author Daniel Clarke + */ +class PIDouble : public PIEditor +{ + Q_OBJECT + public: + PIDouble(QString id, Variant *data, QWidget *parent = 0, const char *name = 0); + ~PIDouble(); + + protected slots: + void spinValueChanged(double value); + virtual void valueChanged( QVariant variant ); + + protected: + DoubleSpinBox *spin; +}; + + +/** +@author Daniel Clarke + */ +class PIFilename : public PIEditor +{ + Q_OBJECT + public: + PIFilename(QString id, Variant *data, QWidget *parent = 0, const char *name = 0); + ~PIFilename(); + + protected slots: + void slotURLChanged(const QString &url); + virtual void valueChanged( QVariant variant ); + // see comments in implementation. + //void slotOpenFileDialog(KURLRequester *kurlreq); + + protected: + KURLRequester *m_urlreq; + KComboBox *m_combo; +}; + +/** +@author David Saxton + */ +class PIInt : public PIEditor +{ + Q_OBJECT + public: + PIInt( const QString &id, Variant *data, QWidget *parent = 0, const char *name = 0); + ~PIInt(); + + protected slots: + void spinValueChanged( int value ); + virtual void valueChanged( QVariant variant ); + + protected: + KIntSpinBox *spin; +}; + + +/** +@author Daniel Clarke + */ +class PILineEdit : public PIEditor +{ + Q_OBJECT + public: + PILineEdit(QString id, Variant *data, QWidget *parent = 0, const char *name = 0); + ~PILineEdit(); + + protected slots: + void slotEditTextChanged(); + virtual void valueChanged( QVariant variant ); + + protected: + KLineEdit *m_edit; +}; + + +/** +@author Daniel Clarke + */ +class PIStringCombo : public PIEditor +{ + Q_OBJECT + public: + PIStringCombo(QString id, Variant *data, QWidget *parent, const char *name = 0); + ~PIStringCombo(); + void popup(); + + public slots: + virtual void valueChanged( QVariant variant ); + void slotComboChanged(); + + protected: + KComboBox *m_combo; + +}; + +#endif diff --git a/src/gui/plvitem.cpp b/src/gui/plvitem.cpp new file mode 100644 index 0000000..420259b --- /dev/null +++ b/src/gui/plvitem.cpp @@ -0,0 +1,90 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "plvitem.h" +#include "variant.h" + +#include +#include +#include + +//BEGIN class PLVItem +PLVItem::PLVItem(KListView *listview, const QString &id, Variant *data) + : KListViewItem(listview, data->editorCaption()) +{ + p_data = data; + m_id = id; + setText(1,p_data->displayString() ); + + connect(data,SIGNAL(valueChanged(QVariant, QVariant )),this,SLOT(updateData(QVariant ))); + + //setHeight(100); +} + + +PLVItem::~PLVItem() +{ +} + +void PLVItem::updateData(QVariant /*value*/) +{ + if (!p_data) + return; + setText(1,p_data->displayString() ); +} + + +int PLVItem::width ( const QFontMetrics & fm, const QListView * lv, int c ) const +{ + if ( c == 0 ) + return 100; +// return KListViewItem::width( fm, lv, c ); + else + return 200; +} +//END class PLVitem + + + +//BEGIN class PLVColorItem +PLVColorItem::PLVColorItem(KListView *listview, const QString &id, Variant *data) + : PLVItem(listview,id,data) +{ +} + + +PLVColorItem::~PLVColorItem() +{ +} + +void PLVColorItem::paintCell ( QPainter * p, const QColorGroup & cg, int column, int width, int align ) +{ + if (!p_data) + return; + // we only draw column 1 "Data" ourselves, otherwise + // we leave it up to KDE + if (column == 1) + { + p->setBackgroundColor( p_data->value().toColor() ); + QBrush brush( p_data->value().toColor() ); + p->fillRect(QRect(0,0,listView()->columnWidth(1),KListViewItem::height()),brush); + } + else + KListViewItem::paintCell(p,cg,column,width,align); +} + +void PLVColorItem::updateData(QVariant value) +{ + listView()->triggerUpdate(); + PLVItem::updateData(value); +} +//END class PLVColorItem + +#include "plvitem.moc" diff --git a/src/gui/plvitem.h b/src/gui/plvitem.h new file mode 100644 index 0000000..fd48845 --- /dev/null +++ b/src/gui/plvitem.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PLVITEM_H +#define PLVITEM_H + +#include +#include +#include +#include + +class Variant; + +/** +@author David Saxton + +PropertiesListView Item +Basic item, which holds the Variant data and Id for an item +*/ +class PLVItem : public QObject, public KListViewItem +{ + Q_OBJECT + public: + PLVItem( KListView *listview, const QString &id, Variant * data ); + ~PLVItem(); + + QString id() const { return m_id; } + Variant * data() const { return p_data; } + + virtual int width ( const QFontMetrics & fm, const QListView * lv, int c ) const; + + public slots: + /** + * Call to change the data held by an item, and update the display + * accordingly. + */ + virtual void updateData(QVariant value); + + protected: + QString m_id; + QGuardedPtr p_data; +}; + +/** +@author Daniel Clarke + */ +class PLVColorItem : public PLVItem +{ + public: + PLVColorItem( KListView *listview, const QString &id, Variant *data ); + ~PLVColorItem(); + + void updateData(QVariant value); + + protected: + virtual void paintCell( QPainter * p, const QColorGroup & cg, int column, int width, int align ); +}; + +#endif diff --git a/src/gui/probepositioner.cpp b/src/gui/probepositioner.cpp new file mode 100644 index 0000000..1ea2606 --- /dev/null +++ b/src/gui/probepositioner.cpp @@ -0,0 +1,210 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "oscilloscope.h" +#include "oscilloscopedata.h" +#include "oscilloscopeview.h" +#include "probepositioner.h" + +#include +#include +#include + +#include +#include + +ProbePositioner::ProbePositioner(QWidget *parent, const char *name) + : QWidget( parent, name, WNoAutoErase ) +{ + m_probePosOffset = 0; + p_draggedProbe = 0l; + setFixedWidth( int(probeArrowWidth) ); + setBackgroundMode(NoBackground); + b_needRedraw = true; + m_pixmap = 0l; +} + + +ProbePositioner::~ProbePositioner() +{ + delete m_pixmap; +} + + +void ProbePositioner::forceRepaint() +{ + b_needRedraw = true; + repaint(false); +} + + +int ProbePositioner::probeOutputHeight() const +{ + int height = int( Oscilloscope::self()->oscilloscopeView->height() - probeArrowHeight ); + int numProbes = Oscilloscope::self()->numberOfProbes(); + if ( numProbes == 0 ) + numProbes = 1; + return height / numProbes; +} + + +int ProbePositioner::probePosition( ProbeData *probeData ) const +{ + if (!probeData) + return -1; + + int spacing = probeOutputHeight(); + int probeNum = Oscilloscope::self()->probeNumber(probeData->id()); + + return int( probeArrowHeight/2 + spacing*( probeNum + probeData->drawPosition() ) ); +} + + +void ProbePositioner::setProbePosition( ProbeData *probeData, int position ) +{ + if (!probeData) + return; + + int height = int( Oscilloscope::self()->oscilloscopeView->height() - probeArrowHeight ); + int numProbes = Oscilloscope::self()->numberOfProbes(); + int spacing = height / numProbes; + int probeNum = Oscilloscope::self()->probeNumber(probeData->id()); + + int minPos = int(probeArrowHeight/2); + int maxPos = int(Oscilloscope::self()->oscilloscopeView->height() - (probeArrowHeight/2)) - 1; + if ( position < minPos ) + position = minPos; + else if ( position > maxPos ) + position = maxPos; + + probeData->setDrawPosition( float(position - probeArrowHeight/2)/float(spacing) - probeNum ); + + forceRepaint(); + Oscilloscope::self()->oscilloscopeView->updateView(); +} + + +ProbeData* ProbePositioner::probeAtPosition( const QPoint &pos ) +{ + int relativeArrowHeight = int( probeArrowHeight * ( 1. - float(pos.x()/probeArrowWidth) ) ); + + const ProbeDataMap::const_iterator end = m_probeDataMap.end(); + for ( ProbeDataMap::const_iterator it = m_probeDataMap.begin(); it != end; ++it ) + { + ProbeData *probeData = it.data(); + int currentPos = probePosition(probeData); + m_probePosOffset = pos.y() - currentPos; + if ( std::abs(m_probePosOffset) <= relativeArrowHeight ) + return probeData; + } + m_probePosOffset = 0; + return 0l; +} + + +void ProbePositioner::slotProbeDataRegistered( int id, ProbeData *probe ) +{ + m_probeDataMap[id] = probe; + connect( probe, SIGNAL(displayAttributeChanged()), this, SLOT(forceRepaint()) ); + // This connect doesn't really belong here, but it save a lot of code + connect( probe, SIGNAL(displayAttributeChanged()), Oscilloscope::self()->oscilloscopeView, SLOT(updateView()) ); + forceRepaint(); + Oscilloscope::self()->oscilloscopeView->updateView(); +} + + +void ProbePositioner::slotProbeDataUnregistered( int id ) +{ + m_probeDataMap.erase(id); + // We "set" the position of each probe to force it into proper bounds + + const ProbeDataMap::const_iterator end = m_probeDataMap.end(); + for ( ProbeDataMap::const_iterator it = m_probeDataMap.begin(); it != end; ++it ) + setProbePosition( it.data(), probePosition( it.data() ) ); + + forceRepaint(); +} + + +void ProbePositioner::resizeEvent( QResizeEvent *e ) +{ + delete m_pixmap; + m_pixmap = new QPixmap( e->size() ); + QWidget::resizeEvent(e); + forceRepaint(); +} + + +void ProbePositioner::mousePressEvent( QMouseEvent * e ) +{ + p_draggedProbe = probeAtPosition(e->pos()); + if (p_draggedProbe) + e->accept(); + else + e->ignore(); +} + + +void ProbePositioner::mouseReleaseEvent( QMouseEvent * e ) +{ + if (p_draggedProbe) + e->accept(); + else + e->ignore(); +} + + +void ProbePositioner::mouseMoveEvent( QMouseEvent * e ) +{ + if (!p_draggedProbe) + { + e->ignore(); + return; + } + e->accept(); + + setProbePosition( p_draggedProbe, e->pos().y() - m_probePosOffset ); + forceRepaint(); +} + + +void ProbePositioner::paintEvent( QPaintEvent *e ) +{ + QRect r = e->rect(); + + if (b_needRedraw) + { + QPainter p; + m_pixmap->fill( paletteBackgroundColor() ); + p.begin(m_pixmap); + p.setClipRegion(e->region()); + + const ProbeDataMap::const_iterator end = m_probeDataMap.end(); + for ( ProbeDataMap::const_iterator it = m_probeDataMap.begin(); it != end; ++it ) + { + ProbeData *probeData = it.data(); + p.setBrush( probeData->color() ); + int currentPos = probePosition(probeData); + + QPointArray pa(3); + pa[0] = QPoint( 0, int(currentPos-(probeArrowHeight/2)) ); + pa[1] = QPoint( int(probeArrowWidth), currentPos ); + pa[2] = QPoint( 0, int(currentPos+(probeArrowHeight/2)) ); + + p.drawPolygon(pa); + } + b_needRedraw = false; + } + + bitBlt( this, r.x(), r.y(), m_pixmap, r.x(), r.y(), r.width(), r.height() ); +} + + +#include "probepositioner.moc" diff --git a/src/gui/probepositioner.h b/src/gui/probepositioner.h new file mode 100644 index 0000000..d106b40 --- /dev/null +++ b/src/gui/probepositioner.h @@ -0,0 +1,77 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PROBEPOSITIONER_H +#define PROBEPOSITIONER_H + +#include + +class ProbeData; +typedef QMap< int, ProbeData* > ProbeDataMap; + +const float probeArrowWidth = 9; +const float probeArrowHeight = 12; + +/** +Widget for positioning the output of Probes in the OscilloscopeView +@author David Saxton +*/ +class ProbePositioner : public QWidget +{ + Q_OBJECT + public: + ProbePositioner(QWidget *parent = 0, const char *name = 0); + ~ProbePositioner(); + /** + * Returns the amount of space (height in pixels) that a probe output + * takes up + */ + int probeOutputHeight() const; + /** + * Returns the probe position (from the top) in pixels that the probe + * with the given id should be displayed at, or -1 if probe with the + * given id couldn't be found + */ + int probePosition( ProbeData *probeData ) const; + /** + * Sets the probe position relative to the top of this widget (and hence + * relative to the top of the oscilloscope view) in pixels + */ + void setProbePosition( ProbeData *probeData, int position ); + /** + * Returns the probe at the given position (plus or minus an an arrow), + * or NULL if none. Records the offset of the position from the mouse + * in m_probePosOffset. + */ + ProbeData* probeAtPosition( const QPoint &pos ); + + public slots: + void forceRepaint(); + + protected slots: + void slotProbeDataRegistered( int id, ProbeData *probe ); + void slotProbeDataUnregistered( int id ); + + protected: + virtual void mousePressEvent( QMouseEvent * e ); + virtual void mouseReleaseEvent( QMouseEvent * e ); + virtual void mouseMoveEvent( QMouseEvent * e ); + virtual void paintEvent( QPaintEvent *e ); + virtual void resizeEvent( QResizeEvent *event ); + + ProbeDataMap m_probeDataMap; + ProbeData *p_draggedProbe; + int m_probePosOffset; + + bool b_needRedraw; + QPixmap *m_pixmap; +}; + +#endif diff --git a/src/gui/processingoptionswidget.ui b/src/gui/processingoptionswidget.ui new file mode 100644 index 0000000..683092a --- /dev/null +++ b/src/gui/processingoptionswidget.ui @@ -0,0 +1,98 @@ + +ProcessingOptionsWidget + + + ProcessingOptionsWidget + + + + 0 + 0 + 458 + 40 + + + + Processing Options + + + + unnamed + + + 0 + + + + m_pMicroSelect + + + + 0 + 0 + + + + + + spacer2 + + + Vertical + + + Expanding + + + + 20 + 16 + + + + + + textLabel1 + + + Output File: + + + + + m_pOutputURL + + + + + + + MicroSelectWidget +
    microselectwidget.h
    + + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image0 +
    +
    + + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000042949444154388db5954d6c545514c77ff7de37eff1a6a550da994e5ba798868f948fc847a2a2911816c436b0a02ed0083161a1981877ee10d90aa94656063491882c5cd4c4b8103f20cd806909a98604da8482341de80cb69de9bcd799799d79efba980f1da3a80b4f727273939bdff99f9b93f3175a6b6a21849080020c4002a29a8f0a5dcd002803bed63a1035f0d0d0504b6f6fef51d7758fa4d3e98d8ee3fc03af128ee3303939399548242eb8aefb09300f78464de9f0f0f0d148cc7caf3d5424de97a7ec17104220242805520a44557bbd4b21f083801d33e63a6d1bc7bf19c6064e0319a35a58b9ae7ba43d54e4d7c54b64dc097c7f09d30ef04b36736983cc7c11b4456b9b492c5e20dc54a6540e00896a8268a7017010f8bcae1830d2e9f4c69ebe3c197782b2ce60d94ddc9b30f9feeb45ae5d7181c5ead35636ef08d3ffe26a76ee3208b4031a56d80aa00768fda362e9380e25bf80ef3b587613d7afc099533380a4b5dda46fcb5aa42998b9eb7173dce5e6788e434763ec7fc942532008ea436003660d2caa7f8d69c3bd8910674e4d033e83877ad8d36fb0aa4d6058658ac5358c5df6383bf480f31fdda5a3632bbbfb6da4ccd5c00a10b2012cc12fd97cfb5516f0187c25cee0619396480ec3ca909d0f3372d1e5f9fe66de3ad605587c712ec55256a2540d5519d19ae24a29057329839f7ecc138944d833102290f3184ae1e6d6f0e98739c61229e6d21eafbed1c9c8c5558c8f3ee4ceed76946a1c43d97091828585223e2eebfbc295f60d45de89707628cb58224577bc85a79e5d4d786581cddb9b0148259711b20145836221400416e0232d1f6595c9ce4538773ac7b54406f0b15784e8e80aa1ac2594190220d021e49f2437960156b70ba095e95f96f18acd8c263cc6122962b1167a7ba34cdd7ec8c977a699bed546722a8fc2a02b6e2185fff78ab586ce78894ddb9ab9f5738ed14b1e030756929d8ff2e4ae5544632b38f96e89a99b298ebd6950cc2d12ed0eb3618b26f520788462ad09877df60db600f0f1fb49c646f21c7ebd836dcf94e9d9b4c0db27d6d3bd36c6426a96bce731703046d7da129a4670836284a054869d4f1b1c7e2dca67676ef3c1898091ef5ad8bc358c3205c93bf7c9a40ad4c660f4728edd7bbb3142ea2fc1da711cfc200011e08b45f6bd1c261adbce9717928c5f9d63fc6a19f0014567773303073790f8214bd6f5282dfbb8b9fa1f6b40d7c1939393533b92e63ad9240990484aec7e41b27d579cbb531e0f67023492d86316ebb768ba1e0f786e6f37e56550c62237aee7011e54abd7c1412291b8a06de378b4d3c0b215da9708e5a3a442192085404a83d4accfecac067c0c43e13a70e3fa12e96409e0325000966bbb354465339d04a6f9dd15fe6dde07ce030780278088d05ad72cc9a6b2f2daaaa74d75a1f0e8d0d5f60b40868a8364ead6248430000b0857a126ffcdf396abf03ce089ffcb4c7f033046c6b4a995e7a00000000049454e44ae426082 + + + + + microselectwidget.h + kurlrequester.h + klineedit.h + kpushbutton.h + +
    diff --git a/src/gui/programmerdlg.cpp b/src/gui/programmerdlg.cpp new file mode 100644 index 0000000..a2186b4 --- /dev/null +++ b/src/gui/programmerdlg.cpp @@ -0,0 +1,90 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "language.h" +#include "microselectwidget.h" +#include "picprogrammer.h" +#include "port.h" +#include "programmerdlg.h" +#include "programmerwidget.h" +#include "src/core/ktlconfig.h" + +#include +#include +#include +#include + +ProgrammerDlg::ProgrammerDlg( const QString & picID, QWidget *parent, const char *name ) + : KDialogBase( parent, name, true, i18n("PIC Programmer"), Ok|Cancel ) +{ + // Change the "Ok" button to a "Burn" button + KGuiItem burnItem = KStdGuiItem::ok(); + burnItem.setText( i18n("Burn") ); + setButtonOK( burnItem ); + + m_bAccepted = false; + m_pProgrammerWidget = new ProgrammerWidget( this ); + m_pProgrammerSettings = new PicProgrammerSettings; + + // Setup the list of programmers + KComboBox * programmerCombo = m_pProgrammerWidget->m_pProgrammerProgram; + QStringList programmerNames = m_pProgrammerSettings->configNames( false ); + programmerCombo->insertStringList( programmerNames ); + programmerCombo->setSizeLimit( programmerNames.size() ); + programmerCombo->setCurrentText( KTLConfig::picProgrammerProgram() ); + + // Sets up the list of ports + m_pProgrammerWidget->m_pPicProgrammerPort->insertStringList( Port::ports( Port::ExistsAndRW ) ); + m_pProgrammerWidget->m_pPicProgrammerPort->setCurrentText( KTLConfig::picProgrammerPort() ); + + // Set the pic type to the one requested + if ( !picID.isEmpty() ) + m_pProgrammerWidget->m_pMicroSelect->setMicro( picID ); + + setMainWidget( m_pProgrammerWidget ); +} + + +ProgrammerDlg::~ProgrammerDlg() +{ +} + + +void ProgrammerDlg::initOptions( ProcessOptions * options ) +{ + if ( !options ) + return; + + options->m_picID = m_pProgrammerWidget->m_pMicroSelect->micro(); + options->m_port = m_pProgrammerWidget->m_pPicProgrammerPort->currentText(); + options->m_program = m_pProgrammerWidget->m_pProgrammerProgram->currentText(); +} + + +void ProgrammerDlg::accept() +{ + m_bAccepted = true; + hide(); +} + + +void ProgrammerDlg::reject() +{ + m_bAccepted = false; +} + + +MicroSelectWidget * ProgrammerDlg::microSelect( ) const +{ + return m_pProgrammerWidget->m_pMicroSelect; +} + + +#include "programmerdlg.moc" diff --git a/src/gui/programmerdlg.h b/src/gui/programmerdlg.h new file mode 100644 index 0000000..ab64e5a --- /dev/null +++ b/src/gui/programmerdlg.h @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PROGRAMMERDLG_H +#define PROGRAMMERDLG_H + +#include + +class MicroSelectWidget; +class PicProgrammerSettings; +class ProcessOptions; +class ProgrammerWidget; + + +/** +@author David Saxton +*/ +class ProgrammerDlg : public KDialogBase +{ + Q_OBJECT + public: + /** + * Create a new ProgrammerDlg with the PIC type set to picID. Other + * options (such as the program to use) will be read in from the + * settings. + */ + ProgrammerDlg( const QString & picID, QWidget * parent = 0, const char * name = 0 ); + ~ProgrammerDlg(); + + virtual void reject(); + virtual void accept(); + bool isAccepted() const { return m_bAccepted; } + /** + * Initialises options with the values that the user has entered into + * the widgets. + */ + void initOptions( ProcessOptions * options ); + + MicroSelectWidget * microSelect() const; + + protected: + bool m_bAccepted; + ProgrammerWidget * m_pProgrammerWidget; + PicProgrammerSettings * m_pProgrammerSettings; +}; + +#endif diff --git a/src/gui/programmerwidget.ui b/src/gui/programmerwidget.ui new file mode 100644 index 0000000..3436ac1 --- /dev/null +++ b/src/gui/programmerwidget.ui @@ -0,0 +1,123 @@ + +ProgrammerWidget + + + ProgrammerWidget + + + + 0 + 0 + 320 + 96 + + + + Programmer + + + + unnamed + + + 0 + + + + textLabel1_3 + + + Program: + + + + + m_pProgrammerProgram + + + + 1 + 0 + 1 + 0 + + + + false + + + + + m_pMicroSelect + + + + 0 + 0 + + + + + + textLabel1 + + + Port + + + + + m_pPicProgrammerPort + + + true + + + + + spacer4 + + + Vertical + + + Expanding + + + + 20 + 0 + + + + + + + + MicroSelectWidget +
    microselectwidget.h
    + + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image0 +
    +
    + + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000042949444154388db5954d6c545514c77ff7de37eff1a6a550da994e5ba798868f948fc847a2a2911816c436b0a02ed0083161a1981877ee10d90aa94656063491882c5cd4c4b8103f20cd806909a98604da8482341de80cb69de9bcd799799d79efba980f1da3a80b4f727273939bdff99f9b93f3175a6b6a21849080020c4002a29a8f0a5dcd002803bed63a1035f0d0d0504b6f6fef51d7758fa4d3e98d8ee3fc03af128ee3303939399548242eb8aefb09300f78464de9f0f0f0d148cc7caf3d5424de97a7ec17104220242805520a44557bbd4b21f083801d33e63a6d1bc7bf19c6064e0319a35a58b9ae7ba43d54e4d7c54b64dc097c7f09d30ef04b36736983cc7c11b4456b9b492c5e20dc54a6540e00896a8268a7017010f8bcae1830d2e9f4c69ebe3c197782b2ce60d94ddc9b30f9feeb45ae5d7181c5ead35636ef08d3ffe26a76ee3208b4031a56d80aa00768fda362e9380e25bf80ef3b587613d7afc099533380a4b5dda46fcb5aa42998b9eb7173dce5e6788e434763ec7fc942532008ea436003660d2caa7f8d69c3bd8910674e4d033e83877ad8d36fb0aa4d6058658ac5358c5df6383bf480f31fdda5a3632bbbfb6da4ccd5c00a10b2012cc12fd97cfb5516f0187c25cee0619396480ec3ca909d0f3372d1e5f9fe66de3ad605587c712ec55256a2540d5519d19ae24a29057329839f7ecc138944d833102290f3184ae1e6d6f0e98739c61229e6d21eafbed1c9c8c5558c8f3ee4ceed76946a1c43d97091828585223e2eebfbc295f60d45de89707628cb58224577bc85a79e5d4d786581cddb9b0148259711b20145836221400416e0232d1f6595c9ce4538773ac7b54406f0b15784e8e80aa1ac2594190220d021e49f2437960156b70ba095e95f96f18acd8c263cc6122962b1167a7ba34cdd7ec8c977a699bed546722a8fc2a02b6e2185fff78ab586ce78894ddb9ab9f5738ed14b1e030756929d8ff2e4ae5544632b38f96e89a99b298ebd6950cc2d12ed0eb3618b26f520788462ad09877df60db600f0f1fb49c646f21c7ebd836dcf94e9d9b4c0db27d6d3bd36c6426a96bce731703046d7da129a4670836284a054869d4f1b1c7e2dca67676ef3c1898091ef5ad8bc358c3205c93bf7c9a40ad4c660f4728edd7bbb3142ea2fc1da711cfc200011e08b45f6bd1c261adbce9717928c5f9d63fc6a19f0014567773303073790f8214bd6f5282dfbb8b9fa1f6b40d7c1939393533b92e63ad9240990484aec7e41b27d579cbb531e0f67023492d86316ebb768ba1e0f786e6f37e56550c62237aee7011e54abd7c1412291b8a06de378b4d3c0b215da9708e5a3a442192085404a83d4accfecac067c0c43e13a70e3fa12e96409e0325000966bbb354465339d04a6f9dd15fe6dde07ce030780278088d05ad72cc9a6b2f2daaaa74d75a1f0e8d0d5f60b40868a8364ead6248430000b0857a126ffcdf396abf03ce089ffcb4c7f033046c6b4a995e7a00000000049454e44ae426082 + + + + + kcombobox.h + microselectwidget.h + +
    diff --git a/src/gui/projectdlgs.cpp b/src/gui/projectdlgs.cpp new file mode 100644 index 0000000..4ea18c0 --- /dev/null +++ b/src/gui/projectdlgs.cpp @@ -0,0 +1,275 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "createsubprojectwidget.h" +#include "linkeroptionswidget.h" +#include "microlibrary.h" +#include "microselectwidget.h" +#include "newprojectwidget.h" +#include "processingoptionswidget.h" +#include "projectdlgs.h" +#include "projectmanager.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//BEGIN class NewProjectDlg +NewProjectDlg::NewProjectDlg( QWidget * parent ) + : KDialogBase( parent, "newprojectdlg", true, "New Project", KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true ) +{ + m_pWidget = new NewProjectWidget(this); + connect( m_pWidget->projectNameEdit, SIGNAL(textChanged(const QString & )), this, SLOT(locationChanged(const QString& )) ); + connect( m_pWidget->projectLocationURL, SIGNAL(textChanged(const QString & )), this, SLOT(locationChanged(const QString& )) ); + + // Check if already valid dir + locationChanged( QString::null ); + + m_pWidget->projectLocationURL->setURL( QDir::homeDirPath() ); + m_pWidget->projectLocationURL->setMode( KFile::Directory ); + + setMainWidget( m_pWidget ); + setInitialSize( m_pWidget->rect().size() ); +} + +void NewProjectDlg::accept() +{ + hide(); + + m_bAccepted = true; + + m_projectName = m_pWidget->projectNameEdit->text(); + m_projectLocation = m_pWidget->projectLocationURL->url(); +} + +void NewProjectDlg::reject() +{ + m_bAccepted = false; +} + +void NewProjectDlg::locationChanged( const QString & ) +{ + m_location = m_pWidget->projectLocationURL->url(); + QDir subDir(m_location); + + if ( !m_location.endsWith("/") ) + m_location.append("/"); + + if ( !m_pWidget->projectNameEdit->text().isEmpty() ) + m_location.append( m_pWidget->projectNameEdit->text().lower() + "/" ); + + m_pWidget->locationLabel->setText( m_location ); + + QDir dir(m_location); + + if ( dir.exists() || !subDir.exists() ) + enableButtonOK(false); + + else + enableButtonOK(true); +} +//END class NewProjectDlg + + + +//BEGIN class CreateSubprojectDlg +CreateSubprojectDlg::CreateSubprojectDlg( QWidget * parent ) + : KDialogBase( parent, "Create Subproject Dialog", true, "Create Subproject", KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true ) +{ + m_pWidget = new CreateSubprojectWidget(this); + + if ( ProjectManager::self()->currentProject() ) + m_pWidget->m_targetFile->setURL( ProjectManager::self()->currentProject()->directory() ); + + m_type = ProgramType; + + setMainWidget( m_pWidget ); + setInitialSize( m_pWidget->rect().size() ); +} + + +CreateSubprojectDlg::~CreateSubprojectDlg() +{ +} + + +void CreateSubprojectDlg::accept() +{ + hide(); + + m_bAccepted = true; + + m_targetFile = m_pWidget->m_targetFile->url(); + m_type = (Type)m_pWidget->m_typeCombo->currentItem(); +} + + +void CreateSubprojectDlg::reject() +{ + m_bAccepted = false; +} +//END class CreateSubprojectDlg + + + +//BEGIN class LinkerOptionsDlg +LinkerOptionsDlg::LinkerOptionsDlg( LinkerOptions * linkingOptions, QWidget *parent ) + : KDialogBase( parent, "Linker Options Dialog", true, "Linker Options", KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true ) +{ + m_pLinkerOptions = linkingOptions; + m_pWidget = new LinkerOptionsWidget(this); + + ProjectInfo * pi = ProjectManager::self()->currentProject(); + assert(pi); + + + //BEGIN Update gplink options + m_pWidget->m_pHexFormat->setCurrentItem( m_pLinkerOptions->hexFormat() ); + m_pWidget->m_pOutputMap->setChecked( m_pLinkerOptions->outputMapFile() ); + m_pWidget->m_pLibraryDir->setText( m_pLinkerOptions->libraryDir() ); + m_pWidget->m_pLinkerScript->setText( m_pLinkerOptions->linkerScript() ); + m_pWidget->m_pOther->setText( m_pLinkerOptions->linkerOther() ); + //END Update gplink options + + + + //BEGIN Update library widgets + const KURL::List availableInternal = pi->childOutputURLs( ProjectItem::LibraryType ); + const QStringList linkedInternal = m_pLinkerOptions->linkedInternal(); + + KURL::List::const_iterator end = availableInternal.end(); + for ( KURL::List::const_iterator it = availableInternal.begin(); it != end; ++it ) + { + QString relativeURL = KURL::relativeURL( pi->url(), *it ); + QCheckListItem * item = new QCheckListItem( m_pWidget->m_pInternalLibraries, relativeURL, QCheckListItem::CheckBox ); + item->setOn( linkedInternal.contains(relativeURL) ); + } + + m_pExternalLibraryRequester = new KURLRequester( 0l ); + m_pExternalLibraryRequester->fileDialog()->setURL( "/usr/share/sdcc/lib" ); + + delete m_pWidget->m_pExternalLibraries; + m_pWidget->m_pExternalLibraries = new KEditListBox( i18n("Link libraries outside project"), m_pExternalLibraryRequester->customEditor(), m_pWidget ); + m_pWidget->m_pExternalLibraries->layout()->setMargin(11); + (dynamic_cast(m_pWidget->layout()))->addMultiCellWidget( m_pWidget->m_pExternalLibraries, 7, 7, 0, 1 ); + +#if defined(KDE_MAKE_VERSION) +# if KDE_VERSION >= KDE_MAKE_VERSION(3,4,0) + m_pWidget->m_pExternalLibraries->setButtons( KEditListBox::Add | KEditListBox::Remove ); +# endif +#endif + m_pWidget->m_pExternalLibraries->insertStringList( m_pLinkerOptions->linkedExternal() ); + //END Update library widgets + + + setMainWidget( m_pWidget ); + setInitialSize( m_pWidget->rect().size() ); +} + + +LinkerOptionsDlg::~LinkerOptionsDlg() +{ + delete m_pExternalLibraryRequester; +} + + +void LinkerOptionsDlg::accept() +{ + hide(); + + QStringList linkedInternal; + for ( QListViewItemIterator internalIt( m_pWidget->m_pInternalLibraries ); internalIt.current(); ++internalIt ) + { + QCheckListItem * item = static_cast(internalIt.current()); + if ( item->isOn() ) + linkedInternal << item->text(); + } + m_pLinkerOptions->setLinkedInternal( linkedInternal ); + + m_pLinkerOptions->setLinkedExternal( m_pWidget->m_pExternalLibraries->items() ); + m_pLinkerOptions->setHexFormat( (LinkerOptions::HexFormat::type) m_pWidget->m_pHexFormat->currentItem() ); + m_pLinkerOptions->setOutputMapFile( m_pWidget->m_pOutputMap->isChecked() ); + m_pLinkerOptions->setLibraryDir( m_pWidget->m_pLibraryDir->text() ); + m_pLinkerOptions->setLinkerScript( m_pWidget->m_pLinkerScript->text() ); + m_pLinkerOptions->setLinkerOther( m_pWidget->m_pOther->text() ); +} + + +void LinkerOptionsDlg::reject() +{ +} +//END class LinkerOptionsDlg + + + +//BEGIN class ProcessingOptionsDlg +ProcessingOptionsDlg::ProcessingOptionsDlg( ProjectItem * projectItem, QWidget *parent ) + : KDialogBase( parent, "Processing Options Dialog", true, "Processing Options", KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true ) +{ + m_pProjectItem = projectItem; + m_pWidget = new ProcessingOptionsWidget(this); + + m_pWidget->m_pMicroSelect->setEnabled( !projectItem->useParentMicroID() ); + + switch ( projectItem->type() ) + { + case ProjectItem::ProjectType: + m_pWidget->m_pOutputURL->setEnabled(false); + break; + + case ProjectItem::FileType: + m_pWidget->m_pOutputURL->setEnabled(true); + break; + + case ProjectItem::ProgramType: + case ProjectItem::LibraryType: + m_pWidget->m_pOutputURL->setEnabled(false); + break; + } + + m_pWidget->m_pOutputURL->setURL( projectItem->outputURL().path() ); + m_pWidget->m_pMicroSelect->setMicro( projectItem->microID() ); + + setMainWidget( m_pWidget ); + setInitialSize( m_pWidget->rect().size() ); +} + + +ProcessingOptionsDlg::~ProcessingOptionsDlg() +{ +} + + +void ProcessingOptionsDlg::accept() +{ + hide(); + + if ( m_pWidget->m_pOutputURL->isEnabled() ) + m_pProjectItem->setOutputURL( m_pWidget->m_pOutputURL->url() ); + + if ( m_pWidget->m_pMicroSelect->isEnabled() ) + m_pProjectItem->setMicroID( m_pWidget->m_pMicroSelect->micro() ); +} + + +void ProcessingOptionsDlg::reject() +{ +} +//END class ProcessingOptionsDlg + + diff --git a/src/gui/projectdlgs.h b/src/gui/projectdlgs.h new file mode 100644 index 0000000..fe50361 --- /dev/null +++ b/src/gui/projectdlgs.h @@ -0,0 +1,159 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PROJECTDLGS_H +#define PROJECTDLGS_H + +#include + +class CreateSubprojectWidget; +class LinkerOptions; +class LinkerOptionsWidget; +class KURLRequester; +class NewProjectWidget; +class ProcessingOptions; +class ProcessingOptionsWidget; +class ProjectItem; + +/** +A standard dialog for getting project details from the user for a new project +@short Dialog for new project details +@author David Saxton +*/ +class NewProjectDlg : public KDialogBase +{ + Q_OBJECT + public: + NewProjectDlg( QWidget * parent ); + + /** + * Called when the 'Cancel' button is pressed. + */ + void reject(); + + /** + * Called when the 'OK' button is pressed. + * User entered values are read in + */ + void accept(); + + bool accepted() const { return m_bAccepted; } + QString projectName() const { return m_projectName; } + QString projectLocation() const { return m_projectLocation; } + QString location() const { return m_location; } + + public slots: + /** + * Called when the projectName or projectLocation edit boxes are edited. + * Checks whether the resultant location combination is a valid path - + * if so, enabels the OK button; otherwise disables it. + */ + void locationChanged( const QString & ); + + protected: + NewProjectWidget * m_pWidget; + bool m_bAccepted; + QString m_projectName; + QString m_projectLocation; + QString m_location; +}; + + +/** +@author David Saxton +*/ +class CreateSubprojectDlg : public KDialogBase +{ + Q_OBJECT + public: + CreateSubprojectDlg( QWidget *parent = 0 ); + ~CreateSubprojectDlg(); + + // The following values should agree with the positions in the combo box + enum Type + { + ProgramType = 0, + LibraryType = 1 + }; + + /** + * Called when the 'Cancel' button is pressed. + */ + void reject(); + /** + * Called when the 'OK' button is pressed. User entered values are read + * in. + */ + void accept(); + + bool accepted() const { return m_bAccepted; } + Type type() const { return m_type; } + QString targetFile() const { return m_targetFile; } + + protected: + CreateSubprojectWidget * m_pWidget; + bool m_bAccepted; + Type m_type; + QString m_targetFile; +}; + + +/** +@author David Saxton +*/ +class LinkerOptionsDlg : public KDialogBase +{ + Q_OBJECT + public: + LinkerOptionsDlg( LinkerOptions * linkingOptions, QWidget *parent = 0 ); + virtual ~LinkerOptionsDlg(); + + /** + * Called when the 'Cancel' button is pressed. + */ + void reject(); + /** + * Called when the 'OK' button is pressed. User entered values are read + * in. + */ + void accept(); + + protected: + LinkerOptions * m_pLinkerOptions; + LinkerOptionsWidget * m_pWidget; + KURLRequester * m_pExternalLibraryRequester; +}; + + +/** +@author David Saxton +*/ +class ProcessingOptionsDlg : public KDialogBase +{ + public: + ProcessingOptionsDlg( ProjectItem * projectItem, QWidget *parent = 0 ); + virtual ~ProcessingOptionsDlg(); + + /** + * Called when the 'Cancel' button is pressed. + */ + void reject(); + /** + * Called when the 'OK' button is pressed. User entered values are read + * in. + */ + void accept(); + + protected: + ProjectItem * m_pProjectItem; + ProcessingOptionsWidget * m_pWidget; +}; + +#endif diff --git a/src/gui/propertieslistview.cpp b/src/gui/propertieslistview.cpp new file mode 100644 index 0000000..5f57aa3 --- /dev/null +++ b/src/gui/propertieslistview.cpp @@ -0,0 +1,328 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "item.h" +#include "cnitemgroup.h" +#include "itemgroup.h" +#include "iteminterface.h" +#include "pieditor.h" +#include "plvitem.h" +#include "propertieslistview.h" +#include "variant.h" + + +#include +#include +#include +#include +#include +#include + +PropertiesListView::PropertiesListView(QWidget *parent, const char *name) + : KListView(parent, name) +{ + addColumn(i18n("Property")); + addColumn(i18n("Data")); + setFullWidth(true); + setColumnAlignment(1,Qt::AlignRight); + + p_lastItem = 0l; + m_diffBt = 0L; + + connect(this,SIGNAL(selectionChanged(QListViewItem*)),this,SLOT(slotSelectionChanged(QListViewItem*))); + m_editor = 0L; + connect(header(),SIGNAL(sizeChange(int,int,int)),this,SLOT(headerSizeChanged(int,int,int))); +} + +PropertiesListView::~PropertiesListView() +{ +} + +void PropertiesListView::slotClear() +{ + destroyEditor(); + delete m_diffBt; + m_diffBt = 0L; + clear(); + m_plvItemMap.clear(); +} + +void PropertiesListView::slotCreate( ItemGroup * itemGroup ) +{ + if ( !itemGroup || !itemGroup->activeItem() ) + { + slotClear(); + return; + } + + Item *item = itemGroup->activeItem(); + + VariantDataMap *vmap = item->variantMap(); + // Build the list + for( VariantDataMap::iterator vait = vmap->begin(); vait != vmap->end(); ++vait ) + { + if ( vait.data()->isHidden() ) + continue; + + switch( vait.data()->type() ) + { + case Variant::Type::Int: + case Variant::Type::Double: + case Variant::Type::String: + case Variant::Type::FileName: + case Variant::Type::Port: + case Variant::Type::Pin: + case Variant::Type::VarName: + case Variant::Type::Combo: + case Variant::Type::Select: + case Variant::Type::Bool: + case Variant::Type::PenStyle: + case Variant::Type::PenCapStyle: + case Variant::Type::SevenSegment: + case Variant::Type::KeyPad: + { + m_plvItemMap[vait.key()] = new PLVItem( this, vait.key(), vait.data() ); + break; + } + case Variant::Type::Color: + { + m_plvItemMap[vait.key()] = new PLVColorItem( this, vait.key(), vait.data() ); + break; + } + case Variant::Type::Raw: + case Variant::Type::Multiline: + case Variant::Type::None: + { + break; + } + } + } + + slotUpdate(itemGroup); +} + + +void PropertiesListView::slotUpdate( ItemGroup * itemGroup ) +{ + if ( !itemGroup ) + { + slotClear(); + return; + } + + const PLVItemMap::iterator end = m_plvItemMap.end(); + for ( PLVItemMap::iterator it = m_plvItemMap.begin(); it != end; ++it ) + { + it.data()->setEnabled( itemGroup->itemsHaveSameDataValue( it.key() ) ); + } +} + +void PropertiesListView::slotSelectionChanged(QListViewItem *item) +{ + if (!item) return; + destroyEditor(); + p_lastItem = dynamic_cast(item); + if ( !p_lastItem->data() ) return; + + const Variant::Type::Value type = p_lastItem->data()->type(); + switch(type) + { + case Variant::Type::String: + { + m_editor = new PILineEdit(p_lastItem->id(),p_lastItem->data(),this); + break; + } + case Variant::Type::Port: + case Variant::Type::Pin: + case Variant::Type::Combo: + case Variant::Type::VarName: + case Variant::Type::Select: + case Variant::Type::PenStyle: + case Variant::Type::PenCapStyle: + case Variant::Type::SevenSegment: + case Variant::Type::KeyPad: + { + m_editor = new PIStringCombo(p_lastItem->id(),p_lastItem->data(),this); + break; + } + case Variant::Type::FileName: + { + m_editor = new PIFilename(p_lastItem->id(),p_lastItem->data(),this); + break; + } + case Variant::Type::Int: + { + m_editor = new PIInt(p_lastItem->id(),p_lastItem->data(),this); + break; + } + case Variant::Type::Double: + { + m_editor = new PIDouble(p_lastItem->id(),p_lastItem->data(),this); + break; + } + case Variant::Type::Color: + { + m_editor = new PIColor(p_lastItem->id(),p_lastItem->data(),this); + break; + } + case Variant::Type::Bool: + { + m_editor = new PIBool(p_lastItem->id(),p_lastItem->data(),this); + break; + } + case Variant::Type::Raw: + case Variant::Type::Multiline: + case Variant::Type::None: + { + break; + } + } + + connect(p_lastItem->data(),SIGNAL(destroyed()),this,SLOT(destroyEditor())); + // Connect so that changes in the editor change the canvas item data. + connect(m_editor,SIGNAL(editorDataChanged(const QString&,QVariant)),ItemInterface::self(),SLOT(slotSetData(const QString&,QVariant))); + connect(m_editor,SIGNAL(editorDataChanged(const QString&,QVariant)),this,SLOT(slotDataChanged(const QString&,QVariant))); + + int x = columnWidth(0); + int y = viewportToContents(QPoint(0,itemRect(p_lastItem).y())).y(); + addChild(m_editor,x,y); + m_editor->setFocus(); + m_editor->show(); + m_editor->setGeometry(QRect(x,y,columnWidth(1),itemRect(p_lastItem).height())); + + if(p_lastItem->data()->type() == Variant::Type::FileName) + { + // The folder button in the KURLComboBox has a minimum size taller than + // the height of the ListViewItems so this is a temporary kludge to + // make it look slightly acceptable. + m_editor->setGeometry(QRect(x,y,columnWidth(1),itemRect(p_lastItem).height()+7)); + } + + // Active the editor as appropriate + switch(type) + { + case Variant::Type::Port: + case Variant::Type::Pin: + case Variant::Type::Combo: + case Variant::Type::VarName: + case Variant::Type::Select: + case Variant::Type::PenStyle: + case Variant::Type::PenCapStyle: + case Variant::Type::SevenSegment: + case Variant::Type::KeyPad: + { + (static_cast(m_editor))->popup(); + break; + } + case Variant::Type::Color: + { + (static_cast(m_editor))->popup(); + break; + } + case Variant::Type::Bool: + { + (static_cast(m_editor))->popup(); + break; + } + case Variant::Type::FileName: + { + break; + } + case Variant::Type::Int: + { + break; + } + case Variant::Type::Double: + { + break; + } + case Variant::Type::String: + { + break; + } + case Variant::Type::Raw: + case Variant::Type::Multiline: + case Variant::Type::None: + { + break; + } + } +} + +void PropertiesListView::destroyEditor() +{ + if( !m_editor ) return; + + removeChild( m_editor ); + delete m_editor; + m_editor = 0L; +} + +void PropertiesListView::headerSizeChanged(int section, int /*oldSize*/, int newSize) +{ + if( !m_editor || section != 1 ) return; + + // Resize the editor to the new column width + // and move it to the right place. + QRect rect = m_editor->geometry(); + rect.setWidth(newSize); + rect.setX( columnWidth(0) ); + m_editor->setGeometry(rect); +} + +void PropertiesListView::slotDataChanged(const QString &/*id*/, QVariant data) +{ + PLVItem *pItem = static_cast(currentItem()); + pItem->updateData(data); +} + +void PropertiesListView::slotMergeProperties() +{ + for( QListViewItemIterator it( this ); it.current(); ++it ) + { + PLVItem * pItem = static_cast(it.current()); + if (pItem->isEnabled()) + continue; + + pItem->setEnabled(true); + // manually call the updates on the canvas + // and in the list + pItem->updateData(pItem->data()->defaultValue()); + ItemInterface::self()->slotSetData(pItem->id(),pItem->data()->defaultValue()); + } +} + + +void PropertiesListView::slotSetDefaults() +{ + for( QListViewItemIterator it( this ); it.current(); ++it ) + { + PLVItem *pItem = static_cast(it.current()); + ItemInterface::self()->slotSetData(pItem->id(),pItem->data()->defaultValue()); + } +} + + +void PropertiesListView::wheelEvent( QWheelEvent *e ) +{ + QPoint _pos = contentsToViewport(e->pos()); + _pos -= pos(); + _pos.setY( _pos.y()+header()->height() ); + QListViewItem *item = itemAt(_pos); + if ( item && item != dynamic_cast(p_lastItem) ) + { + e->accept(); + if(!item->isSelected()) slotSelectionChanged(item); + } + else KListView::wheelEvent(e); +} + +#include "propertieslistview.moc" + diff --git a/src/gui/propertieslistview.h b/src/gui/propertieslistview.h new file mode 100644 index 0000000..c6ad8f7 --- /dev/null +++ b/src/gui/propertieslistview.h @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PROPERTIESLISTVIEW_H +#define PROPERTIESLISTVIEW_H + +#include +#include + +class CNItemGroup; +class ItemGroup; +class PIEditor; +class PLVItem; +class QPushButton; + +typedef QMap< QString, PLVItem * > PLVItemMap; + +/** +@author Daniel Clarke +@author David Saxton +*/ +class PropertiesListView : public KListView +{ +Q_OBJECT +public: + PropertiesListView( QWidget *parent = 0l, const char *name = 0l ); + ~PropertiesListView(); + +public slots: + /** + * Creates a new set of property items and inserts them into the widget. + */ + void slotCreate( ItemGroup * itemGroup ); + /** + * Updates the set of property items (enables/disables according to whether + * the items have differing values, etc). This will be called by slotCreate, + * and any time new items are selected / unselected. + */ + void slotUpdate( ItemGroup * itemGroup ); + /** + * Removes all property items from the widget. + */ + void slotClear(); + void slotSelectionChanged(QListViewItem *item); + /** + * Whenthe selected items have different values, then the property editor + * for the disagreeing property will have a value taken from one of the + * items, but will also be disabled. This will enable all disabled property + * editors and set the items to the value contained. + */ + void slotMergeProperties(); + void slotSetDefaults(); + +protected slots: + void headerSizeChanged(int section, int oldSize, int newSize); + void slotDataChanged(const QString &id, QVariant data); + void destroyEditor(); + +protected: + virtual void wheelEvent( QWheelEvent *e ); + + PIEditor *m_editor; + QPushButton *m_diffBt; + PLVItem *p_lastItem; + PLVItemMap m_plvItemMap; +}; + +#endif diff --git a/src/gui/sdccoptionswidget.ui b/src/gui/sdccoptionswidget.ui new file mode 100644 index 0000000..218f796 --- /dev/null +++ b/src/gui/sdccoptionswidget.ui @@ -0,0 +1,586 @@ + +SDCCOptionsWidget + + + SDCCOptionsWidget + + + + 0 + 0 + 441 + 377 + + + + SDCC Options + + + + unnamed + + + 0 + + + + tabWidget12 + + + + general + + + Ge&neral + + + + unnamed + + + + kcfg_SDCC_nostdlib + + + Don't search in the standard librar&y directory (--nostdlib) + + + Alt+Y + + + + + kcfg_SDCC_nostdinc + + + Don't search in the standard include directory (--nostdinc) + + + + + + + + kcfg_SDCC_less_pedantic + + + Disa&ble pedantic warnings (--less-pedantic) + + + Alt+B + + + + + kcfg_SDCC_std_c89 + + + Use C&89 standard only (--std-c89) + + + Alt+8 + + + Follow the C89 standard and disable SDCC features that conflict with the standard. + + + + + kcfg_SDCC_std_c99 + + + Use C&99 standard only (--std-c99) + + + Alt+9 + + + + + + Follow the C99 standard and disable SDCC features that conflict with the standard (incomplete support). + + + + + spacer32 + + + Vertical + + + Expanding + + + + 20 + 20 + + + + + + + + code_generation + + + Code Gener&ation + + + + unnamed + + + + kcfg_SDCC_stack_auto + + + Stack auto&matic variables (--stack-auto) + + + Alt+M + + + + + + All functions in the source file will be compiled as reentrant, i.e. the parameters and local variables will be allocated on the stack. If this option is used all source files in the project should be compiled with this option. It automatically implies -int-long-reent and -float-reent. + + + + + kcfg_SDCC_int_long_reent + + + Integer li&braries were compiled as reentrant (--int-long-reent) + + + Alt+B + + + + + + Integer (16 bit) and long (32 bit) libraries have been compiled as reentrant. Note by default these libraries are compiled as non-reentrant. + + + + + kcfg_SDCC_float_reent + + + Floating point librar&y was compiled as reentrant (--float-reent) + + + Alt+Y + + + Floating point library is compiled as reentrant. + + + + + kcfg_SDCC_fommit_frame_pointer + + + Leave out the frame pointer (--fommit-frame-pointer) + + + + + + + + kcfg_SDCC_no_xinit_opt + + + Don't memcpy initialized &xram from code (--no-xinit-opt) + + + Alt+X + + + Will not memcpy initialized data from code space into xdata space. This saves a few bytes in code space if you don't have initialized data. + + + + + kcfg_SDCC_all_callee_saves + + + Callee will &always save registers used (--all-callee-saves) + + + Alt+A + + + + + spacer31 + + + Vertical + + + Expanding + + + + 20 + 20 + + + + + + + + optimization + + + &Optimization + + + + unnamed + + + + kcfg_SDCC_nooverlay + + + Disable overlaying leaf function &auto variables (--nooverlay) + + + Alt+A + + + The compiler will not overlay parameters and local variables of any function, see section Parameters and local variables for more details. + + + + + kcfg_SDCC_nogcse + + + Disable the GCSE optimization (--nogcse) + + + + + + + + kcfg_SDCC_nolabelopt + + + Disable label optimi&zation (--nolabelopt) + + + Alt+Z + + + Will not optimize labels (makes the dumpfiles more readable). + + + + + kcfg_SDCC_noinvariant + + + Disable optimization of invariants (--noinvariant) + + + + + + + + kcfg_SDCC_noinduction + + + Disable loop variable induction (--noinduction) + + + + + + + + kcfg_SDCC_no_peep + + + Disable peep-hole optimization (--&no-peep) + + + Alt+N + + + Disable peep-hole optimization. + + + + + kcfg_SDCC_noloopreverse + + + Disable loop reverse optimization (--noloopreverse) + + + + + + Will not do loop reversal optimization. + + + + + kcfg_SDCC_opt_code_size + + + Opti&mize for compact code (--opt-code-size) + + + Alt+M + + + The compiler will optimize code generation towards compact code, possibly at the expense of code speed. + + + + + kcfg_SDCC_opt_code_speed + + + &Optimize for fast code (--opt-code-speed) + + + Alt+O + + + The compiler will optimize code generation towards fast code, possibly at the expense of code size. + + + + + kcfg_SDCC_peep_asm + + + Ena&ble inline assembly peephole optimization (--peep-asm) + + + Alt+B + + + Pass the inline assembler code through the peep hole optimizer. This can cause unexpected changes to inline assembler code, please go through the peephole optimizer rules defined in the source file tree '<target>/peeph.def' before using this option. + + + + + kcfg_SDCC_nojtbound + + + Don't generate boundary check for &jump tables (--nojtbound) + + + Alt+J + + + + + spacer33 + + + Vertical + + + Expanding + + + + 20 + 20 + + + + + + + + pic16_specific + + + PIC&16 Specific + + + + unnamed + + + + kcfg_SDCC_nodefaultlibs + + + Don't use default libraries (--nodefaultlibs) + + + + + + + + kcfg_SDCC_pno_banksel + + + Don't generate BANKSEL directives (--pno-banksel) + + + + + + + + kcfg_SDCC_pstack_model_large + + + Use large stac&k model (--pstack-model=large) + + + Alt+K + + + + + kcfg_SDCC_debug_xtra + + + Show more debug info in assembl&y output (--debug-xtra) + + + Alt+Y + + + + + kcfg_SDCC_denable_peeps + + + E&xplicit enable of peepholes (--denable-peeps) + + + Alt+X + + + + + kcfg_SDCC_calltree + + + Du&mp call tree in .calltree file (--calltree) + + + Alt+M + + + + + kcfg_SDCC_fstack + + + Ena&ble stack optimizations (--fstack) + + + Alt+B + + + + + kcfg_SDCC_optimize_goto + + + Try to use conditional BRA instead of GOTO (--optimi&ze-goto) + + + Alt+Z + + + + + kcfg_SDCC_optimize_cmp + + + Try to optimize some compares (--optimize-cmp) + + + + + + + + kcfg_SDCC_optimize_df + + + Thorough data flow analyis (resource intensive) (--optimize-df) + + + + + + + + spacer34 + + + Vertical + + + Expanding + + + + 20 + 20 + + + + + + + + + kcfg_MiscSDCCOptions + + + + + textLabel2 + + + Other options: + + + + + spacer4 + + + Vertical + + + Expanding + + + + 20 + 16 + + + + + + + + klineedit.h + + diff --git a/src/gui/settingsdlg.cpp b/src/gui/settingsdlg.cpp new file mode 100644 index 0000000..3b42027 --- /dev/null +++ b/src/gui/settingsdlg.cpp @@ -0,0 +1,386 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "asmformattingwidget.h" +#include "generaloptionswidget.h" +#include "gpasmsettingswidget.h" +#include "logicwidget.h" +#include "picprogrammerconfigwidget.h" +#include "picprogrammer.h" +#include "port.h" +#include "sdccoptionswidget.h" +#include "settingsdlg.h" +#include "src/core/ktlconfig.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Make sure that this value is the same as that in ktechlab.kcfg +const int defaultRefreshRate = 50; + +SettingsDlg::SettingsDlg( QWidget *parent, const char *name, KConfigSkeleton *config ) + : KConfigDialog( parent, name, config ) +{ + m_generalOptionsWidget = new GeneralOptionsWidget( this, "generalOptionsWidget" ); + m_gpasmSettingsWidget = new GpasmSettingsWidget( this, "gpasmSettingsWidget" ); + m_sdccOptionsWidget = new SDCCOptionsWidget( this, "sdccOptionsWidget" ); + m_asmFormattingWidget = new AsmFormattingWidget( this, "asmFormattingWidget" ); + m_logicWidget = new LogicWidget( this, "logicWidget" ); + m_picProgrammerConfigWidget = new PicProgrammerConfigWidget( this, "picProgrammerConfigWidget" ); + + m_pPicProgrammerSettings = new PicProgrammerSettings; + + m_logicWidget->kcfg_LogicOutputHighImpedance->setSuffix( QString(" ") + QChar(0x3a9) ); + m_logicWidget->kcfg_LogicOutputLowImpedance->setSuffix( QString(" ") + QChar(0x3a9) ); + + addPage( m_generalOptionsWidget, i18n("General"), "misc", i18n("General Options") ); + addPage( m_picProgrammerConfigWidget, i18n("Programmer"), "memory", i18n("PIC Programmer") ); + addPage( m_asmFormattingWidget, i18n("Formatter"), "indent_asm", i18n("Assembly Formatter") ); + addPage( m_logicWidget, i18n("Logic"), "logic_or", i18n("Electronic Logic Values") ); + addPage( m_gpasmSettingsWidget, "Gpasm", "convert_to_hex", "gpasm" ); + addPage( m_sdccOptionsWidget, "SDCC", "source_c", "SDCC" ); + + connect( m_generalOptionsWidget->refreshRateSlider, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateRefreshRateLabel(int)) ); + connect( m_picProgrammerConfigWidget->kcfg_PicProgrammerProgram, SIGNAL(activated(const QString &)), this, SLOT(slotUpdatePicProgrammerDescription()) ); + connect( m_picProgrammerConfigWidget->removeButton, SIGNAL(clicked()), this, SLOT(slotRemoveProgrammerConfig()) ); + connect( m_picProgrammerConfigWidget->addButton, SIGNAL(clicked()), this, SLOT(slotAddProgrammerConfig()) ); + + + connect( m_picProgrammerConfigWidget->initCommand, SIGNAL(textChanged(const QString &)), this, SLOT(slotSaveCurrentProgrammerConfig()) ); + connect( m_picProgrammerConfigWidget->readCommand, SIGNAL(textChanged(const QString &)), this, SLOT(slotSaveCurrentProgrammerConfig()) ); + connect( m_picProgrammerConfigWidget->writeCommand, SIGNAL(textChanged(const QString &)), this, SLOT(slotSaveCurrentProgrammerConfig()) ); + connect( m_picProgrammerConfigWidget->verifyCommand, SIGNAL(textChanged(const QString &)), this, SLOT(slotSaveCurrentProgrammerConfig()) ); + connect( m_picProgrammerConfigWidget->blankCheckCommand, SIGNAL(textChanged(const QString &)), this, SLOT(slotSaveCurrentProgrammerConfig()) ); + connect( m_picProgrammerConfigWidget->eraseCommand, SIGNAL(textChanged(const QString &)), this, SLOT(slotSaveCurrentProgrammerConfig()) ); + + + m_generalOptionsWidget->kcfg_GridColor->setEnabled( KTLConfig::showGrid() ); + + m_picProgrammerConfigWidget->kcfg_PicProgrammerPort->insertStringList( Port::ports( Port::ExistsAndRW ) ); + slotUpdatePicProgrammerDescription(); +} + + +SettingsDlg::~SettingsDlg() +{ + delete m_pPicProgrammerSettings; +} + + +void SettingsDlg::show() +{ + KComboBox * combo = m_picProgrammerConfigWidget->kcfg_PicProgrammerProgram; + combo->setEditable( true ); + KConfigDialog::show(); + combo->setEditable( false ); +} + + +void SettingsDlg::slotUpdateRefreshRateLabel( int sliderValue ) +{ + const QString number = QString::number( sliderValueToRefreshRate(sliderValue) ); + switch(sliderValue) + { + case 0: + m_generalOptionsWidget->refreshRateLabel->setText( i18n("Lowest (%1 FPS)").arg(number) ); + break; + case 1: + m_generalOptionsWidget->refreshRateLabel->setText( i18n("Low (%1 FPS)").arg(number) ); + break; + case 2: + m_generalOptionsWidget->refreshRateLabel->setText( i18n("Medium (%1 FPS)").arg(number) ); + break; + case 3: + m_generalOptionsWidget->refreshRateLabel->setText( i18n("High (%1 FPS)").arg(number) ); + break; + case 4: + m_generalOptionsWidget->refreshRateLabel->setText( i18n("Highest (%1 FPS)").arg(number) ); + break; + default: + m_generalOptionsWidget->refreshRateLabel->setText( i18n("Unknown value") ); + break; + } + updateButtons(); +} + + +void SettingsDlg::slotUpdatePicProgrammerDescription() +{ + QString program = m_picProgrammerConfigWidget->kcfg_PicProgrammerProgram->currentText(); + + ProgrammerConfig config = m_pPicProgrammerSettings->config( program ); + QString description = config.description; + + bool customProgrammer = ! m_pPicProgrammerSettings->isPredefined( program ); + + QString executable = config.executable; + if ( executable.isEmpty() ) + executable = program.lower(); + + QString programLocation = KStandardDirs::findExe( executable ); + if ( programLocation.isNull() ) + description.prepend( i18n("%1 cannot be found.
    ").arg( executable ) ); + else + description.prepend( i18n("%1 found: %2
    ").arg( executable ).arg(programLocation) ); + + m_picProgrammerConfigWidget->m_pProgrammerDescription->setText( description ); + m_picProgrammerConfigWidget->removeButton->setEnabled( customProgrammer ); + + KLineEdit * edit; + +#define SETUP_COMMAND( name ) \ + edit = m_picProgrammerConfigWidget->name; \ + edit->setText( config.name ); \ + edit->setEnabled(customProgrammer); \ + QToolTip::add( edit, customProgrammer ? 0 : config.name ) + + SETUP_COMMAND( initCommand ); + SETUP_COMMAND( readCommand ); + SETUP_COMMAND( writeCommand ); + SETUP_COMMAND( verifyCommand ); + SETUP_COMMAND( blankCheckCommand ); + SETUP_COMMAND( eraseCommand ); + +#undef SETUP_COMMAND +} + + +void SettingsDlg::slotSaveCurrentProgrammerConfig() +{ + QString program = m_picProgrammerConfigWidget->kcfg_PicProgrammerProgram->currentText(); + + if ( m_pPicProgrammerSettings->isPredefined( program ) ) + return; + + ProgrammerConfig config; + + config.initCommand = m_picProgrammerConfigWidget->initCommand->text(); + config.readCommand = m_picProgrammerConfigWidget->readCommand->text(); + config.writeCommand = m_picProgrammerConfigWidget->writeCommand->text(); + config.verifyCommand = m_picProgrammerConfigWidget->verifyCommand->text(); + config.blankCheckCommand = m_picProgrammerConfigWidget->blankCheckCommand->text(); + config.eraseCommand = m_picProgrammerConfigWidget->eraseCommand->text(); + + m_pPicProgrammerSettings->saveConfig( program, config ); +} + + +void SettingsDlg::slotRemoveProgrammerConfig() +{ + KComboBox * combo = m_picProgrammerConfigWidget->kcfg_PicProgrammerProgram; + + QString program = combo->currentText(); + + KMessageBox::ButtonCode confirm = (KMessageBox::ButtonCode)KMessageBox::warningContinueCancel( this, i18n("Remove programmer configuration \"%1\"?").arg(program), i18n("Remove \"%1\"").arg(program), i18n("Remove") ); + if ( confirm == KMessageBox::Cancel ) + return; + + m_pPicProgrammerSettings->removeConfig( program ); + combo->removeItem( combo->currentItem() ); + slotUpdatePicProgrammerDescription(); +} + + +class NameValidator : public QValidator +{ + public: + NameValidator( QStringList unallowed ) + : QValidator(0) { + m_unallowed = unallowed; + } + + virtual State validate( QString & input, int & ) const { + return (input.isEmpty() || m_unallowed.contains( input.lower() )) ? Intermediate : Acceptable; + } + + protected: + QStringList m_unallowed; +}; + + +void SettingsDlg::slotAddProgrammerConfig() +{ + KComboBox * combo = m_picProgrammerConfigWidget->kcfg_PicProgrammerProgram; + + QStringList takenNames; + int count = combo->count(); + for ( int i = 0; i < count; ++i ) + takenNames << combo->text(i).lower(); + + NameValidator * nv = new NameValidator( takenNames ); + + bool ok = false; + QString name = KInputDialog::getText( i18n("Configuration Name"), i18n("Name"), 0, &ok, this, 0, nv ); + + delete nv; + + if (!ok) + return; + + ProgrammerConfig config; + config.executable = name.lower(); + + m_pPicProgrammerSettings->saveConfig( name, config ); + + combo->insertItem( name ); + combo->setCurrentItem( count ); + slotUpdatePicProgrammerDescription(); +} + + +int SettingsDlg::refreshRateToSliderValue( int refreshRate ) +{ + switch (refreshRate) + { + case 10: return 0; + case 25: return 1; + case 50: return 2; + case 75: return 3; + case 100: return 4; + default: return -1; + } +} + + +int SettingsDlg::sliderValueToRefreshRate( int sliderValue ) +{ + switch (sliderValue) + { + case 0: return 10; + case 1: return 25; + case 2: return 50; + case 3: return 75; + case 4: return 100; + default: return -1; + } +} + + +void SettingsDlg::updateSettings() +{ + KConfig * config = kapp->config(); + + KConfigSkeleton::ItemInt *item = dynamic_cast(KTLConfig::self()->findItem( "RefreshRate" )); + if ( !item ) + return; + + int newRefreshRate = sliderValueToRefreshRate(m_generalOptionsWidget->refreshRateSlider->value()); + + if ( newRefreshRate != KTLConfig::refreshRate() ) + { + item->setValue(newRefreshRate); + config->setGroup("WorkArea"); + if ( newRefreshRate != defaultRefreshRate ) + config->writeEntry("RefreshRate",newRefreshRate); + else + config->deleteEntry("RefreshRate"); + + emit settingsChanged(); + } + + QTimer::singleShot( 0, this, SLOT(slotUpdateSettings()) ); +} + + +void SettingsDlg::slotUpdateSettings() +{ + KConfig * config = kapp->config(); + + KConfigSkeleton::ItemString * item = dynamic_cast(KTLConfig::self()->findItem( "PicProgrammerProgram" )); + if ( !item ) + return; + + KComboBox * combo = m_picProgrammerConfigWidget->kcfg_PicProgrammerProgram; + QString newProgram = combo->currentText(); + + if ( newProgram != KTLConfig::picProgrammerProgram() ) + { + item->setValue( newProgram ); + config->setGroup( "PicProgramming" ); + if ( newProgram != "picp" ) + config->writeEntry( "PicProgrammerProgram", newProgram ); + else + config->deleteEntry( "PicProgrammerProgram" ); + + emit settingsChanged(); + } + + m_pPicProgrammerSettings->save( config ); + + config->sync(); +} + + +void SettingsDlg::updateWidgets() +{ + m_generalOptionsWidget->refreshRateSlider->setValue( refreshRateToSliderValue( KTLConfig::refreshRate() ) ); + + m_pPicProgrammerSettings->load( kapp->config() ); + + QStringList programmerNames = m_pPicProgrammerSettings->configNames( false ); + + KComboBox * combo = m_picProgrammerConfigWidget->kcfg_PicProgrammerProgram; + combo->clear(); + combo->insertStringList( programmerNames ); + combo->setSizeLimit( programmerNames.size() ); + + QTimer::singleShot( 0, this, SLOT(slotUpdateWidgets()) ); +} + + +void SettingsDlg::slotUpdateWidgets() +{ + KComboBox * combo = m_picProgrammerConfigWidget->kcfg_PicProgrammerProgram; + + combo->setCurrentText( KTLConfig::picProgrammerProgram() ); + slotUpdatePicProgrammerDescription(); +} + + +void SettingsDlg::updateWidgetsDefault() +{ + m_generalOptionsWidget->refreshRateSlider->setValue( refreshRateToSliderValue( defaultRefreshRate ) ); + slotUpdatePicProgrammerDescription(); +} + + +bool SettingsDlg::hasChanged() +{ + if ( sliderValueToRefreshRate( m_generalOptionsWidget->refreshRateSlider->value() ) == KTLConfig::refreshRate() ) + return KConfigDialog::hasChanged(); + return true; +} + + +bool SettingsDlg::isDefault() +{ + if ( sliderValueToRefreshRate( m_generalOptionsWidget->refreshRateSlider->value() ) == defaultRefreshRate ) + return KConfigDialog::isDefault(); + + return false; +} + + +#include "settingsdlg.moc" diff --git a/src/gui/settingsdlg.h b/src/gui/settingsdlg.h new file mode 100644 index 0000000..1fbf966 --- /dev/null +++ b/src/gui/settingsdlg.h @@ -0,0 +1,69 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef SETTINGSDLG_H +#define SETTINGSDLG_H + +#include +#include + +class AsmFormattingWidget; +class GeneralOptionsWidget; +class GpasmSettingsWidget; +class LogicWidget; +class PicProgrammerConfigWidget; +class PicProgrammerSettings; +class SDCCOptionsWidget; + + +/** +@author David Saxton +*/ +class SettingsDlg : public KConfigDialog +{ + Q_OBJECT + public: + SettingsDlg( QWidget *parent, const char *name, KConfigSkeleton *config ); + ~SettingsDlg(); + + static int refreshRateToSliderValue( int refreshRate ); + static int sliderValueToRefreshRate( int sliderValue ); + + virtual void show(); + + public slots: + void slotUpdateRefreshRateLabel( int sliderValue ); + void slotUpdatePicProgrammerDescription(); + void slotAddProgrammerConfig(); + void slotRemoveProgrammerConfig(); + void slotSaveCurrentProgrammerConfig(); + + protected slots: + void slotUpdateSettings(); + void slotUpdateWidgets(); + + protected: + virtual void updateSettings(); + virtual void updateWidgets(); + virtual void updateWidgetsDefault(); + virtual bool hasChanged(); + virtual bool isDefault(); + + PicProgrammerSettings * m_pPicProgrammerSettings; + + GeneralOptionsWidget * m_generalOptionsWidget; + GpasmSettingsWidget * m_gpasmSettingsWidget; + SDCCOptionsWidget * m_sdccOptionsWidget; + AsmFormattingWidget * m_asmFormattingWidget; + LogicWidget * m_logicWidget; + PicProgrammerConfigWidget * m_picProgrammerConfigWidget; +}; + +#endif diff --git a/src/gui/symbolviewer.cpp b/src/gui/symbolviewer.cpp new file mode 100644 index 0000000..74d54e1 --- /dev/null +++ b/src/gui/symbolviewer.cpp @@ -0,0 +1,218 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "config.h" +#ifndef NO_GPSIM + +#include "gpsimprocessor.h" +#include "symbolviewer.h" + +#include +#include +#include +#include +#include +#include + +#include + +static const int NAME_COLUMN = 0; +static const int VALUE_COLUMN = 1; + + +//BEGIN class SymbolViewerItem +SymbolViewerItem::SymbolViewerItem( SymbolViewer * symbolViewer, RegisterInfo * registerInfo ) + : KListViewItem( symbolViewer->symbolList() ) +{ + assert(registerInfo); + m_pRegisterInfo = registerInfo; + m_pSymbolViewer = symbolViewer; + + setText( NAME_COLUMN, m_pRegisterInfo->name() ); +// setText( TYPE_COLUMN, RegisterInfo::toString( m_pRegisterInfo->type() ) ); + radixChanged(); // force update of displayed string + + connect( m_pRegisterInfo, SIGNAL(valueChanged(unsigned)), this, SLOT(valueChanged(unsigned)) ); + connect( m_pSymbolViewer, SIGNAL(valueRadixChanged(SymbolViewer::Radix)), this, SLOT(radixChanged()) ); + +} + + +void SymbolViewerItem::valueChanged( unsigned newValue ) +{ + setText( VALUE_COLUMN, m_pSymbolViewer->toDisplayString( newValue ) ); +} + + +void SymbolViewerItem::radixChanged() +{ + valueChanged( m_pRegisterInfo->value() ); +} +//END class SymbolViewerItem + + + +//BEGIN class SymbolView +SymbolViewer * SymbolViewer::m_pSelf = 0l; +SymbolViewer * SymbolViewer::self( KateMDI::ToolView * parent ) +{ + if (!m_pSelf) + { + assert (parent); + m_pSelf = new SymbolViewer(parent); + } + return m_pSelf; +} + +SymbolViewer::SymbolViewer( KateMDI::ToolView * parent ) + : QWidget( (QWidget*)parent ) +{ + QGridLayout * grid = new QGridLayout( this, 1, 1, 0, 6 ); + + m_pSymbolList = new KListView(this); + grid->addMultiCellWidget( m_pSymbolList, 0, 0, 0, 1 ); + + grid->addWidget( new QLabel( i18n("Value radix:"), this ), 1, 0 ); + + m_pRadixCombo = new KComboBox( false, this ); + grid->addWidget( m_pRadixCombo, 1, 1 ); + m_pRadixCombo->insertItem( i18n("Binary") ); + m_pRadixCombo->insertItem( i18n("Octal") ); + m_pRadixCombo->insertItem( i18n("Decimal") ); + m_pRadixCombo->insertItem( i18n("Hexadecimal") ); + m_valueRadix = Decimal; + m_pRadixCombo->setCurrentItem(2); + connect( m_pRadixCombo, SIGNAL(activated(int)), this, SLOT(selectRadix(int)) ); + + m_pGpsim = 0l; + m_pCurrentContext = 0l; + + m_pSymbolList->addColumn( i18n("Name") ); + m_pSymbolList->addColumn( i18n("Value") ); + m_pSymbolList->setFullWidth(true); + m_pSymbolList->setAllColumnsShowFocus( true ); +} + + +SymbolViewer::~SymbolViewer() +{ +} + + +void SymbolViewer::saveProperties( KConfig * config ) +{ + QString oldGroup = config->group(); + + config->setGroup( "SymbolEditor" ); + config->writeEntry( "Radix", m_valueRadix ); + + config->setGroup( oldGroup ); +} + + +void SymbolViewer::readProperties( KConfig * config ) +{ + QString oldGroup = config->group(); + + config->setGroup( "SymbolEditor" ); + m_valueRadix = (SymbolViewer::Radix)config->readNumEntry( "Radix", Decimal ); + + int pos = 4; + switch ( m_valueRadix ) + { + case Binary: + pos--; + case Octal: + pos--; + case Decimal: + pos--; + case Hexadecimal: + pos--; + } + m_pRadixCombo->setCurrentItem( pos ); + + config->setGroup( oldGroup ); +} + + +void SymbolViewer::setContext( GpsimProcessor * gpsim ) +{ + RegisterSet * registerSet = gpsim ? gpsim->registerMemory() : 0l; + + if ( registerSet == m_pCurrentContext ) + return; + + m_pSymbolList->clear(); + m_pGpsim = gpsim; + m_pCurrentContext = registerSet; + + if (!m_pCurrentContext) + return; + + connect( gpsim, SIGNAL(destroyed()), m_pSymbolList, SLOT(clear()) ); + + unsigned count = m_pCurrentContext->size(); + for ( unsigned i = 0; i < count; ++i ) + { + RegisterInfo * reg = m_pCurrentContext->fromAddress(i); + + if ( (reg->type() == RegisterInfo::Generic) || + (reg->type() == RegisterInfo::Invalid) ) + continue; + + new SymbolViewerItem( this, reg ); + } +} + + +void SymbolViewer::selectRadix( int selectIndex ) +{ + if ( (selectIndex<0) || (selectIndex>3) ) + { + kdWarning() << k_funcinfo << "Invalid select position for radix: " << selectIndex << endl; + return; + } + + Radix radii[] = { Binary, Octal, Decimal, Hexadecimal }; + Radix newRadix = radii[selectIndex]; + + if ( newRadix == m_valueRadix ) + return; + + m_valueRadix = newRadix; + + emit valueRadixChanged(m_valueRadix); +} + + +QString SymbolViewer::toDisplayString( unsigned value ) const +{ + switch ( m_valueRadix ) + { + case Binary: + return QString::number( value, 2 ).rightJustify( 8, '0', false ); + + case Octal: + return "0" + QString::number( value, 8 ); + + case Decimal: + return QString::number( value, 10 ); + + case Hexadecimal: + return "0x" + QString::number( value, 16 ); + } + + return "?"; +} +//END class SymbolView + +#include "symbolviewer.moc" + +#endif diff --git a/src/gui/symbolviewer.h b/src/gui/symbolviewer.h new file mode 100644 index 0000000..9a09cb6 --- /dev/null +++ b/src/gui/symbolviewer.h @@ -0,0 +1,103 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "config.h" +#ifndef NO_GPSIM + +#ifndef SYMBOLVIEWER_H +#define SYMBOLVIEWER_H + +#include +#include + +class KComboBox; +class RegisterInfo; +class RegisterSet; +class SymbolViewer; +namespace KateMDI { class ToolView; } + + +/** +@author David Saxton +*/ +class SymbolViewer : public QWidget +{ + Q_OBJECT + public: + static SymbolViewer * self( KateMDI::ToolView * parent = 0l ); + static QString toolViewIdentifier() { return "SymbolViewer"; } + ~SymbolViewer(); + + enum Radix + { + Binary = 2, + Octal = 8, + Decimal = 10, + Hexadecimal = 16 + }; + + Radix valueRadix() const { return m_valueRadix; } + + KListView * symbolList() const { return m_pSymbolList; } + /** + * Write the current properties (such as currently selected radix) to + * the config. + */ + void saveProperties( KConfig * config ); + /** + * Reads the properties (such as the last selected radix) from the + * config file. + */ + void readProperties( KConfig * config ); + + void setContext( GpsimProcessor * gpsim ); + /** + * Converts the value to a string for display according to the currently + * selected radix. + */ + QString toDisplayString( unsigned value ) const; + + signals: + void valueRadixChanged( SymbolViewer::Radix newRadix ); + + public slots: + void selectRadix( int selectIndex ); + + protected: + QGuardedPtr m_pGpsim; + RegisterSet * m_pCurrentContext; + KListView * m_pSymbolList; + Radix m_valueRadix; + + private: + SymbolViewer( KateMDI::ToolView * parent ); + static SymbolViewer * m_pSelf; + KComboBox * m_pRadixCombo; +}; + + +class SymbolViewerItem : public QObject, public KListViewItem +{ + Q_OBJECT + public: + SymbolViewerItem( SymbolViewer * symbolViewer, RegisterInfo * registerInfo ); + + public slots: + void valueChanged( unsigned newValue ); + void radixChanged(); + + protected: + RegisterInfo * m_pRegisterInfo; + SymbolViewer * m_pSymbolViewer; +}; + +#endif + +#endif diff --git a/src/icndocument.cpp b/src/icndocument.cpp new file mode 100644 index 0000000..d220765 --- /dev/null +++ b/src/icndocument.cpp @@ -0,0 +1,1385 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasmanipulator.h" +#include "component.h" +#include "connector.h" +#include "conrouter.h" +#include "cnitemgroup.h" +#include "ecnode.h" +#include "flowcontainer.h" +#include "fpnode.h" +#include "icndocument.h" +#include "icnview.h" +#include "itemdocumentdata.h" +#include "itemlibrary.h" +#include "ktechlab.h" +#include "nodegroup.h" + +#include +#include +#include +#include + +ICNDocument::ICNDocument( const QString &caption, KTechlab *ktechlab, const char *name ) + : ItemDocument( caption, ktechlab, name ), + m_cells(0l) +{ + m_canvas->retune(48); + m_selectList = new CNItemGroup(this); + + createCellMap(); + + m_cmManager->addManipulatorInfo( CMItemMove::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMAutoConnector::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMManualConnector::manipulatorInfo() ); +} + + +ICNDocument::~ICNDocument() +{ + m_bDeleted = true; + + // Go to hell, QCanvas. I'm in charge of what gets deleted. + QCanvasItemList all = m_canvas->allItems(); + const QCanvasItemList::Iterator end = all.end(); + for ( QCanvasItemList::Iterator it= all.begin(); it != end; ++it ) + (*it)->setCanvas(0l); + + // Remove all items from the canvas + selectAll(); + deleteSelection(); + + // Delete anything that got through the above couple of lines + ConnectorList connectorsToDelete = m_connectorList; + const ConnectorList::iterator connectorListEnd = connectorsToDelete.end(); + for ( ConnectorList::iterator it = connectorsToDelete.begin(); it != connectorListEnd; ++it ) + delete *it; + + NodeList nodesToDelete = m_nodeList; + const NodeList::iterator nodeListEnd = nodesToDelete.end(); + for ( NodeList::iterator it = nodesToDelete.begin(); it != nodeListEnd; ++it ) + delete *it; + + GuardedNodeGroupList ngToDelete = m_nodeGroupList; + const GuardedNodeGroupList::iterator nglEnd = ngToDelete.end(); + for ( GuardedNodeGroupList::iterator it = ngToDelete.begin(); it != nglEnd; ++it ) + delete *it; + + delete m_cells; + m_cells = 0l; + delete m_selectList; + m_selectList = 0l; +} + + +View *ICNDocument::createView( ViewContainer *viewContainer, uint viewAreaId, const char *name ) +{ + ICNView *icnView = new ICNView( this, viewContainer, viewAreaId, name ); + handleNewView(icnView); + return icnView; +} + + +ItemGroup* ICNDocument::selectList() const +{ + return m_selectList; +} + + +void ICNDocument::fillContextMenu( const QPoint &pos ) +{ + ItemDocument::fillContextMenu(pos); + slotInitItemActions( dynamic_cast(m_selectList->activeItem()) ); +} + + +CNItem* ICNDocument::cnItemWithID( const QString &id ) +{ + return dynamic_cast(itemWithID(id)); +} + + +Node *ICNDocument::nodeWithID( const QString &id ) +{ + const NodeList::iterator end = m_nodeList.end(); + for ( NodeList::iterator it = m_nodeList.begin(); it != end; ++it ) + { + if ( (*it)->id() == id ) + return *it; + } + return 0L; +} + + +Connector *ICNDocument::connectorWithID( const QString &id ) +{ + const ConnectorList::iterator end = m_connectorList.end(); + for ( ConnectorList::iterator it = m_connectorList.begin(); it != end; ++it ) + { + if ( (*it)->id() == id ) + return *it; + } + return 0L; +} + + +FlowContainer *ICNDocument::flowContainer( const QPoint &pos ) +{ + QCanvasItemList collisions = m_canvas->collisions(pos); + FlowContainer *flowContainer = 0l; + int currentLevel = -1; + const QCanvasItemList::iterator end = collisions.end(); + for ( QCanvasItemList::iterator it = collisions.begin(); it != end; ++it ) + { + if ( FlowContainer *container = dynamic_cast(*it) ) + { + if ( container->level() > currentLevel && !m_selectList->contains(container) ) + { + currentLevel = container->level(); + flowContainer = container; + } + } + } + return flowContainer; +} + + +bool ICNDocument::canConnect( QCanvasItem *qcanvasItem1, QCanvasItem *qcanvasItem2 ) const +{ + // Rough outline of what can and can't connect: + // * At most three connectors to a node + // * Can't have connectors going between different levels (e.g. can't have + // a connector coming outside a FlowContainer from inside). + // * Can't have more than one route between any two nodes + // * In all connections between nodes, must have at least one input and one + // output node at the ends. + + Node *startNode = dynamic_cast(qcanvasItem1); + Node *endNode = dynamic_cast(qcanvasItem2); + + if ( (startNode && startNode->numCon( true, false ) > 2) || (endNode && endNode->numCon( true, false ) > 2) ) + return false; + + + Connector *startConnector = dynamic_cast(qcanvasItem1); + Connector *endConnector = dynamic_cast(qcanvasItem2); + + // Can't have T- or I- junction in PinMapEditor document + if ( type() == Document::dt_pinMapEditor && (startConnector || endConnector) ) + return false; + + // Can't have I-junction in flowcode document + if ( type() == Document::dt_flowcode && startConnector && endConnector ) + return false; + + + //BEGIN Change connectors to nodes + Node * startNode1 = 0l; + Node * startNode2 = 0l; + if (startConnector) + { + startNode1 = startConnector->startNode(); + startNode2 = startConnector->endNode(); + + if ( !startNode1 || !startNode2 ) + return false; + } + else if (!startNode) + return false; + + Node * endNode1 = 0l; + Node * endNode2 = 0l; + if (endConnector) + { + endNode1 = endConnector->startNode(); + endNode2 = endConnector->endNode(); + + if ( !endNode1 || !endNode2 ) + return false; + } + else if ( !endNode ) + return false; + + Node * start[3]; + start[0] = startNode; + start[1] = startNode1; + start[2] = startNode2; + + Node * end[3]; + end[0] = endNode; + end[1] = endNode1; + end[2] = endNode2; + //END Change connectors to nodes + + + //BEGIN Check nodes aren't already connected + for ( unsigned i = 0; i < 3; i++ ) + { + for ( unsigned j = 0; j < 3; j++ ) + { + if ( start[i] && end[j] && start[i]->isConnected(end[j]) ) + return false; + } + } + //END Check nodes aren't already connected together + + + //BEGIN Check we have appropriate input and output allowance + if ( type() == Document::dt_flowcode ) + { + if ( startNode1 && startNode2 && endNode1 && endNode2 ) + { + // Can't have I-configuration + return false; + } + + if ( startNode && endNode ) + { + // Nice and easy straight line to check + + if ( !startNode->acceptInput() && !endNode->acceptInput() ) + return false; + + if ( !startNode->acceptOutput() && !endNode->acceptOutput() ) + return false; + } + + else + { + // We're in a T-configuration, we can only make this if the base of + // the T is an output + Node * base = startNode ? startNode : endNode; + if ( !base->acceptOutput() ) + return false; + } + } + //END Check we have appropriate input and output allowance + + + //BEGIN Simple level check + for ( unsigned i = 0; i < 3; i++ ) + { + for ( unsigned j = 0; j < 3; j++ ) + { + if ( start[i] && end[j] && start[i]->level() != end[j]->level() ) + return false; + } + } + //END Simple level check + + + //BEGIN Advanced level check + CNItem * startParentItem[3]; + for ( unsigned i = 0; i < 3; i++ ) + startParentItem[i] = start[i] ? start[i]->parentItem() : 0l; + + CNItem * endParentItem[3]; + for ( unsigned i = 0; i < 3; i++ ) + endParentItem[i] = end[i] ? end[i]->parentItem() : 0l; + + Item * container[6] = {0l}; + + for ( unsigned i = 0; i < 3; i++ ) + { + if (startParentItem[i]) + { + int dl = start[i]->level() - startParentItem[i]->level(); + if ( dl == 0 ) + container[i] = startParentItem[i]->parentItem(); + else if ( dl == 1 ) + container[i] = startParentItem[i]; + else + kdError() << k_funcinfo << " start, i="<removeConnector(); + + if (con1b) + con1b->removeConnector(); + + if (con2a) + con2a->removeConnector(); + + if (con2b) + con2b->removeConnector(); + + newNode1->removeNode(); + newNode2->removeNode(); + + flushDeleteList(); + return 0l; + } + + con1a->setRoutePoints( *oldCon1Points.at(0), con1UsedManual ); + con1b->setRoutePoints( *oldCon1Points.at(1), con1UsedManual ); + + con2a->setRoutePoints( *oldCon2Points.at(0), con2UsedManual ); + con2b->setRoutePoints( *oldCon2Points.at(1), con2UsedManual ); + + QPointList autoPoints; + if (!pointList) + { + addAllItemConnectorPoints(); + ConRouter cr(this); + cr.mapRoute( pos1.x(), pos1.y(), pos2.x(), pos2.y() ); + autoPoints = cr.pointList(false); + pointList = &autoPoints; + } + newCon->setRoutePoints(*pointList,true); + + + // Avoid flicker: tell them to update their draw lists now + con1->updateConnectorPoints(false); + con2->updateConnectorPoints(false); + newCon->updateDrawList(); + con1a->updateDrawList(); + con1b->updateDrawList(); + con2a->updateDrawList(); + con2b->updateDrawList(); + + + // Now it's safe to remove the connectors + con1->removeConnector(); + con2->removeConnector(); + + flushDeleteList(); + + deleteNodeGroup(node1a); + deleteNodeGroup(node1b); + deleteNodeGroup(node2a); + deleteNodeGroup(node2b); + NodeGroup *ng = createNodeGroup(newNode1); + ng->addNode( newNode2, true ); + ng->init(); + + return newCon; +} + + +NodeGroup* ICNDocument::createNodeGroup( Node *node ) +{ + if ( !node || node->isChildNode() ) { + return 0l; + } + + const GuardedNodeGroupList::iterator end = m_nodeGroupList.end(); + for ( GuardedNodeGroupList::iterator it = m_nodeGroupList.begin(); it != end; ++it ) + { + if ( *it && (*it)->contains(node) ) { + return *it; + } + } + + NodeGroup *group = new NodeGroup(this); + m_nodeGroupList += group; + group->addNode( node, true ); + + return group; +} + + +bool ICNDocument::deleteNodeGroup( Node *node ) +{ + if ( !node || node->isChildNode() ) { + return false; + } + + const GuardedNodeGroupList::iterator end = m_nodeGroupList.end(); + for ( GuardedNodeGroupList::iterator it = m_nodeGroupList.begin(); it != end; ++it ) + { + if ( *it && (*it)->contains(node) ) + { + delete *it; + m_nodeGroupList.remove(it); + return true; + } + } + + return false; +} + + +void ICNDocument::slotRequestAssignNG() +{ + requestEvent( ItemDocumentEvent::UpdateNodeGroups ); +} + + +void ICNDocument::slotAssignNodeGroups() +{ + const GuardedNodeGroupList::iterator nglEnd = m_nodeGroupList.end(); + for ( GuardedNodeGroupList::iterator it = m_nodeGroupList.begin(); it != nglEnd; ++it ) + delete *it; + m_nodeGroupList.clear(); + + const NodeList::iterator end = m_nodeList.end(); + for ( NodeList::iterator it = m_nodeList.begin(); it != end; ++it ) + { + NodeGroup *ng = createNodeGroup(*it); + if (ng) + ng->init(); + } + + // We've destroyed the old node groups, so any collapsed flowcontainers + // containing new node groups need to update them to make them invisible. + const ItemList::const_iterator itemListEnd = m_itemList.end(); + for ( ItemList::const_iterator it = m_itemList.begin(); it != itemListEnd; ++it ) + { + if ( FlowContainer * fc = dynamic_cast((Item*)*it) ) + fc->updateContainedVisibility(); + } +} + + +void ICNDocument::getTranslatable( const ItemList & itemList, ConnectorList * fixedConnectors, ConnectorList * translatableConnectors, NodeGroupList * translatableNodeGroups ) +{ + ConnectorList tempCL1; + if ( !fixedConnectors ) + fixedConnectors = &tempCL1; + + ConnectorList tempCL2; + if ( !translatableConnectors ) + translatableConnectors = &tempCL2; + + NodeGroupList tempNGL; + if ( !translatableNodeGroups ) + translatableNodeGroups = &tempNGL; + + // We record the connectors attached to the items, and + // the number of times an item in the list is connected to + // it - i.e. 1 or 2. For those with 2, it is safe to update their + // route as it simply involves shifting the route + typedef QMap< Connector*, int > ConnectorMap; + ConnectorMap fixedConnectorMap; + + // This list of nodes is built up, used for later in determining fixed NodeGroups + NodeList itemNodeList; + { + const ItemList::const_iterator itemListEnd = itemList.end(); + for ( ItemList::const_iterator it = itemList.begin(); it != itemListEnd; ++it ) + { + CNItem *cnItem = dynamic_cast((Item*)*it); + if ( !cnItem || !cnItem->canvas() ) + continue; + + NodeMap nodeMap = cnItem->nodeMap(); + const NodeMap::iterator nlEnd = nodeMap.end(); + for ( NodeMap::iterator nlIt = nodeMap.begin(); nlIt != nlEnd; ++nlIt ) + { + itemNodeList.append(nlIt.data().node); + } + + ConnectorList conList = cnItem->connectorList(); + conList.remove((Connector*)0l); + const ConnectorList::iterator clEnd = conList.end(); + for ( ConnectorList::iterator clit = conList.begin(); clit != clEnd; ++clit ) + { + ConnectorMap::iterator cit = fixedConnectorMap.find(*clit); + if ( cit != fixedConnectorMap.end() ) { + cit.data()++; + } else { + fixedConnectorMap[*clit] = 1; + } + } + } + } + + // We now look through the NodeGroups to see if we have all the external + // nodes for a given nodeGroup - if so, then the connectors in the fixed + // connectors are ok to be moved + ConnectorList fixedNGConnectors; + { + translatableNodeGroups->clear(); + const GuardedNodeGroupList::const_iterator end = m_nodeGroupList.end(); + for ( GuardedNodeGroupList::const_iterator it = m_nodeGroupList.begin(); it != end; ++it ) + { + NodeGroup *ng = *it; + if (!ng) + continue; + + NodeList externalNodeList = ng->externalNodeList(); + const NodeList::iterator itemNodeListEnd = itemNodeList.end(); + for ( NodeList::iterator inlIt = itemNodeList.begin(); inlIt != itemNodeListEnd; ++inlIt ) + externalNodeList.remove(*inlIt); + + if ( externalNodeList.isEmpty() ) + { + translatableNodeGroups->append(ng); + + const ConnectorList ngConnectorList = ng->connectorList(); + const ConnectorList::const_iterator ngConnectorListEnd = ngConnectorList.end(); + for ( ConnectorList::const_iterator ngclIt = ngConnectorList.begin(); ngclIt != ngConnectorListEnd; ++ngclIt ) + { + if (*ngclIt) + fixedNGConnectors += *ngclIt; + } + } + } + } + + translatableConnectors->clear(); + const ConnectorMap::iterator fcEnd = fixedConnectorMap.end(); + for ( ConnectorMap::iterator it = fixedConnectorMap.begin(); it != fcEnd; ++it ) + { + // We allow it to be fixed if it is connected to two of the CNItems in the + // select list, or is connected to itself (hence only appears to be connected to one, + // but is fixed anyway + Node *startNode = it.key()->endNode(); + Node *endNode = it.key()->startNode(); + if ( (it.data() > 1) || + (startNode && endNode && startNode->parentItem() == endNode->parentItem()) ) + { + translatableConnectors->append( const_cast(it.key()) ); + } + else if ( !fixedNGConnectors.contains(it.key()) && !fixedConnectors->contains(it.key()) ) + { + fixedConnectors->append(it.key()); + } + } +} + + +void ICNDocument::addCPenalty( int x, int y, int score ) +{ + if ( isValidCellReference(x,y) ) + { + (*m_cells)[x][y].Cpenalty += score; + } +} + + +void ICNDocument::createCellMap() +{ + unsigned newCellsX = QMAX( canvas()->width()/cellSize, 1 ); + unsigned newCellsY = QMAX( canvas()->height()/cellSize, 1 ); + + if ( m_cells && newCellsX == m_cellsX && newCellsY == m_cellsY ) + return; + + const ItemList::iterator ciEnd = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != ciEnd; ++it ) + { + CNItem *cnItem = dynamic_cast((Item*)(*it)); + if (cnItem) + cnItem->updateConnectorPoints(false); + } + const ConnectorList::iterator conEnd = m_connectorList.end(); + for ( ConnectorList::iterator it = m_connectorList.begin(); it != conEnd; ++it ) + { + (*it)->updateConnectorPoints(false); + } + + delete m_cells; + m_cellsX = newCellsX; + m_cellsY = newCellsY; + m_cells = new Cells( m_cellsX, m_cellsY ); + + for ( ConnectorList::iterator it = m_connectorList.begin(); it != conEnd; ++it ) + (*it)->updateConnectorPoints(true); +} + + +int ICNDocument::gridSnap( int pos ) +{ + return pos-(pos%8)+4; +// return int((floor(pos/8))*8)+4; +} + +QPoint ICNDocument::gridSnap( const QPoint &pos ) +{ + return QPoint( gridSnap( pos.x() ), gridSnap( pos.y() ) ); +} + + +void ICNDocument::appendDeleteList( QCanvasItem *qcanvasItem ) +{ + if ( !qcanvasItem || m_itemDeleteList.findIndex(qcanvasItem) != -1 ) { + return; + } + + m_itemDeleteList.append(qcanvasItem); + + if ( qcanvasItem->rtti() == ItemDocument::RTTI::Node ) + { + Node *node = dynamic_cast(qcanvasItem); + node->removeNode(); + } + else if ( qcanvasItem->rtti() == ItemDocument::RTTI::CNItem || + qcanvasItem->rtti() == ItemDocument::RTTI::DrawPart ) + { + Item *item = dynamic_cast(qcanvasItem); + item->removeItem(); + } + else if ( qcanvasItem->rtti() == ItemDocument::RTTI::Connector || + qcanvasItem->rtti() == ItemDocument::RTTI::ConnectorLine ) + { + Connector *connector = dynamic_cast(qcanvasItem); + if (!connector) + connector = (dynamic_cast(qcanvasItem))->parent(); + connector->removeConnector(); + } + else + { + kdDebug() << k_funcinfo << "unrecognised QCanvasItem rtti " << QString::number(qcanvasItem->rtti()) << endl; + } +} + +void ICNDocument::flushDeleteList() +{ + // Remove duplicate items in the delete list + QCanvasItemList::iterator end = m_itemDeleteList.end(); + for ( QCanvasItemList::iterator it = m_itemDeleteList.begin(); it != end; ++it ) + { + if ( *it && m_itemDeleteList.contains(*it) > 1 ) { + *it = 0l; + } + } + m_itemDeleteList.remove(0l); + + end = m_itemDeleteList.end(); + for ( QCanvasItemList::iterator it = m_itemDeleteList.begin(); it != end; ++it ) + { + QCanvasItem *qcanvasItem = *it; + m_selectList->removeQCanvasItem(*it); + + if ( Item *item = dynamic_cast(qcanvasItem) ) + m_itemList.remove(item); + + else if ( qcanvasItem->rtti() == ItemDocument::RTTI::Node ) + m_nodeList.remove( dynamic_cast(qcanvasItem) ); + + else if ( qcanvasItem->rtti() == ItemDocument::RTTI::Connector ) + m_connectorList.remove( dynamic_cast(qcanvasItem) ); + + else + kdError() << k_funcinfo << "Unknown qcanvasItem! "<setCanvas(0l); + + delete qcanvasItem; + *it = 0l; + } + +// // Check connectors for merging + bool doneJoin = false; + const NodeList::iterator nlEnd = m_nodeList.end(); + for ( NodeList::iterator it = m_nodeList.begin(); it != nlEnd; ++it ) + { + (*it)->removeNullConnectors(); + int conCount = (*it)->inputConnectorList().count() + (*it)->outputConnectorList().count(); + if ( conCount == 2 && !(*it)->parentItem() ) + { + if ( joinConnectors(*it) ) + doneJoin = true; + } + } + + if (doneJoin) + flushDeleteList(); + + requestRerouteInvalidatedConnectors(); +} + + + +bool ICNDocument::joinConnectors( Node *node ) +{ + // We don't want to destroy the node if it has a parent + if ( node->parentItem() ) + return false; + + node->removeNullConnectors(); + + int conCount = node->inputConnectorList().count() + node->outputConnectorList().count(); + if ( conCount != 2 ) + return false; + + Connector *con1, *con2; + Node *startNode, *endNode; + QPointList conPoints; + + + if ( node->inputConnectorList().count() == 0 ) + { + // Both connectors emerge from node - output - i.e. node is pure start node + con1 = *node->outputConnectorList().at(0); + con2 = *node->outputConnectorList().at(1); + if ( con1 == con2 ) { + return false; + } + + startNode = con1->endNode(); + endNode = con2->endNode(); + conPoints = con1->connectorPoints(true) + con2->connectorPoints(false); + } + else if ( node->inputConnectorList().count() == 1 ) + { + // Ont input, one output + con1 = *node->inputConnectorList().at(0); + con2 = *node->outputConnectorList().at(0); + if ( con1 == con2 ) { + return false; + } + + startNode = con1->startNode(); + endNode = con2->endNode(); + conPoints = con1->connectorPoints(false) + con2->connectorPoints(false); + } + else + { + // Both input - i.e. node is pure end node + con1 = *node->inputConnectorList().at(0); + con2 = *node->inputConnectorList().at(1); + if ( con1 == con2 ) { + return false; + } + + startNode = con1->startNode(); + endNode = con2->startNode(); + conPoints = con1->connectorPoints(false) + con2->connectorPoints(true); + } + + if ( !startNode || !endNode ) + return false; + + Connector *newCon = endNode->createInputConnector(startNode); + if (!newCon) + return false; + + startNode->addOutputConnector(newCon); + newCon->setRoutePoints( conPoints, con1->usesManualPoints() || con2->usesManualPoints() ); + + // Avoid flicker: update draw lists now + con1->updateConnectorPoints(false); + con2->updateConnectorPoints(false); + newCon->updateDrawList(); + + node->removeNode(); + con1->removeConnector(); + con2->removeConnector(); + + return true; +} + + +bool ICNDocument::registerItem( QCanvasItem *qcanvasItem ) +{ + if (!qcanvasItem) + return false; + + if ( !ItemDocument::registerItem(qcanvasItem) ) + { + switch (qcanvasItem->rtti()) + { + case ItemDocument::RTTI::Node: + { + Node *node = (Node*)qcanvasItem; + m_nodeList.append(node); + connect( node, SIGNAL(removed(Node*)), this, SLOT(requestRerouteInvalidatedConnectors()) ); + emit nodeAdded(node); + break; + } + case ItemDocument::RTTI::Connector: + { + Connector *connector = dynamic_cast(qcanvasItem); + m_connectorList.append(connector); + connect( connector, SIGNAL(removed(Connector*)), this, SLOT(requestRerouteInvalidatedConnectors()) ); + emit connectorAdded(connector); + break; + } + default: + { + kdError() << k_funcinfo << "Unrecognised item rtti"<isEmpty() ) + return; + + ItemDocumentData data( type() ); + + // We only want to copy the connectors who have all ends attached to something in the selection + ConnectorList connectorList = m_selectList->connectors(false); + + typedef QMap< Node*, ConnectorList > NCLMap; + NCLMap nclMap; + + ConnectorList::iterator end = connectorList.end(); + for ( ConnectorList::iterator it = connectorList.begin(); it != end; ++it ) + { + Node *startNode = (*it)->startNode(); + if ( startNode && !startNode->isChildNode() ) + nclMap[startNode].append(*it); + + Node *endNode = (*it)->endNode(); + if ( endNode && !endNode->isChildNode() ) + nclMap[endNode].append(*it); + } + + NodeList nodeList; + // Remove those connectors (and nodes) which are dangling on an orphan node + NCLMap::iterator nclEnd = nclMap.end(); + for ( NCLMap::iterator it = nclMap.begin(); it != nclEnd; ++it ) + { + if ( it.data().size() > 1 ) + nodeList.append(it.key()); + + else if ( it.data().size() > 0 ) + connectorList.remove( it.data().at(0) ); + } + + data.addItems( m_selectList->items(false) ); + data.addNodes( nodeList ); + data.addConnectors( connectorList ); + + KApplication::clipboard()->setText( data.toXML(), QClipboard::Clipboard ); +} + +void ICNDocument::selectAll() +{ + const NodeList::iterator nodeEnd = m_nodeList.end(); + for ( NodeList::iterator nodeIt = m_nodeList.begin(); nodeIt != nodeEnd; ++nodeIt ) + { + if (*nodeIt) + select(*nodeIt); + } + const ItemList::iterator itemEnd = m_itemList.end(); + for ( ItemList::iterator itemIt = m_itemList.begin(); itemIt != itemEnd; ++itemIt ) + { + if (*itemIt) + select(*itemIt); + } + const ConnectorList::iterator conEnd = m_connectorList.end(); + for ( ConnectorList::iterator connectorIt = m_connectorList.begin(); connectorIt != conEnd; ++connectorIt ) + { + if (*connectorIt) + select(*connectorIt); + } +} + + +Item* ICNDocument::addItem( const QString &id, const QPoint &p, bool newItem ) +{ + if ( !isValidItem(id) ) { + return 0l; + } + + // First, we need to tell all containers to go to full bounding so that + // we can detect a "collision" with them + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + if ( FlowContainer *flowContainer = dynamic_cast((Item*)(*it)) ) + flowContainer->setFullBounds(true); + } + QCanvasItemList preCollisions = canvas()->collisions(p); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + if ( FlowContainer *flowContainer = dynamic_cast((Item*)(*it)) ) + flowContainer->setFullBounds(false); + } + + + Item *item = itemLibrary()->createItem( id, this, newItem ); + if (!item) return 0L; + + // Look through the CNItems at the given point (sorted by z-coordinate) for + // a container item. + FlowContainer *container = 0l; + const QCanvasItemList::iterator pcEnd = preCollisions.end(); + for ( QCanvasItemList::iterator it = preCollisions.begin(); it != pcEnd && !container; ++it ) + { + if ( FlowContainer *flowContainer = dynamic_cast(*it) ) + container = flowContainer; + } + + // We want to check it is not a special item first as + // isValidItem may prompt the user about his bad choice + if ( !isValidItem(item) ) + { + item->removeItem(); + flushDeleteList(); + return 0L; + } + + int x = int(p.x()); + int y = int(p.y()); + + if ( x < 16 || x > canvas()->width() ) + x = 16; + if ( y < 16 || y > canvas()->height() ) + y = 16; + + if ( CNItem *cnItem = dynamic_cast(item) ) + { + cnItem->snap( x, y ); + + if (container) + container->addChild(cnItem); + } + else + item->move( x, y ); + + item->show(); + requestStateSave(); + return item; +} + + +void ICNDocument::addAllItemConnectorPoints() +{ + // FIXME The next line crashes sometimes??! + const ItemList::iterator ciEnd = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != ciEnd; ++it ) + { + if ( CNItem *cnItem = dynamic_cast((Item*)(*it)) ) + cnItem->updateConnectorPoints(true); + } +} + + +void ICNDocument::requestRerouteInvalidatedConnectors() +{ + requestEvent( ItemDocumentEvent::RerouteInvalidatedConnectors ); +} +void ICNDocument::rerouteInvalidatedConnectors() +{ + qApp->processEvents(300); + + // We only ever need to add the connector points for CNItem's when we're about to reroute... + addAllItemConnectorPoints(); + + // List of connectors which are to be determined to need rerouting (and whose routes aren't controlled by NodeGroups) + ConnectorList connectorRerouteList; + + // For those connectors that are controlled by node groups + NodeGroupList nodeGroupRerouteList; + + const ConnectorList::iterator connectorListEnd = m_connectorList.end(); + for ( ConnectorList::iterator it = m_connectorList.begin(); it != connectorListEnd; ++it ) + { + Connector *connector = *it; + if ( connector && connector->isVisible() && connector->startNode() && connector->endNode() ) + { + // Perform a series of tests to see if the connector needs rerouting + bool needsRerouting = false; + + // Test to see if we actually have any points + const QPointList pointList = connector->connectorPoints(); + if ( pointList.isEmpty() ) + needsRerouting = true; + + // Test to see if the route doesn't match up with the node positions at either end + if (!needsRerouting) + { + const QPoint listStart = pointList.first(); + const QPoint listEnd = pointList.last(); + const QPoint nodeStart = QPoint( int(connector->startNode()->x()), int(connector->startNode()->y()) ); + const QPoint nodeEnd = QPoint( int(connector->endNode()->x()), int(connector->endNode()->y()) ); + + if ( ((listStart != nodeStart) || (listEnd != nodeEnd)) && + ((listStart != nodeEnd) || (listEnd != nodeStart)) ) + { + needsRerouting = true; +// kdDebug() << "listStart=("<usesManualPoints() ) + { + const QCanvasItemList collisions = connector->collisions(true); + const QCanvasItemList::const_iterator collisionsEnd = collisions.end(); + for ( QCanvasItemList::const_iterator collisionsIt = collisions.begin(); (collisionsIt != collisionsEnd) && !needsRerouting; ++collisionsIt ) + { + if ( dynamic_cast(*collisionsIt) ) + needsRerouting = true; + } + } + + if (needsRerouting) + { + NodeGroup *nodeGroup = connector->nodeGroup(); + + if ( !nodeGroup && !connectorRerouteList.contains(connector) ) + connectorRerouteList.append(connector); + + else if ( nodeGroup && !nodeGroupRerouteList.contains(nodeGroup) ) + nodeGroupRerouteList.append(nodeGroup); + } + } + } + + // To allow proper rerouting, we want to start with clean routes for all of the invalidated connectors + const NodeGroupList::iterator nodeGroupRerouteEnd = nodeGroupRerouteList.end(); + for ( NodeGroupList::iterator it = nodeGroupRerouteList.begin(); it != nodeGroupRerouteEnd; ++it ) + { + const ConnectorList contained = (*it)->connectorList(); + const ConnectorList::const_iterator end = contained.end(); + for ( ConnectorList::const_iterator it = contained.begin(); it != end; ++it ) + (*it)->updateConnectorPoints(false); + } + + const ConnectorList::iterator connectorRerouteEnd = connectorRerouteList.end(); + for ( ConnectorList::iterator it = connectorRerouteList.begin(); it != connectorRerouteEnd; ++it ) + (*it)->updateConnectorPoints(false); + + // And finally, reroute the connectors + for ( NodeGroupList::iterator it = nodeGroupRerouteList.begin(); it != nodeGroupRerouteEnd; ++it ) + (*it)->updateRoutes(); + + for ( ConnectorList::iterator it = connectorRerouteList.begin(); it != connectorRerouteEnd; ++it ) + (*it)->rerouteConnector(); + + for ( ConnectorList::iterator it = m_connectorList.begin(); it != connectorListEnd; ++it ) + { + if (*it) + (*it)->updateDrawList(); + } +} + + +Connector* ICNDocument::createConnector( const QString &startNodeId, const QString &endNodeId, QPointList *pointList ) +{ + Node *startNode = nodeWithID(startNodeId); + Node *endNode = nodeWithID(endNodeId); + + if ( !startNode || !endNode ) + { + kdDebug() << "Either/both the connector start node and end node could not be found" << endl; + return 0L; + } + + Connector *connector = endNode->createInputConnector(startNode); + if (!connector) + { + kdError() << k_funcinfo << "End node did not create the connector" << endl; + return 0l; + } + startNode->addOutputConnector(connector); + flushDeleteList(); // Delete any connectors that might have been removed by the nodes + + // Set the route to the manual created one if the user created such a route + if (pointList) + connector->setRoutePoints(*pointList,true); + + ConnectorList connectorList; + connectorList.append(connector); + + setModified(true); + + requestRerouteInvalidatedConnectors(); + return connector; +} + +void ICNDocument::deleteSelection() +{ + // End whatever editing mode we are in, as we don't want to start editing + // something that is about to no longer exist... + m_cmManager->cancelCurrentManipulation(); + + if ( m_selectList->isEmpty() ) + return; + + m_selectList->deleteAllItems(); + flushDeleteList(); + setModified(true); + + // We need to emit this so that property widgets etc... + // can clear themselves. + emit itemUnselected(0L); + + requestRerouteInvalidatedConnectors(); + requestStateSave(); +} + + +ConnectorList ICNDocument::getCommonConnectors( const ItemList &list ) +{ + NodeList nodeList = getCommonNodes(list); + + // Now, get all the connectors, and remove the ones that don't have both end + // nodes in the above generated list + ConnectorList connectorList = m_connectorList; + const ConnectorList::iterator connectorListEnd = connectorList.end(); + for ( ConnectorList::iterator it = connectorList.begin(); it != connectorListEnd; ++it ) + { + Connector *con = *it; + if ( !con || !nodeList.contains(con->startNode()) || !nodeList.contains(con->endNode()) ) { + *it = 0l; + } + } + connectorList.remove((Connector*)0l); + return connectorList; +} + + +NodeList ICNDocument::getCommonNodes( const ItemList &list ) +{ + NodeList nodeList; + + const ItemList::const_iterator listEnd = list.end(); + for ( ItemList::const_iterator it = list.begin(); it != listEnd; ++it ) + { + NodeMap nodeMap; + CNItem *cnItem = dynamic_cast((Item*)*it); + if (cnItem) + nodeMap = cnItem->nodeMap(); + const NodeMap::iterator nodeMapEnd = nodeMap.end(); + for ( NodeMap::iterator it = nodeMap.begin(); it != nodeMapEnd; ++it ) + { + Node *node = it.data().node; + + if ( !nodeList.contains(node) ) { + nodeList += node; + } + + NodeGroup *ng = node->nodeGroup(); + if (ng) + { + NodeList intNodeList = ng->internalNodeList(); + const NodeList::iterator intNodeListEnd = intNodeList.end(); + for ( NodeList::iterator it = intNodeList.begin(); it != intNodeListEnd; ++it ) + { + Node *intNode = *it; + if ( !nodeList.contains(intNode) ) { + nodeList += intNode; + } + } + } + } + } + + return nodeList; +} + + + +DirCursor *DirCursor::m_self = 0l; + +DirCursor::DirCursor() +{ + initCursors(); +} + +DirCursor::~DirCursor() +{ +} + +DirCursor* DirCursor::self() +{ + if (!m_self) m_self = new DirCursor; + return m_self; +} + +void DirCursor::initCursors() +{ +// QCursor c(Qt::ArrowCursor); +// QBitmap bitmap = *c.bitmap(); +// QBitmap mask = *c.mask(); +// QPixmap pm( bitmap->width(), bitmap->height() ); +// pm.setMask(mask); +// pm = c.pi + // @todo finish +} + + +#include "icndocument.moc" diff --git a/src/icndocument.h b/src/icndocument.h new file mode 100644 index 0000000..7a5b126 --- /dev/null +++ b/src/icndocument.h @@ -0,0 +1,280 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ICNDOCUMENT_H +#define ICNDOCUMENT_H + +#include "itemdocument.h" + + +class Cells; +class CNItem; +class CNItemGroup; +class Connector; +class ECNode; +class FlowContainer; +class Node; +class NodeGroup; + +typedef QValueList > ConnectorList; +typedef QValueList > NodeList; +typedef QValueList NodeGroupList; +typedef QValueList > GuardedNodeGroupList; + +/** +@author David Saxton +*/ +class ICNDocument : public ItemDocument +{ +Q_OBJECT +public: + ICNDocument( const QString &caption, KTechlab *ktechlab, const char *name ); + virtual ~ICNDocument(); + + enum hit_score + { + hs_none = 0, + hs_connector = 4, + hs_item = 1000 + }; + + virtual View *createView( ViewContainer *viewContainer, uint viewAreaId, const char *name = 0l ); + + /** + * Will attempt to create an item with the given id at position p. Some item + * (such as PIC/START) have restrictions, and can only have one instance of + * themselves on the canvas, and adds the operation to the undo list + */ + virtual Item* addItem( const QString &id, const QPoint &p, bool newItem ); + /** + * Creates a connector between two nodes, and returns a pointer to it + * and adds the operation to the undo list + */ + Connector* createConnector( const QString &startNodeId, const QString &endNodeId, QPointList *pointList = 0L ); + /** + * short for casting whatever itemWithID(id) returns + */ + CNItem* cnItemWithID( const QString &id ); + /** + * Returns a pointer to a node on the canvas with the given id, + * or NULL if no such node exists + */ + Node* nodeWithID( const QString &id ); + /** + * Returns a pointer to a Connector on the canvas with the given id, + * or NULL if no such Connector exists + */ + Connector* connectorWithID( const QString &id ); + /** + * Adds a QCanvasItem to the delete list to be deleted, + * when flushDeleteList() is called + */ + virtual void appendDeleteList( QCanvasItem *qcanvasItem ); + /** + * Permantly deletes all items that have been added to the delete list with + * the appendDeleteList( QCanvasItem *qcanvasItem ) function. + */ + virtual void flushDeleteList(); + /** + * Reinherit this function to perform special checks on whether the two + * given QCanvasItems (either nodes or connectors or both) can be + * connected together. + */ + virtual bool canConnect( QCanvasItem *qcanvasItem1, QCanvasItem *qcanvasItem2 ) const; + virtual void copy(); + virtual void selectAll(); + + + virtual bool registerItem( QCanvasItem *qcanvasItem ); + /** + * Returns a pointer to the 2-dimension array of ICNDocument cells. + */ + Cells *cells() const { return m_cells; } + /** + * Returns true if the cell-reference given by x and y is valid (i.e. + * greater than 0, but within the m_cells boundary) + */ + inline bool isValidCellReference( const uint x, const uint y ) const + { + return ( xm_leftArrow; + } + + static QPixmap rightArrow() + { + return self()->m_rightArrow; + } + + static QPixmap upArrow() + { + return self()->m_upArrow; + } + + static QPixmap downArrow() + { + return self()->m_downArrow; + } + +protected: + DirCursor(); + void initCursors(); + + static DirCursor *m_self; + QPixmap m_leftArrow; + QPixmap m_rightArrow; + QPixmap m_upArrow; + QPixmap m_downArrow; +}; + + +#endif diff --git a/src/icnview.cpp b/src/icnview.cpp new file mode 100644 index 0000000..cff8a2c --- /dev/null +++ b/src/icnview.cpp @@ -0,0 +1,114 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasmanipulator.h" +#include "icndocument.h" +#include "icnview.h" +#include "ktechlab.h" + +#include +#include +#include +#include +#include + +ICNView::ICNView( ICNDocument *icnDocument, ViewContainer *viewContainer, uint viewAreaId, const char *name ) + : ItemView( icnDocument, viewContainer, viewAreaId, name ) +{ + bool manualRouting = (icnDocument->m_cmManager->cmState() & CMManager::cms_manual_route); + + KActionCollection * ac = actionCollection(); + + //BEGIN Routing Actions + // These actions get inserted into the main menu + m_pAutoRoutingAction = new KRadioAction( i18n("Automatic"), "", 0, this, SLOT(slotSetRoutingAuto()), ac, "routing_mode_auto" ); + m_pAutoRoutingAction->setExclusiveGroup("routing_mode"); + if ( !manualRouting ) + m_pAutoRoutingAction->setChecked( true ); + + m_pManualRoutingAction = new KRadioAction( i18n("Manual"), "", 0, this, SLOT(slotSetRoutingManual()), ac, "routing_mode_manual" ); + m_pManualRoutingAction->setExclusiveGroup("routing_mode"); + if ( manualRouting ) + m_pManualRoutingAction->setChecked( true ); + + + // This popup gets inserted into the toolbar + m_pRoutingModeToolbarPopup = new KToolBarPopupAction( i18n("Connection Routing Mode"), "pencil", 0, 0, 0, ac, "routing_mode" ); + m_pRoutingModeToolbarPopup->setDelayed(false); + + KPopupMenu * m = m_pRoutingModeToolbarPopup->popupMenu(); + m->insertTitle( i18n("Connection Routing Mode") ); + + m->insertItem( /*KGlobal::iconLoader()->loadIcon( "routing_mode_auto", KIcon::Small ), */i18n("Automatic"), 0 ); + m->insertItem( /*KGlobal::iconLoader()->loadIcon( "routing_mode_manual", KIcon::Small ),*/ i18n("Manual"), 1 ); + + m->setCheckable(true); + m->setItemChecked( manualRouting ? 1 : 0, true ); + + connect( m, SIGNAL(activated(int)), this, SLOT(slotSetRoutingMode(int)) ); + //END Routing Actions + + connect( icnDocument->m_cmManager, SIGNAL(manualRoutingChanged(bool )), this, SLOT(slotUpdateRoutingToggles(bool )) ); +} + + +ICNView::~ICNView() +{ +} + + +void ICNView::slotSetRoutingMode( int mode ) +{ + // This function is called when the user selects a mode from the toolbar drop-down menu + bool manualEnabled = (mode == 1); + + if ( bool(p_itemDocument->m_cmManager->cmState() & CMManager::cms_manual_route) == manualEnabled ) + return; + + slotUpdateRoutingMode( manualEnabled ); + slotUpdateRoutingToggles( manualEnabled ); +} + + +void ICNView::slotSetRoutingManual() +{ + slotUpdateRoutingMode( true ); + slotUpdateRoutingToggles( true ); +} + + +void ICNView::slotSetRoutingAuto() +{ + slotUpdateRoutingMode( false ); + slotUpdateRoutingToggles( false ); +} + + +void ICNView::slotUpdateRoutingMode( bool manualRouting ) +{ + p_itemDocument->m_cmManager->slotSetManualRoute( manualRouting ); + p_itemDocument->canvas()->setMessage( manualRouting ? i18n("Manual connection routing enabled.") : i18n("Automatic connection routing enabled.") ); +} + + +void ICNView::slotUpdateRoutingToggles( bool manualRouting ) +{ + m_pRoutingModeToolbarPopup->popupMenu()->setItemChecked( !manualRouting, 0 ); + m_pRoutingModeToolbarPopup->popupMenu()->setItemChecked( manualRouting, 1 ); + + if ( manualRouting ) + m_pManualRoutingAction->setChecked(true); + + else + m_pAutoRoutingAction->setChecked(true); +} + + +#include "icnview.moc" diff --git a/src/icnview.h b/src/icnview.h new file mode 100644 index 0000000..4f4d0bc --- /dev/null +++ b/src/icnview.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ICNVIEW_H +#define ICNVIEW_H + +#include + +class ICNDocument; +class KRadioAction; +class KToolBarPopupAction; + +/** +@author David Saxton +*/ +class ICNView : public ItemView +{ + Q_OBJECT + public: + ICNView( ICNDocument * icnDocument, ViewContainer *viewContainer, uint viewAreaId, const char * name = 0l ); + ~ICNView(); + + protected slots: + void slotSetRoutingMode( int mode ); // 0 = auto, 1 = manual + void slotSetRoutingAuto(); + void slotSetRoutingManual(); + void slotUpdateRoutingMode( bool manualRouting ); + void slotUpdateRoutingToggles( bool manualRouting ); + + protected: + KToolBarPopupAction * m_pRoutingModeToolbarPopup; + KRadioAction * m_pManualRoutingAction; + KRadioAction * m_pAutoRoutingAction; +}; + +#endif diff --git a/src/item.cpp b/src/item.cpp new file mode 100644 index 0000000..1cbf7e3 --- /dev/null +++ b/src/item.cpp @@ -0,0 +1,599 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "itemdocument.h" +#include "itemdocumentdata.h" +#include "core/ktlconfig.h" + +#include +#include +#include +#include +#include +#include +#include + +const int minPrefixExp = -24; +const int maxPrefixExp = 24; +const int numPrefix = int((maxPrefixExp-minPrefixExp)/3)+1; +const QString SIprefix[] = {"y","z","a","f","p","n",QChar(0xB5),"m","","k","M","G","T","P","E","Z","Y"}; + + +Item::Item( ItemDocument *itemDocument, bool newItem, const QString &id ) + : QObject(), QCanvasPolygon( itemDocument->canvas() ) +{ + m_bDynamicContent = false; + m_bIsRaised = false; + m_bDoneCreation = false; + p_parentItem = 0l; + b_deleted = false; + p_itemDocument = itemDocument; + m_baseZ = -1; + + if ( QFontInfo(m_font).pixelSize() > 11 ) // It has to be > 11, not > 12, as (I think) pixelSize() rounds off the actual size + m_font.setPixelSize(12); + + if (newItem) + m_id = p_itemDocument->generateUID(id); + + else + { + m_id = id; + p_itemDocument->registerUID(id); + } +} + + +Item::~Item() +{ + p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems ); + p_itemDocument->unregisterUID( id() ); + + QCanvasPolygon::hide(); + + const VariantDataMap::iterator variantDataEnd = m_variantData.end(); + for ( VariantDataMap::iterator it = m_variantData.begin(); it != variantDataEnd; ++it ) + delete it.data(); + m_variantData.clear(); +} + + +void Item::removeItem() +{ + if (b_deleted) + return; + b_deleted = true; + + hide(); + setCanvas(0l); + emit removed(this); + p_itemDocument->appendDeleteList(this); +} + + +void Item::moveBy( double dx, double dy ) +{ + QCanvasPolygon::moveBy(dx,dy); + emit movedBy( dx, dy ); +} + + +void Item::setChanged() +{ + if (b_deleted) + return; + + if (canvas()) + canvas()->setChanged(boundingRect()); +} + + +void Item::setItemPoints( const QPointArray & pa, bool setSizeFromPoints ) +{ + m_itemPoints = pa; + if (setSizeFromPoints) + setSize( m_itemPoints.boundingRect() ); + itemPointsChanged(); +} + + +void Item::itemPointsChanged() +{ + setPoints(m_itemPoints); +} + + +void Item::setSize( QRect sizeRect, bool forceItemPoints ) +{ + if ( m_sizeRect == sizeRect && !forceItemPoints ) + return; + + if ( !preResize(sizeRect) ) + return; + + canvas()->setChanged(areaPoints().boundingRect()); + m_sizeRect = sizeRect; + if ( m_itemPoints.isEmpty() || forceItemPoints ) + { + setItemPoints( QPointArray( m_sizeRect ), false ); + } + canvas()->setChanged(areaPoints().boundingRect()); + postResize(); + emit resized(); +} + + +ItemData Item::itemData() const +{ + ItemData itemData; + + itemData.type = m_type; + itemData.x = x(); + itemData.y = y(); + + if ( !parentItem() ) + itemData.z = m_baseZ; + + itemData.size = m_sizeRect; + itemData.setSize = canResize(); + + if (p_parentItem) + itemData.parentId = p_parentItem->id(); + + const VariantDataMap::const_iterator end = m_variantData.end(); + for ( VariantDataMap::const_iterator it = m_variantData.begin(); it != end; ++it ) + { + switch( it.data()->type() ) + { + case Variant::Type::String: + case Variant::Type::FileName: + case Variant::Type::Port: + case Variant::Type::Pin: + case Variant::Type::VarName: + case Variant::Type::Combo: + case Variant::Type::Select: + case Variant::Type::Multiline: + case Variant::Type::SevenSegment: + case Variant::Type::KeyPad: + { + itemData.dataString[it.key()] = it.data()->value().toString(); + break; + } + case Variant::Type::Int: + case Variant::Type::Double: + { + itemData.dataNumber[it.key()] = it.data()->value().toDouble(); + break; + } + case Variant::Type::Color: + { + itemData.dataColor[it.key()] = it.data()->value().toColor(); + break; + } + case Variant::Type::Bool: + { + itemData.dataBool[it.key()] = it.data()->value().toBool(); + break; + } + case Variant::Type::Raw: + { + itemData.dataRaw[it.key()] = it.data()->value().toBitArray(); + break; + } + case Variant::Type::PenStyle: + case Variant::Type::PenCapStyle: + { + // These types are only created from DrawPart, and that class + // deals with these, so we can ignore them + break; + } + case Variant::Type::None: + { + // ? Maybe obsoleted data... + break; + } + } + } + + return itemData; +} + + +void Item::restoreFromItemData( const ItemData &itemData ) +{ + move( itemData.x, itemData.y ); + if ( canResize() ) + setSize( itemData.size ); + + Item *parentItem = p_itemDocument->itemWithID( itemData.parentId ); + if (parentItem) + setParentItem(parentItem); + else + m_baseZ = itemData.z; + + //BEGIN Restore data + const QStringMap::const_iterator stringEnd = itemData.dataString.end(); + for ( QStringMap::const_iterator it = itemData.dataString.begin(); it != stringEnd; ++it ) + { + if ( hasProperty(it.key()) ) + property( it.key() )->setValue( it.data() ); + } + + const DoubleMap::const_iterator numberEnd = itemData.dataNumber.end(); + for ( DoubleMap::const_iterator it = itemData.dataNumber.begin(); it != numberEnd; ++it ) + { + if ( hasProperty(it.key()) ) + property( it.key() )->setValue( it.data() ); + } + + const QColorMap::const_iterator colorEnd = itemData.dataColor.end(); + for ( QColorMap::const_iterator it = itemData.dataColor.begin(); it != colorEnd; ++it ) + { + if ( hasProperty(it.key()) ) + property( it.key() )->setValue( it.data() ); + } + + const BoolMap::const_iterator boolEnd = itemData.dataBool.end(); + for ( BoolMap::const_iterator it = itemData.dataBool.begin(); it != boolEnd; ++it ) + { + if ( hasProperty(it.key()) ) + property( it.key() )->setValue( QVariant( it.data(), 0 ) ); + } + + const QBitArrayMap::const_iterator rawEnd = itemData.dataRaw.end(); + for ( QBitArrayMap::const_iterator it = itemData.dataRaw.begin(); it != rawEnd; ++it ) + { + if ( hasProperty(it.key()) ) + property( it.key() )->setValue( it.data() ); + } + //END Restore Data +} + + +bool Item::mousePressEvent( const EventInfo &eventInfo ) +{ + Q_UNUSED(eventInfo); + return false; +} +bool Item::mouseReleaseEvent( const EventInfo &eventInfo ) +{ + Q_UNUSED(eventInfo); + return false; +} +bool Item::mouseMoveEvent( const EventInfo &eventInfo ) +{ + Q_UNUSED(eventInfo); + return false; +} +bool Item::wheelEvent( const EventInfo &eventInfo ) +{ + Q_UNUSED(eventInfo); + return false; +} +void Item::enterEvent() +{ +} +void Item::leaveEvent() +{ +} + +bool Item::mouseDoubleClickEvent( const EventInfo &eventInfo ) +{ + Q_UNUSED(eventInfo); + + typedef QValueList VarPtrLst; + VarPtrLst list; + const VariantDataMap::iterator variantDataEnd = m_variantData.end(); + for ( VariantDataMap::iterator it = m_variantData.begin(); it != variantDataEnd; ++it ) + { + if ( it.data()->type() == Variant::Type::Multiline ) { + list.append(it.data()); + } + } + if ( list.count() > 1 ) + { + kdWarning() << "Item::mouseDoubleClickEvent: Can't handle more than one multiline data"<caption(), "", v->getValue(), ok ); + + KDialogBase *dlg = new KDialogBase( 0l, "", true, v->editorCaption(), KDialogBase::Ok|KDialogBase::Cancel|KDialogBase::User1, KDialogBase::Ok, false, KStdGuiItem::clear() ); + QFrame *frame = dlg->makeMainWidget(); + QVBoxLayout *layout = new QVBoxLayout( frame, 0, dlg->spacingHint() ); + KTextEdit *textEdit = new KTextEdit( frame ); + textEdit->setTextFormat( PlainText ); + textEdit->setText( v->value().toString() ); + layout->addWidget( textEdit, 10 ); + textEdit->setFocus(); + connect( dlg, SIGNAL( user1Clicked() ), textEdit, SLOT( clear() ) ); + dlg->setMinimumWidth( 600 ); + if ( dlg->exec() == KDialogBase::Accepted ) + { + v->setValue( textEdit->text() ); + dataChanged(); + p_itemDocument->setModified(true); + } + delete dlg; + + return true; +} + + +void Item::setSelected( bool yes ) +{ + if ( isSelected() == yes ) { + return; + } + QCanvasPolygon::setSelected(yes); + yes ? (emit selected(this)) : (emit unselected(this)); +} + + +void Item::setParentItem( Item *newParentItem ) +{ +// kdDebug() << k_funcinfo << "this = "<addChild(this); + } + } + + p_parentItem = newParentItem; + (void)level(); + reparented( oldParentItem, newParentItem ); + p_itemDocument->slotUpdateZOrdering(); +} + + +int Item::level() const +{ + return p_parentItem ? p_parentItem->level()+1 : 0; +} + + +ItemList Item::children( bool includeGrandChildren ) const +{ + if (!includeGrandChildren) + return m_children; + + ItemList children = m_children; + ItemList::const_iterator end = m_children.end(); + for ( ItemList::const_iterator it = m_children.begin(); it != end; ++it ) + { + if (!*it) + continue; + + children += (*it)->children(true); + } + + return children; +} + + +void Item::addChild( Item *child ) +{ + if ( !child ) + return; + + if ( child->contains(this) ) + { +// kdError() << k_funcinfo << "Attempting to add a child to this item that is already a parent of this item. Incest results in stack overflow." << endl; + return; + } + + if ( contains( child, true ) ) + { +// kdError() << k_funcinfo << "Already have child " << child << endl; + return; + } + + m_children.append(child); + connect( child, SIGNAL(removed(Item* )), this, SLOT(removeChild(Item* )) ); + + child->setParentItem(this); + childAdded(child); + p_itemDocument->slotUpdateZOrdering(); +} + + +void Item::removeChild( Item *child ) +{ + if ( !child || !m_children.contains(child) ) + return; + + m_children.remove(child); + disconnect( child, SIGNAL(removed(Item* )), this, SLOT(removeChild(Item* )) ); + + childRemoved(child); + p_itemDocument->slotUpdateZOrdering(); +} + + +bool Item::contains( Item *item, bool direct ) const +{ + const ItemList::const_iterator end = m_children.end(); + for ( ItemList::const_iterator it = m_children.begin(); it != end; ++it ) + { + if ( (Item*)*it == item || ( !direct && (*it)->contains( item, false ) ) ) + return true; + } + return false; +} + + +void Item::setRaised( bool isRaised ) +{ + m_bIsRaised = isRaised; + // We'll get called later to update our Z +} + + +void Item::updateZ( int baseZ ) +{ + m_baseZ = baseZ; + double z = ItemDocument::Z::Item + (ItemDocument::Z::DeltaItem)*baseZ; + + if ( isRaised() ) + z += ItemDocument::Z::RaisedItem - ItemDocument::Z::Item; + + setZ(z); + + const ItemList::const_iterator end = m_children.end(); + for ( ItemList::const_iterator it = m_children.begin(); it != end; ++it ) + { + if (*it) + (*it)->updateZ(baseZ+1); + } +} + + +int Item::getNumberPre( double num ) +{ + return (int)(num/getMultiplier(num)); +} + +QString Item::getNumberMag( double num ) +{ + if ( num == 0. ) return ""; + const double exp_n = std::log10(std::abs(num)); + if ( exp_n < minPrefixExp+3 ) return SIprefix[0]; + else if ( exp_n >= maxPrefixExp ) return SIprefix[numPrefix-1]; + else return SIprefix[(int)std::floor((double)(exp_n/3))-(int)floor(double(minPrefixExp/3))]; +} + +double Item::getMultiplier( double num ) +{ + if ( num == 0. ) return 1.; + else return std::pow( 10, 3*std::floor(std::log10(std::abs(num))/3) ); +} + +double Item::getMultiplier( const QString &_mag ) +{ + QString mag; + // Allow the user to enter in "u" instead of mu, as unfortunately many keyboards don't have the mu key + if ( _mag == "u" ) + mag = QChar(0xB5); + else + mag = _mag; + + for ( int i=0; ivalue().toDouble() : 0.0; +} + + +int Item::dataInt( const QString & id ) const +{ + Variant * variant = property(id); + return variant ? variant->value().toInt() : 0; +} + + +bool Item::dataBool( const QString & id ) const +{ + Variant * variant = property(id); + return variant ? variant->value().toBool() : false; +} + + +QString Item::dataString( const QString & id ) const +{ + Variant * variant = property(id); + return variant ? variant->value().toString() : QString::null; +} + + +QColor Item::dataColor( const QString & id ) const +{ + Variant * variant = property(id); + return variant ? variant->value().toColor() : Qt::black; +} + + +Variant * Item::createProperty( const QString & id, Variant::Type::Value type ) +{ + if ( !m_variantData.contains(id) ) + { + m_variantData[id] = new Variant(type); + if (m_bDoneCreation) + connect( m_variantData[id], SIGNAL(valueChanged(QVariant,QVariant)), this, SLOT(dataChanged()) ); + } + + return m_variantData[id]; +} + + +Variant * Item::property( const QString & id ) const +{ + if ( m_variantData.contains(id) ) + return m_variantData[id]; + + kdError() << k_funcinfo << " No such property with id " << id << endl; + return 0l; +} + + +bool Item::hasProperty( const QString & id ) const +{ + return m_variantData.contains(id); +} + + +void Item::finishedCreation( ) +{ + m_bDoneCreation = true; + const VariantDataMap::iterator end = m_variantData.end(); + for ( VariantDataMap::iterator it = m_variantData.begin(); it != end; ++it ) + connect( it.data(), SIGNAL(valueChanged(QVariant,QVariant)), this, SLOT(dataChanged()) ); + dataChanged(); +} +//END Data stuff + +#include "item.moc" diff --git a/src/item.h b/src/item.h new file mode 100644 index 0000000..f1968d2 --- /dev/null +++ b/src/item.h @@ -0,0 +1,308 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ITEM_H +#define ITEM_H + +#include "variant.h" + +#include +#include +#include + + +class Document; +class EventInfo; +class Item; +class ItemData; +class ItemDocument; +class ItemView; +class DoubleSpinBox; +class Document; +class Variant; +class QBitArray; + +typedef Item*(*createItemPtr)( ItemDocument *itemDocument, bool newItem, const char *id ); +typedef QGuardedPtr GuardedItem; +typedef QMap VariantDataMap; +typedef QValueList ItemList; + +/** +@author David Saxton +@author Daniel Clarke +*/ +class Item : public QObject, public QCanvasPolygon +{ +Q_OBJECT +public: + Item( ItemDocument *itemDocument, bool newItem, const QString &id ); + virtual ~Item(); + + /** + * @return Pointer to the VariantMap used for internal data storage + */ + VariantDataMap *variantMap() { return &m_variantData; } + + double dataDouble( const QString & id ) const; + int dataInt( const QString & id ) const; + bool dataBool( const QString & id ) const; + QString dataString( const QString & id ) const; + QColor dataColor( const QString & id ) const; + + virtual Variant * createProperty( const QString & id, Variant::Type::Value type ); + Variant * property( const QString & id ) const; + bool hasProperty( const QString & id ) const; + + /** + * Whether or not we can rotate the item + */ + virtual bool canRotate() const { return false; } + /** + * Whether or not we can flip the item + */ + virtual bool canFlip() const { return false; } + /** + * Whether or not we can resize the item + */ + virtual bool canResize() const { return false; } + /** + * Returns whether the CNItem allows itself to be moved on the canvas. + * Most do, but some (such as the PicItem) don't allow this + */ + virtual bool isMovable() const { return true; } + /** + * If your item doesn't move, yet still continously changes what is being + * displayed (such as a seven segment display or a lamp), then this should + * return true (set m_bDynamicContent to be true in your constructor). + */ + bool hasDynamicContent() const { return m_bDynamicContent; } + /** + * Returns a identifier for the CNItem, which is unique on the ICNDocument + */ + QString id() const { return m_id; } + QString type() const { return m_type; } + /** + * Called from ItemLibrary after this class and subclasses have finished + * constructing themselves. + */ + virtual void finishedCreation(); + /** + * Sets the selected flag of the item to yes. selected or unselected will be + * emitted as appropriate + */ + virtual void setSelected( bool yes ); + /** + * Convenience function for setting the item bounding area as changed on the + * canvas + */ + void setChanged(); + /** + * Sets this item as a child of the given item. Calls reparented with the + * old and the new parent. + */ + void setParentItem( Item *parentItem ); + /** + * The parent item for this item, or NULL if none + */ + Item *parentItem() const { return p_parentItem; } + ItemDocument *itemDocument() const { return p_itemDocument; } + /** + * Returns the number of items away from the top item this is + * (parent-wise). Returns 0 if has no parent. + */ + int level() const; + /** + * If true, then adds ItemDocument::Z::(RaisedItem-Item) to the z value of + * the item. + */ + void setRaised( bool isRaised ); + /** + * @Returns whether raised or not + */ + bool isRaised() const { return m_bIsRaised; } + /** + * Sets this item to the given baseZ level, and calls this function for the + * children with baseZ incremented by one. Reinherit this function to set + * the Z of attached stuff (such as nodes). + */ + virtual void updateZ( int baseZ ); + /** + * Returns the item's position in the overall z-stack of items. + */ + int baseZ() const { return m_baseZ; } + /** + * Adds a child. Calls the virtual function childAdded. + */ + void addChild( Item *child ); + /** + * Returns the list of children. + * @param if includeGrandChildren is true then this list will also contain + * the children's children, and so on recursively, instead of just the + * immediate children. + */ + ItemList children( bool includeGrandChildren = false ) const; + /** + * Returns whether we have the given child as either a direct child, or as + * either a direct or indirect child + */ + bool contains( Item *item, bool direct = false ) const; + /** + * Calls prePresize with the bounds, and if that returns true, sets + * m_sizeRect to the given rect, and then calls postResize. + * @param forceItemPoints if true, will set the item points to a rectangle of the given size + */ + void setSize( QRect sizeRect, bool forceItemPoints = false ); + /** + * Convenience function. + * @see setSize( QRect sizeRect, bool forceItemPoints ); + */ + void setSize( int x, int y, int w, int h, bool forceItemPoints = false ) { setSize( QRect(x,y,w,h), forceItemPoints ); } + /** + * @returns the m_sizeRect rectangble that contains the item points + */ + QRect sizeRect() const { return m_sizeRect; } + /** + * Reinherit this function if you want to determine what the minimum size is + * that this item can be resized to. + */ + virtual QSize minimumSize() const { return QSize(0,0); } + int offsetX() const { return m_sizeRect.x(); } + int offsetY() const { return m_sizeRect.y(); } + int width() const { return m_sizeRect.width(); } + int height() const { return m_sizeRect.height(); } + virtual bool mousePressEvent( const EventInfo &eventInfo ); + virtual bool mouseReleaseEvent( const EventInfo &eventInfo ); + virtual bool mouseDoubleClickEvent ( const EventInfo &eventInfo ); + virtual bool mouseMoveEvent( const EventInfo &eventInfo ); + virtual bool wheelEvent( const EventInfo &eventInfo ); + virtual void enterEvent(); + virtual void leaveEvent(); + /** + * Returns the name of the CNItem, e.g. "Resistor" + */ + QString name() const { return m_name; } + /** + * Returns a description of the CNItem, with html tags if appropriate. + */ + QString description() const { return m_desc; } + /** + * Modifies the exponent of the number so that it appears readable: + * eg 10000->10, 174822->175, 0.6->600, etc + */ + static int getNumberPre( double num ); + /** + * Returns the SI exponent of the number as a letter: + * eg 10000 returns 'k', 0.6 returns 'm', etc + */ + static QString getNumberMag( double num ); + /** + * Returns the multiplier required to get the num up to human readable form: + * eg 10000 returns 0.001, etc + */ + static double getMultiplier( double num ); + /** + * Returns the multiplier required to get the num from human readable form + * to its actual value based on the SI exponent: + * eg 'm' returns 0.001, etc + */ + static double getMultiplier( const QString &mag ); + + virtual ItemData itemData() const; + virtual void restoreFromItemData( const ItemData &itemData ); + + const QFont & font() const { return m_font; } + +public slots: + virtual void removeItem(); + /** + * Moves item - use this instead of moveBy() so that associated Nodes also get moved + */ + virtual void moveBy( double dx, double dy ); + /** + * Removes a child. Calls the virtual function childRemoved + */ + void removeChild( Item *child ); + +signals: + /** + * Emitted when the CNItem is removed. Normally, this signal is caught by associated + * nodes, who will remove themselves as well. + */ + void removed( Item *item ); + /** + * Emitted when the item is selected + */ + void selected( Item *item, bool isSelected = true ); + /** + * Emitted when the item is unselected + */ + void unselected( Item *item, bool isSelected = false ); + /** + * Emitted when the item is resized (after calling postResize) + */ + void resized(); + /** + * Emitted when the item is moved (by dx, dy). + */ + void movedBy( double dx, double dy ); + +protected slots: + virtual void dataChanged() {}; + +protected: + /** + * Reinherit this function if you want to do anything with children. Called + * after the parent is changed, with the old parent and the new parent. + */ + virtual void reparented( Item */*oldParent*/, Item */*newParent*/ ) {}; + /** + * Reinherit this function if you want to do anything with children. Called + * after a child has been added. + */ + virtual void childAdded( Item * ) {}; + /** + * Reinherit this function if you want to do anything with children. Called + * after a child has been removed. + */ + virtual void childRemoved( Item * ) {}; + /** + * Set the rough bounding points for this item. Calls itemPointsChanged + * after setting the points + */ + void setItemPoints( const QPointArray &pa, bool setSizeFromPoints = true ); + /** + * Reinherit this function if you want to apply any sort of transformation + * to the item points + */ + virtual void itemPointsChanged(); + virtual bool preResize( QRect sizeRect ) { Q_UNUSED(sizeRect); return true; } + virtual void postResize() {}; + + QString m_id; + QString m_name, m_desc; // Name and description + QString m_type; + GuardedItem p_parentItem; // If attached to a parent item + ItemList m_children; + QGuardedPtr p_itemDocument; + QPointArray m_itemPoints; // The unorientated and unsized item points + + friend class ItemLibrary; + + int m_baseZ; + bool m_bIsRaised; + bool m_bDoneCreation; + bool b_deleted; + bool m_bDynamicContent; + QFont m_font; + QRect m_sizeRect; + VariantDataMap m_variantData; +}; + +#endif diff --git a/src/itemdocument.cpp b/src/itemdocument.cpp new file mode 100644 index 0000000..cfe3230 --- /dev/null +++ b/src/itemdocument.cpp @@ -0,0 +1,1323 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasmanipulator.h" +#include "circuitdocument.h" +#include "connector.h" +#include "cnitem.h" +#include "drawpart.h" +#include "ecnode.h" +#include "flowcodedocument.h" +#include "icnview.h" +#include "itemdocumentdata.h" +#include "itemgroup.h" +#include "itemselector.h" +#include "ktechlab.h" +#include "core/ktlconfig.h" +#include "pin.h" +#include "simulator.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +//BEGIN class ItemDocument +int ItemDocument::m_nextActionTicket = 0; + +ItemDocument::ItemDocument( const QString &caption, KTechlab *ktechlab, const char *name) + : Document( caption, ktechlab, name ) +{ + m_queuedEvents = 0; + p_ktechlab = ktechlab; + m_nextIdNum = 1; + m_savedState = 0l; + m_currentState = 0l; + m_bIsLoading = false; + + m_canvas = new Canvas( this, "canvas" ); + m_canvasTip = new CanvasTip(this,m_canvas); + m_cmManager = new CMManager(this); + m_undoStack.setAutoDelete(true); + m_redoStack.setAutoDelete(true); + + updateBackground(); + m_canvas->resize( 0, 0 ); + m_canvas->setDoubleBuffering(true); + + m_pEventTimer = new QTimer(this); + connect( m_pEventTimer, SIGNAL(timeout()), this, SLOT(processItemDocumentEvents()) ); + + connect( this, SIGNAL(itemSelected(Item*)), this, SLOT(slotInitItemActions(Item*)) ); + connect( this, SIGNAL(itemUnselected(Item*)), this, SLOT(slotInitItemActions(Item*)) ); + + connect( ComponentSelector::self(), SIGNAL(itemClicked(const QString& )), this, SLOT(slotUnsetRepeatedItemId()) ); + connect( FlowPartSelector::self(), SIGNAL(itemClicked(const QString& )), this, SLOT(slotUnsetRepeatedItemId()) ); +#ifdef MECHANICS + connect( MechanicsSelector::self(), SIGNAL(itemClicked(const QString& )), this, SLOT(slotUnsetRepeatedItemId()) ); +#endif + + m_pAlignmentAction = new KActionMenu( i18n("Alignment"), "rightjust", this ); + + slotUpdateConfiguration(); +} + + +ItemDocument::~ItemDocument() +{ + m_bDeleted = true; + + ItemList toDelete = m_itemList; + const ItemList::iterator end = toDelete.end(); + for ( ItemList::iterator it = toDelete.begin(); it != end; ++it ) + delete *it; + + delete m_cmManager; + m_cmManager = 0l; + delete m_currentState; + m_currentState = 0l; + delete m_canvasTip; + m_canvasTip = 0l; +} + + +void ItemDocument::handleNewView( View * view ) +{ + Document::handleNewView(view); + requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems ); +} + + +bool ItemDocument::registerItem( QCanvasItem *qcanvasItem ) +{ + if (!qcanvasItem) + return false; + + requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems ); + + switch (qcanvasItem->rtti()) + { + case ItemDocument::RTTI::DrawPart: + case ItemDocument::RTTI::CNItem: + { + Item *item = dynamic_cast(qcanvasItem); + m_itemList.append(item); + connect( item, SIGNAL(removed(Item*)), this, SLOT(requestRerouteInvalidatedConnectors()) ); + connect( item, SIGNAL(selected(Item*,bool)), this, SIGNAL(itemSelected(Item*)) ); + connect( item, SIGNAL(unselected(Item*,bool)), this, SIGNAL(itemUnselected(Item*)) ); + itemAdded(item); + return true; + } + default: + return false; + } +} + + +void ItemDocument::slotSetDrawAction( int drawAction ) +{ + m_cmManager->setDrawAction(drawAction); +} + + +void ItemDocument::cancelCurrentOperation() +{ + m_cmManager->cancelCurrentManipulation(); +} + + +void ItemDocument::slotSetRepeatedItemId( const QString &id ) +{ + m_cmManager->setCMState( CMManager::cms_repeated_add, true ); + m_cmManager->setRepeatedAddId(id); +} + + +void ItemDocument::slotUnsetRepeatedItemId() +{ + m_cmManager->setCMState( CMManager::cms_repeated_add, false ); +} + + +void ItemDocument::fileSave() +{ + if ( url().isEmpty() && !getURL(m_fileExtensionInfo) ) return; + writeFile(); +} + + +void ItemDocument::fileSaveAs() +{ + if ( !getURL(m_fileExtensionInfo) ) return; + writeFile(); + + // Our modified state may not have changed, but we emit this to force the + // main window to update our caption. + emit modifiedStateChanged(); +} + + +void ItemDocument::writeFile() +{ + ItemDocumentData data( type() ); + data.saveDocumentState(this); + + if ( data.saveData(url()) ) + { + m_savedState = m_currentState; + setModified(false); + } +} + + +bool ItemDocument::openURL( const KURL &url ) +{ + ItemDocumentData data( type() ); + + if ( !data.loadData(url) ) + return false; + + // Why do we stop simulating while loading a document? + // Crash possible when loading a circuit document, and the Qt event loop is + // reentered (such as when a PIC component pops-up a message box), which + // will then call the Simulator::step function, which might use components + // that have not fully initialized themselves. + + m_bIsLoading = true; + bool wasSimulating = Simulator::self()->isSimulating(); + Simulator::self()->slotSetSimulating( false ); + data.restoreDocument(this); + Simulator::self()->slotSetSimulating( wasSimulating ); + m_bIsLoading = false; + + setURL(url); + clearHistory(); + m_savedState = m_currentState; + setModified(false); + + if ( FlowCodeDocument *fcd = dynamic_cast(this) ) + { + // We need to tell all pic-depedent components about what pic type is in use + emit fcd->picTypeChanged(); + } + + requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems ); + + // Load Z-position info + m_zOrder.clear(); + ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + if ( !*it || (*it)->parentItem() ) + continue; + + m_zOrder[(*it)->baseZ()] = *it; + } + slotUpdateZOrdering(); + + return true; +} + +void ItemDocument::print() +{ + static KPrinter * printer = new KPrinter; + + if ( ! printer->setup( p_ktechlab ) ) + return; + + // setup the printer. with Qt, you always "print" to a + // QPainter.. whether the output medium is a pixmap, a screen, + // or paper + QPainter p; + p.begin( printer ); + + // we let our view do the actual printing + QPaintDeviceMetrics metrics( printer ); + + // Round to 16 (= 2 * 8) so that we cut in the middle of squares + int w = 16*int(metrics.width()/16); + int h = 16*int(metrics.height()/16); + + p.setClipping( true ); + p.setClipRect( 0, 0, w, h, QPainter::CoordPainter ); + + // Send off the painter for drawing + m_canvas->setBackgroundPixmap( 0 ); + + QRect bounding = canvasBoundingRect(); + unsigned int rows = (unsigned) std::ceil( double( bounding.height() ) / double( h ) ); + unsigned int cols = (unsigned) std::ceil( double( bounding.width() ) / double( w ) ); + int offset_x = bounding.x(); + int offset_y = bounding.y(); + + for ( unsigned row = 0; row < rows; ++row ) + { + for ( unsigned col = 0; col < cols; ++col ) + { + if ( row != 0 || col != 0 ) + printer->newPage(); + + QRect drawArea( offset_x + (col * w), offset_y + (row * h), w, h ); + m_canvas->drawArea( drawArea, & p ); + + p.translate( -w, 0 ); + } + p.translate( w * cols, -h ); + } + + updateBackground(); + + // and send the result to the printer + p.end(); +} + + +void ItemDocument::requestStateSave( int actionTicket ) +{ + if ( m_bIsLoading ) + return; + + m_redoStack.clear(); + + if ( (actionTicket >= 0) && (actionTicket == m_currentActionTicket) ) + { + delete m_currentState; + m_currentState = 0l; + } + + m_currentActionTicket = actionTicket; + + if (m_currentState) + m_undoStack.push(m_currentState); + + m_currentState = new ItemDocumentData( type() ); + m_currentState->saveDocumentState(this); + + if (!m_savedState) + m_savedState = m_currentState; + + setModified( m_savedState != m_currentState ); + + emit undoRedoStateChanged(); + + //FIXME To resize undo queue, have to pop and push everything + int maxUndo = KTLConfig::maxUndo(); + if ( maxUndo <= 0 || m_undoStack.count() < (unsigned)maxUndo ) + return; + IDDStack tempStack; + int pushed = 0; + while ( !m_undoStack.isEmpty() && pushed < maxUndo ) + { + tempStack.push( m_undoStack.pop() ); + pushed++; + } + m_undoStack.clear(); + while ( !tempStack.isEmpty() ) + m_undoStack.push( tempStack.pop() ); +} + + +void ItemDocument::clearHistory() +{ + m_undoStack.clear(); + m_redoStack.clear(); + delete m_currentState; + m_currentState = 0l; + requestStateSave(); +} + + +bool ItemDocument::isUndoAvailable() const +{ + return !m_undoStack.isEmpty(); +} + + +bool ItemDocument::isRedoAvailable() const +{ + return !m_redoStack.isEmpty(); +} + + +void ItemDocument::undo() +{ + ItemDocumentData *idd = m_undoStack.pop(); + if (!idd) + return; + + if (m_currentState) + m_redoStack.push(m_currentState); + + idd->restoreDocument(this); + m_currentState = idd; + + setModified( m_savedState != m_currentState ); + emit undoRedoStateChanged(); +} + + +void ItemDocument::redo() +{ + ItemDocumentData *idd = m_redoStack.pop(); + if (!idd) + return; + + if (m_currentState) + m_undoStack.push(m_currentState); + + idd->restoreDocument(this); + m_currentState = idd; + + setModified( m_savedState != m_currentState ); + emit undoRedoStateChanged(); +} + + +void ItemDocument::cut() +{ + copy(); + deleteSelection(); +} + + +void ItemDocument::paste() +{ + QString xml = KApplication::clipboard()->text( QClipboard::Clipboard ); + if ( xml.isEmpty() ) + return; + + unselectAll(); + + ItemDocumentData data( type() ); + data.fromXML(xml); + data.generateUniqueIDs(this); + data.translateContents( 64, 64 ); + data.mergeWithDocument( this, true ); + + // Get rid of any garbage that shouldn't be around / merge connectors / etc + flushDeleteList(); + + requestStateSave(); +} + + +Item *ItemDocument::itemWithID( const QString &id ) +{ + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + if ( (*it)->id() == id ) + return *it; + } + return 0L; +} + + +void ItemDocument::unselectAll() +{ + selectList()->removeAllItems(); +} + + +void ItemDocument::select( QCanvasItem * item ) +{ + if (!item) + return; + item->setSelected( selectList()->contains( item ) || selectList()->addQCanvasItem( item ) ); +} + + +void ItemDocument::select( const QCanvasItemList & list ) +{ + const QCanvasItemList::const_iterator end = list.end(); + for ( QCanvasItemList::const_iterator it = list.begin(); it != end; ++it ) + selectList()->addQCanvasItem(*it); + + selectList()->setSelected(true); +} + + +void ItemDocument::unselect( QCanvasItem *qcanvasItem ) +{ + selectList()->removeQCanvasItem(qcanvasItem); + qcanvasItem->setSelected(false); +} + + +void ItemDocument::slotUpdateConfiguration() +{ + updateBackground(); + m_canvas->setUpdatePeriod( int(1000./KTLConfig::refreshRate()) ); +} + + +QCanvasItem* ItemDocument::itemAtTop( const QPoint &pos ) const +{ + QCanvasItemList list = m_canvas->collisions( QRect( pos.x()-1, pos.y()-1, 3, 3 ) ); + + QCanvasItemList::const_iterator it = list.begin(); + const QCanvasItemList::const_iterator end = list.end(); + while ( it != end ) + { + QCanvasItem *item = *it; + if ( item == m_canvasTip || + item->rtti() == QCanvasItem::Rtti_Line || + item->rtti() == QCanvasItem::Rtti_Text || + item->rtti() == QCanvasItem::Rtti_Rectangle ) + { + ++it; + } + else + { + if ( item->rtti() == ItemDocument::RTTI::ConnectorLine ) + return (static_cast(item))->parent(); + + return item; + } + } + + return 0L; +} + + + +void ItemDocument::alignHorizontally( ) +{ + selectList()->slotAlignHorizontally(); + if ( ICNDocument *icnd = dynamic_cast(this) ) + icnd->requestRerouteInvalidatedConnectors(); +} +void ItemDocument::alignVertically( ) +{ + selectList()->slotAlignVertically(); + if ( ICNDocument *icnd = dynamic_cast(this) ) + icnd->requestRerouteInvalidatedConnectors(); +} +void ItemDocument::distributeHorizontally( ) +{ + selectList()->slotDistributeHorizontally(); + if ( ICNDocument *icnd = dynamic_cast(this) ) + icnd->requestRerouteInvalidatedConnectors(); +} +void ItemDocument::distributeVertically( ) +{ + selectList()->slotDistributeVertically(); + if ( ICNDocument *icnd = dynamic_cast(this) ) + icnd->requestRerouteInvalidatedConnectors(); +} + + +bool ItemDocument::registerUID( const QString &UID ) +{ + if ( m_idList.findIndex(UID) == -1 ) + { + m_idList.append(UID); + return true; + } + + return false; +} + + +void ItemDocument::unregisterUID( const QString & uid ) +{ + m_idList.remove(uid); +} + + +QString ItemDocument::generateUID( QString name ) +{ + name.remove( QRegExp("__.*") ); // Change 'node__13' to 'node', for example + QString idAttempt = name; +// if ( idAttempt.find("__") != -1 ) idAttempt.truncate( idAttempt.find("__") ); + while ( !registerUID(idAttempt) ) { idAttempt = name + "__" + QString::number(m_nextIdNum++); } + + return idAttempt; +} + + +void ItemDocument::canvasRightClick( const QPoint &pos, QCanvasItem* item ) +{ + if (item) + { + if ( item->rtti() == ItemDocument::RTTI::CNItem && + !item->isSelected() ) + { + unselectAll(); + select(item); + } + } + + p_ktechlab->unplugActionList("alignment_actionlist"); + p_ktechlab->unplugActionList("orientation_actionlist"); + p_ktechlab->unplugActionList("component_actionlist"); + fillContextMenu(pos); + + QPopupMenu *pop = static_cast(p_ktechlab->factory()->container("item_popup", p_ktechlab)); + + if (!pop) + return; + + pop->popup(pos); +} + + +void ItemDocument::fillContextMenu( const QPoint & pos ) +{ + Q_UNUSED(pos); + + ItemView * activeItemView = dynamic_cast(activeView()); + if ( !p_ktechlab || !activeItemView ) + return; + + KAction * align_actions[] = { + activeItemView->action("align_horizontally"), + activeItemView->action("align_vertically"), + activeItemView->action("distribute_horizontally"), + activeItemView->action("distribute_vertically") }; + + bool enableAlignment = selectList()->itemCount() > 1; + + if ( !enableAlignment ) + return; + + for ( unsigned i = 0; i < 4; ++i ) + { + align_actions[i]->setEnabled(true); + m_pAlignmentAction->remove( align_actions[i] ); + m_pAlignmentAction->insert( align_actions[i] ); + } + QPtrList alignment_actions; + alignment_actions.append( m_pAlignmentAction ); + p_ktechlab->plugActionList( "alignment_actionlist", alignment_actions ); +} + + +void ItemDocument::slotInitItemActions( Item *item ) +{ + Q_UNUSED(item); + + ItemView * activeItemView = dynamic_cast(activeView()); + if ( !p_ktechlab || !activeItemView ) + return; + + KAction * align_actions[] = { + activeItemView->action("align_horizontally"), + activeItemView->action("align_vertically"), + activeItemView->action("distribute_horizontally"), + activeItemView->action("distribute_vertically") }; + + bool enableAlignment = selectList()->itemCount() > 1; + for ( unsigned i = 0; i < 4; ++i ) + align_actions[i]->setEnabled(enableAlignment); +} + + +void ItemDocument::updateBackground() +{ + // Also used in the constructor to make the background initially. + + // Thoughts. + // ~The pixmap could be done somehow with 1bpp. It might save some waste + // I expect it won't hurt for now. + // ~This is all rather static, only works with square etc... should be no prob. for most uses. IMO. + // ~If you want, decide what maximum and minimum spacing should be, then enforce them + // in the Config (I suppose you can use tags?) + // ~Defaults based on the existing grid background png. It should produce identical results, to your + // original png. + + // **** Below where it says "interval * 10", that decides how big the pixmap will be (always square) + // Originally I set this to 32, which give 256x256 with 8 spacing, as that was the size of your pixmap + // Are there any good reasons to make the a certain size? (i.e. big or small ?). + + int interval = 8; + int bigness = interval * 10; + QPixmap pm( bigness, bigness ); +// pm.fill( KTLConfig::bgColor() ); // first fill the background colour in + pm.fill( Qt::white ); + + if( KTLConfig::showGrid() ){ + QPainter p(&pm); // setup painter to draw on pixmap + p.setPen( KTLConfig::gridColor() ); // set forecolour + // note: anything other than 8 borks this + for( int i = (interval / 2); i < bigness; i+=interval ){ + p.drawLine( 0, i, bigness, i ); // horizontal + p.drawLine( i, 0, i, bigness ); // vertical + } + p.end(); // all done + } + + pm.setDefaultOptimization( QPixmap::BestOptim ); + m_canvas->setBackgroundPixmap(pm); // and the finale. +} + + +void ItemDocument::requestEvent( ItemDocumentEvent::type type ) +{ + m_queuedEvents |= type; + m_pEventTimer->stop(); + m_pEventTimer->start( 0, true ); +} + + +void ItemDocument::processItemDocumentEvents() +{ + // Copy it incase we have new events requested while doing this... + unsigned queuedEvents = m_queuedEvents; + m_queuedEvents = 0; + + if ( queuedEvents & ItemDocumentEvent::ResizeCanvasToItems ) + resizeCanvasToItems(); + + if ( queuedEvents & ItemDocumentEvent::UpdateZOrdering ) + slotUpdateZOrdering(); + + ICNDocument * icnd = dynamic_cast(this); + + if ( icnd && (queuedEvents & ItemDocumentEvent::UpdateNodeGroups) ) + icnd->slotAssignNodeGroups(); + + if ( icnd && (queuedEvents & ItemDocumentEvent::RerouteInvalidatedConnectors) ) + icnd->rerouteInvalidatedConnectors(); +} + + +void ItemDocument::resizeCanvasToItems() +{ + const ViewList::iterator end = m_viewList.end(); + + QRect bound = canvasBoundingRect(); + QSize size( bound.right(), bound.bottom() ); + + m_viewList.remove((View*)0); + + for ( ViewList::iterator it = m_viewList.begin(); it != end; ++it ) + { + CVBEditor * cvbEditor = (static_cast((View*)*it))->cvbEditor(); + + int contentsX, contentsY; + int contentsWMX, contentsWMY; + + cvbEditor->viewportToContents( cvbEditor->viewport()->width(), cvbEditor->viewport()->height(), contentsX, contentsY ); + cvbEditor->inverseWorldMatrix().map( contentsX, contentsY, &contentsWMX, &contentsWMY ); + + // Hack to fix a bug whereby when scrolled, but emoty gap before scrollbars, + // size slowly decreases one pixel at a time + if ( (contentsX - contentsWMX) == 1 ) + contentsWMX = contentsX; + if ( (contentsY - contentsWMY) == 1 ) + contentsWMY = contentsY; + + size = size.expandedTo( QSize( contentsWMX, contentsWMY ) ); + } + + // We want to avoid flicker.... + for ( ViewList::iterator it = m_viewList.begin(); it != end; ++it ) + { + ItemView * itemView = static_cast((View*)*it); + CVBEditor * cvbEditor = itemView->cvbEditor(); + + cvbEditor->setVScrollBarMode( ((size.height()*itemView->zoomLevel()) > cvbEditor->visibleHeight()) ? QScrollView::AlwaysOn : QScrollView::AlwaysOff ); + cvbEditor->setHScrollBarMode( ((size.width()*itemView->zoomLevel()) > cvbEditor->visibleWidth()) ? QScrollView::AlwaysOn : QScrollView::AlwaysOff ); + } + + bool changedSize = canvas()->size() != size; + canvas()->resize( size.width(), size.height() ); + + if (changedSize) + requestEvent( ItemDocumentEvent::ResizeCanvasToItems ); + else if ( ICNDocument * icnd = dynamic_cast(this) ) + icnd->createCellMap(); +} + + +QRect ItemDocument::canvasBoundingRect() const +{ + QRect bound; + + const QCanvasItemList allItems = canvas()->allItems(); + const QCanvasItemList::const_iterator end = allItems.end(); + for ( QCanvasItemList::const_iterator it = allItems.begin(); it != end; ++it ) + { + if ( !(*it)->isVisible() ) + continue; + bound |= (*it)->boundingRect(); + } + + if ( !bound.isNull() ) + { + bound.setLeft( bound.left() - 16 ); + bound.setTop( bound.top() - 16 ); + bound.setRight( bound.right() + 16 ); + bound.setBottom( bound.bottom() + 16 ); + } + + return bound; +} + + +void ItemDocument::exportToImage() +{ + // scaralously copied from print. + // this slot is called whenever the File->Export menu is selected, + // the Export shortcut is pressed or the Export toolbar + // button is clicked + + // widget for the kfiledialog + // It is the bit that says "Crop circuit?" + // Okay need to think of something way better to say here. + // gotme here, KFileDialog makes itself parent so tries to destroy cropCheck when it is deleted. + // therefore we use a pointer. + QString cropMessage; + if ( type() == Document::dt_flowcode ) + cropMessage = i18n("Crop image to program parts"); + + else if ( type() == Document::dt_circuit ) + cropMessage = i18n("Crop image to circuit components"); + + else + cropMessage = i18n("Crop image"); + + QCheckBox *cropCheck = new QCheckBox( cropMessage, p_ktechlab, "cropCheck" ); + cropCheck->setChecked(true); // yes by default? + + // we need an object so we can retrieve which image type was selected by the user + // so setup the filedialog. + KFileDialog exportDialog(QString::null, "*.png|PNG Image\n*.bmp|BMP Image\n*.svg|SVG Image" , p_ktechlab, i18n("Export As Image"), true, cropCheck); + + exportDialog.setOperationMode( KFileDialog::Saving ); + // now actually show it + if ( exportDialog.exec() == QDialog::Rejected ) + return; + KURL url = exportDialog.selectedURL(); + + if ( url.isEmpty() ) + return; + + if ( QFile::exists( url.path() ) ) + { + int query = KMessageBox::warningYesNo( p_ktechlab, i18n( "A file named \"%1\" already exists. " "Are you sure you want to overwrite it?" ).arg( url.fileName() ), i18n( "Overwrite File?" ), i18n( "Overwrite" ), KStdGuiItem::cancel() ); + if ( query == KMessageBox::No ) return; + } + + // with Qt, you always "print" to a + // QPainter.. whether the output medium is a pixmap, a screen, + // or paper + + // needs to be something like QPicture to do SVG etc... + // at the moment the pixmap is just as big as the canvas, + // intend to make some kind of cropping thing so it just + // takes the bit with the circuit on. + + QRect saveArea; + QString type; + QRect cropArea; + QPaintDevice *outputImage; + QString filter = exportDialog.currentFilter(); + filter = filter.lower(); // gently soften the appearance of the letters. + + // did have a switch here but seems you can't use that on strings + if ( filter == "*.png" ) + type = "PNG"; + + else if ( filter == "*.bmp" ) + type = "BMP"; + + else if ( filter == "*.svg" ) + { + KMessageBox::information( NULL, i18n("SVG export is sub-functional"), i18n("Export As Image") ); + type = "SVG"; + } + // I don't like forcing people to use the right extension (personally) + // but it is the easiest way to decide image type. + else + { + KMessageBox::sorry( NULL, i18n("Unknown extension, please select one from the filter list."), i18n("Export As Image") ); + return; + } + + if ( cropCheck->isChecked() ) + { + cropArea = canvasBoundingRect(); + if ( cropArea.isNull() ) + { + KMessageBox::sorry( 0l, i18n("There is nothing to crop"), i18n("Export As Image") ); + return; + } + else + { + cropArea &= canvas()->rect(); + } + } + + saveArea = m_canvas->rect(); + + if ( type == "PNG" || type == "BMP" ) + outputImage = new QPixmap( saveArea.size() ); + + else if ( type == "SVG" ) + { + setSVGExport(true); + outputImage = new QPicture(); + // svg can't be cropped using the qimage method. + saveArea = cropArea; + } + else + { + kdWarning() << "Unknown type!" << endl; + return; + } + + QPainter p(outputImage); + + m_canvas->setBackgroundPixmap(QPixmap()); + m_canvas->drawArea( saveArea, &p ); + updateBackground(); + + p.end(); + + bool saveResult; + + // if cropping we need to convert to an image, + // crop, then save. + if ( cropCheck->isChecked() ) + { + if( type == "SVG" ) + saveResult = dynamic_cast(outputImage)->save( url.path(), type); + + else + { + QImage img = dynamic_cast(outputImage)->convertToImage(); + img = img.copy(cropArea); + saveResult = img.save(url.path(),type); + } + } + else + { + if ( type=="SVG" ) + saveResult = dynamic_cast(outputImage)->save( url.path(), type ); + else + saveResult = dynamic_cast(outputImage)->save( url.path(), type ); + } + + //if(saveResult == true) KMessageBox::information( this, i18n("Sucessfully exported to \"%1\"").arg( url.filename() ), i18n("Image Export") ); + //else KMessageBox::information( this, i18n("Export failed"), i18n("Image Export") ); + + if ( type == "SVG" ) + setSVGExport(false); + + if (saveResult == false) + KMessageBox::information( p_ktechlab, i18n("Export failed"), i18n("Image Export") ); + + delete outputImage; +} + + +void ItemDocument::setSVGExport( bool svgExport ) +{ + // Find any items and tell them not to draw buttons or sliders + QCanvasItemList items = m_canvas->allItems(); + const QCanvasItemList::iterator end = items.end(); + for ( QCanvasItemList::Iterator it = items.begin(); it != end; ++it ) + { + if ( CNItem * cnItem = dynamic_cast(*it) ) + cnItem->setDrawWidgets(!svgExport); + } +} + +void ItemDocument::raiseZ() +{ + raiseZ( selectList()->items(true) ); +} +void ItemDocument::raiseZ( const ItemList & itemList ) +{ + if ( m_zOrder.isEmpty() ) + slotUpdateZOrdering(); + + if ( m_zOrder.isEmpty() ) + return; + + IntItemMap::iterator begin = m_zOrder.begin(); + IntItemMap::iterator previous = m_zOrder.end(); + IntItemMap::iterator it = --m_zOrder.end(); + do + { + Item * previousData = (previous == m_zOrder.end()) ? 0l : previous.data(); + Item * currentData = it.data(); + + if ( currentData && previousData && itemList.contains(currentData) && !itemList.contains(previousData) ) + { + previous.data() = currentData; + it.data() = previousData; + } + + previous = it; + --it; + } + while ( previous != begin ); + + slotUpdateZOrdering(); +} + + +void ItemDocument::lowerZ() +{ + lowerZ( selectList()->items(true) ); +} +void ItemDocument::lowerZ( const ItemList & itemList ) +{ + if ( m_zOrder.isEmpty() ) + slotUpdateZOrdering(); + + if ( m_zOrder.isEmpty() ) + return; + + IntItemMap::iterator previous = m_zOrder.begin(); + IntItemMap::iterator end = m_zOrder.end(); + for ( IntItemMap::iterator it = m_zOrder.begin(); it != end; ++it ) + { + Item * previousData = previous.data(); + Item * currentData = it.data(); + + if ( currentData && previousData && itemList.contains(currentData) && !itemList.contains(previousData) ) + { + previous.data() = currentData; + it.data() = previousData; + } + + previous = it; + } + + slotUpdateZOrdering(); +} + + +void ItemDocument::itemAdded( Item * ) +{ + requestEvent( ItemDocument::ItemDocumentEvent::UpdateZOrdering ); +} + + +void ItemDocument::slotUpdateZOrdering() +{ + ItemList toAdd = m_itemList; + toAdd.remove((Item*)0l); + + IntItemMap newZOrder; + int atLevel = 0; + + IntItemMap::iterator zEnd = m_zOrder.end(); + for ( IntItemMap::iterator it = m_zOrder.begin(); it != zEnd; ++it ) + { + Item * item = it.data(); + if (!item) + continue; + + toAdd.remove(item); + + if ( !item->parentItem() && item->isMovable() ) + newZOrder[atLevel++] = item; + } + + ItemList::iterator addEnd = toAdd.end(); + for ( ItemList::iterator it = toAdd.begin(); it != addEnd; ++it ) + { + Item * item = *it; + if ( item->parentItem() || !item->isMovable() ) + continue; + + newZOrder[atLevel++] = item; + } + + m_zOrder = newZOrder; + + zEnd = m_zOrder.end(); + for ( IntItemMap::iterator it = m_zOrder.begin(); it != zEnd; ++it ) + it.data()->updateZ( it.key() ); +} + + +void ItemDocument::update( ) +{ + ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + if ( (*it)->hasDynamicContent() ) + (*it)->setChanged(); + } +} +//END class ItemDocument + + + +//BEGIN class CanvasTip +CanvasTip::CanvasTip( ItemDocument *itemDocument, QCanvas *qcanvas ) + : QCanvasText(qcanvas) +{ + p_itemDocument = itemDocument; + + setColor( Qt::black ); + setZ( ICNDocument::Z::Tip ); +} + +CanvasTip::~CanvasTip() +{ +} + +void CanvasTip::displayVI( ECNode *node, const QPoint &pos ) +{ + if ( !node || !updateVI() ) + return; + + unsigned num = node->numPins(); + + m_v.resize(num); + m_i.resize(num); + + for ( unsigned i = 0; i < num; i++ ) + { + if ( Pin * pin = node->pin(i) ) + { + m_v[i] = pin->voltage(); + m_i[i] = pin->current(); + } + } + + display(pos); +} + + +void CanvasTip::displayVI( Connector *connector, const QPoint &pos ) +{ + if ( !connector || !updateVI()) + return; + + unsigned num = connector->numWires(); + + m_v.resize(num); + m_i.resize(num); + + for ( unsigned i = 0; i < num; i++ ) + { + if ( Wire * wire = connector->wire(i) ) + { + m_v[i] = wire->voltage(); + m_i[i] = std::abs(wire->current()); + } + } + + display(pos); +} + + +bool CanvasTip::updateVI() +{ + CircuitDocument *circuitDocument = dynamic_cast(p_itemDocument); + if ( !circuitDocument || !Simulator::self()->isSimulating() ) + return false; + + circuitDocument->calculateConnectorCurrents(); + return true; +} + + +void CanvasTip::display( const QPoint &pos ) +{ + unsigned num = m_v.size(); + + for ( unsigned i = 0; i < num; i++ ) + { + if ( !std::isfinite(m_v[i]) || std::abs(m_v[i]) < 1e-9 ) + m_v[i] = 0.; + + if ( !std::isfinite(m_i[i]) || std::abs(m_i[i]) < 1e-9 ) + m_i[i] = 0.; + } + + move( pos.x()+20, pos.y()+4 ); + + if ( num == 0 ) + return; + + if ( num == 1 ) + setText( displayText(0) ); + + else + { + QString text; + for ( unsigned i = 0; i < num; i++ ) + text += QString(" %1: %2\n").arg( QString::number(i) ).arg( displayText(i) ); + setText(text); + } +} + + +QString CanvasTip::displayText( unsigned num ) const +{ + if ( m_v.size() <= num ) + return QString::null; + + return QString(" %1%2V %3%4A ") + .arg( QString::number( m_v[num] / CNItem::getMultiplier(m_v[num]), 'g', 3 ) ) + .arg( CNItem::getNumberMag( m_v[num] ) ) + .arg( QString::number( m_i[num] / CNItem::getMultiplier(m_i[num]), 'g', 3 ) ) + .arg( CNItem::getNumberMag( m_i[num] ) ); +} + + +void CanvasTip::draw( QPainter &p ) +{ + CircuitDocument *circuitDocument = dynamic_cast(p_itemDocument); + if ( !circuitDocument || !Simulator::self()->isSimulating() ) + return; + + p.setBrush( QColor( 0xff, 0xff, 0xdc ) ); + p.setPen( Qt::black ); + p.drawRect( boundingRect() ); + QCanvasText::draw(p); +} +//END class CanvasTip + + + + +//BEGIN class Canvas +Canvas::Canvas( ItemDocument *itemDocument, const char * name ) + : QCanvas( itemDocument, name ) +{ + p_itemDocument = itemDocument; + m_pMessageTimeout = new QTimer(this); + connect( m_pMessageTimeout, SIGNAL(timeout()), this, SLOT(slotSetAllChanged()) ); +} + + +void Canvas::setMessage( const QString & message ) +{ + m_message = message; + + if ( message.isEmpty() ) + m_pMessageTimeout->stop(); + + else + m_pMessageTimeout->start( 2000, true ); + + setAllChanged(); +} + + +void Canvas::drawBackground ( QPainter &p, const QRect & clip ) +{ + QCanvas::drawBackground( p, clip ); +#if 0 + const int scx = (int)((clip.left()-4)/8); + const int ecx = (int)((clip.right()+4)/8); + const int scy = (int)((clip.top()-4)/8); + const int ecy = (int)((clip.bottom()+4)/8); + if ( !((ICNDocument*)(p_itemDocument))->isValidCellReference( scx, scy ) || + !((ICNDocument*)(p_itemDocument))->isValidCellReference( ecx, ecy ) ) return; + Cells *c = ((ICNDocument*)(p_itemDocument))->cells(); + for ( int x=scx; x<=ecx; x++ ) + { + for ( int y=scy; y<=ecy; y++ ) + { + const double score = (*c)[x][y].CIpenalty+(*c)[x][y].Cpenalty; + int value = (int)std::log(score)*20; + if ( value>255 ) value=255; + else if (value<0 ) value=0; + p.setBrush( QColor( 255, (255-value), (255-value) ) ); + p.setPen( Qt::NoPen ); + p.drawRect( (x*8), (y*8), 8, 8 ); + } + } +#endif +} + + +void Canvas::drawForeground ( QPainter &p, const QRect & clip ) +{ + QCanvas::drawForeground( p, clip ); + + if ( !m_pMessageTimeout->isActive() ) + return; + + + + // Following code stolen and adapted from amarok/src/playlist.cpp :) + + // Find out width of smallest view + QSize minSize; + const ViewList viewList = p_itemDocument->viewList(); + ViewList::const_iterator end = viewList.end(); + View * firstView = 0l; + for ( ViewList::const_iterator it = viewList.begin(); it != end; ++it ) + { + if ( !*it ) + continue; + + if ( !firstView ) + { + firstView = *it; + minSize = (*it)->size(); + } + else + minSize = minSize.boundedTo( (*it)->size() ); + } + + if ( !firstView ) + return; + + QSimpleRichText * t = new QSimpleRichText( m_message, QApplication::font() ); + + int w = t->width(); + int h = t->height(); + int x = 15; + int y = 15; + int b = 10; // text padding + + if ( w+2*b >= minSize.width() || h+2*b >= minSize.height() ) + { + delete t; + return; + } + + p.setBrush( firstView->colorGroup().background() ); + p.drawRoundRect( x, y, w+2*b, h+2*b, (8*200)/(w+2*b), (8*200)/(h+2*b) ); + t->draw( &p, x+b, y+b, QRect(), firstView->colorGroup() ); + delete t; +} + + +void Canvas::update() +{ + p_itemDocument->update(); + QCanvas::update(); +} +//END class Canvas + +#include "itemdocument.moc" + + diff --git a/src/itemdocument.h b/src/itemdocument.h new file mode 100644 index 0000000..e9e9f6f --- /dev/null +++ b/src/itemdocument.h @@ -0,0 +1,449 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ITEMDOCUMENT_H +#define ITEMDOCUMENT_H + +#include +#include +#include +#include + +class Canvas; +class CanvasTip; +class Connector; +class CMManager; +class ECNode; +class Item; +class ItemDocumentData; +class ItemGroup; +class KTechlab; +class Operation; + +class KActionMenu; +class QCanvasItem; + +typedef QPtrStack IDDStack; +typedef QGuardedPtr GuardedItem; +typedef QMap< int, GuardedItem > IntItemMap; +typedef QValueList ItemList; +typedef QValueList QPointList; + +/** +@author David Saxton +*/ +class ItemDocument : public Document +{ + Q_OBJECT + public: + ItemDocument( const QString &caption, KTechlab *ktechlab, const char *name = 0 ); + ~ItemDocument(); + + class Z + { + public: + enum + { + Select = 10000000, + Connector = 20000000, + Item = 30000000, + RaisedItem = 40000000, + ResizeHandle = 50000000, + Tip = 60000000, + ConnectorCreateLine = 70000000, + + // How much "Z" separates items stacked on each other + DeltaItem = 10000 + }; + }; + + class RTTI + { + public: + enum + { + None = 1000, + CNItem = 1001, + Node = 1002, + Connector = 1003, + Pin = 1004, + Widget = 1005, + MechanicsItem = 1006, + ResizeHandle = 1007, + DrawPart = 1008, + ConnectorLine = 1009 + }; + }; + + /** + * Some things (such as the canvas getting resized, connectors being + * invalidated, need to be done after editing operations have finished, + * etc, and they also need to be done in the order given in the + * enumeration below. + */ + class ItemDocumentEvent + { + public: enum type + { + ResizeCanvasToItems = 1 << 0, + UpdateNodeGroups = 1 << 1, + RerouteInvalidatedConnectors = 1 << 2, + UpdateZOrdering = 1 << 3, + }; + }; + + virtual void fileSave(); + virtual void fileSaveAs(); + virtual void print(); + virtual bool openURL( const KURL &url ); + /** + * Attempt to register the item, returning true iff successful + */ + virtual bool registerItem( QCanvasItem *qcanvasItem ); + /** + * Will attempt to create an item with the given id at position p. Some item + * (such as PIC/START) have restrictions, and can only have one instance of + * themselves on the canvas, and adds the operation to the undo list + */ + virtual Item* addItem( const QString &id, const QPoint &p, bool newItem ) = 0; + /** + * @returns A pointer to the canvas + */ + Canvas *canvas() const { return m_canvas; } + /** + * Attemtps to register a unique id for the canvas view of an item on the + * canvas. If the id does not already exist, will return true; otherwise + * the function will return false. + */ + bool registerUID( const QString & uid ); + /** + * Generates a unique id based on a possibly unique component name. + */ + QString generateUID( QString name ); + /** + * Unlists the given id as one that is used. + * @see registerUID + */ + void unregisterUID( const QString & uid ); + /** + * @return Whether or not the item is valid; i.e. is appropriate to the + * document being edited, and does not have other special restrictions + * on it (such as only allowing one instance of the Start part in + * FlowCode). + */ + virtual bool isValidItem( Item *item ) = 0; + /** + * @return Whether or not the item is valid; i.e. is appropriate to the + * document being edited, and does not have other special restrictions + * on it (such as only allowing one instance of the Start part in + * FlowCode). + */ + virtual bool isValidItem( const QString &itemId ) = 0; + /** + * Increases the "height" of the given list of items by "one". + */ + void raiseZ( const ItemList & itemList ); + /** + * Decreases the "height" of the given list of items by "one". + */ + void lowerZ( const ItemList & itemList ); + /** + * @return ItemGroup that is used as the select list for this document. + */ + virtual ItemGroup *selectList() const = 0; + /** + * Deselects any currently selected items + */ + void unselectAll(); + /** + * Select a list of QCanvasItem's + */ + void select( const QCanvasItemList & list ); + /** + * Select a QCanvasItem + */ + void select( QCanvasItem * item ); + /** + * Unselects the item + */ + void unselect( QCanvasItem *qcanvasItem ); + /** + * Deletes anything waiting to be deleted. + */ + virtual void flushDeleteList() = 0; + /** + * Returns a rubber-band rectangle that contains all of the items on the + * canvas, padded out by a small border. + */ + QRect canvasBoundingRect() const; + /** + * Returns a pointer to a Item on the canvas with the given id, + * or NULL if no such Item exists. + */ + Item* itemWithID( const QString & ); + /** + * Returns true if the the user can perform an undo action + * (i.e. the undo stack is not empty) + */ + virtual bool isUndoAvailable() const; + /** + * Returns true if the the user can perform an redo action + * (i.e. the redo stack is not empty) + */ + virtual bool isRedoAvailable() const; + /** + * Returns the top item at point (x, y), or NULL if there is no item there + */ + QCanvasItem* itemAtTop( const QPoint &pos ) const; + /** + * Called when the canvas is clicked on with the right mouse button. + * Popups up a menu for editing operations + */ + virtual void canvasRightClick( const QPoint &pos, QCanvasItem* item ); + /** + * List of items in the ItemDocument + */ + ItemList itemList() const { return m_itemList; } + /** + * Set the given QCanvasItem (which will attempt to be casted to known + * items to be deleted. + */ + virtual void appendDeleteList( QCanvasItem * ) = 0; + /** + * Save the current state of the document to the undo/redo history. + * @param actionTicket if this is non-negative, and the last state save + * also had the same actionTicket, then the next state save will + * overwrite the previous state save. + * @see getActionTicket + */ + void requestStateSave( int actionTicket = -1 ); + /** + * Returns a unique id, for use in requestStateSave + */ + int getActionTicket() const { return m_nextActionTicket++; } + /** + * Clears the undo / redo history + */ + void clearHistory(); + /** + * Requests an event to be done after other stuff (editing, etc) is finished. + */ + void requestEvent( ItemDocumentEvent::type type ); + /** + * Called from Canvas (when QCanvas::advance is called). + */ + virtual void update(); + + public slots: + virtual void undo(); + virtual void redo(); + virtual void cut(); + virtual void paste(); + /** + * Selects everything in the view. + */ + virtual void selectAll() = 0; + /** + * Increases the "height" of the selected items. + */ + void raiseZ(); + /** + * Decreases the "height" of the selected items. + */ + void lowerZ(); + /** + * Brings up a file dialog requesting the location of the file to export + * to, and then exports an image of the canvas. + */ + void exportToImage(); + /** + * Deletes whatever is selected. + */ + virtual void deleteSelection() {}; + /** + * Called when the user presses Escape (or similar) + */ + void cancelCurrentOperation(); + /** + * Sets the y-positions of the selected items to the average of the + * initial y-positions. + */ + void alignHorizontally(); + /** + * Sets the x-positions of the selected items to the average of the + * initial x-positions. + */ + void alignVertically(); + /** + * Averages out the horizontal spacing between the selected items. + */ + void distributeHorizontally(); + /** + * Averages out the vertical spacing between the selected items. + */ + void distributeVertically(); + /** + * Adds an items not in the Z ordering to the ordering, and removes any + * items from the Z ordering if they have parents. Then, calls all items + * found in the ordering to tell them their Z position. + */ + void slotUpdateZOrdering(); + /** + * Call this with ItemDocument::DrawAction to start drawing the given thing + */ + void slotSetDrawAction( int da ); + /** + * Sets the editing mode to repeatedly creating a CNItem + * with the given id. Usually called when the user double-clicks on + * the component box. + */ + void slotSetRepeatedItemId( const QString &id ); + /** + * Unsets the editing mode from repeatedly creating a CNItem + */ + void slotUnsetRepeatedItemId(); + /** + * Called when the user changes the configuration. + * This, for example, will tell the CNItems on the canvas to update + * their configuration. + */ + virtual void slotUpdateConfiguration(); + /** + * Enables / disables / selects various actions depending on + * what is selected or not. + */ + virtual void slotInitItemActions( Item *item = 0 ); + /** + * Process queued events (see ItemDocument::ItemDocumentEvent). + */ + void processItemDocumentEvents(); + + signals: + /** + * Emitted when a Item is selected + */ + void itemSelected( Item *item ); + /** + * Emitted when a Item is unselected + */ + void itemUnselected( Item *item = 0 ); + + protected: + /** + * Called from registerItem when a new item is added. + */ + virtual void itemAdded( Item * item ); + virtual void handleNewView( View *view ); + /** + * Set to true to remove buttons and grid and so on from the canvas, set false to put them back + */ + void setSVGExport( bool svgExport ); + void writeFile(); + /** + * Reinherit this if you want to add any options to the right-click context + */ + virtual void fillContextMenu( const QPoint & pos ); + /** + * Reads the background settings (grid-colour, underlying colour) from the Config settings, + * and generates the background pixmap from those settings + */ + void updateBackground(); + /** + * Sets the canvas size to both (a) containing all items present on the + * canvas, and (b) no smaller than the smallest view of the canvas. This + * function should only be called by processItemDocumentEvents - a resize + * request must be made with requestEvent. + */ + void resizeCanvasToItems(); + + Canvas *m_canvas; + KTechlab *p_ktechlab; + QStringList m_idList; + static int m_nextActionTicket; + uint m_nextIdNum; + bool m_bIsLoading; + QSize m_oldCanvasSize; + CMManager *m_cmManager; + ItemList m_itemDeleteList; + ItemList m_itemList; + IDDStack m_undoStack; + IDDStack m_redoStack; + ItemDocumentData * m_currentState; + int m_currentActionTicket; + ItemDocumentData * m_savedState; // Pointer to the document data that holds the state when it saved + QString m_fileExtensionInfo; // For displaying in the save file dialog + CanvasTip * m_canvasTip; + IntItemMap m_zOrder; + KActionMenu * m_pAlignmentAction; + QTimer * m_pEventTimer; + unsigned m_queuedEvents; // OR'ed together list of ItemDocumentEvent::type + + friend class ICNView; + friend class ItemView; +}; + + +/** +@author David Saxton +*/ +class Canvas : public QCanvas +{ + Q_OBJECT + public: + Canvas( ItemDocument *itemDocument, const char * name = 0 ); + + /** + * Sets a message to be displayed on the canvas for a brief period of + * time. If this is called with an empty message, then any existing + * message will be removed. + */ + void setMessage( const QString & message ); + + virtual void update(); + + public slots: + void slotSetAllChanged() { setAllChanged(); } + + protected: + virtual void drawBackground ( QPainter & painter, const QRect & clip ); + virtual void drawForeground ( QPainter & painter, const QRect & clip ); + + ItemDocument *p_itemDocument; + + QString m_message; + QTimer * m_pMessageTimeout; +}; + + +/** +@author David Saxton +*/ +class CanvasTip : public QCanvasText +{ +public: + CanvasTip( ItemDocument *itemDocument, QCanvas *qcanvas ); + virtual ~CanvasTip(); + + void displayVI( ECNode *node, const QPoint &pos ); + void displayVI( Connector *connector, const QPoint &pos ); + +protected: + virtual void draw( QPainter &p ); + bool updateVI(); + void display( const QPoint &pos ); + QString displayText( unsigned num ) const; + + QValueVector m_v; + QValueVector m_i; + ItemDocument *p_itemDocument; +}; + + +#endif diff --git a/src/itemdocumentdata.cpp b/src/itemdocumentdata.cpp new file mode 100644 index 0000000..a582231 --- /dev/null +++ b/src/itemdocumentdata.cpp @@ -0,0 +1,1340 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "connector.h" +#include "ecnode.h" +#include "ecsubcircuit.h" +#include "flowcodedocument.h" +#include "flowcontainer.h" +#include "fpnode.h" +#include "itemdocumentdata.h" +#include "itemlibrary.h" +#include "picitem.h" +#include "pinmapping.h" + +#include +#include +#include +#include +#include +#include +#include + + +// Converts the QBitArray into a string (e.g. "F289A9E") that can be stored in an xml file +static QString toAsciiHex( QBitArray _data ) +{ + QBitArray data = _data; +// data = qCompress(data); + + // Pad out the data to a nice size + if ( (data.size() % 4) != 0 ) + { + data.detach(); + data.resize( data.size() + 4 - (data.size()%4) ); + } + + QString text; + for ( unsigned i = 0; i < data.size()/4; ++i ) + { + unsigned val = 0; + for ( unsigned j = 0; j < 4; ++j ) + val += (data[4*i+j] ? 1:0) << j; + + text += QString::number( val, 16 ); + } + return text; +} + +// Converts a string (e.g. "F289A9E") into a QBitArray, the opposite of the above function +static QBitArray toQBitArray( QString text ) +{ + unsigned size = text.length(); + QBitArray data(size*4); + + for ( unsigned i = 0; i < size; ++i ) + { + unsigned val = QString(text[i]).toInt( 0l, 16 ); + for ( unsigned j = 0; j < 4; ++j ) + data[4*i+j] = val & (1 << j); + } + +// data = qUncompress(data); + + return data; +} + + +//BEGIN class ItemDocumentData +ItemDocumentData::ItemDocumentData( uint documentType ) +{ + reset(); + m_documentType = documentType; +} + + +ItemDocumentData::~ItemDocumentData() +{ +} + + +void ItemDocumentData::reset() +{ + m_itemDataMap.clear(); + m_connectorDataMap.clear(); + m_nodeDataMap.clear(); + m_microData.reset(); + m_documentType = Document::dt_none; +} + + +bool ItemDocumentData::loadData( const KURL &url ) +{ + QString target; + if ( !KIO::NetAccess::download( url, target, 0l ) ) + { + // If the file could not be downloaded, for example does not + // exist on disk, NetAccess will tell us what error to use + KMessageBox::error( 0l, KIO::NetAccess::lastErrorString() ); + + return false; + } + + QFile file(target); + if ( !file.open( IO_ReadOnly ) ) + { + KMessageBox::sorry( 0l, i18n("Could not open %1 for reading").arg(target) ); + return false; + } + + QString xml; + QTextStream textStream( &file ); + while ( !textStream.eof() ) + xml += textStream.readLine() + '\n'; + + file.close(); + return fromXML(xml); +} + + +bool ItemDocumentData::fromXML( const QString &xml ) +{ + reset(); + + QDomDocument doc( "KTechlab" ); + QString errorMessage; + if ( !doc.setContent( xml, &errorMessage ) ) + { + KMessageBox::sorry( 0l, i18n("Couldn't parse xml:\n%1").arg(errorMessage) ); + return false; + } + + QDomElement root = doc.documentElement(); + + QDomNode node = root.firstChild(); + while ( !node.isNull() ) + { + QDomElement element = node.toElement(); + if ( !element.isNull() ) + { + const QString tagName = element.tagName(); + + if ( tagName == "item" ) + elementToItemData(element); + + else if ( tagName == "node" ) + elementToNodeData(element); + + else if ( tagName == "connector" ) + elementToConnectorData(element); + + else if ( tagName == "pic-settings" || tagName == "micro" ) + elementToMicroData(element); + + else if ( tagName == "code" ) + ; // do nothing - we no longer use this tag + + else + kdWarning() << k_funcinfo << "Unrecognised element tag name: "<= 0, then set by a FlowPart, so we don't need to worry about the angle / flip + if ( itemData.orientation >= 0 ) + { + node.setAttribute( "orientation", itemData.orientation ); + } + else + { + node.setAttribute( "angle", itemData.angleDegrees ); + node.setAttribute( "flip", itemData.flipped ); + } + + if ( !itemData.parentId.isEmpty() ) + node.setAttribute( "parent", itemData.parentId ); + + const QStringMap::const_iterator stringEnd = itemData.dataString.end(); + for ( QStringMap::const_iterator it = itemData.dataString.begin(); it != stringEnd; ++it ) + { + QDomElement e = doc.createElement("data"); + node.appendChild(e); + e.setAttribute( "id", it.key() ); + e.setAttribute( "type", "string" ); + e.setAttribute( "value", it.data() ); + } + + const DoubleMap::const_iterator numberEnd = itemData.dataNumber.end(); + for ( DoubleMap::const_iterator it = itemData.dataNumber.begin(); it != numberEnd; ++it ) + { + QDomElement e = doc.createElement("data"); + node.appendChild(e); + e.setAttribute( "id", it.key() ); + e.setAttribute( "type", "number" ); + e.setAttribute( "value", QString::number(it.data()) ); + } + + const QColorMap::const_iterator colorEnd = itemData.dataColor.end(); + for ( QColorMap::const_iterator it = itemData.dataColor.begin(); it != colorEnd; ++it ) + { + QDomElement e = doc.createElement("data"); + node.appendChild(e); + e.setAttribute( "id", it.key() ); + e.setAttribute( "type", "color" ); + e.setAttribute( "value", it.data().name() ); + } + + const QBitArrayMap::const_iterator rawEnd = itemData.dataRaw.end(); + for ( QBitArrayMap::const_iterator it = itemData.dataRaw.begin(); it != rawEnd; ++it ) + { + QDomElement e = doc.createElement("data"); + node.appendChild(e); + e.setAttribute( "id", it.key() ); + e.setAttribute( "type", "raw" ); + e.setAttribute( "value", toAsciiHex(it.data()) ); + } + + const BoolMap::const_iterator boolEnd = itemData.dataBool.end(); + for ( BoolMap::const_iterator it = itemData.dataBool.begin(); it != boolEnd; ++it ) + { + QDomElement e = doc.createElement("data"); + node.appendChild(e); + e.setAttribute( "id", it.key() ); + e.setAttribute( "type", "bool" ); + e.setAttribute( "value", QString::number(it.data()) ); + } + + const BoolMap::const_iterator buttonEnd = itemData.buttonMap.end(); + for ( BoolMap::const_iterator it = itemData.buttonMap.begin(); it != buttonEnd; ++it ) + { + QDomElement e = doc.createElement("button"); + node.appendChild(e); + e.setAttribute( "id", it.key() ); + e.setAttribute( "state", QString::number(it.data()) ); + } + + const IntMap::const_iterator sliderEnd = itemData.sliderMap.end(); + for ( IntMap::const_iterator it = itemData.sliderMap.begin(); it != sliderEnd; ++it ) + { + QDomElement e = doc.createElement("slider"); + node.appendChild(e); + e.setAttribute( "id", it.key() ); + e.setAttribute( "value", QString::number(it.data()) ); + } + + return node; +} + + +void ItemDocumentData::elementToItemData( QDomElement element ) +{ + QString id = element.attribute( "id", QString::null ); + if ( id.isNull() ) + { + kdError() << k_funcinfo << "Could not find id in element" << endl; + return; + } + + ItemData itemData; + itemData.type = element.attribute( "type", QString::null ); + itemData.x = element.attribute( "x", "120" ).toInt(); + itemData.y = element.attribute( "y", "120" ).toInt(); + itemData.z = element.attribute( "z", "-1" ).toInt(); + + if ( element.hasAttribute("width") && + element.hasAttribute("height") ) + { + itemData.setSize = true; + itemData.size = QRect( element.attribute( "offset-x", "0" ).toInt(), + element.attribute( "offset-y", "0" ).toInt(), + element.attribute( "width", "120" ).toInt(), + element.attribute( "height", "120" ).toInt() ); + } + else + itemData.setSize = false; + + itemData.angleDegrees = element.attribute( "angle", "0" ).toInt(); + itemData.flipped = element.attribute( "flip", "0" ).toInt(); + itemData.orientation = element.attribute( "orientation", "-1" ).toInt(); + itemData.parentId = element.attribute( "parent", QString::null ); + + m_itemDataMap[id] = itemData; + + QDomNode node = element.firstChild(); + while ( !node.isNull() ) + { + QDomElement childElement = node.toElement(); + if ( !childElement.isNull() ) + { + const QString tagName = childElement.tagName(); + + if ( tagName == "item" ) + { + // We're reading in a file saved in the older format, with + // child items nestled, so we must specify that the new item + // has the currently parsed item as its parent. + elementToItemData(childElement); + QString childId = childElement.attribute( "id", QString::null ); + if ( !childId.isNull() ) + m_itemDataMap[childId].parentId = id; + } + + else if ( tagName == "data" ) + { + QString dataId = childElement.attribute( "id", QString::null ); + if ( !dataId.isNull() ) + { + QString dataType = childElement.attribute( "type", QString::null ); + QString value = childElement.attribute( "value", QString::null ); + + if ( dataType == "string" || dataType == "multiline" ) + m_itemDataMap[id].dataString[dataId] = value; + else if ( dataType == "number" ) + m_itemDataMap[id].dataNumber[dataId] = value.toDouble(); + else if ( dataType == "color" ) + m_itemDataMap[id].dataColor[dataId] = QColor(value); + else if ( dataType == "raw" ) + m_itemDataMap[id].dataRaw[dataId] = toQBitArray(value); + else if ( dataType == "bool" ) + m_itemDataMap[id].dataBool[dataId] = bool(value.toInt()); + else + kdError() << k_funcinfo << "Unknown data type of \""<itemList() ); + + if ( ICNDocument *icnd = dynamic_cast(itemDocument) ) + { + addConnectors( icnd->connectorList() ); + addNodes( icnd->nodeList() ); + + if ( FlowCodeDocument *fcd = dynamic_cast(itemDocument) ) + { + if ( fcd->microSettings() ) + setMicroData( fcd->microSettings()->microData() ); + } + } + + m_documentType = itemDocument->type(); +} + + +void ItemDocumentData::generateUniqueIDs( ItemDocument *itemDocument ) +{ + if (!itemDocument) + return; + + QStringMap replaced; + replaced[""] = QString::null; + replaced[QString::null] = QString::null; + + ItemDataMap newItemDataMap; + ConnectorDataMap newConnectorDataMap; + NodeDataMap newNodeDataMap; + + //BEGIN Go through and replace the old ids + { + const ItemDataMap::iterator end = m_itemDataMap.end(); + for ( ItemDataMap::iterator it = m_itemDataMap.begin(); it != end; ++it ) + { + if ( !replaced.contains( it.key() ) ) + replaced[it.key()] = itemDocument->generateUID(it.key()); + + newItemDataMap[replaced[it.key()]] = it.data(); + } + } + { + const NodeDataMap::iterator end = m_nodeDataMap.end(); + for ( NodeDataMap::iterator it = m_nodeDataMap.begin(); it != end; ++it ) + { + if ( !replaced.contains( it.key() ) ) + replaced[it.key()] = itemDocument->generateUID(it.key()); + + newNodeDataMap[replaced[it.key()]] = it.data(); + } + } + { + const ConnectorDataMap::iterator end = m_connectorDataMap.end(); + for ( ConnectorDataMap::iterator it = m_connectorDataMap.begin(); it != end; ++it ) + { + if ( !replaced.contains( it.key() ) ) + replaced[it.key()] = itemDocument->generateUID(it.key()); + + newConnectorDataMap[replaced[it.key()]] = it.data(); + } + } + //END Go through and replace the old ids + + //BEGIN Go through and replace the internal references to the ids + { + const ItemDataMap::iterator end = newItemDataMap.end(); + for ( ItemDataMap::iterator it = newItemDataMap.begin(); it != end; ++it ) + { + it.data().parentId = replaced[it.data().parentId]; + } + } + { + const ConnectorDataMap::iterator end = newConnectorDataMap.end(); + for ( ConnectorDataMap::iterator it = newConnectorDataMap.begin(); it != end; ++it ) + { + it.data().startNodeParent = replaced[it.data().startNodeParent]; + it.data().endNodeParent = replaced[it.data().endNodeParent]; + + it.data().startNodeId = replaced[it.data().startNodeId]; + it.data().endNodeId = replaced[it.data().endNodeId]; + } + } + //END Go through and replace the internal references to the ids + + + m_itemDataMap = newItemDataMap; + m_connectorDataMap = newConnectorDataMap; + m_nodeDataMap = newNodeDataMap; +} + + +void ItemDocumentData::translateContents( int dx, int dy ) +{ + //BEGIN Go through and replace the old ids + { + const ItemDataMap::iterator end = m_itemDataMap.end(); + for ( ItemDataMap::iterator it = m_itemDataMap.begin(); it != end; ++it ) + { + it.data().x += dx; + it.data().y += dx; + } + } + { + const NodeDataMap::iterator end = m_nodeDataMap.end(); + for ( NodeDataMap::iterator it = m_nodeDataMap.begin(); it != end; ++it ) + { + it.data().x += dx; + it.data().y += dy; + } + } + { + const ConnectorDataMap::iterator end = m_connectorDataMap.end(); + for ( ConnectorDataMap::iterator it = m_connectorDataMap.begin(); it != end; ++it ) + { + const QPointList::iterator routeEnd = it.data().route.end(); + for ( QPointList::iterator routeIt = it.data().route.begin(); routeIt != routeEnd; ++routeIt ) + { + *routeIt += QPoint( dx/8, dy/8 ); + } + } + } +} + + +void ItemDocumentData::restoreDocument( ItemDocument *itemDocument ) +{ + if ( !itemDocument ) + return; + + ICNDocument *icnd = dynamic_cast(itemDocument); + FlowCodeDocument *fcd = dynamic_cast(icnd); + if ( fcd && !m_microData.id.isEmpty() ) + { + fcd->setPicType(m_microData.id); + fcd->microSettings()->restoreFromMicroData(m_microData); + } + + mergeWithDocument(itemDocument,false); + + { + ItemList removeItems = itemDocument->itemList(); + removeItems.remove((Item*)0l); + + const ItemDataMap::iterator end = m_itemDataMap.end(); + for ( ItemDataMap::iterator it = m_itemDataMap.begin(); it != end; ++it ) + removeItems.remove( itemDocument->itemWithID(it.key()) ); + + const ItemList::iterator removeEnd = removeItems.end(); + for ( ItemList::iterator it = removeItems.begin(); it != removeEnd; ++it ) + { + if ( (*it)->canvas() && (*it)->type() != PicItem::typeString() ) + (*it)->removeItem(); + } + } + + if (icnd) + { + { + NodeList removeNodes = icnd->nodeList(); + removeNodes.remove((Node*)0l); + + const NodeDataMap::iterator end = m_nodeDataMap.end(); + for ( NodeDataMap::iterator it = m_nodeDataMap.begin(); it != end; ++it ) + removeNodes.remove( icnd->nodeWithID( it.key() ) ); + + const NodeList::iterator removeEnd = removeNodes.end(); + for ( NodeList::iterator it = removeNodes.begin(); it != removeEnd; ++it ) + { + if ( (*it)->canvas() && !(*it)->isChildNode() ) + (*it)->removeNode(); + } + } + { + ConnectorList removeConnectors = icnd->connectorList(); + removeConnectors.remove((Connector*)0l); + + const ConnectorDataMap::iterator end = m_connectorDataMap.end(); + for ( ConnectorDataMap::iterator it = m_connectorDataMap.begin(); it != end; ++it ) + removeConnectors.remove( icnd->connectorWithID(it.key()) ); + + const ConnectorList::iterator removeEnd = removeConnectors.end(); + for ( ConnectorList::iterator it = removeConnectors.begin(); it != removeEnd; ++it ) + { + if ( (*it)->canvas() ) + (*it)->removeConnector(); + } + } + } + + itemDocument->flushDeleteList(); +} + + +void ItemDocumentData::mergeWithDocument( ItemDocument *itemDocument, bool selectNew ) +{ + if ( !itemDocument ) + return; + + ICNDocument *icnd = dynamic_cast(itemDocument); + + //BEGIN Restore Nodes + if (icnd) + { + const NodeDataMap::iterator nodeEnd = m_nodeDataMap.end(); + for ( NodeDataMap::iterator it = m_nodeDataMap.begin(); it != nodeEnd; ++it ) + { + if ( !icnd->nodeWithID( it.key() ) ) + { + QString id = it.key(); + if ( itemDocument->type() == Document::dt_circuit ) + new ECNode( icnd, Node::ec_junction, Node::dir_up, QPoint( int(it.data().x), int(it.data().y) ), &id ); + + else if ( itemDocument->type() == Document::dt_flowcode ) + new FPNode( icnd, Node::fp_junction, Node::dir_up, QPoint( int(it.data().x), int(it.data().y) ), &id ); + } + } + for ( NodeDataMap::iterator it = m_nodeDataMap.begin(); it != nodeEnd; ++it ) + { + Node *node = icnd->nodeWithID( it.key() ); + if (node) + node->move( it.data().x, it.data().y ); + } + } + //END Restore Nodes + + + //BEGIN Restore items + const ItemDataMap::iterator itemEnd = m_itemDataMap.end(); + for ( ItemDataMap::iterator it = m_itemDataMap.begin(); it != itemEnd; ++it ) + { + if ( !it.data().type.isEmpty() && !itemDocument->itemWithID( it.key() ) ) + { + Item *item = itemLibrary()->createItem( it.data().type, itemDocument, false, it.key(), false ); + if ( item && !itemDocument->isValidItem(item) ) + { + kdWarning() << "Attempted to create invalid item with id: " << it.key() << endl; + item->removeItem(); + itemDocument->flushDeleteList(); + item = 0l; + } + if (item) + { + //HACK We move the item now before restoreFromItemData is called later, in case it is to be parented + //(as we don't want to move children)... + item->move( it.data().x, it.data().y ); + } + } + } + for ( ItemDataMap::iterator it = m_itemDataMap.begin(); it != itemEnd; ++it ) + { + Item *item = itemDocument->itemWithID(it.key()); + if (!item) + continue; + + item->restoreFromItemData( it.data() ); + item->finishedCreation(); + if (selectNew) + itemDocument->select(item); + item->show(); + } + //END Restore Items + + //BEGIN Restore Connectors + if (icnd) + { + const ConnectorDataMap::iterator connectorEnd = m_connectorDataMap.end(); + for ( ConnectorDataMap::iterator it = m_connectorDataMap.begin(); it != connectorEnd; ++it ) + { + if ( icnd->connectorWithID( it.key() ) ) + continue; + + QString id = it.key(); + Node *startNode = 0l; + Node *endNode = 0l; + + if ( it.data().startNodeIsChild ) + { + CNItem *item = icnd->cnItemWithID( it.data().startNodeParent ); + if (!item) + kdError() << k_funcinfo << "Unable to find node parent with id: "<childNode( it.data().startNodeCId ); + } + else + startNode = icnd->nodeWithID( it.data().startNodeId ); + + if ( it.data().endNodeIsChild ) + { + CNItem *item = icnd->cnItemWithID( it.data().endNodeParent ); + if (!item) + kdError() << k_funcinfo << "Unable to find node parent with id: "<childNode( it.data().endNodeCId ); + } + else + endNode = icnd->nodeWithID( it.data().endNodeId ); + + if ( !startNode || !endNode ) + { + kdError() << k_funcinfo << "End and start nodes for the connector do not both exist" << endl; + } + else + { + Connector *connector = new Connector( startNode, endNode, icnd, &id ); + + startNode->addOutputConnector(connector); + endNode->addInputConnector(connector); + } + } + for ( ConnectorDataMap::iterator it = m_connectorDataMap.begin(); it != connectorEnd; ++it ) + { + Connector *connector = icnd->connectorWithID( it.key() ); + if (connector) + { + connector->restoreFromConnectorData( it.data() ); + if (selectNew) + icnd->select(connector); + } + } + } + //END Restore Connectors + + // This is kind of hackish, but never mind + if ( FlowCodeDocument *fcd = dynamic_cast(itemDocument) ) + { + const ItemList fcdItems = fcd->itemList(); + const ItemList::const_iterator fcdItemsEnd = fcdItems.constEnd(); + for ( ItemList::const_iterator it = fcdItems.constBegin(); it != fcdItemsEnd; ++it ) + { + if ( FlowContainer * fc = dynamic_cast((Item*)*it) ) + fc->updateContainedVisibility(); + } + } +} + + +void ItemDocumentData::setMicroData( const MicroData &data ) +{ + m_microData = data; +} + + +void ItemDocumentData::addItems( const ItemList &itemList ) +{ + const ItemList::const_iterator end = itemList.constEnd(); + for ( ItemList::const_iterator it = itemList.constBegin(); it != end; ++it ) + { + if ( *it && (*it)->canvas() && (*it)->type() != PicItem::typeString() ) + addItemData( (*it)->itemData(), (*it)->id() ); + } +} + + +void ItemDocumentData::addConnectors( const ConnectorList &connectorList ) +{ + const ConnectorList::const_iterator end = connectorList.constEnd(); + for ( ConnectorList::const_iterator it = connectorList.constBegin(); it != end; ++it ) + { + if ( *it && (*it)->canvas() ) + { + if ( (*it)->startNode() && (*it)->endNode() ) + addConnectorData( (*it)->connectorData(), (*it)->id() ); + + else + kdDebug() << k_funcinfo << " *it="<<*it<<" (*it)->startNode()="<<(*it)->startNode()<<" (*it)->endNode()="<<(*it)->endNode()<canvas() && !(*it)->isChildNode() ) + addNodeData( (*it)->nodeData(), (*it)->id() ); + } +} + + +void ItemDocumentData::addItemData( ItemData itemData, QString id ) +{ + m_itemDataMap[id] = itemData; +} + + +void ItemDocumentData::addConnectorData( ConnectorData connectorData, QString id ) +{ + m_connectorDataMap[id] = connectorData; +} + + +void ItemDocumentData::addNodeData( NodeData nodeData, QString id ) +{ + m_nodeDataMap[id] = nodeData; +} +//END class ItemDocumentData + + +//BEGIN class ItemData +ItemData::ItemData() +{ + x = 0; + y = 0; + z = -1; + angleDegrees = 0; + flipped = false; + orientation = -1; + setSize = false; +} +//END class ItemData + + +//BEGIN class ConnectorData +ConnectorData::ConnectorData() +{ + manualRoute = false; + startNodeIsChild = false; + endNodeIsChild = false; +} +//END class ConnectorData + + +//BEGIN class NodeData +NodeData::NodeData() +{ + x = 0; + y = 0; +} +//END class NodeDaata + + +//BEGIN class PinData +PinData::PinData() +{ + type = PinSettings::pt_input; + state = PinSettings::ps_off; +} +//END class PinData + + +//BEGIN class MicroData +MicroData::MicroData() +{ +} + + +void MicroData::reset() +{ + id = QString::null; + pinMap.clear(); +} +//END class MicroData + + +//BEGIN class SubcircuitData +SubcircuitData::SubcircuitData() + : ItemDocumentData( Document::dt_circuit ) +{ +} + + +void SubcircuitData::initECSubcircuit( ECSubcircuit * ecSubcircuit ) +{ + if (!ecSubcircuit) + return; + + generateUniqueIDs( ecSubcircuit->itemDocument() ); + + // Generate a list of the External Connections, sorting by x coordinate + std::multimap< double, QString > extCon; + ItemDataMap::iterator itemEnd = m_itemDataMap.end(); + for ( ItemDataMap::iterator it = m_itemDataMap.begin(); it != itemEnd; ++it ) + { + if ( it.data().type == "ec/external_connection" ) + extCon.insert( std::make_pair( it.data().x, it.key() ) ); + } + + // How many external connections do we have? + ecSubcircuit->setNumExtCon(extCon.size()); + + // Sort the connections into the pins of the subcircuit by y coordinate + std::multimap< double, QString > leftPins; + std::multimap< double, QString > rightPins; + int at = 0; + int size = (extCon.size()/2) + (extCon.size()%2); + const std::multimap< double, QString >::iterator extConEnd = extCon.end(); + for ( std::multimap< double, QString >::iterator it = extCon.begin(); it != extConEnd; ++it ) + { + if ( at < size ) + leftPins.insert( std::make_pair( m_itemDataMap[it->second].y, it->second ) ); + else + rightPins.insert( std::make_pair( m_itemDataMap[it->second].y, it->second ) ); + at++; + } + + // Remove the external connections (recording their names and associated numerical position) + int nodeId = 0; + typedef QMap IntMap; + IntMap nodeMap; + const std::multimap< double, QString >::iterator leftPinsEnd = leftPins.end(); + for ( std::multimap< double, QString >::iterator it = leftPins.begin(); it != leftPinsEnd; ++it ) + { + nodeMap[ it->second ] = nodeId; + ecSubcircuit->setExtConName( nodeId, m_itemDataMap[ it->second ].dataString["name"].data() ); + nodeId++; + m_itemDataMap.remove( it->second ); + } + nodeId = extCon.size()-1; + const std::multimap< double, QString >::iterator rightPinsEnd = rightPins.end(); + for ( std::multimap< double, QString >::iterator it = rightPins.begin(); it != rightPinsEnd; ++it ) + { + nodeMap[ it->second ] = nodeId; + ecSubcircuit->setExtConName( nodeId, m_itemDataMap[ it->second ].dataString["name"].data() ); + nodeId--; + m_itemDataMap.remove( it->second ); + } + + // Replace connector references to the old External Connectors to the nodes + const ConnectorDataMap::iterator connectorEnd = m_connectorDataMap.end(); + for ( ConnectorDataMap::iterator it = m_connectorDataMap.begin(); it != connectorEnd; ++it ) + { + if ( it.data().startNodeIsChild && nodeMap.contains(it.data().startNodeParent ) ) + { + it.data().startNodeCId = QString::number( nodeMap[it.data().startNodeParent] ); + it.data().startNodeParent = ecSubcircuit->id(); + + } + if ( it.data().endNodeIsChild && nodeMap.contains(it.data().endNodeParent ) ) + { + it.data().endNodeCId = QString::number( nodeMap[it.data().endNodeParent] ); + it.data().endNodeParent = ecSubcircuit->id(); + } + } + + // Create all the new stuff + mergeWithDocument( ecSubcircuit->itemDocument(), false ); + + // Parent and hide the new stuff + itemEnd = m_itemDataMap.end(); + for ( ItemDataMap::iterator it = m_itemDataMap.begin(); it != itemEnd; ++it) + { + Component * component = static_cast(ecSubcircuit->itemDocument()->itemWithID( it.key() )); + if (component) + { + component->setParentItem(ecSubcircuit); + component->updateConnectorPoints(false); + component->setVisible(false); + component->setCanvas(0l); + ecSubcircuit->connect( ecSubcircuit, SIGNAL(subcircuitDeleted()), component, SLOT(removeItem()) ); + } + } + for ( ConnectorDataMap::iterator it = m_connectorDataMap.begin(); it != connectorEnd; ++it ) + { + Connector * connector = (static_cast(ecSubcircuit->itemDocument()))->connectorWithID( it.key() ); + if (connector) + { + connector->updateConnectorPoints(false); + connector->setVisible(false); + connector->setCanvas(0l); + ecSubcircuit->connect( ecSubcircuit, SIGNAL(subcircuitDeleted()), connector, SLOT(removeConnector()) ); + } + } + const NodeDataMap::iterator nodeEnd = m_nodeDataMap.end(); + for ( NodeDataMap::iterator it = m_nodeDataMap.begin(); it != nodeEnd; ++it ) + { + Node * node = (static_cast(ecSubcircuit->itemDocument()))->nodeWithID( it.key() ); + if (node) + { + node->setVisible(false); + node->setCanvas(0l); + ecSubcircuit->connect( ecSubcircuit, SIGNAL(subcircuitDeleted()), node, SLOT(removeNode()) ); + } + } + + ecSubcircuit->doneSCInit(); +} +//END class SubcircuitData + diff --git a/src/itemdocumentdata.h b/src/itemdocumentdata.h new file mode 100644 index 0000000..40c92a6 --- /dev/null +++ b/src/itemdocumentdata.h @@ -0,0 +1,242 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ITEMDOCUMENTDATA_H +#define ITEMDOCUMENTDATA_H + +#include "item.h" +#include "microsettings.h" + +#include + +class Connector; +class ECSubcircuit; +class KURL; +class Node; +class PinMapping; + +typedef QValueList > ConnectorList; +typedef QValueList > ItemList; +typedef QValueList > NodeList; +typedef QMap< QString, PinMapping > PinMappingMap; + +typedef QValueList QPointList; +typedef QMap BoolMap; +typedef QMap DoubleMap; +typedef QMap IntMap; +typedef QMap QColorMap; +typedef QMap QStringMap; +typedef QMap QBitArrayMap; + + +class ItemData +{ + public: + ItemData(); + + QString type; + double x; + double y; + int z; + QRect size; + bool setSize; + int orientation; // used for flowparts, should be set to -1 if not used. + double angleDegrees; + bool flipped; + BoolMap buttonMap; + IntMap sliderMap; + QString parentId; + BoolMap dataBool; + DoubleMap dataNumber; + QColorMap dataColor; + QStringMap dataString; + QBitArrayMap dataRaw; +}; +typedef QMap< QString, ItemData > ItemDataMap; + + +class ConnectorData +{ + public: + ConnectorData(); + + QPointList route; + bool manualRoute; + + bool startNodeIsChild; + bool endNodeIsChild; + + QString startNodeCId; + QString endNodeCId; + + QString startNodeParent; + QString endNodeParent; + + QString startNodeId; + QString endNodeId; +}; +typedef QMap< QString, ConnectorData > ConnectorDataMap; + + +class NodeData +{ + public: + NodeData(); + + double x; + double y; +}; +typedef QMap< QString, NodeData > NodeDataMap; + + +class PinData +{ + public: + PinData(); + + PinSettings::pin_type type; + PinSettings::pin_state state; +}; +typedef QMap< QString, PinData > PinDataMap; + + +class MicroData +{ + public: + MicroData(); + void reset(); + + QString id; + PinDataMap pinMap; + QStringMap variableMap; + PinMappingMap pinMappings; +}; + + +/** +This class encapsulates all or part of an ItemDocument. It is used for writing +the document to file / reading from file, as well as for the clipboard and +undo/redo system. +@author David Saxton +*/ +class ItemDocumentData +{ + public: + ItemDocumentData( uint documentType ); + ~ItemDocumentData(); + /** + * Erases / resets all data to defaults + */ + void reset(); + /** + * Read in data from a saved file. Any existing data in this class will + * be deleted first. + * @returns true iff successful + */ + bool loadData( const KURL &url ); + /** + * Write the data to the given file. + * @returns true iff successful + */ + bool saveData( const KURL &url ); + /** + * Returns the xml used for describing the data + */ + QString toXML(); + /** + * Restore the document from the given xml + * @return true if successful + */ + bool fromXML( const QString &xml ); + /** + * Saves the document to the data + */ + void saveDocumentState( ItemDocument *itemDocument ); + /** + * Restores a document to the state stored in this class + */ + void restoreDocument( ItemDocument *itemDocument ); + /** + * Merges the stuff stored here with the given document. If this is + * being used for e.g. pasting, you should call generateUniqueIDs() + * @param selectNew if true then the newly created items & connectors will be selected + */ + void mergeWithDocument( ItemDocument *itemDocument, bool selectNew ); + /** + * Replaces the IDs of everything with unique ones for the document. + * Used in pasting. + */ + void generateUniqueIDs( ItemDocument *itemDocument ); + /** + * Move all the items, connectors, nodes, etc by the given amount + */ + void translateContents( int dx, int dy ); + /** + * Returns the document type. + * @see Document::DocumentType + */ + uint documentType() const { return m_documentType; } + + //BEGIN functions for adding data + void setMicroData( const MicroData &data ); + void addItems( const ItemList &itemList ); + void addConnectors( const ConnectorList &connectorList ); + void addNodes( const NodeList &nodeList ); + + /** + * Add the given ItemData to the stored data + */ + void addItemData( ItemData itemData, QString id ); + /** + * Add the given ConnectorData to the stored data + */ + void addConnectorData( ConnectorData connectorData, QString id ); + /** + * Add the given NodeData to the stored data + */ + void addNodeData( NodeData nodeData, QString id ); + //END functions for adding data + + //BEGIN functions for returning strings for saving to xml + QString documentTypeString() const; + QString revisionString() const; + //END functions for returning strings for saving to xml + + protected: + //BEGIN functions for generating QDomElements + QDomElement microDataToElement( QDomDocument &doc ); + QDomElement itemDataToElement( QDomDocument &doc, const ItemData &itemData ); + QDomElement nodeDataToElement( QDomDocument &doc, const NodeData &nodeData ); + QDomElement connectorDataToElement( QDomDocument &doc, const ConnectorData &connectorData ); + //END functions for generating QDomElements + + //BEGIN functions for reading QDomElements to stored data + void elementToMicroData( QDomElement element ); + void elementToItemData( QDomElement element ); + void elementToNodeData( QDomElement element ); + void elementToConnectorData( QDomElement element ); + //END functions for reading QDomElements to stored data + + ItemDataMap m_itemDataMap; + ConnectorDataMap m_connectorDataMap; + NodeDataMap m_nodeDataMap; + MicroData m_microData; + uint m_documentType; // See Document::DocumentType +}; + + +class SubcircuitData : public ItemDocumentData +{ + public: + SubcircuitData(); + void initECSubcircuit( ECSubcircuit * ecSubcircuit ); +}; + +#endif diff --git a/src/itemgroup.cpp b/src/itemgroup.cpp new file mode 100644 index 0000000..1b640d3 --- /dev/null +++ b/src/itemgroup.cpp @@ -0,0 +1,323 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "icndocument.h" +#include "item.h" +#include "itemgroup.h" +#include "mechanicsdocument.h" + +#include + + +ItemGroup::ItemGroup( ItemDocument *view, const char *name ) + : QObject( view, name ) +{ + m_activeItem = 0l; + b_itemsAreSameType = true; + p_view = view; + p_icnDocument = dynamic_cast(p_view); + p_mechanicsDocument = dynamic_cast(p_view); + QTimer::singleShot( 0, this, SLOT(getViewPtrs()) ); +} + + +ItemGroup::~ItemGroup() +{ +} + + +void ItemGroup::getViewPtrs() +{ + p_icnDocument = dynamic_cast(p_view); + p_mechanicsDocument = dynamic_cast(p_view); +} + + +ItemList ItemGroup::items( bool excludeParentedItems ) const +{ + if (excludeParentedItems) + return m_itemList; + + ItemList items = m_itemList; + ItemList parents = m_itemList; + + uint oldSize = items.size(); + do + { + oldSize = items.size(); + ItemList children; + + ItemList::iterator end = parents.end(); + for ( ItemList::iterator it = parents.begin(); it != end; ++it ) + children += (*it)->children(); + + end = children.end(); + for ( ItemList::iterator it = children.begin(); it != end; ++it ) + { + if ( children.contains(*it) > 1 ) + *it = 0l; + } + children.remove((Item*)0l); + + items += children; + parents = children; + } + while ( oldSize != items.size() ); + + return items; +} + + +bool ItemGroup::itemsHaveSameDataValue( const QString &id ) const +{ + if ( m_itemList.size() < 1 ) { + return true; + } + + if (!itemsAreSameType()) { + return false; + } + + ItemList::const_iterator it = m_itemList.begin(); + const ItemList::const_iterator end = m_itemList.end(); + QVariant firstData = (*it)->property(id)->value(); + for ( ++it; it != end; ++it ) + { + if ( (*it) && (*it)->property(id) && (*it)->property(id)->value() != firstData ) { + return false; + } + } + return true; +} + + +bool ItemGroup::itemsHaveSameData() const +{ + if ( m_itemList.size() < 1 ) { + return true; + } + + if (!itemsAreSameType()) { + return false; + } + + VariantDataMap *variantMap = m_itemList.first()->variantMap(); + const VariantDataMap::const_iterator vitEnd = variantMap->end(); + for ( VariantDataMap::const_iterator vit = variantMap->begin(); vit != vitEnd; ++vit ) + { + if ( !itemsHaveSameDataValue(vit.key()) ) { + return false; + } + } + return true; +} + + +bool ItemGroup::itemsHaveDefaultData() const +{ + if (!itemsHaveSameData()) { + return false; + } + + if ( m_itemList.size() < 1 ) { + return true; + } + + VariantDataMap *variantMap = (*m_itemList.begin())->variantMap(); + const VariantDataMap::const_iterator vitEnd = variantMap->end(); + for ( VariantDataMap::const_iterator vit = variantMap->begin(); vit != vitEnd; ++vit ) + { + if ( !vit.data()->isHidden() && vit.data()->value() != vit.data()->defaultValue() ) + return false; + } + return true; +} + + +void ItemGroup::registerItem( Item *item ) +{ + if ( !item || m_itemList.contains(item) ) { + return; + } + + m_itemList += item; + updateAreSameStatus(); +} + + +void ItemGroup::unregisterItem( Item *item ) +{ + if ( m_itemList.remove(item) > 0 ) { + updateAreSameStatus(); + } +} + + +void ItemGroup::updateAreSameStatus() +{ + b_itemsAreSameType = true; + + if ( m_itemList.size() < 2 ) { + return; + } + + QString activeId = (*m_itemList.begin())->id(); + int discardIndex = activeId.findRev("__"); + if ( discardIndex != -1 ) activeId.truncate(discardIndex); + + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = ++m_itemList.begin(); it != end && b_itemsAreSameType; ++it ) + { + if (*it) + { + QString id = (*it)->id(); + discardIndex = id.findRev("__"); + if ( discardIndex != -1 ) id.truncate(discardIndex); + if ( id != activeId ) + { + b_itemsAreSameType = false; + } + } + } +} + + +void ItemGroup::slotAlignHorizontally() +{ + if ( m_itemList.size() < 2 ) + return; + + double avg_y = 0.; + + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + avg_y += (*it)->y(); + + int new_y = int(avg_y/(8*m_itemList.size()))*8+4; + + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + (*it)->move( (*it)->x(), new_y ); + + p_icnDocument->requestStateSave(); +} + + +void ItemGroup::slotAlignVertically() +{ + if ( m_itemList.size() < 2 ) + return; + + double avg_x = 0.; + + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + avg_x += (*it)->x(); + + int new_x = int(avg_x/(8*m_itemList.size()))*8+4; + + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + (*it)->move( new_x, (*it)->y() ); + + p_icnDocument->requestStateSave(); +} + + +void ItemGroup::slotDistributeHorizontally() +{ + if ( m_itemList.size() < 2 ) + return; + + // We sort the items by their horizontal position so that we can calculate + // an average spacing + typedef std::multimap< double, Item * > DIMap; + + DIMap ranked; + const ItemList::iterator ilend = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != ilend; ++it ) + ranked.insert( std::make_pair( (*it)->x(), *it ) ); + + double avg_spacing = 0; + + Item * previous = 0l; + const DIMap::iterator rankedEnd = ranked.end(); + for ( DIMap::iterator it = ranked.begin(); it != rankedEnd; ++it ) + { + Item * item = it->second; + if (previous) + { + double spacing = item->x() + item->offsetX() - (previous->x() + previous->width() + previous->offsetX()); + avg_spacing += spacing; + } + previous = item; + } + + avg_spacing /= (m_itemList.size()-1); + + DIMap::iterator it = ranked.begin(); + // Position that we are up to + double at = it->second->x() + it->second->width() + it->second->offsetX(); + for ( ++it; it != rankedEnd; ++it ) + { + Item * item = it->second; + double new_x = at - item->offsetX() + avg_spacing; + item->move( int(new_x/8)*8+4, item->y() ); + at = new_x + item->width() + item->offsetX(); + } + + p_icnDocument->requestStateSave(); +} + + +void ItemGroup::slotDistributeVertically() +{ + if ( m_itemList.size() < 2 ) + return; + + // We sort the items by their horizontal position so that we can calculate + // an average spacing + typedef std::multimap< double, Item * > DIMap; + + DIMap ranked; + const ItemList::iterator ilend = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != ilend; ++it ) + ranked.insert( std::make_pair( (*it)->y(), *it ) ); + + double avg_spacing = 0; + + Item * previous = 0l; + const DIMap::iterator rankedEnd = ranked.end(); + for ( DIMap::iterator it = ranked.begin(); it != rankedEnd; ++it ) + { + Item * item = it->second; + if (previous) + { + double spacing = item->y() + item->offsetY() - (previous->y() + previous->height() + previous->offsetY()); + avg_spacing += spacing; + } + previous = item; + } + + avg_spacing /= (m_itemList.size()-1); + + DIMap::iterator it = ranked.begin(); + // Position that we are up to + double at = it->second->y() + it->second->height() + it->second->offsetY(); + for ( ++it; it != rankedEnd; ++it ) + { + Item * item = it->second; + double new_y = at - item->offsetY() + avg_spacing; + item->move( item->x(), int(new_y/8)*8+4 ); + at = new_y + item->height() + item->offsetY(); + } + + p_icnDocument->requestStateSave(); +} + +#include "itemgroup.moc" diff --git a/src/itemgroup.h b/src/itemgroup.h new file mode 100644 index 0000000..6913165 --- /dev/null +++ b/src/itemgroup.h @@ -0,0 +1,140 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ITEMGROUP_H +#define ITEMGROUP_H + +#include + +class Item; +class ICNDocument; +class ItemDocument; +class DoubleSpinBox; +class ItemGroup; +class MechanicsDocument; +class Variant; + +typedef QValueList > ItemList; + +class QCanvasItem; +class QCanvasItemList; + +/** +Generic base class for controlling a selection of Item. Provides +some functionality such as for dealing with item data +@author David Saxton +*/ +class ItemGroup : public QObject +{ +Q_OBJECT +public: + ItemGroup( ItemDocument *view, const char *name = 0 ); + virtual ~ItemGroup(); + + /** + * Returns a pointer to the "active" CNItem - i.e. the last CNItem + * to be added to the CNItemGroup. This will always return a pointer to + * a single item, unless there are no CNItems in the group + */ + Item *activeItem() const { return m_activeItem; } + uint itemCount() const { return m_itemList.count(); } + virtual bool addQCanvasItem( QCanvasItem *qcanvasItem ) = 0; + virtual void setItems( QCanvasItemList list ) = 0; + virtual void removeQCanvasItem( QCanvasItem *qcanvasItem ) = 0; + virtual bool contains( QCanvasItem *qcanvasItem ) const = 0; + virtual uint count() const = 0; + bool isEmpty() const { return (count() == 0); } + virtual void mergeGroup( ItemGroup *group ) = 0; + virtual void removeAllItems() = 0; + virtual void deleteAllItems() = 0; + /** + * Returns a list of all the Items in the group. + * @param excludeParented whether to return items whose (grand-) parents are + * already in the list. + */ + ItemList items( bool excludeParented = true ) const; + /** + * Sets the selected state of all items in the group + */ + virtual void setSelected( bool sel ) = 0; + + /** + * Returns true iff either there are no items, or itemsAreSameType and the + * value of each data (excluding hidden data) for each item is the same + */ + bool itemsHaveSameData() const; + /** + * Returns truee iff either there are no items, or itemsAreSameType and the + * value of the data with the given id is the same for each item + */ + bool itemsHaveSameDataValue( const QString &id ) const; + /** + * Returns true iff all the iff itemsHaveSameData() returns true and the + * value of the data are the defaults + */ + bool itemsHaveDefaultData() const; + /** + * Returns true if all the items in the group are the same (e.g. + * resistors). This is checked for by looking at the ids of the items, + * and seeing if the string before "__#" is the same Note: if there are zero + * items in the group, then this will return true + */ + bool itemsAreSameType() const { return b_itemsAreSameType; } + +public slots: + /** + * Align the selected items horizontally so that their positions have the + * same y coordinate. + */ + void slotAlignHorizontally(); + /** + * Align the selected items horizontally so that their positions have the + * same x coordinate. + */ + void slotAlignVertically(); + /** + * Distribute the selected items horizontally so that they have the same + * spacing in the horizontal direction. + */ + void slotDistributeHorizontally(); + /** + * Distribute the selected items vertically so that they have the same + * spacing in the vertical direction. + */ + void slotDistributeVertically(); + +signals: + void itemAdded( Item *item ); + void itemRemoved( Item *item ); + +protected: + /** + * Subclasses must call this to register the item with the data interface + */ + void registerItem( Item *item ); + /** + * Subclasses must call this to unregister the item with the data interface + */ + void unregisterItem( Item *item ); + void updateAreSameStatus(); + + ItemList m_itemList; + bool b_itemsAreSameType; + ItemDocument * p_view; + + ICNDocument *p_icnDocument; + MechanicsDocument *p_mechanicsDocument;; + Item *m_activeItem; + +private slots: + void getViewPtrs(); +}; + +#endif diff --git a/src/iteminterface.cpp b/src/iteminterface.cpp new file mode 100644 index 0000000..6b9c1af --- /dev/null +++ b/src/iteminterface.cpp @@ -0,0 +1,601 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "circuitview.h" +#include "colorcombo.h" +#include "contexthelp.h" +#include "cnitem.h" +#include "cnitemgroup.h" +#include "doublespinbox.h" +#include "itemdocument.h" +#include "itemeditor.h" +#include "iteminterface.h" +#include "itemview.h" +#include "ktechlab.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +ItemInterface * ItemInterface::m_pSelf = 0l; + +ItemInterface * ItemInterface::self( KTechlab * ktechlab ) +{ + if ( !m_pSelf ) + { + assert(ktechlab); + m_pSelf = new ItemInterface(ktechlab); + } + return m_pSelf; +} + + +ItemInterface::ItemInterface( KTechlab * ktechlab ) + : QObject(ktechlab), + p_ktechlab(ktechlab) +{ + m_pActiveItemEditorToolBar = 0; + p_cvb = 0l; + p_itemGroup = 0l; + p_lastItem = 0l; + m_currentActionTicket = -1; + m_toolBarWidgetID = -1; +} + + +ItemInterface::~ItemInterface() +{ +} + + +void ItemInterface::slotGetActionTicket() +{ + m_currentActionTicket = p_cvb ? p_cvb->getActionTicket() : -1; +} + + +void ItemInterface::slotItemDocumentChanged( ItemDocument * doc ) +{ + slotClearAll(); + if ( ItemDocument * itemDocument = dynamic_cast((Document*)p_cvb) ) + { + disconnect( itemDocument, SIGNAL(itemSelected(Item*)), this, SLOT(slotUpdateItemInterface()) ); + disconnect( itemDocument, SIGNAL(itemUnselected(Item*)), this, SLOT(slotUpdateItemInterface()) ); + } + + p_itemGroup = 0l; + p_cvb = doc; + + slotGetActionTicket(); + + if (!p_cvb) + return; + + connect( p_cvb, SIGNAL(itemSelected(Item*)), this, SLOT(slotUpdateItemInterface()) ); + connect( p_cvb, SIGNAL(itemUnselected(Item*)), this, SLOT(slotUpdateItemInterface()) ); + + p_itemGroup = p_cvb->selectList(); + + slotUpdateItemInterface(); +} + + +void ItemInterface::clearItemEditorToolBar() +{ + if ( m_pActiveItemEditorToolBar && m_toolBarWidgetID != -1 ) + m_pActiveItemEditorToolBar->removeItem(m_toolBarWidgetID); + m_toolBarWidgetID = -1; + itemEditTBCleared(); +} + + +void ItemInterface::slotClearAll() +{ + ContextHelp::self()->slotClear(); + ItemEditor::self()->slotClear(); + clearItemEditorToolBar(); + p_lastItem = 0l; +} + + +void ItemInterface::slotMultipleSelected() +{ + ContextHelp::self()->slotMultipleSelected(); + ItemEditor::self()->slotMultipleSelected(); + clearItemEditorToolBar(); + p_lastItem = 0l; +} + + +void ItemInterface::slotUpdateItemInterface() +{ + if (!p_itemGroup) + return; + + slotGetActionTicket(); + updateItemActions(); + + if (!p_itemGroup->itemsAreSameType() ) + { + slotMultipleSelected(); + return; + } + if ( p_lastItem && p_itemGroup->activeItem() ) + { + ItemEditor::self()->updateMergeDefaults(p_itemGroup); + return; + } + + p_lastItem = p_itemGroup->activeItem(); + if (!p_lastItem) + { + slotClearAll(); + return; + } + + ContextHelp::self()->slotUpdate(p_lastItem); + ItemEditor::self()->slotUpdate(p_itemGroup); + if ( CNItem * cnItem = dynamic_cast((Item*)p_lastItem) ) + ItemEditor::self()->slotUpdate(cnItem); + + // Update item editor toolbar + if ( ItemView * itemView = dynamic_cast(p_cvb->activeView()) ) + { + if ( m_pActiveItemEditorToolBar = dynamic_cast(p_ktechlab->factory()->container("itemEditorTB",itemView)) ) + { + m_pActiveItemEditorToolBar->setFullSize( true ); + QWidget * widget = configWidget(); + m_toolBarWidgetID = 1; + m_pActiveItemEditorToolBar->insertWidget( m_toolBarWidgetID, 0, widget ); + } + } +} + + +void ItemInterface::updateItemActions() +{ + ItemView * itemView = ((ItemDocument*)p_cvb) ? dynamic_cast(p_cvb->activeView()) : 0l; + if ( !itemView ) + return; + + bool itemsSelected = p_itemGroup && p_itemGroup->itemCount(); + + itemView->action("edit_raise")->setEnabled(itemsSelected); + itemView->action("edit_lower")->setEnabled(itemsSelected); + p_ktechlab->action("edit_cut")->setEnabled(itemsSelected); + p_ktechlab->action("edit_copy")->setEnabled(itemsSelected); + + CNItemGroup * cnItemGroup = dynamic_cast((ItemGroup*)p_itemGroup); + CircuitView * circuitView = dynamic_cast(itemView); + + if ( cnItemGroup && circuitView ) + { + circuitView->action("edit_flip")->setEnabled(cnItemGroup->canFlip()); + bool canRotate = cnItemGroup->canRotate(); + circuitView->action("edit_rotate_ccw")->setEnabled(canRotate); + circuitView->action("edit_rotate_cw")->setEnabled(canRotate); + } +} + + +void ItemInterface::setFlowPartOrientation( unsigned orientation ) +{ + CNItemGroup *cnItemGroup = dynamic_cast((ItemGroup*)p_itemGroup); + if (!cnItemGroup) + return; + + cnItemGroup->setFlowPartOrientation( orientation ); +} + + +void ItemInterface::setComponentOrientation( int angleDegrees, bool flipped ) +{ + CNItemGroup *cnItemGroup = dynamic_cast((ItemGroup*)p_itemGroup); + if (!cnItemGroup) + return; + + cnItemGroup->setComponentOrientation( angleDegrees, flipped ); +} + + +void ItemInterface::itemEditTBCleared() +{ + m_stringLineEditMap.clear(); + m_stringComboBoxMap.clear(); + m_stringURLReqMap.clear(); + m_intSpinBoxMap.clear(); + m_doubleSpinBoxMap.clear(); + m_colorComboMap.clear(); + m_boolCheckMap.clear(); +} + + +// The bool specifies whether advanced data should be shown +QWidget * ItemInterface::configWidget() +{ + if ( !p_itemGroup || !p_itemGroup->activeItem() || !m_pActiveItemEditorToolBar ) + return 0l; + + VariantDataMap *variantMap = p_itemGroup->activeItem()->variantMap(); + + QWidget * parent = m_pActiveItemEditorToolBar; + + // Create new widget with the toolbar or dialog as the parent + QWidget * configWidget = new QWidget( parent, "tbConfigWidget" ); + configWidget->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding, 1, 1 ) ); + + QHBoxLayout * configLayout = new QHBoxLayout( configWidget ); +// configLayout->setAutoAdd( true ); + configLayout->setSpacing( 6 ); + +// configLayout->addItem( new QSpacerItem( 0, 0, QSizePolicy::Expanding, QSizePolicy::Fixed ) ); + + const VariantDataMap::iterator vaEnd = variantMap->end(); + for ( VariantDataMap::iterator vait = variantMap->begin(); vait != vaEnd; ++vait ) + { + if ( vait.data()->isHidden() || vait.data()->isAdvanced() ) + continue; + + const Variant::Type::Value type = vait.data()->type(); + + // common to all types apart from bool + QString toolbarCaption = vait.data()->toolbarCaption(); + if ( type != Variant::Type::Bool && !toolbarCaption.isEmpty() ) + configLayout->addWidget( new QLabel( toolbarCaption, configWidget ) ); + + QWidget * editWidget = 0l; // Should be set to the created widget + + switch( type ) + { + case Variant::Type::Port: + case Variant::Type::Pin: + case Variant::Type::VarName: + case Variant::Type::Combo: + case Variant::Type::Select: + case Variant::Type::KeyPad: + case Variant::Type::SevenSegment: + { + QString value = vait.data()->value().toString(); + if ( !value.isEmpty() && !vait.data()->allowed().contains(value) ) + vait.data()->appendAllowed(value); + + const QStringList allowed = vait.data()->allowed(); + + KComboBox * box = new KComboBox(configWidget); + + box->insertStringList(allowed); + box->setCurrentItem(value); + + if ( type == Variant::Type::VarName || type == Variant::Type::Combo ) + box->setEditable( true ); + + m_stringComboBoxMap[vait.key()] = box; + connectMapWidget( box, SIGNAL(textChanged(const QString &))); + connectMapWidget( box, SIGNAL(activated(const QString &))); + + editWidget = box; + break; + } + case Variant::Type::FileName: + { + QString value = vait.data()->value().toString(); + if ( !vait.data()->allowed().contains(value) ) + vait.data()->appendAllowed(value); + + const QStringList allowed = vait.data()->allowed(); + + KURLComboRequester * urlreq = new KURLComboRequester( configWidget ); + urlreq->setFilter( vait.data()->filter() ); + connectMapWidget( urlreq, SIGNAL(urlSelected(const QString &)) ); + m_stringURLReqMap[vait.key()] = urlreq; + + KComboBox * box = urlreq->comboBox(); + box->insertStringList(allowed); + box->setEditable( true ); + + // Note this has to be called after inserting the allowed list + urlreq->setURL( vait.data()->value().toString() ); + + // Generally we only want a file name once the user has finished typing out the full file name. + connectMapWidget( box, SIGNAL(returnPressed(const QString &))); + connectMapWidget( box, SIGNAL(activated(const QString &))); + + editWidget = urlreq; + break; + } + case Variant::Type::String: + { + KLineEdit * edit = new KLineEdit( configWidget ); + + edit->setText( vait.data()->value().toString() ); + connectMapWidget(edit,SIGNAL(textChanged(const QString &))); + m_stringLineEditMap[vait.key()] = edit; + editWidget = edit; + break; + } + case Variant::Type::Int: + { + KIntSpinBox *spin = new KIntSpinBox( (int)vait.data()->minValue(), (int)vait.data()->maxValue(), 1, vait.data()->value().toInt(), 10, configWidget ); + + connectMapWidget( spin, SIGNAL(valueChanged(int)) ); + m_intSpinBoxMap[vait.key()] = spin; + editWidget = spin; + break; + } + case Variant::Type::Double: + { + DoubleSpinBox *spin = new DoubleSpinBox( vait.data()->minValue(), vait.data()->maxValue(), vait.data()->minAbsValue(), vait.data()->value().toDouble(), vait.data()->unit(), configWidget ); + + connectMapWidget( spin, SIGNAL(valueChanged(double))); + m_doubleSpinBoxMap[vait.key()] = spin; + editWidget = spin; + break; + } + case Variant::Type::Color: + { + QColor value = vait.data()->value().toColor(); + + ColorCombo * colorBox = new ColorCombo( (ColorCombo::ColorScheme)vait.data()->colorScheme(), configWidget ); + + colorBox->setColor( value ); + connectMapWidget( colorBox, SIGNAL(activated(const QColor &))); + m_colorComboMap[vait.key()] = colorBox; + + editWidget = colorBox; + break; + } + case Variant::Type::Bool: + { + const bool value = vait.data()->value().toBool(); + QCheckBox * box = new QCheckBox( vait.data()->toolbarCaption(), configWidget ); + + box->setChecked(value); + connectMapWidget( box, SIGNAL(toggled(bool))); + m_boolCheckMap[vait.key()] = box; + editWidget = box; + break; + } + case Variant::Type::Raw: + case Variant::Type::PenStyle: + case Variant::Type::PenCapStyle: + case Variant::Type::Multiline: + case Variant::Type::None: + { + // Do nothing, as these data types are not handled in the toolbar + break; + } + } + + if ( !editWidget ) + continue; + + // In the case of the toolbar, we don't want it too high + if ( editWidget->height() > parent->height()-2 ) + editWidget->setMaximumHeight( parent->height()-2 ); + + switch ( type ) + { + case Variant::Type::VarName: + case Variant::Type::Combo: + case Variant::Type::String: + { + QSizePolicy p( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed, 1, 1 ); + + editWidget->setSizePolicy( p ); + editWidget->setMaximumWidth( 250 ); + break; + } + + case Variant::Type::FileName: + case Variant::Type::Port: + case Variant::Type::Pin: + case Variant::Type::Select: + case Variant::Type::KeyPad: + case Variant::Type::SevenSegment: + case Variant::Type::Int: + case Variant::Type::Double: + case Variant::Type::Color: + case Variant::Type::Bool: + case Variant::Type::Raw: + case Variant::Type::PenStyle: + case Variant::Type::PenCapStyle: + case Variant::Type::Multiline: + case Variant::Type::None: + break; + } + + configLayout->addWidget( editWidget ); + } + + configLayout->addItem( new QSpacerItem( 0, 0, QSizePolicy::Expanding, QSizePolicy::Fixed ) ); + + return configWidget; +} + + +void ItemInterface::connectMapWidget( QWidget *widget, const char *_signal ) +{ + connect( widget, _signal, this, SLOT(tbDataChanged()) ); +} + + +void ItemInterface::tbDataChanged() +{ + // Manual string values + const KLineEditMap::iterator m_stringLineEditMapEnd = m_stringLineEditMap.end(); + for ( KLineEditMap::iterator leit = m_stringLineEditMap.begin(); leit != m_stringLineEditMapEnd; ++leit ) + { + slotSetData( leit.key(), leit.data()->text() ); + } + + // String values from comboboxes + const KComboBoxMap::iterator m_stringComboBoxMapEnd = m_stringComboBoxMap.end(); + for ( KComboBoxMap::iterator cmit = m_stringComboBoxMap.begin(); cmit != m_stringComboBoxMapEnd; ++cmit ) + { + slotSetData( cmit.key(), cmit.data()->currentText() ); + } + + // Colors values from colorcombos + const ColorComboMap::iterator m_colorComboMapEnd = m_colorComboMap.end(); + for ( ColorComboMap::iterator ccit = m_colorComboMap.begin(); ccit != m_colorComboMapEnd; ++ccit ) + { + slotSetData( ccit.key(), ccit.data()->color() ); + } + + // Bool values from checkboxes + const QCheckBoxMap::iterator m_boolCheckMapEnd = m_boolCheckMap.end(); + for ( QCheckBoxMap::iterator chit = m_boolCheckMap.begin(); chit != m_boolCheckMapEnd; ++chit ) + { + slotSetData( chit.key(), chit.data()->isChecked() ); + } + + const IntSpinBoxMap::iterator m_intSpinBoxMapEnd = m_intSpinBoxMap.end(); + for ( IntSpinBoxMap::iterator it = m_intSpinBoxMap.begin(); it != m_intSpinBoxMapEnd; ++it ) + { + slotSetData( it.key(), it.data()->value() ); + } + + // (?) Combined values from spin boxes and combo boxes + // (?) Get values from all spin boxes + + const DoubleSpinBoxMap::iterator m_doubleSpinBoxMapEnd = m_doubleSpinBoxMap.end(); + for ( DoubleSpinBoxMap::iterator sbit = m_doubleSpinBoxMap.begin(); sbit != m_doubleSpinBoxMapEnd; ++sbit ) + { +// VariantDataMap::iterator vait = variantData.find(sbit.key()); + slotSetData( sbit.key(), sbit.data()->value() ); + } + + // Filenames from KURLRequesters + const KURLReqMap::iterator m_stringURLReqMapEnd = m_stringURLReqMap.end(); + for ( KURLReqMap::iterator urlit = m_stringURLReqMap.begin(); urlit != m_stringURLReqMapEnd; ++urlit ) + { + slotSetData( urlit.key(), urlit.data()->url() ); + } + + if (p_cvb) + p_cvb->setModified(true); +} + + + + +void ItemInterface::slotSetData( const QString &id, QVariant value ) +{ + if ( !p_itemGroup || (p_itemGroup->itemCount() == 0) ) + return; + + if ( !p_itemGroup->itemsAreSameType() ) + { + kdDebug() << k_funcinfo << "Items are not the same type!"<items(true); + const ItemList::const_iterator end = itemList.end(); + for ( ItemList::const_iterator it = itemList.begin(); it != end; ++it ) + { + if (*it) + (*it)->property(id)->setValue(value); + } + if (p_cvb) + p_cvb->setModified(true); + + + VariantDataMap * variantMap = (*itemList.begin())->variantMap(); + VariantDataMap::iterator it = variantMap->find(id); + if ( it == variantMap->end() ) + return; + + + // setData might have been called from the PropertiesListView, so want + // to see if the toolbar widgets want setting + + switch( it.data()->type() ) + { + case Variant::Type::String: + { + KLineEditMap::iterator mit = m_stringLineEditMap.find(id); + if ( mit != m_stringLineEditMap.end() ) mit.data()->setText( it.data()->value().toString() ); + break; + } + case Variant::Type::FileName: + { + KURLReqMap::iterator mit = m_stringURLReqMap.find(id); + if ( mit != m_stringURLReqMap.end() ) mit.data()->setURL( it.data()->value().toString() ); + break; + } + case Variant::Type::PenCapStyle: + case Variant::Type::PenStyle: + case Variant::Type::Port: + case Variant::Type::Pin: + case Variant::Type::VarName: + case Variant::Type::Combo: + case Variant::Type::Select: + case Variant::Type::SevenSegment: + case Variant::Type::KeyPad: + { + KComboBoxMap::iterator mit = m_stringComboBoxMap.find(id); + if ( mit != m_stringComboBoxMap.end() ) mit.data()->setCurrentItem( it.data()->value().toString() ); + break; + } + case Variant::Type::Int: + { + IntSpinBoxMap::iterator mit = m_intSpinBoxMap.find(id); + if ( mit != m_intSpinBoxMap.end() ) { + KIntSpinBox *sb = mit.data(); + sb->setValue( it.data()->value().toInt() ); + } + break; + } + case Variant::Type::Double: + { + DoubleSpinBoxMap::iterator mit = m_doubleSpinBoxMap.find(id); + if ( mit != m_doubleSpinBoxMap.end() ) { + DoubleSpinBox *sb = mit.data(); + sb->setValue( it.data()->value().toDouble() ); + } + break; + } + case Variant::Type::Color: + { + ColorComboMap::iterator mit = m_colorComboMap.find(id); + if ( mit != m_colorComboMap.end() ) mit.data()->setColor( it.data()->value().toColor() ); + break; + } + case Variant::Type::Bool: + { + QCheckBoxMap::iterator mit = m_boolCheckMap.find(id); + if ( mit != m_boolCheckMap.end() ) mit.data()->setChecked( it.data()->value().toBool() ); + break; + } + case Variant::Type::Raw: + case Variant::Type::Multiline: + case Variant::Type::None: + { + // This data will never be handled in the toolbar/PLV, so no need to worry about it + break; + } + } + + ItemEditor::self()->updateMergeDefaults(p_itemGroup); + + if (p_cvb) + p_cvb->requestStateSave(m_currentActionTicket); +} + +#include "iteminterface.moc" diff --git a/src/iteminterface.h b/src/iteminterface.h new file mode 100644 index 0000000..22a4a04 --- /dev/null +++ b/src/iteminterface.h @@ -0,0 +1,131 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ITEMINTERFACE_H +#define ITEMINTERFACE_H + +#include + +class CNItemGroup; +class DoubleSpinBox; +class Item; +class ItemDocument; +class ItemGroup; +class ItemInterface; +class KTechlab; +class MechanicsGroup; +class Variant; + +class ColorCombo; +class KComboBox; +class KToolBar; +class KURLRequester; +class QCheckBox; +class KLineEdit; +class KIntSpinBox; + + +typedef QMap VariantDataMap; +typedef QMap KComboBoxMap; +typedef QMap KLineEditMap; +typedef QMap DoubleSpinBoxMap; +typedef QMap IntSpinBoxMap; +typedef QMap ColorComboMap; +typedef QMap KURLReqMap; +typedef QMap QCheckBoxMap; + +/** +This acts as an interface between the ItemDocument's and the associated +Items's, and the various objects that like to know about them +(e.g. ContextHelp, ItemEditor, ItemEditTB) +@author David Saxton +*/ +class ItemInterface : public QObject +{ + Q_OBJECT + public: + ~ItemInterface(); + static ItemInterface * self( KTechlab * ktechlab = 0l ); + + /** + * Sets the orientation of all flowparts in the group. + */ + void setFlowPartOrientation( unsigned orientation ); + /** + * Sets the orientation of all components in the group. + */ + void setComponentOrientation( int angleDegrees, bool flipped ); + /** + * Updates actions based on the items currently selected (e.g. rotate, + * flip, etc) + */ + void updateItemActions(); + /** + * Returns a configuration widget for the component for insertion into te + * ItemEditTB. + * @param showAdvanced Whether advanced data should be shown + */ + virtual QWidget * configWidget(); + + public slots: + /** + * If cnItemsAreSameType() returns true, then set the + * data with the given id for all the CNItems in the group. + * Else, it only sets the data for the activeCNItem() + */ + void slotSetData( const QString &id, QVariant value ); + /** + * Called when the ItemEditTB is cleared. This clears all widget maps. + */ + void itemEditTBCleared(); + void tbDataChanged(); + void slotItemDocumentChanged( ItemDocument *view ); + void slotUpdateItemInterface(); + void slotClearAll(); + void slotMultipleSelected(); + void clearItemEditorToolBar(); + + protected: + /** + * Connects the specified widget to either tbDataChanged or advDataChanged + * as specified by mi. + */ + void connectMapWidget( QWidget *widget, const char *_signal); + + KTechlab * const p_ktechlab; + + // Widget maps. + KLineEditMap m_stringLineEditMap; + KComboBoxMap m_stringComboBoxMap; + KURLReqMap m_stringURLReqMap; + DoubleSpinBoxMap m_doubleSpinBoxMap; + IntSpinBoxMap m_intSpinBoxMap; + ColorComboMap m_colorComboMap; + QCheckBoxMap m_boolCheckMap; + + // Use by item editor toolbar + QGuardedPtr m_pActiveItemEditorToolBar; + int m_toolBarWidgetID; + + + protected slots: + void slotGetActionTicket(); + + private: + ItemInterface( KTechlab * ktechlab ); + static ItemInterface * m_pSelf; + + QGuardedPtr p_cvb; + QGuardedPtr p_itemGroup; + QGuardedPtr p_lastItem; + int m_currentActionTicket; +}; + +#endif diff --git a/src/itemlibrary.cpp b/src/itemlibrary.cpp new file mode 100644 index 0000000..d749f7f --- /dev/null +++ b/src/itemlibrary.cpp @@ -0,0 +1,476 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "config.h" + +#include "cnitem.h" +#include "canvasitemparts.h" +#include "circuitdocument.h" +#include "component.h" +#include "ecsubcircuit.h" +#include "ecnode.h" +#include "itemlibrary.h" +#include "node.h" +#include "subcircuits.h" + +#ifdef MECHANICS +#include "chassiscircular2.h" +#endif + +#include "dptext.h" +#include "dpline.h" +#include "solidshape.h" + +#include "callsub.h" +#include "count.h" +#include "delay.h" +#include "embed.h" +#include "end.h" +#include "inputbutton.h" +#include "interrupt.h" +#include "forloop.h" +#include "keypad.h" +#include "pulse.h" +#include "readport.h" +#include "repeat.h" +#include "setpin.h" +#include "sevenseg.h" +#include "start.h" +#include "sub.h" +#include "testpin.h" +#include "unary.h" +#include "varassignment.h" +#include "varcomparison.h" +#include "while.h" +#include "writeport.h" + +#include "addac.h" +#include "bidirled.h" +#include "binarycounter.h" +#include "bussplitter.h" +#include "demultiplexer.h" +#include "dependentsource.h" +#include "discretelogic.h" +#include "externalconnection.h" +#include "flipflop.h" +#include "fulladder.h" +#include "inductor.h" +#include "magnitudecomparator.h" +#include "matrixdisplay.h" +#include "matrixdisplaydriver.h" +#include "meter.h" +#include "multiinputgate.h" +#include "multiplexer.h" +#include "parallelportcomponent.h" +#include "piccomponent.h" +#include "pushswitch.h" +#include "probe.h" +#include "ram.h" +#include "resistordip.h" +#include "rotoswitch.h" +#include "serialportcomponent.h" +#include "toggleswitch.h" + +#include "ec555.h" +#include "ecbcdto7segment.h" +#include "eccapacitor.h" +#include "ecclockinput.h" +#include "eccurrentsignal.h" +#include "eccurrentsource.h" +#include "ecdiode.h" +#include "ecfixedvoltage.h" +#include "ecground.h" +#include "eckeypad.h" +#include "ecled.h" +#include "ecbjt.h" +#include "ecopamp.h" +#include "ecpotentiometer.h" +#include "ecresistor.h" +#include "ecsevensegment.h" +#include "ecsignallamp.h" +#include "ecvoltagesignal.h" +#include "ecvoltagesource.h" + +#include "pinmapping.h" + +#include "libraryitem.h" + +#include "kdebug.h" +#include +#include +#include +#include +#include +#include +#include + +#include + +ItemLibrary::ItemLibrary() +{ + addFlowParts(); + addComponents(); + addMechanics(); + addDrawParts(); +} + + +ItemLibrary::~ItemLibrary() +{ + const LibraryItemList::iterator end = m_items.end(); + for ( LibraryItemList::iterator it = m_items.begin(); it != end; ++it ) + { + delete *it; + } + m_items.clear(); +} + + +void ItemLibrary::addFlowParts() +{ + // Container loops + addLibraryItem( Repeat::libraryItem() ); + addLibraryItem( While::libraryItem() ); + addLibraryItem( ForLoop::libraryItem() ); + + // Variable operations + addLibraryItem( Unary::libraryItem() ); + addLibraryItem( VarAssignment::libraryItem() ); + addLibraryItem( VarComparison::libraryItem() ); + + // I/O + addLibraryItem( SetPin::libraryItem() ); + addLibraryItem( TestPin::libraryItem() ); + addLibraryItem( WritePort::libraryItem() ); + addLibraryItem( ReadPort::libraryItem() ); + + // Functions + addLibraryItem( SevenSeg::libraryItem() ); +// addLibraryItem( Pulse::libraryItem() ); + addLibraryItem( Keypad::libraryItem() ); +// addLibraryItem( Count::libraryItem() ); +// addLibraryItem( InputButton::libraryItem() ); + addLibraryItem( Delay::libraryItem() ); + + // Common + addLibraryItem( Embed::libraryItem() ); + addLibraryItem( CallSub::libraryItem() ); +// addLibraryItem( Interrupt::libraryItem() ); + addLibraryItem( Sub::libraryItem() ); + addLibraryItem( End::libraryItem() ); + addLibraryItem( Start::libraryItem() ); +} + + +void ItemLibrary::addComponents() +{ + // Integrated Circuits + addLibraryItem( ECBCDTo7Segment::libraryItem() ); + addLibraryItem( MatrixDisplayDriver::libraryItem() ); + addLibraryItem( BinaryCounter::libraryItem() ); + addLibraryItem( DAC::libraryItem() ); + addLibraryItem( ADC::libraryItem() ); + addLibraryItem( ECOpAmp::libraryItem() ); + addLibraryItem( MagnitudeComparator::libraryItem() ); + addLibraryItem( Demultiplexer::libraryItem() ); + addLibraryItem( Multiplexer::libraryItem() ); + addLibraryItem( FullAdder::libraryItem() ); + addLibraryItem( RAM::libraryItem() ); + addLibraryItem( EC555::libraryItem() ); + addLibraryItem( ECDFlipFlop::libraryItem() ); + addLibraryItem( ECSRFlipFlop::libraryItem() ); + addLibraryItem( ECJKFlipFlop::libraryItem() ); +#ifndef NO_GPSIM + addLibraryItem( PICComponent::libraryItem() ); +#endif + + // Connections + addLibraryItem( ParallelPortComponent::libraryItem() ); + addLibraryItem( SerialPortComponent::libraryItem() ); + addLibraryItem( ExternalConnection::libraryItem() ); + addLibraryItem( BusSplitter::libraryItem() ); + + // Logic + addLibraryItem( ECXnor::libraryItem() ); + addLibraryItem( ECXor::libraryItem() ); + addLibraryItem( ECNor::libraryItem() ); + addLibraryItem( ECOr::libraryItem() ); + addLibraryItem( ECNand::libraryItem() ); + addLibraryItem( ECAnd::libraryItem() ); + addLibraryItem( Inverter::libraryItem() ); + addLibraryItem( Buffer::libraryItem() ); + addLibraryItem( ECClockInput::libraryItem() ); + addLibraryItem( ECLogicOutput::libraryItem() ); + addLibraryItem( ECLogicInput::libraryItem() ); + + + // Outputs +// addLibraryItem( FrequencyMeter::libraryItem() ); + addLibraryItem( CurrentProbe::libraryItem() ); + addLibraryItem( VoltageProbe::libraryItem() ); + addLibraryItem( LogicProbe::libraryItem() ); + addLibraryItem( ECAmmeter::libraryItem() ); + addLibraryItem( ECVoltMeter::libraryItem() ); + addLibraryItem( MatrixDisplay::libraryItem() ); + addLibraryItem( ECSevenSegment::libraryItem() ); + addLibraryItem( BiDirLED::libraryItem() ); + addLibraryItem( ECSignalLamp::libraryItem() ); + addLibraryItem( ECLed::libraryItem() ); + + // Switches + addLibraryItem( ECRotoSwitch::libraryItem() ); + addLibraryItem( ECDPDT::libraryItem() ); + addLibraryItem( ECSPDT::libraryItem() ); + addLibraryItem( ECDPST::libraryItem() ); + addLibraryItem( ECSPST::libraryItem() ); + addLibraryItem( ECKeyPad::libraryItem() ); + addLibraryItem( ECPTBSwitch::libraryItem() ); + addLibraryItem( ECPTMSwitch::libraryItem() ); + + + // Discrete + addLibraryItem( ECPotentiometer::libraryItem() ); + addLibraryItem( ResistorDIP::libraryItem() ); + addLibraryItem( ECBJT::libraryItemPNP() ); + addLibraryItem( ECBJT::libraryItemNPN() ); + addLibraryItem( Inductor::libraryItem() ); + addLibraryItem( ECDiode::libraryItem() ); + addLibraryItem( ECCapacitor::libraryItem() ); + addLibraryItem( ECResistor::libraryItem() ); + + // Dependent Sources + addLibraryItem( ECVCVS::libraryItem() ); + addLibraryItem( ECVCCS::libraryItem() ); + addLibraryItem( ECCCVS::libraryItem() ); + addLibraryItem( ECCCCS::libraryItem() ); + + // Independent Sources + addLibraryItem( ECCurrentSignal::libraryItem() ); + addLibraryItem( ECVoltageSignal::libraryItem() ); + addLibraryItem( ECCurrentSource::libraryItem() ); + addLibraryItem( ECGround::libraryItem() ); + addLibraryItem( ECFixedVoltage::libraryItem() ); + addLibraryItem( ECCell::libraryItem() ); + + // Other + addLibraryItem( ECSubcircuit::libraryItem() ); + addLibraryItem( PIC_IC::libraryItem() ); +} + + +void ItemLibrary::addDrawParts() +{ + addLibraryItem( DPText::libraryItem() ); + addLibraryItem( DPLine::libraryItem() ); + addLibraryItem( DPArrow::libraryItem() ); + addLibraryItem( DPRectangle::libraryItem() ); + addLibraryItem( DPEllipse::libraryItem() ); +} + + +void ItemLibrary::addMechanics() +{ +#ifdef MECHANICS + addLibraryItem( ChassisCircular2::libraryItem() ); +#endif +} + + +void ItemLibrary::addLibraryItem( LibraryItem *item ) +{ + m_items.append(item); +} + + +Item *ItemLibrary::createItem( const QString &id, ItemDocument *itemDocument, bool newItem, const char *newId, bool finishCreation ) +{ + Item * item = 0l; + if ( id.startsWith("sc/") ) + { + // Is a subcircuit... + + CircuitDocument * circuitDocument = dynamic_cast(itemDocument); + if (!circuitDocument) + { + kdWarning() << "Cannot create subcircuit without a circuit document" << endl; + return 0l; + } + + QString temp = id; + int numId = temp.remove("sc/").toInt(); + + item = subcircuits()->createSubcircuit( numId, /*id,*/ circuitDocument, newItem, newId ); + } + + else + { + const LibraryItemList::iterator end = m_items.end(); + LibraryItemList::iterator it = m_items.begin(); + for ( ; it != end; ++it ) + { + if ( (*it)->allIDs().contains(id) ) + { + item = (*it)->createItemFnPtr()( itemDocument, newItem, newId ); + item->m_type = (*it)->activeID(); + break; + } + } + + if ( it == end ) + kdWarning() << "Could not find the item constructor for id " << id << endl; + } + + if ( finishCreation && item ) + item->finishedCreation(); + + return item; +} + + +QImage ItemLibrary::itemImage( Item *item, const uint maxSize ) +{ + Component *component = dynamic_cast(item); + + QRect bound = item->boundingRect().normalize(); + bound.setLeft( bound.left()-8 ); + bound.setRight( bound.right()+8 ); + bound.setTop( bound.top()-8 ); + bound.setBottom( bound.bottom()+8 ); + + // We want a nice square bounding rect + const int dy = bound.width() - bound.height(); + if ( dy > 0 ) + { + bound.setTop( bound.top()-(dy/2) ); + bound.setBottom( bound.bottom()+(dy/2) ); + } + else if ( dy < 0 ) + { + bound.setLeft( bound.left()+(dy/2) ); + bound.setRight( bound.right()-(dy/2) ); + } + + const bool cache = ((bound.width()*bound.height()) > (int)maxSize); + QString type; + if ( cache && m_imageMap.contains(item->type()) ) + return m_imageMap[item->type()]; + + // Create pixmap big enough to contain CNItem and surrounding nodes + // and copy the button grab to it + + QPixmap pm( bound.size() ); + + QBitmap mask( bound.size() ); + mask.fill( Qt::color0 ); + + QPainter maskPainter(&mask); + maskPainter.translate( -bound.x(), -bound.y() ); + maskPainter.setPen( Qt::color1 ); + maskPainter.setBrush( Qt::color1 ); + + + QPainter p(&pm); + p.translate( -bound.x(), -bound.y() ); + p.setPen( item->pen() ); + p.setBrush( item->brush() ); + + // Now draw the shape :-) + const bool sel = item->isSelected(); + if (sel) + { + // We block the signals as we end up in an infinite loop with cnitem emitting a selected signal + item->blockSignals(true); + item->setSelected(false); + item->blockSignals(false); + } + item->drawShape(p); + item->drawShape(maskPainter); + if (sel) + { + item->blockSignals(true); + item->setSelected(sel); + item->blockSignals(false); + } + + maskPainter.setPen( Qt::color1 ); + maskPainter.setBrush( Qt::color1 ); + + QWMatrix transMatrix; // Matrix to apply to the image + + CNItem *cnItem = dynamic_cast(item); + if (cnItem) + { + NodeMap nodes = cnItem->nodeMap(); + const NodeMap::iterator nodesEnd = nodes.end(); + for ( NodeMap::iterator it = nodes.begin(); it != nodesEnd; ++it ) + { + Node *node = it.data().node; + const bool sel = node->isSelected(); + if (sel) + node->setSelected(false); + if ( ECNode *ecnode = dynamic_cast(node) ) + { + const bool showVB = ecnode->showVoltageBars(); + ecnode->setShowVoltageBars(false); + ecnode->drawShape(p); + ecnode->drawShape(maskPainter); + ecnode->setShowVoltageBars(showVB); + } + else + { + node->drawShape(p); + node->drawShape(maskPainter); + } + if (sel) + node->setSelected(sel); + } + + p.setPen(Qt::black); + TextMap text = cnItem->textMap(); + const TextMap::iterator textEnd = text.end(); + for ( TextMap::iterator it = text.begin(); it != textEnd; ++it ) + { + it.data()->drawShape(p); + it.data()->drawShape(maskPainter); + } + +// maskPainter.setPen( Qt::color1 ); +// maskPainter.setBrush( Qt::color1 ); + cnItem->drawWidgets(p); +// cnItem->drawWidgets(maskPainter); + + transMatrix = Component::transMatrix( component->angleDegrees(), component->flipped(), bound.width()/2, bound.height()/2, true ); + } + + pm.setMask(mask); + + // Now, rotate the image so that it's the right way up, and scale it to size + QImage im = pm.convertToImage(); + im = im.xForm(transMatrix); + im = im.smoothScale( 50, 50, QImage::ScaleMin ); + + if (cache) + m_imageMap[item->type()] = im; + + return im; +} + +QPixmap ItemLibrary::itemIconFull( const QString &id ) +{ + LibraryItemList::iterator end = m_items.end(); + for ( LibraryItemList::iterator it = m_items.begin(); it != end; ++it ) + { + if ( *it && (*it)->allIDs().contains(id) ) + { + return (*it)->iconFull(); + } + } + return QPixmap(); +} diff --git a/src/itemlibrary.h b/src/itemlibrary.h new file mode 100644 index 0000000..181eb5f --- /dev/null +++ b/src/itemlibrary.h @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ITEMLIBRARY_H +#define ITEMLIBRARY_H + +#include +#include + +class Document; +class Item; +class ItemDocument; +class ItemLibrary; +class LibraryItem; +inline ItemLibrary* itemLibrary(); + +typedef QMap< QString, QImage > ImageMap; +typedef QValueList LibraryItemList; + +/** +While the program is running, only one instance of this class is created. +You can get it by calling itemLibrary() +@short Holds the list of CNItems +@author David Saxton +*/ +class ItemLibrary +{ +public: + ~ItemLibrary(); + /** + * Returns a QPixmap of the item icon + */ + QPixmap itemIconFull( const QString &id ); + /** + * Append the given item into the library + */ + void addLibraryItem( LibraryItem *item ); + /** + * Returns a list of items in the library + */ + LibraryItemList* items() { return &m_items; } + /** + * Creates a new item with the given id, and returns a pointer to it + */ + Item *createItem( const QString &id, ItemDocument *itemDocument, bool newItem, const char *newId = 0L, bool finishCreation = true ); + /** + * Returns an image of the given cnitem. As QPixmap::convertToImage is + * a *very* slow function, this will cache the result and return that for + * large images. + * @param cnItem A pointer to the CNItem + * @param maxSize The maximum size (in pixels) before the image is cached + */ + QImage itemImage( Item *item, const uint maxSize = 36000 ); + +protected: + void addComponents(); + void addFlowParts(); + void addMechanics(); + void addDrawParts(); + + ItemLibrary(); + + LibraryItemList m_items; + ImageMap m_imageMap; + + friend ItemLibrary* itemLibrary(); +}; + +inline ItemLibrary* itemLibrary() +{ + static ItemLibrary *_itemLibrary = new ItemLibrary(); + return _itemLibrary; +} + +#endif diff --git a/src/itemview.cpp b/src/itemview.cpp new file mode 100644 index 0000000..452d33c --- /dev/null +++ b/src/itemview.cpp @@ -0,0 +1,581 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasmanipulator.h" +#include "cnitem.h" +#include "connector.h" +#include "docmanager.h" +#include "drawpart.h" +#include "ecnode.h" +#include "itemdocument.h" +#include "itemview.h" +#include "ktechlab.h" +#include "core/ktlconfig.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +//BEGIN class ItemView +ItemView::ItemView( ItemDocument * itemDocument, ViewContainer *viewContainer, uint viewAreaId, const char *name ) + : View( itemDocument, viewContainer, viewAreaId, name ) +{ + KActionCollection * ac = actionCollection(); + + KStdAction::selectAll( itemDocument, SLOT(selectAll()), ac ); + KStdAction::zoomIn( this, SLOT(zoomIn()), ac ); + KStdAction::zoomOut( this, SLOT(zoomOut()), ac ); + KStdAction::actualSize( this, SLOT(actualSize()), ac )->setEnabled(false); + + + KAccel *pAccel = new KAccel(this); + pAccel->insert( "Cancel", i18n("Cancel"), i18n("Cancel the current operation"), Qt::Key_Escape, itemDocument, SLOT(cancelCurrentOperation()) ); + pAccel->readSettings(); + + new KAction( i18n("Delete"), "editdelete", Qt::Key_Delete, itemDocument, SLOT(deleteSelection()), ac, "edit_delete" ); + new KAction( i18n("Export as Image..."), 0, 0, itemDocument, SLOT(exportToImage()), ac, "file_export_image"); + + //BEGIN Item Alignment actions + new KAction( i18n("Align Horizontally"), 0, 0, itemDocument, SLOT(alignHorizontally()), ac, "align_horizontally" ); + new KAction( i18n("Align Vertically"), 0, 0, itemDocument, SLOT(alignVertically()), ac, "align_vertically" ); + new KAction( i18n("Distribute Horizontally"), 0, 0, itemDocument, SLOT(distributeHorizontally()), ac, "distribute_horizontally" ); + new KAction( i18n("Distribute Vertically"), 0, 0, itemDocument, SLOT(distributeVertically()), ac, "distribute_vertically" ); + //END Item Alignment actions + + + //BEGIN Draw actions + KToolBarPopupAction * pa = new KToolBarPopupAction( i18n("Draw"), "paintbrush", 0, 0, 0, ac, "edit_draw" ); + pa->setDelayed(false); + + KPopupMenu * m = pa->popupMenu(); + m->insertTitle( i18n("Draw") ); + + m->insertItem( KGlobal::iconLoader()->loadIcon( "tool_text", KIcon::Small ), i18n("Text"), DrawPart::da_text ); + m->insertItem( KGlobal::iconLoader()->loadIcon( "tool_line", KIcon::Small ), i18n("Line"), DrawPart::da_line ); + m->insertItem( KGlobal::iconLoader()->loadIcon( "tool_arrow", KIcon::Small ), i18n("Arrow"), DrawPart::da_arrow ); + m->insertItem( KGlobal::iconLoader()->loadIcon( "tool_ellipse", KIcon::Small ), i18n("Ellipse"), DrawPart::da_ellipse ); + m->insertItem( KGlobal::iconLoader()->loadIcon( "tool_rectangle", KIcon::Small ), i18n("Rectangle"), DrawPart::da_rectangle ); + connect( m, SIGNAL(activated(int)), itemDocument, SLOT(slotSetDrawAction(int)) ); + //END Draw actions + + + //BEGIN Item Control actions + new KAction( i18n("Raise Selection"), "1uparrow", Qt::Key_PageUp, itemDocument, SLOT(raiseZ()), ac, "edit_raise" ); + new KAction( i18n("Lower Selection"), "1downarrow", Qt::Key_PageDown, itemDocument, SLOT(lowerZ()), ac, "edit_lower" ); + //END Item Control actions + + + KAction * na = new KAction( "", 0, 0, 0, 0, ac, "null_action" ); + na->setEnabled(false); + + setXMLFile( "ktechlabitemviewui.rc" ); + + m_pUpdateStatusTmr = new QTimer(this); + connect( m_pUpdateStatusTmr, SIGNAL(timeout()), this, SLOT(updateStatus()) ); + connect( this, SIGNAL(viewUnfocused()), this, SLOT(stopUpdatingStatus()) ); + + p_itemDocument = itemDocument; + m_zoomLevel = 1.; + m_CVBEditor = new CVBEditor( p_itemDocument->canvas(), this, "cvbEditor" ); + m_CVBEditor->setLineWidth(1); + + m_layout->insertWidget( 0, m_CVBEditor ); + + setAcceptDrops(true); +} + + +ItemView::~ItemView() +{ +} + + +bool ItemView::canZoomIn() const +{ + return true; +} +bool ItemView::canZoomOut() const +{ + return int(std::floor((100*m_zoomLevel)+0.5)) > 25; +} + + +void ItemView::zoomIn() +{ + int currentZoomPercent = int(std::floor((100*m_zoomLevel)+0.5)); + int newZoom = currentZoomPercent; + + if ( currentZoomPercent < 100 ) + newZoom += 25; + else if ( currentZoomPercent < 200 ) + newZoom += 50; + else + newZoom += 100; + + m_zoomLevel = newZoom/100.; + + QWMatrix m( m_zoomLevel, 0.0, 0.0, m_zoomLevel, 1.0, 1.0 ); + m_CVBEditor->setWorldMatrix(m); + + p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems ); + updateZoomActions(); +} + + +void ItemView::zoomOut() +{ + int currentZoomPercent = int(std::floor((100*m_zoomLevel)+0.5)); + int newZoom = currentZoomPercent; + + if ( currentZoomPercent <= 25 ) + return; + if ( currentZoomPercent <= 100 ) + newZoom -= 25; + else if ( currentZoomPercent <= 200 ) + newZoom -= 50; + else + newZoom -= 100; + + m_zoomLevel = newZoom/100.; + + QWMatrix m( m_zoomLevel, 0.0, 0.0, m_zoomLevel, 1.0, 1.0 ); + m_CVBEditor->setWorldMatrix(m); + + p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems ); + updateZoomActions(); +} + + +void ItemView::actualSize() +{ + m_zoomLevel = 1.0; + QWMatrix m( m_zoomLevel, 0.0, 0.0, m_zoomLevel, 1.0, 1.0 ); + m_CVBEditor->setWorldMatrix(m); + + p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems ); + updateZoomActions(); +} + + +void ItemView::updateZoomActions() +{ + action("view_zoom_in")->setEnabled( canZoomIn() ); + action("view_zoom_out")->setEnabled( canZoomOut() ); + action("view_actual_size")->setEnabled( m_zoomLevel != 1.0 ); +} + + +void ItemView::dropEvent( QDropEvent *event ) +{ + KURL::List urls; + if ( KURLDrag::decode( event, urls ) ) + { + // Then it is URLs that we can decode :) + const KURL::List::iterator end = urls.end(); + for ( KURL::List::iterator it = urls.begin(); it != end; ++it ) + { + DocManager::self()->openURL(*it); + } + return; + } + + if ( !QString(event->format()).startsWith("ktechlab/") ) + return; + + QString text; + QDataStream stream( event->encodedData(event->format()), IO_ReadOnly ); + stream >> text; + + QPoint position = event->pos(); + position.setX( int((position.x() + m_CVBEditor->contentsX())/m_zoomLevel) ); + position.setY( int((position.y() + m_CVBEditor->contentsY())/m_zoomLevel) ); + + // Get a new component item + p_itemDocument->addItem( text, position, true ); + + setFocus(); +} + + +void ItemView::scrollToMouse( const QPoint &pos ) +{ + QPoint position = pos * m_zoomLevel; + + int left = m_CVBEditor->contentsX(); + int top = m_CVBEditor->contentsY(); + int right = left + m_CVBEditor->visibleWidth(); + int bottom = top + m_CVBEditor->visibleHeight(); + + if( position.x() < left ) m_CVBEditor->scrollBy( position.x() - left, 0 ); + else if( position.x() > right ) m_CVBEditor->scrollBy( position.x() - right, 0 ); + + if( position.y() < top ) m_CVBEditor->scrollBy( 0, position.y() - top ); + else if( position.y() > bottom ) m_CVBEditor->scrollBy( 0, position.y() - bottom); +} + + +void ItemView::contentsMousePressEvent( QMouseEvent *e ) +{ + if (!e) + return; + + e->accept(); + + // For some reason, when we are initially unfocused, we only receive the + // release event if the user drags the mouse - not very often. So see if we + // were initially unfocused, and if so, do unclick as well. + bool wasFocused = isFocused(); + setFocused(); + + if ( !p_itemDocument ) + return; + + p_itemDocument->canvas()->setMessage( QString::null ); + p_itemDocument->m_cmManager->mousePressEvent( EventInfo( this, e ) ); + + if ( !wasFocused ) + p_itemDocument->m_cmManager->mouseReleaseEvent( EventInfo( this, e ) ); +} + + +void ItemView::contentsMouseDoubleClickEvent( QMouseEvent *e ) +{ + if (!e) + return; + + e->accept(); + + //HACK: Pass this of as a single press event if widget underneath + QCanvasItem * atTop = p_itemDocument->itemAtTop( e->pos()/zoomLevel() ); + if ( atTop && atTop->rtti() == ItemDocument::RTTI::Widget ) + contentsMousePressEvent(e); + else + p_itemDocument->m_cmManager->mouseDoubleClickEvent( EventInfo( this, e ) ); +} + + +void ItemView::contentsMouseMoveEvent( QMouseEvent *e ) +{ + if ( !e || !p_itemDocument ) + return; + + e->accept(); + + p_itemDocument->m_cmManager->mouseMoveEvent( EventInfo( this, e ) ); + if ( !m_pUpdateStatusTmr->isActive() ) + startUpdatingStatus(); +} + + +void ItemView::contentsMouseReleaseEvent( QMouseEvent *e ) +{ + if (!e) + return; + + e->accept(); + + p_itemDocument->m_cmManager->mouseReleaseEvent( EventInfo( this, e ) ); +} + + +void ItemView::contentsWheelEvent( QWheelEvent *e ) +{ + if (!e) + return; + + e->accept(); + + p_itemDocument->m_cmManager->wheelEvent( EventInfo( this, e ) ); +} + + +void ItemView::dragEnterEvent( QDragEnterEvent *event ) +{ + startUpdatingStatus(); + + KURL::List urls; + if ( KURLDrag::decode( event, urls ) ) + { + event->accept(true); + // Then it is URLs that we can decode later :) + return; + } +} + + +void ItemView::enterEvent( QEvent * e ) +{ + Q_UNUSED(e); + startUpdatingStatus(); +} + + +void ItemView::leaveEvent( QEvent * e ) +{ + Q_UNUSED(e); + stopUpdatingStatus(); + + // Cleanup + setCursor(Qt::ArrowCursor); + + if (p_ktechlab) + p_ktechlab->slotChangeStatusbar(QString::null); + + if ( p_itemDocument ) + p_itemDocument->m_canvasTip->setVisible(false); +} + + +void ItemView::slotUpdateConfiguration() +{ +// m_CVBEditor->setEraseColor( KTLConfig::bgColor() ); + m_CVBEditor->setEraseColor( Qt::white ); + + if ( m_pUpdateStatusTmr->isActive() ) + startUpdatingStatus(); +} + + +void ItemView::startUpdatingStatus() +{ + m_pUpdateStatusTmr->stop(); + m_pUpdateStatusTmr->start( int(1000./KTLConfig::refreshRate()) ); +} + + +void ItemView::stopUpdatingStatus() +{ + m_pUpdateStatusTmr->stop(); +} + + +void ItemView::updateStatus() +{ + QPoint pos = (m_CVBEditor->mapFromGlobal( QCursor::pos() ) + QPoint( m_CVBEditor->contentsX(), m_CVBEditor->contentsY() )) / zoomLevel(); + + ItemDocument * itemDocument = static_cast(document()); + if ( !itemDocument ) + return; + + CMManager * cmManager = itemDocument->m_cmManager; + CanvasTip * canvasTip = itemDocument->m_canvasTip; + + bool displayTip = false; + QCursor cursor = Qt::ArrowCursor; + QString statusbar; + + if ( cmManager->cmState() & CMManager::cms_repeated_add ) + { + cursor = Qt::CrossCursor; + statusbar = i18n("Left click to add. Right click to resume normal editing"); + } + else if ( cmManager->cmState() & CMManager::cms_draw ) + { + cursor = Qt::CrossCursor; + statusbar = i18n("Click and hold to start drawing."); + } + else if ( cmManager->currentManipulator()) + { + switch ( cmManager->currentManipulator()->type() ) + { + case CanvasManipulator::RepeatedItemAdd: + cursor = Qt::CrossCursor; + statusbar = i18n("Left click to add. Right click to resume normal editing"); + break; + case CanvasManipulator::ManualConnector: + statusbar = i18n("Right click to cancel the connector"); + // no break + case CanvasManipulator::AutoConnector: + cursor = Qt::CrossCursor; + break; + case CanvasManipulator::ItemMove: + case CanvasManipulator::MechItemMove: + cursor = Qt::SizeAllCursor; + break; + case CanvasManipulator::Draw: + cursor = Qt::CrossCursor; + break; + default: + break; + } + + } + else if ( QCanvasItem *qcanvasItem = itemDocument->itemAtTop(pos) ) + { + switch( qcanvasItem->rtti() ) + { + case ItemDocument::RTTI::Connector: + { + cursor = Qt::CrossCursor; + if ( itemDocument->type() != Document::dt_circuit ) + break; + + canvasTip->displayVI( static_cast(qcanvasItem), pos ); + displayTip = true; + break; + } + case ItemDocument::RTTI::Node: + { + cursor = Qt::CrossCursor; + ECNode * ecnode = dynamic_cast(qcanvasItem); + if ( !ecnode ) + break; + + canvasTip->displayVI( ecnode, pos ); + displayTip = true; + break; + } + case ItemDocument::RTTI::CNItem: + { + statusbar = (static_cast(qcanvasItem))->name(); + break; + } + default: + { + break; + } + } + } + setCursor(cursor); + + if (p_ktechlab) + p_ktechlab->slotChangeStatusbar(statusbar); + + canvasTip->setVisible(displayTip); +} + +//END class ItemView + + + +//BEGIN class CVBEditor +CVBEditor::CVBEditor( QCanvas *canvas, ItemView *itemView, const char *name ) + : QCanvasView( canvas, itemView, name, WNoAutoErase | WStaticContents ) +{ + b_ignoreEvents = false; + b_passEventsToView = true; + p_itemView = itemView; + viewport()->setMouseTracking(true); + setAcceptDrops(true); + setFrameShape(NoFrame); +// setEraseColor( KTLConfig::bgColor() ); + setEraseColor( Qt::white ); + setPaletteBackgroundColor( Qt::white ); + viewport()->setEraseColor( Qt::white ); + viewport()->setPaletteBackgroundColor( Qt::white ); +} + + +void CVBEditor::contentsMousePressEvent( QMouseEvent* e ) +{ + if (b_passEventsToView) + p_itemView->contentsMousePressEvent(e); + else + QCanvasView::contentsMousePressEvent(e); +} + + +void CVBEditor::contentsMouseReleaseEvent( QMouseEvent* e ) +{ + if (b_passEventsToView) + p_itemView->contentsMouseReleaseEvent(e); + else + QCanvasView::contentsMouseReleaseEvent(e); +} + + +void CVBEditor::contentsMouseDoubleClickEvent( QMouseEvent* e ) +{ + if (b_passEventsToView) + p_itemView->contentsMouseDoubleClickEvent(e); + else + QCanvasView::contentsMouseDoubleClickEvent(e); +} + + +void CVBEditor::contentsMouseMoveEvent( QMouseEvent* e ) +{ + if (b_passEventsToView) + p_itemView->contentsMouseMoveEvent(e); + else + QCanvasView::contentsMouseMoveEvent(e); +} + + +void CVBEditor::dragEnterEvent( QDragEnterEvent* e ) +{ + if (b_passEventsToView) + p_itemView->dragEnterEvent(e); + else + QCanvasView::dragEnterEvent(e); +} + + +void CVBEditor::dropEvent( QDropEvent* e ) +{ + if (b_passEventsToView) + p_itemView->dropEvent(e); + else + QCanvasView::dropEvent(e); +} + + +void CVBEditor::enterEvent( QEvent * e ) +{ + if (b_passEventsToView) + p_itemView->enterEvent(e); + else + QCanvasView::enterEvent(e); +} + + +void CVBEditor::leaveEvent( QEvent* e ) +{ + if (b_passEventsToView) + p_itemView->leaveEvent(e); + else + QCanvasView::leaveEvent(e); +} + + +void CVBEditor::contentsWheelEvent( QWheelEvent *e ) +{ + if (b_ignoreEvents) + { + e->ignore(); + return; + } + + if (b_passEventsToView) + p_itemView->contentsWheelEvent(e); + else + { + b_ignoreEvents = true; + QCanvasView::wheelEvent(e); + b_ignoreEvents = false; + } +} + +void CVBEditor::viewportResizeEvent( QResizeEvent * e ) +{ + QCanvasView::viewportResizeEvent(e); + p_itemView->p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems ); +} +//END class CVBEditor + +#include "itemview.moc" diff --git a/src/itemview.h b/src/itemview.h new file mode 100644 index 0000000..2bca8fd --- /dev/null +++ b/src/itemview.h @@ -0,0 +1,113 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ITEMVIEW_H +#define ITEMVIEW_H + +#include + +#include +#include + +class CVBEditor; +class ItemDocument; +class QTimer; + +/** +@author David Saxton +*/ +class ItemView : public View +{ + Q_OBJECT + public: + ItemView( ItemDocument *itemDocument, ViewContainer *viewContainer, uint viewAreaId, const char *name = 0 ); + ~ItemView(); + + virtual bool canZoomIn() const; + virtual bool canZoomOut() const; + CVBEditor *cvbEditor() const { return m_CVBEditor; } + /** + * @returns The zoom level + */ + double zoomLevel() const { return m_zoomLevel; } + + public slots: + void actualSize(); + void zoomIn(); + void zoomOut(); + void scrollToMouse( const QPoint &pos ); + virtual void updateStatus(); + + protected slots: + /** + * Called when the user changes the configuration. + */ + virtual void slotUpdateConfiguration(); + void startUpdatingStatus(); + void stopUpdatingStatus(); + + protected: + void updateZoomActions(); + /** + * Attempts to create a new CNItem if one was dragged onto the canvas + */ + void dropEvent( QDropEvent* ); + /** + * Reinherit to allow different types of items to be dragged in. + */ + virtual void dragEnterEvent( QDragEnterEvent* ); + void contentsMousePressEvent( QMouseEvent *e ); + void contentsMouseReleaseEvent( QMouseEvent *e ); + void contentsMouseDoubleClickEvent( QMouseEvent *e ); + void contentsMouseMoveEvent( QMouseEvent *e ); + void contentsWheelEvent( QWheelEvent *e ); + void enterEvent( QEvent * e ); + void leaveEvent( QEvent * e ); + + QGuardedPtr p_itemDocument; + CVBEditor *m_CVBEditor; + double m_zoomLevel; + QTimer * m_pUpdateStatusTmr; + + friend class CVBEditor; +}; + + +/** +@author David Saxton +*/ +class CVBEditor : public QCanvasView +{ +Q_OBJECT +public: + CVBEditor( QCanvas *canvas, ItemView *itemView, const char *name ); + + void setPassEventsToView( bool pass ) { b_passEventsToView = pass; } + + virtual void contentsMousePressEvent( QMouseEvent* e ); + virtual void contentsMouseReleaseEvent( QMouseEvent* e ); + virtual void contentsMouseDoubleClickEvent( QMouseEvent* e ); + virtual void contentsMouseMoveEvent( QMouseEvent* e ); + virtual void dragEnterEvent( QDragEnterEvent* e ); + virtual void dropEvent( QDropEvent* e ); + virtual void contentsWheelEvent( QWheelEvent *e ); + virtual void enterEvent( QEvent * e ); + virtual void leaveEvent( QEvent * e ); + +protected: + virtual void viewportResizeEvent( QResizeEvent * ); + ItemView *p_itemView; + bool b_passEventsToView; + bool b_ignoreEvents; +}; + + + +#endif diff --git a/src/katemdi.cpp b/src/katemdi.cpp new file mode 100644 index 0000000..0f34de1 --- /dev/null +++ b/src/katemdi.cpp @@ -0,0 +1,863 @@ +/* This file is part of the KDE libraries + Copyright (C) 2005 Christoph Cullmann + Copyright (C) 2002, 2003 Joseph Wenninger + + GUIClient partly based on ktoolbarhandler.cpp: Copyright (C) 2002 Simon Hausmann + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "katemdi.h" + +#include +#include +#include +#include +#include +#include +#include + + +namespace KateMDI { + +//BEGIN SPLITTER + +Splitter::Splitter(Orientation o, QWidget* parent, const char* name) + : QSplitter(o, parent, name) +{ +} + +Splitter::~Splitter() +{ +} + +bool Splitter::isLastChild(QWidget* w) const +{ + return ( idAfter( w ) == 0 ); +} + +int Splitter::idAfter ( QWidget * w ) const +{ + return QSplitter::idAfter (w); +} + +//END SPLITTER + + +//BEGIN TOGGLETOOLVIEWACTION + +ToggleToolViewAction::ToggleToolViewAction ( const QString& text, const KShortcut& cut, ToolView *tv, + QObject* parent, const char* name ) + : KToggleAction(text,cut,parent,name) + , m_tv(tv) +{ + connect(this,SIGNAL(toggled(bool)),this,SLOT(slotToggled(bool))); + connect(m_tv,SIGNAL(visibleChanged(bool)),this,SLOT(visibleChanged(bool))); + + setChecked(m_tv->visible()); +} + +ToggleToolViewAction::~ToggleToolViewAction() +{ + unplugAll(); +} + +void ToggleToolViewAction::visibleChanged(bool) +{ + if (isChecked() != m_tv->visible()) + setChecked (m_tv->visible()); +} + +void ToggleToolViewAction::slotToggled(bool t) +{ + if (t) + { + m_tv->mainWindow()->showToolView (m_tv); + m_tv->setFocus (); + } + else + { + m_tv->mainWindow()->hideToolView (m_tv); + m_tv->mainWindow()->centralWidget()->setFocus (); + } +} + +//END TOGGLETOOLVIEWACTION + + +//BEGIN GUICLIENT + +GUIClient::GUIClient ( MainWindow *mw ) + : QObject ( mw ) + , KXMLGUIClient ( mw ) + , m_mw (mw) +{ + connect( m_mw->guiFactory(), SIGNAL( clientAdded( KXMLGUIClient * ) ), + this, SLOT( clientAdded( KXMLGUIClient * ) ) ); + + if (actionCollection()->kaccel()==0) + actionCollection()->setWidget(m_mw); + + + // read shortcuts + actionCollection()->readShortcutSettings( "Shortcuts", kapp->config() ); +} + +GUIClient::~GUIClient() +{ +} + +void GUIClient::registerToolView (ToolView *tv) +{ + QString aname = QString("kate_mdi_toolview_") + tv->id; + + // try to read the action shortcut + KShortcut sc; + KConfig *cfg = kapp->config(); + QString _grp = cfg->group(); + cfg->setGroup("Shortcuts"); + sc = KShortcut( cfg->readEntry( aname, "" ) ); + cfg->setGroup( _grp ); +} + +void GUIClient::clientAdded( KXMLGUIClient *client ) +{ + if ( client == this ) + updateActions(); +} + +void GUIClient::updateActions() +{ + if ( !factory() ) + return; +} + +//END GUICLIENT + + +//BEGIN TOOLVIEW + +ToolView::ToolView (MainWindow *mainwin, Sidebar *sidebar, QWidget *parent) + : QVBox (parent) + , m_mainWin (mainwin) + , m_sidebar (sidebar) + , m_visible (false) + , persistent (false) +{ +} + +ToolView::~ToolView () +{ + m_mainWin->toolViewDeleted (this); +} + +void ToolView::setVisible (bool vis) +{ + if (m_visible == vis) + return; + + m_visible = vis; + emit visibleChanged (m_visible); +} + +bool ToolView::visible () const +{ + return m_visible; +} + +void ToolView::childEvent ( QChildEvent *ev ) +{ + // set the widget to be focus proxy if possible + if (ev->inserted() && ev->child() && ev->child()->qt_cast("QWidget")) + setFocusProxy ((QWidget *)(ev->child()->qt_cast("QWidget"))); + + QVBox::childEvent (ev); +} + +//END TOOLVIEW + + +//BEGIN SIDEBAR + +Sidebar::Sidebar (KMultiTabBar::KMultiTabBarPosition pos, MainWindow *mainwin, QWidget *parent) + : KMultiTabBar ((pos == KMultiTabBar::Top || pos == KMultiTabBar::Bottom) ? KMultiTabBar::Horizontal : KMultiTabBar::Vertical, parent) + , m_mainWin (mainwin) + , m_splitter (0) + , m_ownSplit (0) + , m_lastSize (0) +{ + setSidebarPosition( pos ); + hide (); +} + +Sidebar::~Sidebar () +{ +} + +void Sidebar::setSidebarPosition( KMultiTabBarPosition pos ) +{ + m_pos = pos; + setPosition(pos); +} + +void Sidebar::setSidebarStyle( KMultiTabBarStyle style ) +{ + m_sidebarTabStyle = style; + setStyle(style); +} + +void Sidebar::setSplitter (Splitter *sp) +{ + m_splitter = sp; + m_ownSplit = new Splitter ((sidebarPosition() == KMultiTabBar::Top || sidebarPosition() == KMultiTabBar::Bottom) ? Qt::Horizontal : Qt::Vertical, m_splitter); + m_ownSplit->setOpaqueResize( KGlobalSettings::opaqueResize() ); + m_ownSplit->setChildrenCollapsible( false ); + m_splitter->setResizeMode( m_ownSplit, QSplitter::KeepSize ); + m_ownSplit->hide (); +} + +ToolView *Sidebar::addWidget (const QPixmap &icon, const QString &text, ToolView *widget) +{ + static int id = 0; + + if (widget) + { + if (widget->sidebar() == this) + return widget; + + widget->sidebar()->removeWidget (widget); + } + + int newId = ++id; + + appendTab (icon, newId, text); + + if (!widget) + { + widget = new ToolView (m_mainWin, this, m_ownSplit); + widget->hide (); + widget->icon = icon; + widget->text = text; + } + else + { + widget->hide (); + widget->reparent (m_ownSplit, 0, QPoint()); + widget->m_sidebar = this; + } + + // save it's pos ;) + widget->persistent = false; + + m_idToWidget.insert (newId, widget); + m_widgetToId.insert (widget, newId); + m_toolviews.push_back (widget); + + show (); + + connect(tab(newId),SIGNAL(clicked(int)),this,SLOT(tabClicked(int))); + tab(newId)->installEventFilter(this); + + return widget; +} + +bool Sidebar::removeWidget (ToolView *widget) +{ + if (!m_widgetToId.contains(widget)) + return false; + + removeTab(m_widgetToId[widget]); + + m_idToWidget.remove (m_widgetToId[widget]); + m_widgetToId.remove (widget); + m_toolviews.remove (widget); + + bool anyVis = false; + QIntDictIterator it( m_idToWidget ); + for ( ; it.current(); ++it ) + { + if (!anyVis) + anyVis = it.current()->isVisible(); + } + + if (m_idToWidget.isEmpty()) + { + m_ownSplit->hide (); + hide (); + } + else if (!anyVis) + m_ownSplit->hide (); + + return true; +} + +bool Sidebar::showWidget (ToolView *widget) +{ + if (!m_widgetToId.contains(widget)) + return false; + + // hide other non-persistent views + QIntDictIterator it( m_idToWidget ); + for ( ; it.current(); ++it ) + if ((it.current() != widget) && !it.current()->persistent) + { + it.current()->hide(); + setTab (it.currentKey(), false); + it.current()->setVisible(false); + } + + setTab (m_widgetToId[widget], true); + + m_ownSplit->show (); + widget->show (); + + widget->setVisible (true); + + return true; +} + +bool Sidebar::hideWidget (ToolView *widget) +{ + if (!m_widgetToId.contains(widget)) + return false; + + bool anyVis = false; + + updateLastSize (); + + for ( QIntDictIterator it( m_idToWidget ); it.current(); ++it ) + { + if (it.current() == widget) + { + it.current()->hide(); + continue; + } + + if (!anyVis) + anyVis = it.current()->isVisible(); + } + + // lower tab + setTab (m_widgetToId[widget], false); + + if (!anyVis) + m_ownSplit->hide (); + + widget->setVisible (false); + + return true; +} + +void Sidebar::tabClicked(int i) +{ + ToolView *w = m_idToWidget[i]; + + if (!w) + return; + + if (isTabRaised(i)) + { + showWidget (w); + w->setFocus (); + } + else + { + hideWidget (w); + m_mainWin->centralWidget()->setFocus (); + } +} + +bool Sidebar::eventFilter(QObject *obj, QEvent *ev) +{ + if (ev->type()==QEvent::ContextMenu) + { + QContextMenuEvent *e = (QContextMenuEvent *) ev; + KMultiTabBarTab *bt = dynamic_cast(obj); + if (bt) + { + kdDebug()<<"Request for popup"<id(); + + ToolView *w = m_idToWidget[m_popupButton]; + + if (w) + { + KPopupMenu *p = new KPopupMenu (this); + + p->insertTitle(SmallIcon("view_remove"), i18n("Behavior"), 50); + + p->insertItem(w->persistent ? SmallIconSet("window_nofullscreen") : SmallIconSet("window_fullscreen"), w->persistent ? i18n("Make Non-Persistent") : i18n("Make Persistent"), 10); + + p->insertTitle(SmallIcon("move"), i18n("Move To"), 51); + + if (sidebarPosition() != 0) + p->insertItem(SmallIconSet("back"), i18n("Left Sidebar"),0); + + if (sidebarPosition() != 1) + p->insertItem(SmallIconSet("forward"), i18n("Right Sidebar"),1); + + if (sidebarPosition() != 2) + p->insertItem(SmallIconSet("up"), i18n("Top Sidebar"),2); + + if (sidebarPosition() != 3) + p->insertItem(SmallIconSet("down"), i18n("Bottom Sidebar"),3); + + connect(p, SIGNAL(activated(int)), + this, SLOT(buttonPopupActivate(int))); + + p->exec(e->globalPos()); + delete p; + + return true; + } + } + } + + return false; +} + +void Sidebar::buttonPopupActivate (int id) +{ + ToolView *w = m_idToWidget[m_popupButton]; + + if (!w) + return; + + // move ids + if (id < 4) + { + // move + show ;) + m_mainWin->moveToolView (w, (KMultiTabBar::KMultiTabBarPosition) id); + m_mainWin->showToolView (w); + } + + // toggle persistent + if (id == 10) + w->persistent = !w->persistent; +} + +void Sidebar::updateLastSize () +{ + QValueList s = m_splitter->sizes (); + + int i = 0; + if ((sidebarPosition() == KMultiTabBar::Right || sidebarPosition() == KMultiTabBar::Bottom)) + i = 2; + + // little threshold + if (s[i] > 2) + m_lastSize = s[i]; +} + +class TmpToolViewSorter +{ + public: + ToolView *tv; + unsigned int pos; +}; + +void Sidebar::restoreSession (KConfig *config) +{ + // get the last correct placed toolview + unsigned int firstWrong = 0; + for ( ; firstWrong < m_toolviews.size(); ++firstWrong ) + { + ToolView *tv = m_toolviews[firstWrong]; + + unsigned int pos = config->readUnsignedNumEntry (QString ("Kate-MDI-ToolView-%1-Sidebar-Position").arg(tv->id), firstWrong); + + if (pos != firstWrong) + break; + } + + // we need to reshuffle, ahhh :( + if (firstWrong < m_toolviews.size()) + { + // first: collect the items to reshuffle + QValueList toSort; + for (unsigned int i=firstWrong; i < m_toolviews.size(); ++i) + { + TmpToolViewSorter s; + s.tv = m_toolviews[i]; + s.pos = config->readUnsignedNumEntry (QString ("Kate-MDI-ToolView-%1-Sidebar-Position").arg(m_toolviews[i]->id), i); + toSort.push_back (s); + } + + // now: sort the stuff we need to reshuffle + for (unsigned int m=0; m < toSort.size(); ++m) + for (unsigned int n=m+1; n < toSort.size(); ++n) + if (toSort[n].pos < toSort[m].pos) + { + TmpToolViewSorter tmp = toSort[n]; + toSort[n] = toSort[m]; + toSort[m] = tmp; + } + + // then: remove this items from the button bar + // do this backwards, to minimize the relayout efforts + for (int i=m_toolviews.size()-1; i >= (int)firstWrong; --i) + { + removeTab (m_widgetToId[m_toolviews[i]]); + } + + // insert the reshuffled things in order :) + for (unsigned int i=0; i < toSort.size(); ++i) + { + ToolView *tv = toSort[i].tv; + + m_toolviews[firstWrong+i] = tv; + + // readd the button + int newId = m_widgetToId[tv]; + appendTab (tv->icon, newId, tv->text); + connect(tab(newId),SIGNAL(clicked(int)),this,SLOT(tabClicked(int))); + tab(newId)->installEventFilter(this); + + // reshuffle in splitter + m_ownSplit->moveToLast (tv); + } + } + + // update last size if needed + updateLastSize (); + + // restore the own splitter sizes + QValueList s = config->readIntListEntry (QString ("Kate-MDI-Sidebar-%1-Splitter").arg(sidebarPosition())); + m_ownSplit->setSizes (s); + + // show only correct toolviews, remember persistent values ;) + bool anyVis = false; + for ( unsigned int i=0; i < m_toolviews.size(); ++i ) + { + ToolView *tv = m_toolviews[i]; + + tv->persistent = config->readBoolEntry (QString ("Kate-MDI-ToolView-%1-Persistent").arg(tv->id), false); + tv->setVisible (config->readBoolEntry (QString ("Kate-MDI-ToolView-%1-Visible").arg(tv->id), false)); + + if (!anyVis) + anyVis = tv->visible(); + + setTab (m_widgetToId[tv],tv->visible()); + + if (tv->visible()) + tv->show(); + else + tv->hide (); + } + + if (anyVis) + m_ownSplit->show(); + else + m_ownSplit->hide(); +} + +void Sidebar::saveSession (KConfig *config) +{ + // store the own splitter sizes + QValueList s = m_ownSplit->sizes(); + config->writeEntry (QString ("Kate-MDI-Sidebar-%1-Splitter").arg(sidebarPosition()), s); + + // store the data about all toolviews in this sidebar ;) + for ( unsigned int i=0; i < m_toolviews.size(); ++i ) + { + ToolView *tv = m_toolviews[i]; + + config->writeEntry (QString ("Kate-MDI-ToolView-%1-Position").arg(tv->id), tv->sidebar()->sidebarPosition()); + config->writeEntry (QString ("Kate-MDI-ToolView-%1-Sidebar-Position").arg(tv->id), i); + config->writeEntry (QString ("Kate-MDI-ToolView-%1-Visible").arg(tv->id), tv->visible()); + config->writeEntry (QString ("Kate-MDI-ToolView-%1-Persistent").arg(tv->id), tv->persistent); + } +} + +//END SIDEBAR + + +//BEGIN MAIN WINDOW + +MainWindow::MainWindow (QWidget* parentWidget, const char* name) + : KParts::MainWindow( parentWidget, name) + , m_restoreConfig (0) + , m_guiClient (new GUIClient (this)) +{ + // init the internal widgets + QHBox *hb = new QHBox (this); + setCentralWidget(hb); + + m_sidebars[KMultiTabBar::Left] = new Sidebar (KMultiTabBar::Left, this, hb); + + m_hSplitter = new Splitter (Qt::Horizontal, hb); + m_hSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() ); + + m_sidebars[KMultiTabBar::Left]->setSplitter (m_hSplitter); + + QVBox *vb = new QVBox (m_hSplitter); + m_hSplitter->setCollapsible(vb, false); + + m_sidebars[KMultiTabBar::Top] = new Sidebar (KMultiTabBar::Top, this, vb); + + m_vSplitter = new Splitter (Qt::Vertical, vb); + m_vSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() ); + + m_sidebars[KMultiTabBar::Top]->setSplitter (m_vSplitter); + + m_centralWidget = new QVBox (m_vSplitter); + m_vSplitter->setCollapsible(m_centralWidget, false); + + m_sidebars[KMultiTabBar::Bottom] = new Sidebar (KMultiTabBar::Bottom, this, vb); + m_sidebars[KMultiTabBar::Bottom]->setSplitter (m_vSplitter); + + m_sidebars[KMultiTabBar::Right] = new Sidebar (KMultiTabBar::Right, this, hb); + m_sidebars[KMultiTabBar::Right]->setSplitter (m_hSplitter); +} + +MainWindow::~MainWindow () +{ + // cu toolviews + while (!m_toolviews.isEmpty()) + delete m_toolviews[0]; + + // seems like we really should delete this by hand ;) + delete m_centralWidget; + + for (unsigned int i=0; i < 4; ++i) + delete m_sidebars[i]; +} + +QWidget *MainWindow::centralWidget () const +{ + return m_centralWidget; +} + +ToolView *MainWindow::createToolView (const QString &identifier, KMultiTabBar::KMultiTabBarPosition pos, const QPixmap &icon, const QString &text) +{ + if (m_idToWidget[identifier]) + return 0; + + // try the restore config to figure out real pos + if (m_restoreConfig && m_restoreConfig->hasGroup (m_restoreGroup)) + { + m_restoreConfig->setGroup (m_restoreGroup); + pos = (KMultiTabBar::KMultiTabBarPosition) m_restoreConfig->readNumEntry (QString ("Kate-MDI-ToolView-%1-Position").arg(identifier), pos); + } + + ToolView *v = m_sidebars[pos]->addWidget (icon, text, 0); + v->id = identifier; + + m_idToWidget.insert (identifier, v); + m_toolviews.push_back (v); + + // register for menu stuff + m_guiClient->registerToolView (v); + + return v; +} + +ToolView *MainWindow::toolView (const QString &identifier) const +{ + return m_idToWidget[identifier]; +} + +void MainWindow::toolViewDeleted (ToolView *widget) +{ + if (!widget) + return; + + if (widget->mainWindow() != this) + return; + + // unregister from menu stuff + + widget->sidebar()->removeWidget (widget); + + m_idToWidget.remove (widget->id); + m_toolviews.remove (widget); +} + +void MainWindow::setToolViewStyle (KMultiTabBar::KMultiTabBarStyle style) +{ + m_sidebars[0]->setSidebarStyle(style); + m_sidebars[1]->setSidebarStyle(style); + m_sidebars[2]->setSidebarStyle(style); + m_sidebars[3]->setSidebarStyle(style); +} + +KMultiTabBar::KMultiTabBarStyle MainWindow::toolViewStyle () const +{ + // all sidebars have the same style, so just take Top + return m_sidebars[KMultiTabBar::Top]->sidebarTabStyle(); +} + +bool MainWindow::moveToolView (ToolView *widget, KMultiTabBar::KMultiTabBarPosition pos) +{ + if (!widget || widget->mainWindow() != this) + return false; + + // try the restore config to figure out real pos + if (m_restoreConfig && m_restoreConfig->hasGroup (m_restoreGroup)) + { + m_restoreConfig->setGroup (m_restoreGroup); + pos = (KMultiTabBar::KMultiTabBarPosition) m_restoreConfig->readNumEntry (QString ("Kate-MDI-ToolView-%1-Position").arg(widget->id), pos); + } + + m_sidebars[pos]->addWidget (widget->icon, widget->text, widget); + + return true; +} + +bool MainWindow::showToolView (ToolView *widget) +{ + if (!widget || widget->mainWindow() != this) + return false; + + // skip this if happens during restoring, or we will just see flicker + if (m_restoreConfig && m_restoreConfig->hasGroup (m_restoreGroup)) + return true; + + return widget->sidebar()->showWidget (widget); +} + +bool MainWindow::hideToolView (ToolView *widget) +{ + if (!widget || widget->mainWindow() != this) + return false; + + // skip this if happens during restoring, or we will just see flicker + if (m_restoreConfig && m_restoreConfig->hasGroup (m_restoreGroup)) + return true; + + return widget->sidebar()->hideWidget (widget); +} + +void MainWindow::startRestore (KConfig *config, const QString &group) +{ + // first save this stuff + m_restoreConfig = config; + m_restoreGroup = group; + + if (!m_restoreConfig || !m_restoreConfig->hasGroup (m_restoreGroup)) + { + //BEGIN Added stuff specifically for ktechlab + QValueList hs; + hs << 220 << 100 << 230; + QValueList vs; + vs << 0 << 100 << 150; + + m_sidebars[0]->setLastSize (hs[0]); + m_sidebars[1]->setLastSize (hs[2]); + m_sidebars[2]->setLastSize (vs[0]); + m_sidebars[3]->setLastSize (vs[2]); + + m_hSplitter->setSizes(hs); + m_vSplitter->setSizes(vs); + //END Added stuff specifically for ktechlab + + return; + } + + // apply size once, to get sizes ready ;) + m_restoreConfig->setGroup (m_restoreGroup); + restoreWindowSize (m_restoreConfig); + + m_restoreConfig->setGroup (m_restoreGroup); + + // get main splitter sizes ;) + QValueList hs = m_restoreConfig->readIntListEntry ("Kate-MDI-H-Splitter"); + QValueList vs = m_restoreConfig->readIntListEntry ("Kate-MDI-V-Splitter"); + + m_sidebars[0]->setLastSize (hs[0]); + m_sidebars[1]->setLastSize (hs[2]); + m_sidebars[2]->setLastSize (vs[0]); + m_sidebars[3]->setLastSize (vs[2]); + + m_hSplitter->setSizes(hs); + m_vSplitter->setSizes(vs); + + setToolViewStyle( (KMultiTabBar::KMultiTabBarStyle)m_restoreConfig->readNumEntry ("Kate-MDI-Sidebar-Style", (int)toolViewStyle()) ); +} + +void MainWindow::finishRestore () +{ + if (!m_restoreConfig) + return; + + if (m_restoreConfig->hasGroup (m_restoreGroup)) + { + // apply all settings, like toolbar pos and more ;) + applyMainWindowSettings(m_restoreConfig, m_restoreGroup); + + // reshuffle toolviews only if needed + m_restoreConfig->setGroup (m_restoreGroup); + for ( unsigned int i=0; i < m_toolviews.size(); ++i ) + { + KMultiTabBar::KMultiTabBarPosition newPos = (KMultiTabBar::KMultiTabBarPosition) m_restoreConfig->readNumEntry (QString ("Kate-MDI-ToolView-%1-Position").arg(m_toolviews[i]->id), m_toolviews[i]->sidebar()->sidebarPosition()); + + if (m_toolviews[i]->sidebar()->sidebarPosition() != newPos) + { + moveToolView (m_toolviews[i], newPos); + } + } + + // restore the sidebars + m_restoreConfig->setGroup (m_restoreGroup); + for (unsigned int i=0; i < 4; ++i) + m_sidebars[i]->restoreSession (m_restoreConfig); + } + + // clear this stuff, we are done ;) + m_restoreConfig = 0; + m_restoreGroup = ""; +} + +void MainWindow::saveSession (KConfig *config, const QString &group) +{ + if (!config) + return; + + saveMainWindowSettings (config, group); + + config->setGroup (group); + + // save main splitter sizes ;) + QValueList hs = m_hSplitter->sizes(); + QValueList vs = m_vSplitter->sizes(); + + if (hs[0] <= 2 && !m_sidebars[0]->splitterVisible ()) + hs[0] = m_sidebars[0]->lastSize(); + if (hs[2] <= 2 && !m_sidebars[1]->splitterVisible ()) + hs[2] = m_sidebars[1]->lastSize(); + if (vs[0] <= 2 && !m_sidebars[2]->splitterVisible ()) + vs[0] = m_sidebars[2]->lastSize(); + if (vs[2] <= 2 && !m_sidebars[3]->splitterVisible ()) + vs[2] = m_sidebars[3]->lastSize(); + + config->writeEntry ("Kate-MDI-H-Splitter", hs); + config->writeEntry ("Kate-MDI-V-Splitter", vs); + + // save sidebar style + config->writeEntry ("Kate-MDI-Sidebar-Style", (int)toolViewStyle()); + + // save the sidebars + for (unsigned int i=0; i < 4; ++i) + m_sidebars[i]->saveSession (config); +} + +//END MAIN WINDOW + +} // namespace KateMDI + +#include "katemdi.moc" + diff --git a/src/katemdi.h b/src/katemdi.h new file mode 100644 index 0000000..aca8419 --- /dev/null +++ b/src/katemdi.h @@ -0,0 +1,412 @@ +/* This file is part of the KDE libraries + Copyright (C) 2005 Christoph Cullmann + Copyright (C) 2002, 2003 Joseph Wenninger + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __KATE_MDI_H__ +#define __KATE_MDI_H__ + +#include + +#include + +#include +#include +#include + +namespace KateMDI { + + +/** This class is needed because QSplitter cant return an index for a widget. */ +class Splitter : public QSplitter +{ + Q_OBJECT + + public: + Splitter(Orientation o, QWidget* parent=0, const char* name=0); + ~Splitter(); + + /** Since there is supposed to be only 2 childs of a katesplitter, + * any child other than the last is the first. + * This method uses QSplitter::idAfter(widget) which + * returns 0 if there is no widget after this one. + * This results in an error if widget is not a child + * in this splitter */ + bool isLastChild(QWidget* w) const; + + int idAfter ( QWidget * w ) const; +}; + +class ToggleToolViewAction : public KToggleAction +{ + Q_OBJECT + + public: + ToggleToolViewAction ( const QString& text, const KShortcut& cut, + class ToolView *tv, QObject* parent = 0, const char* name = 0 ); + + virtual ~ToggleToolViewAction(); + + protected slots: + void slotToggled(bool); + void visibleChanged(bool); + + private: + ToolView *m_tv; +}; + +class GUIClient : public QObject, public KXMLGUIClient +{ + Q_OBJECT + + public: + GUIClient ( class MainWindow *mw ); + virtual ~GUIClient(); + + void registerToolView (ToolView *tv); + + private slots: + void clientAdded( KXMLGUIClient *client ); + void updateActions(); + + private: + MainWindow *m_mw; +}; + +class ToolView : public QVBox +{ + Q_OBJECT + + friend class Sidebar; + friend class MainWindow; + friend class GUIClient; + friend class ToggleToolViewAction; + + protected: + /** + * ToolView + * Objects of this clas represent a toolview in the mainwindow + * you should only add one widget as child to this toolview, it will + * be automatically set to be the focus proxy of the toolview + * @param mainwin main window for this toolview + * @param sidebar sidebar of this toolview + * @param parent parent widget, e.g. the splitter of one of the sidebars + */ + ToolView (class MainWindow *mainwin, class Sidebar *sidebar, QWidget *parent); + + public: + /** + * destuct me, this is allowed for all, will care itself that the toolview is removed + * from the mainwindow and sidebar + */ + virtual ~ToolView (); + + signals: + /** + * toolview hidden or shown + * @param bool is this toolview made visible? + */ + void visibleChanged (bool visible); + + /** + * some internal methodes needed by the main window and the sidebars + */ + protected: + MainWindow *mainWindow () { return m_mainWin; } + + Sidebar *sidebar () { return m_sidebar; } + + void setVisible (bool vis); + + public: + bool visible () const; + + protected: + void childEvent ( QChildEvent *ev ); + + private: + MainWindow *m_mainWin; + Sidebar *m_sidebar; + + /** + * unique id + */ + QString id; + + /** + * is visible in sidebar + */ + bool m_visible; + + /** + * is this view persistent? + */ + bool persistent; + + QPixmap icon; + QString text; +}; + +class Sidebar : public KMultiTabBar +{ + Q_OBJECT + + public: + Sidebar (KMultiTabBar::KMultiTabBarPosition pos, class MainWindow *mainwin, QWidget *parent); + virtual ~Sidebar (); + + void setSplitter (Splitter *sp); + + //HACK use these functions intead of their respective functions in + //KMultiTabBar so that we know what they were set to. + void setSidebarPosition( KMultiTabBarPosition pos ); + KMultiTabBar::KMultiTabBarPosition sidebarPosition() const { return m_pos; } + void setSidebarStyle( KMultiTabBarStyle style ); + KMultiTabBar::KMultiTabBarStyle sidebarTabStyle() const { return m_sidebarTabStyle; } + + public: + ToolView *addWidget (const QPixmap &icon, const QString &text, ToolView *widget); + bool removeWidget (ToolView *widget); + + bool showWidget (ToolView *widget); + bool hideWidget (ToolView *widget); + + void setLastSize (int s) { m_lastSize = s; } + int lastSize () const { return m_lastSize; } + void updateLastSize (); + + bool splitterVisible () const { return m_ownSplit->isVisible(); } + + void restoreSession (); + + /** + * restore the current session config from given object, use current group + * @param config config object to use + */ + void restoreSession (KConfig *config); + + /** + * save the current session config to given object, use current group + * @param config config object to use + */ + void saveSession (KConfig *config); + + private slots: + void tabClicked(int); + + protected: + bool eventFilter(QObject *obj, QEvent *ev); + + private slots: + void buttonPopupActivate (int id); + + private: + MainWindow *m_mainWin; + + KMultiTabBar::KMultiTabBarStyle m_sidebarTabStyle; + KMultiTabBar::KMultiTabBarPosition m_pos; + Splitter *m_splitter; + KMultiTabBar *m_tabBar; + Splitter *m_ownSplit; + + QIntDict m_idToWidget; + QMap m_widgetToId; + + /** + * list of all toolviews around in this sidebar + */ + QValueList m_toolviews; + + int m_lastSize; + + int m_popupButton; +}; + +class MainWindow : public KParts::MainWindow +{ + Q_OBJECT + + friend class ToolView; + + // + // Constructor area + // + public: + /** + * Constructor + */ + MainWindow (QWidget* parentWidget = 0, const char* name = 0); + + /** + * Destructor + */ + virtual ~MainWindow (); + + // + // public interfaces + // + public: + /** + * central widget ;) + * use this as parent for your content + * this widget will get focus if a toolview is hidden + * @return central widget + */ + QWidget *centralWidget () const; + + /** + * add a given widget to the given sidebar if possible, name is very important + * @param identifier unique identifier for this toolview + * @param pos position for the toolview, if we are in session restore, this is only a preference + * @param icon icon to use for the toolview + * @param text text to use in addition to icon + * @return created toolview on success or 0 + */ + ToolView *createToolView (const QString &identifier, KMultiTabBar::KMultiTabBarPosition pos, const QPixmap &icon, const QString &text); + + /** + * give you handle to toolview for the given name, 0 if no toolview around + * @param identifier toolview name + * @return toolview if existing, else 0 + */ + ToolView *toolView (const QString &identifier) const; + + /** + * set the toolview's tabbar style. + * @param style the tabbar style. + */ + void setToolViewStyle (KMultiTabBar::KMultiTabBarStyle style); + + /** + * get the toolview's tabbar style. Call this before @p startRestore(), + * otherwise you overwrite the usersettings. + * @return toolview's tabbar style + */ + KMultiTabBar::KMultiTabBarStyle toolViewStyle () const; + + protected: + /** + * called by toolview destructor + * @param widget toolview which is destroyed + */ + void toolViewDeleted (ToolView *widget); + + /** + * modifiers for existing toolviews + */ + public: + /** + * move a toolview around + * @param widget toolview to move + * @param pos position to move too, during session restore, only preference + * @return success + */ + bool moveToolView (ToolView *widget, KMultiTabBar::KMultiTabBarPosition pos); + + /** + * show given toolview, discarded while session restore + * @param widget toolview to show + * @return success + */ + bool showToolView (ToolView *widget); + + /** + * hide given toolview, discarded while session restore + * @param widget toolview to hide + * @return success + */ + bool hideToolView (ToolView *widget); + + /** + * session saving and restore stuff + */ + public: + /** + * start the restore + * @param config config object to use + * @param group config group to use + */ + void startRestore (KConfig *config, const QString &group); + + /** + * finish the restore + */ + void finishRestore (); + + /** + * save the current session config to given object and group + * @param config config object to use + * @param group config group to use + */ + void saveSession (KConfig *config, const QString &group); + + /** + * internal data ;) + */ + private: + /** + * map identifiers to widgets + */ + QDict m_idToWidget; + + /** + * list of all toolviews around + */ + QValueList m_toolviews; + + /** + * widget, which is the central part of the + * main window ;) + */ + QWidget *m_centralWidget; + + /** + * horizontal splitter + */ + Splitter *m_hSplitter; + + /** + * vertical splitter + */ + Splitter *m_vSplitter; + + /** + * sidebars for the four sides + */ + Sidebar *m_sidebars[4]; + + /** + * config object for session restore, only valid between + * start and finish restore calls + */ + KConfig *m_restoreConfig; + + /** + * restore group + */ + QString m_restoreGroup; + + /** + * out guiclient + */ + GUIClient *m_guiClient; +}; + +} + +#endif diff --git a/src/ktechlab.cpp b/src/ktechlab.cpp new file mode 100644 index 0000000..cc89ffb --- /dev/null +++ b/src/ktechlab.cpp @@ -0,0 +1,1232 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "circuitdocument.h" +#include "config.h" +#include "contexthelp.h" +#include "docmanager.h" +#include "filemetainfo.h" +#include "flowcodedocument.h" +#include "itemeditor.h" +#include "itemgroup.h" +#include "iteminterface.h" +#include "itemlibrary.h" +#include "ktechlab.h" +#include "core/ktlconfig.h" +#include "languagemanager.h" +#include "mechanicsdocument.h" +#include "microlibrary.h" +#include "newfiledlg.h" +#include "oscilloscope.h" +#include "projectmanager.h" +#include "recentfilesaction.h" +#include "settingsdlg.h" +#include "subcircuits.h" +#include "symbolviewer.h" +#include "textdocument.h" +#include "textview.h" +#include "viewcontainer.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +KTechlab::KTechlab() + : KateMDI::MainWindow( 0, "KTechlab" ) +{ + QTime ct; + ct.start(); + + m_bIsShown = false; + m_pContainerDropSource = 0l; + m_pContainerDropReceived = 0l; + m_pContextMenuContainer = 0l; + m_pFocusedContainer = 0l; + m_pToolBarOverlayLabel = 0l; + + m_pUpdateCaptionsTimer = new QTimer( this ); + connect( m_pUpdateCaptionsTimer, SIGNAL(timeout()), this, SLOT(slotUpdateCaptions()) ); + + setMinimumSize( 400, 400 ); + + DocManager::self(this); + ItemInterface::self(this); + + setupTabWidget(); + setupToolDocks(); + setupActions(); + setupView(); + readProperties( KGlobal::config() ); + +// kdDebug() << "Constructor time: " << ct.elapsed() << endl; +} + + +KTechlab::~KTechlab() +{ + fileMetaInfo()->saveAllMetaInfo(); + + delete fileMetaInfo(); + delete itemLibrary(); // This better be the last time the item library is used! + delete subcircuits(); +} + + +void KTechlab::show() +{ + KateMDI::MainWindow::show(); + m_bIsShown = true; +} + + +void KTechlab::load( const KURL & url ) +{ + if ( url.url().endsWith( ".ktechlab", false ) ) + { + // This is a ktechlab project; it has to be handled separetly from a + // normal file. + + ProjectManager::self()->slotOpenProject( url ); + return; + } + + + QString target; + // the below code is what you should normally do. in this + // example case, we want the url to our own. you probably + // want to use this code instead for your app + + // download the contents + if ( !KIO::NetAccess::download( url, target, this ) ) + { + // If the file could not be downloaded, for example does not + // exist on disk, NetAccess will tell us what error to use + KMessageBox::error(this, KIO::NetAccess::lastErrorString()); + + return; + } + + addRecentFile(url); + + // set our caption + setCaption( url.prettyURL() ); + + // load in the file (target is always local) + DocManager::self()->openURL( target ); + + // and remove the temp file + KIO::NetAccess::removeTempFile( target ); +} + + +QStringList KTechlab::recentFiles() +{ + return m_recentFiles->items(); +} + + +void KTechlab::setupToolDocks() +{ +#if defined(KDE_MAKE_VERSION) +# if KDE_VERSION >= KDE_MAKE_VERSION(3,3,0) + setToolViewStyle( KMultiTabBar::KDEV3ICON ); +# endif +#endif + + QPixmap pm; + KIconLoader * loader = KGlobal::iconLoader(); + KateMDI::ToolView * tv = 0l; + + tv = createToolView( ProjectManager::toolViewIdentifier(), + KMultiTabBar::Left, + loader->loadIcon( "attach", KIcon::Small ), + i18n("Project") ); + ProjectManager::self( this, tv ); + + pm.load( locate( "appdata", "icons/circuit.png" ) ); + tv = createToolView( ComponentSelector::toolViewIdentifier(), + KMultiTabBar::Left, + pm, + i18n("Components") ); + ComponentSelector::self(tv); + + // Create an instance of the subcircuits interface, now that we have created the component selector + subcircuits(); + Subcircuits::loadSubcircuits(); + + pm.load( locate( "appdata", "icons/flowcode.png" ) ); + tv = createToolView( FlowPartSelector::toolViewIdentifier(), + KMultiTabBar::Left, + pm, + i18n("Flow Parts") ); + FlowPartSelector::self(tv); + +#ifdef MECHANICS + pm.load( locate( "appdata", "icons/mechanics.png" ) ); + tv = createToolView( MechanicsSelector::toolViewIdentifier(), + KMultiTabBar::Left, + pm, + i18n("Mechanics") ); + MechanicsSelector::self(tv); +#endif + + pm.load( locate( "appdata", "icons/item.png" ) ); + tv = createToolView( ItemEditor::toolViewIdentifier(), + KMultiTabBar::Right, + pm, + i18n("Item Editor") ); + ItemEditor::self(tv); + + tv = createToolView( ContextHelp::toolViewIdentifier(), + KMultiTabBar::Right, + loader->loadIcon( "contents", KIcon::Small ), + i18n("Context Help") ); + ContextHelp::self(tv); + + tv = createToolView( LanguageManager::toolViewIdentifier(), + KMultiTabBar::Bottom, + loader->loadIcon( "log", KIcon::Small ), + i18n("Messages") ); + LanguageManager::self( tv, this ); + +#ifndef NO_GPSIM + tv = createToolView( SymbolViewer::toolViewIdentifier(), + KMultiTabBar::Right, + loader->loadIcon( "blockdevice", KIcon::Small ), + i18n("Symbol Viewer") ); + SymbolViewer::self(tv); +#endif + + addOscilloscopeAsToolView(this); +} + + +void KTechlab::addWindow( ViewContainer * vc ) +{ + if ( vc && !m_viewContainerList.contains(vc) ) + { + m_viewContainerList << vc; + connect( vc, SIGNAL(destroyed(QObject* )), this, SLOT(slotViewContainerDestroyed(QObject* )) ); + } + + m_viewContainerList.remove((ViewContainer*)0); + slotUpdateTabWidget(); + slotDocModifiedChanged(); +} + + +void KTechlab::setupView() +{ + setAcceptDrops(true); + setStandardToolBarMenuEnabled(true); + setXMLFile("ktechlabui.rc"); + createShellGUI(true); + action("newfile_popup")->plug( toolBar("mainToolBar"), 0 ); + action("file_new")->unplug( toolBar("mainToolBar") ); + statusBar()->show(); +} + + +void KTechlab::overlayToolBarScreenshot() +{ + if ( !m_pToolBarOverlayLabel ) + { + m_pToolBarOverlayLabel = new QLabel( 0, 0, WStyle_StaysOnTop | WStyle_Customize | WStyle_NoBorder | WNoAutoErase | WType_Popup ); + m_pToolBarOverlayLabel->hide(); + m_pToolBarOverlayLabel->setBackgroundMode( NoBackground ); + } + + if ( !m_bIsShown ) + { + // The window isn't visible yet, so there's nothing to overlay (and if we tried, + // it would appear as a strange floating toolbar). + return; + } + + if ( m_pToolBarOverlayLabel->isShown() ) + { + // This is to avoid successive calls to removeGUIClient when we have + // already popped it up for the first call, and don't want to take + // another screenshot (as that would be without the toolbar). + return; + } + + QPtrListIterator toolBarIterator(); + +// QWidget * toolsWidget = toolBar( "toolsToolBar" ); +// QWidget * debugWidget = toolBar( "debugTB" ); + + KToolBar * toolsWidget = static_cast(child( "toolsToolBar", "KToolBar" )); + KToolBar * debugWidget = static_cast(child( "debugTB", "KToolBar" )); + + if ( !toolsWidget && !debugWidget ) + return; + + QWidget * parent = static_cast(toolsWidget ? toolsWidget->parent() : debugWidget->parent()); + + QRect grabRect; + + // 128 is a sanity check (widget can do strange things when being destroyed) + + if ( toolsWidget && toolsWidget->height() <= 128 ) + grabRect |= toolsWidget->geometry(); + if ( debugWidget && debugWidget->height() <= 128 ) + grabRect |= debugWidget->geometry(); + + if ( !grabRect.isValid() ) + return; + + QPixmap shot = QPixmap::grabWidget( parent, grabRect.x(), grabRect.y(), grabRect.width(), grabRect.height() ); + + m_pToolBarOverlayLabel->move( parent->mapToGlobal( grabRect.topLeft() ) ); + m_pToolBarOverlayLabel->setFixedSize( grabRect.size() ); + m_pToolBarOverlayLabel->setPixmap( shot ); + m_pToolBarOverlayLabel->show(); + + QTimer::singleShot( 100, this, SLOT( hideToolBarOverlay() ) ); +} + + +void KTechlab::hideToolBarOverlay() +{ + if ( !m_pToolBarOverlayLabel ) + return; + +// QWidget * hiddenWidget = toolBar( "toolsToolBar" ); +// if ( !hiddenWidget ) +// return; + +// hiddenWidget->setBackgroundMode( NoBackground ); +// hiddenWidget->setWFlags( WNoAutoErase ); +// hiddenWidget->setUpdatesEnabled( false ); + + m_pToolBarOverlayLabel->hide(); +} + + +void KTechlab::addNoRemoveGUIClient( KXMLGUIClient * client ) +{ + if ( client && !m_noRemoveGUIClients.contains( client ) ) + m_noRemoveGUIClients << client; +} + + +void KTechlab::removeGUIClients() +{ + QValueList clientsToRemove; + + QPtrList clients = factory()->clients(); + for ( KXMLGUIClient * client = clients.first(); client; client = clients.next() ) + { + if ( client && client != this && !m_noRemoveGUIClients.contains( client ) ) + clientsToRemove << client; + } + + if ( clients.isEmpty() ) + return; + + overlayToolBarScreenshot(); + + QValueList::iterator end = clientsToRemove.end(); + for ( QValueList::iterator it = clientsToRemove.begin(); it != end; ++it ) + factory()->removeClient(*it); +} + + +void KTechlab::setupTabWidget() +{ + m_pViewContainerTabWidget = new KTabWidget(centralWidget()); + connect( tabWidget(), SIGNAL(currentChanged(QWidget* )), this, SLOT(slotViewContainerActivated(QWidget* )) ); + connect( tabWidget(), SIGNAL(testCanDecode(const QDragMoveEvent*, bool& )), this, SLOT(slotTabDragEvent(const QDragMoveEvent*, bool& )) ); + connect( tabWidget(), SIGNAL(initiateDrag(QWidget* )), this, SLOT(slotTabDragInitiate(QWidget* )) ); + connect( tabWidget(), SIGNAL(receivedDropEvent(QDropEvent* )), this, SLOT(slotTabReceivedDropEvent(QDropEvent* )) ); + connect( tabWidget(), SIGNAL(receivedDropEvent(QWidget*, QDropEvent* )), this, SLOT(slotTabReceivedDropEvent(QWidget*, QDropEvent* )) ); + + KConfig *config = kapp->config(); + config->setGroup("UI"); + + bool CloseOnHover = config->readBoolEntry( "CloseOnHover", false ); + tabWidget()->setHoverCloseButton( CloseOnHover ); + + bool CloseOnHoverDelay = config->readBoolEntry( "CloseOnHoverDelay", false ); + tabWidget()->setHoverCloseButtonDelayed( CloseOnHoverDelay ); + +// bool openNewTabAfterCurrent = config->readBoolEntry( "OpenNewTabAfterCurrent", false ); +// bool showTabIcons = config->readBoolEntry( "ShowTabIcons", true ); + + if (config->readBoolEntry( "ShowCloseTabsButton", true )) + { + QToolButton *but = new QToolButton(tabWidget()); + but->setIconSet(SmallIcon("tab_remove")); + but->adjustSize(); + but->hide(); + connect( but, SIGNAL(clicked()), this, SLOT(slotViewContainerClose()) ); + tabWidget()->setCornerWidget(but, TopRight); + } +// tabWidget()->setTabReorderingEnabled(true); +// connect(tabWidget(), SIGNAL(movedTab(int, int)), this, SLOT(tabMoved(int, int))); + connect(tabWidget(), SIGNAL(contextMenu(QWidget*,const QPoint &)), this, SLOT(slotTabContext(QWidget*,const QPoint &))); + //END Tab bar stuff +} + + +void KTechlab::slotUpdateTabWidget() +{ + m_viewContainerList.remove( (ViewContainer*)0 ); + + bool noWindows = m_viewContainerList.isEmpty(); + + if ( QWidget * button = tabWidget()->cornerWidget(TopRight) ) + button->setHidden( noWindows ); + + if ( noWindows ) + setCaption( 0 ); +} + + +void KTechlab::setupActions() +{ + KActionCollection *ac = actionCollection(); + + KStdAction::openNew( this, SLOT(slotFileNew()), ac ); + KStdAction::open( this, SLOT(slotFileOpen()), ac ); + KStdAction::save( this, SLOT(slotFileSave()), ac ); + KStdAction::saveAs( this, SLOT(slotFileSaveAs()), ac ); + KStdAction::close( this, SLOT(slotViewClose()), ac ); + KStdAction::print( this, SLOT(slotFilePrint()), ac ); + KStdAction::quit( this, SLOT(slotFileQuit()), ac ); + KStdAction::undo( this, SLOT(slotEditUndo()), ac ); + KStdAction::redo( this, SLOT(slotEditRedo()), ac ); + KStdAction::cut( this, SLOT(slotEditCut()), ac ); + KStdAction::copy( this, SLOT(slotEditCopy()), ac ); + KStdAction::paste( this, SLOT(slotEditPaste()), ac ); + KStdAction::keyBindings( this, SLOT(slotOptionsConfigureKeys()), ac ); + KStdAction::configureToolbars( this, SLOT(slotOptionsConfigureToolbars()), ac ); + KStdAction::preferences( this, SLOT(slotOptionsPreferences()), ac ); + + //BEGIN New file popup + KToolBarPopupAction *p = new KToolBarPopupAction( i18n("&New"), "filenew", KStdAccel::shortcut(KStdAccel::New), this, SLOT(slotFileNew()), ac, "newfile_popup" ); + p->popupMenu()->insertTitle( i18n("New File") ); + (new KAction( i18n("Assembly"), "source", 0, this, SLOT(slotFileNewAssembly()), ac, "newfile_asm" ))->plug( p->popupMenu() ); + (new KAction( i18n("C source"), "source_c", 0, this, SLOT(slotFileNewC()), ac, "newfile_c" ))->plug( p->popupMenu() ); + (new KAction( i18n("Circuit"), "ktechlab_circuit", 0, this, SLOT(slotFileNewCircuit()), ac, "newfile_circuit" ))->plug( p->popupMenu() ); + (new KAction( i18n("FlowCode"), "ktechlab_flowcode", 0, this, SLOT(slotFileNewFlowCode()), ac, "newfile_flowcode" ))->plug( p->popupMenu() ); +#ifdef MECHANICS + (new KAction( i18n("Mechanics"), "ktechlab_mechanics", 0, this, SLOT(slotFileNewMechanics()), ac, "newfile_mechanics" ))->plug( p->popupMenu() ); +#endif + (new KAction( "Microbe", "ktechlab_microbe", 0, this, SLOT(slotFileNewMicrobe()), ac, "newfile_microbe" ))->plug( p->popupMenu() ); + //END New File popup + + +// m_recentFiles = KStdAction::openRecent( this, SLOT(load(const KURL&)), ac ); + m_recentFiles = new RecentFilesAction( "Recent Files", i18n("Open Recent"), this, SLOT(load(const KURL &)), ac, "file_open_recent" ); + m_statusbarAction = KStdAction::showStatusbar( this, SLOT(slotOptionsShowStatusbar()), ac ); + + //BEGIN Project Actions + ProjectManager *pm = ProjectManager::self(this); + new KAction( i18n("New Project.."), "window_new", 0, pm, SLOT(slotNewProject()), ac, "project_new" ); + new KAction( i18n("Open Project..."), "project_open", 0, pm, SLOT(slotOpenProject()), ac, "project_open" ); +// m_recentProjects = new KRecentFilesAction( i18n("Open &Recent Project..."), 0, ProjectManager::self(), SLOT(slotOpenProject(const KURL&)), ac, "project_open_recent" ); + m_recentProjects = new RecentFilesAction( "Recent Projects", i18n("Open &Recent Project..."), ProjectManager::self(), SLOT(slotOpenProject(const KURL&)), ac, "project_open_recent" ); + new KAction( i18n("Export to Makefile..."), "fileexport", 0, pm, SLOT(slotExportToMakefile()), ac, "project_export_makefile" ); + new KAction( i18n("Create Subproject..."), 0, 0, pm, SLOT(slotCreateSubproject()), ac, "project_create_subproject" ); + new KAction( i18n("Add Existing File..."), "fileopen", 0, pm, SLOT(slotAddFile()), ac, "project_add_existing_file" ); + new KAction( i18n("Add Current File..."), "fileimport", 0, pm, SLOT(slotAddCurrentFile()), ac, "project_add_current_file" ); +// new KAction( i18n("Project Options"), "configure", 0, pm, SLOT(slotProjectOptions()), ac, "project_options" ); + new KAction( i18n("Close Project"), "fileclose", 0, pm, SLOT(slotCloseProject()), ac, "project_close" ); + new KAction( i18n("Remove from Project"), "editdelete", 0, pm, SLOT(slotRemoveSelected()), ac, "project_remove_selected" ); + new KAction( i18n("Insert Existing File..."), "fileopen", 0, pm, SLOT(slotSubprojectAddExistingFile()), ac, "subproject_add_existing_file" ); + new KAction( i18n("Insert Current File..."), "fileimport", 0, pm, SLOT(slotSubprojectAddCurrentFile()),ac, "subproject_add_current_file" ); + new KAction( i18n("Linker Options..."), "configure", 0, pm, SLOT(slotSubprojectLinkerOptions()), ac, "project_item_linker_options" ); + new KAction( i18n("Build..."), "launch", 0, pm, SLOT(slotItemBuild()), ac, "project_item_build" ); + new KAction( i18n("Upload..."), "convert_to_pic", 0, pm, SLOT(slotItemUpload()), ac, "project_item_upload" ); + new KAction( i18n("Processing Options..."), "configure", 0, pm, SLOT(slotItemProcessingOptions()), ac, "project_item_processing_options" ); + //END Project Actions + + new KAction( i18n("Split View Left/Right"), "view_right", Qt::CTRL|Qt::SHIFT|Qt::Key_L, this, SLOT(slotViewSplitLeftRight()), ac, "view_split_leftright" ); + new KAction( i18n("Split View Top/Bottom"), "view_bottom", Qt::CTRL|Qt::SHIFT|Qt::Key_T, this, SLOT(slotViewSplitTopBottom()), ac, "view_split_topbottom" ); + + KToggleAction * ta = new KToggleAction( i18n("Run Simulation"), "player_play", Qt::Key_F10, 0, 0, ac, "simulation_run" ); + ta->setChecked(true); + connect( ta, SIGNAL(toggled(bool )), Simulator::self(), SLOT(slotSetSimulating(bool )) ); +#if defined(KDE_MAKE_VERSION) +# if KDE_VERSION >= KDE_MAKE_VERSION(3,3,0) + ta->setCheckedState( KGuiItem( i18n("Pause Simulation"), "player_pause", 0 ) ); +# endif +#endif + + // We can call slotCloseProject now that the actions have been created + ProjectManager::self(this)->updateActions(); + + DocManager::self(this)->disableContextActions(); +} + + +void KTechlab::slotViewContainerActivated( QWidget * viewContainer ) +{ + if (m_pFocusedContainer) + m_pFocusedContainer->setUnfocused(); + + m_pFocusedContainer = dynamic_cast(viewContainer); + if ( !m_pFocusedContainer ) + return; + + m_pFocusedContainer->setFocused(); +} + + +void KTechlab::slotViewContainerDestroyed( QObject * object ) +{ + m_viewContainerList.remove( static_cast(object) ); + m_viewContainerList.remove( (ViewContainer*)0 ); + slotUpdateTabWidget(); +} + + +void KTechlab::slotTabDragEvent( const QDragMoveEvent *e, bool &accept ) +{ + // Hmm...this function doesn't actually seem to get called. Instead, + // KTabBar just seems to go straight to slotTabDragInitiate. + Q_UNUSED(e); + accept = true; +} + + +void KTechlab::slotTabDragInitiate( QWidget *widget ) +{ + ViewContainer *viewContainer = dynamic_cast(widget); + if (!viewContainer) + return; + QDragObject *dragObject = new ViewContainerDrag(viewContainer); + dragObject->drag(); +} + + +void KTechlab::slotTabReceivedDropEvent( QDropEvent *e ) +{ + if (!e) + return; + ViewContainer *viewContainerSource = dynamic_cast(e->source()); + if (!viewContainerSource) + { + e->ignore(); + return; + } + e->accept(true); + viewContainerSource->duplicateViewContainer(); +} + + +void KTechlab::slotTabReceivedDropEvent( QWidget *widget, QDropEvent *e ) +{ + if (!e) + return; + m_pContainerDropSource = dynamic_cast(e->source()); + m_pContainerDropReceived = dynamic_cast(widget); + if ( !m_pContainerDropSource || !m_pContainerDropReceived || (m_pContainerDropSource == m_pContainerDropReceived) ) + { + e->ignore(); + return; + } + e->accept(true); + + KPopupMenu dropMenu; + dropMenu.insertItem( KGlobal::iconLoader()->loadIcon( "goto", KIcon::Small ), i18n("&Insert Into"), 0 ); + dropMenu.insertItem( KGlobal::iconLoader()->loadIcon( "editcopy", KIcon::Small ), i18n("&Copy Into"), 1 ); + dropMenu.insertSeparator(); + dropMenu.insertItem( KGlobal::iconLoader()->loadIcon( "stop", KIcon::Small ), i18n("C&ancel"), 2 ); + + connect( &dropMenu, SIGNAL(activated(int)), this, SLOT(slotDragContextActivated(int)) ); +// dropMenu.exec(e->pos() + widget->pos() ); + dropMenu.exec( QCursor::pos() ); +} + + +void KTechlab::slotDragContextActivated( int id ) +{ + if ( !m_pContainerDropSource || !m_pContainerDropReceived ) + return; + + switch (id) + { + case 0: + m_pContainerDropSource->copyViewContainerIntoExisting(m_pContainerDropReceived); + m_pContainerDropSource->closeViewContainer(); + break; + case 1: + m_pContainerDropSource->copyViewContainerIntoExisting(m_pContainerDropReceived); + break; + case 2: + default: + break; + } +} + + +KAction * KTechlab::action( const QString & name ) const +{ + KAction * action = actionCollection()->action(name); + if ( !action ) + kdError() << k_funcinfo << "No such action: " << name << endl; + return action; +} + + +void KTechlab::saveProperties( KConfig *conf ) +{ + // Dumbass KMainWindow - can't handle my width/height correctly. Whoever thought of the "+1" hack anyway?! + conf->setGroup("UI"); + conf->writeEntry( "Width", width() ); + conf->writeEntry( "Height", height() ); + conf->writeEntry( "WinState", KWin::windowInfo( winId(), NET::WMState ).state() ); + +#ifndef NO_GPSIM + SymbolViewer::self()->saveProperties( conf ); +#endif + + if ( ProjectManager::self()->currentProject() ) + { + conf->setGroup("Project"); + conf->writePathEntry( "Open", ProjectManager::self()->currentProject()->url().prettyURL() ); + } + else + conf->deleteGroup("Project"); + + //BEGIN Open Views State + // Remvoe old entries describing the save state - we don't want a horrible mish-mash of saved states + const QStringList groupList = conf->groupList(); + const QStringList::const_iterator groupListEnd = groupList.end(); + for ( QStringList::const_iterator it = groupList.begin(); it != groupListEnd; ++it ) + { + if ( (*it).startsWith("ViewContainer") ) + conf->deleteGroup(*it); + } + + uint viewContainerId = 1; + const ViewContainerList::iterator vcEnd = m_viewContainerList.end(); + for ( ViewContainerList::iterator it = m_viewContainerList.begin(); it != vcEnd; ++it ) + { + if ( !(*it) || !(*it)->canSaveUsefulStateInfo() ) + continue; + + // To make sure the ViewContainers are restored in the right order, we must create them in alphabetical order, + // as KConfig stores them as such... + const QString id = QString::number(viewContainerId++).rightJustify( 4, '0' ); + + conf->setGroup( "ViewContainer " + id ); + (*it)->saveState(conf); + } + //END Open Views State + + saveSession( conf, "KateMDI" ); + // Piss off KMainWindow + conf->setGroup("KateMDI"); + int scnum = QApplication::desktop()->screenNumber(parentWidget()); + QRect desk = QApplication::desktop()->screenGeometry(scnum); + conf->deleteEntry( QString::fromLatin1("Width %1").arg(desk.width()) ); + conf->deleteEntry( QString::fromLatin1("Height %1").arg(desk.height()) ); + + conf->sync(); +} + + +void KTechlab::readProperties( KConfig *conf ) +{ + startRestore( conf, "KateMDI" ); + + m_recentFiles->loadEntries(); + m_recentProjects->loadEntries(); + + //BEGIN Restore Open Views + if ( KTLConfig::restoreDocumentsOnStartup() ) + { + // If we have a lot of views open from last time, then opening them will take a long time. + // So we want to enter the qt event loop to finish drawing the window et al before adding the views. + qApp->processEvents(); + + const QStringList groupList = conf->groupList(); + const QStringList::const_iterator groupListEnd = groupList.end(); + for ( QStringList::const_iterator it = groupList.begin(); it != groupListEnd; ++it ) + { + if ( (*it).startsWith("ViewContainer") ) + { + ViewContainer *viewContainer = new ViewContainer( *it, this ); + + conf->setGroup(*it); + viewContainer->restoreState( conf, *it ); + + addWindow( viewContainer ); + } + } + } + //END Restore Open Views + + conf->setGroup("Project"); + if ( conf->readPathEntry("Open") != QString::null ) + ProjectManager::self()->slotOpenProject( KURL( conf->readPathEntry("Open") ) ); + +#ifndef NO_GPSIM + SymbolViewer::self()->readProperties( conf ); +#endif + + finishRestore(); + + // Dumbass KMainWindow - can't handle my width/height correctly. Whoever thought of the "+1" hack anyway?! + conf->setGroup("UI"); + resize( conf->readNumEntry( "Width", 800 ), conf->readNumEntry( "Height", 500 ) ); + KWin::setState( winId(), conf->readLongNumEntry( "WinState", NET::Max ) ); +} + + +void KTechlab::dragEnterEvent(QDragEnterEvent *event) +{ + // accept uri drops only + event->accept(KURLDrag::canDecode(event)); +} + + +void KTechlab::dropEvent(QDropEvent *event) +{ + // this is a very simplistic implementation of a drop event. we + // will only accept a dropped URL. the Qt dnd code can do *much* + // much more, so please read the docs there + KURL::List urls; + + // see if we can decode a URI.. if not, just ignore it + if (KURLDrag::decode(event, urls) && !urls.isEmpty()) + { + // okay, we have a URI.. process it + const KURL &url = urls.first(); + + // load in the file + load(url); + } +} + + +void KTechlab::slotOptionsShowStatusbar() +{ + // this is all very cut and paste code for showing/hiding the + // statusbar + if (m_statusbarAction->isChecked()) + statusBar()->show(); + else + statusBar()->hide(); +} + + +void KTechlab::slotOptionsConfigureKeys() +{ +// KKeyDialog::configureKeys(actionCollection(), "ktechlabui.rc"); + KKeyDialog::configure( actionCollection(), this, true ); +} + + +void KTechlab::slotOptionsConfigureToolbars() +{ + KEditToolbar *dlg = new KEditToolbar(guiFactory()); + + if (dlg->exec()) + { + createShellGUI( false ); + createShellGUI( true ); + } + + delete dlg; +} + + +void KTechlab::slotOptionsPreferences() +{ + // An instance of your dialog could be already created and could be cached, + // in which case you want to display the cached dialog instead of creating + // another one + if ( KConfigDialog::showDialog( "settings" ) ) + return; + + // KConfigDialog didn't find an instance of this dialog, so lets create it: + SettingsDlg* dialog = new SettingsDlg( this, "settings", KTLConfig::self() ); + + // User edited the configuration - update your local copies of the + // configuration data + connect( dialog, SIGNAL(settingsChanged()), this, SLOT(slotUpdateConfiguration()) ); + dialog->show(); +} + + +void KTechlab::slotUpdateConfiguration() +{ + emit configurationChanged(); +} + + +void KTechlab::slotChangeStatusbar( const QString & text ) +{ + // Avoid flicker by repeatedly displaying the same message, as QStatusBar does not check for this + if ( m_lastStatusBarMessage == text ) + return; + + statusBar()->message(text); + m_lastStatusBarMessage = text; +} + + +void KTechlab::slotTabContext( QWidget* widget,const QPoint & pos ) +{ + // Shamelessly stolen from KDevelop... + + KPopupMenu * tabMenu = new KPopupMenu; + tabMenu->insertTitle( (dynamic_cast(widget))->caption() ); + + //Find the document on whose tab the user clicked + m_pContextMenuContainer = 0l; + + m_viewContainerList.remove((ViewContainer*)0l); + + const ViewContainerList::iterator vcEnd = m_viewContainerList.end(); + for ( ViewContainerList::iterator it = m_viewContainerList.begin(); it != vcEnd; ++it ) + { + ViewContainer * viewContainer = *it; + if ( viewContainer == widget ) + { + m_pContextMenuContainer = viewContainer; + + tabMenu->insertItem( i18n("Close"), 0 ); + + View *view = (viewContainer->viewCount() == 1) ? viewContainer->activeView() : 0l; + + if ( view && view->document()->isModified() ) + tabMenu->insertItem( i18n("Save"), 1 ); + + if ( view && !view->document()->url().isEmpty() ) + tabMenu->insertItem( i18n("Reload"), 2 ); + + if ( m_viewContainerList.count() > 1 ) + tabMenu->insertItem( i18n("Close All Others"), 4 ); + + } + } + + connect( tabMenu, SIGNAL( activated(int) ), this, SLOT(slotTabContextActivated(int)) ); + + tabMenu->exec(pos); + delete tabMenu; +} + + +void KTechlab::slotTabContextActivated( int id ) +{ + // Shamelessly stolen from KDevelop... + + if( !m_pContextMenuContainer ) + return; + + View *view = m_pContextMenuContainer->activeView(); + if (!view) + return; + QGuardedPtr document = view->document(); + + switch(id) + { + case 0: + { + m_pContextMenuContainer->closeViewContainer(); + break; + } + case 1: + document->fileSave(); + break; + case 2: + { + KURL url = document->url(); + if ( document->fileClose() ) + { + delete document; + DocManager::self()->openURL(url); + } + break; + } + case 4: + { + const ViewContainerList::iterator vcEnd = m_viewContainerList.end(); + for ( ViewContainerList::iterator it = m_viewContainerList.begin(); it != vcEnd; ++it ) + { + ViewContainer *viewContainer = *it; + if ( viewContainer && viewContainer != m_pContextMenuContainer ) + { + if ( !viewContainer->closeViewContainer() ) + return; + } + } + break; + } + default: + break; + } +} + + + +void KTechlab::slotFileNewAssembly() +{ + TextDocument *document = DocManager::self()->createTextDocument(); + if (document) + document->slotInitLanguage( TextDocument::ct_asm ); +} +void KTechlab::slotFileNewMicrobe() +{ + TextDocument *document = DocManager::self()->createTextDocument(); + if (document) + document->slotInitLanguage( TextDocument::ct_microbe ); +} +void KTechlab::slotFileNewC() +{ + TextDocument *document = DocManager::self()->createTextDocument(); + if (document) + document->slotInitLanguage( TextDocument::ct_c ); +} +void KTechlab::slotFileNewCircuit() +{ + DocManager::self()->createCircuitDocument(); +} +void KTechlab::slotFileNewFlowCode() +{ + slotFileNew(); +} +void KTechlab::slotFileNewMechanics() +{ + DocManager::self()->createMechanicsDocument(); +} + +void KTechlab::slotFileNew() +{ + NewFileDlg *newFileDlg = new NewFileDlg(this); + + newFileDlg->exec(); + + bool addToProject = newFileDlg->addToProject(); + bool accepted = newFileDlg->accepted(); + int finalType = newFileDlg->fileType(); + QString microID = newFileDlg->microID(); + int codeType = newFileDlg->codeType(); + + delete newFileDlg; + if (!accepted) + return; + + Document *created = 0l; + + if ( finalType == Document::dt_circuit ) + created = DocManager::self()->createCircuitDocument(); + + else if ( finalType == Document::dt_flowcode ) + { + FlowCodeDocument * fcd = DocManager::self()->createFlowCodeDocument(); + fcd->setPicType(microID); + created = fcd; + } + + else if ( finalType == Document::dt_mechanics ) + created = DocManager::self()->createMechanicsDocument(); + + else + { + // Presumably a text document + TextDocument * textDocument = DocManager::self()->createTextDocument(); + + if (textDocument) + textDocument->slotInitLanguage( (TextDocument::CodeType)codeType ); + + created = textDocument; + } + + if ( created && addToProject ) + created->setAddToProjectOnSave(true); +} + +void KTechlab::slotFileOpen() +{ + // this slot is called whenever the File->Open menu is selected, + // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar + // button is clicked + + // standard filedialog + KURL::List urls = getFileURLs(); + const KURL::List::iterator end = urls.end(); + for ( KURL::List::iterator it = urls.begin(); it != end; ++ it) + load(*it); +} + +void KTechlab::addRecentFile( const KURL &url ) +{ + m_recentFiles->addURL( url ); + emit recentFileAdded(url); +} + + +KURL::List KTechlab::getFileURLs() +{ + return KFileDialog::getOpenURLs( + QString::null, + "*|All Files\n" + "*.asm *.src *.inc|Assembly Code (*.asm, *.src, *.inc)\n" + "*.hex|Intel Hex (*.hex)\n" + "*.circuit|Circuit (*.circuit)\n" + "*.flowcode|FlowCode (*.flowcode)\n" + "*.basic *.microbe|Microbe (*.microbe, *.basic)\n" + "*.mechanics|Mechanics (*.mechanics)\n", + 0L, + i18n("Open Location") ); +} + + +void KTechlab::slotDocModifiedChanged() +{ + //BEGIN Set tab icons + KIconLoader *loader = KGlobal::iconLoader(); + const ViewContainerList::iterator vcEnd = m_viewContainerList.end(); + for ( ViewContainerList::iterator it = m_viewContainerList.begin(); it != vcEnd; ++it ) + { + ViewContainer * vc = *it; + if ( !vc || !vc->activeView() || !vc->activeView()->document() ) + continue; + + QString iconName; + + if ( vc->activeView()->document()->isModified() ) + iconName = "filesave"; + + else switch ( vc->activeView()->document()->type() ) + { + case Document::dt_circuit: + iconName = "ktechlab_circuit"; + break; + + case Document::dt_flowcode: + iconName = "ktechlab_flowcode"; + break; + + case Document::dt_mechanics: + iconName = "ktechlab_mechanics"; + break; + + case Document::dt_text: + iconName = "txt"; + break; + + case Document::dt_pinMapEditor: + break; + + case Document::dt_none: + iconName = "unknown"; + break; + } + + tabWidget()->setTabIconSet( vc, loader->loadIcon( iconName, KIcon::Small ) ); + } + //END Set tab icons +} + + +void KTechlab::requestUpdateCaptions() +{ + m_pUpdateCaptionsTimer->start( 0, true ); +} + + +void KTechlab::slotUpdateCaptions() +{ + //BEGIN Set KTechlab caption + Document *document = DocManager::self()->getFocusedDocument(); + QString newCaption; + if ( document ) + { + KURL url = document->url(); + if ( url.isEmpty() ) + newCaption = document->caption(); + else + { + if ( url.isLocalFile() && url.ref().isNull() && url.query().isNull() ) + newCaption = url.path(); + else + newCaption = url.prettyURL(); + } + } + else + newCaption = ""; + + if (newCaption != caption().remove(" - KTechlab")) + setCaption(newCaption); + //END Set KTechlab caption + + + //BEGIN Set tab captions + emit needUpdateCaptions(); + + if ( document && document->activeView() && document->activeView()->viewContainer() ) + { + document->activeView()->viewContainer()->updateCaption(); + } + //END Set tab captions +} + + +void KTechlab::slotDocUndoRedoChanged() +{ + Document *document = DocManager::self()->getFocusedDocument(); + if (!document) + return; + + action("edit_undo")->setEnabled( document->isUndoAvailable() ); + action("edit_redo")->setEnabled( document->isRedoAvailable() ); +} + +void KTechlab::slotFileSave() +{ + Document *document = DocManager::self()->getFocusedDocument(); + if (document) + document->fileSave(); +} + +void KTechlab::slotFileSaveAs() +{ + Document *document = DocManager::self()->getFocusedDocument(); + if (document) + document->fileSaveAs(); +} + +void KTechlab::slotFilePrint() +{ + Document *document = DocManager::self()->getFocusedDocument(); + if (document) + document->print(); +} + + +bool KTechlab::queryClose() +{ + saveProperties( KGlobal::config() ); + + if ( DocManager::self()->closeAll() && ProjectManager::self()->slotCloseProject() ) + { + ViewContainerList::iterator end = m_viewContainerList.end(); + for ( ViewContainerList::iterator it = m_viewContainerList.begin(); it != end; ++it ) + { + if ( *it ) + (*it)->setKTechlabDeleted(); + } + + return true; + } + + return false; +} + +void KTechlab::slotFileQuit() +{ + // close the first window, the list makes the next one the first again. + // This ensures that queryClose() is called on each window to ask for closing + KMainWindow* w; + if(memberList) + { + for( w=memberList->first(); w!=0; w=memberList->next() ) + { + // only close the window if the closeEvent is accepted. If the user presses Cancel on the saveModified() dialog, + // the window and the application stay open. + if( !w->close() ) break; + } + } + + slotChangeStatusbar( i18n("Exiting...") ); +} + +void KTechlab::slotEditUndo() +{ + Document *document = DocManager::self()->getFocusedDocument(); + if (document) + document->undo(); +} + +void KTechlab::slotEditRedo() +{ + Document *document = DocManager::self()->getFocusedDocument(); + if (document) + document->redo(); +} + +void KTechlab::slotEditCut() +{ + Document *document = DocManager::self()->getFocusedDocument(); + if (document) + document->cut(); +} + +void KTechlab::slotEditCopy() +{ + Document *document = DocManager::self()->getFocusedDocument(); + if (document) + document->copy(); +} + +void KTechlab::slotEditPaste() +{ + Document *document = DocManager::self()->getFocusedDocument(); + if (document) + document->paste(); +} + +void KTechlab::slotViewContainerClose() +{ + if (m_pFocusedContainer) + m_pFocusedContainer->closeViewContainer(); +} +void KTechlab::slotViewClose() +{ + View *view = DocManager::self()->getFocusedView(); + if (view) + view->closeView(); +} +void KTechlab::slotViewSplitLeftRight() +{ + View *view = DocManager::self()->getFocusedView(); + if (!view) + return; + ViewContainer *vc = view->viewContainer(); + uint vaId = vc->createViewArea( view->viewAreaId(), ViewArea::Right ); + view->document()->createView( vc, vaId ); +} +void KTechlab::slotViewSplitTopBottom() +{ + View *view = DocManager::self()->getFocusedView(); + if (!view) + return; + ViewContainer *vc = view->viewContainer(); + uint vaId = vc->createViewArea( view->viewAreaId(), ViewArea::Bottom ); + view->document()->createView( vc, vaId ); +} + +#include "ktechlab.moc" diff --git a/src/ktechlab.desktop b/src/ktechlab.desktop new file mode 100644 index 0000000..14ccf66 --- /dev/null +++ b/src/ktechlab.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=KTechlab +Exec=ktechlab %i %m -caption "%c" +Icon=ktechlab +Type=Application +DocPath=ktechlab/index.html +Comment=An IDE for microcontrollers and electronics +Terminal=0 +MimeType=application/x-ktechlab;application/x-flowcode;application/x-circuit;application/x-microbe; +Categories=Qt;KDE;Education;Science;Electronics diff --git a/src/ktechlab.h b/src/ktechlab.h new file mode 100644 index 0000000..b69d0c2 --- /dev/null +++ b/src/ktechlab.h @@ -0,0 +1,243 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef KTECHLAB_H +#define KTECHLAB_H + +#include + +class CircuitDocument; +class TextDocument; +class ComponentSelector; +class Document; +class FlowCodeDocument; +class ItemEditor; +class LanguageManager; +class LogView; +class MechanicsDocument; +class ProjectManager; +class View; +class ViewContainer; + +typedef QValueList< QGuardedPtr > ViewContainerList; + +class KAction; +class RecentFilesAction; +class KTabWidget; +class KToolBar; +class KToggleAction; +class KURL; +class QLabel; + +/** + * This class serves as the main window for KTechlab. It handles the + * menus, toolbars, status bars, loading/saving files, config, etc. + * + * @short Main window class + * @author David Saxton + */ +class KTechlab : public KateMDI::MainWindow +{ + Q_OBJECT + public: + KTechlab(); + ~KTechlab(); + + /** + * Returns a pointer to an action with the given name. + */ + KAction * action( const QString & name ) const; + /** + * Returns a URL from a Open File dialog (with all ktechlab related file + * types allowed). + */ + static KURL::List getFileURLs(); + /** + * Returns a list of the recently opened/saved files + */ + QStringList recentFiles(); + /** + * The tab and window captions will get updated when we have re-entered + * the Qt event loop. + */ + void requestUpdateCaptions(); + /** + * Returns the tabwidget that shows the list of view containers. + */ + KTabWidget * tabWidget() const { return m_pViewContainerTabWidget; } + /** + * Registers the viewcontainer with the internal list. + */ + void addWindow( ViewContainer * vc ); + /** + * Removes all gui clients added to the factory other than ourself. + */ + void removeGUIClients(); + /** + * Work around a crash. Adds the given KXMLGUIClient to a list of those + * that ktechlab will not attempt to remove on calling removeGUIClients. + */ + void addNoRemoveGUIClient( KXMLGUIClient * client ); + /** + * For preventing flickering when we are updating the toolbars - grab + * a pixmap of the current toolbars, and overlay it in position. + */ + void overlayToolBarScreenshot(); + + virtual void show(); + + signals: + /** + * Emitted when the user changes the configuration settings in the config dialog + */ + void configurationChanged(); + /** + * Emitted when a recent file is added + */ + void recentFileAdded( const KURL &url ); + /** + * Emitted when ViewContainers should update their captions. + */ + void needUpdateCaptions(); + + public slots: + /** + * The user right clicked on a tab item. + */ + void slotTabContext( QWidget* widget,const QPoint & pos ); + void slotDragContextActivated( int id ); + /** + * The user clicked on an item in the tab-menu (from right clicking). + */ + void slotTabContextActivated( int id ); + void slotChangeStatusbar(const QString& text); + void load(const KURL& url); + void slotUpdateConfiguration(); + /** + * Adds a url to the list of recently opened files + */ + void addRecentFile( const KURL &url ); + /** + * A document had its modified state changed; will update actions, + * tab titles, etc as appropriate. + */ + void slotDocModifiedChanged(); + /** + * A document had its undo/redo state changed; will update actions, + * tab titles, etc as appropriate. + */ + void slotDocUndoRedoChanged(); + + protected: + /** + * Overridden virtuals for Qt drag 'n drop (XDND) + */ + virtual void dragEnterEvent(QDragEnterEvent *event); + virtual void dropEvent(QDropEvent *event); + /** + * This function is called when it is time for the app to save its + * properties for session management purposes. + */ + void saveProperties(KConfig *); + /** + * This function is called when this app is restored. The KConfig + * object points to the session management config file that was saved + * with @ref saveProperties + */ + void readProperties(KConfig *); + /** + * Called before the window is closed, either by the user or indirectly by the session manager. + * This function doesn't actually close the main window; it only queries the user and closes the active view. + * To quit the appliaction completly, you should use KTechlab::slotFileQuit() + */ + virtual bool queryClose(); + + protected slots: + void slotViewContainerActivated( QWidget * viewContainer ); + void slotTabDragEvent( const QDragMoveEvent *e, bool &accept ); + void slotTabDragInitiate( QWidget *widget ); + void slotTabReceivedDropEvent( QDropEvent *e ); + void slotTabReceivedDropEvent( QWidget *widget, QDropEvent *e ); + void slotUpdateTabWidget(); + /** + * Updates the tab and window captions from what is currently open and + * focused. + */ + void slotUpdateCaptions(); + + private slots: + /** + * Called from a QTimer timeout (which should be after the toolbars have + * finished constructing themselves). + */ + void hideToolBarOverlay(); + void slotViewContainerDestroyed( QObject * obj ); + + void slotFileNewAssembly(); + void slotFileNewMicrobe(); + void slotFileNewC(); + void slotFileNewCircuit(); + void slotFileNewFlowCode(); + void slotFileNewMechanics(); + void slotFileNew(); + void slotFileOpen(); + void slotFileSave(); + void slotFileSaveAs(); + void slotFilePrint(); + void slotFileQuit(); + + // Editing operations + void slotEditUndo(); + void slotEditRedo(); + void slotEditCut(); + void slotEditCopy(); + void slotEditPaste(); + + /** + * Split the current view into two + */ + void slotViewSplitLeftRight(); + /** + * Split the current view into two + */ + void slotViewSplitTopBottom(); + void slotViewContainerClose(); + void slotViewClose(); + + void slotOptionsShowStatusbar(); + void slotOptionsConfigureKeys(); + void slotOptionsConfigureToolbars(); + void slotOptionsPreferences(); + + private: + void setupActions(); + void setupToolDocks(); + void setupView(); + void setupTabWidget(); + + RecentFilesAction * m_recentFiles; + RecentFilesAction * m_recentProjects; + KToggleAction * m_statusbarAction; + KTabWidget * m_pViewContainerTabWidget; + QString m_lastStatusBarMessage; + QValueList m_noRemoveGUIClients; + QLabel * m_pToolBarOverlayLabel; + bool m_bIsShown; // Set true when show() is called + ViewContainerList m_viewContainerList; + QTimer * m_pUpdateCaptionsTimer; + + QGuardedPtr m_pContextMenuContainer; + QGuardedPtr m_pFocusedContainer; + QGuardedPtr m_pContainerDropSource; + QGuardedPtr m_pContainerDropReceived; +}; + +#endif // KTECHLAB_H + diff --git a/src/ktechlabcircuitui.rc b/src/ktechlabcircuitui.rc new file mode 100644 index 0000000..a21cb18 --- /dev/null +++ b/src/ktechlabcircuitui.rc @@ -0,0 +1,31 @@ + + + + + &Tools + + + Routing Mode + + + + + + + + + + + + + + + + + + + Item Editor + + + + diff --git a/src/ktechlabflowcodeui.rc b/src/ktechlabflowcodeui.rc new file mode 100644 index 0000000..ea08666 --- /dev/null +++ b/src/ktechlabflowcodeui.rc @@ -0,0 +1,31 @@ + + + + &Tools + + + Routing Mode + + + + + + + + + + + + + + + + + + + + Item Editor + + + + diff --git a/src/ktechlabitemviewui.rc b/src/ktechlabitemviewui.rc new file mode 100644 index 0000000..bcfd6a7 --- /dev/null +++ b/src/ktechlabitemviewui.rc @@ -0,0 +1,38 @@ + + + + + &File + + + + + &Edit + + + + + + + &View + + + + + + + + &Tools + + + + + + + + Tools + + + + + diff --git a/src/ktechlabkateui.rc b/src/ktechlabkateui.rc new file mode 100644 index 0000000..9d901f1 --- /dev/null +++ b/src/ktechlabkateui.rc @@ -0,0 +1,120 @@ + + + + + &File + + + + + + + &Edit + + + + + + + + + + + + + + + &View + + + + + + + + + + + + + + &Code Folding + + + + + + + + + + &Tools + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + &Settings + + + + + + + + + + Main Toolbar + + + + + + diff --git a/src/ktechlabmechanicsui.rc b/src/ktechlabmechanicsui.rc new file mode 100644 index 0000000..a36d2f0 --- /dev/null +++ b/src/ktechlabmechanicsui.rc @@ -0,0 +1,11 @@ + + + + + + + Item Editor + + + + diff --git a/src/ktechlabtextui.rc b/src/ktechlabtextui.rc new file mode 100644 index 0000000..0c35801 --- /dev/null +++ b/src/ktechlabtextui.rc @@ -0,0 +1,96 @@ + + + + + &File + + + + + + + &Tools + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + &Debug + + + + + + + + + + + + + + + + Main Toolbar + + + + + + + + Debugger + + + + + + + diff --git a/src/ktechlabui.rc b/src/ktechlabui.rc new file mode 100644 index 0000000..ade29e5 --- /dev/null +++ b/src/ktechlabui.rc @@ -0,0 +1,135 @@ + + + + + &File + + + + + &View + + + + + + + + &Project + + + + + + + + + + + + + + + + &Tools + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/languages/Makefile.am b/src/languages/Makefile.am new file mode 100644 index 0000000..fef84e7 --- /dev/null +++ b/src/languages/Makefile.am @@ -0,0 +1,14 @@ +INCLUDES = -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/electronics -I$(top_srcdir)/src/electronics/components \ + -I$(top_srcdir)/src/electronics/simulation -I$(top_srcdir)/src/flowparts -I$(top_srcdir)/src/gui \ + -I$(top_srcdir)/src/languages -I$(top_srcdir)/src/mechanics -I$(top_srcdir)/src/micro -Igui \ + $(all_includes) +METASOURCES = AUTO +noinst_LTLIBRARIES = liblanguages.la +liblanguages_la_SOURCES = language.cpp languagemanager.cpp microbe.cpp \ + externallanguage.cpp gpasm.cpp gpdasm.cpp processchain.cpp flowcode.cpp asmparser.cpp \ + sdcc.cpp gplink.cpp gplib.cpp sourceline.cpp picprogrammer.cpp +noinst_HEADERS = externallanguage.h gpasm.h gpdasm.h language.h \ + languagemanager.h microbe.h processchain.h flowcode.h asmparser.h sdcc.h gplink.h gplib.h \ + sourceline.h picprogrammer.h +liblanguages_la_LIBADD = $(top_builddir)/src/gui/libgui.la diff --git a/src/languages/asmparser.cpp b/src/languages/asmparser.cpp new file mode 100644 index 0000000..eb4b7cd --- /dev/null +++ b/src/languages/asmparser.cpp @@ -0,0 +1,150 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "asmparser.h" +#include "config.h" +#include "gpsimprocessor.h" + +#include +#include +#include + +AsmParser::AsmParser( const QString &url ) + : m_url(url) +{ + m_bContainsRadix = false; + m_type = Absolute; +} + + +AsmParser::~AsmParser() +{ +} + + +bool AsmParser::parse( GpsimDebugger * debugger ) +{ + QFile file(m_url); + if ( !file.open(IO_ReadOnly) ) + return false; + + QTextStream stream( &file ); + + m_type = Absolute; + m_bContainsRadix = false; + m_picID = QString::null; + + QStringList nonAbsoluteOps = QStringList::split( ",", + "code,.def,.dim,.direct,endw,extern,.file,global,idata,.ident,.line,.type,udata,udata_acs,udata_ovr,udata_shr" ); + + unsigned inputAtLine = 0; + while ( !stream.atEnd() ) + { + const QString line = stream.readLine().stripWhiteSpace(); + if ( m_type != Relocatable ) + { + QString col0 = line.section( QRegExp("[; ]"), 0, 0 ); + col0 = col0.stripWhiteSpace(); + if ( nonAbsoluteOps.contains(col0) ) + m_type = Relocatable; + } + if ( !m_bContainsRadix ) + { + if ( line.contains( QRegExp("^RADIX[\\s]*") ) || line.contains( QRegExp("^radix[\\s]*") ) ) + m_bContainsRadix = true; + } + if ( m_picID.isEmpty() ) + { + // We look for "list p = ", and "list p = picid ", and subtract the positions / lengths away from each other to get the picid text position + QRegExp fullRegExp("[lL][iI][sS][tT][\\s]+[pP][\\s]*=[\\s]*[\\d\\w]+"); + QRegExp halfRegExp("[lL][iI][sS][tT][\\s]+[pP][\\s]*=[\\s]*"); + + int startPos = fullRegExp.search(line); + if ( (startPos != -1) && (startPos == halfRegExp.search(line)) ) + { + m_picID = line.mid( startPos + halfRegExp.matchedLength(), fullRegExp.matchedLength() - halfRegExp.matchedLength() ); + m_picID = m_picID.upper(); + if ( !m_picID.startsWith("P") ) + m_picID.prepend("P"); + } + } +#ifndef NO_GPSIM + if ( debugger && line.startsWith(";#CSRC\t") ) + { + // Assembly file produced (by sdcc) from C, line is in format: + // ;#CSRC\t[file-name] [file-line] + // The filename can contain spaces. + int fileLineAt = line.findRev(" "); + + if ( fileLineAt == -1 ) + kdWarning() << k_funcinfo << "Syntax error in line \"" << line << "\" while looking for file-line" << endl; + else + { + // 7 = length_of(";#CSRC\t") + QString fileName = line.mid( 7, fileLineAt-7 ); + QString fileLineString = line.mid( fileLineAt+1, line.length() - fileLineAt - 1 ); + + if ( fileName.startsWith("\"") ) + { + // Newer versions of SDCC insert " around the filename + fileName.remove( 0, 1 ); // First " + fileName.remove( fileName.length()-1, 1 ); // Last " + } + + bool ok; + int fileLine = fileLineString.toInt(&ok) - 1; + if ( ok && fileLine >= 0 ) + debugger->associateLine( fileName, fileLine, m_url, inputAtLine ); + else + kdDebug() << k_funcinfo << "Not a valid line number: \"" << fileLineString << "\"" << endl; + } + } + if ( debugger && (line.startsWith(".line\t") || line.startsWith(";#MSRC") ) ) + { + // Assembly file produced by either sdcc or microbe, line is in format: + // \t[".line"/"#MSRC"]\t[file-line]; [file-name]\t[c/microbe source code for that line] + // We're screwed if the file name contains tabs, but hopefully not many do... + QStringList lineParts = QStringList::split( '\t', line ); + if ( lineParts.size() < 2 ) + kdWarning() << k_funcinfo << "Line is in wrong format for extracing source line and file: \""<= 0 ) + debugger->associateLine( fileName, fileLine, m_url, inputAtLine ); + else + kdDebug() << k_funcinfo << "Not a valid line number: \"" << fileLineString << "\"" << endl; + } + } + } +#endif // !NO_GPSIM + inputAtLine++; + } + + return true; +} + diff --git a/src/languages/asmparser.h b/src/languages/asmparser.h new file mode 100644 index 0000000..ab21837 --- /dev/null +++ b/src/languages/asmparser.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef ASMPARSER_H +#define ASMPARSER_H + +#include + +class GpsimDebugger; + +/** +Reads in an assembly file, and extracts useful information from it, such as the +PIC ID + +@author David Saxton +*/ +class AsmParser +{ + public: + AsmParser( const QString &url ); + ~AsmParser(); + + enum Type { Relocatable, Absolute }; + + /** + * Read in data from file, return success status. + * @param debugger if this is non-null, then source-line markers read + * from the assembly file (such as those beginning with ";#CSRC" will be + * passed to hllDebugger). + */ + bool parse( GpsimDebugger * debugger = 0l ); + /** + * Returns the PIC ID + */ + QString picID() const { return m_picID; } + /** + * Returns whether or not the assembly file contained the "set radix" + * directive + */ + bool containsRadix() const { return m_bContainsRadix; } + /** + * If the assembly file contains any of several key words that identify + * it as a relocatable object, then this will return Relocatable. + */ + Type type() const { return m_type; } + + protected: + const QString m_url; + QString m_picID; + bool m_bContainsRadix; + Type m_type; +}; + +#endif diff --git a/src/languages/externallanguage.cpp b/src/languages/externallanguage.cpp new file mode 100644 index 0000000..7297e63 --- /dev/null +++ b/src/languages/externallanguage.cpp @@ -0,0 +1,167 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "externallanguage.h" +#include "languagemanager.h" +#include "logview.h" + +#include +#include +#include +#include + +ExternalLanguage::ExternalLanguage( ProcessChain *processChain, KTechlab *parent, const QString &name ) + : Language( processChain, parent, name ) +{ + m_languageProcess = 0l; +} + + +ExternalLanguage::~ExternalLanguage() +{ + deleteLanguageProcess(); +} + + +void ExternalLanguage::deleteLanguageProcess() +{ + if (!m_languageProcess) + return; + + // I'm not too sure if this combination of killing the process is the best way.... +// m_languageProcess->tryTerminate(); +// QTimer::singleShot( 5000, m_languageProcess, SLOT( kill() ) ); +// delete m_languageProcess; + m_languageProcess->kill(); + m_languageProcess->deleteLater(); + + m_languageProcess = 0L; +} + + +void ExternalLanguage::receivedStdout( KProcess *, char * buffer, int buflen ) +{ + QStringList lines = QStringList::split( '\n', QString::fromLocal8Bit( buffer, buflen ), false ); + QStringList::iterator end = lines.end(); + + for ( QStringList::iterator it = lines.begin(); it != end; ++it ) + { + if ( isError( *it ) ) + { + outputError( *it ); + outputtedError( *it ); + } + else if ( isWarning( *it ) ) + { + outputWarning( *it ); + outputtedWarning( *it ); + } + else + { + outputMessage( *it ); + outputtedMessage( *it ); + } + } +} + + +void ExternalLanguage::receivedStderr( KProcess *, char * buffer, int buflen ) +{ + QStringList lines = QStringList::split( '\n', QString::fromLocal8Bit( buffer, buflen ), false ); + QStringList::iterator end = lines.end(); + + for ( QStringList::iterator it = lines.begin(); it != end; ++it ) + { + if ( isStderrOutputFatal( *it ) ) + { + outputError( *it ); + outputtedError( *it ); + } + else + { + outputWarning( *it ); + outputtedWarning( *it ); + } + } +} + + +void ExternalLanguage::processExited( KProcess * ) +{ + if ( !m_languageProcess ) + return; + bool allOk = processExited( m_languageProcess->normalExit() && m_errorCount == 0 ); + finish(allOk); + deleteLanguageProcess(); +} + + +void ExternalLanguage::processInitFailed() +{ + finish(false); + deleteLanguageProcess(); +} + + +bool ExternalLanguage::start() +{ + displayProcessCommand(); + + return m_languageProcess->start( KProcess::NotifyOnExit, KProcess::All ); +} + + +void ExternalLanguage::resetLanguageProcess() +{ + reset(); + deleteLanguageProcess(); + m_errorCount = 0; + + m_languageProcess = new KProcess(this); + + connect( m_languageProcess, SIGNAL(receivedStdout( KProcess*, char*, int )), + this, SLOT(receivedStdout( KProcess*, char*, int )) ); + + connect( m_languageProcess, SIGNAL(receivedStderr( KProcess*, char*, int )), + this, SLOT(receivedStderr( KProcess*, char*, int )) ); + + connect( m_languageProcess, SIGNAL(processExited( KProcess* )), + this, SLOT(processExited( KProcess* )) ); +} + + +void ExternalLanguage::displayProcessCommand() +{ + QStringList quotedArguments; + QValueList arguments = m_languageProcess->args(); + + if ( arguments.size() == 1 ) + quotedArguments << arguments[0]; + + else + { + QValueList::const_iterator end = arguments.end(); + + for ( QValueList::const_iterator it = arguments.begin(); it != end; ++it ) + { + if ( (*it).isEmpty() || (*it).contains( QRegExp("[\\s]") ) ) + quotedArguments << KProcess::quote( *it ); + else + quotedArguments << *it; + } + } + +// outputMessage( "" + quotedArguments.join(" ") + "" ); + outputMessage( quotedArguments.join(" ") ); +// LanguageManager::self()->logView()->addOutput( quotedArguments.join(" "), LogView::ot_info ); +} + + +#include "externallanguage.moc" diff --git a/src/languages/externallanguage.h b/src/languages/externallanguage.h new file mode 100644 index 0000000..401c2b8 --- /dev/null +++ b/src/languages/externallanguage.h @@ -0,0 +1,97 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef EXTERNALLANGUAGE_H +#define EXTERNALLANGUAGE_H + +#include "language.h" + +class KProcess; + +/** +Base class for Language support that relies on an external program; so this +class provides functionality for dealing with external processes. + +@author Daniel Clarke +@author David Saxton +*/ +class ExternalLanguage : public Language +{ +Q_OBJECT +public: + ExternalLanguage( ProcessChain *processChain, KTechlab *parent, const QString &name ); + ~ExternalLanguage(); + +protected slots: + void receivedStdout( KProcess *, char * buffer, int buflen ); + void receivedStderr( KProcess *, char * buffer, int buflen ); + void processExited( KProcess * ); + +protected: + /** + * Call this to start the language process. ExternalLanguage will ensure + * that communication et all is properly set up. + * @return true on success, false on error + */ + bool start(); + /** + * @returns whether the string outputted to stdout is an error or not + */ + virtual bool isError( const QString &message ) const = 0; + /** + * @returns whether the string outputted to stderr is fatal (stopped compilation) + */ + virtual bool isStderrOutputFatal( const QString & message ) const { Q_UNUSED(message); return true; } + /** + * @returns whether the string outputted to stdout is a warning or not + */ + virtual bool isWarning( const QString &message ) const = 0; + /** + * Called when the process outputs a (non warning/error) message + */ + virtual void outputtedMessage( const QString &/*message*/ ) {}; + /** + * Called when the process outputs a warning + */ + virtual void outputtedWarning( const QString &/*message*/ ) {}; + /** + * Called when the process outputs an error + */ + virtual void outputtedError( const QString &/*message*/ ) {}; + /** + * Called when the process exits (called before any signals are emitted, + * etc). If you reinherit this function, you should return whether + * everything is OK. + */ + virtual bool processExited( bool successfully ) { return successfully; } + /** + * Call this function if your process could not be started - the process + * will be deleted, and a failure signal emitted. + */ + void processInitFailed(); + /** + * Disconnects and deletes the language's process. + */ + void deleteLanguageProcess(); + /** + * Creates process and makes connections, ready for the derived class to + * add arguments and start the process. + */ + void resetLanguageProcess(); + /** + * Prints out the command used for running the process, with any arguments + * that contain spaces put into quotation marks. + */ + void displayProcessCommand(); + + KProcess * m_languageProcess; +}; + +#endif diff --git a/src/languages/flowcode.cpp b/src/languages/flowcode.cpp new file mode 100644 index 0000000..d19d17e --- /dev/null +++ b/src/languages/flowcode.cpp @@ -0,0 +1,496 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "flowcodedocument.h" +#include "flowcode.h" +#include "flowcontainer.h" +#include "flowpart.h" +#include "microsettings.h" +#include "microinfo.h" +#include "micropackage.h" +#include "node.h" +#include "pinmapping.h" + +#include +// #include +#include + +FlowCode::FlowCode( ProcessChain *processChain, KTechlab *parent ) + : Language( processChain, parent, i18n("FlowCode") ) +{ + m_successfulMessage = i18n("*** Microbe generation successful ***"); + m_failedMessage = i18n("*** Microbe generation failed ***"); + p_startPart = 0l; +} + +FlowCode::~FlowCode() +{ +} + + +void FlowCode::processInput( ProcessOptions options ) +{ + m_processOptions = options; + + if ( !options.p_flowCodeDocument ) + { + options.p_flowCodeDocument = new FlowCodeDocument( QString::null, 0l ); + options.p_flowCodeDocument->openURL( options.inputFiles().first() ); + + connect( this, SIGNAL(processSucceeded( Language *)), options.p_flowCodeDocument, SLOT(deleteLater()) ); + connect( this, SIGNAL(processFailed( Language *)), options.p_flowCodeDocument, SLOT(deleteLater()) ); + } + + if ( !options.p_flowCodeDocument->microSettings() ) + { + finish(false); + return; + } + + QFile file(options.intermediaryOutput()); + if ( file.open(IO_WriteOnly | IO_ReadOnly) == false ) + { + finish(false); + return; + } + file.close(); + + if ( file.open(IO_WriteOnly) == false ) + { + finish(false); + return; + } + + const QString code = generateMicrobe( options.p_flowCodeDocument->itemList(), options.p_flowCodeDocument->microSettings() ); + if (code.isEmpty()) + { + finish(false); + return; + } + + QTextStream stream(&file); + stream << code; + file.close(); + finish(true); +} + + +void FlowCode::setStartPart( FlowPart *startPart ) +{ + p_startPart = startPart; +} + + +void FlowCode::addCode( const QString& code ) +{ + m_code += code; + if ( !m_code.endsWith("\n") ) m_code += '\n'; +} + +bool FlowCode::isValidBranch( FlowPart *flowPart ) +{ + return flowPart && (flowPart->level() >= m_curLevel) && !m_stopParts.contains(flowPart); +} + +void FlowCode::addCodeBranch( FlowPart * flowPart ) +{ + if (!flowPart) + return; + + if ( !isValidBranch(flowPart) ) + return; + + if ( m_addedParts.contains(flowPart) ) + { + const QString labelName = genLabel(flowPart->id()); + addCode( "goto "+labelName ); + m_gotos.append(labelName); + return; + } + else + { + m_addedParts.append(flowPart); + int prevLevel = m_curLevel; + m_curLevel = flowPart->level(); + + const QString labelName = genLabel(flowPart->id()); + addCode(labelName+':'); + m_labels.append(labelName); + + flowPart->generateMicrobe(this); + m_curLevel = prevLevel; + } +} + +QString FlowCode::genLabel( const QString &id ) +{ + return "__label_"+id; +} + +void FlowCode::addStopPart( FlowPart *part ) +{ + if (part) m_stopParts.append(part); +} + +void FlowCode::removeStopPart( FlowPart *part ) +{ + if (!part) return; + + // We only want to remove one instance of the FlowPart, in case it has been + // used as a StopPart for more than one FlowPart + FlowPartList::iterator it = m_stopParts.find(part); + if ( it != m_stopParts.end() ) m_stopParts.remove(it); +} + +QString FlowCode::generateMicrobe( const ItemList &itemList, MicroSettings *settings ) +{ + bool foundStart = false; + const ItemList::const_iterator end = itemList.end(); + for ( ItemList::const_iterator it = itemList.begin(); it != end; ++it ) + { + if (!*it) + continue; + + FlowPart * startPart = dynamic_cast((Item*)*it); + + if (!startPart) + continue; + + // Check to see if we have any floating connections + const NodeMap nodeMap = startPart->nodeMap(); + NodeMap::const_iterator nodeMapEnd = nodeMap.end(); + for ( NodeMap::const_iterator nodeMapIt = nodeMap.begin(); nodeMapIt != nodeMapEnd; ++nodeMapIt ) + { + Node * node = nodeMapIt.data().node; + if ( !node || (node->type() != Node::fp_out) ) + continue; + + if ( !startPart->outputPart( nodeMapIt.key() ) ) + outputWarning( i18n("Warning: Floating connection for %1").arg( startPart->id() ) ); + } + + FlowContainer * fc = dynamic_cast((Item*)*it); + + if ( (*it)->id().startsWith("START") && startPart ) + { + foundStart = true; + setStartPart(startPart); + } + else if ( ((*it)->id().startsWith("interrupt") || (*it)->id().startsWith("sub")) && fc ) + { + addSubroutine(fc); + } + } + + if (!foundStart) + { + outputError( i18n("KTechlab was unable to find the \"Start\" part.\nThis must be included as the starting point for your program.") ); + return 0; + } + + m_addedParts.clear(); + m_stopParts.clear(); + m_gotos.clear(); + m_labels.clear(); + m_code = QString::null; + + // PIC type + { + const QString codeString = settings->microInfo()->id() + "\n"; + addCode(codeString); + } + + // Initial variables + { + QStringList vars = settings->variableNames(); + + // If "inited" is true at the end, we comment at the insertion point + bool inited = false; + const QString codeString = "// Initial variable values:\n"; + addCode(codeString); + + const QStringList::iterator end = vars.end(); + for ( QStringList::iterator it = vars.begin(); it != end; ++it ) + { + VariableInfo *info = settings->variableInfo(*it); + if ( info /*&& info->initAtStart*/ ) + { + inited = true; + addCode(*it+" = "+info->valueAsString()); + } + } + if (!inited) { + m_code.remove(codeString); + } else { + addCode("\n"); + } + } + + // Initial pin maps + { + const PinMappingMap pinMappings = settings->pinMappings(); + PinMappingMap::const_iterator end = pinMappings.end(); + for ( PinMappingMap::const_iterator it = pinMappings.begin(); it != end; ++it ) + { + QString type; + + switch ( it.data().type() ) + { + case PinMapping::Keypad_4x3: + case PinMapping::Keypad_4x4: + type = "keypad"; + break; + + case PinMapping::SevenSegment: + type = "sevenseg"; + break; + + case PinMapping::Invalid: + break; + } + + if ( type.isEmpty() ) + continue; + + addCode( QString("%1 %2 %3").arg( type ).arg( it.key() ).arg( it.data().pins().join(" ") ) ); + } + } + + // Initial port settings + { + QStringList portNames = settings->microInfo()->package()->portNames(); + const QStringList::iterator end = portNames.end(); + + // TRIS registers (remember that this is set to ..11111 on all resets) + for ( QStringList::iterator it = portNames.begin(); it != end; ++it ) + { + const int portType = settings->portType(*it); + const int pinCount = settings->microInfo()->package()->pinCount( 0, *it ); + + // We don't need to reset it if portType == 2^(pinCount-1) + if ( portType != (1<level(); + addCodeBranch(p_startPart); + addCode("end"); + + { + const FlowPartList::iterator end = m_subroutines.end(); + for ( FlowPartList::iterator it = m_subroutines.begin(); it != end; ++it ) + { + m_curLevel = 0; + if (*it) + { + addCode("\n"); + addCodeBranch(*it); + } + } + } + + tidyCode(); + return m_code; +} + +void FlowCode::tidyCode() +{ + // First, get rid of the unused labels + const QStringList::iterator end = m_labels.end(); + for ( QStringList::iterator it = m_labels.begin(); it != end; ++it ) + { + if ( !m_gotos.contains(*it) ) m_code.remove(*it+':'); + } + + + // And now on to handling indentation :-) + + if ( !m_code.endsWith("\n") ) m_code.append("\n"); + QString newCode; + bool multiLineComment = false; // For "/*"..."*/" + bool comment = false; // For "//" + bool asmEmbed = false; + bool asmEmbedAllowed = true; + bool asmKeyword = false; + int asmEmbedLevel = -1; + int level = 0; + + int pos=-1; + const int length = m_code.length(); + while ( ++posparentItem() || !dynamic_cast(part) ) return; + m_subroutines.append(part); +} + + +ProcessOptions::ProcessPath::Path FlowCode::outputPath( ProcessOptions::ProcessPath::Path inputPath ) const +{ + switch (inputPath) + { + case ProcessOptions::ProcessPath::FlowCode_AssemblyAbsolute: + return ProcessOptions::ProcessPath::Microbe_AssemblyAbsolute; + + case ProcessOptions::ProcessPath::FlowCode_Microbe: + return ProcessOptions::ProcessPath::None; + + case ProcessOptions::ProcessPath::FlowCode_PIC: + return ProcessOptions::ProcessPath::Microbe_PIC; + + case ProcessOptions::ProcessPath::FlowCode_Program: + return ProcessOptions::ProcessPath::Microbe_Program; + + case ProcessOptions::ProcessPath::AssemblyAbsolute_PIC: + case ProcessOptions::ProcessPath::AssemblyAbsolute_Program: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Library: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Object: + case ProcessOptions::ProcessPath::AssemblyRelocatable_PIC: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Program: + case ProcessOptions::ProcessPath::C_AssemblyRelocatable: + case ProcessOptions::ProcessPath::C_Library: + case ProcessOptions::ProcessPath::C_Object: + case ProcessOptions::ProcessPath::C_PIC: + case ProcessOptions::ProcessPath::C_Program: + case ProcessOptions::ProcessPath::Microbe_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Microbe_PIC: + case ProcessOptions::ProcessPath::Microbe_Program: + case ProcessOptions::ProcessPath::Object_Disassembly: + case ProcessOptions::ProcessPath::Object_Library: + case ProcessOptions::ProcessPath::Object_PIC: + case ProcessOptions::ProcessPath::Object_Program: + case ProcessOptions::ProcessPath::PIC_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Program_Disassembly: + case ProcessOptions::ProcessPath::Program_PIC: + case ProcessOptions::ProcessPath::Invalid: + case ProcessOptions::ProcessPath::None: + return ProcessOptions::ProcessPath::Invalid; + } + + return ProcessOptions::ProcessPath::Invalid; +} + diff --git a/src/languages/flowcode.h b/src/languages/flowcode.h new file mode 100644 index 0000000..afa17db --- /dev/null +++ b/src/languages/flowcode.h @@ -0,0 +1,107 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef FLOWCODE_H +#define FLOWCODE_H + +#include "language.h" + +#include +#include +#include +#include +#include + +class CNItem; +class FlowPart; +class Item; +class MicroSettings; + +typedef QValueList FlowPartList; +typedef QValueList > ItemList; + +/** +"FlowCode" can possibly be considered a misnomer, as the output is actually Microbe. +However, the function of this class is to take a set of FlowParts, and generate the +basic from the code that they create. The 3 simple steps for usage of this function: +(1) Create an instance of this class, giving the Start point and setings +(2) Add all the subroutines present using addSubroutine() +(3) Call generateMicrobe() to get the Microbe code. +@author David Saxton +*/ +class FlowCode : public Language +{ +public: + FlowCode( ProcessChain *processChain, KTechlab *parent ); + + virtual void processInput( ProcessOptions options ); + virtual ProcessOptions::ProcessPath::Path outputPath( ProcessOptions::ProcessPath::Path inputPath ) const; + + /** + * You must set the start part + */ + void setStartPart( FlowPart *startPart ); + ~FlowCode(); + /** + * You must add all top level subroutines using this function + */ + void addSubroutine( FlowPart *part ); + /** + * Adds code at the current insertion point + */ + void addCode( const QString& code ); + /** + * Adds a code branch to the current insertion point. This will stop when the level gets + * below the original starting level (so for insertion of the contents of a for loop, + * insertion will stop at the end of that for loop). + * @param flowPart The next FlowPart to get code from + */ + void addCodeBranch( FlowPart *flowPart ); + /** + * Designates a FlowPart as a stopping part (i.e. will refuse requests to addCodeBranch + * for that FlowPart until removeStopPart is called + */ + void addStopPart( FlowPart *part ); + /** + * Undesignates a FlowPart as a stopping part + */ + void removeStopPart( FlowPart *part ); + /** + * Generates and returns the microbe code + * @param nonVerbal if true then will not inform the user when something goes wrong + */ + QString generateMicrobe( const ItemList &itemList, MicroSettings *settings ); + /** + * Returns true if the FlowPart is a valid one for adding a branch + */ + bool isValidBranch( FlowPart *flowPart ); + /** + * Generates a nice label name from the string, e.g. genLabel("callsub") + * returns "__label_callsub". + */ + static QString genLabel( const QString &id ); + +protected: + /** + * Performs indenting, removal of unnecessary labels, etc. + */ + void tidyCode(); + + QStringList m_gotos; // Gotos used + QStringList m_labels; // Labels used + FlowPartList m_subroutines; + FlowPartList m_addedParts; + FlowPartList m_stopParts; + FlowPart *p_startPart; + QString m_code; + int m_curLevel; +}; + +#endif diff --git a/src/languages/gpasm.cpp b/src/languages/gpasm.cpp new file mode 100644 index 0000000..447354e --- /dev/null +++ b/src/languages/gpasm.cpp @@ -0,0 +1,187 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "asmparser.h" +#include "docmanager.h" +#include "gpasm.h" +#include "logview.h" +#include "languagemanager.h" +#include "src/core/ktlconfig.h" + +#include +#include +#include +#include + +Gpasm::Gpasm( ProcessChain *processChain, KTechlab * parent ) + : ExternalLanguage( processChain, parent, "Gpasm" ) +{ + m_successfulMessage = i18n("*** Assembly successful ***"); + m_failedMessage = i18n("*** Assembly failed ***"); +} + + +Gpasm::~Gpasm() +{ +} + + +void Gpasm::processInput( ProcessOptions options ) +{ + resetLanguageProcess(); + m_processOptions = options; + + AsmParser p( options.inputFiles().first() ); + p.parse(); + + *m_languageProcess << ("gpasm"); + + if ( ProcessOptions::ProcessPath::from( options.processPath() ) == ProcessOptions::ProcessPath::AssemblyRelocatable ) + *m_languageProcess << ("--object"); + +// *m_languageProcess << ("--debug-info"); // Debug info + + // Output filename + *m_languageProcess << ("--output"); + *m_languageProcess << ( options.intermediaryOutput() ); + + if ( !options.m_hexFormat.isEmpty() ) + { + *m_languageProcess << ("--hex-format"); + *m_languageProcess << (options.m_hexFormat); + } + + // Radix + if ( !p.containsRadix() ) + { + *m_languageProcess << ("--radix"); + switch( KTLConfig::radix() ) + { + case KTLConfig::EnumRadix::Binary: + *m_languageProcess << ("BIN"); + break; + case KTLConfig::EnumRadix::Octal: + *m_languageProcess << ("OCT"); + break; + case KTLConfig::EnumRadix::Hexadecimal: + *m_languageProcess << ("HEX"); + break; + case KTLConfig::EnumRadix::Decimal: + default: + *m_languageProcess << ("DEC"); + break; + } + } + + // Warning Level + *m_languageProcess << ("--warning"); + switch( KTLConfig::gpasmWarningLevel() ) + { + case KTLConfig::EnumGpasmWarningLevel::Warnings: + *m_languageProcess << ("1"); + break; + case KTLConfig::EnumGpasmWarningLevel::Errors: + *m_languageProcess << ("2"); + break; + default: + case KTLConfig::EnumGpasmWarningLevel::All: + *m_languageProcess << ("0"); + break; + } + + // Ignore case + if ( KTLConfig::ignoreCase() ) + *m_languageProcess << ("--ignore-case"); + + // Dos formatting + if ( KTLConfig::dosFormat() ) + *m_languageProcess << ("--dos"); + + // Force list + if ( options.b_forceList ) + *m_languageProcess << ("--force-list"); + + // Other options + if ( !KTLConfig::miscGpasmOptions().isEmpty() ) + *m_languageProcess << ( KTLConfig::miscGpasmOptions() ); + + // Input Asm file + *m_languageProcess << ( options.inputFiles().first() ); + + if ( !start() ) + { + KMessageBox::sorry( LanguageManager::self()->logView(), i18n("Assembly failed. Please check you have gputils installed.") ); + processInitFailed(); + return; + } +} + + +bool Gpasm::isError( const QString &message ) const +{ + return message.contains( "Error", false ); +} + + +bool Gpasm::isWarning( const QString &message ) const +{ + return message.contains( "Warning", false ); +} + + +ProcessOptions::ProcessPath::Path Gpasm::outputPath( ProcessOptions::ProcessPath::Path inputPath ) const +{ + switch (inputPath) + { + case ProcessOptions::ProcessPath::AssemblyAbsolute_PIC: + return ProcessOptions::ProcessPath::Program_PIC; + + case ProcessOptions::ProcessPath::AssemblyAbsolute_Program: + return ProcessOptions::ProcessPath::None; + + case ProcessOptions::ProcessPath::AssemblyRelocatable_Library: + return ProcessOptions::ProcessPath::Object_Library; + + case ProcessOptions::ProcessPath::AssemblyRelocatable_Object: + return ProcessOptions::ProcessPath::None; + + case ProcessOptions::ProcessPath::AssemblyRelocatable_PIC: + return ProcessOptions::ProcessPath::Object_PIC; + + case ProcessOptions::ProcessPath::AssemblyRelocatable_Program: + return ProcessOptions::ProcessPath::Object_Program; + + case ProcessOptions::ProcessPath::C_AssemblyRelocatable: + case ProcessOptions::ProcessPath::C_Library: + case ProcessOptions::ProcessPath::C_Object: + case ProcessOptions::ProcessPath::C_PIC: + case ProcessOptions::ProcessPath::C_Program: + case ProcessOptions::ProcessPath::FlowCode_AssemblyAbsolute: + case ProcessOptions::ProcessPath::FlowCode_Microbe: + case ProcessOptions::ProcessPath::FlowCode_PIC: + case ProcessOptions::ProcessPath::FlowCode_Program: + case ProcessOptions::ProcessPath::Microbe_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Microbe_PIC: + case ProcessOptions::ProcessPath::Microbe_Program: + case ProcessOptions::ProcessPath::Object_Disassembly: + case ProcessOptions::ProcessPath::Object_Library: + case ProcessOptions::ProcessPath::Object_PIC: + case ProcessOptions::ProcessPath::Object_Program: + case ProcessOptions::ProcessPath::PIC_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Program_Disassembly: + case ProcessOptions::ProcessPath::Program_PIC: + case ProcessOptions::ProcessPath::Invalid: + case ProcessOptions::ProcessPath::None: + return ProcessOptions::ProcessPath::Invalid; + } + + return ProcessOptions::ProcessPath::Invalid; +} + diff --git a/src/languages/gpasm.h b/src/languages/gpasm.h new file mode 100644 index 0000000..c92a969 --- /dev/null +++ b/src/languages/gpasm.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef GPASM_H +#define GPASM_H + +#include "externallanguage.h" + +/** +@short Interface to the GNU PIC assembler +@author David Saxton +*/ +class Gpasm : public ExternalLanguage +{ + public: + Gpasm( ProcessChain *processChain, KTechlab *parent ); + ~Gpasm(); + + virtual void processInput( ProcessOptions options ); + virtual ProcessOptions::ProcessPath::Path outputPath( ProcessOptions::ProcessPath::Path inputPath ) const; + + protected: + virtual bool isError( const QString &message ) const; + virtual bool isWarning( const QString &message ) const; +}; + +#endif diff --git a/src/languages/gpdasm.cpp b/src/languages/gpdasm.cpp new file mode 100644 index 0000000..8c255d3 --- /dev/null +++ b/src/languages/gpdasm.cpp @@ -0,0 +1,158 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "docmanager.h" +#include "gpdasm.h" +#include "logview.h" +#include "languagemanager.h" + +#include +#include +#include +#include +#include + +Gpdasm::Gpdasm( ProcessChain *processChain, KTechlab *parent ) + : ExternalLanguage( processChain, parent, "Gpdasm" ) +{ + m_successfulMessage = i18n("*** Disassembly successful ***"); + m_failedMessage = i18n("*** Disassembly failed ***"); +} + + +Gpdasm::~Gpdasm() +{ +} + + +void Gpdasm::processInput( ProcessOptions options ) +{ + resetLanguageProcess(); + m_asmOutput = ""; + m_processOptions = options;; + + *m_languageProcess << ("gpdasm"); + + *m_languageProcess << ("--processor"); + *m_languageProcess << ( options.m_picID ); + *m_languageProcess << ( options.inputFiles().first() ); + + if ( !start() ) + { + KMessageBox::sorry( LanguageManager::self()->logView(), i18n("Disassembly failed. Please check you have gputils installed.") ); + processInitFailed(); + return; + } +} + + +void Gpdasm::outputtedMessage( const QString &message ) +{ + m_asmOutput += message + "\n"; +} + + +bool Gpdasm::processExited( bool successfully ) +{ + if (!successfully) + return false; + + QFile file(m_processOptions.intermediaryOutput()); + if ( file.open(IO_WriteOnly) == false ) + return false; + + QTextStream stream(&file); + stream << m_asmOutput; + file.close(); + return true; +} + + +bool Gpdasm::isError( const QString &message ) const +{ + return (message.find( "error", -1, false ) != -1); +} + + +bool Gpdasm::isWarning( const QString &message ) const +{ + return (message.find( "warning", -1, false ) != -1); +} + + +MessageInfo Gpdasm::extractMessageInfo( const QString &text ) +{ + if ( text.length()<5 || !text.startsWith("/") ) + return MessageInfo(); + + const int index = text.find( ".asm", 0, false )+4; + if ( index == -1+4 ) + return MessageInfo(); + const QString fileName = text.left(index); + + // Extra line number + const QString message = text.right(text.length()-index); + const int linePos = message.find( QRegExp(":[\\d]+") ); + int line = -1; + if ( linePos != -1 ) + { + const int linePosEnd = message.find( ':', linePos+1 ); + if ( linePosEnd != -1 ) + { + const QString number = message.mid( linePos+1, linePosEnd-linePos-1 ).stripWhiteSpace(); + bool ok; + line = number.toInt(&ok)-1; + if (!ok) line = -1; + } + } + + return MessageInfo( fileName, line ); +} + + + +ProcessOptions::ProcessPath::Path Gpdasm::outputPath( ProcessOptions::ProcessPath::Path inputPath ) const +{ + switch (inputPath) + { + case ProcessOptions::ProcessPath::Object_Disassembly: + case ProcessOptions::ProcessPath::Program_Disassembly: + return ProcessOptions::ProcessPath::None; + + case ProcessOptions::ProcessPath::AssemblyAbsolute_PIC: + case ProcessOptions::ProcessPath::AssemblyAbsolute_Program: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Library: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Object: + case ProcessOptions::ProcessPath::AssemblyRelocatable_PIC: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Program: + case ProcessOptions::ProcessPath::C_AssemblyRelocatable: + case ProcessOptions::ProcessPath::C_Library: + case ProcessOptions::ProcessPath::C_Object: + case ProcessOptions::ProcessPath::C_PIC: + case ProcessOptions::ProcessPath::C_Program: + case ProcessOptions::ProcessPath::FlowCode_AssemblyAbsolute: + case ProcessOptions::ProcessPath::FlowCode_Microbe: + case ProcessOptions::ProcessPath::FlowCode_PIC: + case ProcessOptions::ProcessPath::FlowCode_Program: + case ProcessOptions::ProcessPath::Microbe_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Microbe_PIC: + case ProcessOptions::ProcessPath::Microbe_Program: + case ProcessOptions::ProcessPath::Object_Library: + case ProcessOptions::ProcessPath::Object_PIC: + case ProcessOptions::ProcessPath::Object_Program: + case ProcessOptions::ProcessPath::PIC_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Program_PIC: + case ProcessOptions::ProcessPath::Invalid: + case ProcessOptions::ProcessPath::None: + return ProcessOptions::ProcessPath::Invalid; + } + + return ProcessOptions::ProcessPath::Invalid; +} diff --git a/src/languages/gpdasm.h b/src/languages/gpdasm.h new file mode 100644 index 0000000..149ed26 --- /dev/null +++ b/src/languages/gpdasm.h @@ -0,0 +1,39 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef GPDASM_H +#define GPDASM_H + +#include + +/** +Interface to the GNU Pic Disassembler +@author David Saxton +*/ +class Gpdasm : public ExternalLanguage +{ +public: + Gpdasm( ProcessChain *processChain, KTechlab *parent ); + ~Gpdasm(); + + virtual void processInput( ProcessOptions options ); + virtual MessageInfo extractMessageInfo( const QString &text ); + virtual ProcessOptions::ProcessPath::Path outputPath( ProcessOptions::ProcessPath::Path inputPath ) const; + +protected: + virtual void outputtedMessage( const QString &message ); + virtual bool isError( const QString &message ) const; + virtual bool isWarning( const QString &message ) const; + virtual bool processExited( bool successfully ); + + QString m_asmOutput; // Outputed by gpdasm +}; + +#endif diff --git a/src/languages/gplib.cpp b/src/languages/gplib.cpp new file mode 100644 index 0000000..db4a32b --- /dev/null +++ b/src/languages/gplib.cpp @@ -0,0 +1,139 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "gplib.h" +#include "languagemanager.h" +#include "logview.h" + +#include +#include +#include + +Gplib::Gplib( ProcessChain *processChain, KTechlab * parent ) + : ExternalLanguage( processChain, parent, "Gpasm" ) +{ + m_successfulMessage = i18n("*** Archiving successful ***"); + m_failedMessage = i18n("*** Archiving failed ***"); +} + + +Gplib::~Gplib() +{ +} + + +void Gplib::processInput( ProcessOptions options ) +{ + resetLanguageProcess(); + m_processOptions = options; + + *m_languageProcess << ("gplib"); + *m_languageProcess << ("--create"); + + *m_languageProcess << ( options.intermediaryOutput() ); + + const QStringList inputFiles = options.inputFiles(); + QStringList::const_iterator end = inputFiles.end(); + for ( QStringList::const_iterator it = inputFiles.begin(); it != end; ++it ) + *m_languageProcess << ( *it ); + + if ( !start() ) + { + KMessageBox::sorry( LanguageManager::self()->logView(), i18n("Linking failed. Please check you have gputils installed.") ); + processInitFailed(); + return; + } +} + + +bool Gplib::isError( const QString &message ) const +{ + return message.contains( "Error", false ); +} + + +bool Gplib::isWarning( const QString &message ) const +{ + return message.contains( "Warning", false ); +} + + +MessageInfo Gplib::extractMessageInfo( const QString &text ) +{ +#if 0 + if ( text.length()<5 || !text.startsWith("/") ) + return MessageInfo(); + + const int index = text.find( ".asm", 0, false )+4; + if ( index == -1+4 ) + return MessageInfo(); + const QString fileName = text.left(index); + + // Extra line number + const QString message = text.right(text.length()-index); + const int linePos = message.find( QRegExp(":[\\d]+") ); + int line = -1; + if ( linePos != -1 ) +{ + const int linePosEnd = message.find( ':', linePos+1 ); + if ( linePosEnd != -1 ) +{ + const QString number = message.mid( linePos+1, linePosEnd-linePos-1 ).stripWhiteSpace(); + bool ok; + line = number.toInt(&ok)-1; + if (!ok) line = -1; +} +} + return MessageInfo( fileName, line ); +#endif + return MessageInfo(); +} + + + + +ProcessOptions::ProcessPath::Path Gplib::outputPath( ProcessOptions::ProcessPath::Path inputPath ) const +{ + switch (inputPath) + { + case ProcessOptions::ProcessPath::Object_Library: + return ProcessOptions::ProcessPath::None; + + case ProcessOptions::ProcessPath::AssemblyAbsolute_PIC: + case ProcessOptions::ProcessPath::AssemblyAbsolute_Program: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Library: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Object: + case ProcessOptions::ProcessPath::AssemblyRelocatable_PIC: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Program: + case ProcessOptions::ProcessPath::C_AssemblyRelocatable: + case ProcessOptions::ProcessPath::C_Library: + case ProcessOptions::ProcessPath::C_Object: + case ProcessOptions::ProcessPath::C_PIC: + case ProcessOptions::ProcessPath::C_Program: + case ProcessOptions::ProcessPath::FlowCode_AssemblyAbsolute: + case ProcessOptions::ProcessPath::FlowCode_Microbe: + case ProcessOptions::ProcessPath::FlowCode_PIC: + case ProcessOptions::ProcessPath::FlowCode_Program: + case ProcessOptions::ProcessPath::Microbe_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Microbe_PIC: + case ProcessOptions::ProcessPath::Microbe_Program: + case ProcessOptions::ProcessPath::Object_Disassembly: + case ProcessOptions::ProcessPath::Object_PIC: + case ProcessOptions::ProcessPath::Object_Program: + case ProcessOptions::ProcessPath::PIC_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Program_Disassembly: + case ProcessOptions::ProcessPath::Program_PIC: + case ProcessOptions::ProcessPath::Invalid: + case ProcessOptions::ProcessPath::None: + return ProcessOptions::ProcessPath::Invalid; + } + + return ProcessOptions::ProcessPath::Invalid; +} diff --git a/src/languages/gplib.h b/src/languages/gplib.h new file mode 100644 index 0000000..35cb1da --- /dev/null +++ b/src/languages/gplib.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef GPLIB_H +#define GPLIB_H + +#include + +/** +@author David Saxton +*/ +class Gplib : public ExternalLanguage +{ + public: + Gplib( ProcessChain *processChain, KTechlab *parent ); + ~Gplib(); + + virtual void processInput( ProcessOptions options ); + virtual MessageInfo extractMessageInfo( const QString &text ); + virtual ProcessOptions::ProcessPath::Path outputPath( ProcessOptions::ProcessPath::Path inputPath ) const; + + protected: + virtual bool isError( const QString &message ) const; + virtual bool isWarning( const QString &message ) const; +}; + +#endif diff --git a/src/languages/gplink.cpp b/src/languages/gplink.cpp new file mode 100644 index 0000000..548449a --- /dev/null +++ b/src/languages/gplink.cpp @@ -0,0 +1,174 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "gplink.h" +#include "languagemanager.h" +#include "logview.h" + +#include +#include +#include + +Gplink::Gplink( ProcessChain *processChain, KTechlab * parent ) + : ExternalLanguage( processChain, parent, "Gpasm" ) +{ + m_successfulMessage = i18n("*** Linking successful ***"); + m_failedMessage = i18n("*** Linking failed ***"); +} + + +Gplink::~Gplink() +{ +} + + +void Gplink::processInput( ProcessOptions options ) +{ + resetLanguageProcess(); + m_processOptions = options; + + *m_languageProcess << ("gplink"); + + if ( !options.m_hexFormat.isEmpty() ) + { + *m_languageProcess << ("--hex-format"); + *m_languageProcess << (options.m_hexFormat); + } + + if ( options.m_bOutputMapFile ) + *m_languageProcess << ("--map"); + + if ( !options.m_libraryDir.isEmpty() ) + { + *m_languageProcess << ("--include"); + *m_languageProcess << ( options.m_libraryDir ); + } + + if ( !options.m_linkerScript.isEmpty() ) + { + *m_languageProcess << ("--script"); + *m_languageProcess << ( options.m_linkerScript ); + } + + if ( !options.m_linkOther.isEmpty() ) + *m_languageProcess << (options.m_linkOther); + + // Output hex file + *m_languageProcess << ("--output"); + *m_languageProcess << ( options.intermediaryOutput() ); + + // Input object file + const QStringList inputFiles = options.inputFiles(); + QStringList::const_iterator end = inputFiles.end(); + for ( QStringList::const_iterator it = inputFiles.begin(); it != end; ++it ) + *m_languageProcess << ( *it ); + + // Other libraries + end = options.m_linkLibraries.end(); + for ( QStringList::const_iterator it = options.m_linkLibraries.begin(); it != end; ++it ) + *m_languageProcess << ( *it ); + + if ( !start() ) + { + KMessageBox::sorry( LanguageManager::self()->logView(), i18n("Linking failed. Please check you have gputils installed.") ); + processInitFailed(); + return; + } +} + + +bool Gplink::isError( const QString &message ) const +{ + return message.contains( "Error", false ); +} + + +bool Gplink::isWarning( const QString &message ) const +{ + return message.contains( "Warning", false ); +} + + +MessageInfo Gplink::extractMessageInfo( const QString &text ) +{ +#if 0 + if ( text.length()<5 || !text.startsWith("/") ) + return MessageInfo(); + + const int index = text.find( ".asm", 0, false )+4; + if ( index == -1+4 ) + return MessageInfo(); + const QString fileName = text.left(index); + + // Extra line number + const QString message = text.right(text.length()-index); + const int linePos = message.find( QRegExp(":[\\d]+") ); + int line = -1; + if ( linePos != -1 ) + { + const int linePosEnd = message.find( ':', linePos+1 ); + if ( linePosEnd != -1 ) + { + const QString number = message.mid( linePos+1, linePosEnd-linePos-1 ).stripWhiteSpace(); + bool ok; + line = number.toInt(&ok)-1; + if (!ok) line = -1; + } + } + return MessageInfo( fileName, line ); +#endif + return MessageInfo(); +} + + + +ProcessOptions::ProcessPath::Path Gplink::outputPath( ProcessOptions::ProcessPath::Path inputPath ) const +{ + switch (inputPath) + { + case ProcessOptions::ProcessPath::Object_PIC: + return ProcessOptions::ProcessPath::Program_PIC; + + case ProcessOptions::ProcessPath::Object_Program: + return ProcessOptions::ProcessPath::None; + + case ProcessOptions::ProcessPath::AssemblyAbsolute_PIC: + case ProcessOptions::ProcessPath::AssemblyAbsolute_Program: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Library: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Object: + case ProcessOptions::ProcessPath::AssemblyRelocatable_PIC: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Program: + case ProcessOptions::ProcessPath::C_AssemblyRelocatable: + case ProcessOptions::ProcessPath::C_Library: + case ProcessOptions::ProcessPath::C_Object: + case ProcessOptions::ProcessPath::C_PIC: + case ProcessOptions::ProcessPath::C_Program: + case ProcessOptions::ProcessPath::FlowCode_AssemblyAbsolute: + case ProcessOptions::ProcessPath::FlowCode_Microbe: + case ProcessOptions::ProcessPath::FlowCode_PIC: + case ProcessOptions::ProcessPath::FlowCode_Program: + case ProcessOptions::ProcessPath::Microbe_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Microbe_PIC: + case ProcessOptions::ProcessPath::Microbe_Program: + case ProcessOptions::ProcessPath::Object_Disassembly: + case ProcessOptions::ProcessPath::Object_Library: + case ProcessOptions::ProcessPath::PIC_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Program_Disassembly: + case ProcessOptions::ProcessPath::Program_PIC: + case ProcessOptions::ProcessPath::Invalid: + case ProcessOptions::ProcessPath::None: + return ProcessOptions::ProcessPath::Invalid; + } + + return ProcessOptions::ProcessPath::Invalid; +} + + + diff --git a/src/languages/gplink.h b/src/languages/gplink.h new file mode 100644 index 0000000..c60f9f9 --- /dev/null +++ b/src/languages/gplink.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef GPLINK_H +#define GPLINK_H + +#include + +/** +@short Interface to the GNU PIC linker +@author David Saxton +*/ +class Gplink : public ExternalLanguage +{ + public: + Gplink( ProcessChain *processChain, KTechlab *parent ); + ~Gplink(); + + virtual void processInput( ProcessOptions options ); + virtual MessageInfo extractMessageInfo( const QString &text ); + virtual ProcessOptions::ProcessPath::Path outputPath( ProcessOptions::ProcessPath::Path inputPath ) const; + + protected: + virtual bool isError( const QString &message ) const; + virtual bool isWarning( const QString &message ) const; +}; + +#endif diff --git a/src/languages/language.cpp b/src/languages/language.cpp new file mode 100644 index 0000000..e7ce759 --- /dev/null +++ b/src/languages/language.cpp @@ -0,0 +1,558 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "asmparser.h" +#include "ktechlab.h" +#include "language.h" +#include "logview.h" +#include "outputmethoddlg.h" +#include "processchain.h" +#include "projectmanager.h" +#include "languagemanager.h" +#include "src/core/ktlconfig.h" + +#include +#include +#include +#include +#include +#include + +//BEGIN class Language +Language::Language( ProcessChain *processChain, KTechlab *parent, const QString &name ) + : QObject(parent,name) +{ + p_ktechlab = parent; + p_processChain = processChain; +} + + +Language::~Language() +{ +} + + +void Language::outputMessage( const QString &message ) +{ + LanguageManager::self()->slotMessage( message, extractMessageInfo(message) ); +} + + +void Language::outputWarning( const QString &message ) +{ + LanguageManager::self()->slotWarning( message, extractMessageInfo(message) ); +} + + +void Language::outputError( const QString &message ) +{ + LanguageManager::self()->slotError( message, extractMessageInfo(message) ); + m_errorCount++; +} + + +void Language::finish( bool successful ) +{ + if (successful) + { + outputMessage(m_successfulMessage + "\n"); + p_ktechlab->slotChangeStatusbar(m_successfulMessage); + + ProcessOptions::ProcessPath::Path newPath = outputPath( m_processOptions.processPath() ); + + if ( newPath == ProcessOptions::ProcessPath::None ) + emit processSucceeded(this); + + else if (p_processChain) + { + m_processOptions.setInputFiles( m_processOptions.intermediaryOutput() ); + m_processOptions.setIntermediaryOutput( m_processOptions.targetFile() ); + m_processOptions.setProcessPath(newPath); +// p_processChain->compile(m_processOptions); + p_processChain->setProcessOptions(m_processOptions); + p_processChain->compile(); + } + } + else + { + outputError(m_failedMessage + "\n"); + p_ktechlab->slotChangeStatusbar(m_failedMessage); + emit processFailed(this); + return; + } +} + + +void Language::reset() +{ + m_errorCount = 0; +} + + +MessageInfo Language::extractMessageInfo( const QString &text ) +{ + if ( !text.startsWith("/") ) + return MessageInfo(); + + const int index = text.find( ":", 0, false ); + if ( index == -1 ) + return MessageInfo(); + const QString fileName = text.left(index); + + // Extra line number + const QString message = text.right(text.length()-index); + const int linePos = message.find( QRegExp(":[\\d]+") ); + int line = -1; + if ( linePos != -1 ) + { + const int linePosEnd = message.find( ':', linePos+1 ); + if ( linePosEnd != -1 ) + { + const QString number = message.mid( linePos+1, linePosEnd-linePos-1 ).stripWhiteSpace(); + bool ok; + line = number.toInt(&ok)-1; + if (!ok) line = -1; + } + } + return MessageInfo( fileName, line ); +} +//END class Language + + + +//BEGIN class ProcessOptionsSpecial +ProcessOptionsSpecial::ProcessOptionsSpecial() +{ + m_bOutputMapFile = true; + b_forceList = true; + b_addToProject = ProjectManager::self()->currentProject(); + + p_flowCodeDocument = 0l; + + switch ( KTLConfig::hexFormat() ) + { + case KTLConfig::EnumHexFormat::inhx8m: + m_hexFormat = "inhx8m"; + break; + + case KTLConfig::EnumHexFormat::inhx8s: + m_hexFormat = "inhx8s"; + break; + + case KTLConfig::EnumHexFormat::inhx16: + m_hexFormat = "inhx16"; + break; + + case KTLConfig::EnumHexFormat::inhx32: + default: + m_hexFormat = "inhx32"; + break; + } +} +//END class ProcessOptionsSpecial + + +//BEGIN class ProcessOptions +ProcessOptions::ProcessOptions() +{ + m_pHelper = new ProcessOptionsHelper; + + b_targetFileSet = false; + m_pTextOutputTarget = 0l; +} + + +ProcessOptions::ProcessOptions( OutputMethodInfo info ) +{ + m_pHelper = new ProcessOptionsHelper; + + b_addToProject = info.addToProject(); + m_picID = info.picID(); + b_targetFileSet = false; + + QString target; + if ( !KIO::NetAccess::download( info.outputFile(), target, 0l ) ) + { + // If the file could not be downloaded, for example does not + // exist on disk, NetAccess will tell us what error to use + KMessageBox::error( 0l, KIO::NetAccess::lastErrorString() ); + + return; + } + setTargetFile(target); + + switch ( info.method() ) + { + case OutputMethodInfo::Method::Direct: + m_method = Method::LoadAsNew; + break; + + case OutputMethodInfo::Method::SaveAndForget: + m_method = Method::Forget; + break; + + case OutputMethodInfo::Method::SaveAndLoad: + m_method = Method::Load; + break; + } +} + + +void ProcessOptions::setTextOutputTarget( TextDocument * target, QObject * receiver, const char * slot ) +{ + m_pTextOutputTarget = target; + QObject::connect( m_pHelper, SIGNAL(textOutputtedTo( TextDocument* )), receiver, slot ); +} + + +void ProcessOptions::setTextOutputtedTo( TextDocument * outputtedTo ) +{ + m_pTextOutputTarget = outputtedTo; + emit m_pHelper->textOutputtedTo( m_pTextOutputTarget ); +} + + +void ProcessOptions::setTargetFile( const QString &file ) +{ + if (b_targetFileSet) + { + kdWarning() << "Trying to reset target file!"< +#include + +class FlowCodeDocument; +class KTechlab; +class LogView; +class MessageInfo; +class MicroSettings; +class OutputMethodInfo; +class ProcessChain; +class ProcessOptions; +class TextDocument; +class QProcess; + +typedef QValueList ProcessOptionsList; + +class ProcessOptionsSpecial +{ + public: + ProcessOptionsSpecial(); + + bool b_addToProject; + bool b_forceList; + QString m_picID; + FlowCodeDocument * p_flowCodeDocument; + + // Linking + QString m_hexFormat; + bool m_bOutputMapFile; + QString m_libraryDir; + QString m_linkerScript; + QStringList m_linkLibraries; + QString m_linkOther; + + // Programming + QString m_port; + QString m_program; +}; + + +class ProcessOptionsHelper : public QObject +{ + Q_OBJECT +#define protected public + signals: +#undef protected + void textOutputtedTo( TextDocument * outputtedTo ); +}; + + +class ProcessOptions : public ProcessOptionsSpecial +{ + public: + ProcessOptions(); + ProcessOptions( OutputMethodInfo info ); + + class ProcessPath { public: + enum MediaType + { + AssemblyAbsolute, + AssemblyRelocatable, + C, + Disassembly, + FlowCode, + Library, + Microbe, + Object, + Pic, + Program, + + Unknown // Used for guessing the media type + }; + + enum Path // From_To // processor that will be invoked first + { + AssemblyAbsolute_PIC, // gpasm (indirect) + AssemblyAbsolute_Program, // gpasm (direct) + + AssemblyRelocatable_Library, // gpasm (indirect) + AssemblyRelocatable_Object, // gpasm (direct) + AssemblyRelocatable_PIC, // gpasm (indirect) + AssemblyRelocatable_Program, // gpasm (indirect) + + C_AssemblyRelocatable, // sdcc (direct) + C_Library, // sdcc (indirect) + C_Object, // sdcc (indirect) + C_PIC, // sdcc (indirect) + C_Program, // sdcc (indirect) + + FlowCode_AssemblyAbsolute, // flowcode (indirect) + FlowCode_Microbe, // flowcode (direct) + FlowCode_PIC, // flowcode (indirect) + FlowCode_Program, // flowcode (indirect) + + Microbe_AssemblyAbsolute, // microbe (direct) + Microbe_PIC, // microbe (indirect) + Microbe_Program, // microbe (indirect) + + Object_Disassembly, // gpdasm (direct) + Object_Library, // gplib (direct) + Object_PIC, // gplink (indirect) + Object_Program, // gplink (direct) + + PIC_AssemblyAbsolute, // download from pic (direct) + + Program_Disassembly, // gpdasm (direct) + Program_PIC, // upload to pic (direct) + + Invalid, // From and to types are incompatible + None // From and to types are the same + }; + + static Path path( MediaType from, MediaType to ); + static MediaType from( Path path ); + static MediaType to( Path path ); + }; + + class Method + { + public: enum type + { + Forget, // Don't do anything after processing successfully + LoadAsNew, // Load the output as a new file + Load // Load the output file + }; + }; + + /** + * Tries to guess the media type from the url (and possible the contents + * of the file as well). + */ + static ProcessPath::MediaType guessMediaType( const QString & url ); + /** + * The *final* target file (not any intermediatary ones) + */ + QString targetFile() const { return m_targetFile; } + /** + * This sets the final target file, as well as the initial intermediatary one + */ + void setTargetFile( const QString &file ); + + void setIntermediaryOutput( const QString &file ) { m_intermediaryFile = file; } + QString intermediaryOutput() const { return m_intermediaryFile; } + + void setInputFiles( const QStringList & files ) { m_inputFiles = files; } + QStringList inputFiles() const { return m_inputFiles; } + + void setMethod( Method::type method ) { m_method = method; } + Method::type method() const { return m_method; } + + void setProcessPath( ProcessPath::Path path ) { m_processPath = path; } + ProcessPath::Path processPath() const { return m_processPath; } + + /** + * If the output is text; If the user has selected (in config options) + * ReuseSameViewForOutput, then the given TextDocument will have its + * text set to the output if the TextDocument is not modified and has + * an empty url. Otherwise a new TextDocument will be created. Either + * way, once the the processing has finished, a signal will be emitted + * to the given receiver passing a TextDocument * as an argument. This + * is not to be confused with setTextOutputtedTo, which is called once + * the processing has finished, and will call-back to the slot given. + */ + void setTextOutputTarget( TextDocument * target, QObject * receiver, const char * slot ); + /** + * @see setTextOutputTarget + */ + TextDocument * textOutputTarget() const { return m_pTextOutputTarget; } + /** + * @see setTextOuputTarget + */ + void setTextOutputtedTo( TextDocument * outputtedTo ); + + protected: + TextDocument * m_pTextOutputTarget; + ProcessOptionsHelper * m_pHelper; + bool b_targetFileSet; + QStringList m_inputFiles; + QString m_targetFile; + QString m_intermediaryFile; + Method::type m_method; + ProcessPath::Path m_processPath; +}; + + +/** +@author Daniel Clarke +@author David Saxton +*/ +class Language : public QObject +{ + Q_OBJECT + public: + Language( ProcessChain *processChain, KTechlab *parent, const QString &name ); + ~Language(); + + /** + * Compile / assemble / dissassembly / whatever the given input. + * @returns true if processing was started succesfully (this is different to finishing successfuly). + */ + virtual void processInput( ProcessOptions options ) = 0; + /** + * Return the ProcessOptions object current state + */ + ProcessOptions processOptions() const { return m_processOptions; } + /** + * Return the output path from the given input path. Will return None + * if we've done processing. + */ + virtual ProcessOptions::ProcessPath::Path outputPath( ProcessOptions::ProcessPath::Path inputPath ) const = 0; + + signals: + /** + * Emitted when the processing was successful. + * @param language Pointer to this class + */ + void processSucceeded( Language *language ); + /** + * Emitted when the processing failed. + * @param language Pointer to this class + */ + void processFailed( Language *language ); + + protected: + /** + * Examines the string for the line number if applicable, and creates a new + * MessageInfo for it. + */ + virtual MessageInfo extractMessageInfo( const QString &text ); + + /** + * Reset the error count + */ + void reset(); + void outputMessage( const QString &message ); + void outputWarning( const QString &message ); + void outputError( const QString &error ); + void finish( bool successful ); + + int m_errorCount; + KTechlab *p_ktechlab; + ProcessOptions m_processOptions; + ProcessChain *p_processChain; + + /** + * A message appropriate to the language's success after compilation or similar. + */ + QString m_successfulMessage; + /** + * A message appropriate to the language's failure after compilation or similar. + */ + QString m_failedMessage; +}; + +#endif diff --git a/src/languages/languagemanager.cpp b/src/languages/languagemanager.cpp new file mode 100644 index 0000000..a6dddd8 --- /dev/null +++ b/src/languages/languagemanager.cpp @@ -0,0 +1,108 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "docmanager.h" +#include "languagemanager.h" +#include "logview.h" +#include "ktechlab.h" +#include "ktempfile.h" +#include "src/core/ktlconfig.h" +#include "outputmethoddlg.h" +#include "processchain.h" +#include "projectmanager.h" + +#include "microbe.h" +#include "gpasm.h" +#include "gpdasm.h" + +#include +#include +#include +#include + +#include + + +LanguageManager * LanguageManager::m_pSelf = 0l; + + +LanguageManager * LanguageManager::self( KateMDI::ToolView * parent, KTechlab * ktl ) +{ + if (!m_pSelf) + { + assert(parent); + assert(ktl); + m_pSelf = new LanguageManager( parent, ktl ); + } + return m_pSelf; +} + + +LanguageManager::LanguageManager( KateMDI::ToolView * parent, KTechlab * ktl ) + : QObject((QObject*)ktl) +{ + p_ktechlab = ktl; + m_logView = new LogView( parent, "LanguageManager LogView"); + + QWhatsThis::add( m_logView, i18n("These messages show the output of language-related functionality such as compiling and assembling.

    For error messages, clicking on the line will automatically open up the file at the position of the error.") ); + connect( m_logView, SIGNAL(paraClicked(const QString&, MessageInfo )), this, SLOT(slotParaClicked(const QString&, MessageInfo )) ); + reset(); +} + + +LanguageManager::~LanguageManager() +{ +} + + +void LanguageManager::reset() +{ + m_logView->clear(); +} + + +ProcessChain * LanguageManager::compile( ProcessOptions options ) +{ + if ( KTLConfig::raiseMessagesLog() ) + p_ktechlab->showToolView( p_ktechlab->toolView( toolViewIdentifier() ) ); + + return new ProcessChain( options, p_ktechlab ); +} + + +ProcessListChain * LanguageManager::compile( ProcessOptionsList pol ) +{ + if ( KTLConfig::raiseMessagesLog() ) + p_ktechlab->showToolView( p_ktechlab->toolView( toolViewIdentifier() ) ); + + return new ProcessListChain( pol, p_ktechlab ); +} + + +void LanguageManager::slotError( const QString &error, MessageInfo messageInfo ) +{ + m_logView->addOutput( error, LogView::ot_error, messageInfo ); +} +void LanguageManager::slotWarning( const QString &error, MessageInfo messageInfo ) +{ + m_logView->addOutput( error, LogView::ot_warning, messageInfo ); +} +void LanguageManager::slotMessage( const QString &error, MessageInfo messageInfo ) +{ + m_logView->addOutput( error, LogView::ot_message, messageInfo ); +} + +void LanguageManager::slotParaClicked( const QString& message, MessageInfo messageInfo ) +{ + Q_UNUSED(message); + DocManager::self()->gotoTextLine( messageInfo.fileURL(), messageInfo.fileLine() ); +} + +#include "languagemanager.moc" diff --git a/src/languages/languagemanager.h b/src/languages/languagemanager.h new file mode 100644 index 0000000..c5bda98 --- /dev/null +++ b/src/languages/languagemanager.h @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef LANGUAGEMANAGER_H +#define LANGUAGEMANAGER_H + +#include +#include + +#include "language.h" + +class FlowCode; +class Gpasm; +class Gpdasm; +class KTechlab; +class Language; +class LanguageManager; +class LogView; +class MessageInfo; +class Microbe; +class ProcessChain; +class ProcessListChain; +class ProcessOptions; +namespace KateMDI { class ToolView; } + +/** +@author David Saxton +*/ +class LanguageManager : public QObject +{ + Q_OBJECT + public: + static LanguageManager * self( KateMDI::ToolView * parent = 0l, KTechlab * ktl = 0l ); + static QString toolViewIdentifier() { return "LanguageManager"; } + ~LanguageManager(); + + /** + * Call to compile a file of one type all the way to another type, this can + * also be used in reverse to disassemble code. Connect to the returned + * ProcessChain for notification of compile success / failure + * @return Pointer to the ProcessChain used to compile + */ + ProcessChain * compile( ProcessOptions options ); + ProcessListChain * compile( ProcessOptionsList pol ); + /** + * @return Pointer to the LogView that displays the output messages + */ + LogView * logView() const { return m_logView; } + /** + * Clear any errors and clear the log view + */ + void reset(); + + public slots: + /** + * Called when the user clicks on any text in the LogView + */ + void slotParaClicked( const QString& message, MessageInfo messageInfo ); + /** + * Called by languages to report an error message + * @param error Error message to report + */ + void slotError( const QString &error, MessageInfo messageInfo ); + /** + * Called by languages to report a warning message + * @param warning Warning message to report + */ + void slotWarning( const QString &warning, MessageInfo messageInfo ); + /** + * Called by languages to report a general message + * @param message General message to report + */ + void slotMessage( const QString &message, MessageInfo messageInfo ); + + protected: + LanguageManager( KateMDI::ToolView * parent, KTechlab * ktl ); + + private: + LogView * m_logView; + static LanguageManager * m_pSelf; + KTechlab * p_ktechlab; +}; + +#endif diff --git a/src/languages/microbe.cpp b/src/languages/microbe.cpp new file mode 100644 index 0000000..628b3c1 --- /dev/null +++ b/src/languages/microbe.cpp @@ -0,0 +1,136 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "contexthelp.h" +#include "docmanager.h" +#include "logview.h" +#include "microbe.h" +#include "languagemanager.h" + +#include +#include +#include +#include + +#include +#include + +Microbe::Microbe( ProcessChain *processChain, KTechlab *parent ) + : ExternalLanguage( processChain, parent, "Microbe" ) +{ + m_failedMessage = i18n("*** Compilation failed ***"); + m_successfulMessage = i18n("*** Compilation successful ***"); + + // Setup error messages list + QFile file( locate("appdata",i18n("error_messages_en_gb")) ); + if ( file.open( IO_ReadOnly ) ) + { + QTextStream stream( &file ); + QString line; + while ( !stream.atEnd() ) + { + line = stream.readLine(); // line of text excluding '\n' + if ( !line.isEmpty() ) + { + bool ok; + const int pos = line.left( line.find("#") ).toInt(&ok); + if (ok) { + m_errorMessages[pos] = line.right(line.length()-line.find("#")); + } else { + kdError() << k_funcinfo << "Error parsing Microbe error-message file"<logView(), i18n("Assembly failed. Please check you have KTechlab installed properly (\"microbe\" could not be started).") ); + processInitFailed(); + return; + } +} + + +bool Microbe::isError( const QString &message ) const +{ + return message.contains( "Error", false ); +} + +bool Microbe::isWarning( const QString &message ) const +{ + return message.contains( "Warning", false ); +} + + +ProcessOptions::ProcessPath::Path Microbe::outputPath( ProcessOptions::ProcessPath::Path inputPath ) const +{ + switch (inputPath) + { + case ProcessOptions::ProcessPath::Microbe_AssemblyAbsolute: + return ProcessOptions::ProcessPath::None; + + case ProcessOptions::ProcessPath::Microbe_PIC: + return ProcessOptions::ProcessPath::AssemblyAbsolute_PIC; + + case ProcessOptions::ProcessPath::Microbe_Program: + return ProcessOptions::ProcessPath::AssemblyAbsolute_Program; + + case ProcessOptions::ProcessPath::AssemblyAbsolute_PIC: + case ProcessOptions::ProcessPath::AssemblyAbsolute_Program: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Library: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Object: + case ProcessOptions::ProcessPath::AssemblyRelocatable_PIC: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Program: + case ProcessOptions::ProcessPath::C_AssemblyRelocatable: + case ProcessOptions::ProcessPath::C_Library: + case ProcessOptions::ProcessPath::C_Object: + case ProcessOptions::ProcessPath::C_PIC: + case ProcessOptions::ProcessPath::C_Program: + case ProcessOptions::ProcessPath::FlowCode_AssemblyAbsolute: + case ProcessOptions::ProcessPath::FlowCode_Microbe: + case ProcessOptions::ProcessPath::FlowCode_PIC: + case ProcessOptions::ProcessPath::FlowCode_Program: + case ProcessOptions::ProcessPath::Object_Disassembly: + case ProcessOptions::ProcessPath::Object_Library: + case ProcessOptions::ProcessPath::Object_PIC: + case ProcessOptions::ProcessPath::Object_Program: + case ProcessOptions::ProcessPath::PIC_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Program_Disassembly: + case ProcessOptions::ProcessPath::Program_PIC: + case ProcessOptions::ProcessPath::Invalid: + case ProcessOptions::ProcessPath::None: + return ProcessOptions::ProcessPath::Invalid; + } + + return ProcessOptions::ProcessPath::Invalid; +} diff --git a/src/languages/microbe.h b/src/languages/microbe.h new file mode 100644 index 0000000..568db4b --- /dev/null +++ b/src/languages/microbe.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef MICROBE_H +#define MICROBE_H + +#include "externallanguage.h" + +#include + +typedef QMap< int, QString > ErrorMap; + +/** +@author Daniel Clarke +@author David Saxton +*/ +class Microbe : public ExternalLanguage +{ +public: + Microbe( ProcessChain *processChain, KTechlab *parent ); + ~Microbe(); + + virtual void processInput( ProcessOptions options ); + virtual ProcessOptions::ProcessPath::Path outputPath( ProcessOptions::ProcessPath::Path inputPath ) const; + +protected: + virtual bool isError( const QString &message ) const; + virtual bool isWarning( const QString &message ) const; + + ErrorMap m_errorMessages; +}; + +#endif diff --git a/src/languages/picprogrammer.cpp b/src/languages/picprogrammer.cpp new file mode 100644 index 0000000..6f5e76f --- /dev/null +++ b/src/languages/picprogrammer.cpp @@ -0,0 +1,456 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "languagemanager.h" +#include "picprogrammer.h" +#include "src/core/ktlconfig.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +//BEGIN class ProgrammerConfig +ProgrammerConfig::ProgrammerConfig() +{ +} + + +void ProgrammerConfig::reset() +{ + initCommand = QString::null; + readCommand = QString::null; + writeCommand = QString::null; + verifyCommand = QString::null; + blankCheckCommand = QString::null; + eraseCommand = QString::null; +} +//END class ProgrammerConfig + + + +//BEGIN class PicProgrammerSettings +bool PicProgrammerSettings::m_bDoneStaticConfigsInit = false; +ProgrammerConfigMap PicProgrammerSettings::m_staticConfigs = ProgrammerConfigMap(); + + +PicProgrammerSettings::PicProgrammerSettings() +{ + if ( !m_bDoneStaticConfigsInit ) + initStaticConfigs(); +} + + +void PicProgrammerSettings::initStaticConfigs() +{ + m_bDoneStaticConfigsInit = true; + ProgrammerConfig config; + + config.description = i18n("Supported programmers: %1").arg("JuPic, PICStart Plus, Warp-13"); + config.description += i18n("
    Interface: Serial Port"); + config.initCommand = ""; + config.readCommand = "picp %port %device -rp %file"; + config.writeCommand = "picp %port %device -wp %file"; + config.verifyCommand = ""; + config.blankCheckCommand = "picp %port %device -b"; + config.eraseCommand = "picp %port %device -e"; +// config.executable = "picp"; + m_staticConfigs[ "PICP" ] = config; + + + config.description = i18n("Supported programmers: %1").arg("Epic Plus"); + config.description += i18n("
    Interface: Parallel Port"); + config.initCommand = "odyssey init"; + config.readCommand = "odyssey %device read %file"; + config.writeCommand = "odyssey %device write %file"; + config.verifyCommand = "odyssey %device verify %file"; + config.blankCheckCommand = "odyssey %device blankcheck"; + config.eraseCommand = "odyssey %device erase"; +// config.executable = "odyssey"; + m_staticConfigs[ "Odyssey" ] = config; + + + config.description = i18n("Supported programmers: %1").arg("JDM PIC-Programmer 2, PIC-PG2C"); + config.description += i18n("
    Interface: Serial Port"); + config.initCommand = ""; + config.readCommand = "picprog --output %file --pic %port"; + config.writeCommand = "picprog --burn --input %file --pic %port --device %device"; + config.verifyCommand = ""; + config.blankCheckCommand = ""; + config.eraseCommand = "picprog --erase --pic %device"; + m_staticConfigs[ "PICProg" ] = config; + + + config.description = i18n("Supported programmers: %1").arg("Epic Plus"); + config.description += i18n("
    Interface: Parallel Port"); + config.initCommand = ""; + config.readCommand = "dump84 --dump-all --output=%file"; + config.writeCommand = "prog84 --intel16=%file"; + config.verifyCommand = ""; + config.blankCheckCommand = ""; + config.eraseCommand = "prog84 --clear"; + m_staticConfigs[ "prog84" ] = config; + + + config.description = i18n("Supported programmers: %1").arg("Kit 149, Kit 150"); + config.description += i18n("
    Interface: USB Port"); + config.initCommand = ""; + config.readCommand = "pp -d %device -r %file"; + config.writeCommand = "pp -d %device -w %file"; + config.verifyCommand = "pp -d %device -v %file"; + config.blankCheckCommand = ""; + config.eraseCommand = "pp -d %device -e"; + m_staticConfigs[ "PP" ] = config; + + + config.description = i18n("Supported programmers: %1").arg("Wisp628"); + config.description += i18n("
    Interface: Serial Port"); + config.initCommand = ""; + config.readCommand = "xwisp ID %device PORT %device DUMP"; + config.writeCommand = "xwisp ID %device PORT %device WRITE %file"; + config.verifyCommand = ""; + config.blankCheckCommand = ""; + config.eraseCommand = "xwisp ID %device PORT %device ERASE"; + m_staticConfigs[ "XWisp" ] = config; + + +#if 0 + config.description = i18n("Supported programmers: %1").arg("Epic Plus, JDM PIC-Programmer 2, PICCOLO, PICCOLO Grande, Trivial HVP Programmer"); + config.description += i18n("
    Interface: Serial Port and Parallel Port"); + config.initCommand = ""; + config.readCommand = ""; + config.writeCommand = ""; + config.verifyCommand = ""; + config.blankCheckCommand = ""; + config.eraseCommand = ""; + config.executable = "pkp"; + m_staticConfigs[ "PiKdev" ] = config; + config.executable = ""; + + + config.description = i18n("Supported programmers: %1").arg("Trivial LVP programmer, Trivial HVP Programmer"); + config.description += i18n("
    Interface: Parallel Port"); + config.initCommand = ""; + config.readCommand = ""; + config.writeCommand = ""; + config.verifyCommand = ""; + config.blankCheckCommand = ""; + config.eraseCommand = ""; + m_staticConfigs[ "PicPrg2" ] = config; + + + config.description = i18n("Supported programmers: %1").arg("El Cheapo"); + config.description += i18n("
    Interface: Parallel Port"); + config.initCommand = ""; + config.readCommand = ""; + config.writeCommand = ""; + config.verifyCommand = ""; + config.blankCheckCommand = ""; + config.eraseCommand = ""; + m_staticConfigs[ "PP06" ] = config; + + + config.description = i18n("Supported programmers: %1").arg("NOPPP"); + config.description += i18n("
    Interface: Parallel Port"); + config.initCommand = ""; + config.readCommand = ""; + config.writeCommand = ""; + config.verifyCommand = ""; + config.blankCheckCommand = ""; + config.eraseCommand = ""; + m_staticConfigs[ "NOPPP" ] = config; + + + config.description = i18n("Supported programmers: %1").arg("SNOPPP"); + config.description += i18n("
    Interface: Parallel Port"); + config.initCommand = ""; + config.readCommand = ""; + config.writeCommand = ""; + config.verifyCommand = ""; + config.blankCheckCommand = ""; + config.eraseCommand = ""; + m_staticConfigs[ "SNOPPP" ] = config; +#endif +} + + +void PicProgrammerSettings::load( KConfig * config ) +{ + QStringList oldCustomProgrammers = config->groupList().grep("CustomProgrammer_"); + QStringList::iterator ocpEnd = oldCustomProgrammers.end(); + for ( QStringList::iterator it = oldCustomProgrammers.begin(); it != ocpEnd; ++it ) + { + // The CustomProgrammer_ string we searched for might appear half way through... (don't want) + if ( (*it).startsWith("CustomProgrammer_") ) + { + config->setGroup(*it); + + ProgrammerConfig pc; + pc.initCommand = config->readEntry( "InitCommand" ); + pc.readCommand = config->readEntry( "ReadCommand" ); + pc.writeCommand = config->readEntry( "WriteCommand" ); + pc.verifyCommand = config->readEntry( "VerifyCommand" ); + pc.blankCheckCommand = config->readEntry( "BlankCheckCommand" ); + pc.eraseCommand = config->readEntry( "EraseCommand" ); + + QString name = config->readEntry( "Name" ); + m_customConfigs[name] = pc; + } + } +} + + +void PicProgrammerSettings::save( KConfig * config ) +{ + QStringList oldCustomProgrammers = config->groupList().grep("CustomProgrammer_"); + QStringList::iterator ocpEnd = oldCustomProgrammers.end(); + for ( QStringList::iterator it = oldCustomProgrammers.begin(); it != ocpEnd; ++it ) + { + // The CustomProgrammer_ string we searched for might appear half way through... (don't want) + if ( (*it).startsWith("CustomProgrammer_") ) + config->deleteGroup(*it); + } + + int at = 0; + ProgrammerConfigMap::iterator end = m_customConfigs.end(); + for ( ProgrammerConfigMap::iterator it = m_customConfigs.begin(); it != end; ++it ) + { + config->setGroup( QString("CustomProgrammer_%1").arg(at++) ); + + config->writeEntry( "Name", it.key() ); + config->writeEntry( "InitCommand", it.data().initCommand ); + config->writeEntry( "ReadCommand", it.data().readCommand ); + config->writeEntry( "WriteCommand", it.data().writeCommand ); + config->writeEntry( "VerifyCommand", it.data().verifyCommand ); + config->writeEntry( "BlankCheckCommand", it.data().blankCheckCommand ); + config->writeEntry( "EraseCommand", it.data().eraseCommand ); + } +} + + +ProgrammerConfig PicProgrammerSettings::config( const QString & name ) +{ + if ( name.isEmpty() ) + return ProgrammerConfig(); + + QString l = name.lower(); + + ProgrammerConfigMap::const_iterator end = m_customConfigs.end(); + for ( ProgrammerConfigMap::const_iterator it = m_customConfigs.begin(); it != end; ++it ) + { + if ( it.key().lower() == l ) + return *it; + } + + end = m_staticConfigs.end(); + for ( ProgrammerConfigMap::const_iterator it = m_staticConfigs.begin(); it != end; ++it ) + { + if ( it.key().lower() == l ) + return *it; + } + + return m_customConfigs[ name ]; +} + + +void PicProgrammerSettings::removeConfig( const QString & name ) +{ + if ( isPredefined( name ) ) + { + kdWarning() << k_funcinfo << "Cannot remove a predefined PIC programmer configuration." << endl; + return; + } + + QString l = name.lower(); + + ProgrammerConfigMap::iterator end = m_customConfigs.end(); + for ( ProgrammerConfigMap::iterator it = m_customConfigs.begin(); it != end; ++it ) + { + if ( it.key().lower() == l ) + { + m_customConfigs.remove( it ); + return; + } + } +} + + +void PicProgrammerSettings::saveConfig( const QString & name, const ProgrammerConfig & config ) +{ + if ( isPredefined( name ) ) + { + kdWarning() << k_funcinfo << "Cannot save to a predefined PIC programmer configuration." << endl; + return; + } + + QString l = name.lower(); + + ProgrammerConfigMap::iterator end = m_customConfigs.end(); + for ( ProgrammerConfigMap::iterator it = m_customConfigs.begin(); it != end; ++it ) + { + if ( it.key().lower() == l ) + { + *it = config; + return; + } + } + + m_customConfigs[ name ] = config; +} + + +QStringList PicProgrammerSettings::configNames( bool makeLowercase ) const +{ + if ( !makeLowercase ) + return m_customConfigs.keys() + m_staticConfigs.keys(); + + QStringList names; + + ProgrammerConfigMap::const_iterator end = m_customConfigs.end(); + for ( ProgrammerConfigMap::const_iterator it = m_customConfigs.begin(); it != end; ++it ) + names << it.key().lower(); + + end = m_staticConfigs.end(); + for ( ProgrammerConfigMap::const_iterator it = m_staticConfigs.begin(); it != end; ++it ) + names << it.key().lower(); + + return names; +} + + +bool PicProgrammerSettings::isPredefined( const QString & name ) const +{ + QString l = name.lower(); + + ProgrammerConfigMap::const_iterator end = m_staticConfigs.end(); + for ( ProgrammerConfigMap::const_iterator it = m_staticConfigs.begin(); it != end; ++it ) + { + if ( it.key().lower() == l ) + return true; + } + + return false; +} +//END class PicProgrammerSettings + + + +//BEGIN class PicProgrammer +PicProgrammer::PicProgrammer( ProcessChain *processChain, KTechlab * parent ) + : ExternalLanguage( processChain, parent, "PicProgrammer" ) +{ + m_successfulMessage = i18n("*** Programming successful ***"); + m_failedMessage = i18n("*** Programming failed ***"); +} + + +PicProgrammer::~PicProgrammer() +{ +} + + +void PicProgrammer::processInput( ProcessOptions options ) +{ + resetLanguageProcess(); + m_processOptions = options; + + PicProgrammerSettings settings; + settings.load( kapp->config() ); + + QString program = options.m_program; + if ( !settings.configNames( true ).contains( program.lower() ) ) + { + kdError() << k_funcinfo << "Invalid program" << endl; + finish( false ); + return; + } + + ProgrammerConfig config = settings.config( program ); + + QString command = config.writeCommand; + command.replace( "%port", options.m_port ); + command.replace( "%device", QString( options.m_picID ).remove("P") ); + command.replace( "%file", KProcess::quote( options.inputFiles().first() ) ); + + m_languageProcess->setUseShell( true ); + *m_languageProcess << command; + + if ( !start() ) + { +// KMessageBox::sorry( LanguageManager::self()->logView(), i18n("Could not program PIC.") ); + processInitFailed(); + return; + } +} + + +bool PicProgrammer::isError( const QString &message ) const +{ + return message.contains( "Error", false ); +} + + +bool PicProgrammer::isWarning( const QString &message ) const +{ + return message.contains( "Warning", false ); +} + + +ProcessOptions::ProcessPath::Path PicProgrammer::outputPath( ProcessOptions::ProcessPath::Path inputPath ) const +{ + switch (inputPath) + { + case ProcessOptions::ProcessPath::PIC_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Program_PIC: + return ProcessOptions::ProcessPath::None; + + case ProcessOptions::ProcessPath::AssemblyAbsolute_PIC: + case ProcessOptions::ProcessPath::AssemblyAbsolute_Program: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Library: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Object: + case ProcessOptions::ProcessPath::AssemblyRelocatable_PIC: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Program: + case ProcessOptions::ProcessPath::C_AssemblyRelocatable: + case ProcessOptions::ProcessPath::C_Library: + case ProcessOptions::ProcessPath::C_Object: + case ProcessOptions::ProcessPath::C_PIC: + case ProcessOptions::ProcessPath::C_Program: + case ProcessOptions::ProcessPath::FlowCode_AssemblyAbsolute: + case ProcessOptions::ProcessPath::FlowCode_Microbe: + case ProcessOptions::ProcessPath::FlowCode_PIC: + case ProcessOptions::ProcessPath::FlowCode_Program: + case ProcessOptions::ProcessPath::Microbe_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Microbe_PIC: + case ProcessOptions::ProcessPath::Microbe_Program: + case ProcessOptions::ProcessPath::Object_Disassembly: + case ProcessOptions::ProcessPath::Object_Library: + case ProcessOptions::ProcessPath::Object_PIC: + case ProcessOptions::ProcessPath::Object_Program: + case ProcessOptions::ProcessPath::Program_Disassembly: + case ProcessOptions::ProcessPath::Invalid: + case ProcessOptions::ProcessPath::None: + return ProcessOptions::ProcessPath::Invalid; + } + + return ProcessOptions::ProcessPath::Invalid; +} +//END class PicProgrammer + + diff --git a/src/languages/picprogrammer.h b/src/languages/picprogrammer.h new file mode 100644 index 0000000..580cf6b --- /dev/null +++ b/src/languages/picprogrammer.h @@ -0,0 +1,127 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PICPROGRAMMER_H +#define PICPROGRAMMER_H + +#include "externallanguage.h" + + +class KConfig; +class KProcess; + + +class ProgrammerConfig +{ + public: + ProgrammerConfig(); + + /** + * Clears the type and all commands. + */ + void reset(); + + QString initCommand; + QString readCommand; + QString writeCommand; + QString verifyCommand; + QString blankCheckCommand; + QString eraseCommand; + + QString description; + QString executable; // The name of the program executable +}; + +typedef QMap< QString, ProgrammerConfig > ProgrammerConfigMap; + + + +/** +This class provides access to the PIC Programmer configurations. Several are +predefinied; the rest can be read from and written to, and removed. Names are +case insensitive. + +Each programmer configuration is in the form of the ProgrammerConfig struct. + +@author David Saxton +*/ +class PicProgrammerSettings +{ + public: + PicProgrammerSettings(); + + /** + * Reads in custom ProgrammerConfigs from config. Any previously loaded + * configurations stored in this class will removed first. + */ + void load( KConfig * config ); + /** + * Saves the custom ProgrammConfigs to config. + */ + void save( KConfig * config ); + /** + * @return the ProgrammConfig for the programmer with the given name. If + * no such ProgrammerConfigs with the given name exist, then one will be + * created. The name is case insensitive (although the full case of the + * name will be stored if a new ProgrammerConfig is created). + */ + ProgrammerConfig config( const QString & name ); + /** + * Removes the config (if it is custom) with the give name. + */ + void removeConfig( const QString & name ); + /** + * Sets the ProgrammerConfig with the given name (or creates one if no + * such config exists). The name is case insensitive. + */ + void saveConfig( const QString & name, const ProgrammerConfig & config ); + /** + * @param makeLowercase whether the names should be converted to + * lowercase before returning. + * @return a list of names of the custom and predefined configs. + */ + QStringList configNames( bool makeLowercase ) const; + /** + * @return whether the given config is predefined. + */ + bool isPredefined( const QString & name ) const; + + protected: + /** + * Called when a PicProgrammerSettings object is first created. Does + * initialization of the predefined configs. + */ + void initStaticConfigs(); + + ProgrammerConfigMap m_customConfigs; + + static bool m_bDoneStaticConfigsInit; + static ProgrammerConfigMap m_staticConfigs; +}; + + +/** +@author David Saxton +*/ +class PicProgrammer : public ExternalLanguage +{ + public: + PicProgrammer( ProcessChain *processChain, KTechlab *parent ); + ~PicProgrammer(); + + virtual void processInput( ProcessOptions options ); + virtual ProcessOptions::ProcessPath::Path outputPath( ProcessOptions::ProcessPath::Path inputPath ) const; + + protected: + virtual bool isError( const QString &message ) const; + virtual bool isWarning( const QString &message ) const; +}; + +#endif diff --git a/src/languages/processchain.cpp b/src/languages/processchain.cpp new file mode 100644 index 0000000..e17c6ae --- /dev/null +++ b/src/languages/processchain.cpp @@ -0,0 +1,326 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "asmparser.h" +#include "docmanager.h" +#include "gplib.h" +#include "src/core/ktlconfig.h" +#include "language.h" +#include "languagemanager.h" +#include "logview.h" +#include "outputmethoddlg.h" +#include "processchain.h" +#include "projectmanager.h" +#include "textdocument.h" + +#include "flowcode.h" +#include "gpasm.h" +#include "gpdasm.h" +#include "gplink.h" +#include "microbe.h" +#include "picprogrammer.h" +#include "sdcc.h" + +#include +#include +#include +#include +#include + + +//BEGIN class ProcessChain +ProcessChain::ProcessChain( ProcessOptions options, KTechlab * ktechlab, const char *name ) + : QObject( (QObject*)ktechlab, name) +{ + m_pKTechlab = ktechlab; + m_pFlowCode = 0l; + m_pGpasm = 0l; + m_pGpdasm = 0l; + m_pGplib = 0l; + m_pGplink = 0l; + m_pMicrobe = 0l; + m_pPicProgrammer = 0l; + m_pSDCC = 0l; + m_processOptions = options; + + QString target; + if ( ProcessOptions::ProcessPath::to( options.processPath() ) == ProcessOptions::ProcessPath::Pic ) + target = options.m_picID; + else + target = options.targetFile(); + + LanguageManager::self()->logView()->addOutput( i18n("Building: %1").arg( target ), LogView::ot_important ); + QTimer::singleShot( 0, this, SLOT(compile()) ); +} + + +ProcessChain::~ProcessChain() +{ + delete m_pFlowCode; + m_pFlowCode = 0l; + delete m_pGpasm; + m_pGpasm = 0l; + delete m_pGpdasm; + m_pGpdasm = 0l; + delete m_pGplib; + m_pGplib = 0l; + delete m_pGplink; + m_pGplink = 0l; + delete m_pMicrobe; + m_pMicrobe = 0l; + delete m_pPicProgrammer; + m_pPicProgrammer = 0l; + delete m_pSDCC; + m_pSDCC = 0l; +} + + +// void ProcessChain::compile( ProcessOptions * options ) +void ProcessChain::compile() +{ + // If the micro id in the options is empty, then attempt to get it from any + // open project (it might not be necessarily...but won't hurt if it isn't). + if ( m_processOptions.m_picID.isEmpty() ) + { + if ( ProjectInfo * projectInfo = ProjectManager::self()->currentProject() ) + { + ProjectItem * projectItem = projectInfo->findItem( m_processOptions.inputFiles().first() ); + if (projectItem) + m_processOptions.m_picID = projectItem->microID(); + } + } + + switch ( m_processOptions.processPath() ) + { +#define DIRECT_PROCESS( path, processor ) case ProcessOptions::ProcessPath::path: { processor()->processInput(m_processOptions); break; } +#define INDIRECT_PROCESS( path, processor, extension ) case ProcessOptions::ProcessPath::path: { KTempFile f( QString::null, extension ); f.close(); m_processOptions.setIntermediaryOutput( f.name() ); processor()->processInput(m_processOptions); break; } + + INDIRECT_PROCESS( AssemblyAbsolute_PIC, gpasm, ".hex" ) + DIRECT_PROCESS( AssemblyAbsolute_Program, gpasm ) + INDIRECT_PROCESS( AssemblyRelocatable_Library, gpasm, ".o" ) + DIRECT_PROCESS( AssemblyRelocatable_Object, gpasm ) + INDIRECT_PROCESS( AssemblyRelocatable_PIC, gpasm, ".o" ) + INDIRECT_PROCESS( AssemblyRelocatable_Program, gpasm, ".o" ) + DIRECT_PROCESS( C_AssemblyRelocatable, sdcc ) + INDIRECT_PROCESS( C_Library, sdcc, ".asm" ) + INDIRECT_PROCESS( C_Object, sdcc, ".asm" ) + INDIRECT_PROCESS( C_PIC, sdcc, ".asm" ) + INDIRECT_PROCESS( C_Program, sdcc, ".asm" ) + INDIRECT_PROCESS( FlowCode_AssemblyAbsolute, flowCode, ".microbe" ) + DIRECT_PROCESS( FlowCode_Microbe, flowCode ) + INDIRECT_PROCESS( FlowCode_PIC, flowCode, ".microbe" ) + INDIRECT_PROCESS( FlowCode_Program, flowCode, ".microbe" ) + DIRECT_PROCESS( Microbe_AssemblyAbsolute, microbe ) + INDIRECT_PROCESS( Microbe_PIC, microbe, ".asm" ) + INDIRECT_PROCESS( Microbe_Program, microbe, ".asm" ) + DIRECT_PROCESS( Object_Disassembly, gpdasm ) + DIRECT_PROCESS( Object_Library, gplib ) + INDIRECT_PROCESS( Object_PIC, gplink, ".lib" ) + DIRECT_PROCESS( Object_Program, gplink ) + DIRECT_PROCESS( PIC_AssemblyAbsolute, picProgrammer ) + DIRECT_PROCESS( Program_Disassembly, gpdasm ) + DIRECT_PROCESS( Program_PIC, picProgrammer ) +#undef DIRECT_PROCESS +#undef INDIRECT_PROCESS + + case ProcessOptions::ProcessPath::Invalid: + kdWarning() << k_funcinfo << "Process path is invalid" << endl; + + case ProcessOptions::ProcessPath::None: + kdWarning() << k_funcinfo << "Nothing to do" << endl; + break; + } +} + + +void ProcessChain::slotFinishedCompile(Language *language) +{ + ProcessOptions options = language->processOptions(); + + if ( options.b_addToProject && ProjectManager::self()->currentProject() ) + ProjectManager::self()->currentProject()->addFile( KURL(options.targetFile()) ); + + ProcessOptions::ProcessPath::MediaType typeTo = ProcessOptions::ProcessPath::to( m_processOptions.processPath() ); + + TextDocument * editor = 0l; + if ( KTLConfig::reuseSameViewForOutput() ) + { + editor = options.textOutputTarget(); + if ( editor && (!editor->url().isEmpty() || editor->isModified()) ) + editor = 0l; + } + + switch (typeTo) + { + case ProcessOptions::ProcessPath::AssemblyAbsolute: + case ProcessOptions::ProcessPath::AssemblyRelocatable: + case ProcessOptions::ProcessPath::C: + case ProcessOptions::ProcessPath::Disassembly: + case ProcessOptions::ProcessPath::Library: + case ProcessOptions::ProcessPath::Microbe: + case ProcessOptions::ProcessPath::Object: + case ProcessOptions::ProcessPath::Program: + { + switch ( options.method() ) + { + case ProcessOptions::Method::LoadAsNew: + { + if ( !editor ) + editor = DocManager::self()->createTextDocument(); + + if ( !editor ) + break; + + QString text; + QFile f( options.targetFile() ); + if ( !f.open( IO_ReadOnly ) ) + { + editor->deleteLater(); + editor = 0l; + break; + } + + QTextStream stream(&f); + + while ( !stream.atEnd() ) + text += stream.readLine()+'\n'; + + f.close(); + + editor->setText( text, true ); + break; + } + + case ProcessOptions::Method::Load: + { + editor = dynamic_cast( DocManager::self()->openURL(options.targetFile()) ); + break; + } + + case ProcessOptions::Method::Forget: + break; + } + } + + case ProcessOptions::ProcessPath::FlowCode: + case ProcessOptions::ProcessPath::Pic: + case ProcessOptions::ProcessPath::Unknown: + break; + } + + + if (editor) + { + switch (typeTo) + { + case ProcessOptions::ProcessPath::AssemblyAbsolute: + case ProcessOptions::ProcessPath::AssemblyRelocatable: + { + if ( KTLConfig::autoFormatMBOutput() ) + editor->formatAssembly(); + editor->slotInitLanguage( TextDocument::ct_asm ); + break; + } + + case ProcessOptions::ProcessPath::C: + editor->slotInitLanguage( TextDocument::ct_c ); + break; + + case ProcessOptions::ProcessPath::Disassembly: + break; + + case ProcessOptions::ProcessPath::Library: + case ProcessOptions::ProcessPath::Object: + case ProcessOptions::ProcessPath::Program: + editor->slotInitLanguage( TextDocument::ct_hex ); + break; + + case ProcessOptions::ProcessPath::Microbe: + editor->slotInitLanguage( TextDocument::ct_microbe ); + break; + + case ProcessOptions::ProcessPath::FlowCode: + case ProcessOptions::ProcessPath::Pic: + case ProcessOptions::ProcessPath::Unknown: + break; + } + + DocManager::self()->giveDocumentFocus( editor ); + } + + options.setTextOutputtedTo( editor ); + + emit successful(options); + emit successful(); +} + +#define LanguageFunction(a,b,c) \ +a * ProcessChain::b( ) \ +{ \ + if ( !c ) \ + { \ + c = new a( this, m_pKTechlab ); \ + connect( c, SIGNAL(processSucceeded(Language* )), this, SLOT(slotFinishedCompile(Language* )) ); \ + connect( c, SIGNAL(processFailed(Language* )), this, SIGNAL(failed()) ); \ + } \ + return c; \ +} + +LanguageFunction( FlowCode, flowCode, m_pFlowCode ) +LanguageFunction( Gpasm, gpasm, m_pGpasm ) +LanguageFunction( Gpdasm, gpdasm, m_pGpdasm ) +LanguageFunction( Gplib, gplib, m_pGplib ) +LanguageFunction( Gplink, gplink, m_pGplink ) +LanguageFunction( Microbe, microbe, m_pMicrobe ) +LanguageFunction( PicProgrammer, picProgrammer, m_pPicProgrammer ) +LanguageFunction( SDCC, sdcc, m_pSDCC ) +//END class ProcessChain + + + +//BEGIN class ProcessListChain +ProcessListChain::ProcessListChain( ProcessOptionsList pol, KTechlab * parent, const char * name ) + : QObject( (QObject*)parent, name ) +{ + m_processOptionsList = pol; + m_pKTechlab = parent; + + // Start us off... + slotProcessChainSuccessful(); +} + + +void ProcessListChain::slotProcessChainSuccessful() +{ + if ( m_processOptionsList.isEmpty() ) + { + emit successful(); + return; + } + + ProcessOptionsList::iterator it = m_processOptionsList.begin(); + ProcessOptions po = *it; + m_processOptionsList.remove(it); + + ProcessChain * pc = LanguageManager::self()->compile(po); + + connect( pc, SIGNAL(successful()), this, SLOT(slotProcessChainSuccessful()) ); + connect( pc, SIGNAL(failed()), this, SLOT(slotProcessChainFailed()) ); +} + + +void ProcessListChain::slotProcessChainFailed() +{ + emit failed(); +} +//END class ProcessListChain + + +#include "processchain.moc" diff --git a/src/languages/processchain.h b/src/languages/processchain.h new file mode 100644 index 0000000..90b871e --- /dev/null +++ b/src/languages/processchain.h @@ -0,0 +1,127 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PROCESSCHAIN_H +#define PROCESSCHAIN_H + +#include "language.h" +#include +#include + +class FlowCode; +class Gpasm; +class Gpdasm; +class Gplib; +class Gplink; +class KTechlab; +class Microbe; +class PicProgrammer; +class ProcesOptions; +class SDCC; + +typedef QValueList ProcessOptionsList; + +/** +@author Daniel Clarke +@author David Saxton +*/ +class ProcessChain : public QObject +{ + Q_OBJECT + public: + ProcessChain( ProcessOptions options, KTechlab *parent, const char *name = 0l ); + ~ProcessChain(); + + void setProcessOptions( ProcessOptions options ) { m_processOptions = options; } + + public slots: + /** + * Adds the output file to project if requested in the options, and opens + * the file in a code editor. Called to signal that a language in the last + * step of a compile has finished its compiling successfully. + */ + void slotFinishedCompile( Language * language ); + /** + * Call to compile a file of one type all the way to another type. This + * uses the ProcessOptions given in the constructor of this function, or + * later in setProcessOptions. + */ + void compile(); + + signals: + /** + * Emitted when compiling has successfully gone all the way through to the + * specified 'typeTo' + * @param options The ProcessOptions holding the output filename + * @see compile + */ + void successful(ProcessOptions options); + /** + * Convenience signal + */ + void successful(); + /** + * Emitted if not successful + */ + void failed(); + + protected: + FlowCode * flowCode(); + Gpasm * gpasm(); + Gpdasm * gpdasm(); + Gplib * gplib(); + Gplink * gplink(); + Microbe * microbe(); + PicProgrammer * picProgrammer(); + SDCC * sdcc(); + + int m_errorCount; + ProcessOptions m_processOptions; + KTechlab * m_pKTechlab; + + private: + FlowCode * m_pFlowCode; + Microbe * m_pMicrobe; + Gpasm * m_pGpasm; + Gpdasm * m_pGpdasm; + Gplib * m_pGplib; + Gplink * m_pGplink; + PicProgrammer * m_pPicProgrammer; + SDCC * m_pSDCC; +}; + + +class ProcessListChain : public QObject +{ + Q_OBJECT + + public: + ProcessListChain( ProcessOptionsList pol, KTechlab *parent, const char *name = 0l ); + + signals: + /** + * Emitted if successful + */ + void successful(); + /** + * Emitted if not successful + */ + void failed(); + + protected slots: + void slotProcessChainSuccessful(); + void slotProcessChainFailed(); + + protected: + ProcessOptionsList m_processOptionsList; + KTechlab * m_pKTechlab; +}; + +#endif diff --git a/src/languages/sdcc.cpp b/src/languages/sdcc.cpp new file mode 100644 index 0000000..553e974 --- /dev/null +++ b/src/languages/sdcc.cpp @@ -0,0 +1,205 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "asminfo.h" +#include "languagemanager.h" +#include "logview.h" +#include "microinfo.h" +#include "microlibrary.h" +#include "sdcc.h" +#include "src/core/ktlconfig.h" + +#include +#include +#include + +SDCC::SDCC( ProcessChain * processChain, KTechlab * parent ) + : ExternalLanguage( processChain, parent, "SDCC" ) +{ + m_successfulMessage = i18n("*** Compilation successful ***"); + m_failedMessage = i18n("*** Compilation failed ***"); +} + + +SDCC::~SDCC() +{ +} + + +void SDCC::processInput( ProcessOptions options ) +{ + resetLanguageProcess(); + + MicroInfo * info = MicroLibrary::self()->microInfoWithID( options.m_picID ); + if (!info) + { + outputError( i18n("Could not find PIC with ID \"%1\".").arg(options.m_picID) ); + return; + } + + m_processOptions = options; + + *m_languageProcess << ("sdcc"); + + + //BEGIN Pass custom sdcc options +#define ARG(text,option) if ( KTLConfig::text() ) *m_languageProcess << ( QString("--%1").arg(option) ); + // General + ARG( sDCC_nostdlib, "nostdlib" ) + ARG( sDCC_nostdinc, "nostdinc" ) + ARG( sDCC_less_pedantic, "less-pedantic" ) + ARG( sDCC_std_c89, "std-c89" ) + ARG( sDCC_std_c99, "std-c99" ) + + // Code generation + ARG( sDCC_stack_auto, "stack-auto" ) + ARG( sDCC_int_long_reent, "int-long-reent" ) + ARG( sDCC_float_reent, "float-reent" ) + ARG( sDCC_fommit_frame_pointer, "fommit-frame-pointer" ) + ARG( sDCC_no_xinit_opt, "no-xinit-opt" ) + ARG( sDCC_all_callee_saves, "all-callee-saves" ) + + // Optimization + ARG( sDCC_nooverlay, "nooverlay" ) + ARG( sDCC_nogcse, "nogcse" ) + ARG( sDCC_nolabelopt, "nolabelopt" ) + ARG( sDCC_noinvariant, "noinvariant" ) + ARG( sDCC_noinduction, "noinduction" ) + ARG( sDCC_no_peep, "no-peep" ) + ARG( sDCC_noloopreverse, "noloopreverse" ) + ARG( sDCC_opt_code_size, "opt-code-size" ) + ARG( sDCC_opt_code_speed, "opt-code-speed" ) + ARG( sDCC_peep_asm, "peep-asm" ) + ARG( sDCC_nojtbound, "nojtbound" ) + + // PIC16 Specific + if ( info->instructionSet()->set() == AsmInfo::PIC16 ) + { + ARG( sDCC_nodefaultlibs, "nodefaultlibs" ) + ARG( sDCC_pno_banksel, "pno-banksel" ) + ARG( sDCC_pstack_model_large, "pstack-model=large" ) + ARG( sDCC_debug_xtra, "debug-xtra" ) + ARG( sDCC_denable_peeps, "denable-peeps" ) + ARG( sDCC_calltree, "calltree" ) + ARG( sDCC_fstack, "fstack" ) + ARG( sDCC_optimize_goto, "optimize-goto" ) + ARG( sDCC_optimize_cmp, "optimize-cmp" ) + ARG( sDCC_optimize_df, "optimize-df" ) + } +#undef ARG + + if ( !KTLConfig::miscSDCCOptions().isEmpty() ) + *m_languageProcess << ( KTLConfig::miscSDCCOptions() ); + //END Pass custom sdcc options + + + *m_languageProcess << ("--debug"); // Enable debugging symbol output + *m_languageProcess << ("-S"); // Compile only; do not assemble or link + + QString asmSwitch; + switch ( info->instructionSet()->set() ) + { + case AsmInfo::PIC12: + // Last time I checked, SDCC doesn't support Pic12, and probably never will, but whatever... + asmSwitch = "-mpic12"; + break; + case AsmInfo::PIC14: + asmSwitch = "-mpic14"; + break; + case AsmInfo::PIC16: + asmSwitch = "-mpic16"; + break; + } + + *m_languageProcess << (asmSwitch); + + *m_languageProcess << ( "-"+options.m_picID.lower() ); + + *m_languageProcess << ( options.inputFiles().first() ); + + *m_languageProcess << ("-o"); + *m_languageProcess << ( options.intermediaryOutput() ); + + if ( !start() ) + { + KMessageBox::sorry( LanguageManager::self()->logView(), i18n("Compilation failed. Please check you have sdcc installed.") ); + processInitFailed(); + return; + } +} + + +bool SDCC::isError( const QString &message ) const +{ + return false; +} + + +bool SDCC::isStderrOutputFatal( const QString & message ) const +{ + if ( message.startsWith("Processor:") ) + return false; + + return true; +} + + +bool SDCC::isWarning( const QString &message ) const +{ + return false; +} + + +ProcessOptions::ProcessPath::Path SDCC::outputPath( ProcessOptions::ProcessPath::Path inputPath ) const +{ + switch (inputPath) + { + case ProcessOptions::ProcessPath::C_AssemblyRelocatable: + return ProcessOptions::ProcessPath::None; + + case ProcessOptions::ProcessPath::C_Library: + return ProcessOptions::ProcessPath::AssemblyRelocatable_Library; + + case ProcessOptions::ProcessPath::C_Object: + return ProcessOptions::ProcessPath::AssemblyRelocatable_Object; + + case ProcessOptions::ProcessPath::C_PIC: + return ProcessOptions::ProcessPath::AssemblyAbsolute_PIC; + + case ProcessOptions::ProcessPath::C_Program: + return ProcessOptions::ProcessPath::AssemblyRelocatable_Program; + + case ProcessOptions::ProcessPath::AssemblyAbsolute_PIC: + case ProcessOptions::ProcessPath::AssemblyAbsolute_Program: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Library: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Object: + case ProcessOptions::ProcessPath::AssemblyRelocatable_PIC: + case ProcessOptions::ProcessPath::AssemblyRelocatable_Program: + case ProcessOptions::ProcessPath::FlowCode_AssemblyAbsolute: + case ProcessOptions::ProcessPath::FlowCode_Microbe: + case ProcessOptions::ProcessPath::FlowCode_PIC: + case ProcessOptions::ProcessPath::FlowCode_Program: + case ProcessOptions::ProcessPath::Microbe_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Microbe_PIC: + case ProcessOptions::ProcessPath::Microbe_Program: + case ProcessOptions::ProcessPath::Object_Disassembly: + case ProcessOptions::ProcessPath::Object_Library: + case ProcessOptions::ProcessPath::Object_PIC: + case ProcessOptions::ProcessPath::Object_Program: + case ProcessOptions::ProcessPath::PIC_AssemblyAbsolute: + case ProcessOptions::ProcessPath::Program_Disassembly: + case ProcessOptions::ProcessPath::Program_PIC: + case ProcessOptions::ProcessPath::Invalid: + case ProcessOptions::ProcessPath::None: + return ProcessOptions::ProcessPath::Invalid; + } + + return ProcessOptions::ProcessPath::Invalid; +} diff --git a/src/languages/sdcc.h b/src/languages/sdcc.h new file mode 100644 index 0000000..a6de933 --- /dev/null +++ b/src/languages/sdcc.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef SDCC_H +#define SDCC_H + +#include + +/** +@author David Saxton +*/ +class SDCC : public ExternalLanguage +{ + public: + SDCC( ProcessChain * processChain, KTechlab * parent ); + ~SDCC(); + + virtual void processInput( ProcessOptions options ); + virtual ProcessOptions::ProcessPath::Path outputPath( ProcessOptions::ProcessPath::Path inputPath ) const; + + protected: + virtual bool isError( const QString & message ) const; + virtual bool isWarning( const QString & message ) const; + virtual bool isStderrOutputFatal( const QString & message ) const; +}; + +#endif diff --git a/src/languages/sourceline.cpp b/src/languages/sourceline.cpp new file mode 100644 index 0000000..9ca89bb --- /dev/null +++ b/src/languages/sourceline.cpp @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "sourceline.h" + + +//BEGIN class SourceLine +SourceLine::SourceLine() + : m_line(-1) +{ +} + + +SourceLine::SourceLine( const QString & fileName, int line ) + : m_fileName(fileName), + m_line(line) +{ +} + + +bool SourceLine::operator < ( const SourceLine & sourceLine ) const +{ + return (m_fileName < sourceLine.fileName()) || + (m_fileName == sourceLine.fileName() && m_line < sourceLine.line()); +} + + +bool SourceLine::operator == ( const SourceLine & sourceLine ) const +{ + return (sourceLine.fileName() == fileName()) && + (sourceLine.line() == line()); +} +//END class SourceLine + + diff --git a/src/languages/sourceline.h b/src/languages/sourceline.h new file mode 100644 index 0000000..d2e774d --- /dev/null +++ b/src/languages/sourceline.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef SOURCELINE_H +#define SOURCELINE_H + +#include + +/** +@author David Saxton + */ +class SourceLine +{ + public: + /** + * Creates an invalid source line (line is negative). + */ + SourceLine(); + SourceLine( const QString & fileName, int line ); + + QString fileName() const { return m_fileName; } + int line() const { return m_line; } + + bool isValid() const { return m_line >= 0; } + + bool operator < ( const SourceLine & sourceLine ) const; + bool operator == ( const SourceLine & sourceLine ) const; + + protected: + QString m_fileName; + int m_line; +}; + + +#endif diff --git a/src/libraryitem.cpp b/src/libraryitem.cpp new file mode 100644 index 0000000..f7ba013 --- /dev/null +++ b/src/libraryitem.cpp @@ -0,0 +1,81 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "libraryitem.h" + +#include +#include +#include +#include + +LibraryItem::LibraryItem( QStringList idList, const QString &name, const QString &category, QPixmap icon, Type type, createItemPtr _createItem ) +{ + m_idList = idList; + m_name = name; + m_category = category; + m_icon_full = icon; + m_type = type; + createItem = _createItem; + createIcon16(); +} + + +LibraryItem::LibraryItem( QStringList idList, const QString &name, const QString &category, const QString &iconName, Type type, createItemPtr _createItem ) +{ + m_idList = idList; + m_name = name; + m_category = category; + m_icon_full.load( locate( "appdata", "icons/"+iconName ) ); + m_type = type; + createItem = _createItem; + createIcon16(); +} + + +LibraryItem::LibraryItem( QStringList idList, const QString &name, const QString &category, Type type, createItemPtr _createItem ) +{ + m_idList = idList; + m_name = name; + m_category = category; + m_type = type; + createItem = _createItem; + createIcon16(); +} + + +LibraryItem::~LibraryItem() +{ +} + + +void LibraryItem::createIcon16() +{ + if ( m_icon_full.isNull() ) + m_icon_full = KGlobal::iconLoader()->loadIcon( "null", KIcon::Small ); + +// const int size = KIcon::SizeSmallMedium; +// const int size = 22; + const int size = 16; + + if ( m_icon_full.width() == size && m_icon_full.height() == size ) + { + m_icon_16 = m_icon_full; + return; + } + + QImage im = m_icon_full.convertToImage(); + im = im.smoothScale( size, size, QImage::ScaleMin ); + m_icon_16.convertFromImage(im); +} + +QString LibraryItem::activeID( ) const +{ + return m_idList.isEmpty() ? "" : m_idList[0]; +} diff --git a/src/libraryitem.h b/src/libraryitem.h new file mode 100644 index 0000000..1e6b429 --- /dev/null +++ b/src/libraryitem.h @@ -0,0 +1,69 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef LIBRARYITEM_H +#define LIBRARYITEM_H + +#include "item.h" + +class QStringList; + +/** +This holds details of an item - id, name, category it is displayed in in its +respective item selector, icon, function pointers to creating the item, etc. +Normally each item will only pass one id, but some items have had their IDs +changed during the history of ktl, so passing a stringlist will take the first +ID as the "active" id, and the rest as IDs that will also be recognized, but +never displayed to the user. +@short Details of an Item +@author David Saxton +*/ +class LibraryItem +{ + public: + ~LibraryItem(); + + enum Type + { + lit_flowpart, + lit_component, + lit_mechanical, + lit_drawpart, + lit_subcircuit, + lit_other + }; + LibraryItem( QStringList idList, const QString &name, const QString &category, QPixmap icon, Type type, createItemPtr createItem ); + LibraryItem( QStringList idList, const QString &name, const QString &category, const QString &iconName, Type type, createItemPtr createItem ); + LibraryItem( QStringList idList, const QString &name, const QString &category, Type type, createItemPtr createItem ); + + QString activeID() const; + QStringList allIDs() const { return m_idList; } + QString name() const { return m_name; } + QString category() const { return m_category; } + QPixmap iconFull() const { return m_icon_full; } + QPixmap icon16() const { return m_icon_16; } + createItemPtr createItemFnPtr() const { return createItem; } + int type() const { return m_type; } + + protected: + void createIcon16(); + + private: + QStringList m_idList; + QString m_name; + QString m_category; + QPixmap m_icon_full; + QPixmap m_icon_16; + createItemPtr createItem; + int m_type; +}; +typedef QValueList LibraryItemList; + +#endif diff --git a/src/mechanics/Makefile.am b/src/mechanics/Makefile.am new file mode 100644 index 0000000..0444358 --- /dev/null +++ b/src/mechanics/Makefile.am @@ -0,0 +1,8 @@ +INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/drawparts $(all_includes) +METASOURCES = AUTO +noinst_HEADERS = mechanicsitem.h chassiscircular2.h mechanicssimulation.h \ + mechanicsdocument.h mechanicsgroup.h mechanicsview.h + +noinst_LTLIBRARIES = libmechanics.la +libmechanics_la_SOURCES = mechanicsitem.cpp chassiscircular2.cpp \ + mechanicssimulation.cpp mechanicsdocument.cpp mechanicsgroup.cpp mechanicsview.cpp diff --git a/src/mechanics/chassiscircular2.cpp b/src/mechanics/chassiscircular2.cpp new file mode 100644 index 0000000..91b9f0a --- /dev/null +++ b/src/mechanics/chassiscircular2.cpp @@ -0,0 +1,144 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "chassiscircular2.h" + +#include "libraryitem.h" + +#include +#include +#include + +#include +#include + +double normalizeAngle( double angle ); + + +Item* ChassisCircular2::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ChassisCircular2( (MechanicsDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* ChassisCircular2::libraryItem() +{ + return new LibraryItem( + QString("mech/chassis_circular_2"), + i18n("Circular 2-Wheel Chassis"), + i18n("Chassis'"), + "chassis.png", + LibraryItem::lit_mechanical, + ChassisCircular2::construct ); +} + + +ChassisCircular2::ChassisCircular2( MechanicsDocument *mechanicsDocument, bool newItem, const char *id ) + : MechanicsItem( mechanicsDocument, newItem, (id) ? id : "chassis_circular_2" ) +{ + m_name = i18n("Circular 2-Wheel Chassis"); + m_desc = i18n("A circular base with two wheels and a support point."); + + m_theta1 = 0.0; + m_theta2 = 0.0; + + QPointArray pa; + pa.makeEllipse( -25, -25, 50, 50 ); + QWMatrix m(4,0,0,4,0,0); + m.setTransformationMode( QWMatrix::Areas ); + pa = m.map(pa); + setItemPoints(pa); + + itemResized(); +} + + +ChassisCircular2::~ChassisCircular2() +{ +} + + +void ChassisCircular2::itemResized() +{ + const double w = sizeRect().width(); + const double h = sizeRect().height(); + + m_wheel1Pos = QRect( int(w/5), int(h/6), int(w/4), int(h/8) ); + m_wheel2Pos = QRect( int(w/5), int(5*h/6-h/8), int(w/4), int(h/8) ); +} + + +void ChassisCircular2::advance( int phase ) +{ + if ( phase != 1 ) + return; + + double speed1 = 60.; // pixels per second + double speed2 = 160.; // pixels per second + + m_theta1 = normalizeAngle( m_theta1 + (speed1/1000.)/m_wheel1Pos.width() ); + m_theta2 = normalizeAngle( m_theta2 + (speed2/1000.)/m_wheel2Pos.width() ); + + const double d1 = speed1/1000.; + const double d2 = speed2/1000.; + const double sep = m_wheel2Pos.center().y()-m_wheel1Pos.center().y(); + + double dtheta = std::atan( (d2-d1)/sep ); // Change in orientation of chassis + double moveAngle = absolutePosition().angle()+dtheta/2; + rotateBy(dtheta); + moveBy( ((d1+d2)/2.)*std::cos(moveAngle), ((d1+d2)/2.)*std::sin(moveAngle) ); +} + + +void ChassisCircular2::drawShape( QPainter &p ) +{ + const double _x = int(sizeRect().x() + x()); + const double _y = int(sizeRect().y() + y()); + const double w = sizeRect().width(); + const double h = sizeRect().height(); + + initPainter(p); + p.setBrush( QColor( 255, 246, 210 ) ); + QRect circleRect = sizeRect(); + circleRect.moveLeft( int(circleRect.left() + x()) ); + circleRect.moveTop( int(circleRect.top() + y()) ); + p.drawEllipse(circleRect); + + // Draw wheels + // TODO get this info from m_wheel1Pos and m_wheel2Pos + const double X = _x+(w/5); // Wheel's left pos + const double H = h/8; // Wheel's height + const double y1 = _y+(h/6); // Wheel 1 y-pos + const double y2 = _y+(5*h/6)-H; // Wheel 2 y-pos + + p.setPen( Qt::NoPen ); + const double stripeWidth = 5; + const double offset2 = 1 + int(m_theta1*m_wheel1Pos.width())%int(2*stripeWidth); + const double offset1 = 1 + int(m_theta2*m_wheel2Pos.width())%int(2*stripeWidth); + p.setBrush( QColor( 255, 232, 182 ) ); + for ( double i=-1; i + +MechanicsDocument::MechanicsDocument( const QString &caption, KTechlab *ktechlab, const char *name ) + : ItemDocument( caption, ktechlab, name ) +{ + m_type = Document::dt_mechanics; + m_pDocumentIface = new MechanicsDocumentIface(this); + m_fileExtensionInfo = i18n("*.mechanics|Mechanics (*.mechanics)\n*|All Files"); + m_canvas->retune(128); + + m_selectList = new MechanicsGroup(this); + + m_cmManager->addManipulatorInfo( CMSelect::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMDraw::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMRightClick::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMRepeatedItemAdd::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMItemResize::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMMechItemMove::manipulatorInfo() ); + m_mechanicsSimulation = new MechanicsSimulation(this); + requestStateSave(); +} + + +MechanicsDocument::~MechanicsDocument() +{ + m_bDeleted = true; + + // Remove all items from the canvas + selectAll(); + deleteSelection(); + delete m_mechanicsSimulation; +} + +View *MechanicsDocument::createView( ViewContainer *viewContainer, uint viewAreaId, const char *name ) +{ + ItemView *itemView = new MechanicsView( this, viewContainer, viewAreaId, name ); + handleNewView(itemView); + return itemView; +} + + +ItemGroup *MechanicsDocument::selectList() const +{ + return m_selectList; +} + + + + +bool MechanicsDocument::isValidItem( const QString &itemId ) +{ + return itemId.startsWith("mech/") || itemId.startsWith("dp/"); +} + + +bool MechanicsDocument::isValidItem( Item *item ) +{ + return item && ((dynamic_cast(item)) || (dynamic_cast(item))); +} + + +Item* MechanicsDocument::addItem( const QString &id, const QPoint &p, bool newItem ) +{ + if ( !isValidItem(id) ) + return 0l; + + Item *item = itemLibrary()->createItem( id, this, newItem ); + if (!item) + return 0L; + + QRect rect = item->boundingRect(); + + int dx = (int)(p.x())-rect.width()/2; + int dy = (int)(p.y())-rect.height()/2; + + if ( dx < 16 || dx > canvas()->width() ) dx = 16; + if ( dy < 16 || dy > canvas()->height() ) dy = 16; + + item->move( dx, dy ); + item->show(); + + registerItem(item); +// setModified(true); + requestStateSave(); + return item; +} + + +void MechanicsDocument::deleteSelection() +{ + // End whatever editing mode we are in, as we don't want to start editing + // something that is about to no longer exist... + m_cmManager->cancelCurrentManipulation(); + + if ( m_selectList->isEmpty() ) + return; + + // We nee to tell the selete items to remove themselves, and then + // pass the items that have add themselves to the delete list to the + // CommandAddItems command + + m_selectList->deleteAllItems(); + flushDeleteList(); + setModified(true); + + // We need to emit this so that property widgets etc... + // can clear themselves. + emit itemUnselected(0L); + requestStateSave(); +} + + +bool MechanicsDocument::registerItem( QCanvasItem *qcanvasItem ) +{ + return ItemDocument::registerItem(qcanvasItem); +} + + +void MechanicsDocument::appendDeleteList( QCanvasItem *qcanvasItem ) +{ + MechanicsItem *mechItem = dynamic_cast(qcanvasItem); + if ( !mechItem || m_itemDeleteList.contains(mechItem) ) { + return; + } + + m_itemDeleteList.append(mechItem); + m_itemList.remove(mechItem); + + disconnect( mechItem, SIGNAL(selected(Item*,bool)), this, SIGNAL(itemSelected(Item*)) ); + disconnect( mechItem, SIGNAL(unselected(Item*,bool)), this, SIGNAL(itemUnselected(Item*)) ); + + mechItem->removeItem(); +} + + +void MechanicsDocument::flushDeleteList() +{ + // Remove duplicate items in the delete list + ItemList::iterator end = m_itemDeleteList.end(); + for ( ItemList::iterator it = m_itemDeleteList.begin(); it != end; ++it ) + { + if ( *it && m_itemDeleteList.contains(*it) > 1 ) + *it = 0l; + } + m_itemDeleteList.remove(QGuardedPtr(0l)); + + end = m_itemDeleteList.end(); + for ( ItemList::iterator it = m_itemDeleteList.begin(); it != end; ++it ) + { + m_itemList.remove(*it); + (*it)->setCanvas(0l); + delete *it; + } +} + + +MechanicsItem* MechanicsDocument::mechanicsItemWithID( const QString &id ) +{ + return dynamic_cast(itemWithID(id)); +} + + +void MechanicsDocument::selectAll() +{ + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + select(*it); + } +} + + +void MechanicsDocument::copy() +{ +} + +#include "mechanicsdocument.moc" diff --git a/src/mechanics/mechanicsdocument.h b/src/mechanics/mechanicsdocument.h new file mode 100644 index 0000000..dfe454f --- /dev/null +++ b/src/mechanics/mechanicsdocument.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef MECHANICSDOCUMENT_H +#define MECHANICSDOCUMENT_H + +#include "itemdocument.h" + +class KTechlab; +class MechanicsGroup; +class MechanicsItem; +class MechanicsSimulation; + +typedef QValueList MechItemList; +typedef QValueList MechanicsItemList; + +/** +@author David Saxton +*/ +class MechanicsDocument : public ItemDocument +{ +Q_OBJECT +public: + MechanicsDocument( const QString &caption, KTechlab *ktechlab, const char *name = 0 ); + ~MechanicsDocument(); + + virtual View *createView( ViewContainer *viewContainer, uint viewAreaId, const char *name = 0l ); + + virtual bool isValidItem( const QString &itemId ); + virtual bool isValidItem( Item *item ); + + virtual void deleteSelection(); + virtual void copy(); + virtual void selectAll(); + virtual ItemGroup *selectList() const; + MechanicsItem *mechanicsItemWithID( const QString &id ); + virtual Item* addItem( const QString &id, const QPoint &p, bool newItem ); + /** + * Adds a QCanvasItem to the delete list to be deleted, when + * flushDeleteList() is called + */ + virtual void appendDeleteList( QCanvasItem *qcanvasItem ); + /** + * Permantly deletes all items that have been added to the delete list with + * the appendDeleteList( QCanvasItem *qcanvasItem ) function. + */ + virtual void flushDeleteList(); + /** + * Register an item with the ICNDocument. + */ + virtual bool registerItem( QCanvasItem *qcanvasItem ); + +protected: + MechanicsGroup *m_selectList; + MechanicsSimulation *m_mechanicsSimulation; +}; + + +#endif diff --git a/src/mechanics/mechanicsgroup.cpp b/src/mechanics/mechanicsgroup.cpp new file mode 100644 index 0000000..94fe703 --- /dev/null +++ b/src/mechanics/mechanicsgroup.cpp @@ -0,0 +1,243 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "mechanicsgroup.h" +#include "mechanicsitem.h" +#include "mechanicsdocument.h" + +MechanicsGroup::MechanicsGroup( MechanicsDocument *mechanicsDocument, const char *name ) + : ItemGroup( mechanicsDocument, name ) +{ + b_isRaised = false; +} + + +MechanicsGroup::~MechanicsGroup() +{ +} + + +bool MechanicsGroup::addItem( Item *item ) +{ + if ( !item || !item->canvas() || m_itemList.contains(item) ) { + return false; + } + + // Check that the item's parent isn't already selected + Item *parent = item->parentItem(); + while (parent) + { + if ( m_itemList.contains(parent) ) + return false; + parent = parent->parentItem(); + } + removeChildren(item); + + registerItem(item); + updateInfo(); + item->setSelected(true); + if ( MechanicsItem *mechanicsItem = dynamic_cast(item) ) + mechanicsItem->setRaised(b_isRaised); + emit itemAdded(item); + return true; +} + + +bool MechanicsGroup::removeItem( Item *item ) +{ + if ( !item || !m_itemList.contains(item) ) { + return false; + } + unregisterItem(item); + updateInfo(); + item->setSelected(false); + MechanicsItem *mechanicsItem = dynamic_cast(item); + if (mechanicsItem) + mechanicsItem->setRaised(false); + emit itemRemoved(item); + return true; +} + + +void MechanicsGroup::removeChildren( Item *item ) +{ + if (!item) + return; + + const ItemList children = item->children(); + const ItemList::const_iterator end = children.end(); + for ( ItemList::const_iterator it = children.begin(); it != end; ++it ) + { + removeChildren(*it); + removeItem(*it); + } +} + + +void MechanicsGroup::setRaised( bool isRaised ) +{ + b_isRaised = isRaised; + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + MechanicsItem *mechanicsItem = dynamic_cast((Item*)*it); + if (mechanicsItem) + mechanicsItem->setRaised(b_isRaised); + } +} + + +void MechanicsGroup::setSelectionMode( uint sm ) +{ + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + MechanicsItem *mechanicsItem = dynamic_cast((Item*)*it); + if (mechanicsItem) + mechanicsItem->setSelectionMode( (MechanicsItem::SelectionMode)sm ); + } +} + + +MechanicsItemList MechanicsGroup::extractMechanicsItems() const +{ + MechanicsItemList mechanicsItemList; + + const ItemList::const_iterator end = m_itemList.end(); + for ( ItemList::const_iterator it = m_itemList.begin(); it != end; ++it ) + { + MechanicsItem *mechanicsItem = dynamic_cast((Item*)*it); + if (mechanicsItem) + mechanicsItemList.append(mechanicsItem); + } + + return mechanicsItemList; +} + + +MechanicsItemList MechanicsGroup::toplevelMechItemList() const +{ + MechanicsItemList toplevel; + + MechanicsItemList mechItemList = extractMechanicsItems(); + + const MechanicsItemList::const_iterator end = mechItemList.end(); + for ( MechanicsItemList::const_iterator it = mechItemList.begin(); it != end; ++it ) + { + MechanicsItem* parent = *it; + while (parent) + { + if ( !parent->parentItem() && !toplevel.contains(parent) ) + toplevel.append(parent); + + parent = dynamic_cast(parent->parentItem()); + } + } + + return toplevel; +} + + +void MechanicsGroup::setSelected( bool sel ) +{ + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + if (*it && (*it)->isSelected() != sel ) { + (*it)->setSelected(sel); + } + } +} + + +bool MechanicsGroup::addQCanvasItem( QCanvasItem* item ) +{ + return addItem( dynamic_cast(item) ); +} + +bool MechanicsGroup::contains(QCanvasItem* item) const +{ + return m_itemList.contains(dynamic_cast(item)); +} + + +void MechanicsGroup::deleteAllItems() +{ + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + if (*it) + (*it)->removeItem(); + } + + removeAllItems(); +} + +void MechanicsGroup::mergeGroup(ItemGroup* itemGroup) +{ + MechanicsGroup *group = dynamic_cast(itemGroup); + if (!group) { + return; + } + + const ItemList items = group->items(); + const ItemList::const_iterator end = items.end(); + for ( ItemList::const_iterator it = items.begin(); it != end; ++it ) + { + addItem(*it); + } +} + +void MechanicsGroup::removeAllItems() +{ + while ( !m_itemList.isEmpty() ) + removeItem(m_itemList.first()); +} + +void MechanicsGroup::removeQCanvasItem(QCanvasItem* item) +{ + removeItem(dynamic_cast(item)); +} + + +void MechanicsGroup::setItems(QCanvasItemList list) +{ + { + ItemList removeList; + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + if ( !list.contains(*it) ) { + removeList.append(*it); + } + } + const ItemList::iterator rend = removeList.end(); + for ( ItemList::iterator it = removeList.begin(); it != rend; ++it ) + { + removeItem(*it); + (*it)->setSelected(false); + } + } + + const QCanvasItemList::iterator end = list.end(); + for ( QCanvasItemList::iterator it = list.begin(); it != end; ++it ) + { + // We don't need to check that we've already got the item as it will + // be checked in the function call + addQCanvasItem(*it); + } +} + + +void MechanicsGroup::updateInfo() +{ +} + +#include "mechanicsgroup.moc" diff --git a/src/mechanics/mechanicsgroup.h b/src/mechanics/mechanicsgroup.h new file mode 100644 index 0000000..6b49966 --- /dev/null +++ b/src/mechanics/mechanicsgroup.h @@ -0,0 +1,72 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef MECHANICSGROUP_H +#define MECHANICSGROUP_H + +#include + + +class MechanicsItem; +class MechanicsDocument; +typedef QValueList MechanicsItemList; + +/** +@author David Saxton +*/ +class MechanicsGroup : public ItemGroup +{ +Q_OBJECT +public: + MechanicsGroup( MechanicsDocument *mechanicsDocument, const char *name = 0); + ~MechanicsGroup(); + + /** + * Returns a list of top-level mechanics items only + */ + MechanicsItemList toplevelMechItemList() const; + /** + * Sets the selection mode of all MechanicsItems in the group + */ + void setSelectionMode( uint sm ); + /** + * "Raises" (increases the z value of) the selected group of items + */ + void setRaised( bool isRaised ); + /** + * Removes all the children of the given item from the group + */ + void removeChildren( Item *item ); + bool addItem( Item *item ); + bool removeItem( Item *item ); + virtual bool addQCanvasItem(QCanvasItem* item); + virtual bool contains(QCanvasItem* item) const; + virtual uint count() const { return itemCount(); } + virtual void deleteAllItems(); + virtual void mergeGroup(ItemGroup* group); + virtual void removeAllItems(); + virtual void removeQCanvasItem(QCanvasItem* item); + virtual void setItems(QCanvasItemList list); + /** + * Sets the selected state of all items in the group + */ + virtual void setSelected( bool sel ); + /** + * Extracts the mechanics items from the item list + */ + MechanicsItemList extractMechanicsItems() const; + +protected: + void updateInfo(); + + bool b_isRaised; +}; + +#endif diff --git a/src/mechanics/mechanicsitem.cpp b/src/mechanics/mechanicsitem.cpp new file mode 100644 index 0000000..acf2239 --- /dev/null +++ b/src/mechanics/mechanicsitem.cpp @@ -0,0 +1,433 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "itemdocumentdata.h" +#include "mechanicsitem.h" +#include "mechanicsdocument.h" + +#include +#include +#include +#include +#include +#include + +/** +@returns an angle between 0 and 2 pi +*/ +double normalizeAngle( double angle ) +{ + if ( angle < 0 ) + angle += 6.2832*(std::ceil(-angle)); + + return angle - 6.2832*std::floor(angle/6.2832); +} + +MechanicsItem::MechanicsItem( MechanicsDocument *mechanicsDocument, bool newItem, const QString &id ) + : Item( mechanicsDocument, newItem, id ) +{ + p_mechanicsDocument = mechanicsDocument; + m_selectionMode = MechanicsItem::sm_move; + + createProperty( "mass", Variant::Type::Double ); + property("mass")->setCaption( i18n("Mass") ); + property("mass")->setUnit("g"); + property("mass")->setValue(10.0); + property("mass")->setMinValue(1e-3); + property("mass")->setMaxValue(1e12); + property("mass")->setAdvanced(true); + + createProperty( "moi", Variant::Type::Double ); + property("moi")->setCaption( i18n("Moment of Inertia") ); + property("moi")->setUnit("gm"); + property("moi")->setValue(0.01); + property("moi")->setMinValue(1e-3); + property("moi")->setMaxValue(1e12); + property("moi")->setAdvanced(true); + + setZ(ItemDocument::Z::Item); + setAnimated(true); + p_mechanicsDocument->registerItem(this); +} + + +MechanicsItem::~MechanicsItem() +{ +} + + +int MechanicsItem::rtti() const +{ + return ItemDocument::RTTI::MechanicsItem; +} + + +void MechanicsItem::setSelectionMode( SelectionMode sm ) +{ + if ( sm == m_selectionMode ) + return; + + m_selectionMode = sm; +} + + +void MechanicsItem::setSelected( bool yes ) +{ + if ( yes == isSelected() ) + return; + + if (!yes) + // Reset the selection mode + m_selectionMode = MechanicsItem::sm_resize; + + Item::setSelected(yes); +} + + +void MechanicsItem::dataChanged() +{ + Item::dataChanged(); + m_mechanicsInfo.mass = dataDouble("mass"); + m_mechanicsInfo.momentOfInertia = dataDouble("moi"); + updateMechanicsInfoCombined(); +} + + +PositionInfo MechanicsItem::absolutePosition() const +{ + MechanicsItem *parentMechItem = dynamic_cast((Item*)(p_parentItem)); + if (parentMechItem) + return parentMechItem->absolutePosition() + m_relativePosition; + + return m_relativePosition; +} + + +void MechanicsItem::reparented( Item *oldItem, Item *newItem ) +{ + MechanicsItem *oldMechItem = dynamic_cast(oldItem); + MechanicsItem *newMechItem = dynamic_cast(newItem); + + if (oldMechItem) + { + m_relativePosition = oldMechItem->absolutePosition() + m_relativePosition; + disconnect( oldMechItem, SIGNAL(moved()), this, SLOT(parentMoved()) ); + } + + if (newMechItem) + { + m_relativePosition = m_relativePosition - newMechItem->absolutePosition(); + connect( newMechItem, SIGNAL(moved()), this, SLOT(parentMoved()) ); + } + + updateCanvasPoints(); +} + + +void MechanicsItem::childAdded( Item *child ) +{ + MechanicsItem *mechItem = dynamic_cast(child); + if (!mechItem) + return; + + connect( mechItem, SIGNAL(updateMechanicsInfoCombined()), this, SLOT(childMoved()) ); + updateMechanicsInfoCombined(); +} + + +void MechanicsItem::childRemoved( Item *child ) +{ + MechanicsItem *mechItem = dynamic_cast(child); + if (!mechItem) + return; + + disconnect( mechItem, SIGNAL(updateMechanicsInfoCombined()), this, SLOT(childMoved()) ); + updateMechanicsInfoCombined(); +} + + +void MechanicsItem::parentMoved() +{ + PositionInfo absPos = absolutePosition(); + Item::moveBy( absPos.x() - x(), absPos.y() - y() ); + updateCanvasPoints(); + emit moved(); +} + + +void MechanicsItem::updateCanvasPoints() +{ + const QRect ipbr = m_itemPoints.boundingRect(); + + double scalex = double(m_sizeRect.width()) / double(ipbr.width()); + double scaley = double(m_sizeRect.height()) / double(ipbr.height()); + + PositionInfo abs = absolutePosition(); + + QWMatrix m; + m.rotate(abs.angle()*57.29577951308232); + m.translate( m_sizeRect.left(), m_sizeRect.top() ); + m.scale( scalex, scaley ); + m.translate( -int(ipbr.left()), -int(ipbr.top()) ); + setPoints( m.map(m_itemPoints) ); + + QRect tempt = m.mapRect(ipbr); +} + + +void MechanicsItem::rotateBy( double dtheta ) +{ + m_relativePosition.rotate(dtheta); + updateCanvasPoints(); + updateMechanicsInfoCombined(); + emit moved(); +} + + +void MechanicsItem::moveBy( double dx, double dy ) +{ + m_relativePosition.translate( dx, dy ); + Item::moveBy( m_relativePosition.x() - x(), m_relativePosition.y() - y() ); + emit moved(); +} + + +void MechanicsItem::updateMechanicsInfoCombined() +{ + m_mechanicsInfoCombined = m_mechanicsInfo; + + double mass_x = 0.; + double mass_y = 0.; + + const ItemList::const_iterator end = m_children.end(); + for ( ItemList::const_iterator it = m_children.begin(); it != end; ++it ) + { + MechanicsItem *child = dynamic_cast((Item*)*it); + if (child) + { + CombinedMechanicsInfo *childInfo = child->mechanicsInfoCombined(); + const PositionInfo relativeChildPosition = child->relativePosition(); + + double mass = childInfo->mass; +// double angle = relativeChildPosition.angle(); + double dx = relativeChildPosition.x() /*+ cos(angle)*childInfo->m_x - sin(angle)*childInfo->m_y*/; + double dy = relativeChildPosition.y() /*+ sin(angle)*childInfo->m_x + cos(angle)*childInfo->m_y*/; + + m_mechanicsInfoCombined.mass += mass; + mass_x += mass * dx; + mass_y += mass * dy; + + double length_squared = dx*dx + dy*dy; + m_mechanicsInfoCombined.momentOfInertia += length_squared * childInfo->momentOfInertia; + } + } + + m_mechanicsInfoCombined.x = mass_x / m_mechanicsInfoCombined.mass; + m_mechanicsInfoCombined.y = mass_y / m_mechanicsInfoCombined.mass; +} + + +ItemData MechanicsItem::itemData() const +{ + ItemData itemData = Item::itemData(); + itemData.angleDegrees = m_relativePosition.angle()*57.29577951308232; + return itemData; +} + + +bool MechanicsItem::mousePressEvent( const EventInfo &eventInfo ) +{ + Q_UNUSED(eventInfo); + return false; +} + + +bool MechanicsItem::mouseReleaseEvent( const EventInfo &eventInfo ) +{ + Q_UNUSED(eventInfo); + return false; +} + + +bool MechanicsItem::mouseDoubleClickEvent( const EventInfo &eventInfo ) +{ + Q_UNUSED(eventInfo); + return false; +} + + +bool MechanicsItem::mouseMoveEvent( const EventInfo &eventInfo ) +{ + Q_UNUSED(eventInfo); + return false; +} + + +bool MechanicsItem::wheelEvent( const EventInfo &eventInfo ) +{ + Q_UNUSED(eventInfo); + return false; +} + + +void MechanicsItem::enterEvent() +{ +} + + +void MechanicsItem::leaveEvent() +{ +} + + +QRect MechanicsItem::maxInnerRectangle( const QRect &outerRect ) const +{ + QRect normalizedOuterRect = outerRect.normalize(); + const double LEFT = normalizedOuterRect.left(); + const double TOP = normalizedOuterRect.top(); + const double X = normalizedOuterRect.width(); + const double Y = normalizedOuterRect.height(); + const double a = normalizeAngle(absolutePosition().angle()); + + double left; + double top; + double width; + double height; + +// if ( can change width/height ratio ) + { + double x1 = X*std::cos(a) - Y*std::sin(a); + double y1 = X*std::sin(a) + Y*std::cos(a); + double x2 = X*std::cos(a); + double y2 = X*std::sin(a); + double x3 = -Y*std::sin(a); + double y3 = Y*std::cos(a); + + double xbig;/* = std::max( std::abs(x2-x3), std::abs(x1) );*/ + double ybig;/* = std::max( std::abs(y2-y3), std::abs(y1) );*/ + if ( (a - floor(a/6.2832)*6.2832) < 3.1416 ) + { + xbig = std::abs(x3-x2); + ybig = std::abs(y1); + } + else + { + xbig = std::abs(x1); + ybig = std::abs(y3-y2); + } + + width = X*(X/xbig); + height = Y*(Y/ybig); + + top = -std::sin(a) * (LEFT + width*std::sin(a)) + std::cos(a)*TOP; + left = std::cos(a) * (LEFT + width*std::sin(a)) + std::sin(a)*TOP; + } + + return QRect( int(left), int(top), int(width), int(height) ); +} + + +void MechanicsItem::initPainter( QPainter &p ) +{ + PositionInfo absPos = absolutePosition(); + p.translate( absPos.x(), absPos.y() ); + // 57.29577951308232 is the number of degrees per radian. + p.rotate( absPos.angle()*57.29577951308232 ); + p.translate( -absPos.x(), -absPos.y() ); +} + + +void MechanicsItem::deinitPainter( QPainter &p ) +{ + PositionInfo absPos = absolutePosition(); + p.translate( absPos.x(), absPos.y() ); + // 57.29577951308232 is the number of degrees per radian. + p.rotate( -absPos.angle()*57.29577951308232 ); + p.translate( -absPos.x(), -absPos.y() ); +} + + + + + +PositionInfo::PositionInfo() +{ + reset(); +} + + +const PositionInfo PositionInfo::operator+( const PositionInfo &info ) +{ + // Copy the child to a new position + PositionInfo newInfo = info; + + // Translate the newInfo by our translation amount + newInfo.translate( x(), y() ); + + // Rotate the child about us + newInfo.rotateAboutPoint( x(), y(), angle() ); + + return newInfo; +} + + +const PositionInfo PositionInfo::operator-( const PositionInfo &info ) +{ + + PositionInfo newInfo = *this; + + newInfo.translate( -info.x(), -info.y() ); + newInfo.rotate( -info.angle() ); + + return newInfo; +} + + +void PositionInfo::rotateAboutPoint( double x, double y, double angle ) +{ + m_angle += angle; + + double newx = x + (m_x-x)*std::cos(angle) - (m_y-y)*std::sin(angle); + double newy = y + (m_x-x)*std::sin(angle) + (m_y-y)*std::cos(angle); + + m_x = newx; + m_y = newy; +} + + +void PositionInfo::reset() +{ + m_x = 0.; + m_y = 0.; + m_angle = 0.; +} + + + +MechanicsInfo::MechanicsInfo() +{ + mass = 0.; + momentOfInertia = 0.; +} +CombinedMechanicsInfo::CombinedMechanicsInfo() + : MechanicsInfo() +{ + x = 0.; + y = 0.; +} +CombinedMechanicsInfo::CombinedMechanicsInfo( const MechanicsInfo &info ) + : MechanicsInfo(info) +{ + x = 0.; + y = 0.; +} + + +#include "mechanicsitem.moc" diff --git a/src/mechanics/mechanicsitem.h b/src/mechanics/mechanicsitem.h new file mode 100644 index 0000000..db500fc --- /dev/null +++ b/src/mechanics/mechanicsitem.h @@ -0,0 +1,237 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef MECHANICSITEM_H +#define MECHANICSITEM_H + +#include +#include + +class LibraryItem; +class MechanicsItem; +// class MechanicsItemOverlayItem; +class MechanicsDocument; +typedef QValueList MechanicsItemList; + +/** +@short Stores mass, moment of inertia +@author David Saxton +*/ +class MechanicsInfo +{ +public: + MechanicsInfo(); + + double mass; // Mass + double momentOfInertia; // Moment of inertia +}; + +class CombinedMechanicsInfo : public MechanicsInfo +{ +public: + CombinedMechanicsInfo(); + CombinedMechanicsInfo( const MechanicsInfo &info ); + + double x; // X coordinate of center of mass + double y; // Y coordinate of center of mass +}; + +/** +@short Stores a position and orientation +@author David Saxton +*/ +class PositionInfo +{ +public: + PositionInfo(); + /** + * Adds together two positions: for this=PARENT +(CHILD), the new position + * is formed by translating this position by that of the CHILDs + * translation, and then rotating everything about the center of this item + */ + const PositionInfo operator+( const PositionInfo &info ); + /** + * Not quite the inverse of operator+. Subtracts the given position info + * as if it was applied before this current info. + */ + const PositionInfo operator-( const PositionInfo &info ); + /** + * x position (0 is left) + */ + double x() const { return m_x; } + /** + * y position (0 is top) + */ + double y() const { return m_y; } + /** + * Angle in radians, positive direction is anticlockwise + */ + double angle() const { return m_angle; } + /** + * Sets the x-position + */ + void setX( double x ) { m_x = x; } + /** + * Sets the y-position + */ + void setY( double y ) { m_y = y; } + /** + * Sets the angle + */ + void setAngle( double angle ) { m_angle = angle; } + /** + * Adds (x,y) to the current position + */ + void translate( double dx, const double dy ) { m_x += dx; m_y += dy; } + /** + * Rotates anticlockwise by the given amount (in radians) + */ + void rotate( double angle ) { m_angle += angle; } + /** + * Resets the position to (0,0), and the orientation to 0 + */ + void reset(); + /** + * Rotates the current position about the given point through the given + * angle in radians anticlockwise. This will change the position and + * orientation. + */ + void rotateAboutPoint( double x, double y, double angle ); + +protected: + double m_x; + double m_y; + double m_angle; +}; + + +/** +@author David Saxton +*/ +class MechanicsItem : public Item +{ +Q_OBJECT +public: + MechanicsItem( MechanicsDocument *mechanicsDocument, bool newItem, const QString &id ); + virtual ~MechanicsItem(); + + enum SelectionMode + { + sm_move, + sm_resize, + sm_rotate + }; + /** + * Returns the run-time identifier for the MechanicsItem + */ + int rtti() const; + /** + * Sets the selection mode (sm_resize or sm_rotate). Note that setSelected + * also needs to be called to select the item. + */ + void setSelectionMode( SelectionMode sm ); + virtual void setSelected( bool yes ); + /** + * @returns the selection mode + */ + SelectionMode selectionMode() const { return m_selectionMode; } + /** + * Move the MechanicsItem by the given amount + */ + virtual void moveBy( double dx, double dy ); + /** + * Returns the absolute position on the canvas + */ + PositionInfo absolutePosition() const; + /** + * Returns the position relative to the parent item (or the absolute + * position if there is no parent item) + */ + PositionInfo relativePosition() const { return m_relativePosition; } + /** + * Returns the mechanics info for this item (so not taking into account that + * of attached children) + */ + MechanicsInfo *mechanicsInfo() { return &m_mechanicsInfo; } + /** + * Returns the combined mechanics info for this item (which takes into + * account that of attached children). + */ + CombinedMechanicsInfo *mechanicsInfoCombined() { return &m_mechanicsInfoCombined; } + /** + * Returns the rectangle that can legitimately fit inside the given bounding + * rectangle, given this items current rotation. Legitimately means that + * whether this item is allowed to be distorted, inverted, resized, etc. + */ + QRect maxInnerRectangle( const QRect &outerRect ) const; + + virtual ItemData itemData() const; + + virtual bool mousePressEvent( const EventInfo &eventInfo ); + virtual bool mouseReleaseEvent( const EventInfo &eventInfo ); + virtual bool mouseDoubleClickEvent ( const EventInfo &eventInfo ); + virtual bool mouseMoveEvent( const EventInfo &eventInfo ); + virtual bool wheelEvent( const EventInfo &eventInfo ); + virtual void enterEvent(); + virtual void leaveEvent(); + +public slots: + /** + * Rotate the item by the given amount (in radians) + */ + void rotateBy( double dtheta ); + void parentMoved(); + +signals: + /** + * Emitted when this item moves (translates or rotates) + */ + void moved(); + +protected slots: + /** + * Recalculate the combined mechanics info (e.g. when mass is changed, or child added) + */ + void updateMechanicsInfoCombined(); + +protected: + virtual void reparented( Item *oldItem, Item *newItem ); + virtual void childAdded( Item *child ); + virtual void childRemoved( Item *child ); + /** + * Called when this item is resized, so that sub classes can do whatever + */ + virtual void itemResized() {}; + /** + * Sets the correct orientation on the painter + */ + void initPainter( QPainter &p ); + /** + * *Must* be called after calling initPainter, if initPainter was called + */ + void deinitPainter( QPainter &p ); + virtual void dataChanged(); + virtual void itemPointsChanged() { updateCanvasPoints(); } + /** + * Calculates the setPoints required from the current m_itemPoints and the + * current position / angle + */ + void updateCanvasPoints(); + + MechanicsDocument *p_mechanicsDocument; + PositionInfo m_relativePosition; // Absolution position if not attached to a parent item, or otherwise relative to parent item + MechanicsInfo m_mechanicsInfo; + CombinedMechanicsInfo m_mechanicsInfoCombined; + +private: + SelectionMode m_selectionMode; +}; + +#endif diff --git a/src/mechanics/mechanicssimulation.cpp b/src/mechanics/mechanicssimulation.cpp new file mode 100644 index 0000000..d5ec98d --- /dev/null +++ b/src/mechanics/mechanicssimulation.cpp @@ -0,0 +1,139 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "mechanicsdocument.h" +#include "mechanicsitem.h" +#include "mechanicssimulation.h" + +#include +#include + +MechanicsSimulation::MechanicsSimulation( MechanicsDocument *mechanicsDocument ) + : QObject(mechanicsDocument) +{ + p_mechanicsDocument = mechanicsDocument; + m_advanceTmr = new QTimer(this); + connect( m_advanceTmr, SIGNAL(timeout()), this, SLOT(slotAdvance()) ); + m_advanceTmr->start(1); +} + + +MechanicsSimulation::~MechanicsSimulation() +{ +} + + +void MechanicsSimulation::slotAdvance() +{ + if ( p_mechanicsDocument && p_mechanicsDocument->canvas() ) + p_mechanicsDocument->canvas()->advance(); +} + + +RigidBody::RigidBody( MechanicsDocument *mechanicsDocument ) +{ + p_mechanicsDocument = mechanicsDocument; + p_overallParent = 0l; +} + + +RigidBody::~RigidBody() +{ +} + + +bool RigidBody::addMechanicsItem( MechanicsItem *item ) +{ + if ( !item || m_mechanicsItemList.contains(item) ) + return false; + + m_mechanicsItemList.append(item); + findOverallParent(); + return true; +} + + +void RigidBody::moveBy( double dx, double dy ) +{ + if (overallParent()) + overallParent()->moveBy( dx, dy ); +} + + +void RigidBody::rotateBy( double dtheta ) +{ + if (overallParent()) + overallParent()->rotateBy(dtheta); +} + + +bool RigidBody::findOverallParent() +{ + p_overallParent = 0l; + if ( m_mechanicsItemList.isEmpty() ) + return false; + + m_mechanicsItemList.remove(0l); + + const MechanicsItemList::iterator end = m_mechanicsItemList.end(); + for ( MechanicsItemList::iterator it = m_mechanicsItemList.begin(); it != end; ++it ) + { + MechanicsItem *parentItem = *it; + MechanicsItem *parentCandidate = dynamic_cast((*it)->parentItem()); + + while (parentCandidate) + { + parentItem = parentCandidate; + parentCandidate = dynamic_cast(parentItem->parentItem()); + } + + if ( !p_overallParent ) + // Must be the first item to test + p_overallParent = parentItem; + + if ( p_overallParent != parentItem ) + { + p_overallParent = 0l; + return false; + } + } + return true; +} + + +void RigidBody::updateRigidBodyInfo() +{ + if (!p_overallParent) + return; + + m_mass = p_overallParent->mechanicsInfoCombined()->mass; + m_momentOfInertia = p_overallParent->mechanicsInfoCombined()->momentOfInertia; +} + + +Vector2D::Vector2D() +{ + x = 0.; + y = 0.; +} + +double Vector2D::length() const +{ + return std::sqrt( x*x + y*y ); +} + +RigidBodyState::RigidBodyState() +{ + angularMomentum = 0.; +} + + + +#include "mechanicssimulation.moc" diff --git a/src/mechanics/mechanicssimulation.h b/src/mechanics/mechanicssimulation.h new file mode 100644 index 0000000..19b474b --- /dev/null +++ b/src/mechanics/mechanicssimulation.h @@ -0,0 +1,133 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef MECHANICSSIMULATION_H +#define MECHANICSSIMULATION_H + +#include +#include +#include + +class MechanicsItem; +class MechanicsDocument; +typedef QValueList MechanicsItemList; + + +/** +@short 2 dimensional vector with associated length functions et al +@author David Saxton +*/ +class Vector2D +{ +public: + Vector2D(); + + double length() const; + double lengthSquared() const { return x*x + y*y; } + + double x; + double y; +}; + + +/** +@short State of a rigid body, in an inertial MechanicsDocument frame +@author David Saxton +*/ +class RigidBodyState +{ +public: + RigidBodyState(); + + Vector2D linearMomentum; + double angularMomentum; + Vector2D position; // Position of center of mass +}; + + +/** +@author David Saxton +*/ +class MechanicsSimulation : public QObject +{ +Q_OBJECT +public: + MechanicsSimulation( MechanicsDocument *mechanicsDocument ); + ~MechanicsSimulation(); + + MechanicsDocument* mechanicsDocument() const { return p_mechanicsDocument; } + +protected slots: + void slotAdvance(); + +protected: + QGuardedPtr p_mechanicsDocument; + QTimer *m_advanceTmr; +}; + + +/** +Rigid body with mass, inertia, etc. Collection of mechanics items with +functionality for moving them about, rotating, etc. Only one mother-parent +(has no parent itself, all other items are descendents) allowed. +@short Rigid body, handles MechanicsItems +@author David Saxton +*/ +class RigidBody +{ +public: + RigidBody( MechanicsDocument *mechanicsDocument ); + ~RigidBody(); + + /** + * + */ + void advance( int phase, double delta ); + /** + * Add the MechanicsItem to the entity. + * @returns true iff successful in adding + */ + bool addMechanicsItem( MechanicsItem *item ); + /** + * Pointer to the mother MechanicsItem. + */ + MechanicsItem *overallParent() const { return p_overallParent; } + /** + * Updates the mass and the moment of inertia info + */ + void updateRigidBodyInfo(); + +protected: + /** + * Attempt to find the overall parent. + * @returns false iff unsucessful (including if there are no MechanicsItems present) + */ + bool findOverallParent(); + /** + * Move the set of MechanicsItems by the given amount + */ + void moveBy( double dx, double dy ); + /** + * Rotate the set of MechanicsItems by the given amount about the center of + * mass. + * @param angle Rotate amount in radians + */ + void rotateBy( double dtheta ); + + MechanicsItemList m_mechanicsItemList; + MechanicsItem *p_overallParent; + MechanicsDocument *p_mechanicsDocument; + + RigidBodyState m_rigidBodyState; + double m_mass; + double m_momentOfInertia; +}; + +#endif diff --git a/src/mechanics/mechanicsview.cpp b/src/mechanics/mechanicsview.cpp new file mode 100644 index 0000000..d49c66a --- /dev/null +++ b/src/mechanics/mechanicsview.cpp @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "mechanicsdocument.h" +#include "mechanicsview.h" +#include "viewiface.h" + + +MechanicsView::MechanicsView( MechanicsDocument *mechanicsDocument, ViewContainer *viewContainer, uint viewAreaId, const char *name ) + : ItemView( mechanicsDocument, viewContainer, viewAreaId, name ) +{ + setXMLFile( "ktechlabmechanicsui.rc", true ); + m_pViewIface = new MechanicsViewIface(this); +} + + +MechanicsView::~MechanicsView() +{ + delete m_pViewIface; + m_pViewIface = 0l; +} + + + + +void MechanicsView::dragEnterEvent( QDragEnterEvent * e ) +{ + ItemView::dragEnterEvent(e); + if ( e->isAccepted() ) + return; + + e->accept( e->provides("ktechlab/mechanical") ); +} + +#include "mechanicsview.moc" diff --git a/src/mechanics/mechanicsview.h b/src/mechanics/mechanicsview.h new file mode 100644 index 0000000..f787b1c --- /dev/null +++ b/src/mechanics/mechanicsview.h @@ -0,0 +1,33 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef MECHANICSVIEW_H +#define MECHANICSVIEW_H + +#include + +class MechanicsDocument; + +/** +@author David Saxton +*/ +class MechanicsView : public ItemView +{ + Q_OBJECT + public: + MechanicsView( MechanicsDocument *mechanicsDocument, ViewContainer *viewContainer, uint viewAreaId, const char *name = 0l ); + ~MechanicsView(); + + protected: + virtual void dragEnterEvent( QDragEnterEvent * e ); + MechanicsDocument *m_pMechanicsDocument; +}; + +#endif diff --git a/src/micro/Makefile.am b/src/micro/Makefile.am new file mode 100644 index 0000000..37dc64f --- /dev/null +++ b/src/micro/Makefile.am @@ -0,0 +1,7 @@ +INCLUDES = $(all_includes) +METASOURCES = AUTO +noinst_LTLIBRARIES = libmicro.la +noinst_HEADERS = microinfo.h picinfo.h picinfo16bit.h picinfo14bit.h \ + picinfo12bit.h microlibrary.h asminfo.h +libmicro_la_SOURCES = microinfo.cpp picinfo.cpp picinfo16bit.cpp \ + picinfo14bit.cpp picinfo12bit.cpp microlibrary.cpp micropackage.cpp asminfo.cpp diff --git a/src/micro/asminfo.cpp b/src/micro/asminfo.cpp new file mode 100644 index 0000000..3a12b57 --- /dev/null +++ b/src/micro/asminfo.cpp @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (C) 2003,2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "asminfo.h" + +#include + +AsmInfo::AsmInfo() +{ +} + + +AsmInfo::~AsmInfo() +{ +} + + +void AsmInfo::addInstruction( const QString & operand, const QString & description, const QString & opcode ) +{ + Instruction instruction; + instruction.operand = operand; + instruction.description = description; + instruction.opcode = opcode; + m_instructionList.append( instruction ); + m_operandList.append( operand ); +} + + +QString AsmInfo::setToString( Set set ) +{ + switch (set) + { + case AsmInfo::PIC12: + return "PIC12"; + + case AsmInfo::PIC14: + return "PIC14"; + + case AsmInfo::PIC16: + return "PIC16"; + } + + kdWarning() << k_funcinfo << "Unrecognized set="<portNames(); + else return ""; +} + +QStringList MicroInfo::pinIDs() +{ + if (m_package) return m_package->pinIDs(); + else return ""; +} + +QStringList MicroInfo::bidirPinIDs() +{ + if (m_package) return m_package->bidirPinIDs(); + else return ""; +} + +int MicroInfo::totalNumPins() +{ + if (m_package) return m_package->totalNumPins(); + else return 0; +} + +int MicroInfo::numIOPins() +{ + if (m_package) return m_package->numIOPins(); + else return 0; +} + +int MicroInfo::numIOPins( const QString &portName ) +{ + if (m_package) return m_package->numIOPins(portName); + else return 0; +} +#endif + diff --git a/src/micro/microinfo.h b/src/micro/microinfo.h new file mode 100644 index 0000000..7a22bf7 --- /dev/null +++ b/src/micro/microinfo.h @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef MICROINFO_H +#define MICROINFO_H + +#include + +class AsmInfo; +class MicroPackage; + +/** +@author David Saxton +*/ +class MicroInfo +{ +public: + enum Support + { + FullSupport = 1 << 0, + PartialSupport = 1 << 1, + NoSupport = 1 << 2 + }; + enum { AllSupport = FullSupport | PartialSupport | NoSupport }; + + MicroInfo(); + virtual ~MicroInfo(); + + virtual AsmInfo * instructionSet() = 0; + /** + * Returns the gpsim emulator support status + */ + virtual Support gpsimSupport() const { return NoSupport; } + /** + * Returns the FlowCode support (i.e. constructing flowcode for the PIC) + */ + virtual Support flowcodeSupport() const { return NoSupport; } + /** + * Returns the Microbe support (i.e. compiling) + */ + virtual Support microbeSupport() const { return NoSupport; } + /** + * Returns a pointer to the Micro Package in use + */ + MicroPackage *package() const { return m_package; } + /** + * Returns an id unique to the Micro + */ + QString id() const { return m_id; } + +protected: + QString m_id; + MicroPackage *m_package; +}; + +#endif + diff --git a/src/micro/microlibrary.cpp b/src/micro/microlibrary.cpp new file mode 100644 index 0000000..f0faabc --- /dev/null +++ b/src/micro/microlibrary.cpp @@ -0,0 +1,115 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "microinfo.h" +#include "microlibrary.h" + +#include +#include + +#include "picinfo12bit.h" +#include "picinfo14bit.h" +#include "picinfo16bit.h" + +#include "micropackage.h" + +MicroLibrary * MicroLibrary::m_pSelf = 0l; +static KStaticDeleter staticMicroLibraryDeleter; + +MicroLibrary * MicroLibrary::self() +{ + if ( !m_pSelf ) + staticMicroLibraryDeleter.setObject( m_pSelf, new MicroLibrary() ); + return m_pSelf; +} + +MicroLibrary::MicroLibrary() +{ + addMicroInfo( new PicInfo12C508() ); + addMicroInfo( new PicInfo12C509() ); + addMicroInfo( new PicInfo16C54 () ); + addMicroInfo( new PicInfo16C55() ); + addMicroInfo( new PicInfo16C61() ); + addMicroInfo( new PicInfo16C62() ); + addMicroInfo( new PicInfo16C63() ); + addMicroInfo( new PicInfo16C64() ); + addMicroInfo( new PicInfo16F627() ); + addMicroInfo( new PicInfo16F628() ); + addMicroInfo( new PicInfo16C65() ); + addMicroInfo( new PicInfo16C71() ); + addMicroInfo( new PicInfo16C72() ); + addMicroInfo( new PicInfo16C73() ); + addMicroInfo( new PicInfo16C712() ); + addMicroInfo( new PicInfo16C716() ); + addMicroInfo( new PicInfo16C74() ); + addMicroInfo( new PicInfo16C84() ); + addMicroInfo( new PicInfo16CR83() ); + addMicroInfo( new PicInfo16F83() ); + addMicroInfo( new PicInfo16CR84() ); + addMicroInfo( new PicInfo16F84() ); + addMicroInfo( new PicInfo16F873() ); + addMicroInfo( new PicInfo16F874() ); + addMicroInfo( new PicInfo16F877() ); + addMicroInfo( new PicInfo17C752() ); + addMicroInfo( new PicInfo17C756() ); + addMicroInfo( new PicInfo17C762() ); + addMicroInfo( new PicInfo17C766() ); + addMicroInfo( new PicInfo18C242() ); + addMicroInfo( new PicInfo18C252() ); + addMicroInfo( new PicInfo18C442() ); + addMicroInfo( new PicInfo18C452() ); + addMicroInfo( new PicInfo18F442() ); + addMicroInfo( new PicInfo18F452() ); +} + +MicroLibrary::~MicroLibrary() +{ + const MicroInfoList::iterator end = m_microInfoList.end(); + for ( MicroInfoList::iterator it = m_microInfoList.begin(); it != end; ++it ) + { + delete *it; + *it = 0l; + } +} + +MicroInfo * const MicroLibrary::microInfoWithID( QString id ) +{ + id = id.upper(); + const MicroInfoList::iterator end = m_microInfoList.end(); + for ( MicroInfoList::iterator it = m_microInfoList.begin(); it != end; ++it ) + { + if ( (*it)->id() == id ) return *it; + } + + return 0L; +} + +void MicroLibrary::addMicroInfo( MicroInfo *microInfo ) +{ + if (microInfo) + m_microInfoList += microInfo; +} + +QStringList MicroLibrary::microIDs( unsigned asmSet, unsigned gpsimSupport, unsigned flowCodeSupport, unsigned microbeSupport ) +{ + QStringList ids; + + const MicroInfoList::iterator end = m_microInfoList.end(); + for ( MicroInfoList::iterator it = m_microInfoList.begin(); it != end; ++it ) + { + MicroInfo * info = *it; + if ( (info->instructionSet()->set() & asmSet) && + (info->gpsimSupport() & gpsimSupport) && + (info->flowcodeSupport() & flowCodeSupport) && + (info->microbeSupport() & microbeSupport) ) + ids << info->id(); + } + return ids; +} diff --git a/src/micro/microlibrary.h b/src/micro/microlibrary.h new file mode 100644 index 0000000..537cf6c --- /dev/null +++ b/src/micro/microlibrary.h @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef MICRoLIBRARY_H +#define PICLIBRARY_H + +#include "asminfo.h" +#include "microinfo.h" + +#include +#include +#include + +class MicroInfo; +class MicroLibrary; +typedef QValueList MicroInfoList; + +inline MicroLibrary *microLibrary(); + +/** +@short Stores all the avaiable PICs (info) +@author David Saxton +*/ +class MicroLibrary +{ + public: + static MicroLibrary * self(); + + ~MicroLibrary(); + + MicroInfo * const microInfoWithID( QString id ); + void addMicroInfo( MicroInfo *microInfo ); + + /** + * Returns a list of micro ids with the given properties (OR'ed + * together). + */ + QStringList microIDs( unsigned asmSet = AsmInfo::AsmSetAll, unsigned gpsimSupport = MicroInfo::AllSupport, unsigned flowCodeSupport = MicroInfo::AllSupport, unsigned microbeSupport = MicroInfo::AllSupport ); + + private: + MicroLibrary(); + static MicroLibrary * m_pSelf; + + MicroInfoList m_microInfoList; + friend MicroLibrary *microLibrary(); +}; + +#endif diff --git a/src/micro/micropackage.cpp b/src/micro/micropackage.cpp new file mode 100644 index 0000000..9becbab --- /dev/null +++ b/src/micro/micropackage.cpp @@ -0,0 +1,109 @@ +/*************************************************************************** + * Copyright (C) 2003 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "micropackage.h" + +#include + +PicPin::PicPin() +{ + pinID = "INVALID"; + type = PicPin::type_bidir; + portName = "INVALID"; + portPosition = -1; +} + + +PicPin::PicPin( const QString &_pinID, PicPin::pin_type _type, const QString &_portName, int _portPosition ) +{ + pinID = _pinID; + type = _type; + portName = _portName; + portPosition = _portPosition; +} + +MicroPackage::MicroPackage( const int pinCount ) +{ + m_numPins = pinCount; +} + +MicroPackage::~MicroPackage() +{ +} + +void MicroPackage::assignPin( int pinPosition, PicPin::pin_type type, const QString& pinID, const QString& portName, int portPosition ) +{ + if ( m_picPinMap.find(pinPosition) != m_picPinMap.end() ) + { + kdError() << "PicDevice::assignBidirPin: Attempting to reset pin "< +#include + +#include + +/** +@author David Saxton +*/ +class PicPin +{ +public: + enum pin_type + { + type_input = 0x1, // Input only pin + type_bidir = 0x2, // Bi-directional (input/output) + type_open = 0x4, // Open collector + type_vss = 0x8, // Voltage source + type_vdd = 0x10, // Voltage drain + type_mclr = 0x20, // Memory clear + type_osc = 0x40 // Oscillator + }; + + PicPin(); + PicPin( const QString &_pinID, PicPin::pin_type _type, const QString &_portName = "", int _portPosition = -1 ); + + PicPin::pin_type type; + + QString pinID; // Id of pin, eg 'MCLR' + + // For bidir (io) pins + QString portName; // Name of port, eg 'PORTA' + int portPosition; // Position in port +}; +typedef QMap PicPinMap; + +/** +@short Describes the PIC package (i.e. pins) +@author David Saxton +*/ +class MicroPackage +{ +public: + MicroPackage( const int pinCount ); + virtual ~MicroPackage(); + + /** + * Assigns a pin to a position in the package. + */ + void assignPin( int pinPosition, PicPin::pin_type type, const QString& pinID, const QString& portName = "", int portPosition = -1); + /** + * Returns the pins of the given type(s). If portName is not specified, all pins will be returned; + * not just those belonging to a given port. pin_type's can be OR'ed together + * e.g. pins( PicPin::type_input | PicPin::type_bidir, "PORTA" ) will return all bidirectional or + * input pins belonging to PORTA. If pinType is 0, then this will return all pins + */ + PicPinMap pins( uint pinType = 0, const QString& portName = "" ); + /** + * Returns just a QStringList of the pin ids. + * @see pins( uint pinType, const QString& portName ) + */ + QStringList pinIDs( uint pinType = 0, const QString& portName = "" ); + /** + * Returns the number of pins of the given type(s) (which can be OR'ed together), with the given + * port name if specified, while avoiding the construction of a new PicPinMap. if pinType is 0, + * then all pin types are considered + * @see pins + */ + int pinCount( uint pinType = 0, const QString& portName = "" ); + /** + * Returns a list of port names, eg 'PORTA', 'PORTB' for the package + */ + QStringList portNames() const { return m_portNames; } + /** + * Returns the number of ports + */ + uint portCount() const { return m_portNames.size(); } + +private: + PicPinMap m_picPinMap; + QStringList m_portNames; + int m_numPins; +}; + +#endif + + diff --git a/src/micro/picinfo.cpp b/src/micro/picinfo.cpp new file mode 100644 index 0000000..2e38c12 --- /dev/null +++ b/src/micro/picinfo.cpp @@ -0,0 +1,24 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "picinfo.h" + +PicInfo::PicInfo() + : MicroInfo() +{ + m_package = 0l; +} + + +PicInfo::~PicInfo() +{ +} + + diff --git a/src/micro/picinfo.h b/src/micro/picinfo.h new file mode 100644 index 0000000..cd9d155 --- /dev/null +++ b/src/micro/picinfo.h @@ -0,0 +1,31 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PICINFO_H +#define PICINFO_H + +#include "microinfo.h" + +/** +This is the base class for all 12bit, 14bit and 16bit PICs. +Thanks go to gpsim & Scott Dattalo for some of the the hierachal PIC class +structure used here :-) +@short Base class for all PICMicros +@author David Saxton +*/ +class PicInfo : public MicroInfo +{ + public: + PicInfo(); + virtual ~PicInfo(); + virtual AsmInfo * instructionSet() = 0; +}; + +#endif diff --git a/src/micro/picinfo12bit.cpp b/src/micro/picinfo12bit.cpp new file mode 100644 index 0000000..12f8dd5 --- /dev/null +++ b/src/micro/picinfo12bit.cpp @@ -0,0 +1,181 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "micropackage.h" +#include "picinfo12bit.h" + +#include +#include + +PicAsm12bit *PicAsm12bit::m_self = 0; +static KStaticDeleter staticDeleter; + +PicAsm12bit *PicAsm12bit::self() +{ + if ( !m_self ) staticDeleter.setObject( m_self, new PicAsm12bit() ); + return m_self; +} + + +PicInfo12bit::PicInfo12bit() + : PicInfo() +{ +} + + +PicInfo12bit::~PicInfo12bit() +{ +} + +PicAsm12bit::PicAsm12bit() + : AsmInfo() +{ + // Byte-orientated file register operations + addInstruction( "ADDWF", 0, "000111dfffff" ); + addInstruction( "ANDWF", 0, "000101dfffff" ); + addInstruction( "CLRF", 0, "0000011fffff" ); + addInstruction( "CLRW", 0, "000001000000" ); + addInstruction( "COMF", 0, "001001dfffff" ); + addInstruction( "DECF", 0, "000011dfffff" ); + addInstruction( "DECFSZ", 0, "001011dfffff" ); + addInstruction( "INCF", 0, "001010dfffff" ); + addInstruction( "INCFSZ", 0, "001111dfffff" ); + addInstruction( "IORWF", 0, "000100dfffff" ); + addInstruction( "MOVF", 0, "001000dfffff" ); + addInstruction( "MOVWF", 0, "0000001fffff" ); + addInstruction( "NOP", 0, "000000000000" ); + addInstruction( "RLF", 0, "001101dfffff" ); + addInstruction( "RRF", 0, "001100dfffff" ); + addInstruction( "SUBWF", 0, "000010dfffff" ); + addInstruction( "SWAPF", 0, "001110dfffff" ); + addInstruction( "XORWF", 0, "000110dfffff" ); + + // Bit-orientated file register operations + addInstruction( "BCF", 0, "0100bbbfffff" ); + addInstruction( "BSF", 0, "0101bbbfffff" ); + addInstruction( "BTFSC", 0, "0110bbbfffff" ); + addInstruction( "BTFSS", 0, "0111bbbfffff" ); + + // Literal and control operations + addInstruction( "ANDLW", 0, "1110kkkkkkkk" ); + addInstruction( "CALL", 0, "1001kkkkkkkk" ); + addInstruction( "CLRWDT", 0, "000000000100" ); + addInstruction( "GOTO", 0, "101kkkkkkkkk" ); + addInstruction( "IORLW", 0, "1101kkkkkkkk" ); + addInstruction( "MOVLW", 0, "1100kkkkkkkk" ); +// addInstruction( "RETFIE", 0, "00000000001001" ); + addInstruction( "OPTION", 0, "000000000010" ); + addInstruction( "RETLW", 0, "1000kkkkkkkk" ); +// addInstruction( "RETURN", 0, "00000000001000" ); + addInstruction( "SLEEP", 0, "000000000011" ); +// addInstruction( "SUBLW", 0, "11110xkkkkkkkk" ); + addInstruction( "TRIS", 0, "000000000fff" ); + addInstruction( "XORLW", 0, "1111kkkkkkkk" ); +} + + + +PicInfo16C54::PicInfo16C54() + : PicInfo12bit() +{ + m_id = "P16C54"; + + delete m_package; + m_package = new MicroPackage(18); + + m_package->assignPin( 17, PicPin::type_bidir, "RA0", "PORTA", 0 ); + m_package->assignPin( 18, PicPin::type_bidir, "RA1", "PORTA", 1 ); + m_package->assignPin( 1, PicPin::type_bidir, "RA2", "PORTA", 2 ); + m_package->assignPin( 2, PicPin::type_bidir, "RA3", "PORTA", 3 ); + m_package->assignPin( 3, PicPin::type_open, "RA4", "PORTA", 4 ); + + m_package->assignPin( 6, PicPin::type_bidir, "RB0", "PORTB", 0 ); + m_package->assignPin( 7, PicPin::type_bidir, "RB1", "PORTB", 1 ); + m_package->assignPin( 8, PicPin::type_bidir, "RB2", "PORTB", 2 ); + m_package->assignPin( 9, PicPin::type_bidir, "RB3", "PORTB", 3 ); + m_package->assignPin( 10, PicPin::type_bidir, "RB4", "PORTB", 4 ); + m_package->assignPin( 11, PicPin::type_bidir, "RB5", "PORTB", 5 ); + m_package->assignPin( 12, PicPin::type_bidir, "RB6", "PORTB", 6 ); + m_package->assignPin( 13, PicPin::type_bidir, "RB7", "PORTB", 7 ); + + m_package->assignPin( 4, PicPin::type_mclr, "MCLR" ); + m_package->assignPin( 5, PicPin::type_vss, "VSS" ); + m_package->assignPin( 14, PicPin::type_vdd, "VDD" ); + m_package->assignPin( 15, PicPin::type_osc, "OSC2" ); + m_package->assignPin( 16, PicPin::type_osc, "OSC1" ); +} + +PicInfo16C54::~PicInfo16C54() +{ + delete m_package; + m_package = 0l; +} + +PicInfo16C55::PicInfo16C55() + : PicInfo12bit() +{ + m_id = "P16C55"; +} +PicInfo16C55::~PicInfo16C55() +{ +} + + +PicInfo12C508::PicInfo12C508() + : PicInfo12bit() +{ + m_id = "P12C508"; + + delete m_package; + m_package = new MicroPackage(8); + + m_package->assignPin( 7, PicPin::type_bidir, "GP0", "GPIO", 0 ); + m_package->assignPin( 6, PicPin::type_bidir, "GP1", "GPIO", 1 ); + m_package->assignPin( 5, PicPin::type_bidir, "GP2", "GPIO", 2 ); + m_package->assignPin( 4, PicPin::type_input, "GP3", "GPIO", 3 ); + m_package->assignPin( 3, PicPin::type_bidir, "GP4", "GPIO", 4 ); + m_package->assignPin( 2, PicPin::type_bidir, "GP5", "GPIO", 5 ); + + m_package->assignPin( 8, PicPin::type_vss, "VSS" ); + m_package->assignPin( 1, PicPin::type_vdd, "VDD" ); +} +PicInfo12C508::~PicInfo12C508() +{ + delete m_package; + m_package = 0l; +} + +PicInfo12C509::PicInfo12C509() + : PicInfo12C508() +{ + m_id = "P12C509"; +} +PicInfo12C509::~PicInfo12C509() +{ +} + +PicInfo12C671::PicInfo12C671() + : PicInfo12C508() +{ + m_id = "P12C671"; +} +PicInfo12C671::~PicInfo12C671() +{ +} + +PicInfo12C672::PicInfo12C672() + : PicInfo12C508() +{ + m_id = "P12C672"; +} +PicInfo12C672::~PicInfo12C672() +{ +} + diff --git a/src/micro/picinfo12bit.h b/src/micro/picinfo12bit.h new file mode 100644 index 0000000..899bfc7 --- /dev/null +++ b/src/micro/picinfo12bit.h @@ -0,0 +1,112 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PICINFO12BIT_H +#define PICINFO12BIT_H + +#include "picinfo.h" +#include "asminfo.h" + +/** +@short 12 Bit PIC Instructions +@author David Saxton + */ +class PicAsm12bit : public AsmInfo +{ + public: + static PicAsm12bit *self(); + virtual Set set() const { return AsmInfo::PIC12; } + + protected: + static PicAsm12bit *m_self; + + private: + PicAsm12bit(); +}; + +/** +@author David Saxton + */ +class PicInfo12bit : public PicInfo +{ + public: + PicInfo12bit(); + ~PicInfo12bit(); + + virtual AsmInfo * instructionSet() { return PicAsm12bit::self(); } +}; + +/** +@author David Saxton + */ +class PicInfo16C54 : public PicInfo12bit +{ + public: + PicInfo16C54(); + ~PicInfo16C54(); + virtual Support gpsimSupport() const { return FullSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16C55 : public PicInfo12bit +{ + public: + PicInfo16C55(); + ~PicInfo16C55(); + virtual Support gpsimSupport() const { return FullSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo12C508 : public PicInfo12bit +{ + public: + PicInfo12C508(); + ~PicInfo12C508(); + virtual Support gpsimSupport() const { return FullSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo12C509 : public PicInfo12C508 +{ + public: + PicInfo12C509(); + ~PicInfo12C509(); + virtual Support gpsimSupport() const { return FullSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo12C671 : public PicInfo12C508 +{ + public: + PicInfo12C671(); + ~PicInfo12C671(); + virtual Support gpsimSupport() const { return NoSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo12C672 : public PicInfo12C508 +{ + public: + PicInfo12C672(); + ~PicInfo12C672(); + virtual Support gpsimSupport() const { return NoSupport; } +}; + +#endif diff --git a/src/micro/picinfo14bit.cpp b/src/micro/picinfo14bit.cpp new file mode 100644 index 0000000..9e75a92 --- /dev/null +++ b/src/micro/picinfo14bit.cpp @@ -0,0 +1,446 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "micropackage.h" +#include "picinfo14bit.h" + +#include +#include + +PicAsm14bit *PicAsm14bit::m_self = 0; +static KStaticDeleter staticDeleter; + +PicAsm14bit *PicAsm14bit::self() +{ + if ( !m_self ) staticDeleter.setObject( m_self, new PicAsm14bit() ); + return m_self; +} + + +PicInfo14bit::PicInfo14bit() + : PicInfo() +{ +} + + +PicInfo14bit::~PicInfo14bit() +{ +} + + +PicAsm14bit::PicAsm14bit() + : AsmInfo() +{ + // Byte-orientated file register operations + addInstruction( "ADDWF", 0, "000111dfffffff" ); + addInstruction( "ANDWF", 0, "000101dfffffff" ); + addInstruction( "CLRF", 0, "0000011fffffff" ); + addInstruction( "CLRW", 0, "0000010xxxxxxx" ); + addInstruction( "COMF", 0, "001001dfffffff" ); + addInstruction( "DECF", 0, "000011dfffffff" ); + addInstruction( "DECFSZ", 0, "001011dfffffff" ); + addInstruction( "INCF", 0, "001010dfffffff" ); + addInstruction( "INCFSZ", 0, "001111dfffffff" ); + addInstruction( "IORWF", 0, "000100dfffffff" ); + addInstruction( "MOVF", 0, "001000dfffffff" ); + addInstruction( "MOVWF", 0, "0000001fffffff" ); + addInstruction( "NOP", 0, "0000000xx00000" ); + addInstruction( "RLF", 0, "001101dfffffff" ); + addInstruction( "RRF", 0, "001100dfffffff" ); + addInstruction( "SUBWF", 0, "000010dfffffff" ); + addInstruction( "SWAPF", 0, "001110dfffffff" ); + addInstruction( "XORWF", 0, "000110dfffffff" ); + + // Bit-orientated file register operations + addInstruction( "BCF", 0, "0100bbbfffffff" ); + addInstruction( "BSF", 0, "0101bbbfffffff" ); + addInstruction( "BTFSC", 0, "0110bbbfffffff" ); + addInstruction( "BTFSS", 0, "0111bbbfffffff" ); + + // Literal and control operations + addInstruction( "ADDLW", 0, "11111xkkkkkkkk" ); + addInstruction( "ANDLW", 0, "111001kkkkkkkk" ); + addInstruction( "CALL", 0, "100kkkkkkkkkkk" ); + addInstruction( "CLRWDT", 0, "00000001100100" ); + addInstruction( "GOTO", 0, "101kkkkkkkkkkk" ); + addInstruction( "IORLW", 0, "111000kkkkkkkk" ); + addInstruction( "MOVLW", 0, "1100xxkkkkkkkk" ); + addInstruction( "RETFIE", 0, "00000000001001" ); + addInstruction( "RETLW", 0, "1101xxkkkkkkkk" ); + addInstruction( "RETURN", 0, "00000000001000" ); + addInstruction( "SLEEP", 0, "00000000000011" ); + addInstruction( "SUBLW", 0, "11110xkkkkkkkk" ); + addInstruction( "XORLW", 0, "111010kkkkkkkk" ); +} + +PicInfo16C8x::PicInfo16C8x() + : PicInfo14bit() +{ + delete m_package; + m_package = new MicroPackage(18); + + m_package->assignPin( 17, PicPin::type_bidir, "RA0", "PORTA", 0 ); + m_package->assignPin( 18, PicPin::type_bidir, "RA1", "PORTA", 1 ); + m_package->assignPin( 1, PicPin::type_bidir, "RA2", "PORTA", 2 ); + m_package->assignPin( 2, PicPin::type_bidir, "RA3", "PORTA", 3 ); + m_package->assignPin( 3, PicPin::type_open, "RA4", "PORTA", 4 ); + + m_package->assignPin( 6, PicPin::type_bidir, "RB0", "PORTB", 0 ); + m_package->assignPin( 7, PicPin::type_bidir, "RB1", "PORTB", 1 ); + m_package->assignPin( 8, PicPin::type_bidir, "RB2", "PORTB", 2 ); + m_package->assignPin( 9, PicPin::type_bidir, "RB3", "PORTB", 3 ); + m_package->assignPin( 10, PicPin::type_bidir, "RB4", "PORTB", 4 ); + m_package->assignPin( 11, PicPin::type_bidir, "RB5", "PORTB", 5 ); + m_package->assignPin( 12, PicPin::type_bidir, "RB6", "PORTB", 6 ); + m_package->assignPin( 13, PicPin::type_bidir, "RB7", "PORTB", 7 ); + + m_package->assignPin( 4, PicPin::type_mclr, "MCLR" ); + m_package->assignPin( 5, PicPin::type_vss, "VSS" ); + m_package->assignPin( 14, PicPin::type_vdd, "VDD" ); + m_package->assignPin( 15, PicPin::type_osc, "OSC2" ); + m_package->assignPin( 16, PicPin::type_osc, "OSC1" ); +} + +PicInfo16C8x::~PicInfo16C8x() +{ + delete m_package; + m_package = 0l; +} + +PicInfo16C84::PicInfo16C84() + : PicInfo16C8x() +{ + m_id = "P16C84"; +} +PicInfo16C84::~PicInfo16C84() +{ +} + +PicInfo16F84::PicInfo16F84() + : PicInfo16C8x() +{ + m_id = "P16F84"; +} +PicInfo16F84::~PicInfo16F84() +{ +} + +PicInfo16CR84::PicInfo16CR84() + : PicInfo16F84() +{ + m_id = "P16CR84"; +} +PicInfo16CR84::~PicInfo16CR84() +{ +} + +PicInfo16F83::PicInfo16F83() + : PicInfo16C8x() +{ + m_id = "P16F83"; +} +PicInfo16F83::~PicInfo16F83() +{ +} + +PicInfo16CR83::PicInfo16CR83() + : PicInfo16F83() +{ + m_id = "P16CR83"; +} +PicInfo16CR83::~PicInfo16CR83() +{ +} + +PicInfo16C61::PicInfo16C61() + : PicInfo16C8x() +{ + m_id = "P16C61"; +} +PicInfo16C61::~PicInfo16C61() +{ +} + +PicInfo16X6X::PicInfo16X6X() + : PicInfo14bit() +{ + m_id = "P16X6X"; +} +PicInfo16X6X::~PicInfo16X6X() +{ +} + +PicInfo16C62::PicInfo16C62() + : PicInfo16X6X() +{ + m_id = "P16C62"; + + delete m_package; + m_package = new MicroPackage(28); + + m_package->assignPin( 2, PicPin::type_bidir, "RA0", "PORTA", 0 ); + m_package->assignPin( 3, PicPin::type_bidir, "RA1", "PORTA", 1 ); + m_package->assignPin( 4, PicPin::type_bidir, "RA2", "PORTA", 2 ); + m_package->assignPin( 5, PicPin::type_bidir, "RA3", "PORTA", 3 ); + m_package->assignPin( 6, PicPin::type_open, "RA4", "PORTA", 4 ); + m_package->assignPin( 7, PicPin::type_bidir, "RA5", "PORTA", 5 ); + + m_package->assignPin( 21, PicPin::type_bidir, "RB0", "PORTB", 0 ); + m_package->assignPin( 22, PicPin::type_bidir, "RB1", "PORTB", 1 ); + m_package->assignPin( 23, PicPin::type_bidir, "RB2", "PORTB", 2 ); + m_package->assignPin( 24, PicPin::type_bidir, "RB3", "PORTB", 3 ); + m_package->assignPin( 25, PicPin::type_bidir, "RB4", "PORTB", 4 ); + m_package->assignPin( 26, PicPin::type_bidir, "RB5", "PORTB", 5 ); + m_package->assignPin( 27, PicPin::type_bidir, "RB6", "PORTB", 6 ); + m_package->assignPin( 28, PicPin::type_bidir, "RB7", "PORTB", 7 ); + + m_package->assignPin( 11, PicPin::type_bidir, "RC0", "PORTC", 0 ); + m_package->assignPin( 12, PicPin::type_bidir, "RC1", "PORTC", 1 ); + m_package->assignPin( 13, PicPin::type_bidir, "RC2", "PORTC", 2 ); + m_package->assignPin( 14, PicPin::type_bidir, "RC3", "PORTC", 3 ); + m_package->assignPin( 15, PicPin::type_bidir, "RC4", "PORTC", 4 ); + m_package->assignPin( 16, PicPin::type_bidir, "RC5", "PORTC", 5 ); + m_package->assignPin( 17, PicPin::type_bidir, "RC6", "PORTC", 6 ); + m_package->assignPin( 18, PicPin::type_bidir, "RC7", "PORTC", 7 ); + + m_package->assignPin( 1, PicPin::type_mclr, "MCLR" ); + m_package->assignPin( 8, PicPin::type_vss, "VSS" ); + m_package->assignPin( 9, PicPin::type_osc, "OSC1" ); + m_package->assignPin( 10, PicPin::type_osc, "OSC2" ); + m_package->assignPin( 19, PicPin::type_vss, "VSS" ); + m_package->assignPin( 20, PicPin::type_vdd, "VDD" ); +} +PicInfo16C62::~PicInfo16C62() +{ + delete m_package; + m_package = 0l; +} + +PicInfo16C63::PicInfo16C63() + : PicInfo16C62() +{ + m_id = "P16C63"; +} +PicInfo16C63::~PicInfo16C63() +{ +} + +PicInfo16C64::PicInfo16C64() + : PicInfo16X6X() +{ + m_id = "P16C64"; + + delete m_package; + m_package = new MicroPackage(40); + + m_package->assignPin( 2, PicPin::type_bidir, "RA0", "PORTA", 0 ); + m_package->assignPin( 3, PicPin::type_bidir, "RA1", "PORTA", 1 ); + m_package->assignPin( 4, PicPin::type_bidir, "RA2", "PORTA", 2 ); + m_package->assignPin( 5, PicPin::type_bidir, "RA3", "PORTA", 3 ); + m_package->assignPin( 6, PicPin::type_open, "RA4", "PORTA", 4 ); + m_package->assignPin( 7, PicPin::type_bidir, "RA5", "PORTB", 5 ); + + m_package->assignPin( 33, PicPin::type_bidir, "RB0", "PORTB", 0 ); + m_package->assignPin( 34, PicPin::type_bidir, "RB1", "PORTB", 1 ); + m_package->assignPin( 35, PicPin::type_bidir, "RB2", "PORTB", 2 ); + m_package->assignPin( 36, PicPin::type_bidir, "RB3", "PORTB", 3 ); + m_package->assignPin( 37, PicPin::type_bidir, "RB4", "PORTB", 4 ); + m_package->assignPin( 38, PicPin::type_bidir, "RB5", "PORTB", 5 ); + m_package->assignPin( 39, PicPin::type_bidir, "RB6", "PORTB", 6 ); + m_package->assignPin( 40, PicPin::type_bidir, "RB7", "PORTB", 7 ); + + m_package->assignPin( 15, PicPin::type_bidir, "RC0", "PORTC", 0 ); + m_package->assignPin( 16, PicPin::type_bidir, "RC1", "PORTC", 1 ); + m_package->assignPin( 17, PicPin::type_bidir, "RC2", "PORTC", 2 ); + m_package->assignPin( 18, PicPin::type_bidir, "RC3", "PORTC", 3 ); + m_package->assignPin( 23, PicPin::type_bidir, "RC4", "PORTC", 4 ); + m_package->assignPin( 24, PicPin::type_bidir, "RC5", "PORTC", 5 ); + m_package->assignPin( 25, PicPin::type_bidir, "RC6", "PORTC", 6 ); + m_package->assignPin( 26, PicPin::type_bidir, "RC7", "PORTC", 7 ); + + m_package->assignPin( 19, PicPin::type_bidir, "RD0", "PORTD", 0 ); + m_package->assignPin( 20, PicPin::type_bidir, "RD1", "PORTD", 1 ); + m_package->assignPin( 21, PicPin::type_bidir, "RD2", "PORTD", 2 ); + m_package->assignPin( 22, PicPin::type_bidir, "RD3", "PORTD", 3 ); + m_package->assignPin( 27, PicPin::type_bidir, "RD4", "PORTD", 4 ); + m_package->assignPin( 28, PicPin::type_bidir, "RD5", "PORTD", 5 ); + m_package->assignPin( 29, PicPin::type_bidir, "RD6", "PORTD", 6 ); + m_package->assignPin( 30, PicPin::type_bidir, "RD7", "PORTD", 7 ); + + m_package->assignPin( 8, PicPin::type_bidir, "RE0", "PORTE", 0 ); + m_package->assignPin( 9, PicPin::type_bidir, "RE1", "PORTE", 1 ); + m_package->assignPin( 10, PicPin::type_bidir, "RE2", "PORTE", 2 ); + + m_package->assignPin( 1, PicPin::type_mclr, "MCLR" ); + m_package->assignPin( 11, PicPin::type_vdd, "VDD" ); + m_package->assignPin( 12, PicPin::type_vss, "VSS" ); + m_package->assignPin( 13, PicPin::type_osc, "OSC1" ); + m_package->assignPin( 14, PicPin::type_osc, "OSC2" ); + m_package->assignPin( 31, PicPin::type_vss, "VSS" ); + m_package->assignPin( 32, PicPin::type_vdd, "VDD" ); +} +PicInfo16C64::~PicInfo16C64() +{ + delete m_package; + m_package = 0l; +} + +PicInfo16C65::PicInfo16C65() + : PicInfo16C64() +{ + m_id = "P16C65"; +} +PicInfo16C65::~PicInfo16C65() +{ +} + +PicInfo16F62x::PicInfo16F62x() + : PicInfo16X6X() +{ + m_id = "P16F62x"; + + delete m_package; + m_package = new MicroPackage(18); + + m_package->assignPin( 17, PicPin::type_bidir, "RA0", "PORTA", 0 ); + m_package->assignPin( 18, PicPin::type_bidir, "RA1", "PORTA", 1 ); + m_package->assignPin( 1, PicPin::type_bidir, "RA2", "PORTA", 2 ); + m_package->assignPin( 2, PicPin::type_bidir, "RA3", "PORTA", 3 ); + m_package->assignPin( 3, PicPin::type_bidir, "RA4", "PORTA", 4 ); + m_package->assignPin( 4, PicPin::type_input, "RA5", "PORTA", 5 ); + m_package->assignPin( 15, PicPin::type_bidir, "RA6", "PORTA", 6 ); + m_package->assignPin( 16, PicPin::type_bidir, "RA7", "PORTA", 7 ); + + m_package->assignPin( 6, PicPin::type_bidir, "RB0", "PORTB", 0 ); + m_package->assignPin( 7, PicPin::type_bidir, "RB1", "PORTB", 1 ); + m_package->assignPin( 8, PicPin::type_bidir, "RB2", "PORTB", 2 ); + m_package->assignPin( 9, PicPin::type_bidir, "RB3", "PORTB", 3 ); + m_package->assignPin( 10, PicPin::type_bidir, "RB4", "PORTB", 4 ); + m_package->assignPin( 11, PicPin::type_bidir, "RB5", "PORTB", 5 ); + m_package->assignPin( 12, PicPin::type_bidir, "RB6", "PORTB", 6 ); + m_package->assignPin( 13, PicPin::type_bidir, "RB7", "PORTB", 7 ); + + m_package->assignPin( 5, PicPin::type_vss, "VSS" ); + m_package->assignPin( 14, PicPin::type_vdd, "VDD" ); +} +PicInfo16F62x::~PicInfo16F62x() +{ + delete m_package; + m_package = 0l; +} + +PicInfo16F627::PicInfo16F627() + : PicInfo16F62x() +{ + m_id = "P16F627"; +} +PicInfo16F627::~PicInfo16F627() +{ +} + +PicInfo16F628::PicInfo16F628() + : PicInfo16F627() +{ + m_id = "P16F628"; +} +PicInfo16F628::~PicInfo16F628() +{ +} + +PicInfo16F648::PicInfo16F648() + : PicInfo16F628() +{ + m_id = "P16F648"; +} +PicInfo16F648::~PicInfo16F648() +{ +} + +PicInfo16C71::PicInfo16C71() + : PicInfo16C61() +{ + m_id = "P16C71"; +} +PicInfo16C71::~PicInfo16C71() +{ +} + +PicInfo16C712::PicInfo16C712() + : PicInfo16C62() +{ + m_id = "P16C712"; +} +PicInfo16C712::~PicInfo16C712() +{ +} + +PicInfo16C716::PicInfo16C716() + : PicInfo16C712() +{ + m_id = "P16C716"; +} +PicInfo16C716::~PicInfo16C716() +{ +} + +PicInfo16C72::PicInfo16C72() + : PicInfo16C62() +{ + m_id = "P16C72"; +} +PicInfo16C72::~PicInfo16C72() +{ +} + +PicInfo16C73::PicInfo16C73() + : PicInfo16C63() +{ + m_id = "P16C73"; +} +PicInfo16C73::~PicInfo16C73() +{ +} + +PicInfo16C74::PicInfo16C74() + : PicInfo16C65() +{ + m_id = "P16C74"; +} +PicInfo16C74::~PicInfo16C74() +{ +} + +PicInfo16F873::PicInfo16F873() + : PicInfo16C73() +{ + m_id = "P16F873"; +} +PicInfo16F873::~PicInfo16F873() +{ +} + +PicInfo16F874::PicInfo16F874() + : PicInfo16C74() +{ + m_id = "P16F874"; +} +PicInfo16F874::~PicInfo16F874() +{ +} + +PicInfo16F877::PicInfo16F877() + : PicInfo16F874() +{ + m_id = "P16F877"; +} +PicInfo16F877::~PicInfo16F877() +{ +} + diff --git a/src/micro/picinfo14bit.h b/src/micro/picinfo14bit.h new file mode 100644 index 0000000..4f20cb1 --- /dev/null +++ b/src/micro/picinfo14bit.h @@ -0,0 +1,330 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PICINFO14BIT_H +#define PICINFO14BIT_H + +#include "picinfo.h" +#include "asminfo.h" + +/** +@short 14 Bit PIC Instructions +@author David Saxton + */ +class PicAsm14bit : public AsmInfo +{ + public: + static PicAsm14bit *self(); + virtual Set set() const { return AsmInfo::PIC14; } + + protected: + static PicAsm14bit *m_self; + + private: + PicAsm14bit(); +}; + +/** +@author David Saxton + */ +class PicInfo14bit : public PicInfo +{ + public: + PicInfo14bit(); + ~PicInfo14bit(); + + virtual AsmInfo* instructionSet() { return PicAsm14bit::self(); } +}; + +/** +@author David Saxton + */ +class PicInfo16C8x : public PicInfo14bit +{ + public: + PicInfo16C8x(); + ~PicInfo16C8x(); +}; + +/** +@author David Saxton + */ +class PicInfo16C84 : public PicInfo16C8x +{ + public: + PicInfo16C84(); + ~PicInfo16C84(); + virtual Support gpsimSupport() const { return FullSupport; } + virtual Support microbeSupport() const { return FullSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16F84 : public PicInfo16C8x +{ + public: + PicInfo16F84(); + ~PicInfo16F84(); + virtual Support gpsimSupport() const { return FullSupport; } + virtual Support flowcodeSupport() const { return FullSupport; } + virtual Support microbeSupport() const { return FullSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16CR84 : public PicInfo16F84 +{ + public: + PicInfo16CR84(); + ~PicInfo16CR84(); + virtual Support gpsimSupport() const { return FullSupport; } + virtual Support flowcodeSupport() const { return NoSupport; } + virtual Support microbeSupport() const { return NoSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16F83 : public PicInfo16C8x +{ + public: + PicInfo16F83(); + ~PicInfo16F83(); + virtual Support gpsimSupport() const { return FullSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16CR83 : public PicInfo16F83 +{ + public: + PicInfo16CR83(); + ~PicInfo16CR83(); + virtual Support gpsimSupport() const { return FullSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16C61 : public PicInfo16C8x +{ + public: + PicInfo16C61(); + ~PicInfo16C61(); + virtual Support gpsimSupport() const { return FullSupport; } +}; + + +/** +@author David Saxton + */ +class PicInfo16X6X : public PicInfo14bit +{ + public: + PicInfo16X6X(); + ~PicInfo16X6X(); + virtual Support gpsimSupport() const { return NoSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16C62 : public PicInfo16X6X +{ + public: + PicInfo16C62(); + ~PicInfo16C62(); + virtual Support gpsimSupport() const { return FullSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16C63 : public PicInfo16C62 +{ + public: + PicInfo16C63(); + ~PicInfo16C63(); + virtual Support gpsimSupport() const { return FullSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16C64 : public PicInfo16X6X +{ + public: + PicInfo16C64(); + ~PicInfo16C64(); + virtual Support gpsimSupport() const { return PartialSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16C65 : public PicInfo16C64 +{ + public: + PicInfo16C65(); + ~PicInfo16C65(); + virtual Support gpsimSupport() const { return PartialSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16F62x : public PicInfo16X6X +{ + public: + PicInfo16F62x(); + ~PicInfo16F62x(); + virtual Support gpsimSupport() const { return NoSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16F627 : public PicInfo16F62x +{ + public: + PicInfo16F627(); + ~PicInfo16F627(); + virtual Support gpsimSupport() const { return FullSupport; } + virtual Support flowcodeSupport() const { return PartialSupport; } + virtual Support microbeSupport() const { return FullSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16F628 : public PicInfo16F627 +{ + public: + PicInfo16F628(); + ~PicInfo16F628(); + virtual Support gpsimSupport() const { return FullSupport; } + virtual Support flowcodeSupport() const { return PartialSupport; } + virtual Support microbeSupport() const { return FullSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16F648 : public PicInfo16F628 +{ + public: + PicInfo16F648(); + ~PicInfo16F648(); + virtual Support gpsimSupport() const { return NoSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16C71 : public PicInfo16C61 +{ + public: + PicInfo16C71(); + ~PicInfo16C71(); + virtual Support gpsimSupport() const { return FullSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16C712 : public PicInfo16C62 +{ + public: + PicInfo16C712(); + ~PicInfo16C712(); + virtual Support gpsimSupport() const { return FullSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16C716 : public PicInfo16C712 +{ + public: + PicInfo16C716(); + ~PicInfo16C716(); + virtual Support gpsimSupport() const { return FullSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16C72 : public PicInfo16C62 +{ + public: + PicInfo16C72(); + ~PicInfo16C72(); + virtual Support gpsimSupport() const { return PartialSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16C73 : public PicInfo16C63 +{ + public: + PicInfo16C73(); + ~PicInfo16C73(); + virtual Support gpsimSupport() const { return PartialSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16C74 : public PicInfo16C65 +{ + public: + PicInfo16C74(); + ~PicInfo16C74(); + virtual Support gpsimSupport() const { return PartialSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16F873 : public PicInfo16C73 +{ + public: + PicInfo16F873(); + ~PicInfo16F873(); + virtual Support gpsimSupport() const { return PartialSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16F874 : public PicInfo16C74 +{ + public: + PicInfo16F874(); + ~PicInfo16F874(); + virtual Support gpsimSupport() const { return PartialSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo16F877 : public PicInfo16F874 +{ + public: + PicInfo16F877(); + ~PicInfo16F877(); + virtual Support gpsimSupport() const { return PartialSupport; } +}; + +#endif diff --git a/src/micro/picinfo16bit.cpp b/src/micro/picinfo16bit.cpp new file mode 100644 index 0000000..cc7663f --- /dev/null +++ b/src/micro/picinfo16bit.cpp @@ -0,0 +1,345 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "micropackage.h" +#include "picinfo16bit.h" + +#include +#include + +PicAsm16bit *PicAsm16bit::m_self = 0; +static KStaticDeleter staticDeleter; + +PicAsm16bit *PicAsm16bit::self() +{ + if ( !m_self ) staticDeleter.setObject( m_self, new PicAsm16bit() ); + return m_self; +} + +PicInfo16bit::PicInfo16bit() + : PicInfo() +{ +} + + +PicInfo16bit::~PicInfo16bit() +{ +} + + + +PicAsm16bit::PicAsm16bit() + : AsmInfo() +{ + // TODO 16 bit Asm instructions for PICs + + // Byte-orientated file register operations + addInstruction( "ADDWF", 0, "000111dfffffff" ); + addInstruction( "ANDWF", 0, "000101dfffffff" ); + addInstruction( "CLRF", 0, "0000011fffffff" ); + addInstruction( "CLRW", 0, "0000010xxxxxxx" ); + addInstruction( "COMF", 0, "001001dfffffff" ); + addInstruction( "DECF", 0, "000011dfffffff" ); + addInstruction( "DECFSZ", 0, "001011dfffffff" ); + addInstruction( "INCF", 0, "001010dfffffff" ); + addInstruction( "INCFSZ", 0, "001111dfffffff" ); + addInstruction( "IORWF", 0, "000100dfffffff" ); + addInstruction( "MOVF", 0, "001000dfffffff" ); + addInstruction( "MOVWF", 0, "0000001fffffff" ); + addInstruction( "NOP", 0, "0000000xx00000" ); + addInstruction( "RLF", 0, "001101dfffffff" ); + addInstruction( "RRF", 0, "001100dfffffff" ); + addInstruction( "SUBWF", 0, "000010dfffffff" ); + addInstruction( "SWAPF", 0, "001110dfffffff" ); + addInstruction( "XORWF", 0, "000110dfffffff" ); + + // Bit-orientated file register operations + addInstruction( "BCF", 0, "0100bbbfffffff" ); + addInstruction( "BSF", 0, "0101bbbfffffff" ); + addInstruction( "BTFSC", 0, "0110bbbfffffff" ); + addInstruction( "BTFSS", 0, "0111bbbfffffff" ); + + // Literal and control operations + addInstruction( "ADDLW", 0, "11111xkkkkkkkk" ); + addInstruction( "ANDLW", 0, "111001kkkkkkkk" ); + addInstruction( "CALL", 0, "100kkkkkkkkkkk" ); + addInstruction( "CLRWDT", 0, "00000001100100" ); + addInstruction( "GOTO", 0, "101kkkkkkkkkkk" ); + addInstruction( "IORLW", 0, "111000kkkkkkkk" ); + addInstruction( "MOVLW", 0, "1100xxkkkkkkkk" ); + addInstruction( "RETFIE", 0, "00000000001001" ); + addInstruction( "RETLW", 0, "1101xxkkkkkkkk" ); + addInstruction( "RETURN", 0, "00000000001000" ); + addInstruction( "SLEEP", 0, "00000000000011" ); + addInstruction( "SUBLW", 0, "11110xkkkkkkkk" ); + addInstruction( "XORLW", 0, "111010kkkkkkkk" ); +} + + +PicInfo17C7xx::PicInfo17C7xx() + : PicInfo16bit() +{ + m_id = "P17C7xx"; +} +PicInfo17C7xx::~PicInfo17C7xx() +{ +} + +PicInfo17C75x::PicInfo17C75x() + : PicInfo17C7xx() +{ + m_id = "P17C75x"; +} +PicInfo17C75x::~PicInfo17C75x() +{ +} + +PicInfo17C752::PicInfo17C752() + : PicInfo17C75x() +{ + m_id = "P17C752"; +} +PicInfo17C752::~PicInfo17C752() +{ +} + +PicInfo17C756::PicInfo17C756() + : PicInfo17C75x() +{ + m_id = "P17C756"; +} +PicInfo17C756::~PicInfo17C756() +{ +} + +PicInfo17C756A::PicInfo17C756A() + : PicInfo17C75x() +{ + m_id = "P17C756A"; +} +PicInfo17C756A::~PicInfo17C756A() +{ +} + +PicInfo17C762::PicInfo17C762() + : PicInfo17C75x() +{ + m_id = "P17C762"; +} +PicInfo17C762::~PicInfo17C762() +{ +} + +PicInfo17C766::PicInfo17C766() + : PicInfo17C75x() +{ + m_id = "P17C766"; +} +PicInfo17C766::~PicInfo17C766() +{ +} + +PicInfo18Cxx2::PicInfo18Cxx2() + : PicInfo16bit() +{ + m_id = "P18Cxx2"; +} +PicInfo18Cxx2::~PicInfo18Cxx2() +{ +} + +PicInfo18C2x2::PicInfo18C2x2() + : PicInfo16bit() +{ + m_id = "P18C2x2"; +} +PicInfo18C2x2::~PicInfo18C2x2() +{ +} + +PicInfo18C242::PicInfo18C242() + : PicInfo18C2x2() +{ + m_id = "P18C242"; +} +PicInfo18C242::~PicInfo18C242() +{ +} + +PicInfo18C252::PicInfo18C252() + : PicInfo18C242() +{ + m_id = "P18C252"; +} +PicInfo18C252::~PicInfo18C252() +{ +} + +PicInfo18C4x2::PicInfo18C4x2() + : PicInfo16bit() +{ + m_id = "P18C4x2"; + + delete m_package; + m_package = new MicroPackage(40); + + m_package->assignPin( 2, PicPin::type_bidir, "RA0", "PORTA", 0 ); + m_package->assignPin( 3, PicPin::type_bidir, "RA1", "PORTA", 1 ); + m_package->assignPin( 4, PicPin::type_bidir, "RA2", "PORTA", 2 ); + m_package->assignPin( 5, PicPin::type_bidir, "RA3", "PORTA", 3 ); + m_package->assignPin( 6, PicPin::type_open, "RA4", "PORTA", 4 ); + m_package->assignPin( 7, PicPin::type_bidir, "RA5", "PORTB", 5 ); + + m_package->assignPin( 33, PicPin::type_bidir, "RB0", "PORTB", 0 ); + m_package->assignPin( 34, PicPin::type_bidir, "RB1", "PORTB", 1 ); + m_package->assignPin( 35, PicPin::type_bidir, "RB2", "PORTB", 2 ); + m_package->assignPin( 36, PicPin::type_bidir, "RB3", "PORTB", 3 ); + m_package->assignPin( 37, PicPin::type_bidir, "RB4", "PORTB", 4 ); + m_package->assignPin( 38, PicPin::type_bidir, "RB5", "PORTB", 5 ); + m_package->assignPin( 39, PicPin::type_bidir, "RB6", "PORTB", 6 ); + m_package->assignPin( 40, PicPin::type_bidir, "RB7", "PORTB", 7 ); + + m_package->assignPin( 15, PicPin::type_bidir, "RC0", "PORTC", 0 ); + m_package->assignPin( 16, PicPin::type_bidir, "RC1", "PORTC", 1 ); + m_package->assignPin( 17, PicPin::type_bidir, "RC2", "PORTC", 2 ); + m_package->assignPin( 18, PicPin::type_bidir, "RC3", "PORTC", 3 ); + m_package->assignPin( 23, PicPin::type_bidir, "RC4", "PORTC", 4 ); + m_package->assignPin( 24, PicPin::type_bidir, "RC5", "PORTC", 5 ); + m_package->assignPin( 25, PicPin::type_bidir, "RC6", "PORTC", 6 ); + m_package->assignPin( 26, PicPin::type_bidir, "RC7", "PORTC", 7 ); + + m_package->assignPin( 19, PicPin::type_bidir, "RD0", "PORTD", 0 ); + m_package->assignPin( 20, PicPin::type_bidir, "RD1", "PORTD", 1 ); + m_package->assignPin( 21, PicPin::type_bidir, "RD2", "PORTD", 2 ); + m_package->assignPin( 22, PicPin::type_bidir, "RD3", "PORTD", 3 ); + m_package->assignPin( 27, PicPin::type_bidir, "RD4", "PORTD", 4 ); + m_package->assignPin( 28, PicPin::type_bidir, "RD5", "PORTD", 5 ); + m_package->assignPin( 29, PicPin::type_bidir, "RD6", "PORTD", 6 ); + m_package->assignPin( 30, PicPin::type_bidir, "RD7", "PORTD", 7 ); + + m_package->assignPin( 8, PicPin::type_bidir, "RE0", "PORTE", 0 ); + m_package->assignPin( 9, PicPin::type_bidir, "RE1", "PORTE", 1 ); + m_package->assignPin( 10, PicPin::type_bidir, "RE2", "PORTE", 2 ); + + m_package->assignPin( 1, PicPin::type_mclr, "MCLR" ); + m_package->assignPin( 11, PicPin::type_vdd, "VDD" ); + m_package->assignPin( 12, PicPin::type_vss, "VSS" ); + m_package->assignPin( 13, PicPin::type_osc, "OSC1" ); + m_package->assignPin( 14, PicPin::type_osc, "OSC2" ); + m_package->assignPin( 31, PicPin::type_vss, "VSS" ); + m_package->assignPin( 32, PicPin::type_vdd, "VDD" ); +} + +PicInfo18C4x2::~PicInfo18C4x2() +{ + delete m_package; + m_package = 0l; +} + +PicInfo18C442::PicInfo18C442() + : PicInfo18C4x2() +{ + m_id = "P18C442"; +} +PicInfo18C442::~PicInfo18C442() +{ +} + +PicInfo18C452::PicInfo18C452() + : PicInfo18C442() +{ + m_id = "P18C452"; +} +PicInfo18C452::~PicInfo18C452() +{ +} + +PicInfo18F442::PicInfo18F442() + : PicInfo18C442() +{ + m_id = "P18F442"; +} +PicInfo18F442::~PicInfo18F442() +{ +} + +PicInfo18F248::PicInfo18F248() + : PicInfo18F442() +{ + m_id = "P18F248"; +} +PicInfo18F248::~PicInfo18F248() +{ +} + +PicInfo18F452::PicInfo18F452() + : PicInfo18F442() +{ + m_id = "P18F452"; +} +PicInfo18F452::~PicInfo18F452() +{ +} + +PicInfo18Fxx20::PicInfo18Fxx20() + : PicInfo16bit() +{ + m_id = "P18Fxx20"; +} +PicInfo18Fxx20::~PicInfo18Fxx20() +{ +} + +PicInfo18F1220::PicInfo18F1220() + : PicInfo18Fxx20() +{ + m_id = "P18F1220"; + + delete m_package; + m_package = new MicroPackage(18); + + m_package->assignPin( 1, PicPin::type_bidir, "RA0", "PORTA", 0 ); + m_package->assignPin( 2, PicPin::type_bidir, "RA1", "PORTA", 1 ); + m_package->assignPin( 6, PicPin::type_bidir, "RA2", "PORTA", 2 ); + m_package->assignPin( 7, PicPin::type_bidir, "RA3", "PORTA", 3 ); + m_package->assignPin( 3, PicPin::type_open, "RA4", "PORTA", 4 ); + m_package->assignPin( 4, PicPin::type_open, "RA5", "PORTA", 5 ); + m_package->assignPin( 15, PicPin::type_open, "RA6", "PORTA", 6 ); + m_package->assignPin( 16, PicPin::type_open, "RA7", "PORTA", 7 ); + + m_package->assignPin( 8, PicPin::type_bidir, "RB0", "PORTB", 0 ); + m_package->assignPin( 9, PicPin::type_bidir, "RB1", "PORTB", 1 ); + m_package->assignPin( 17, PicPin::type_bidir, "RB2", "PORTB", 2 ); + m_package->assignPin( 18, PicPin::type_bidir, "RB3", "PORTB", 3 ); + m_package->assignPin( 10, PicPin::type_bidir, "RB4", "PORTB", 4 ); + m_package->assignPin( 11, PicPin::type_bidir, "RB5", "PORTB", 5 ); + m_package->assignPin( 12, PicPin::type_bidir, "RB6", "PORTB", 6 ); + m_package->assignPin( 13, PicPin::type_bidir, "RB7", "PORTB", 7 ); + + m_package->assignPin( 5, PicPin::type_vss, "VSS" ); + m_package->assignPin( 14, PicPin::type_vdd, "VDD" ); +} + +PicInfo18F1220::~PicInfo18F1220() +{ + delete m_package; + m_package = 0l; +} + +PicInfo18F1320::PicInfo18F1320() + : PicInfo18F1220() +{ + m_id = "P18F1320"; +} +PicInfo18F1320::~PicInfo18F1320() +{ +} + + diff --git a/src/micro/picinfo16bit.h b/src/micro/picinfo16bit.h new file mode 100644 index 0000000..975c23c --- /dev/null +++ b/src/micro/picinfo16bit.h @@ -0,0 +1,266 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PICINFO16BIT_H +#define PICINFO16BIT_H + +#include "picinfo.h" +#include "asminfo.h" + +/** +@short 16 Bit PIC Instructions +@author David Saxton + */ +class PicAsm16bit : public AsmInfo +{ + public: + static PicAsm16bit *self(); + virtual Set set() const { return AsmInfo::PIC16; } + + protected: + static PicAsm16bit *m_self; + + private: + PicAsm16bit(); +}; + +/** +@author David Saxton + */ +class PicInfo16bit : public PicInfo +{ + public: + PicInfo16bit(); + ~PicInfo16bit(); + + virtual AsmInfo * instructionSet() { return PicAsm16bit::self(); } +}; + +/** +@author David Saxton + */ +class PicInfo17C7xx : public PicInfo16bit +{ + public: + PicInfo17C7xx(); + ~PicInfo17C7xx(); + virtual Support gpsimSupport() const { return NoSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo17C75x : public PicInfo17C7xx +{ + public: + PicInfo17C75x(); + ~PicInfo17C75x(); + virtual Support gpsimSupport() const { return NoSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo17C752 : public PicInfo17C75x +{ + public: + PicInfo17C752(); + ~PicInfo17C752(); + virtual Support gpsimSupport() const { return PartialSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo17C756 : public PicInfo17C75x +{ + public: + PicInfo17C756(); + ~PicInfo17C756(); + virtual Support gpsimSupport() const { return PartialSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo17C756A : public PicInfo17C75x +{ + public: + PicInfo17C756A(); + ~PicInfo17C756A(); + virtual Support gpsimSupport() const { return NoSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo17C762 : public PicInfo17C75x +{ + public: + PicInfo17C762(); + ~PicInfo17C762(); + virtual Support gpsimSupport() const { return PartialSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo17C766 : public PicInfo17C75x +{ + public: + PicInfo17C766(); + ~PicInfo17C766(); + virtual Support gpsimSupport() const { return PartialSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo18Cxx2 : public PicInfo16bit +{ + public: + PicInfo18Cxx2(); + ~PicInfo18Cxx2(); + virtual Support gpsimSupport() const { return NoSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo18C2x2 : public PicInfo16bit +{ + public: + PicInfo18C2x2(); + ~PicInfo18C2x2(); + virtual Support gpsimSupport() const { return NoSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo18C242 : public PicInfo18C2x2 +{ + public: + PicInfo18C242(); + ~PicInfo18C242(); + virtual Support gpsimSupport() const { return PartialSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo18C252 : public PicInfo18C242 +{ + public: + PicInfo18C252(); + ~PicInfo18C252(); + virtual Support gpsimSupport() const { return PartialSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo18C4x2 : public PicInfo16bit +{ + public: + PicInfo18C4x2(); + ~PicInfo18C4x2(); + virtual Support gpsimSupport() const { return NoSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo18C442 : public PicInfo18C4x2 +{ + public: + PicInfo18C442(); + ~PicInfo18C442(); + virtual Support gpsimSupport() const { return PartialSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo18C452 : public PicInfo18C442 +{ + public: + PicInfo18C452(); + ~PicInfo18C452(); + virtual Support gpsimSupport() const { return PartialSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo18F442 : public PicInfo18C442 +{ + public: + PicInfo18F442(); + ~PicInfo18F442(); + virtual Support gpsimSupport() const { return PartialSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo18F248 : public PicInfo18F442 +{ + public: + PicInfo18F248(); + ~PicInfo18F248(); + virtual Support gpsimSupport() const { return NoSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo18F452 : public PicInfo18F442 +{ + public: + PicInfo18F452(); + ~PicInfo18F452(); + virtual Support gpsimSupport() const { return PartialSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo18Fxx20 : public PicInfo16bit +{ + public: + PicInfo18Fxx20(); + ~PicInfo18Fxx20(); + virtual Support gpsimSupport() const { return NoSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo18F1220 : public PicInfo18Fxx20 +{ + public: + PicInfo18F1220(); + ~PicInfo18F1220(); + virtual Support gpsimSupport() const { return NoSupport; } +}; + +/** +@author David Saxton + */ +class PicInfo18F1320 : public PicInfo18F1220 +{ + public: + PicInfo18F1320(); + ~PicInfo18F1320(); + virtual Support gpsimSupport() const { return NoSupport; } +}; + +#endif diff --git a/src/microbe.xml b/src/microbe.xml new file mode 100644 index 0000000..0168c9e --- /dev/null +++ b/src/microbe.xml @@ -0,0 +1,139 @@ + + + + + + + asm + + high + low + + for + to + step + + if + then + else + + while + + alias + repeat + until + end + + + call + goto + delay + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/microsettings.cpp b/src/microsettings.cpp new file mode 100644 index 0000000..4554dc9 --- /dev/null +++ b/src/microsettings.cpp @@ -0,0 +1,338 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "itemdocumentdata.h" +#include "microinfo.h" +#include "micropackage.h" +#include "pinmapping.h" + + +//BEGIN class VariableInfo +VariableInfo::VariableInfo() +{ + type = MicroSettings::vt_unknown; + value = QVariant(0); + initAtStart = false; + permanent = false; +} + +void VariableInfo::setValue( const QVariant & _value ) +{ + value = _value; +} + +QString VariableInfo::valueAsString() const +{ + if ( value.canCast(QVariant::String) ) return value.toString(); + if ( value.canCast(QVariant::Int) ) return QString::number(value.toInt()); + return "0"; +} +//END class VariableInfo + + + +//BEGIN class PinSettings +PinSettings::PinSettings() + : QObject() +{ + m_type = PinSettings::pt_input; + m_state = PinSettings::ps_off; + m_id = "pin"; +} + +PinSettings::PinSettings( PinSettings::pin_type _type, PinSettings::pin_state _state, const QString &id, const QString &port ) +{ + m_type = _type; + m_state = _state; + m_id = id; + m_port = port; +} + + +void PinSettings::setType( PinSettings::pin_type type ) +{ + if ( m_type == type ) + return; + m_type = type; + emit settingsChanged(); +} + + +void PinSettings::setState( PinSettings::pin_state state ) +{ + if ( m_state == state) + return; + m_state = state; + emit settingsChanged(); +} +//END class PinSettings + + + +//BEGIN class MicroSettings +MicroSettings::MicroSettings( MicroInfo * microInfo ) +{ + _microInfo = microInfo; + + QStringList portNames = _microInfo->package()->portNames(); + const QStringList::iterator portNamesEnd = portNames.end(); + for ( QStringList::iterator it = portNames.begin(); it != portNamesEnd; ++it ) + { + PinSettingsList portPins; + QStringList pinIDs; + pinIDs = _microInfo->package()->pinIDs( PicPin::type_bidir | PicPin::type_open, *it ); + pinIDs.sort(); + const int numPins = pinIDs.size(); + for ( int i=0; isetType(type); +} + +void MicroSettings::setPinState( const QString &id, PinSettings::pin_state state ) +{ + PinSettings *pin = pinWithID(id); + if (pin) + pin->setState(state); +} + + +PinSettings* MicroSettings::pinWithID( const QString &id ) +{ + const PinSettingsList::iterator pinListEnd = m_pinSettingsList.end(); + for ( PinSettingsList::iterator it = m_pinSettingsList.begin(); it != pinListEnd; ++it ) + { + if ( (*it)->id() == id ) return *it; + } + return 0L; +} + +int MicroSettings::portState( const QString &port ) +{ + if ( microInfo()->package()->portNames().findIndex(port) == -1 ) return -1; + + int pinPower = 1; + int num = 0; + + const PinSettingsList::iterator pinListEnd = m_pinSettingsList.end(); + for ( PinSettingsList::iterator it = m_pinSettingsList.begin(); it != pinListEnd; ++it ) + { + if ( (*it)->port() == port ) + { + if ( (*it)->state() == PinSettings::ps_on ) num += pinPower; +// cout << "(*it)->state()="<<(*it)->state()<package()->portNames().findIndex(port) == -1 ) return -1; + + int pinPower = 1; + int num = 0; + + const PinSettingsList::iterator pinListEnd = m_pinSettingsList.end(); + for ( PinSettingsList::iterator it = m_pinSettingsList.begin(); it != pinListEnd; ++it ) + { + if ( (*it)->port() == port ) + { + if ( (*it)->type() == PinSettings::pt_input ) num += pinPower; + pinPower *= 2; + } + } + + return num; +} + +void MicroSettings::setPortState( const QString &port, int state ) +{ + PortList::iterator plit = m_ports.find(port); + if ( plit == m_ports.end() ) return; + + const PinSettingsList::iterator plitEnd = plit.data().end(); + for ( PinSettingsList::iterator it = plit.data().begin(); it != plitEnd; ++it ) + { +// cout << "state="<setState( (state%2 == 1) ? PinSettings::ps_on : PinSettings::ps_off ); +// cout << "(*it)->state()="<<(*it)->state()<setType( (type%2 == 1) ? PinSettings::pt_input : PinSettings::pt_output ); + type /= 2; + } +} + + +MicroData MicroSettings::microData() const +{ + MicroData data; + data.id = microInfo()->id(); + data.pinMappings = pinMappings(); + + const PinSettingsList::const_iterator pinListEnd = m_pinSettingsList.end(); + for ( PinSettingsList::const_iterator it = m_pinSettingsList.begin(); it != pinListEnd; ++it ) + { + data.pinMap[(*it)->id()].type = (*it)->type(); + data.pinMap[(*it)->id()].state= (*it)->state(); + } + + const VariableMap::const_iterator variableMapEnd = m_variableMap.end(); + for ( VariableMap::const_iterator it = m_variableMap.begin(); it != variableMapEnd; ++it ) + { + if ( it.data().permanent ) + data.variableMap[it.key()] = it.data().valueAsString(); + } + + return data; +} + + +void MicroSettings::restoreFromMicroData( const MicroData µData ) +{ + setPinMappings( microData.pinMappings ); + + const PinDataMap::const_iterator pinMapEnd = microData.pinMap.end(); + for ( PinDataMap::const_iterator it = microData.pinMap.begin(); it != pinMapEnd; ++it ) + { + PinSettings *pin = pinWithID(it.key()); + if (pin) + { + pin->setState( it.data().state ); + pin->setType( it.data().type ); + } + } + + const QStringMap::const_iterator variableMapEnd = microData.variableMap.end(); + for ( QStringMap::const_iterator it = microData.variableMap.begin(); it != variableMapEnd; ++it ) + { + setVariable( it.key(), it.data(), true ); + } +} + + +void MicroSettings::setVariable( const QString &name, QVariant value, bool permanent ) +{ + if ( name.isNull() ) return; + VariableMap::iterator it = m_variableMap.find(name); + if ( it != m_variableMap.end() ) + { + it.data().setValue(value); + it.data().permanent = permanent; + it.data().initAtStart = permanent; + } + else + { + VariableInfo info; + info.setValue(value); + info.permanent = permanent; + info.initAtStart = permanent; + m_variableMap[name] = info; + } +} + + +QStringList MicroSettings::variableNames() +{ + QStringList list; + const VariableMap::iterator variableMapEnd = m_variableMap.end(); + for ( VariableMap::iterator it = m_variableMap.begin(); it != variableMapEnd; ++it ) + { + list += it.key(); + } + return list; +} + + +VariableInfo* MicroSettings::variableInfo( const QString &name ) +{ + if ( name.isNull() ) return 0l; + VariableMap::iterator it = m_variableMap.find(name); + if ( it != m_variableMap.end() ) { + return &(it.data()); + } else { + return 0l; + } +} + + +bool MicroSettings::deleteVariable( const QString &name ) +{ + if ( name.isNull() ) return false; + VariableMap::iterator it = m_variableMap.find(name); + if ( it != m_variableMap.end() ) + { + m_variableMap.erase(it); + return true; + } else { + return false; + } +} + + +void MicroSettings::removeAllVariables() +{ + m_variableMap.clear(); +} + + +PinMapping MicroSettings::pinMapping( const QString & id ) const +{ + return m_pinMappings[id]; +} + + +void MicroSettings::setPinMappings( const PinMappingMap & pinMappings ) +{ + m_pinMappings = pinMappings; + emit pinMappingsChanged(); +} + + +PinMappingMap MicroSettings::pinMappings() const +{ + return m_pinMappings; +} +//END class MicroSettings + + diff --git a/src/microsettings.h b/src/microsettings.h new file mode 100644 index 0000000..d960f10 --- /dev/null +++ b/src/microsettings.h @@ -0,0 +1,211 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef MICROSETTINGS_H +#define MICROSETTINGS_H + +#include +#include + +class QString; +class QVariant; +class MicroData; +class MicroInfo; + +class VariableInfo +{ +public: + VariableInfo(); + + // Returns the value as a string + QString valueAsString() const; + + // MicroSettings::VariableType (don't rely on this just yet...) + int type; + + // Sets the value + void setValue( const QVariant & value ); + + // If true, the variable will be initialised at the start of the FlowCode + // to the given value + bool initAtStart; + + // True if the variable was "created" by the user in the variable dialog, + // as opposed to being from a variable name entry box + bool permanent; + +private: + QVariant value; +}; + + +typedef QMap< QString, VariableInfo > VariableMap; // Variable name, variable info + + +/** +@short Stores pic pin settings - type/state +@author David Saxton +*/ +class PinSettings : public QObject +{ + Q_OBJECT + public: + enum pin_type + { + pt_input, + pt_output + }; + + enum pin_state + { + ps_on, + ps_off + }; + + PinSettings(); + PinSettings( PinSettings::pin_type _type, PinSettings::pin_state _state, const QString &id, const QString &port ); + + PinSettings::pin_type type() const { return m_type; } + PinSettings::pin_state state() const { return m_state; } + QString id() const { return m_id; } + QString port() const { return m_port; } + + void setType( PinSettings::pin_type type ); + void setState( PinSettings::pin_state state ); + + signals: + /** + * Emitted when either the type or the state is changed. + */ + void settingsChanged(); + + private: + PinSettings::pin_type m_type; + PinSettings::pin_state m_state; + QString m_id; + QString m_port; +}; +typedef QValueList PinSettingsList; + +class PinMapping; +typedef QMap< QString, PinMapping > PinMappingMap; +typedef QMap< QString, PinSettingsList > PortList; + +/** +This class stores PIC settings that are specific to the PIC program being devloped. +This includes such things as port settings and variable settings. +This is different from PIC info, which includes stuff such as PIC pin names + +@short Stores Pic settings - pin settings +@author David Saxton +*/ +class MicroSettings : public QObject +{ + Q_OBJECT +public: + enum VariableType + { + vt_signedInteger, + vt_unsignedInteger, + vt_unknown + }; + MicroSettings( MicroInfo *microInfo ); + ~MicroSettings(); + /** + * Returns microdata to describe the microsettings. + * This includes ports settins and variable settings + */ + MicroData microData() const; + void restoreFromMicroData( const MicroData µData ); + /** + * Returns a pointer to the MicroInfo object for the PIC in use + */ + MicroInfo *microInfo() const { return _microInfo; } + /** + * Set the pin with the given id to the given initial type (input/output) + */ + void setPinType( const QString &id, PinSettings::pin_type type ); + /** + * Set the pin with the given id to the given initial state (on/off) + */ + void setPinState( const QString &id, PinSettings::pin_state state ); + /** + * Returns a pointer to the PinSettings for the pin with the given id, + * or null if no such pin exists. + */ + PinSettings* pinWithID( const QString &id ); + /** + * Returns the initial port state (on/off) for the given port. + * Each pin state occupies one bit of the returned integer. + */ + int portState( const QString &port ); + /** + * Sets the port with the given name to the given state + */ + void setPortState( const QString &port, int state ); + /** + * Sets the port with the given name to the given type + */ + void setPortType( const QString &port, int type ); + /** + * Returns the initial port type (intput/output) for the given port. + * Each pin type occupies one bit of the returned integer. + */ + int portType( const QString &port ); + /** + * Sets the variable "name" to the initial value "value. If the variable + * already exists, its value will be changed. Else, the variable will be + * created. + */ + void setVariable( const QString &name, QVariant value, bool permanent = true ); + /** + * Returns the list of initial variables as a QStringList, just the names + * without the values. Generated from the VariableMap m_variables. + */ + QStringList variableNames(); + /** + * Returns a pointer to the variable info with the given name, or NULL + * if the variable is not found + */ + VariableInfo *variableInfo( const QString &name ); + /** + * Deletes the variable with the given name, returns true if successul + * (i.e. a variable with that name existed), or false if not + */ + bool deleteVariable( const QString &name ); + /** + * Removes all variables + */ + void removeAllVariables(); + /** + * Sets the list of Pin Mappings to that given. + */ + void setPinMappings( const PinMappingMap & pinMappings ); + /** + * Returns the pic pin mapping with the given id. + */ + PinMapping pinMapping( const QString & id ) const; + /** + * Returns the list of different Pin Mappings; + */ + PinMappingMap pinMappings() const; + +signals: + void pinMappingsChanged(); + +private: + PinMappingMap m_pinMappings; + PinSettingsList m_pinSettingsList; + MicroInfo *_microInfo; + VariableMap m_variableMap; + PortList m_ports; +}; + +#endif diff --git a/src/node.cpp b/src/node.cpp new file mode 100644 index 0000000..9a3531d --- /dev/null +++ b/src/node.cpp @@ -0,0 +1,486 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "cnitem.h" +#include "icndocument.h" +#include "connector.h" +#include "itemdocumentdata.h" +#include "node.h" + +#include + +#include + +Node::Node( ICNDocument *icnDocument, Node::node_type type, node_dir dir, const QPoint &pos, QString *id ) + : QObject(), QCanvasPolygon( icnDocument->canvas() ) +{ + p_nodeGroup = 0l; + p_parentItem = 0L; + b_deleted = false; + m_dir = dir; + m_type = type; + p_icnDocument = icnDocument; + m_level = 0; + m_selectedColor = QColor( 101, 134, 192 ); + + if (id) + { + m_id = *id; + if ( !p_icnDocument->registerUID(*id) ) + kdError() << k_funcinfo << "Could not register id " << *id << endl; + } + else m_id = p_icnDocument->generateUID("node"+QString::number(type)); + + initPoints(); + move( pos.x(), pos.y() ); + setBrush( Qt::black ); + setPen( Qt::black ); + show(); + + emit (moved(this)); +} + + +Node::~Node() +{ + p_icnDocument->unregisterUID( id() ); +} + + +int Node::rtti() const +{ + return ICNDocument::RTTI::Node; +} + + +void Node::setLevel( const int level ) +{ + m_level = level; +} + + +bool Node::acceptInput() const +{ + return type() != fp_out; +} + + +bool Node::acceptOutput() const +{ + return type() != fp_in; +} + + +void Node::setVisible( bool yes ) +{ + if ( isVisible() == yes ) + return; + + QCanvasPolygon::setVisible(yes); + + const ConnectorList::iterator inputEnd = m_inputConnectorList.end(); + for ( ConnectorList::iterator it = m_inputConnectorList.begin(); it != inputEnd; ++it ) + { + Connector *connector = *it; + if (connector) + { + if ( isVisible() ) + connector->setVisible(true); + + else + { + Node *node = connector->startNode(); + connector->setVisible( node && node->isVisible() ); + } + } + } + + const ConnectorList::iterator outputEnd = m_outputConnectorList.end(); + for ( ConnectorList::iterator it = m_outputConnectorList.begin(); it != outputEnd; ++it ) + { + Connector *connector = *it; + if (connector) + { + if ( isVisible() ) + connector->setVisible(true); + + else + { + Node *node = connector->endNode(); + connector->setVisible( node && node->isVisible() ); + } + } + } +} + + +bool Node::isConnected( Node *node, NodeList *checkedNodes ) +{ + if ( this == node ) + return true; + + bool firstNode = !checkedNodes; + if (firstNode) + checkedNodes = new NodeList(); + + else if ( checkedNodes->contains(this) ) + return false; + + + checkedNodes->append(this); + + const ConnectorList::const_iterator inputEnd = m_inputConnectorList.end(); + for ( ConnectorList::const_iterator it = m_inputConnectorList.begin(); it != inputEnd; ++it ) + { + Connector *connector = *it; + if (connector) + { + Node *startNode = connector->startNode(); + if ( startNode && startNode->isConnected( node, checkedNodes ) ) { + if (firstNode) { + delete checkedNodes; + } + return true; + } + } + } + + const ConnectorList::const_iterator outputEnd = m_outputConnectorList.end(); + for ( ConnectorList::const_iterator it = m_outputConnectorList.begin(); it != outputEnd; ++it ) + { + Connector *connector = *it; + if (connector) + { + Node *endNode = connector->endNode(); + if ( endNode && endNode->isConnected( node, checkedNodes ) ) { + if (firstNode) { + delete checkedNodes; + } + return true; + } + } + } + + if (firstNode) { + delete checkedNodes; + } + + return false; +} + + +void Node::setOrientation( node_dir dir ) +{ + if ( m_dir == dir ) + return; + + if ( dir != Node::dir_up && + dir != Node::dir_right && + dir != Node::dir_down && + dir != Node::dir_left ) + { + kdDebug() << "Node::setOrientation: Unknown node direction "<level()); + + connect( p_parentItem, SIGNAL(movedBy(double, double )), this, SLOT(moveBy(double, double)) ); + connect( p_parentItem, SIGNAL(removed(Item*)), this, SLOT(removeNode(Item*)) ); +} + + +void Node::removeNode() +{ + if (b_deleted) + return; + b_deleted = true; + + emit removed(this); + p_icnDocument->appendDeleteList(this); +} + + +void Node::moveBy( double dx, double dy ) +{ + if ( dx == 0 && dy == 0 ) return; + QCanvasPolygon::moveBy( dx, dy ); + emit moved(this); +} + + +int Node::numCon( bool includeParentItem, bool includeHiddenConnectors ) const +{ + unsigned count = 0; + + const ConnectorList connectors[2] = { m_inputConnectorList, m_outputConnectorList }; + + for ( unsigned i = 0; i < 2; i++ ) + { + ConnectorList::const_iterator end = connectors[i].end(); + for ( ConnectorList::const_iterator it = connectors[i].begin(); it != end; ++it ) + { + if ( *it && (includeHiddenConnectors || (*it)->canvas()) ) + count++; + } + } + + if ( isChildNode() && includeParentItem ) + count++; + + return count; +} + + +void Node::addOutputConnector( Connector * const connector ) +{ + if ( type() == fp_in || !handleNewConnector(connector) ) + return; + + m_outputConnectorList.append(connector); + + if ( type() == fp_out || type() == fp_junction ) + { + // We can only have one output connector, so remove the others. Note + // that this code has to come *after* adding the new output connector, + // as this node will delete itself if it's an fp_junction and there are + // no output connectors. + + const ConnectorList connectors = m_outputConnectorList; + const ConnectorList::const_iterator end = connectors.end(); + for ( ConnectorList::const_iterator it = connectors.begin(); it != end; ++it ) + { + Connector * con = *it; + if ( con && con != connector ) + con->removeConnector(); + } + } + + m_outputConnectorList.remove((Connector*)0l); +} + + +void Node::addInputConnector( Connector * const connector ) +{ + if ( type() == fp_out || !handleNewConnector(connector) ) + return; + + m_inputConnectorList.append(connector); +} + + +bool Node::handleNewConnector( Connector * connector ) +{ + if (!connector) + return false; + + if ( m_inputConnectorList.contains(connector) || m_outputConnectorList.contains(connector) ) + { + kdWarning() << k_funcinfo << " Already have connector = " << connector << endl; + return false; + } + + connect( this, SIGNAL(removed(Node*)), connector, SLOT(removeConnector(Node*)) ); + connect( connector, SIGNAL(removed(Connector*)), this, SLOT(checkForRemoval(Connector*)) ); + connect( connector, SIGNAL(selected(bool)), this, SLOT(setNodeSelected(bool)) ); + + if ( !isChildNode() ) + p_icnDocument->slotRequestAssignNG(); + + return true; +} + + +Connector* Node::createInputConnector( Node * startNode ) +{ + if ( type() == fp_out || !startNode ) + return 0l; + + Connector *connector = new Connector( startNode, this, p_icnDocument ); + addInputConnector(connector); + + return connector; +} + + +void Node::removeConnector( Connector *connector ) +{ + if (!connector) + return; + + ConnectorList::iterator it; + + it = m_inputConnectorList.find(connector); + if ( it != m_inputConnectorList.end() ) + { + (*it)->removeConnector(); + (*it) = 0L; + } + + it = m_outputConnectorList.find(connector); + if ( it != m_outputConnectorList.end() ) + { + (*it)->removeConnector(); + (*it) = 0L; + } +} + +void Node::checkForRemoval( Connector *connector ) +{ + removeConnector(connector); + setNodeSelected(false); + + removeNullConnectors(); + + if (!p_parentItem) + { + int conCount = m_inputConnectorList.count() + m_outputConnectorList.count(); + if ( conCount < 2 ) + removeNode(); + } + + if ( type() == Node::fp_junction && m_outputConnectorList.isEmpty() ) + removeNode(); +} + +void Node::removeNullConnectors() +{ + m_inputConnectorList.remove((Connector*)0L); + m_outputConnectorList.remove((Connector*)0L); +} + + +NodeData Node::nodeData() const +{ + NodeData data; + data.x = x(); + data.y = y(); + return data; +} + + +void Node::setNodeSelected( bool yes ) +{ + if ( isSelected() == yes ) + return; + + QCanvasItem::setSelected(yes); + + setPen( yes ? m_selectedColor : Qt::black ); + setBrush( yes ? m_selectedColor : Qt::black ); +} + +#include "node.moc" diff --git a/src/node.h b/src/node.h new file mode 100644 index 0000000..9f440b3 --- /dev/null +++ b/src/node.h @@ -0,0 +1,222 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef NODE_H +#define NODE_H + +#include +#include + +class CNItem; +class Item; +class ICNDocument; +class ICNDocument; +class Connector; +class Node; +class NodeData; +class NodeGroup; +class QTimer; + +typedef QValueList > ConnectorList; +typedef QValueList > NodeList; + +/** +@short A standard node that can be associated with a Connector or a CNItem +@author David Saxton +*/ +class Node : public QObject, public QCanvasPolygon +{ +Q_OBJECT +public: + /** + * Used for run-time identification of the node: + * Can be electronic node (so has values of current, voltage, etc) + * or a pic part node + */ + enum node_type + { + ec_pin, + ec_junction, + fp_in, + fp_out, + fp_junction + }; + + enum node_dir + { + dir_up = 270, + dir_right = 0, + dir_down = 90, + dir_left = 180 + }; + Node( ICNDocument *icnDocument, Node::node_type type, node_dir dir, const QPoint &pos, QString *id = 0L ); + virtual ~Node(); + + /** + * Sets the node's visibility, as well as updating the visibility of the + * attached connectors as appropriate + */ + virtual void setVisible( bool yes ); + /** + * Returns the global id, that is unique to the node + * amongst all the nodes on the canvas + */ + const QString id() const { return m_id; } + /** + * Returns the id that is internal to the CNItem to which the + * node belongs to. Returns a null QString if no parentitem + */ + const QString childId() const { return m_childId; } + /** + * Use this function to set the child-id, that is unique to the node + * amongst the other nodes associated with its parent CNItem + */ + void setChildId( const QString &id ) { m_childId = id; } + /** + * Returns the run-time-type-identifier of ICNDocument::RTTI::Node + */ + virtual int rtti() const; + /** + * Sets the "level" of the node. By default, the level is 0. The level of + * the node tells the node what CNItems it can be connected to through + * a connector. + * @see level + */ + virtual void setLevel( const int level ); + /** + * Returns the level of the nodes + * @see setLevel + */ + int level() const { return m_level; } + /** + * Use this to identify the type of node - eg ECNode or FPNode + */ + node_type type() const { return m_type; } + /** + * Returns true if the node can accept input connections. This will depend + * on the node type and number of input / output connections. + */ + bool acceptInput() const; + /** + * Returns true if the node can accept output connections. This will depend + * on the node type and number of input / output connections. + */ + bool acceptOutput() const; + /** + * Sets the orientation of the node. + */ + void setOrientation( node_dir dir ); + /** + * Associates a CNItem with the node - ie the node belongs to the CNItem, + * and hence gets deleted when the CNItem gets deleted.s + */ + virtual void setParentItem( CNItem *parentItem ); + /** + * Returns true if the node is part of a CNItem + * (i.e. not between multiple connectors) + */ + bool isChildNode() const { return (p_parentItem != 0L); } + /** + * Returns a pointer to the CNItem to which the node belongs, + * or Null if it doesn't. + */ + CNItem *parentItem() const { return p_parentItem; } + /** + * Remove a specific connector + */ + void removeConnector( Connector *connector ); + /** + * Creates a new connector, sets this as the end node to the connector + * (i.e. this node is the connector's input node), and returns a pointer + * to the connector. + */ + Connector* createInputConnector( Node * startNode ); + /** + * Registers an input connector (i.e. this is the end node) as connected + * to this node. + */ + void addInputConnector( Connector * const connector ); + /** + * Registers an input connector (i.e. this is the start node) as connected + * to this node. + */ + void addOutputConnector( Connector * const connector ); + /** + * Returns the total number of connections to the node. This is the number + * of input connectors, the number of output connectors, and the parent + * item connector if it exists and is requested. + * @param includeParentItem Count the parent item as a connector if it exists + * @param includeHiddenConnectors hidden connectors are those as e.g. part of a subcircuit + */ + int numCon( bool includeParentItem, bool includeHiddenConnectors ) const; + + NodeData nodeData() const; + + ConnectorList inputConnectorList() const { return m_inputConnectorList; } + ConnectorList outputConnectorList() const { return m_outputConnectorList; } + + void setNodeGroup( NodeGroup *ng ) { p_nodeGroup = ng; } + NodeGroup *nodeGroup() const { return p_nodeGroup; } + + /** + * Returns true if this node is connected (or is the same as) the node given + * by other connectors or nodes (although not through CNItems) + * checkedNodes is a list of nodes that have already been checked for + * being the connected nodes, and so can simply return if they are in there. + * If it is null, it will assume that it is the first ndoe & will create a list + */ + bool isConnected( Node *node, NodeList *checkedNodes = 0L ); + + void removeNullConnectors(); + /** + * Draw shape. Note that this has to remain public. + */ + virtual void drawShape( QPainter &p ) = 0; + +public slots: + void moveBy( double dx, double dy ); + void removeNode(Item*) { removeNode(); } + void removeNode(); + void checkForRemoval( Connector *connector ); + void setNodeSelected( bool yes ); + +signals: + void moved( Node *node ); + /** + * Emitted when the CNItem is removed. Normally, this signal is caught by associated + * nodes, who will remove themselves as well. + */ + void removed( Node* node ); + +protected: + /** If this node has precisely two connectors emerging from it, then this + * function will trace thw two connectors until the point where they + * diverge; this point is returned. */ + QPoint findConnectorDivergePoint( bool * found ); + void initPoints(); + bool handleNewConnector( Connector * newConnector ); + + node_type m_type; + QString m_id; + QString m_childId; + node_dir m_dir; + ICNDocument *p_icnDocument; + CNItem *p_parentItem; + ConnectorList m_inputConnectorList; + ConnectorList m_outputConnectorList; + int m_level; + NodeGroup *p_nodeGroup; + QColor m_selectedColor; + +private: + bool b_deleted; +}; + +#endif diff --git a/src/nodegroup.cpp b/src/nodegroup.cpp new file mode 100644 index 0000000..fe55293 --- /dev/null +++ b/src/nodegroup.cpp @@ -0,0 +1,572 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "icndocument.h" +#include "connector.h" +#include "conrouter.h" +#include "node.h" +#include "nodegroup.h" + +#include +#include +#include + +NodeGroup::NodeGroup( ICNDocument *icnDocument, const char *name ) + : QObject( icnDocument, name ) +{ + p_icnDocument = icnDocument; + b_visible = true; +} + + +NodeGroup::~NodeGroup() +{ + clearConList(); + + m_extNodeList.remove( (Node*)0l ); + const NodeList::iterator xnEnd = m_extNodeList.end(); + for ( NodeList::iterator it = m_extNodeList.begin(); it != xnEnd; ++it ) + (*it)->setNodeGroup(0l); + m_extNodeList.clear(); + + m_nodeList.remove( (Node*)0l ); + const NodeList::iterator nEnd = m_nodeList.end(); + for ( NodeList::iterator it = m_nodeList.begin(); it != nEnd; ++it ) + (*it)->setNodeGroup(0l); + m_nodeList.clear(); +} + + +void NodeGroup::setVisible( bool visible ) +{ + if ( b_visible == visible ) + return; + + b_visible = visible; + + m_nodeList.remove( (Node*)0l ); + const NodeList::iterator nEnd = m_nodeList.end(); + for ( NodeList::iterator it = m_nodeList.begin(); it != nEnd; ++it ) + (*it)->setVisible(visible); +} + + +void NodeGroup::addNode( Node *node, bool checkSurrouding ) +{ + if ( !node || node->isChildNode() || m_nodeList.contains(node) ) { + return; + } + + m_nodeList.append(node); + node->setNodeGroup(this); + node->setVisible(b_visible); + + if (checkSurrouding) + { + ConnectorList con = node->inputConnectorList(); + ConnectorList::iterator end = con.end(); + for ( ConnectorList::iterator it = con.begin(); it != end; ++it ) + { + if (*it) { + addNode( (*it)->startNode(), true ); + } + } + + con = node->outputConnectorList(); + end = con.end(); + for ( ConnectorList::iterator it = con.begin(); it != end; ++it ) + { + if (*it) { + addNode( (*it)->endNode(), true ); + } + } + } +} + + +void NodeGroup::translate( int dx, int dy ) +{ + if ( (dx == 0) && (dy == 0) ) + return; + + m_conList.remove((Connector*)0l); + m_nodeList.remove((Node*)0l); + + const ConnectorList::iterator conEnd = m_conList.end(); + for ( ConnectorList::iterator it = m_conList.begin(); it != conEnd; ++it ) + { + (*it)->updateConnectorPoints(false); + (*it)->translateRoute( dx, dy ); + } + + const NodeList::iterator nodeEnd = m_nodeList.end(); + for ( NodeList::iterator it = m_nodeList.begin(); it != nodeEnd; ++it ) + (*it)->moveBy( dx, dy ); +} + + +void NodeGroup::updateRoutes() +{ + resetRoutedMap(); + + // Basic algorithm used here: starting with the external nodes, find the + // pair with the shortest distance between them. Route the connectors + // between the two nodes appropriately. Remove that pair of nodes from the + // list, and add the nodes along the connector route (which have been spaced + // equally along the route). Repeat until all the nodes are connected. + + + const ConnectorList::iterator conEnd = m_conList.end(); + for ( ConnectorList::iterator it = m_conList.begin(); it != conEnd; ++it ) + { + if (*it) + (*it)->updateConnectorPoints(false); + } + + Node *n1, *n2; + NodeList currentList = m_extNodeList; + while ( !currentList.isEmpty() ) + { + findBestPair( ¤tList, &n1, &n2 ); + if ( n1 == 0l || n2 == 0l ) { + return; + } + NodeList route = findRoute( n1, n2 ); + currentList += route; + + ConRouter cr(p_icnDocument); + cr.mapRoute( (int)n1->x(), (int)n1->y(), (int)n2->x(), (int)n2->y() ); + QPointListList pl = cr.dividePoints( route.size()+1 ); + + const NodeList::iterator routeEnd = route.end(); + const QPointListList::iterator plEnd = pl.end(); + Node *prev = n1; + NodeList::iterator routeIt = route.begin(); + for ( QPointListList::iterator it = pl.begin(); it != plEnd; ++it ) + { + Node *next = (routeIt == routeEnd) ? n2 : (Node*)*(routeIt++); + removeRoutedNodes( ¤tList, prev, next ); + QPointList pointList = *it; + if ( prev != n1 ) + { + QPoint first = pointList.first(); + prev->moveBy( first.x() - prev->x(), first.y() - prev->y() ); + } + Connector *con = findCommonConnector( prev, next ); + if (con) + { + con->updateConnectorPoints(false); + con->setRoutePoints( pointList, false, false ); + con->updateConnectorPoints(true); +// con->conRouter()->setPoints( &pointList, con->startNode() != prev ); +// con->conRouter()->setPoints( &pointList, con->pointsAreReverse( &pointList ) ); +// con->calcBoundingPoints(); + } + prev = next; + } + } +} + + +NodeList NodeGroup::findRoute( Node *startNode, Node *endNode ) +{ + NodeList nl; + if ( !startNode || !endNode || startNode == endNode ) { + return nl; + } + + IntList temp; + IntList il = findRoute( temp, getNodePos(startNode), getNodePos(endNode) ); + + const IntList::iterator end = il.end(); + for ( IntList::iterator it = il.begin(); it != end; ++it ) + { + Node *node = getNodePtr(*it); + if (node) { + nl += node; + } + } + + nl.remove(startNode); + nl.remove(endNode); + + return nl; +} + + +IntList NodeGroup::findRoute( IntList used, int currentNode, int endNode, bool *success ) +{ + bool temp; + if (!success) { + success = &temp; + } + *success = false; + + if ( !used.contains(currentNode) ) { + used.append(currentNode); + } + + if ( currentNode == endNode ) { + *success = true; + return used; + } + + const uint n = m_nodeList.size()+m_extNodeList.size(); + for ( uint i=0; iinputConnectorList() + n1->outputConnectorList(); + ConnectorList n2Con = n2->inputConnectorList() + n2->outputConnectorList(); + + const ConnectorList::iterator end = n1Con.end(); + for ( ConnectorList::iterator it = n1Con.begin(); it != end; ++it ) + { + if ( n2Con.contains(*it) ) { + return *it; + } + } + return 0l; +} + + +void NodeGroup::findBestPair( NodeList *list, Node **n1, Node **n2 ) +{ + *n1 = 0l; + *n2 = 0l; + + if ( list->size() < 2 ) { + return; + } + + const NodeList::iterator end = list->end(); + int shortest = 1<<30; + + // Try and find any that are aligned horizontally + for ( NodeList::iterator it1 = list->begin(); it1 != end; ++it1 ) + { + NodeList::iterator it2 = it1; + for ( ++it2; it2 != end; ++it2 ) + { + if ( *it1 != *it2 && (*it1)->y() == (*it2)->y() && canRoute( *it1, *it2 ) ) + { + const int distance = std::abs((double)( (*it1)->x()-(*it2)->x() )); + if ( distance < shortest ) + { + shortest = distance; + *n1 = *it1; + *n2 = *it2; + } + } + } + } + if (*n1) { + return; + } + + // Try and find any that are aligned vertically + for ( NodeList::iterator it1 = list->begin(); it1 != end; ++it1 ) + { + NodeList::iterator it2 = it1; + for ( ++it2; it2 != end; ++it2 ) + { + if ( *it1 != *it2 && (*it1)->x() == (*it2)->x() && canRoute( *it1, *it2 ) ) + { + const int distance = std::abs((double)( (*it1)->y()-(*it2)->y() )); + if ( distance < shortest ) + { + shortest = distance; + *n1 = *it1; + *n2 = *it2; + } + } + } + } + if (*n1) { + return; + } + + // Now, lets just find the two closest nodes + for ( NodeList::iterator it1 = list->begin(); it1 != end; ++it1 ) + { + NodeList::iterator it2 = it1; + for ( ++it2; it2 != end; ++it2 ) + { + if ( *it1 != *it2 && canRoute( *it1, *it2 ) ) + { + const int dx = (int)((*it1)->x()-(*it2)->x()); + const int dy = (int)((*it1)->y()-(*it2)->y()); + const int distance = std::abs((double)dx) + std::abs((double)dy); + if ( distance < shortest ) + { + shortest = distance; + *n1 = *it1; + *n2 = *it2; + } + } + } + } + + if (!*n1) { + kdError() << "NodeGroup::findBestPair: Could not find a routable pair of nodes!"<contains(node) ) { + return; + } + reachable->append(node); + + const uint n = m_nodeList.size() + m_extNodeList.size(); + assert( node < int(n) ); + for ( uint i=0; istartNode()); + int n2 = getNodePos(con->endNode()); + if ( n1 != -1 && n2 != -1 ) + { + b_routedMap[n1*n + n2] = b_routedMap[n2*n + n1] = true; + } + } + } +} + + +void NodeGroup::removeRoutedNodes( NodeList *nodes, Node *n1, Node *n2 ) +{ + if (!nodes) { + return; + } + + // Lets get rid of any duplicate nodes in nodes (as a general cleaning operation) + const NodeList::iterator end = nodes->end(); + for ( NodeList::iterator it = nodes->begin(); it != end; ++it ) + { + if ( nodes->contains(*it) > 1 ) { + *it = 0l; + } + } + nodes->remove((Node*)0l); + + const int n1pos = getNodePos(n1); + const int n2pos = getNodePos(n2); + + if ( n1pos == -1 || n2pos == -1 ) { + return; + } + + const uint n = m_nodeList.size() + m_extNodeList.size(); + + b_routedMap[n1pos*n + n2pos] = b_routedMap[n2pos*n + n1pos] = false; + + bool n1HasCon = false; + bool n2HasCon = false; + + for ( uint i=0; iremove(n1); + } + if (!n2HasCon) { + nodes->remove(n2); + } +} + + +int NodeGroup::getNodePos( Node *n ) +{ + if (!n) { + return -1; + } + int pos = m_nodeList.findIndex(n); + if ( pos != -1 ) { + return pos; + } + pos = m_extNodeList.findIndex(n); + if ( pos != -1 ) { + return pos+m_nodeList.size(); + } + return -1; +} + + +Node* NodeGroup::getNodePtr( int n ) +{ + if ( n<0 ) { + return 0l; + } + const int a = m_nodeList.size(); + if (nsetNodeGroup(0l); + disconnect( con, SIGNAL(removed(Connector*)), this, SLOT(connectorRemoved(Connector*)) ); + } + } + m_conList.clear(); +} + + +void NodeGroup::init() +{ + NodeList::iterator xnEnd = m_extNodeList.end(); + for ( NodeList::iterator it = m_extNodeList.begin(); it != xnEnd; ++it ) + { + (*it)->setNodeGroup(0l); + } + m_extNodeList.clear(); + + clearConList(); + + // First, lets get all of our external nodes and internal connectors + const NodeList::iterator nlEnd = m_nodeList.end(); + for ( NodeList::iterator nodeIt = m_nodeList.begin(); nodeIt != nlEnd; ++nodeIt ) + { + ConnectorList inCon = (*nodeIt)->inputConnectorList(); + ConnectorList outCon = (*nodeIt)->outputConnectorList(); + ConnectorList::iterator conEnd; + + conEnd = inCon.end(); + for ( ConnectorList::iterator conIt = inCon.begin(); conIt != conEnd; ++conIt ) + { + Connector *con = *conIt; + addExtNode(con->startNode()); + if ( !m_conList.contains(con) ) { + m_conList += con; + con->setNodeGroup(this); + } + connect( con, SIGNAL(removed(Connector*)), this, SLOT(connectorRemoved(Connector*)) ); + } + + conEnd = outCon.end(); + for ( ConnectorList::iterator conIt = outCon.begin(); conIt != conEnd; ++conIt ) + { + Connector *con = *conIt; + addExtNode(con->endNode()); + if ( !m_conList.contains(con) ) { + m_conList += con; + con->setNodeGroup(this); + } + connect( con, SIGNAL(removed(Connector*)), this, SLOT(connectorRemoved(Connector*)) ); + } + + // Connect the node up to us + connect( *nodeIt, SIGNAL(removed(Node*)), this, SLOT(nodeRemoved(Node*)) ); + } + + // And connect up our external nodes + xnEnd = m_extNodeList.end(); + for ( NodeList::iterator it = m_extNodeList.begin(); it != xnEnd; ++it ) + { +// connect( *it, SIGNAL(moved(Node*)), this, SLOT(extNodeMoved()) ); + connect( *it, SIGNAL(removed(Node*)), this, SLOT(nodeRemoved(Node*)) ); + } +} + + +void NodeGroup::nodeRemoved( Node *node ) +{ + // We are probably about to get deleted by ICNDocument anyway...so no point in doing anything + m_nodeList.remove(node); + node->setNodeGroup(0l); + node->setVisible(true); + m_extNodeList.remove(node); +} + + +void NodeGroup::connectorRemoved( Connector *connector ) +{ + m_conList.remove(connector); +} + + +void NodeGroup::addExtNode( Node *node ) +{ + if ( !m_extNodeList.contains(node) && !m_nodeList.contains(node) ) + { + m_extNodeList.append(node); + node->setNodeGroup(this); + } +} + +#include "nodegroup.moc" diff --git a/src/nodegroup.h b/src/nodegroup.h new file mode 100644 index 0000000..f3f49f8 --- /dev/null +++ b/src/nodegroup.h @@ -0,0 +1,145 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef NODEGROUP_H +#define NODEGROUP_H + +#include +#include +#include +#include + +class ICNDocument; +class Connector; +class ConRouter; +class Node; +class NodeGroup; + +class QTimer; + +typedef QValueList IntList; +typedef QValueList NodeGroupList; +typedef QValueList > NodeList; + +/** +Controls a group of nodes who are not attached to any CNItems (poor things!) +along with their associated connectors. +@author David Saxton +*/ +class NodeGroup : public QObject +{ +Q_OBJECT +public: + NodeGroup( ICNDocument *icnDocument, const char *name = 0); + ~NodeGroup(); + /** + * Adds a node to the group (this checks to make sure that the node is not + * a child node). If checkSurrouding is true, then surrounding nodes will be + * checked to see if they are valid for inclusion - and if so, include them. + */ + void addNode( Node *node, bool checkSurrouding ); + /** + * Returns the list of internal nodes + */ + NodeList internalNodeList() const { return m_nodeList; } + /** + * Returns the list of external nodes + */ + NodeList externalNodeList() const { return m_extNodeList; } + /** + * Returns the list of connectors + */ + ConnectorList connectorList() const { return m_conList; } + /** + * Translates the routes by the given amount + */ + void translate( int dx, int dy ); + void init(); + /** + * @returns true if node is an internal node to this group + */ + bool contains( Node *node ) const { return m_nodeList.contains(node); } + /** + * Reroute the NodeGroup. This function should only ever be called by + * ICNDocument::rerouteInvalidatedConnectors(), as it is important that + * there is only ever one entity controlling the routing of connectors. + */ + void updateRoutes(); + /** + * Sets the visibility of all nodes in the group. + */ + void setVisible( bool visible ); + +public slots: + /** + * Called when an internal or external node is deleted + */ + void nodeRemoved( Node *node ); + /** + * Called when a connector is removed + */ + void connectorRemoved( Connector *connector ); + + +protected: + void clearConList(); + /** + * Finds the common connector between two nodes + */ + Connector* findCommonConnector( Node *n1, Node *n2 ); + /** + * Find the best pair of nodes in the given list to route between. These + * will be nodes that give a ncie path (e.g. if they're aligned horizontally + * or vertically), or otherwise the closest such pair. The two nodes will be + * returned in n1 and n2. + */ + void findBestPair( NodeList *list, Node **n1, Node **n2 ); + /** + * Finds the nodes along the route with the given start and end nodes (which + * will be unique). The end nodes are not included in the returned list. + */ + NodeList findRoute( Node *startNode, Node *endNode ); + + ConnectorList m_conList; + NodeList m_nodeList; + NodeList m_extNodeList; + ICNDocument *p_icnDocument; + QValueVector b_routedMap; // Routes between different nodes + bool b_visible; + +private: + IntList findRoute( IntList used, int currentNode, int endNode, bool *success = 0l ); + void resetRoutedMap(); + /** + * Looks at b_routedMap as well as the connectors coming out of nodes, and + * removes the nodes from the given list that have all of their connectors + * routed. + */ + void removeRoutedNodes( NodeList *nodes, Node *n1, Node *n2 ); + void addExtNode( Node *node ); + /** + * Looks at b_mappedRoute to see if there is a completely unrouted set of + * connectors between the two given nodes; + */ + bool canRoute( Node *n1, Node *n2 ); + void getReachable( IntList *reachable, int node ); + /** + * Either: position of node in m_nodeList, + * or: (position of node in m_extNodeList) + m_nodeList.size() + * or: -1 + */ + int getNodePos( Node *n ); + /** + * Essentially the inverse of getNodePos + */ + Node* getNodePtr( int n ); +}; + +#endif diff --git a/src/oscilloscopedata.cpp b/src/oscilloscopedata.cpp new file mode 100644 index 0000000..cc1e289 --- /dev/null +++ b/src/oscilloscopedata.cpp @@ -0,0 +1,171 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "oscilloscopedata.h" +#include "oscilloscope.h" + +//BEGIN class ProbeData +ProbeData::ProbeData( int id ) + : m_id(id) +{ + m_resetTime = Simulator::self()->time(); +// b_isPaused = false; + m_color = Qt::black; + m_drawPosition = 0.5; + m_insertPos = 0; +} + + +ProbeData::~ProbeData() +{ + unregisterProbe(m_id); +} + + +void ProbeData::setColor( QColor color ) +{ + m_color = color; + emit displayAttributeChanged(); +} +//END class ProbeData + + +//BEGIN class LogicProbeData +LogicProbeData::LogicProbeData( int id ) + : ProbeData(id) +{ +} + + +void LogicProbeData::eraseData() +{ + bool lastValue = false; + bool hasLastValue = m_insertPos > 0; + if (hasLastValue) + lastValue = m_data[m_insertPos-1].value; + + m_data.reset(); + m_insertPos = 0; + m_resetTime = Simulator::self()->time(); + + if (hasLastValue) + addDataPoint( LogicDataPoint( lastValue, m_resetTime ) ); +} + + +ullong LogicProbeData::findPos( llong time ) const +{ + if ( time <= 0 ) + return 0; + + for ( int a = m_data.allocatedUpTo()-1; a >= 0; a-- ) + { + DCArray * dcArray = m_data.dcArray(a); + + // We're only interested in this if the earliest recorded data point in this dcArray is <= time + if ( m_data.toPos( a, 0, 0 ) >= m_insertPos || (dcArray->chunk(0)->data[0].time > ullong(time)) ) + continue; + + // Cool, somewhere in this dcArray.... + for ( int b = dcArray->allocatedUpTo()-1; b >= 0; b-- ) + { + // Done check if the data we'd be accessing is beyond that set + if ( m_data.toPos( a, b, 0 ) >= m_insertPos || dcArray->chunk(b)->data[0].time > ullong(time) ) + continue; + + // Soon... + for ( int c = DATA_CHUNK_SIZE-1; c >= 0; c-- ) + { + ullong pos = m_data.toPos( a, b, c ); + + if ( pos >= m_insertPos || dcArray->chunk(b)->data[c].time > ullong(time) ) + continue; + + // Wee! + return pos; + } + } + } + + // Either we have no data points, or the one closest to the given time will be the one at the start + return 0; +} +//END class LogicProbeData + + +//BEGIN class FloatingProbeData +FloatingProbeData::FloatingProbeData( int id ) + : ProbeData(id) +{ + m_scaling = Linear; + m_upperAbsValue = 10.0; + m_lowerAbsValue = 0.1; +} + + +void FloatingProbeData::eraseData() +{ + m_data.reset(); + m_insertPos = 0; + m_resetTime = Simulator::self()->time(); +} + + +ullong FloatingProbeData::findPos( llong time ) const +{ + if ( time <= 0 || ullong(time) <= m_resetTime || m_insertPos == 0 ) + return 0; + + ullong at = ullong((time-m_resetTime)*double(LINEAR_UPDATE_RATE)/double(LOGIC_UPDATE_RATE)); + + if ( at >= m_insertPos ) + at = m_insertPos-1; + + return at; +} + + +ullong FloatingProbeData::toTime( ullong at ) const +{ + return ullong(m_resetTime + (at*LOGIC_UPDATE_RATE/LINEAR_UPDATE_RATE)); +} + + +void FloatingProbeData::setScaling( Scaling scaling ) +{ + if ( m_scaling == scaling ) + return; + + m_scaling = scaling; + emit displayAttributeChanged(); +} + + +void FloatingProbeData::setUpperAbsValue( double upperAbsValue ) +{ + if ( m_upperAbsValue == upperAbsValue ) + return; + + m_upperAbsValue = upperAbsValue; + emit displayAttributeChanged(); +} + + +void FloatingProbeData::setLowerAbsValue( double lowerAbsValue ) +{ + if ( m_lowerAbsValue == lowerAbsValue ) + return; + + m_lowerAbsValue = lowerAbsValue; + emit displayAttributeChanged(); +} +//END class FloatingProbeData + + diff --git a/src/oscilloscopedata.h b/src/oscilloscopedata.h new file mode 100644 index 0000000..cbabdac --- /dev/null +++ b/src/oscilloscopedata.h @@ -0,0 +1,365 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef OSCILLOSCOPEDATA_H +#define OSCILLOSCOPEDATA_H + +#include +#include + +typedef long long llong; +typedef unsigned long long ullong; +typedef unsigned int uint; + +#define DATA_CHUNK_SIZE (8192/sizeof(T)) +#define DATA_CHUNK_ARRAY_SIZE ((8192-sizeof(uint))/sizeof(DataChunk*)) + +// Allow a minimum of 64 megabytes of stored data (67108864 bytes) +/// \todo The maximum allowed amount of stored data should be configurable or +/// more intelligent (e.g. taking into account the number of probes or the +/// amount of physical memory on the system). +#define DCARRAY_ARRAY_SIZE ((67108864/(8192*DATA_CHUNK_ARRAY_SIZE))+1) + + +/** +For use in LogicProbe: Every time the input changes state, the new input state +is recorded in value, along with the simulator time that it occurs at. + */ +class LogicDataPoint +{ + public: + LogicDataPoint() + { + value = 0; + time = 0; + } + LogicDataPoint( bool v, ullong t ) + { + value = v; + time = t; + } + bool value : 1; + ullong time : 63; +}; + + +template +class DataChunk +{ + public: + DataChunk() { memset( data, 0, DATA_CHUNK_SIZE*sizeof(T) ); } + + T data[ DATA_CHUNK_SIZE ]; + + private: + // We don't want to accidently copy a shedload of data + DataChunk( const DataChunk & ); +}; + +typedef DataChunk LogicChunk; +typedef DataChunk FloatingChunk; + + +template +class DCArray +{ + public: + DCArray() + { + memset( m_data, 0, DATA_CHUNK_ARRAY_SIZE*sizeof(DataChunk *) ); + m_allocatedUpTo = 0; + } + ~DCArray() + { + for ( uint i=0; i * chunk( uint i ) + { + if ( i >= m_allocatedUpTo ) + allocateUpTo(i+1024); + + if ( i >= DATA_CHUNK_ARRAY_SIZE ) + return 0l; + + return m_data[i]; + } + uint allocatedUpTo() const { return m_allocatedUpTo; } + + + protected: + void allocateUpTo( uint upTo ) + { + if ( upTo > DATA_CHUNK_ARRAY_SIZE ) + upTo = DATA_CHUNK_ARRAY_SIZE; + + for ( uint i=m_allocatedUpTo; i; + m_allocatedUpTo = upTo; + } + + DataChunk * m_data[DATA_CHUNK_ARRAY_SIZE]; + uint m_allocatedUpTo; + + private: + // We don't want to accidently copy a shedload of data + DCArray( const DCArray & ); +}; + + +template +class StoredData +{ + public: + StoredData() + { + memset( m_data, 0, DCARRAY_ARRAY_SIZE*sizeof(DCArray *) ); + m_allocatedUpTo = 0; + } + ~StoredData() + { + reset(); + } + + inline T & operator[]( ullong i ) + { + return dataAt(i); + } + inline T & dataAt( ullong i, ullong * insertPos = 0 ) + { + ullong c = i % DATA_CHUNK_SIZE; + ullong b = ullong((i-c)/DATA_CHUNK_SIZE) % DATA_CHUNK_ARRAY_SIZE; + ullong a = ullong((ullong((i-c)/DATA_CHUNK_SIZE)-b)/DATA_CHUNK_ARRAY_SIZE); + + if ( a >= m_allocatedUpTo ) + allocateUpTo(a+1); + + if ( a >= DCARRAY_ARRAY_SIZE ) + { + a = DCARRAY_ARRAY_SIZE - 1; + if ( insertPos ) + *insertPos = toPos( a, b, c ); + } + + return m_data[a]->chunk(b)->data[c]; + } + + ullong toPos( ullong a, ullong b, ullong c ) const + { + return (((a*DATA_CHUNK_ARRAY_SIZE)+b)*DATA_CHUNK_SIZE)+c; + } + + uint allocatedUpTo() const { return m_allocatedUpTo; } + + DCArray * dcArray( unsigned pos ) const + { + return (pos < m_allocatedUpTo) ? m_data[pos] : 0l; + } + + /** + * Initialises all data to 0 + */ + void reset() + { + for ( uint i=0; i= DCARRAY_ARRAY_SIZE ) + { + // Shuffle all data (getting rid of the oldest data) + delete m_data[0]; + for ( unsigned i = 1; i < m_allocatedUpTo; ++i ) + m_data[i-1] = m_data[i]; + + upTo = DCARRAY_ARRAY_SIZE; + m_allocatedUpTo--; + } + + for ( unsigned i = m_allocatedUpTo; i < upTo; ++i ) + m_data[i] = new DCArray; + + m_allocatedUpTo = upTo; + } + DCArray * m_data[DCARRAY_ARRAY_SIZE]; + + uint m_allocatedUpTo; + + private: + // We don't want to accidently copy a shedload of data + StoredData( const StoredData & ); +}; + + +/** +@author David Saxton + */ +class ProbeData : public QObject +{ + Q_OBJECT; + public: + ProbeData( int id ); + ~ProbeData(); + + /** + * @returns unique id for oscilloscope, set on construction + */ + int id() const { return m_id; } + /** + * Set the proportion (0 = top, 1 = bottom) of the way down the + * oscilloscope view that the probe output is drawn. If the proportion + * is out of range ( <0, or >1), then the drawPosition is set to 0/1 + */ + void setDrawPosition( float drawPosition ) { m_drawPosition = drawPosition; } + /** + * Returns the draw position. Default is 0.5. + * @see setDrawPosition + */ + float drawPosition() const { return m_drawPosition; } + /** + * Set the colour that is used to display the probe in the oscilloscope. + * Default is black. + */ + void setColor( QColor color ); + /** + * @returns the colour that is used to display the probe in the oscilloscope + */ + QColor color() const { return m_color; } +// /** +// * Will not record any data when paused +// */ +// void setPaused( bool isPaused ) { b_isPaused = isPaused; } + /** + * Returns the time (in Simulator time) that this probe was created at, + * or last reset. + */ + ullong resetTime() const { return m_resetTime; } + /** + * Erases all recorded data, and sets m_resetTime to the current + * simulator time. + */ + virtual void eraseData() = 0; + /** + * Searches for and returns the position of the last DataPoint that was + * added before or at the given Simulator time. If no DataPoints were + * were recorded before the given time, then will return the one closest + * to the given time. Will return 0 if no DataPoints have been recorded + * yet. + */ + virtual ullong findPos( llong time ) const = 0; + + ullong insertPos() const { return m_insertPos; } + + signals: + /** + * Emitted when an attribute that affects how the probe is drawn in the + * oscilloscope is changed. + */ + void displayAttributeChanged(); + + protected: + const int m_id; + float m_drawPosition; + ullong m_insertPos; +// bool b_isPaused; + ullong m_resetTime; + QColor m_color; +}; + + +/** +@author David Saxton +*/ +class LogicProbeData : public ProbeData +{ + public: + LogicProbeData( int id ); + + /** + * Appends the data point to the set of data. + */ + void addDataPoint( LogicDataPoint data ) + { + ullong next = m_insertPos++; + m_data.dataAt( next, & m_insertPos ) = data; + } + + virtual void eraseData(); + virtual ullong findPos( llong time ) const; + + protected: + StoredData m_data; + friend class OscilloscopeView; +}; + + +/** +@author David Saxton +*/ +class FloatingProbeData : public ProbeData +{ + public: + enum Scaling { Linear, Logarithmic }; + + FloatingProbeData( int id ); + + /** + * Appends the data point to the set of data. + */ + void addDataPoint( float data ) { m_data[m_insertPos++] = data; } + /** + * Converts the insert position to a Simulator time. + */ + ullong toTime( ullong at ) const; + /** + * Sets the scaling to use in the oscilloscope display. + */ + void setScaling( Scaling scaling ); + /** + * @return the scaling used for the oscilloscope display. + */ + Scaling scaling() const { return m_scaling; } + /** + * Sets the value to use as the upper absolute value in the display. + */ + void setUpperAbsValue( double upperAbsValue ); + /** + * @return the upper absolute value to use in the display. + */ + double upperAbsValue() const { return m_upperAbsValue; } + /** + * Sets the value to use as the lower absolute value in the display + * (this is only used with logarithmic scaling). + */ + void setLowerAbsValue( double lowerAbsValue ); + /** + * @return the lower absolute value to use in the display (this is + * only used with logarithmic scaling). + */ + double lowerAbsValue() const { return m_lowerAbsValue; } + + virtual void eraseData(); + virtual ullong findPos( llong time ) const; + + protected: + Scaling m_scaling; + double m_upperAbsValue; + double m_lowerAbsValue; + StoredData m_data; + friend class OscilloscopeView; +}; + + +#endif diff --git a/src/picitem.cpp b/src/picitem.cpp new file mode 100644 index 0000000..cbd7f1f --- /dev/null +++ b/src/picitem.cpp @@ -0,0 +1,397 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasitemparts.h" +#include "flowcodedocument.h" +#include "microinfo.h" +#include "microsettings.h" +#include "microsettingsdlg.h" +#include "micropackage.h" +#include "picitem.h" + +#include +#include +#include +#include + +static const int InnerWidth = 88; +static const int SidePadding = 24; +static const int TopPadding = 36; +static const int BottomPadding = 42; +static const int PinWidth = 12; +static const int PinSeparation = 16 - PinWidth; +static const int PinLength = 8; +static const int ArcWidth = 22; +static const int PinDirArrow = 3; + + +//BEGIN class PinItem +PinItem::PinItem( FlowCodeDocument* _view, QPoint position, bool _onLeft, PinSettings * pinSettings ) + : QCanvasRectangle(0) +{ + m_pinSettings = pinSettings; + view = _view; + onLeft = _onLeft; + + connect( m_pinSettings, SIGNAL(settingsChanged()), this, SLOT(updateDrawing()) ); + + if ( QFontInfo(m_font).pixelSize() > 11 ) // It has to be > 11, not > 12, as (I think) pixelSize() rounds off the actual size + m_font.setPixelSize(12); + + setCanvas( view->canvas() ); + + move ( position.x(), position.y() ); + initItem(); + setZ( (ICNDocument::Z::RaisedItem + ICNDocument::Z::ResizeHandle)/2 + 1 ); // Hackish, but whatever +} + + +int PinItem::rtti() const +{ + return ItemDocument::RTTI::Pin; +} + + +void PinItem::updateDrawing() +{ + update(); +} + + +void PinItem::initItem() +{ + setSize( PinLength, PinWidth ); + setSelected(false); + setPen( Qt::black ); + calcTextRect(); + show(); +} + + +void PinItem::drawShape( QPainter& p ) +{ + if (!m_pinSettings) + return; + + if ( m_pinSettings->state() == PinSettings::ps_on ) + { + if ( m_pinSettings->type() == PinSettings::pt_output ) + setBrush( QColor( 255, 127, 127 ) ); + else + setBrush( QColor( 255, 191, 191 ) ); + } + else + setBrush( Qt::white ); + + p.drawRect(rect()); + + p.setFont(m_font); + p.setBrush( Qt::NoBrush ); + QRect r = m_textRect; + if ( onLeft ) + p.drawText( r, Qt::AlignLeft, m_pinSettings->id() ); + else + p.drawText( r, Qt::AlignRight, m_pinSettings->id() ); + QRect br = p.boundingRect( r, Qt::AlignLeft, m_pinSettings->id() ); + + int left; + int right; + if ( onLeft ) + { + right = (int)x(); + left = right - 8; + } + else + { + left = (int)x() + PinLength; + right = left + 8; + } + + int midY = (int)y() + PinWidth/2; + QPointArray pa(3); + int midLeft = left + (8-PinDirArrow)/2; + int midRight = left + (8+PinDirArrow)/2; + + if ( onLeft ) + { + midLeft--; + midRight--; + } + else + { + midLeft++; + midRight++; + } + + p.setBrush( Qt::black ); + + // Right facing arrow + if ( (m_pinSettings->type() == PinSettings::pt_input && onLeft) || + (m_pinSettings->type() == PinSettings::pt_output && !onLeft) ) + { + pa[0] = QPoint::QPoint( midRight, midY ); + pa[1] = QPoint::QPoint( midLeft, midY - PinDirArrow ); + pa[2] = QPoint::QPoint( midLeft, midY + PinDirArrow ); + p.drawPolygon(pa); + p.drawLine ( left, midY, right, midY ); + } + else // Left facing arrow + { + pa[0] = QPoint::QPoint( midLeft, midY ); + pa[1] = QPoint::QPoint( midRight, midY - PinDirArrow ); + pa[2] = QPoint::QPoint( midRight, midY + PinDirArrow ); + p.drawPolygon(pa); + p.drawLine ( left, midY, right, midY ); + } +} + + +QRect PinItem::boundingRect () const +{ + QRect r = m_textRect; + if ( onLeft ) + r.setLeft( (int)x() - 10 ); + else + r.setRight( (int)x() + PinLength + 10 ); + + return r; +} + + +QString PinItem::id() +{ + return m_pinSettings->id(); +} + + +void PinItem::switchState() +{ + if ( m_pinSettings->state() == PinSettings::ps_on ) + m_pinSettings->setState(PinSettings::ps_off); + else + m_pinSettings->setState(PinSettings::ps_on); + + update(); +} + + +void PinItem::dragged( int dx ) +{ + if ( (onLeft && dx > 0) || + (!onLeft && dx < 0) ) + { + m_pinSettings->setType(PinSettings::pt_input); + } + else + m_pinSettings->setType(PinSettings::pt_output); + + update(); +} + + +void PinItem::moveBy ( double dx, double dy ) +{ + QCanvasRectangle::moveBy( dx, dy ); + calcTextRect(); +} + + +void PinItem::calcTextRect() +{ + m_textRect = rect(); + m_textRect.moveTop( m_textRect.top()-2 ); + QRect br; + + QWidget tmpWidget; + QPainter p(&tmpWidget); + + p.setFont(m_font); + + if (!m_pinSettings) + { + kdDebug() << "PinItem::textRect: No pinSettings!"<id() ); + } + else + { + m_textRect.setLeft( m_textRect.right() - InnerWidth/2 ); + m_textRect.setRight( (int)x() - 2 ); + br = p.boundingRect( m_textRect, Qt::AlignRight, m_pinSettings->id() ); + } +} +//END class PinItem + + + +//BEGIN class PicItem +PicItem::PicItem( ICNDocument *icnDocument, bool newItem, const char *id, MicroSettings *_microSettings ) + : CNItem( icnDocument, newItem, id ? id : "picitem" ) +{ + m_name = "PIC"; + m_type = typeString(); + p_icnDocument = icnDocument; + icnDocument->registerItem(this); + + microSettings = _microSettings; + const int numPins = microSettings->microInfo()->package()->pinCount( PicPin::type_bidir | PicPin::type_input | PicPin::type_open ); + const int numSide = (numPins/2) + (numPins%2); + + m_bExpanded = true; + m_innerHeight = (numSide+2)*PinWidth + (numSide-1)*PinSeparation; + updateVisibility(); + + addButton( "settings", QRect( SidePadding-8, m_innerHeight+TopPadding+(BottomPadding-24)/2-1, InnerWidth+16, 24 ), i18n("Advanced...") ); + addButton( "expandBtn", QRect( (TopPadding-22)/2, (TopPadding-22)/2, 22, 22 ), KGlobal::iconLoader()->loadIcon( "down", KIcon::Small ), true ); + button("expandBtn")->setState(true); + + move( 12, 12 ); + + QStringList pinIDs = microSettings->microInfo()->package()->pinIDs( PicPin::type_bidir | PicPin::type_input | PicPin::type_open ); + QStringList::iterator it = pinIDs.begin(); + + for ( int i=0; i < numSide; ++i, ++it ) + { + QPoint position( int(this->x()) + SidePadding - PinLength+1, int(y()) + TopPadding + (i+1)*PinWidth + i*PinSeparation ); + const QString id = *it; + PinSettings *settings = microSettings->pinWithID(id); + m_pinItemList.append( new PinItem( dynamic_cast(icnDocument), position, true, settings ) ); + } + + for ( int i=0; i < numPins/2; ++i, ++it ) + { + QPoint position( int(this->x()) + SidePadding + InnerWidth-1, int(y()) + TopPadding + m_innerHeight - ( (i+2)*PinWidth + i*PinSeparation ) ); + const QString id = *it; + PinSettings *settings = microSettings->pinWithID(id); + m_pinItemList.append( new PinItem( dynamic_cast(icnDocument), position, false, settings ) ); + } + + setSelected(false); + setPen( Qt::black ); + updateZ(-1); + update(); + show(); +} + + +PicItem::~PicItem() +{ + const PinItemList::iterator end = m_pinItemList.end(); + for ( PinItemList::iterator it = m_pinItemList.begin(); it != end; ++it ) + delete *it; + + m_pinItemList.clear(); +} + + +void PicItem::updateZ( int baseZ ) +{ + (void)baseZ; + setZ( (ICNDocument::Z::RaisedItem + ICNDocument::Z::ResizeHandle)/2 ); // Hackish, but whatever + button("settings")->setZ( z()+1 ); + button("expandBtn")->setZ( z()+1 ); +} + + +void PicItem::drawShape( QPainter & p ) +{ + int _x = int(x()); + int _y = int(y()); + + p.setBrush( QColor( 0xef, 0xff, 0xef ) ); + p.setFont( font() ); + + p.drawRoundRect( _x, _y, width(), height(), 2000/width(), 2000/height() ); + + p.drawText( _x+TopPadding-2, _y, width()-TopPadding+2, TopPadding, Qt::AlignVCenter, i18n("PIC Settings") ); + + if ( !m_bExpanded ) + return; + + // Draw rectangle to cut off pins + p.setBrush( QColor( 239, 255, 255 ) ); + QRect r( _x+SidePadding, _y+TopPadding, InnerWidth, m_innerHeight ); + p.drawRect(r); + + // Draw dimple thingy at end of pic + p.drawArc( r.x()+(r.width()-ArcWidth)/2, r.y()+1-ArcWidth/2, ArcWidth, ArcWidth, 180*16, 180*16 ); + + // Draw vertical text centered in PIC + p.translate( r.width()/2 + r.x(), r.height()/2 + r.y() ); + p.rotate(90); + QRect textRect( r.width()/-2, r.height()/-2, r.width(), r.height() ); + p.drawText( textRect, Qt::AlignCenter, microSettings->microInfo()->id() ); + + p.rotate(-90); + p.translate( r.width()/-2 - r.x(), r.height()/-2 - r.y() ); +} + + +void PicItem::buttonStateChanged( const QString &id, bool state ) +{ + if ( id == "expandBtn" ) + { + m_bExpanded = state; + updateVisibility(); + } + + else if ( id == "settings" ) + { + if (!state) + return; + + // Redraw button + button("settings")->setState(false); + update(); + + MicroSettingsDlg *dlg = new MicroSettingsDlg( microSettings, 0L, "microSettingsDlg" ); + connect( dlg, SIGNAL(okClicked()), this, SLOT(slotMicroSettingsDlgAccepted()) ); + connect( dlg, SIGNAL(applyClicked()), this, SLOT(slotMicroSettingsDlgAccepted()) ); + dlg->show(); + // At this point the PIC is selected but this does not appear to the + // user so we must deselect it when done. + p_icnDocument->unselectAll(); + } +} + + +void PicItem::updateVisibility() +{ + if (m_bExpanded) + setSize( 0, 0, InnerWidth+(2*SidePadding), m_innerHeight+TopPadding+BottomPadding, true ); + + else + setSize( 0, 0, InnerWidth+(2*SidePadding), TopPadding, true ); + + const PinItemList::iterator end = m_pinItemList.end(); + for ( PinItemList::iterator it = m_pinItemList.begin(); it != end; ++it ) + (*it)->setVisible(m_bExpanded); + + if ( Button * btn = button("settings") ) + btn->setVisible(m_bExpanded); +} + + +void PicItem::slotMicroSettingsDlgAccepted() +{ + const PinItemList::iterator end = m_pinItemList.end(); + for ( PinItemList::iterator it = m_pinItemList.begin(); it != end; ++it ) + canvas()->setChanged( (*it)->boundingRect() ); + + p_icnDocument->requestStateSave(); +} +//END class PicItem + +#include "picitem.moc" diff --git a/src/picitem.h b/src/picitem.h new file mode 100644 index 0000000..0474ba8 --- /dev/null +++ b/src/picitem.h @@ -0,0 +1,94 @@ +/*************************************************************************** + * Copyright (C) 2003,2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PICITEM_H +#define PICITEM_H + +#include "cnitem.h" + +#include + +class MicroSettings; +class FlowCodeDocument; +class PinSettings; + +/** +@short Allows visual setting of pin type/state +@author David Saxton +*/ +class PinItem : public QObject, public QCanvasRectangle +{ + Q_OBJECT +public: + PinItem( FlowCodeDocument* _view, QPoint position, bool _onLeft, PinSettings *_pinSettings ); + + int rtti() const; + QRect boundingRect () const; + void switchState(); + + QString id(); + + /** + * Called from ICNDocument when the pin item was dragged + */ + void dragged( int dx ); + + virtual void moveBy ( double dx, double dy ); + +public slots: + void updateDrawing(); + +private: + void initItem(); + void drawShape( QPainter& p ); + void calcTextRect(); + + FlowCodeDocument *view; // Pointer to canvas view that the component item is currently on + bool onLeft; + PinSettings * m_pinSettings; + QRect m_textRect; + QFont m_font; +}; +typedef QValueList PinItemList; + + +/** +Allows visual editing of inital PIC settings +@author David Saxton +*/ +class PicItem : public CNItem +{ + Q_OBJECT + public: + PicItem( ICNDocument *icnDocument, bool newItem, const char *id, MicroSettings *_microSettings ); + ~PicItem(); + + void drawShape( QPainter &p ); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual bool isMovable() const { return false; } + + static QString typeString() { return "microitem"; } + virtual void updateZ( int baseZ ); + + protected slots: + void slotMicroSettingsDlgAccepted(); + + protected: + void updateVisibility(); + + MicroSettings *microSettings; + PinItemList m_pinItemList; + ICNDocument *p_icnDocument; + bool m_bExpanded; + int m_innerHeight; +}; + +#endif diff --git a/src/projectmanager.cpp b/src/projectmanager.cpp new file mode 100644 index 0000000..dfef6b3 --- /dev/null +++ b/src/projectmanager.cpp @@ -0,0 +1,1256 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "core/ktlconfig.h" +#include "docmanager.h" +#include "document.h" +#include "language.h" +#include "languagemanager.h" +#include "ktechlab.h" +#include "microselectwidget.h" +#include "programmerdlg.h" +#include "projectdlgs.h" +#include "projectmanager.h" +#include "recentfilesaction.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//BEGIN class LinkerOptions +LinkerOptions::LinkerOptions() +{ + m_hexFormat = HexFormat::inhx32; + m_bOutputMapFile = false; +} + + +QDomElement LinkerOptions::toDomElement( QDomDocument & doc, const KURL & baseURL ) const +{ + QDomElement node = doc.createElement("linker"); + + node.setAttribute( "hex-format", hexFormatToString(hexFormat()) ); + node.setAttribute( "output-map-file", outputMapFile() ); + node.setAttribute( "library-dir", libraryDir() ); + node.setAttribute( "linker-script", linkerScript() ); + node.setAttribute( "other", linkerOther() ); + + QStringList::const_iterator end = m_linkedInternal.end(); + for ( QStringList::const_iterator it = m_linkedInternal.begin(); it != end; ++it ) + { + QDomElement child = doc.createElement("linked-internal"); + node.appendChild(child); + child.setAttribute( "url", KURL::relativeURL( baseURL, *it ) ); + } + + end = m_linkedExternal.end(); + for ( QStringList::const_iterator it = m_linkedExternal.begin(); it != end; ++it ) + { + QDomElement child = doc.createElement("linked-external"); + node.appendChild(child); + child.setAttribute( "url", *it ); + } + + return node; +} + + +void LinkerOptions::domElementToLinkerOptions( const QDomElement & element, const KURL & baseURL ) +{ + setHexFormat( stringToHexFormat( element.attribute( "hex-format", QString::null ) ) ); + setOutputMapFile( element.attribute( "output-map-file", "0" ).toInt() ); + setLibraryDir( element.attribute( "library-dir", QString::null ) ); + setLinkerScript( element.attribute( "linker-script", QString::null ) ); + setLinkerOther( element.attribute( "other", QString::null ) ); + + m_linkedInternal.clear(); + m_linkedExternal.clear(); + + QDomNode node = element.firstChild(); + while ( !node.isNull() ) + { + QDomElement childElement = node.toElement(); + if ( !childElement.isNull() ) + { + const QString tagName = childElement.tagName(); + + if ( tagName == "linked-internal" ) + m_linkedInternal << KURL( baseURL, childElement.attribute( "url", QString::null ) ).url(); + + else if ( tagName == "linked-external" ) + m_linkedExternal << childElement.attribute( "url", QString::null ); + + else + kdError() << k_funcinfo << "Unrecognised element tag name: "<deleteLater(); + m_children.clear(); + + delete m_pILVItem; + m_pILVItem = 0l; +} + + +void ProjectItem::setILVItem( ILVItem * ilvItem ) +{ + m_pILVItem = ilvItem; + ilvItem->setOpen(true); + ilvItem->setText( 0, name() ); + ilvItem->setProjectItem(this); + updateILVItemPixmap(); +} + + +void ProjectItem::updateILVItemPixmap() +{ + if ( !m_pILVItem ) + return; + + switch ( type() ) + { + case ProjectType: + { + // ?! - We shouldn't have an ilvitem for this. + break; + } + + case ProgramType: + { + QPixmap pm; + pm.load( locate( "appdata", "icons/project_program.png" ) ); + m_pILVItem->setPixmap( 0, pm ); + break; + } + + case LibraryType: + { + QPixmap pm; + pm.load( locate( "appdata", "icons/project_library.png" ) ); + m_pILVItem->setPixmap( 0, pm ); + break; + } + + case FileType: + { + KMimeType::Ptr m = KMimeType::findByPath( url().path() ); + m_pILVItem->setPixmap( 0, m->pixmap( KIcon::Small ) ); + break; + } + } +} + + +void ProjectItem::addChild( ProjectItem * child ) +{ + if ( !child || m_children.contains(child) ) + return; + + m_children << child; + + child->setILVItem( m_pILVItem ? + new ILVItem( m_pILVItem, child->name() ) : + new ILVItem( m_pProjectManager, name() ) ); + + updateControlChildMicroIDs(); +} + + +void ProjectItem::updateControlChildMicroIDs() +{ + bool control = false; + switch ( type() ) + { + case ProjectItem::ProjectType: + case ProjectItem::LibraryType: + case ProjectItem::ProgramType: + control = !microID().isEmpty(); + break; + + case ProjectItem::FileType: + control = true; + break; + } + + m_children.remove( (ProjectItem*)0l ); + ProjectItemList::iterator end = m_children.end(); + for ( ProjectItemList::iterator it = m_children.begin(); it != end; ++it ) + (*it)->setUseParentMicroID( control ); +} + + +void ProjectItem::setName( const QString & name ) +{ + m_name = name; + if (m_pILVItem) + m_pILVItem->setText( 0, name ); +} + + +void ProjectItem::setURL( const KURL & url ) +{ + m_url = url; + + if ( m_name.isEmpty() ) + setName( url.fileName() ); + + if ( type() != FileType ) + { + // The output url *is* our url + setOutputURL(url); + } + else if ( outputURL().isEmpty() ) + { + // Try and guess what the output url should be... + QString newExtension; + + switch ( outputType() ) + { + case ProgramOutput: + newExtension = ".hex"; + break; + + case ObjectOutput: + newExtension = ".o"; + break; + + case LibraryOutput: + newExtension = ".o"; + break; + + case UnknownOutput: + break; + } + + if ( !newExtension.isEmpty() ) + { + const QString fileName = url.url(); + QString extension = fileName.right( fileName.length() - fileName.findRev('.') ); + setOutputURL( QString(fileName).replace( extension, newExtension ) ); + } + } + + updateILVItemPixmap(); +} + + +QString ProjectItem::microID() const +{ + if ( !m_bUseParentMicroID ) + return m_microID; + + return m_pParent ? m_pParent->microID() : QString::null; +} + + +void ProjectItem::setMicroID( const QString & id ) +{ + ProcessingOptions::setMicroID(id); + updateControlChildMicroIDs(); +} + + +ProjectItem::OutputType ProjectItem::outputType() const +{ + if ( !m_pParent ) + return UnknownOutput; + + switch ( m_pParent->type() ) + { + case ProjectItem::ProjectType: + { + // We're a top level build target, so look at our own type + switch ( type() ) + { + case ProjectItem::ProjectType: + kdWarning() << k_funcinfo << "Parent item and this item are both project items" << endl; + return UnknownOutput; + + case ProjectItem::FileType: + case ProjectItem::ProgramType: + return ProgramOutput; + + case ProjectItem::LibraryType: + return LibraryOutput; + } + return UnknownOutput; + } + + case ProjectItem::FileType: + { + kdWarning() << k_funcinfo << "Don't know how to handle parent item being a file" << endl; + return UnknownOutput; + } + + case ProjectItem::ProgramType: + case ProjectItem::LibraryType: + return ObjectOutput; + } + + return UnknownOutput; +} + + +bool ProjectItem::build( ProcessOptionsList * pol ) +{ + if ( !pol ) + return false; + + // Check to see that we aren't already in the ProcessOptionstList; + ProcessOptionsList::iterator polEnd = pol->end(); + for ( ProcessOptionsList::iterator it = pol->begin(); it != polEnd; ++it ) + { + if ( (*it).targetFile() == outputURL().path() ) + return true; + } + + ProjectInfo * projectInfo = ProjectManager::self()->currentProject(); + assert(projectInfo); + + if ( outputURL().isEmpty() ) + { + KMessageBox::sorry( 0l, i18n("Don't know how to build \"%1\" (output url is empty).").arg(name()) ); + return false; + } + + // Build all internal libraries that we depend on + QStringList::iterator send = m_linkedInternal.end(); + for ( QStringList::iterator it = m_linkedInternal.begin(); it != send; ++it ) + { + ProjectItem * lib = projectInfo->findItem( projectInfo->directory() + *it ); + if ( !lib ) + { + KMessageBox::sorry( 0l, i18n("Don't know how to build \"%1\" (library does not exist in project).").arg(*it) ); + return false; + } + + if ( !lib->build(pol) ) + return false; + } + + + // Build all children + m_children.remove( (ProjectItem*)0l ); + ProjectItemList::iterator cend = m_children.end(); + for ( ProjectItemList::iterator it = m_children.begin(); it != cend; ++it ) + { + if ( ! (*it)->build(pol) ) + return false; + } + + + // Now build ourself + ProcessOptions po; + po.b_addToProject = false; + po.setTargetFile( outputURL().path() ); + po.m_picID = microID(); + + ProcessOptions::ProcessPath::MediaType typeTo; + + switch ( outputType() ) + { + case UnknownOutput: + KMessageBox::sorry( 0l, i18n("Don't know how to build \"%1\" (unknown output type).").arg(name()) ); + return false; + + case ProgramOutput: + typeTo = ProcessOptions::ProcessPath::Program; + break; + + case ObjectOutput: + typeTo = ProcessOptions::ProcessPath::Object; + break; + + case LibraryOutput: + typeTo = ProcessOptions::ProcessPath::Library; + break; + } + + switch ( type() ) + { + case ProjectType: + // Nothing to do + return true; + + case FileType: + po.setInputFiles( url().path() ); + po.setProcessPath( ProcessOptions::ProcessPath::path( ProcessOptions::guessMediaType( url().url() ), typeTo ) ); + break; + + case ProgramType: + case LibraryType: + // Build up a list of input urls + QStringList inputFiles; + + // Link child objects + m_children.remove( (ProjectItem*)0l ); + ProjectItemList::iterator cend = m_children.end(); + for ( ProjectItemList::iterator it = m_children.begin(); it != cend; ++it ) + inputFiles << (*it)->outputURL().path(); + + po.setInputFiles(inputFiles); + po.setProcessPath( ProcessOptions::ProcessPath::path( ProcessOptions::ProcessPath::Object, typeTo ) ); + break; + } + + po.m_hexFormat = hexFormatToString( hexFormat() ); + po.m_bOutputMapFile = outputMapFile(); + po.m_libraryDir = libraryDir(); + po.m_linkerScript = linkerScript(); + po.m_linkOther = linkerOther(); + + // Link against libraries + QStringList::iterator lend = m_linkedInternal.end(); + for ( QStringList::iterator it = m_linkedInternal.begin(); it != lend; ++it ) + po.m_linkLibraries += projectInfo->directory() + *it; + lend = m_linkedExternal.end(); + for ( QStringList::iterator it = m_linkedExternal.begin(); it != lend; ++it ) + po.m_linkLibraries += *it; + + // Save our working file (if open) and append to the build list + Document * currentDoc = DocManager::self()->findDocument( url() ); + if (currentDoc) + currentDoc->fileSave(); + pol->append(po); + + return true; +} + + +void ProjectItem::upload( ProcessOptionsList * pol ) +{ + build( pol ); + + ProgrammerDlg * dlg = new ProgrammerDlg( microID(), (QWidget*)p_ktechlab, "Programmer Dlg" ); + + dlg->exec(); + if ( !dlg->isAccepted() ) + { + dlg->deleteLater(); + return; + } + + ProcessOptions po; + dlg->initOptions( & po ); + po.b_addToProject = false; + po.setInputFiles( outputURL().path() ); + po.setProcessPath( ProcessOptions::ProcessPath::Program_PIC ); + + pol->append( po ); + + dlg->deleteLater(); +} + + +QDomElement ProjectItem::toDomElement( QDomDocument & doc, const KURL & baseURL ) const +{ + QDomElement node = doc.createElement("item"); + + node.setAttribute( "type", typeToString() ); + node.setAttribute( "name", m_name ); + node.setAttribute( "url", KURL::relativeURL( baseURL, m_url.url() ) ); + + node.appendChild( LinkerOptions::toDomElement( doc, baseURL ) ); + node.appendChild( ProcessingOptions::toDomElement( doc, baseURL ) ); + + + ProjectItemList::const_iterator end = m_children.end(); + for ( ProjectItemList::const_iterator it = m_children.begin(); it != end; ++it ) + { + if (*it) + node.appendChild( (*it)->toDomElement( doc, baseURL ) ); + } + + return node; +} + + +KURL::List ProjectItem::childOutputURLs( unsigned types, unsigned outputTypes ) const +{ + KURL::List urls; + + ProjectItemList::const_iterator end = m_children.end(); + for ( ProjectItemList::const_iterator it = m_children.begin(); it != end; ++it ) + { + if (!*it) + continue; + + if ( ((*it)->type() & types) && ((*it)->outputType() & outputTypes) ) + urls += (*it)->outputURL().prettyURL(); + + urls += (*it)->childOutputURLs(types); + } + + return urls; +} + + +ProjectItem * ProjectItem::findItem( const KURL & url ) +{ + if ( this->url() == url ) + return this; + + ProjectItemList::const_iterator end = m_children.end(); + for ( ProjectItemList::const_iterator it = m_children.begin(); it != end; ++it ) + { + if (!*it) + continue; + + ProjectItem * found = (*it)->findItem(url); + if (found) + return found; + } + + return 0l; +} + + +bool ProjectItem::closeOpenFiles() +{ + Document * doc = DocManager::self()->findDocument(m_url); + if ( doc && !doc->fileClose() ) + return false; + + m_children.remove( (ProjectItem*)0l ); + ProjectItemList::iterator end = m_children.end(); + for ( ProjectItemList::iterator it = m_children.begin(); it != end; ++it ) + { + if ( !(*it)->closeOpenFiles() ) + return false; + } + + return true; +} + + +void ProjectItem::addFiles() +{ + KURL::List urls = p_ktechlab->getFileURLs(); + const KURL::List::iterator end = urls.end(); + for ( KURL::List::iterator it = urls.begin(); it != end; ++ it) + addFile(*it); +} + + +void ProjectItem::addCurrentFile() +{ + Document *document = DocManager::self()->getFocusedDocument(); + if (!document) + return; + + // If the file isn't saved yet, we must do that + // before it is added to the project. + if( document->url().isEmpty() ) + { + document->fileSaveAs(); + // If the user pressed cancel then just give up, + // otherwise the file can now be added. + } + + if( !document->url().isEmpty() ) + addFile( document->url() ); +} + + +void ProjectItem::addFile( const KURL & url ) +{ + if ( url.isEmpty() ) + return; + + m_children.remove( (ProjectItem*)0l ); + ProjectItemList::iterator end = m_children.end(); + for ( ProjectItemList::iterator it = m_children.begin(); it != end; ++it ) + { + if ( (*it)->type() == FileType && (*it)->url() == url ) + return; + } + + ProjectItem * item = new ProjectItem( this, FileType, m_pProjectManager, p_ktechlab ); + item->setURL(url); + addChild(item); +} + + +QString ProjectItem::typeToString() const +{ + switch (m_type) + { + case ProjectType: + return "Project"; + + case FileType: + return "File"; + + case ProgramType: + return "Program"; + + case LibraryType: + return "Library"; + } + return QString::null; +} + + +ProjectItem::Type ProjectItem::stringToType( const QString & type ) +{ + if ( type == "Project" ) + return ProjectType; + + if ( type == "File" ) + return FileType; + + if ( type == "Program" ) + return ProgramType; + + if ( type == "Library" ) + return LibraryType; + + return FileType; +} + + +void ProjectItem::domElementToItem( const QDomElement & element, const KURL & baseURL ) +{ + Type type = stringToType( element.attribute( "type", QString::null ) ); + QString name = element.attribute( "name", QString::null ); + KURL url( baseURL, element.attribute( "url", QString::null ) ); + + ProjectItem * createdItem = new ProjectItem( this, type, m_pProjectManager, p_ktechlab ); + createdItem->setName( name ); + createdItem->setURL( url ); + + addChild( createdItem ); + + QDomNode node = element.firstChild(); + while ( !node.isNull() ) + { + QDomElement childElement = node.toElement(); + if ( !childElement.isNull() ) + { + const QString tagName = childElement.tagName(); + + if ( tagName == "linker" ) + createdItem->domElementToLinkerOptions( childElement, baseURL ); + + else if ( tagName == "processing" ) + createdItem->domElementToProcessingOptions( childElement, baseURL ); + + else if ( tagName == "item" ) + createdItem->domElementToItem( childElement, baseURL ); + + else + kdError() << k_funcinfo << "Unrecognised element tag name: "<toDomElement( doc, m_url ) ); + + QTextStream stream(&file); + stream << doc.toString(); + file.close(); + + (static_cast(p_ktechlab->action("project_open_recent")))->addURL(m_url); + + return true; +} + + +bool ProjectInfo::saveAndClose() +{ + if (!save()) + return false; + + if (!closeOpenFiles()) + return false; + + return true; +} +//END class ProjectInfo + + + +//BEGIN class ProjectManager +ProjectManager * ProjectManager::m_pSelf = 0l; + +ProjectManager * ProjectManager::self( KTechlab * ktl, KateMDI::ToolView * parent ) +{ + if ( !m_pSelf ) + { + assert(ktl); + assert(parent); + m_pSelf = new ProjectManager( ktl, parent ); + } + return m_pSelf; +} + + +ProjectManager::ProjectManager( KTechlab * ktl, KateMDI::ToolView * parent ) + : ItemSelector( parent, "Project Manager" ), + m_pCurrentProject(0l), + p_ktechlab(ktl) +{ + QWhatsThis::add( this, i18n("Displays the list of files in the project.\nTo open or close a project, use the \"Project\" menu. Right click on a file to remove it from the project") ); + + setListCaption( i18n("File") ); + setCaption( i18n("Project Manager") ); + + connect( this, SIGNAL(clicked(QListViewItem*)), this, SLOT(slotItemClicked(QListViewItem*)) ); +} + + +ProjectManager::~ProjectManager() +{ +} + + +void ProjectManager::slotNewProject() +{ + if ( !slotCloseProject() ) + return; + + NewProjectDlg *newProjectDlg = new NewProjectDlg(this); + newProjectDlg->exec(); + + if ( newProjectDlg->accepted() ) + { + m_pCurrentProject = new ProjectInfo( this, p_ktechlab ); + m_pCurrentProject->setName( newProjectDlg->projectName() ); + m_pCurrentProject->setURL( newProjectDlg->location() + m_pCurrentProject->name().lower() + ".ktechlab" ); + + QDir dir; + if ( !dir.mkdir( m_pCurrentProject->directory() ) ) + kdDebug() << "Error in creating directory " << m_pCurrentProject->directory() << endl; + + m_pCurrentProject->save(); + updateActions(); + + emit projectCreated(); + } + + delete newProjectDlg; +} + + +void ProjectManager::slotProjectOptions() +{ +} + + +void ProjectManager::slotOpenProject() +{ + KURL url = KFileDialog::getOpenURL(QString::null, + "*.ktechlab|KTechlab Project(*.ktechlab)\n*|All Files", this, i18n("Open Location")); + + if ( url.isEmpty() ) + return; + + slotOpenProject(url); +} + + +void ProjectManager::slotOpenProject( const KURL & url ) +{ + if ( m_pCurrentProject && m_pCurrentProject->url() == url ) + return; + + if ( !slotCloseProject() ) + return; + + m_pCurrentProject = new ProjectInfo( this, p_ktechlab ); + + if ( !m_pCurrentProject->open(url) ) + { + m_pCurrentProject->deleteLater(); + m_pCurrentProject = 0l; + return; + } + + RecentFilesAction * rfa = static_cast(p_ktechlab->action("project_open_recent")); + rfa->addURL( m_pCurrentProject->url() ); + + if ( KTLConfig::raiseItemSelectors() ) + p_ktechlab->showToolView( p_ktechlab->toolView( toolViewIdentifier() ) ); + + updateActions(); + emit projectOpened(); +} + + +bool ProjectManager::slotCloseProject() +{ + if ( !m_pCurrentProject ) + return true; + + if ( !m_pCurrentProject->saveAndClose() ) + return false; + + m_pCurrentProject->deleteLater(); + m_pCurrentProject = 0l; + updateActions(); + emit projectClosed(); + return true; +} + + +void ProjectManager::slotCreateSubproject() +{ + if ( !currentProject() ) + return; + + CreateSubprojectDlg * dlg = new CreateSubprojectDlg(this); + dlg->exec(); + + if ( dlg->accepted() ) + { + ProjectItem::Type type = ProjectItem::ProgramType; + switch ( dlg->type() ) + { + case CreateSubprojectDlg::ProgramType: + type = ProjectItem::ProgramType; + break; + + case CreateSubprojectDlg::LibraryType: + type = ProjectItem::LibraryType; + break; + } + + ProjectItem * subproject = new ProjectItem( currentProject(), type, this, p_ktechlab ); + subproject->setURL( dlg->targetFile() ); + + currentProject()->addChild(subproject); + currentProject()->save(); + + emit subprojectCreated(); + } + + delete dlg; +} + + +void ProjectManager::updateActions() +{ + bool projectIsOpen = m_pCurrentProject; + + p_ktechlab->action("project_create_subproject")->setEnabled( projectIsOpen ); + p_ktechlab->action("project_export_makefile")->setEnabled( projectIsOpen ); + p_ktechlab->action("subproject_add_existing_file")->setEnabled( projectIsOpen ); + p_ktechlab->action("subproject_add_current_file")->setEnabled( projectIsOpen ); +// p_ktechlab->action("project_options")->setEnabled( projectIsOpen ); + p_ktechlab->action("project_close")->setEnabled( projectIsOpen ); + p_ktechlab->action("project_add_existing_file")->setEnabled( projectIsOpen ); + p_ktechlab->action("project_add_current_file")->setEnabled( projectIsOpen ); +} + + +void ProjectManager::slotAddFile() +{ + if ( !currentProject() ) + return; + + currentProject()->addFiles(); + emit filesAdded(); +} + + +void ProjectManager::slotAddCurrentFile() +{ + if ( !currentProject() ) + return; + currentProject()->addCurrentFile(); + emit filesAdded(); +} + + +void ProjectManager::slotSubprojectAddExistingFile() +{ + ILVItem * currentItem = dynamic_cast(selectedItem()); + if ( !currentItem || !currentItem->projectItem() ) + return; + + currentItem->projectItem()->addFiles(); + emit filesAdded(); +} + + +void ProjectManager::slotSubprojectAddCurrentFile() +{ + ILVItem * currentItem = dynamic_cast(selectedItem()); + if ( !currentItem || !currentItem->projectItem() ) + return; + + currentItem->projectItem()->addCurrentFile(); + emit filesAdded(); +} + + +void ProjectManager::slotItemBuild() +{ + ILVItem * currentItem = dynamic_cast(selectedItem()); + if ( !currentItem || !currentItem->projectItem() ) + return; + + ProcessOptionsList pol; + currentItem->projectItem()->build(&pol); + LanguageManager::self()->compile(pol); +} + + +void ProjectManager::slotItemUpload() +{ + ILVItem * currentItem = dynamic_cast(selectedItem()); + if ( !currentItem || !currentItem->projectItem() ) + return; + + ProcessOptionsList pol; + currentItem->projectItem()->upload(&pol); + LanguageManager::self()->compile(pol); +} + + +void ProjectManager::slotRemoveSelected() +{ + ILVItem *currentItem = dynamic_cast(selectedItem()); + if ( !currentItem ) + return; + + int choice = KMessageBox::questionYesNo( this, i18n("Do you really want to remove \"%1\"?").arg( currentItem->text(0) ), i18n("Remove Project File?"), KGuiItem(i18n("Remove")), KGuiItem(i18n("Cancel")) ); + + if ( choice == KMessageBox::No ) + return; + + currentItem->projectItem()->deleteLater(); + emit filesRemoved(); +} + + +void ProjectManager::slotExportToMakefile() +{ +} + + +void ProjectManager::slotSubprojectLinkerOptions() +{ + ILVItem * currentItem = dynamic_cast(selectedItem()); + if ( !currentItem || !currentItem->projectItem() ) + return; + + LinkerOptionsDlg * dlg = new LinkerOptionsDlg( currentItem->projectItem(), this ); + dlg->exec(); + currentProject()->save(); + + // The dialog sets the options for us if it was accepted, so we don't need to do anything + delete dlg; +} + + +void ProjectManager::slotItemProcessingOptions() +{ + ILVItem * currentItem = dynamic_cast(selectedItem()); + if ( !currentItem || !currentItem->projectItem() ) + return; + + ProcessingOptionsDlg * dlg = new ProcessingOptionsDlg( currentItem->projectItem(), this ); + dlg->exec(); + currentProject()->save(); + + // The dialog sets the options for us if it was accepted, so we don't need to do anything + delete dlg; +} + + +void ProjectManager::slotItemClicked( QListViewItem * item ) +{ + ILVItem * ilvItem = dynamic_cast(item); + if ( !ilvItem ) + return; + + ProjectItem * projectItem = ilvItem->projectItem(); + if ( !projectItem || projectItem->type() != ProjectItem::FileType ) + return; + + DocManager::self()->openURL( projectItem->url() ); +} + + +void ProjectManager::slotContextMenuRequested( QListViewItem * item, const QPoint& pos, int /*col*/ ) +{ + QString popupName; + ILVItem * ilvItem = dynamic_cast(item); + KAction * linkerOptionsAct = p_ktechlab->action("project_item_linker_options"); + linkerOptionsAct->setEnabled(false); + + if ( !m_pCurrentProject ) + popupName = "project_none_popup"; + + else if ( !ilvItem ) + popupName = "project_blank_popup"; + + else + { + ProcessOptions::ProcessPath::MediaType mediaType = ProcessOptions::guessMediaType( ilvItem->projectItem()->url().url() ); + + switch ( ilvItem->projectItem()->type() ) + { + case ProjectItem::FileType: + if ( mediaType == ProcessOptions::ProcessPath::Unknown ) + popupName = "project_file_other_popup"; + else + popupName = "project_file_popup"; + break; + + case ProjectItem::ProgramType: + popupName = "project_program_popup"; + break; + + case ProjectItem::LibraryType: + popupName = "project_library_popup"; + break; + + case ProjectItem::ProjectType: + return; + } + switch ( ilvItem->projectItem()->outputType() ) + { + case ProjectItem::ProgramOutput: + linkerOptionsAct->setEnabled(true); + break; + + case ProjectItem::ObjectOutput: + case ProjectItem::LibraryOutput: + case ProjectItem::UnknownOutput: + linkerOptionsAct->setEnabled(false); + break; + } + + // Only have linking options for SDCC files + linkerOptionsAct->setEnabled( mediaType == ProcessOptions::ProcessPath::C ); + } + + bool haveFocusedDocument = DocManager::self()->getFocusedDocument(); + p_ktechlab->action("subproject_add_current_file")->setEnabled( haveFocusedDocument ); + p_ktechlab->action("project_add_current_file")->setEnabled( haveFocusedDocument ); + + QPopupMenu *pop = static_cast(p_ktechlab->factory()->container( popupName, p_ktechlab )); + if (pop) + pop->popup(pos); +} +//END class ProjectManager + +#include "projectmanager.moc" diff --git a/src/projectmanager.h b/src/projectmanager.h new file mode 100644 index 0000000..81620cb --- /dev/null +++ b/src/projectmanager.h @@ -0,0 +1,345 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef PROJECTMANAGER_H +#define PROJECTMANAGER_H + +#include "itemselector.h" + +#include +#include +#include + +class Document; +class ILVItem; +class KTechlab; +class ProcessOptions; +class ProjectInfo; +class ProjectItem; +class ProjectManager; +class QDomDocument; +class QDomElement; +class QStringList; +namespace KateMDI { class ToolView; } + +typedef QValueList ProcessOptionsList; +typedef QValueList< QGuardedPtr > ProjectItemList; + + +class LinkerOptions +{ + public: + LinkerOptions(); + + class HexFormat + { + public: + enum type { inhx32, inhx8m, inhx8s, inhx16 }; + }; + + HexFormat::type hexFormat() const { return m_hexFormat; } + void setHexFormat( HexFormat::type hexFormat ) { m_hexFormat = hexFormat; } + + bool outputMapFile() const { return m_bOutputMapFile; } + void setOutputMapFile( bool outputMapFile ) { m_bOutputMapFile = outputMapFile; } + + QString libraryDir() const { return m_libraryDir; } + void setLibraryDir( const QString & libraryDir ) { m_libraryDir = libraryDir; } + + QString linkerScript() const { return m_linkerScript; } + void setLinkerScript( const QString & linkerScript ) { m_linkerScript = linkerScript; } + + QString linkerOther() const { return m_other; } + void setLinkerOther( const QString & other ) { m_other = other; } + + /** + * Used for linkable ProjectItems. Returns a list of urls of files + * inside the project to link against. Each url is relative to the + * project directory. + */ + QStringList linkedInternal() const { return m_linkedInternal; } + void setLinkedInternal( const QStringList & linkedInternal ) { m_linkedInternal = linkedInternal; } + + /** + * Used for linkable ProjectItems. Returns a list of urls of files + * outside the project to link against. Each url is absolute. + */ + QStringList linkedExternal() const { return m_linkedExternal; } + void setLinkedExternal( const QStringList & linkedExternal ) { m_linkedExternal = linkedExternal; } + + QDomElement toDomElement( QDomDocument & doc, const KURL & baseURL ) const; + + static QString hexFormatToString( HexFormat::type format ); + static HexFormat::type stringToHexFormat( const QString & hexFormat ); + + protected: + void domElementToLinkerOptions( const QDomElement & element, const KURL & baseURL ); + + QStringList m_linkedInternal; + QStringList m_linkedExternal; + HexFormat::type m_hexFormat; + bool m_bOutputMapFile; + QString m_libraryDir; + QString m_linkerScript; + QString m_other; +}; + + +class ProcessingOptions +{ + public: + ProcessingOptions(); + virtual ~ProcessingOptions(); + + /** + * Sets the output url that this item will be built into (if this is a + * buildable item). + */ + void setOutputURL( const KURL & url ) { m_outputURL = url; } + KURL outputURL() const { return m_outputURL; } + + /** + * Set the microprocessor id that this project item is being built for + * (when applicable). + */ + virtual void setMicroID( const QString & id ) { m_microID = id; } + virtual QString microID() const { return m_microID; } + + QDomElement toDomElement( QDomDocument & doc, const KURL & baseURL ) const; + + void setUseParentMicroID( bool useParentMicroID ) { m_bUseParentMicroID = useParentMicroID; } + bool useParentMicroID() const { return m_bUseParentMicroID; } + + protected: + void domElementToProcessingOptions( const QDomElement & element, const KURL & baseURL ); + + KURL m_outputURL; + QString m_microID; + bool m_bUseParentMicroID; +}; + + +/** +@author David Saxton +*/ +class ProjectItem : public QObject, public LinkerOptions, public ProcessingOptions +{ + public: + enum Type + { + ProjectType = 1 << 0, + FileType = 1 << 1, + ProgramType = 1 << 2, + LibraryType = 1 << 3 + }; + enum { AllTypes = ProjectType | FileType | ProgramType | LibraryType }; + + enum OutputType + { + ProgramOutput = 1 << 0, + ObjectOutput = 1 << 1, + LibraryOutput = 1 << 2, + UnknownOutput = 1 << 3 + }; + enum { AllOutputs = ProgramOutput | ObjectOutput | LibraryOutput | UnknownOutput }; + + ProjectItem( ProjectItem * parent, Type type, ProjectManager * projectManager, KTechlab * ktechlab ); + virtual ~ProjectItem(); + + Type type() const { return m_type; } + QString typeToString() const; + static Type stringToType( const QString & type ); + + void setILVItem( ILVItem * ilvItem ); + + /** + * Adds the child to the list of children, and creates an ILVItem for it + * in the project tree view. + */ + void addChild( ProjectItem * child ); + ProjectItemList children() const { return m_children; } + + void setName( const QString & name ); + QString name() const { return m_name; } + + /** + * Sets the (input) url that this project item refers to. If the output + * url has not yet been set, then this project item will set the output + * url based on this (input) url. + */ + void setURL( const KURL & url ); + KURL url() const { return m_url; } + + OutputType outputType() const; + + /** + * Returns a list of output urls of the children and their recursively + * contained children (does not include the url for this project item). + * @param types An OR'ed list of ProjectItem::Type values for the + * children. + * @param outputTypes An OR'ed list of ProjectItem::OutputType values + * for the children. + */ + KURL::List childOutputURLs( unsigned types = AllTypes, unsigned outputTypes = AllOutputs ) const; + + /** + * Creates a new ProjectItem for the given url and adds it as a child. + */ + void addFile( const KURL & url ); + /** + * Queries the user for a list of urls to add, and then calls addFile + * for each url. + */ + void addFiles(); + + void addCurrentFile(); + bool closeOpenFiles(); + QDomElement toDomElement( QDomDocument & doc, const KURL & baseURL ) const; + + bool build( ProcessOptionsList * pol ); + void upload( ProcessOptionsList * pol ); + + virtual void setMicroID( const QString & id ); + virtual QString microID() const; + + /** + * Searches this item and the children for an item for the given url, + * return null if no such item could be found. + */ + ProjectItem * findItem( const KURL & url ); + + protected: + void domElementToItem( const QDomElement & element, const KURL & baseURL ); + void updateILVItemPixmap(); + void updateControlChildMicroIDs(); + + KURL m_url; + QString m_name; + ProjectItemList m_children; + Type m_type; + + KTechlab * p_ktechlab; + QGuardedPtr m_pILVItem; + ProjectManager * m_pProjectManager; + ProjectItem * m_pParent; +}; + + +/** +@author David Saxton +*/ +class ProjectInfo : public ProjectItem +{ + Q_OBJECT + + public: + ProjectInfo( ProjectManager * projectManager, KTechlab * ktechlab ); + ~ProjectInfo(); + + /** + * Returns the directory that the project is saved in + */ + QString directory() const { return m_url.directory(false); } + + /** + * Saves the project information to file, and attempts to close all + * open project files. + * @return true iff succesful + */ + bool saveAndClose(); + bool save(); + + bool open( const KURL & url ); +}; + +/** +@short Project Management +@author David Saxton +*/ +class ProjectManager : public ItemSelector +{ + Q_OBJECT + public: + ~ProjectManager(); + static ProjectManager * self( KTechlab * ktl = 0l, KateMDI::ToolView * parent = 0l ); + + static QString toolViewIdentifier() { return "ProjectManager"; } + + /** + * @return the currently open project, or NULL if no project is open. + */ + ProjectInfo * currentProject() const { return m_pCurrentProject; } + + void updateActions(); + + signals: + /** + * Emitted when an existing project is opened. + */ + void projectOpened(); + /** + * Emitted when the current project is closed. + */ + void projectClosed(); + /** + * Emitted when a new project is created. + */ + void projectCreated(); + /** + * Emitted when a subproject is created. + */ + void subprojectCreated(); + /** + * Emitted when file(s) are added to the project or a subproject. + */ + void filesAdded(); + /** + * Emitted when file(s) are removed from the project or a subproject. + */ + void filesRemoved(); + + public slots: + void slotNewProject(); + void slotOpenProject(); + void slotOpenProject( const KURL &url ); + bool slotCloseProject(); + void slotCreateSubproject(); + void slotAddFile(); + void slotAddCurrentFile(); + void slotSubprojectAddExistingFile(); + void slotSubprojectAddCurrentFile(); + void slotItemBuild(); + void slotItemUpload(); + void slotItemProcessingOptions(); + void slotRemoveSelected(); + void slotExportToMakefile(); + void slotSubprojectLinkerOptions(); + /** + * Pops ups a project configuration dialog + */ + void slotProjectOptions(); + + private slots: + void slotContextMenuRequested( QListViewItem *item, const QPoint &pos, int col ); + /** + * Called when a user clicks on any item in the project view + */ + void slotItemClicked( QListViewItem * item ); + + protected: + ProjectInfo * m_pCurrentProject; + KTechlab * const p_ktechlab; + + private: + ProjectManager( KTechlab * ktl, KateMDI::ToolView * parent ); + static ProjectManager * m_pSelf; +}; + +#endif diff --git a/src/recentfilesaction.cpp b/src/recentfilesaction.cpp new file mode 100644 index 0000000..ac38d6b --- /dev/null +++ b/src/recentfilesaction.cpp @@ -0,0 +1,173 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "recentfilesaction.h" + +#include +#include +#include +#include + +RecentFilesAction::RecentFilesAction( const QString & configGroupName, const QString& text, const QObject* receiver, const char* slot, QObject* parent, const char* name ) + : KSelectAction( text, 0/*pix*/, parent, name ) +{ + m_configGroupName = configGroupName; + m_maxItems = 10; + + m_popup = new KPopupMenu; + connect(m_popup, SIGNAL(aboutToShow()), this, SLOT(menuAboutToShow())); + connect(m_popup, SIGNAL(activated(int)), this, SLOT(menuItemActivated(int))); + connect( this, SIGNAL( activated( const QString& ) ), + this, SLOT( itemSelected( const QString& ) ) ); + + setMenuAccelsEnabled( false ); + + if ( receiver ) + connect( this, SIGNAL(urlSelected(const KURL &)), receiver, slot ); +} + + +RecentFilesAction::~RecentFilesAction() +{ + delete m_popup; +} + +void RecentFilesAction::addURL( const KURL& url ) +{ + if ( url.isLocalFile() && !KGlobal::dirs()->relativeLocation("tmp", url.path()).startsWith("/")) + return; + + QString file; + if ( url.isLocalFile() && url.ref().isNull() && url.query().isNull() ) + file = url.path(); + else + file = url.prettyURL(); + + QStringList lst = items(); + + // remove file if already in list + lst.remove( file ); + + // remove last item if already maxitems in list + if( lst.count() == m_maxItems ) + { + // remove last item + lst.remove( lst.last() ); + } + + // add file to list + lst.prepend( file ); + setItems( lst ); + + saveEntries(); +} + + +void RecentFilesAction::loadEntries() +{ + KConfig * config = KGlobal::config(); + + QString key; + QString value; + QString oldGroup; + QStringList lst; + + oldGroup = config->group(); + + config->setGroup( m_configGroupName ); + + // read file list + for( unsigned int i = 1 ; i <= m_maxItems ; i++ ) + { + key = QString( "File%1" ).arg( i ); + value = config->readPathEntry( key ); + + if (!value.isNull()) + lst.append( value ); + } + + // set file + setItems( lst ); + + config->setGroup( oldGroup ); +} + +void RecentFilesAction::saveEntries() +{ + KConfig * config = KGlobal::config(); + + QString key; + QString value; + QString oldGroup; + QStringList lst = items(); + + oldGroup = config->group(); + + config->deleteGroup( m_configGroupName, true ); + config->setGroup( m_configGroupName ); + + // write file list + for( unsigned int i = 1 ; i <= lst.count() ; i++ ) + { + key = QString( "File%1" ).arg( i ); + value = lst[ i - 1 ]; + config->writePathEntry( key, value ); + } + + config->setGroup( oldGroup ); + + config->sync(); +} + +void RecentFilesAction::itemSelected( const QString& text ) +{ + emit urlSelected( KURL( text ) ); +} + +void RecentFilesAction::menuItemActivated( int id ) +{ + emit urlSelected( KURL(m_popup->text(id)) ); +} + +void RecentFilesAction::menuAboutToShow() +{ + KPopupMenu *menu = m_popup; + menu->clear(); + QStringList list = items(); + QStringList::iterator end = list.end(); + for ( QStringList::Iterator it = list.begin(); it != end; ++it ) + menu->insertItem(*it); +} + +void RecentFilesAction::slotClicked() +{ + KAction::slotActivated(); +} + +void RecentFilesAction::slotActivated(const QString& text) +{ + KSelectAction::slotActivated(text); +} + + +void RecentFilesAction::slotActivated(int id) +{ + KSelectAction::slotActivated(id); +} + + +void RecentFilesAction::slotActivated() +{ + emit activated( currentItem() ); + emit activated( currentText() ); +} + + +#include "recentfilesaction.moc" diff --git a/src/recentfilesaction.h b/src/recentfilesaction.h new file mode 100644 index 0000000..158e945 --- /dev/null +++ b/src/recentfilesaction.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef RECENTFILESACTION_H +#define RECENTFILESACTION_H + +#include + +/** +Taken mainly from kdelibs/kdeui/kactionclasses.[cpp/h], author Michael Koch. +Adapted to work around strange bug occuring. +*/ +class RecentFilesAction : public KSelectAction +{ + Q_OBJECT + public: + RecentFilesAction( const QString & configGroupName, const QString & text, const QObject * receiver, const char* slot, QObject* parent, const char * name ); + + ~RecentFilesAction(); + + /** + * Loads the recent files entries from a given KConfig object. + * You can provide the name of the group used to load the entries. + * If the groupname is empty, entries are load from a group called 'RecentFiles' + * + * This method does not effect the active group of KConfig. + */ + void loadEntries(); + /** + * Saves the current recent files entries to a given KConfig object. + * You can provide the name of the group used to load the entries. + * If the groupname is empty, entries are saved to a group called 'RecentFiles' + * + * This method does not effect the active group of KConfig. + */ + void saveEntries(); + /** + * Add URL to recent files list. + * + * @param url The URL of the file + */ + void addURL( const KURL& url ); + + signals: + /** + * This signal gets emited when the user selects an URL. + * + * @param url The URL thats the user selected. + */ + void urlSelected( const KURL& url ); + + protected slots: + void itemSelected( const QString& string ); + void menuAboutToShow(); + void menuItemActivated( int id ); + void slotClicked(); + virtual void slotActivated(int); + virtual void slotActivated(const QString& ); + virtual void slotActivated(); + + protected: + unsigned m_maxItems; + KPopupMenu * m_popup; + QString m_configGroupName; +}; + +#endif diff --git a/src/resizeoverlay.cpp b/src/resizeoverlay.cpp new file mode 100644 index 0000000..9d714bd --- /dev/null +++ b/src/resizeoverlay.cpp @@ -0,0 +1,746 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "itemdocument.h" +#include "mechanicsitem.h" +#include "resizeoverlay.h" + +#include +#include + + +//BEGIN class ResizeOverlay +ResizeOverlay::ResizeOverlay( Item *parent ) + : QObject(parent) +{ + b_showResizeHandles = false; + b_visible = true; + p_item = parent; +} + + +ResizeOverlay::~ResizeOverlay() +{ + const ResizeHandleMap::iterator end = m_resizeHandleMap.end(); + for ( ResizeHandleMap::iterator it = m_resizeHandleMap.begin(); it != end; ++it ) + { + if (it.data()) + it.data()->setCanvas(0l); + delete (ResizeHandle*)it.data(); + } + m_resizeHandleMap.clear(); +} + + +void ResizeOverlay::showResizeHandles( bool show ) +{ + b_showResizeHandles = show; + const ResizeHandleMap::iterator end = m_resizeHandleMap.end(); + for ( ResizeHandleMap::iterator it = m_resizeHandleMap.begin(); it != end; ++it ) + { + it.data()->setVisible(b_showResizeHandles && b_visible); + } +} + + +void ResizeOverlay::setVisible( bool visible ) +{ + b_visible = visible; + const ResizeHandleMap::iterator end = m_resizeHandleMap.end(); + for ( ResizeHandleMap::iterator it = m_resizeHandleMap.begin(); it != end; ++it ) + { + it.data()->setVisible(b_showResizeHandles && b_visible); + } +} + + +ResizeHandle *ResizeOverlay::createResizeHandle( int id, ResizeHandle::DrawType drawType, int xsnap, int ysnap ) +{ + ResizeHandleMap::iterator it = m_resizeHandleMap.find(id); + if ( it != m_resizeHandleMap.end() ) + return it.data(); + + ResizeHandle *newResizeHandle = new ResizeHandle( this, id, drawType, xsnap, ysnap ); + m_resizeHandleMap[id] = newResizeHandle; + connect( newResizeHandle, SIGNAL(rhMovedBy(int, double, double )), this, SLOT(slotResizeHandleMoved(int, double, double )) ); + return newResizeHandle; +} + + +void ResizeOverlay::removeResizeHandle( int id ) +{ + ResizeHandleMap::iterator it = m_resizeHandleMap.find(id); + if ( it == m_resizeHandleMap.end() ) + return; + + ResizeHandle *rh = it.data(); + disconnect( rh, SIGNAL(rhMovedBy(int, double, double )), this, SLOT(slotResizeHandleMoved(int, double, double )) ); + delete rh; + m_resizeHandleMap.erase(it); +} + + +ResizeHandle *ResizeOverlay::resizeHandle( int id ) +{ + ResizeHandleMap::iterator it = m_resizeHandleMap.find(id); + if ( it != m_resizeHandleMap.end() ) + return it.data(); + return 0l; +} + + +void ResizeOverlay::slotMoveAllResizeHandles( double dx, double dy ) +{ + const ResizeHandleMap::iterator end = m_resizeHandleMap.end(); + for ( ResizeHandleMap::iterator it = m_resizeHandleMap.begin(); it != end; ++it ) + { + it.data()->moveBy( dx, dy ); + } +} + + +void ResizeOverlay::syncX( ResizeHandle *rh1, ResizeHandle *rh2, ResizeHandle *rh3 ) +{ + syncX( rh1, rh2 ); + syncX( rh1, rh3 ); + syncX( rh2, rh3 ); +} +void ResizeOverlay::syncY( ResizeHandle *rh1, ResizeHandle *rh2, ResizeHandle *rh3 ) +{ + syncY( rh1, rh2 ); + syncY( rh1, rh3 ); + syncY( rh2, rh3 ); +} +void ResizeOverlay::syncX( ResizeHandle *rh1, ResizeHandle *rh2 ) +{ + if ( !rh1 || !rh2 ) + return; + connect( rh1, SIGNAL(rhMovedByX(double )), rh2, SLOT(slotMoveByX(double )) ); + connect( rh2, SIGNAL(rhMovedByX(double )), rh1, SLOT(slotMoveByX(double )) ); +} +void ResizeOverlay::syncY( ResizeHandle *rh1, ResizeHandle *rh2 ) +{ + if ( !rh1 || !rh2 ) + return; + connect( rh1, SIGNAL(rhMovedByY(double )), rh2, SLOT(slotMoveByY(double )) ); + connect( rh2, SIGNAL(rhMovedByY(double )), rh1, SLOT(slotMoveByY(double )) ); +} +//END class ResizeOverlay + + + +//BEGIN class MechanicsItemOverlay +MechanicsItemOverlay::MechanicsItemOverlay( MechanicsItem *parent ) + : ResizeOverlay(parent) +{ + p_mechanicsItem = parent; + connect( parent, SIGNAL(moved()), this, SLOT(slotUpdateResizeHandles()) ); + connect( parent, SIGNAL(resized()), this, SLOT(slotUpdateResizeHandles()) ); + + m_tl = createResizeHandle( ResizeHandle::rhp_topLeft, ResizeHandle::dt_resize_backwardsDiagonal ); + m_tm = createResizeHandle( ResizeHandle::rhp_topMiddle, ResizeHandle::dt_resize_vertical ); + m_tr = createResizeHandle( ResizeHandle::rhp_topRight, ResizeHandle::dt_resize_forwardsDiagonal ); + m_mr = createResizeHandle( ResizeHandle::rhp_middleRight, ResizeHandle::dt_resize_horizontal ); + m_br = createResizeHandle( ResizeHandle::rhp_bottomRight, ResizeHandle::dt_resize_backwardsDiagonal ); + m_bm = createResizeHandle( ResizeHandle::rhp_bottomMiddle, ResizeHandle::dt_resize_vertical ); + m_bl = createResizeHandle( ResizeHandle::rhp_bottomLeft, ResizeHandle::dt_resize_forwardsDiagonal ); + m_ml = createResizeHandle( ResizeHandle::rhp_middleLeft, ResizeHandle::dt_resize_horizontal ); + m_mm = createResizeHandle( ResizeHandle::rhp_center, ResizeHandle::dt_point_crosshair ); + + slotUpdateResizeHandles(); +} + +MechanicsItemOverlay::~MechanicsItemOverlay() +{ +} + +void MechanicsItemOverlay::slotUpdateResizeHandles() +{ + const PositionInfo absPos = p_mechanicsItem->absolutePosition(); + const QRect sizeRect = p_mechanicsItem->sizeRect(); + + QPointArray pa(9); + pa[0] = sizeRect.topLeft(); + pa[2] = sizeRect.topRight(); + pa[1] = (pa[0]+pa[2])/2; + pa[4] = sizeRect.bottomRight(); + pa[3] = (pa[2]+pa[4])/2; + pa[6] = sizeRect.bottomLeft(); + pa[5] = (pa[4]+pa[6])/2; + pa[7] = (pa[6]+pa[0])/2; + pa[8] = QPoint(0,0); + + QWMatrix m; + m.rotate(absPos.angle()*57.29577951308232); + + pa = m.map(pa); + + m_tl->move( absPos.x()+pa[0].x(), absPos.y()+pa[0].y() ); + m_tm->move( absPos.x()+pa[1].x(), absPos.y()+pa[1].y() ); + m_tr->move( absPos.x()+pa[2].x(), absPos.y()+pa[2].y() ); + m_mr->move( absPos.x()+pa[3].x(), absPos.y()+pa[3].y() ); + m_br->move( absPos.x()+pa[4].x(), absPos.y()+pa[4].y() ); + m_bm->move( absPos.x()+pa[5].x(), absPos.y()+pa[5].y() ); + m_bl->move( absPos.x()+pa[6].x(), absPos.y()+pa[6].y() ); + m_ml->move( absPos.x()+pa[7].x(), absPos.y()+pa[7].y() ); + m_mm->move( absPos.x()+pa[8].x(), absPos.y()+pa[8].y() ); +} + +void MechanicsItemOverlay::slotResizeHandleMoved( int id, double dx, double dy ) +{ + Q_UNUSED(id); + Q_UNUSED(dx); + Q_UNUSED(dy); + + switch (id) + { + case ResizeHandle::rhp_topLeft: + break; + case ResizeHandle::rhp_topMiddle: + break; + case ResizeHandle::rhp_topRight: + break; + case ResizeHandle::rhp_middleRight: + break; + case ResizeHandle::rhp_bottomRight: + break; + case ResizeHandle::rhp_bottomMiddle: + break; + case ResizeHandle::rhp_bottomLeft: + break; + case ResizeHandle::rhp_middleLeft: + break; + case ResizeHandle::rhp_center: + break; + default: + kdError() << k_funcinfo << "Unknown resize handle id " << id << endl; + break; + } +} +//END class MechanicsItemOverlay + + + +//BEGIN class RectangularOverlay +RectangularOverlay::RectangularOverlay( Item *parent, int xsnap, int ysnap ) + : ResizeOverlay(parent) +{ + connect( parent, SIGNAL(resized()), this, SLOT(slotUpdateResizeHandles()) ); + connect( parent, SIGNAL(movedBy(double, double )), this, SLOT(slotMoveAllResizeHandles(double, double )) ); + + m_tl = createResizeHandle( ResizeHandle::rhp_topLeft, ResizeHandle::dt_resize_backwardsDiagonal, xsnap, ysnap ); + m_tm = createResizeHandle( ResizeHandle::rhp_topMiddle, ResizeHandle::dt_resize_vertical, xsnap, ysnap ); + m_tr = createResizeHandle( ResizeHandle::rhp_topRight, ResizeHandle::dt_resize_forwardsDiagonal, xsnap, ysnap ); + m_mr = createResizeHandle( ResizeHandle::rhp_middleRight, ResizeHandle::dt_resize_horizontal, xsnap, ysnap ); + m_br = createResizeHandle( ResizeHandle::rhp_bottomRight, ResizeHandle::dt_resize_backwardsDiagonal, xsnap, ysnap ); + m_bm = createResizeHandle( ResizeHandle::rhp_bottomMiddle, ResizeHandle::dt_resize_vertical, xsnap, ysnap ); + m_bl = createResizeHandle( ResizeHandle::rhp_bottomLeft, ResizeHandle::dt_resize_forwardsDiagonal, xsnap, ysnap ); + m_ml = createResizeHandle( ResizeHandle::rhp_middleLeft, ResizeHandle::dt_resize_horizontal, xsnap, ysnap ); + + syncX( m_tl, m_ml, m_bl ); + syncX( m_tr, m_mr, m_br ); + syncY( m_tl, m_tm, m_tr ); + syncY( m_bl, m_bm, m_br ); + + slotUpdateResizeHandles(); +} + + +void RectangularOverlay::removeTopMiddle() +{ + if (!m_tm) + return; + removeResizeHandle( m_tm->id() ); + m_tm = 0l; +} + + +void RectangularOverlay::removeBotMiddle() +{ + if (!m_bm) + return; + removeResizeHandle( m_bm->id() ); + m_bm = 0l; +} + + +void RectangularOverlay::slotUpdateResizeHandles() +{ + const QRect sizeRect = p_item->sizeRect(); + + int x1 = sizeRect.left() + int(p_item->x()); + int x2 = x1 + sizeRect.width(); + + int y1 = sizeRect.top() + int(p_item->y()); + int y2 = y1 + sizeRect.height(); + + m_tl->move( x1, y1 ); + if (m_tm) + m_tm->move( (x1+x2)/2, y1 ); + m_tr->move( x2, y1 ); + m_mr->move( x2, (y1+y2)/2 ); + m_br->move( x2, y2 ); + if (m_bm) + m_bm->move( (x1+x2)/2, y2 ); + m_bl->move( x1, y2 ); + m_ml->move( x1, (y1+y2)/2 ); +} + + +bool RectangularOverlay::isValidXPos( ResizeHandle *rh ) +{ + Q_UNUSED(rh); + bool ok; + getSizeRect( 0l, &ok, 0l ); + return ok; +} + + +bool RectangularOverlay::isValidYPos( ResizeHandle *rh ) +{ + Q_UNUSED(rh); + bool ok; + getSizeRect( 0l, 0l, &ok ); + return ok; +} + + +void RectangularOverlay::slotResizeHandleMoved( int id, double dx, double dy ) +{ + Q_UNUSED(id); + Q_UNUSED(dx); + Q_UNUSED(dy); + + bool ok; + QRect sizeRect = getSizeRect(&ok); + if (!ok) + return; + + p_item->setSize(sizeRect); + slotUpdateResizeHandles(); +} + + +QRect RectangularOverlay::getSizeRect( bool *ok, bool *widthOk, bool *heightOk ) const +{ + bool t1,t2,t3; + if (!ok) + ok = &t1; + if (!widthOk) + widthOk = &t2; + if (!heightOk) + heightOk = &t3; + + int width = int(m_br->x() - m_tl->x()); + int height = int(m_br->y() - m_tl->y()); + + QRect sizeRect( int(m_tl->x() - p_item->x()), + int(m_tl->y() - p_item->y()), + width, height ); + + *widthOk = sizeRect.width() >= p_item->minimumSize().width(); + *heightOk = sizeRect.height() >= p_item->minimumSize().height(); + *ok = *widthOk && *heightOk; + + return sizeRect; +} +//END class RectangularOverlay + + + +//BEGIN class LineOverlay +LineOverlay::LineOverlay( Item * parent ) + : ResizeOverlay(parent) +{ + connect( parent, SIGNAL(resized()), this, SLOT(slotUpdateResizeHandles()) ); + connect( parent, SIGNAL(movedBy(double, double )), this, SLOT(slotMoveAllResizeHandles(double, double )) ); + + m_pStart = createResizeHandle( ResizeHandle::rhp_start, ResizeHandle::dt_point_rect ); + m_pEnd = createResizeHandle( ResizeHandle::rhp_end, ResizeHandle::dt_point_rect ); + + slotUpdateResizeHandles(); +} + + +QPoint LineOverlay::startPoint() const +{ + return QPoint( int(m_pStart->x()), int(m_pStart->y()) ); +} +QPoint LineOverlay::endPoint() const +{ + return QPoint( int(m_pEnd->x()), int(m_pEnd->y()) ); +} + + +void LineOverlay::slotUpdateResizeHandles() +{ + int _x = int(p_item->x() + p_item->offsetX()); + int _y = int(p_item->y() + p_item->offsetY()); + + m_pStart->move( _x, _y ); + m_pEnd->move( _x+p_item->width(), _y+p_item->height() ); +} + + +void LineOverlay::slotResizeHandleMoved( int id, double dx, double dy ) +{ + Q_UNUSED(id); + Q_UNUSED(dx); + Q_UNUSED(dy); + + p_item->setSize( int(m_pStart->x()-p_item->x()), int(m_pStart->y()-p_item->y()), + int(m_pEnd->x()-m_pStart->x()), int(m_pEnd->y()-m_pStart->y()) ); +} +//END class LineOverlay + + + +//BEGIN class ResizeHandle +ResizeHandle::ResizeHandle( ResizeOverlay *resizeOverlay, int id, DrawType drawType, int xsnap, int ysnap ) + : QObject(), QCanvasRectangle( 0, 0, 13, 13, resizeOverlay->parentItem()->canvas() ) +{ + p_resizeOverlay = resizeOverlay; + m_drawType = drawType; + m_id = id; + b_hover = false; + m_xsnap = xsnap; + m_ysnap = ysnap; + setZ( ItemDocument::Z::ResizeHandle ); +} + +ResizeHandle::~ResizeHandle() +{ + hide(); +} + +int ResizeHandle::rtti() const +{ + return ItemDocument::RTTI::ResizeHandle; +} + +void ResizeHandle::setHover( bool hover ) +{ + if ( b_hover == hover ) + return; + + b_hover = hover; + canvas()->setChanged( QRect( int(x())-8, int(y())-8, 15, 15 ) ); +} + +QPointArray ResizeHandle::areaPoints() const +{ +// QPointArray pa = QCanvasRectangle::areaPoints(); +// pa.translate( -7, -7 ); +// return pa; + return QPointArray( QRect( int(x())-8, int(y())-8, 15, 15 ) ); +} + +void ResizeHandle::moveRH( double _x, double _y ) +{ + double dx = int((_x-4)/m_xsnap)*m_xsnap+4 - x(); + double dy = int((_y-4)/m_ysnap)*m_ysnap+4 - y(); + if ( (dx == 0) && (dy == 0) ) + return; + + //BEGIN Move and check + moveBy( dx, dy ); + if ( dx != 0 ) + emit rhMovedByX(dx); + if ( dy != 0 ) + emit rhMovedByY(dy); + + bool xOk = p_resizeOverlay->isValidXPos(this); + bool yOk = p_resizeOverlay->isValidYPos(this); + + if (!xOk) + { + moveBy( -dx, 0 ); + emit rhMovedByX(-dx); + dx = 0; + } + if (!yOk) + { + moveBy( 0, -dy ); + emit rhMovedByY(-dy); + dy = 0; + } + + if ( !xOk && !yOk ) + return; + //END Move and check + + emit rhMovedBy( id(), dx, dy ); +} + +void ResizeHandle::setDrawType( DrawType drawType ) +{ + m_drawType = drawType; + canvas()->setChanged(boundingRect()); +} + +void ResizeHandle::drawShape( QPainter &p ) +{ + p.drawPixmap( rect().topLeft()-QPoint( 7, 7 ), handlePixmap( m_drawType, b_hover ) ); +} + +const QPixmap& ResizeHandle::handlePixmap( DrawType drawType, bool hover ) +{ + const char * resize_forwardsDiagonal_hover_xpm[] = { + "13 13 3 1", + " c None", + ". c #000000", + "+ c #8EA5D0", + " ", + " ....... ", + " ..+++. ", + " .++++. ", + " .+++++. ", + " . .+++++.. ", + " ...+++++... ", + " ..+++++. . ", + " .+++++. ", + " .++++. ", + " .+++.. ", + " ....... ", + " "}; + static QPixmap pixmap_forwardsDiagonal_hover(resize_forwardsDiagonal_hover_xpm); + + const char * resize_forwardsDiagonal_nohover_xpm[] = { + "13 13 2 1", + " c None", + ". c #000000", + " ", + " ....... ", + " ...... ", + " ...... ", + " ....... ", + " . ........ ", + " ........... ", + " ........ . ", + " ....... ", + " ...... ", + " ...... ", + " ....... ", + " "}; + static QPixmap pixmap_forwardsDiagonal_nohover(resize_forwardsDiagonal_nohover_xpm); + + + const char * resize_backwardsDiagonal_hover_xpm[] = { + "13 13 3 1", + " c None", + ". c #000000", + "+ c #8EA5D0", + " ", + " ....... ", + " .+++.. ", + " .++++. ", + " .+++++. ", + " ..+++++. . ", + " ...+++++... ", + " . .+++++.. ", + " .+++++. ", + " .++++. ", + " ..+++. ", + " ....... ", + " "}; + static QPixmap pixmap_backwardsDiagonal_hover(resize_backwardsDiagonal_hover_xpm); + + const char * resize_backwardsDiagonal_nohover_xpm[] = { + "13 13 2 1", + " c None", + ". c #000000", + " ", + " ....... ", + " ...... ", + " ...... ", + " ....... ", + " ........ . ", + " ........... ", + " . ........ ", + " ....... ", + " ...... ", + " ...... ", + " ....... ", + " "}; + static QPixmap pixmap_backwardsDiagonal_nohover(resize_backwardsDiagonal_nohover_xpm); + + + const char * resize_vertical_hover_xpm[] = { + "13 13 3 1", + " c None", + ". c #000000", + "+ c #8EA5D0", + " . ", + " ... ", + " ..+.. ", + " ..+++.. ", + " ..+++++.. ", + " .+++. ", + " .+++. ", + " .+++. ", + " ..+++++.. ", + " ..+++.. ", + " ..+.. ", + " ... ", + " . "}; + static QPixmap pixmap_vertical_hover(resize_vertical_hover_xpm); + + const char * resize_vertical_nohover_xpm[] = { + "13 13 2 1", + " c None", + ". c #000000", + " . ", + " ... ", + " ..... ", + " ....... ", + " ......... ", + " ..... ", + " ..... ", + " ..... ", + " ......... ", + " ....... ", + " ..... ", + " ... ", + " . "}; + static QPixmap pixmap_vertical_nohover(resize_vertical_nohover_xpm); + + + const char * resize_horizontal_hover_xpm[] = { + "13 13 3 1", + " c None", + ". c #000000", + "+ c #8EA5D0", + " ", + " ", + " . . ", + " .. .. ", + " ..+...+.. ", + " ..+++++++.. ", + "..+++++++++..", + " ..+++++++.. ", + " ..+...+.. ", + " .. .. ", + " . . ", + " ", + " "}; + static QPixmap pixmap_horizontal_hover(resize_horizontal_hover_xpm); + + const char * resize_horizontal_nohover_xpm[] = { + "13 13 2 1", + " c None", + ". c #000000", + " ", + " ", + " . . ", + " .. .. ", + " ......... ", + " ........... ", + ".............", + " ........... ", + " ......... ", + " .. .. ", + " . . ", + " ", + " "}; + static QPixmap pixmap_horizontal_nohover(resize_horizontal_nohover_xpm); + + const char * point_rect_hover_xpm[] = { + "13 13 3 1", + " c None", + ". c #000000", + "+ c #8EA5D0", + " ", + " ", + " ", + " ", + " ", + " ..... ", + " .+++. ", + " .+++. ", + " .+++. ", + " ..... ", + " ", + " ", + " "}; + static QPixmap pixmap_point_rect_hover(point_rect_hover_xpm); + + const char * point_rect_nohover_xpm[] = { + "13 13 3 1", + " c None", + ". c #000000", + "+ c #FFFFFF", + " ", + " ", + " ", + " ", + " ", + " ..... ", + " .+++. ", + " .+++. ", + " .+++. ", + " ..... ", + " ", + " ", + " "}; + static QPixmap pixmap_point_rect_nohover(point_rect_nohover_xpm); + + if (hover) + { + switch(drawType) + { + case ResizeHandle::dt_resize_forwardsDiagonal: + return pixmap_forwardsDiagonal_hover; + case ResizeHandle::dt_resize_backwardsDiagonal: + return pixmap_backwardsDiagonal_hover; + case ResizeHandle::dt_resize_vertical: + return pixmap_vertical_hover; + case ResizeHandle::dt_resize_horizontal: + return pixmap_horizontal_hover; + case ResizeHandle::dt_point_rect: + return pixmap_point_rect_hover; + + case ResizeHandle::dt_point_crosshair: + case ResizeHandle::dt_rotate_topLeft: + case ResizeHandle::dt_rotate_topRight: + case ResizeHandle::dt_rotate_bottomRight: + case ResizeHandle::dt_rotate_bottomLeft: + kdWarning() << k_funcinfo << "ResizeHandle of type " << drawType << " does not have an image." << endl; + } + } + else + { + switch(drawType) + { + case ResizeHandle::dt_resize_forwardsDiagonal: + return pixmap_forwardsDiagonal_nohover; + case ResizeHandle::dt_resize_backwardsDiagonal: + return pixmap_backwardsDiagonal_nohover; + case ResizeHandle::dt_resize_vertical: + return pixmap_vertical_nohover; + case ResizeHandle::dt_resize_horizontal: + return pixmap_horizontal_nohover; + case ResizeHandle::dt_point_rect: + return pixmap_point_rect_nohover; + + case ResizeHandle::dt_point_crosshair: + case ResizeHandle::dt_rotate_topLeft: + case ResizeHandle::dt_rotate_topRight: + case ResizeHandle::dt_rotate_bottomRight: + case ResizeHandle::dt_rotate_bottomLeft: + kdWarning() << k_funcinfo << "ResizeHandle of type " << drawType << " does not have an image." << endl; + } + } + + static QPixmap blank; + return blank; +} +//END class ResizeHandle + +#include "resizeoverlay.moc" diff --git a/src/resizeoverlay.h b/src/resizeoverlay.h new file mode 100644 index 0000000..c71e6de --- /dev/null +++ b/src/resizeoverlay.h @@ -0,0 +1,276 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef RESIZEOVERLAY_H +#define RESIZEOVERLAY_H + +// This file contains class definitions for different types of resizing and rotating + +#include +#include +#include +#include +#include + +class MechanicsItem; +class ResizeHandle; +class ResizeOverlay; +class QEvent; + +typedef QMap< int, QGuardedPtr > ResizeHandleMap; + +/** +@author David Saxton +*/ +class ResizeHandle : public QObject, public QCanvasRectangle +{ + Q_OBJECT +public: + /** + * Convenience enumeration for resize handle positioning. Note: this class + * does not make use of the values in this enumeration - it is just + * provided here for use by other classes. + */ + enum ResizeHandlePosition + { + rhp_none, + rhp_topLeft, + rhp_topMiddle, + rhp_topRight, + rhp_middleRight, + rhp_bottomRight, + rhp_bottomMiddle, + rhp_bottomLeft, + rhp_middleLeft, + rhp_center, + rhp_start, + rhp_end + }; + + enum DrawType + { + // Draws a simple rectangle + dt_point_rect, + + // Crosshair + dt_point_crosshair, + + // Straight arrows in various directions + dt_resize_forwardsDiagonal, + dt_resize_backwardsDiagonal, + dt_resize_vertical, + dt_resize_horizontal, + + // Arrows as part of an arc + dt_rotate_topLeft, + dt_rotate_topRight, + dt_rotate_bottomRight, + dt_rotate_bottomLeft + }; + + ResizeHandle( ResizeOverlay *resizeOverlay, int id, DrawType drawType, int xsnap, int ysnap ); + ~ResizeHandle(); + + int id() const { return m_id; } + int rtti() const; + + void setDrawType( DrawType drawType ); + void moveRH( double x, double y ); + void setHover( bool hover ); + + static const QPixmap& handlePixmap( DrawType drawType, bool hover ); + + virtual QPointArray areaPoints () const; + +public slots: + void slotMoveByX( double dx ) { moveBy( dx, 0 ); } + void slotMoveByY( double dy ) { moveBy( 0, dy ); } + +signals: + void rhMovedBy( int id, double dx, double dy ); + void rhMovedByX( double dx ); + void rhMovedByY( double dy ); + +protected: + virtual void drawShape( QPainter &p ); + DrawType m_drawType; + bool b_hover; // If true, then paint resize handle for mouse hovering over + int m_id; + int m_xsnap; + int m_ysnap; + ResizeOverlay *p_resizeOverlay; + +}; +typedef QValueList ResizeHandleList; + +/** +@author David Saxton +*/ +class ResizeOverlay : public QObject +{ + Q_OBJECT +public: + ResizeOverlay( Item *parent ); + ~ResizeOverlay(); + + Item *parentItem() const { return p_item; } + + /** + * Shows / hides the resize handles. They are hidden by default. + */ + void showResizeHandles( bool show ); + /** + * Sets the visibility. Visibility is true by default. + */ + void setVisible( bool visible ); + /** + * Reinherit this function to determine whether the X coordinate of the spot + * that the resize handle has moved into is valid or not + */ + virtual bool isValidXPos( ResizeHandle *rh ) { Q_UNUSED(rh); return true; } + /** + * Reinherit this function to determine whether the Y coordinate of the spot + * that the resize handle has moved into is valid or not + */ + virtual bool isValidYPos( ResizeHandle *rh ) { Q_UNUSED(rh); return true; } + +public slots: + void slotMoveAllResizeHandles( double dx, double dy ); + +protected slots: + virtual void slotResizeHandleMoved( int id, double dx, double dy ) = 0; + +protected: + /** + * Connects up the given resize handles so that they are always kept at the + * same horizontal coordinate + */ + void syncX( ResizeHandle *rh1, ResizeHandle *rh2 ); + void syncX( ResizeHandle *rh1, ResizeHandle *rh2, ResizeHandle *rh3 ); + /** + * Connects up the given resize handles so that they are always kept at the + * same vertical coordinate + */ + void syncY( ResizeHandle *rh1, ResizeHandle *rh2 ); + void syncY( ResizeHandle *rh1, ResizeHandle *rh2, ResizeHandle *rh3 ); + /** + * Returns a pointer to the ResizeHandle with the given id, or 0 if no such + * handle exists + */ + ResizeHandle *resizeHandle( int id ); + /** + * Creates and attaches the resize handle with the given DrawType. If a + * ResizeHandle with the given id exists, will return a pointer to that + * instead + */ + ResizeHandle *createResizeHandle( int id, ResizeHandle::DrawType drawType, int xsnap = 1, int ysnap = 1 ); + /** + * Removes the resize handle with the given id + */ + void removeResizeHandle( int id ); + + Item *p_item; + ResizeHandleMap m_resizeHandleMap; + bool b_showResizeHandles; + bool b_visible; +}; + + +/** +@author David Saxton +*/ +class MechanicsItemOverlay : public ResizeOverlay +{ +Q_OBJECT +public: + MechanicsItemOverlay( MechanicsItem *parent ); + ~MechanicsItemOverlay(); + +public slots: + void slotUpdateResizeHandles(); + +protected slots: + virtual void slotResizeHandleMoved( int id, double dx, double dy ); + +protected: + ResizeHandle *m_tl; + ResizeHandle *m_tm; + ResizeHandle *m_tr; + ResizeHandle *m_mr; + ResizeHandle *m_br; + ResizeHandle *m_bm; + ResizeHandle *m_bl; + ResizeHandle *m_ml; + ResizeHandle *m_mm; + MechanicsItem *p_mechanicsItem; +}; + + +/** +@author David Saxton +*/ +class RectangularOverlay : public ResizeOverlay +{ +Q_OBJECT +public: + RectangularOverlay( Item *item, int xsnap = 1, int ysnap = 1 ); + void removeTopMiddle(); + void removeBotMiddle(); + /** + * Get the size rectangle from the position of the handles. If the size + * is invalid (e.g. the parent Item does not consider it a valid size, + * then *ok is set to false; otherwise to true. + * @returns the sizerect, regardless of whether or not it is valid + */ + QRect getSizeRect( bool *ok = 0l, bool *widthOk = 0l, bool *heightOk = 0l ) const; + virtual bool isValidXPos( ResizeHandle *rh ); + virtual bool isValidYPos( ResizeHandle *rh ); + +public slots: + void slotUpdateResizeHandles(); + +protected slots: + virtual void slotResizeHandleMoved( int id, double dx, double dy ); + +protected: + ResizeHandle *m_tl; + ResizeHandle *m_tm; + ResizeHandle *m_tr; + ResizeHandle *m_mr; + ResizeHandle *m_br; + ResizeHandle *m_bm; + ResizeHandle *m_bl; + ResizeHandle *m_ml; +}; + + +/** +@author David Saxton +*/ +class LineOverlay : public ResizeOverlay +{ + Q_OBJECT + public: + LineOverlay( Item * parent ); + QPoint startPoint() const; + QPoint endPoint() const; + + public slots: + void slotUpdateResizeHandles(); + + protected slots: + virtual void slotResizeHandleMoved( int id, double dx, double dy ); + + protected: + ResizeHandle * m_pStart; + ResizeHandle * m_pEnd; +}; + +#endif diff --git a/src/simulator.cpp b/src/simulator.cpp new file mode 100644 index 0000000..c0f406d --- /dev/null +++ b/src/simulator.cpp @@ -0,0 +1,469 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "component.h" +#include "gpsimprocessor.h" +#include "pin.h" +#include "simulator.h" +#include "switch.h" + +#include +#include + + +//BEGIN class Simulator +Simulator * Simulator::m_pSelf = 0l; +static KStaticDeleter staticSimulatorDeleter; + +Simulator * Simulator::self() +{ + if (!m_pSelf) + staticSimulatorDeleter.setObject( m_pSelf, new Simulator() ); + return m_pSelf; +} + + +Simulator::Simulator() +{ + m_currentChain = 0; + m_llNumber = 0; + m_stepNumber = 0; + m_bIsSimulating = true; + m_gpsimProcessors = 0l; + m_componentCallbacks = 0l; + m_components = 0l; + m_ordinaryCircuits = 0l; + m_switches = 0l; + + unsigned max = unsigned(LOGIC_UPDATE_RATE/LINEAR_UPDATE_RATE); + for ( unsigned i = 0; i < max; i++ ) + { + m_pStartStepCallback[i] = 0l; + m_pNextStepCallback[i] = 0l; + } + + LogicConfig lc; + m_pChangedLogicStart = new LogicOut( lc, false ); + m_pChangedLogicLast = m_pChangedLogicStart; + + m_pChangedCircuitStart = new Circuit; + m_pChangedCircuitLast = m_pChangedCircuitStart; + + QTimer * stepTimer = new QTimer(this); + connect( stepTimer, SIGNAL(timeout()), this, SLOT(step()) ); + stepTimer->start(1); +} + + +Simulator::~Simulator() +{ + delete m_pChangedLogicStart; + delete m_pChangedCircuitStart; + + detachAll(m_gpsimProcessors); + detachAll(m_components); + detachAll(m_componentCallbacks); + detachAll(m_ordinaryCircuits); + detachAll(m_switches); +} + + +void Simulator::step() +{ + if (!m_bIsSimulating) + return; + + // We are called a thousand times a second (the maximum allowed by QTimer), + // so divide the LINEAR_UPDATE_RATE by 1e3 for the number of loops we need + // to do. + const unsigned maxSteps = unsigned(LINEAR_UPDATE_RATE/1e3); + for ( unsigned i = 0; i < maxSteps; ++i ) + { + m_llNumber = 0; + m_stepNumber++; + + // Update the non-logic parts of the simulation + LinkedList * component = m_components; + while (component) + { + component->data()->stepNonLogic(); + component = component->m_pNext; + } + LinkedList * circuit = m_ordinaryCircuits; + while (circuit) + { + circuit->data()->doNonLogic(); + circuit = circuit->m_pNext; + } + LinkedList * sw = m_switches; + while (sw) + { + sw->data()->bounce(); + sw = sw->m_pNext; + } + + // Update the logic parts of our simulation + const unsigned max = unsigned(LOGIC_UPDATE_RATE/LINEAR_UPDATE_RATE); + for ( m_llNumber = 0; m_llNumber < max; ++m_llNumber ) + { + // Update the logic components + LinkedList * callback = m_componentCallbacks; + while (callback) + { + callback->data()->callback(); + callback = callback->m_pNext; + } + + callback = m_pStartStepCallback[m_llNumber]; + while (callback) + { + LinkedList * next = callback->m_pNext; + callback->m_pNext = 0l; + callback->data()->callback(); + callback = next; + } + m_pStartStepCallback[m_llNumber] = 0l; + +#ifndef NO_GPSIM + // Update the gpsim processors + LinkedList * gpsimProcessor = m_gpsimProcessors; + while (gpsimProcessor) + { + gpsimProcessor->data()->executeNext(); + gpsimProcessor = gpsimProcessor->m_pNext; + } +#endif + + + int prevChain = m_currentChain; + m_currentChain = 1 - m_currentChain; + + + // Update the non-logic circuits + if ( Circuit * changed = m_pChangedCircuitStart->nextChanged(prevChain) ) + { + for ( Circuit * circuit = changed; circuit; circuit = circuit->nextChanged(prevChain) ) + circuit->setCanAddChanged(true); + + m_pChangedCircuitStart->setNextChanged( 0l, prevChain ); + m_pChangedCircuitLast = m_pChangedCircuitStart; + + do + { + Circuit * next = changed->nextChanged(prevChain); + changed->setNextChanged( 0l, prevChain ); + changed->doLogic(); + changed = next; + } + while (changed); + } + + // Call the logic callbacks + if (LogicOut * changed = m_pChangedLogicStart->nextChanged(prevChain)) + { + for ( LogicOut * out = changed; out; out = out->nextChanged(prevChain) ) + out->setCanAddChanged(true); + + m_pChangedLogicStart->setNextChanged( 0l, prevChain ); + m_pChangedLogicLast = m_pChangedLogicStart; + do + { + LogicOut * next = changed->nextChanged(prevChain); + changed->setNextChanged( 0l, prevChain ); + + double v = changed->isHigh() ? changed->outputHighVoltage() : 0.0; + + for ( PinList::iterator it = changed->pinListBegin; it != changed->pinListEnd; ++it ) + { + if ( Pin * pin = *it ) + pin->setVoltage(v); + } + + LogicIn * logicCallback = changed; + while (logicCallback) + { + logicCallback->callCallback(); + logicCallback = logicCallback->nextLogic(); + } + + changed = next; + } + while (changed); + } + } + } +} + + +void Simulator::slotSetSimulating( bool simulate ) +{ + if ( m_bIsSimulating == simulate ) + return; + + m_bIsSimulating = simulate; + emit simulatingStateChanged(simulate); +} + + +void Simulator::createLogicChain( LogicOut * logicOut, const LogicInList & logicInList, const PinList & pinList ) +{ + if (!logicOut) + return; + + bool state = logicOut->outputState(); + + logicOut->setUseLogicChain(true); + logicOut->pinList = pinList; + logicOut->pinListBegin = logicOut->pinList.begin(); + logicOut->pinListEnd = logicOut->pinList.end(); + + LogicIn * last = logicOut; + const LogicInList::const_iterator end = logicInList.end(); + for ( LogicInList::const_iterator it = logicInList.begin(); it != end; ++it ) + { + LogicIn * next = *it; + last->setNextLogic(next); + last->setLastState(state); + last = next; + } + last->setNextLogic(0l); + last->setLastState(state); + + // Mark it as changed, if it isn't already changed... + LogicOut * changed = m_pChangedLogicStart->nextChanged(m_currentChain); + while (changed) + { + if ( changed == logicOut ) + return; + changed = changed->nextChanged(m_currentChain); + } + addChangedLogic(logicOut); + logicOut->setCanAddChanged(false); + + if ( !m_logicChainStarts.contains( logicOut ) ) + m_logicChainStarts << logicOut; +} + + +template +void Simulator::attach( LinkedList ** start, T * data ) +{ + if (!data) + return; + + while ( *start && (*start)->m_pNext ) + { + if ( (*start)->data() == data ) + return; + start = & (*start)->m_pNext; + } + + if (*start) + (*start)->m_pNext = new LinkedList(data); + else + *start = new LinkedList(data); +} + + +template +void Simulator::detach( LinkedList ** start, T * data ) +{ + if (!data) + return; + + while (*start) + { + if ( (*start)->data() == data ) + { + LinkedList * toDelete = *start; + *start = (*start)->m_pNext; + delete toDelete; + return; + } + + start = & (*start)->m_pNext; + } +} + + +template +void Simulator::detachAll( LinkedList * list ) +{ + while (list) + { + LinkedList * next = list->m_pNext; + delete list; + list = next; + } +} + + +void Simulator::attachGpsimProcessor( GpsimProcessor * cpu ) +{ + attach( & m_gpsimProcessors, cpu ); +} + + +void Simulator::detachGpsimProcessor( GpsimProcessor * cpu ) +{ + detach( & m_gpsimProcessors, cpu ); +} + + +void Simulator::attachComponentCallback( Component * component, VoidCallbackPtr function ) +{ + attach( & m_componentCallbacks, new ComponentCallback( component, function ) ); +} + + +void Simulator::attachComponent( Component * component ) +{ + if ( !component || !component->doesStepNonLogic() ) + return; + + attach( & m_components, component ); +} + + +void Simulator::detachComponent( Component * component ) +{ + detach( & m_components, component ); + detachComponentCallbacks(component); +} + + +void Simulator::attachSwitch( Switch * sw ) +{ + attach( & m_switches, sw ); +} + + +void Simulator::detachSwitch( Switch * sw ) +{ + detach( & m_switches, sw ); +} + + +void Simulator::detachComponentCallbacks( Component * component ) +{ + LinkedList * callback = m_componentCallbacks; + while (callback) + { + LinkedList * next = callback->m_pNext; + ComponentCallback * data = callback->data(); + if ( data->component() == component ) + { + detach( & m_componentCallbacks, data ); + delete data; + } + callback = next; + } +} + + +void Simulator::attachCircuit( Circuit * circuit ) +{ + if (!circuit) + return; + attach( & m_ordinaryCircuits, circuit ); + addChangedCircuit(circuit); + circuit->setCanAddChanged(false); +} + + +void Simulator::removeLogicInReferences( LogicIn * logicIn ) +{ + if ( !logicIn ) + return; + + QValueList::iterator end = m_logicChainStarts.end(); + for ( QValueList::iterator it = m_logicChainStarts.begin(); it != end; ++it ) + { + LogicIn * logicCallback = *it; + while (logicCallback) + { + if ( logicCallback->nextLogic() == logicIn ) + logicCallback->setNextLogic( logicCallback->nextLogic()->nextLogic() ); + logicCallback = logicCallback->nextLogic(); + } + } +} + + +void Simulator::removeLogicOutReferences( LogicOut * logic ) +{ + m_logicChainStarts.remove( logic ); + + // Any changes to the code below will probably also apply to Simulator::detachCircuit + + if ( m_pChangedLogicLast == logic ) + { + LogicOut * previous_1 = 0l; + LogicOut * previous_2 = 0l; + for ( LogicOut * logic = m_pChangedLogicStart; logic; ) + { + if (previous_1) + previous_2 = previous_1; + previous_1 = logic; + logic = logic->nextChanged( m_currentChain ); + } + + m_pChangedLogicLast = previous_2; + } + + for ( unsigned chain = 0; chain < 2; ++chain ) + { + for ( LogicOut * prevChanged = m_pChangedLogicStart; prevChanged; prevChanged = prevChanged->nextChanged( chain ) ) + { + LogicOut * nextChanged = prevChanged->nextChanged( chain ); + if ( nextChanged == logic ) + prevChanged->setNextChanged( nextChanged->nextChanged( chain ), chain ); + } + } +} + + +void Simulator::detachCircuit( Circuit * circuit ) +{ + if (!circuit) + return; + + detach( & m_ordinaryCircuits, circuit ); + + // Any changes to the code below will probably also apply to Simulator::removeLogicOutReferences + + if ( m_pChangedCircuitLast == circuit ) + { + Circuit * previous_1 = 0l; + Circuit * previous_2 = 0l; + for ( Circuit * circuit = m_pChangedCircuitStart; circuit; ) + { + if (previous_1) + previous_2 = previous_1; + previous_1 = circuit; + circuit = circuit->nextChanged( m_currentChain ); + } + + m_pChangedCircuitLast = previous_2; + } + + for ( unsigned chain = 0; chain < 2; ++chain ) + { + for ( Circuit * prevChanged = m_pChangedCircuitStart; prevChanged; prevChanged = prevChanged->nextChanged( chain ) ) + { + Circuit * nextChanged = prevChanged->nextChanged( chain ); + if ( nextChanged == circuit ) + prevChanged->setNextChanged( nextChanged->nextChanged( chain ), chain ); + } + } +} +//END class Simulator + +#include "simulator.moc" diff --git a/src/simulator.h b/src/simulator.h new file mode 100644 index 0000000..a6ade3a --- /dev/null +++ b/src/simulator.h @@ -0,0 +1,247 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef SIMULATOR_H +#define SIMULATOR_H + +#include "circuit.h" +#include "logic.h" + +/** +This should be a multiple of 1000. It is the number of times a second that +linear elements are updated. +*/ +const int LINEAR_UPDATE_RATE = int(1e4); + +/** +This should be a multiple of 1000. It is the number of times a second that +logic elements are updated. +*/ +const int LOGIC_UPDATE_RATE = int(1e6); + + +class Circuit; +class CircuitDocument; +class Component; +class ComponentCallback; +class ECNode; +class GpsimProcessor; +class LogicIn; +class LogicOut; +class Switch; +class Wire; + +typedef QValueList ECNodeList; +typedef QValueList LogicInList; + +typedef void(Component::*VoidCallbackPtr)(); + +template +class LinkedList +{ + public: + LinkedList( T * data ) { m_pData = data; m_pNext = 0l; } + T * data() const { return m_pData; } + + LinkedList * m_pNext; + + protected: + T * m_pData; +}; + + +class ComponentCallback +{ + public: + ComponentCallback( Component * component, VoidCallbackPtr function ) + { + m_pComponent = component; + m_pFunction = function; + } + + void callback() { (m_pComponent->*m_pFunction)(); } + Component * component() const { return m_pComponent; } + + protected: + Component * m_pComponent; + VoidCallbackPtr m_pFunction; +}; + + +/** +This singleton class oversees all simulation (keeping in sync linear, nonlinear, +logic, external simulators (such as gpsim), mechanical simulation, etc). +@author David Saxton +*/ +class Simulator : public QObject +{ + Q_OBJECT + public: + static Simulator * self(); + ~Simulator(); + + /** + * Number of (1/LOGIC_UPDATE_RATE) intervals that the simulator has been + * stepping for. + */ + long long time() const { return m_stepNumber*(long long)(LOGIC_UPDATE_RATE/LINEAR_UPDATE_RATE) + m_llNumber; } + /** + * Initializes a new logic chain. + */ + void createLogicChain( LogicOut * logicOut, const LogicInList & logicInList, const PinList & pinList ); + /** + * Adds the given LogicOut to the list of changed LogicOuts + */ + void addChangedLogic( LogicOut * changed ) + { + m_pChangedLogicLast->setNextChanged( changed, m_currentChain ); + m_pChangedLogicLast = changed; + } + /** + * Remove pointers to the given LogicOut, called when it is deleted for + * safety reasons. + */ + void removeLogicOutReferences( LogicOut * logic ); + /** + * Remove pointers to the given LogicIn, called when it is deleted for + * safety reasons. Simulator does not have any references to LogicIns + * itself - instead, they are removed from logic chains which are + * currently marked as changed. + */ + void removeLogicInReferences( LogicIn * logic ); + /** + * Adds the given Circuit to the list of changed Circuits + */ + void addChangedCircuit( Circuit * changed ) + { + m_pChangedCircuitLast->setNextChanged( changed, m_currentChain ); + m_pChangedCircuitLast = changed; + } + inline void addStepCallback( int at, LinkedList * ccb ); + /** + * Add the given processor to the simulator. GpsimProcessor::step will + * be called while present in the simulator (it is at GpsimProcessor's + * disgression whether to actually step, depending on its running + * status). + * @see detachGpsimProcessor( GpsimProcessor * cpu ); + */ + void attachGpsimProcessor( GpsimProcessor * cpu ); + /** + * Remove the given processor from the simulation loop + */ + void detachGpsimProcessor( GpsimProcessor * cpu ); + /** + * Attach the component callback to the simulator. This will be called + * during the logic update loop, at LOGIC_UPDATE_RATE times per second (so + * make sure the function passed is an efficient one!). + */ + void attachComponentCallback( Component * component, VoidCallbackPtr function ); + /** + * Removes the callbacks for the given component from the simulator. + */ + void detachComponentCallbacks( Component * component ); + /** + * Attach the component to the simulator. + */ + void attachComponent( Component * component ); + /** + * Detaches the component from the simulator. + */ + void detachComponent( Component * component ); + /** + * Attach a circuit to the simulator + */ + void attachCircuit( Circuit * circuit ); + /** + * Detach a circuit from the simulator. + */ + void detachCircuit( Circuit * circuit ); + /** + * Attaches the switch to the simulator (only needed when the switch has + * started bouncing. + */ + void attachSwitch( Switch * sw ); + /** + * Detaches the switch from the simulator (called when the switch has + * stopped bouncing). + */ + void detachSwitch( Switch * sw ); + /** + * @return whether or not we are currently simulating stuff + * @see slotSetSimulating + */ + bool isSimulating() const { return m_bIsSimulating; } + + public slots: + /** + * Set whether or not to simulate at the moment. + * @see isSimulating + */ + void slotSetSimulating( bool simulate ); + + signals: + /** + * Emitted when the simulating state changes. + * @see slotSetSimulating + */ + void simulatingStateChanged( bool isSimulating ); + + private slots: + void step(); + + protected: + template + void attach( LinkedList ** start, T * data ); + template + void detach( LinkedList ** start, T * data ); + template + void detachAll( LinkedList * list ); + + bool m_bIsSimulating; + static Simulator * m_pSelf; + + ///List of LogicOuts that are at the start of a LogicChain + QValueList m_logicChainStarts; + + LogicOut * m_pChangedLogicStart; + LogicOut * m_pChangedLogicLast; + + Circuit * m_pChangedCircuitStart; + Circuit * m_pChangedCircuitLast; + + LinkedList * m_gpsimProcessors; + LinkedList * m_components; + LinkedList * m_componentCallbacks; + LinkedList * m_ordinaryCircuits; + LinkedList * m_switches; + + LinkedList * m_pStartStepCallback[LOGIC_UPDATE_RATE/LINEAR_UPDATE_RATE]; + LinkedList * m_pNextStepCallback[LOGIC_UPDATE_RATE/LINEAR_UPDATE_RATE]; + + private: + Simulator(); + long m_llNumber; + long long m_stepNumber; + unsigned char m_currentChain; +}; + + +inline void Simulator::addStepCallback( int at, LinkedList * ccb ) +{ + if ( !m_pStartStepCallback[at] ) + m_pStartStepCallback[at] = ccb; + + else + m_pNextStepCallback[at]->m_pNext = ccb; + + m_pNextStepCallback[at] = ccb; +} + +#endif diff --git a/src/textdocument.cpp b/src/textdocument.cpp new file mode 100644 index 0000000..ba03c04 --- /dev/null +++ b/src/textdocument.cpp @@ -0,0 +1,1146 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "asmformatter.h" +#include "asminfo.h" +#include "asmparser.h" +#include "debugmanager.h" +#include "docmanager.h" +#include "documentiface.h" +#include "filemetainfo.h" +#include "gpsimprocessor.h" +#include "ktechlab.h" +#include "language.h" +#include "languagemanager.h" +#include "microselectwidget.h" +#include "programmerdlg.h" +#include "symbolviewer.h" +#include "textdocument.h" +#include "textview.h" + +// #include + +#include +#include +#include +#include +#include + + +TextDocument *TextDocument::constructTextDocument( const QString& caption, KTechlab *parent, const char *name ) +{ + TextDocument *textDocument = new TextDocument( caption, parent, name); + if( textDocument->m_constructorSuccessful ) + return textDocument; + delete textDocument; + return 0L; +} + + +TextDocument::TextDocument( const QString &caption, KTechlab *ktechlab, const char *name ) + : Document( caption, ktechlab, name ), + m_doc(0) +{ + m_constructorSuccessful = false; + +#ifndef NO_GPSIM + m_bOwnDebugger = false; + b_lockSyncBreakpoints = false; + m_lastDebugLineAt = -1; + m_pDebugger = 0l; +#endif + + m_pLastTextOutputTarget = 0l; + m_guessedCodeType = TextDocument::ct_unknown; + m_type = Document::dt_text; + m_bookmarkActions.setAutoDelete(true); + m_pDocumentIface = new TextDocumentIface(this); + + KLibFactory *factory = KLibLoader::self()->factory("libkatepart"); + if(!factory) + { + KMessageBox::sorry( ktechlab, i18n("Libkatepart not available for constructing editor") ); + return; + } + m_doc = (Kate::Document*)(KTextEditor::Document *)factory->create( 0L, "kate", "KTextEditor::Document"); + + guessScheme(); + + connect( m_doc, SIGNAL(undoChanged()), this, SIGNAL(undoRedoStateChanged()) ); + connect( m_doc, SIGNAL(undoChanged()), this, SLOT(slotSyncModifiedStates()) ); + connect( m_doc, SIGNAL(textChanged()), this, SLOT(slotSyncModifiedStates()) ); + connect( m_doc, SIGNAL(marksChanged()), this, SLOT(slotUpdateMarksInfo()) ); + connect( m_doc, SIGNAL(selectionChanged()), this, SLOT(slotSelectionmChanged()) ); + + m_doc->setDescription((KTextEditor::MarkInterface::MarkTypes)Breakpoint, i18n("Breakpoint")); + m_doc->setPixmap((KTextEditor::MarkInterface::MarkTypes)Breakpoint, *inactiveBreakpointPixmap()); + m_doc->setPixmap((KTextEditor::MarkInterface::MarkTypes)ActiveBreakpoint, *activeBreakpointPixmap()); + m_doc->setPixmap((KTextEditor::MarkInterface::MarkTypes)ReachedBreakpoint, *reachedBreakpointPixmap()); + m_doc->setPixmap((KTextEditor::MarkInterface::MarkTypes)DisabledBreakpoint, *disabledBreakpointPixmap()); + m_doc->setPixmap((KTextEditor::MarkInterface::MarkTypes)ExecutionPoint, *executionPointPixmap()); + m_doc->setMarksUserChangable( Bookmark | Breakpoint ); + + m_constructorSuccessful = true; +} + + +TextDocument::~TextDocument() +{ + if( !m_constructorSuccessful ) + return; + + debugStop(); + + ViewList::iterator end = m_viewList.end(); + for ( ViewList::iterator it = m_viewList.begin(); it != end; ++it ) + { + if ( TextView * tv = dynamic_cast( (View*)*it) ) + { + Kate::View * kv = tv->kateView(); + p_ktechlab->factory()->removeClient( kv ); + } + } + + delete m_doc; + m_doc = 0l; + + delete m_pDocumentIface; + m_pDocumentIface = 0l; +} + + +bool TextDocument::fileClose() +{ + const QString path = url().prettyURL(); + if ( !path.isEmpty() ) + fileMetaInfo()->grabMetaInfo( path, this ); + + return Document::fileClose(); +} + + +TextView* TextDocument::textView() const +{ + return static_cast(activeView()); +} + + +View * TextDocument::createView( ViewContainer *viewContainer, uint viewAreaId, const char *name ) +{ + TextView * textView = new TextView( this, viewContainer, viewAreaId, name ); + + fileMetaInfo()->initializeFromMetaInfo( url().prettyURL(), textView ); + + handleNewView(textView); + return textView; +} + + +Kate::View* TextDocument::createKateView( QWidget *parent, const char *name ) +{ + return static_cast((m_doc->createView( parent, name ))->qt_cast("Kate::View")); +} + + +void TextDocument::cut() +{ + if (textView()) + textView()->cut(); +} +void TextDocument::copy() +{ + if (textView()) + textView()->copy(); +} +void TextDocument::paste() +{ + if (textView()) + textView()->paste(); +} + + +void TextDocument::setText( const QString & text, bool asInitial ) +{ + if ( asInitial ) + { + disconnect( m_doc, SIGNAL(undoChanged()), this, SIGNAL(undoRedoStateChanged()) ); + disconnect( m_doc, SIGNAL(undoChanged()), this, SLOT(slotSyncModifiedStates()) ); + disconnect( m_doc, SIGNAL(textChanged()), this, SLOT(slotSyncModifiedStates()) ); + } + + const ViewList::iterator end = m_viewList.end(); + for ( ViewList::iterator it = m_viewList.begin(); it != end; ++it ) + (static_cast((View*)*it))->saveCursorPosition(); + + m_doc->setText(text); + + for ( ViewList::iterator it = m_viewList.begin(); it != end; ++it ) + (static_cast((View*)*it))->restoreCursorPosition(); + + if ( asInitial ) + { + m_doc->clearUndo(); + m_doc->clearRedo(); + setModified(false); + + connect( m_doc, SIGNAL(undoChanged()), this, SIGNAL(undoRedoStateChanged()) ); + connect( m_doc, SIGNAL(undoChanged()), this, SLOT(slotSyncModifiedStates()) ); + connect( m_doc, SIGNAL(textChanged()), this, SLOT(slotSyncModifiedStates()) ); + } +} + + +void TextDocument::undo() +{ + m_doc->undo(); + slotSyncModifiedStates(); +} + + +void TextDocument::redo() +{ + m_doc->redo(); + slotSyncModifiedStates(); +} + + +void TextDocument::slotSyncModifiedStates() +{ + setModified( m_doc->isModified() ); +} +void TextDocument::setModified( bool modified ) +{ + if ( (modified == b_modified) && (modified == isModified()) ) { + return; + } + m_doc->setModified(modified); + b_modified = modified; + + emit modifiedStateChanged(); +} + + +void TextDocument::guessScheme( bool allowDisable ) +{ + // And specific file actions depending on the current type of file + QString fileName = url().fileName(); + QString extension = fileName.right( fileName.length() - fileName.findRev('.') - 1 ); + + if ( extension == "asm" || extension == "src" || extension == "inc" ) + slotInitLanguage(ct_asm); + + else if ( extension == "hex" ) + slotInitLanguage(ct_hex); + + else if ( extension == "basic" || extension == "microbe" ) + slotInitLanguage(ct_microbe); + + else if ( extension == "c" ) + slotInitLanguage(ct_c); + + else if ( m_guessedCodeType != TextDocument::ct_unknown ) + slotInitLanguage(m_guessedCodeType); + + else if ( allowDisable && activeView() ) + textView()->disableActions(); +} + + +void TextDocument::slotInitLanguage( CodeType type ) +{ + QString hlName; + + switch (type) + { + case ct_asm: + hlName = "PicAsm"; + break; + + case ct_c: + hlName = "C"; + break; + + case ct_hex: + break; + + case ct_microbe: + hlName = "Microbe"; + break; + + case ct_unknown: + break; + } + + if ( !hlName.isEmpty() ) + { + int i = 0; + int hlModeCount = m_doc->hlModeCount(); + while ( ihlModeName(i) != hlName ) + i++; + + m_doc->setHlMode(i); + } + + m_guessedCodeType = type; + + ViewList::iterator end = m_viewList.end(); + for ( ViewList::iterator it = m_viewList.begin(); it != end; ++it ) + { + if ( TextView * tv = dynamic_cast( (View*)*it ) ) + tv->initCodeActions(); + } +} + + +void TextDocument::formatAssembly() +{ + AsmFormatter formatter; + QStringList lines = QStringList::split( "\n", m_doc->text(), true ); + setText( formatter.tidyAsm(lines), false ); + setModified(true); +} + + +void TextDocument::fileSave( const KURL& url ) +{ + if ( m_doc->url().path() != url.path() ) + { + kdError() << k_funcinfo << "Error: Kate::View url and passed url do not match; cannot save." << endl; + return; + } + + if ( activeView() && (textView()->save() == Kate::View::SAVE_OK ) ) + saveDone(); +} + + +void TextDocument::fileSaveAs() +{ + if ( activeView() && (textView()->saveAs() == Kate::View::SAVE_OK) ) + saveDone(); + + // Our modified state may not have changed, but we emit this to force the + // main window to update our caption. + emit modifiedStateChanged(); +} + + +void TextDocument::saveDone() +{ + setURL( m_doc->url() ); + guessScheme(false); + setModified(false); + emit modifiedStateChanged(); +} + + +bool TextDocument::openURL( const KURL& url ) +{ + m_doc->openURL(url); + setURL(url); + + fileMetaInfo()->initializeFromMetaInfo( url.prettyURL(), this ); + guessScheme(); + +#ifndef NO_GPSIM + DebugManager::self()->urlOpened( this ); +#endif + + return true; +} + + +void TextDocument::setLastTextOutputTarget( TextDocument * target ) +{ + m_pLastTextOutputTarget = target; +} + + +QString TextDocument::outputFilePath( const QString &ext ) +{ + QString filePath = url().path(); + if ( filePath.isEmpty() ) + { + KTempFile f( QString::null, ext ); + (*f.textStream()) << m_doc->text(); + f.close(); + DocManager::self()->associateDocument( f.name(), this ); + return f.name(); + } + if ( isModified() ) + { + fileSave(); + } + return filePath; +} + + +void TextDocument::slotConvertTo( int target ) +{ + switch ( (ConvertToTarget)target ) + { + case TextDocument::MicrobeOutput: + break; + + case TextDocument::AssemblyOutput: + convertToAssembly(); + break; + + case TextDocument::HexOutput: + convertToHex(); + break; + + case TextDocument::PICOutput: + convertToPIC(); + break; + } +} + + +void TextDocument::convertToAssembly() +{ + QString filePath; + bool showPICSelect = false; + ProcessOptions::ProcessPath::MediaType toType; + + if ( m_guessedCodeType == TextDocument::ct_microbe ) + { + toType = ProcessOptions::ProcessPath::AssemblyAbsolute; + filePath = outputFilePath(".microbe"); + } + + else if ( m_guessedCodeType == TextDocument::ct_hex ) + { + toType = ProcessOptions::ProcessPath::Disassembly; + filePath = outputFilePath(".hex"); + } + + else if ( m_guessedCodeType == TextDocument::ct_c ) + { + toType = ProcessOptions::ProcessPath::AssemblyRelocatable; + filePath = outputFilePath(".c"); + showPICSelect = true; + } + + else + { + kdError() << "Could not get file type for converting to assembly!"<setAllowedAsmSet( AsmInfo::PIC14 | AsmInfo::PIC16 ); + + dlg.setOutputExtension(".asm"); + dlg.setFilter("*.asm *.src *.inc|Assembly Code (*.asm, *.src, *.inc)\n*|All Files"); + dlg.exec(); + if (!dlg.isAccepted()) + return; + + ProcessOptions o( dlg.info() ); + o.setTextOutputTarget( m_pLastTextOutputTarget, this, SLOT(setLastTextOutputTarget( TextDocument* )) ); + o.setInputFiles(filePath); + o.setProcessPath( ProcessOptions::ProcessPath::path( ProcessOptions::guessMediaType(filePath), toType ) ); + LanguageManager::self()->compile(o); +} + + +void TextDocument::convertToHex() +{ + QString filePath; + bool showPICSelect = false; + + if ( m_guessedCodeType == TextDocument::ct_microbe ) + filePath = outputFilePath(".microbe"); + + else if ( m_guessedCodeType == TextDocument::ct_asm ) + filePath = outputFilePath(".asm"); + + else if ( m_guessedCodeType == TextDocument::ct_c ) + { + filePath = outputFilePath(".c"); + showPICSelect = true; + } + + else + { + kdError() << "Could not get file type for converting to hex!"<setAllowedAsmSet( AsmInfo::PIC14 | AsmInfo::PIC16 ); + + dlg.exec(); + if (!dlg.isAccepted()) + return; + + ProcessOptions o( dlg.info() ); + o.setTextOutputTarget( m_pLastTextOutputTarget, this, SLOT(setLastTextOutputTarget( TextDocument* )) ); + o.setInputFiles(filePath); + o.setProcessPath( ProcessOptions::ProcessPath::path( ProcessOptions::guessMediaType(filePath), ProcessOptions::ProcessPath::Program ) ); + LanguageManager::self()->compile(o); +} + + +void TextDocument::convertToPIC() +{ + QString filePath; + + QString picID; + + switch ( m_guessedCodeType ) + { + case ct_microbe: + filePath = outputFilePath(".microbe"); + break; + + case ct_asm: + { + filePath = outputFilePath(".asm"); + AsmParser p( filePath ); + p.parse(); + picID = p.picID(); + break; + } + + case ct_c: + filePath = outputFilePath(".c"); + break; + + case ct_hex: + filePath = outputFilePath(".hex"); + break; + + case ct_unknown: + kdError() << "Could not get file type for converting to hex!"<microSelect()->setAllowedAsmSet( AsmInfo::PIC14 | AsmInfo::PIC16 ); + + dlg->exec(); + if ( !dlg->isAccepted() ) + { + dlg->deleteLater(); + return; + } + + ProcessOptions o; + dlg->initOptions( & o ); + o.setInputFiles( filePath ); + o.setProcessPath( ProcessOptions::ProcessPath::path( ProcessOptions::guessMediaType(filePath), ProcessOptions::ProcessPath::Pic ) ); + LanguageManager::self()->compile( o ); + + dlg->deleteLater(); +} + + +void TextDocument::print() +{ + KTextEditor::printInterface(m_doc)->print (); +} + + +void TextDocument::slotSelectionmChanged() +{ + p_ktechlab->action( "edit_cut" )->setEnabled( m_doc->hasSelection () ); + p_ktechlab->action( "edit_copy" )->setEnabled( m_doc->hasSelection () ); +} + + +IntList TextDocument::bookmarkList() const +{ + IntList bookmarkList; + + typedef QPtrList MarkList; + MarkList markList = m_doc->marks(); + + // Find out what marks need adding to our internal lists + for ( KTextEditor::Mark * mark = markList.first(); mark; mark = markList.next() ) + { + if ( mark->type & Bookmark ) + bookmarkList += mark->line; + } + + return bookmarkList; +} + + +void TextDocument::slotUpdateMarksInfo() +{ + if ( activeView() ) + textView()->slotUpdateMarksInfo(); + +#ifndef NO_GPSIM + syncBreakpoints(); +#endif + + // Update our list of bookmarks in the menu + p_ktechlab->unplugActionList("bookmark_actionlist"); + m_bookmarkActions.clear(); + + QPtrList markList = m_doc->marks(); + + // Find out what marks need adding to our internal lists + for ( KTextEditor::Mark * mark = markList.first(); mark; mark = markList.next() ) + { + if ( mark->type & Bookmark ) + { + KAction * a = new KAction( i18n("%1 - %2").arg( QString::number( mark->line+1 ) ).arg( m_doc->textLine(mark->line) ), + 0, this, SLOT(slotBookmarkRequested()), this, + QString("bookmark_%1").arg(QString::number(mark->line).ascii()) ); + m_bookmarkActions.append(a); + } + } + + p_ktechlab->plugActionList( "bookmark_actionlist", m_bookmarkActions ); +} + + +void TextDocument::slotBookmarkRequested() +{ + const QObject * s = sender(); + if (!s) return; + + QString name = s->name(); + if ( !name.startsWith("bookmark_") ) + return; + + name.remove("bookmark_"); + int line = -1; + bool ok; + line = name.toInt(&ok); + if ( ok && line >= 0 && activeView() ) + (static_cast(activeView()))->gotoLine(line); +} + + +void TextDocument::setBookmarks( const IntList &lines ) +{ + clearBookmarks(); + const IntList::const_iterator end = lines.end(); + for ( IntList::const_iterator it = lines.begin(); it != end; ++it ) + setBookmark( *it, true ); +} + + +void TextDocument::clearBookmarks() +{ + QPtrList markList = m_doc->marks(); + + // Find out what marks need adding to our internal lists + for ( KTextEditor::Mark * mark = markList.first(); mark; mark = markList.next() ) + { + if ( mark->type & Bookmark ) + m_doc->removeMark( mark->line, Bookmark ); + } + + slotUpdateMarksInfo(); +} + + +void TextDocument::setBookmark( uint line, bool isBookmark ) +{ + if (isBookmark) + m_doc->addMark( line, Bookmark ); + + else + m_doc->removeMark( line, Bookmark ); +} + + +void TextDocument::setBreakpoints( const IntList &lines ) +{ +#ifndef NO_GPSIM + clearBreakpoints(); + const IntList::const_iterator end = lines.end(); + for ( IntList::const_iterator it = lines.begin(); it != end; ++it ) + setBreakpoint( *it, true ); +#endif // !NO_GPSIM +} + + +IntList TextDocument::breakpointList() const +{ + IntList breakpointList; + +#ifndef NO_GPSIM + typedef QPtrList MarkList; + MarkList markList = m_doc->marks(); + + // Find out what marks need adding to our internal lists + for ( KTextEditor::Mark * mark = markList.first(); mark; mark = markList.next() ) + { + if ( mark->type & Breakpoint ) + breakpointList += mark->line; + } +#endif // !NO_GPSIM + + return breakpointList; +} + + +void TextDocument::setBreakpoint( uint line, bool isBreakpoint ) +{ +#ifndef NO_GPSIM + if (isBreakpoint) + { + m_doc->addMark( line, Breakpoint ); + if (m_pDebugger) + m_pDebugger->setBreakpoint( m_debugFile, line, true ); + } + else + { + m_doc->removeMark( line, Breakpoint ); + if (m_pDebugger) + m_pDebugger->setBreakpoint( m_debugFile, line, false ); + } +#endif // !NO_GPSIM +} + + +void TextDocument::debugRun() +{ +#ifndef NO_GPSIM + if (m_pDebugger) + { + m_pDebugger->gpsim()->setRunning(true); + slotInitDebugActions(); + return; + } + + switch ( guessedCodeType() ) + { + case ct_unknown: + KMessageBox::sorry( 0l, i18n("Unknown code type."), i18n("Cannot debug") ); + return; + + case ct_hex: + KMessageBox::sorry( 0l, i18n("Cannot debug hex."), i18n("Cannot debug") ); + return; + + case ct_microbe: + m_bLoadDebuggerAsHLL = true; + m_debugFile = outputFilePath(".microbe"); + break; + + case ct_asm: + m_bLoadDebuggerAsHLL = false; + m_debugFile = outputFilePath(".asm"); + break; + + case ct_c: + m_bLoadDebuggerAsHLL = true; + m_debugFile = outputFilePath(".c"); + break; + } + + m_symbolFile = GpsimProcessor::generateSymbolFile( m_debugFile, this, SLOT(slotCODCreationSucceeded()), SLOT(slotCODCreationFailed()) ); +#endif // !NO_GPSIM +} + + +void TextDocument::debugInterrupt() +{ +#ifndef NO_GPSIM + if (!m_pDebugger) + return; + + m_pDebugger->gpsim()->setRunning(false); + slotInitDebugActions(); +#endif // !NO_GPSIM +} + + +void TextDocument::debugStop() +{ +#ifndef NO_GPSIM + if ( !m_pDebugger || !m_bOwnDebugger ) + return; + + m_pDebugger->gpsim()->deleteLater(); + m_pDebugger = 0l; + slotDebugSetCurrentLine( SourceLine() ); + slotInitDebugActions(); +#endif // !NO_GPSIM +} + + +void TextDocument::debugStep() +{ +#ifndef NO_GPSIM + if (!m_pDebugger) + return; + + m_pDebugger->stepInto(); +#endif // !NO_GPSIM +} + + +void TextDocument::debugStepOver() +{ +#ifndef NO_GPSIM + if (!m_pDebugger) + return; + + m_pDebugger->stepOver(); +#endif // !NO_GPSIM +} + + +void TextDocument::debugStepOut() +{ +#ifndef NO_GPSIM + if (!m_pDebugger) + return; + + m_pDebugger->stepOut(); +#endif // !NO_GPSIM +} + + +void TextDocument::slotDebugSetCurrentLine( const SourceLine & line ) +{ +#ifndef NO_GPSIM + int textLine = line.line(); + + if ( DocManager::self()->findDocument( line.fileName() ) != this ) + textLine = -1; + + m_doc->removeMark( m_lastDebugLineAt, ExecutionPoint ); + m_doc->addMark( textLine, ExecutionPoint ); + + if ( activeView() ) + textView()->setCursorPosition( textLine, 0 ); + + m_lastDebugLineAt = textLine; +#endif // !NO_GPSIM +} + + +void TextDocument::slotInitDebugActions() +{ +#ifndef NO_GPSIM + if ( m_pDebugger ) + { + if ( m_pDebugger->gpsim()->isRunning() ) + slotDebugSetCurrentLine( SourceLine() ); + else + slotDebugSetCurrentLine( m_pDebugger->currentLine() ); + } + + if ( activeView() ) + textView()->slotInitDebugActions(); +#endif // !NO_GPSIM +} + + +void TextDocument::slotCODCreationSucceeded() +{ +#ifndef NO_GPSIM + GpsimProcessor * gpsim = new GpsimProcessor( m_symbolFile, this ); + + if (m_bLoadDebuggerAsHLL) + gpsim->setDebugMode( GpsimDebugger::HLLDebugger ); + else + gpsim->setDebugMode( GpsimDebugger::AsmDebugger ); + + setDebugger( gpsim->currentDebugger(), true ); +#endif // !NO_GPSIM +} +void TextDocument::slotCODCreationFailed() +{ +#ifndef NO_GPSIM + m_debugFile = QString::null; + m_symbolFile = QString::null; +#endif // !NO_GPSIM +} + + +void TextDocument::slotDebuggerDestroyed() +{ +#ifndef NO_GPSIM + slotDebugSetCurrentLine( SourceLine() ); + m_pDebugger = 0l; + m_debugFile = QString::null; + slotInitDebugActions(); +#endif // !NO_GPSIM +} + + +#ifndef NO_GPSIM +void TextDocument::clearBreakpoints() +{ + QPtrList markList = m_doc->marks(); + + // Find out what marks need adding to our internal lists + for ( KTextEditor::Mark * mark = markList.first(); mark; mark = markList.next() ) + { + if ( mark->type & Bookmark ) + m_doc->removeMark( mark->line, Breakpoint ); + } + + slotUpdateMarksInfo(); +} + + +void TextDocument::syncBreakpoints() +{ + if (b_lockSyncBreakpoints) + return; + + // We don't really care about synching marks if we aren't debugging / aren't able to take use of the marks + if (!m_pDebugger) + return; + + b_lockSyncBreakpoints = true; + + typedef QPtrList MarkList; + MarkList markList = m_doc->marks(); + + IntList bpList; + + // Find out what marks need adding to our internal lists + for ( KTextEditor::Mark * mark = markList.first(); mark; mark = markList.next() ) + { + const int line = mark->line; + + if ( mark->type & Breakpoint ) + bpList.append(line); + + if ( mark->type == ExecutionPoint ) + m_lastDebugLineAt = line; + } + + m_pDebugger->setBreakpoints( m_debugFile, bpList ); + + b_lockSyncBreakpoints = false; +} + + +bool TextDocument::debuggerIsRunning() const +{ + return m_pDebugger; +} + + +bool TextDocument::debuggerIsStepping() const +{ + return m_pDebugger && !m_pDebugger->gpsim()->isRunning(); +} + + +void TextDocument::setDebugger( GpsimDebugger * debugger, bool ownDebugger ) +{ + if ( debugger == m_pDebugger ) + return; + + // If we create a gpsim, then we may get called by DebugManager, which will + // try to claim we don't own it. So if we have a symbol file waiting, thne + // wait until we are called from its successful creation + if ( !m_symbolFile.isEmpty() && !ownDebugger ) + return; + + // Reset it for use next time + m_symbolFile = QString::null; + + if (m_bOwnDebugger) + delete m_pDebugger; + + m_pDebugger = debugger; + m_bOwnDebugger = ownDebugger; + + if (!m_pDebugger) + return; + + if ( m_debugFile.isEmpty() ) + m_debugFile = url().path(); + + connect( m_pDebugger, SIGNAL(destroyed()), this, SLOT(slotDebuggerDestroyed()) ); + connect( m_pDebugger->gpsim(), SIGNAL(runningStatusChanged(bool )), this, SLOT(slotInitDebugActions()) ); + connect( m_pDebugger, SIGNAL(lineReached(const SourceLine &)), this, SLOT(slotDebugSetCurrentLine(const SourceLine &)) ); + m_pDebugger->setBreakpoints( m_debugFile, breakpointList() ); + + slotInitDebugActions(); + if ( !m_pDebugger->gpsim()->isRunning() ) + slotDebugSetCurrentLine( m_pDebugger->currentLine() ); + + if ( this == dynamic_cast(DocManager::self()->getFocusedDocument()) ) + SymbolViewer::self()->setContext( m_pDebugger->gpsim() ); +} +#endif // !NO_GPSIM + + +const QPixmap* TextDocument::inactiveBreakpointPixmap() +{ + const char*breakpoint_gr_xpm[]={ + "11 16 6 1", + "c c #c6c6c6", + "d c #2c2c2c", + "# c #000000", + ". c None", + "a c #ffffff", + "b c #555555", + "...........", + "...........", + "...#####...", + "..#aaaaa#..", + ".#abbbbbb#.", + "#abbbbbbbb#", + "#abcacacbd#", + "#abbbbbbbb#", + "#abcacacbd#", + "#abbbbbbbb#", + ".#bbbbbbb#.", + "..#bdbdb#..", + "...#####...", + "...........", + "...........", + "..........."}; + static QPixmap pixmap( breakpoint_gr_xpm ); + return &pixmap; +} + + +const QPixmap* TextDocument::activeBreakpointPixmap() +{ + const char* breakpoint_xpm[]={ + "11 16 6 1", + "c c #c6c6c6", + ". c None", + "# c #000000", + "d c #840000", + "a c #ffffff", + "b c #ff0000", + "...........", + "...........", + "...#####...", + "..#aaaaa#..", + ".#abbbbbb#.", + "#abbbbbbbb#", + "#abcacacbd#", + "#abbbbbbbb#", + "#abcacacbd#", + "#abbbbbbbb#", + ".#bbbbbbb#.", + "..#bdbdb#..", + "...#####...", + "...........", + "...........", + "..........."}; + static QPixmap pixmap( breakpoint_xpm ); + return &pixmap; +} + + + +const QPixmap* TextDocument::reachedBreakpointPixmap() +{ + const char*breakpoint_bl_xpm[]={ + "11 16 7 1", + "a c #c0c0ff", + "# c #000000", + "c c #0000c0", + "e c #0000ff", + "b c #dcdcdc", + "d c #ffffff", + ". c None", + "...........", + "...........", + "...#####...", + "..#ababa#..", + ".#bcccccc#.", + "#acccccccc#", + "#bcadadace#", + "#acccccccc#", + "#bcadadace#", + "#acccccccc#", + ".#ccccccc#.", + "..#cecec#..", + "...#####...", + "...........", + "...........", + "..........."}; + static QPixmap pixmap( breakpoint_bl_xpm ); + return &pixmap; +} + + +const QPixmap* TextDocument::disabledBreakpointPixmap() +{ + const char*breakpoint_wh_xpm[]={ + "11 16 7 1", + "a c #c0c0ff", + "# c #000000", + "c c #0000c0", + "e c #0000ff", + "b c #dcdcdc", + "d c #ffffff", + ". c None", + "...........", + "...........", + "...#####...", + "..#ddddd#..", + ".#ddddddd#.", + "#ddddddddd#", + "#ddddddddd#", + "#ddddddddd#", + "#ddddddddd#", + "#ddddddddd#", + ".#ddddddd#.", + "..#ddddd#..", + "...#####...", + "...........", + "...........", + "..........."}; + static QPixmap pixmap( breakpoint_wh_xpm ); + return &pixmap; +} + + +const QPixmap* TextDocument::executionPointPixmap() +{ + const char*exec_xpm[]={ + "11 16 4 1", + "a c #00ff00", + "b c #000000", + ". c None", + "# c #00c000", + "...........", + "...........", + "...........", + "#a.........", + "#aaa.......", + "#aaaaa.....", + "#aaaaaaa...", + "#aaaaaaaaa.", + "#aaaaaaa#b.", + "#aaaaa#b...", + "#aaa#b.....", + "#a#b.......", + "#b.........", + "...........", + "...........", + "..........."}; + static QPixmap pixmap( exec_xpm ); + return &pixmap; +} + +#include "textdocument.moc" diff --git a/src/textdocument.h b/src/textdocument.h new file mode 100644 index 0000000..1876473 --- /dev/null +++ b/src/textdocument.h @@ -0,0 +1,245 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef TEXTDOCUMENT_H +#define TEXTDOCUMENT_H + +#include "config.h" +#include "document.h" + +#include + +#include + +class GpsimDebugger; +class SourceLine; +class TextView; + +typedef QValueList IntList; + +/** +@author David Saxton +*/ +class TextDocument : public Document +{ +Q_OBJECT +public: + ~TextDocument(); + + enum CodeType + { + ct_unknown, + ct_asm, + ct_c, + ct_hex, + ct_microbe + }; + + enum MarkType { + Bookmark = KTextEditor::MarkInterface::markType01, + Breakpoint = KTextEditor::MarkInterface::markType02, + ActiveBreakpoint = KTextEditor::MarkInterface::markType03, + ReachedBreakpoint = KTextEditor::MarkInterface::markType04, + DisabledBreakpoint = KTextEditor::MarkInterface::markType05, + ExecutionPoint = KTextEditor::MarkInterface::markType06 + }; + + virtual View *createView( ViewContainer *viewContainer, uint viewAreaId, const char *name = 0l ); + + /** + * Attempts to construct a new TextDocument object and returns a pointer to + * it if successful, or 0 if it failed. + * @returns pointer to constructed object, or 0 if there was a problem + */ + static TextDocument *constructTextDocument( const QString& caption, KTechlab *parent, const char *name = 0L ); + /** + * @returns the guessed code type that this file is + */ + CodeType guessedCodeType() const { return m_guessedCodeType; } + /** + * Set the given lines as all bookmarks + */ + void setBookmarks( const IntList &lines ); + /** + * Set the given line to a bookmark (or not) + */ + void setBookmark( uint line, bool isBookmark ); + /** + * @return List of bookmarks + */ + IntList bookmarkList() const; + + /** + * Set the given lines as all breakpoints + */ + void setBreakpoints( const IntList &lines ); + /** + * Set the given line to a breakpoint (or not ) + */ + void setBreakpoint( uint line, bool isBreakpoint ); + /** + * @return List of breakpoints + */ + IntList breakpointList() const; + +#ifndef NO_GPSIM + /** + * Attach ourselves to the given debugger. + * @param ownDebugger whether we have permission to delete it. + */ + void setDebugger( GpsimDebugger * debugger, bool ownDebugger ); + GpsimDebugger * debugger() const { return m_pDebugger; } + bool ownDebugger() const { return m_bOwnDebugger; } + /** + * Returns true if the debugger is running (this includes when we are in + * stepping mode) + */ + bool debuggerIsRunning() const; + /** + * Returns true if we are in stepping more + */ + bool debuggerIsStepping() const; + QString debugFile() const { return m_debugFile; } + virtual void clearBreakpoints(); +#endif + + virtual bool openURL(const KURL& url); + void fileSave(const KURL& url); + /** + * Set the document to the given text, making the document unmodified, and + * reseting the undo/redo history/ + * @param asInitial whether the next should be treated as if we had just + * opened the file (no undo/redo history, and unmodified). + */ + void setText( const QString & text, bool asInitial ); + /** + * Attempts to guess the filetype from the file extension, and load an + * appropriate highlighting/etc + * @param allowDisable If false, will simply keep the old scheme if nothing + * appropriate is found + */ + void guessScheme( bool allowDisable = true ); + + virtual void fileSave() { fileSave(url()); } + virtual void fileSaveAs(); + virtual void print(); + virtual void setModified( bool modified ); + + Kate::View* createKateView( QWidget *parent, const char *name = 0l ); + + virtual void undo(); + virtual void redo(); + virtual void cut(); + virtual void copy(); + virtual void paste(); + + virtual bool isModified() const { return m_doc->isModified(); } + virtual bool isUndoAvailable() const { return (m_doc->undoCount() != 0); } + virtual bool isRedoAvailable() const { return (m_doc->redoCount() != 0); } + + void clearBookmarks(); + virtual bool fileClose(); + + static const QPixmap* inactiveBreakpointPixmap(); + static const QPixmap* activeBreakpointPixmap(); + static const QPixmap* reachedBreakpointPixmap(); + static const QPixmap* disabledBreakpointPixmap(); + static const QPixmap* executionPointPixmap(); + /** + * Returns a TextView pointer to the active TextView (if there is one) + */ + TextView *textView() const; + + enum ConvertToTarget + { + MicrobeOutput, // (not used) + AssemblyOutput, + HexOutput, + PICOutput + }; + + Kate::Document * kateDocument() const { return m_doc; } + +public slots: + /** + * @param target as ConvertToTarget + */ + void slotConvertTo( int target ); + void convertToAssembly(); + void convertToHex(); + void convertToPIC(); + void formatAssembly(); + void debugRun(); + void debugInterrupt(); + void debugStep(); + void debugStepOver(); + void debugStepOut(); + void debugStop(); + void slotInitLanguage( CodeType type ); + /** + * Called when change line / toggle marks + */ + void slotUpdateMarksInfo(); + + void slotDebugSetCurrentLine( const SourceLine & line ); + /** + * Initialize the actions appropriate for when the debugger is running + * or stepping + */ + void slotInitDebugActions(); + +protected: + /** + * Returns a filepath with the editor's contents in. If the url of this file + * is non-empty (i.e. the user has already saved the file), then that url is + * returned. Otherwise, a temporary file with the given extension (ext) is + * created, and the location of this file is returned. + */ + QString outputFilePath( const QString &ext ); + void saveDone(); +#ifndef NO_GPSIM + /** + * Looks at the list of marks returned by Kate, and syncs them with the + * marks that we know about + */ + void syncBreakpoints(); + + int m_lastDebugLineAt; // Last line with a debug point reached mark + bool m_bLoadDebuggerAsHLL; +#endif + + Kate::Document *m_doc; + QGuardedPtr m_pLastTextOutputTarget; + +private slots: + void setLastTextOutputTarget( TextDocument * target ); + void slotSyncModifiedStates(); + void slotCODCreationSucceeded(); + void slotCODCreationFailed(); + void slotDebuggerDestroyed(); + void slotBookmarkRequested(); + void slotSelectionmChanged(); + +private: + TextDocument( const QString& caption, KTechlab *parent, const char *name = 0L ); + bool m_constructorSuccessful; + CodeType m_guessedCodeType; + QPtrList m_bookmarkActions; + +#ifndef NO_GPSIM + bool b_lockSyncBreakpoints; // Used to avoid calling syncMarks() when we are currently doing so + bool m_bOwnDebugger; + QGuardedPtr m_pDebugger; + QString m_symbolFile; + QString m_debugFile; +#endif +}; + +#endif diff --git a/src/textview.cpp b/src/textview.cpp new file mode 100644 index 0000000..49a1946 --- /dev/null +++ b/src/textview.cpp @@ -0,0 +1,496 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#define protected public +#include +#undef protected + +#include "asmformatter.h" +#include "config.h" +#include "filemetainfo.h" +#include "gpsimprocessor.h" +#include "ktechlab.h" +#include "symbolviewer.h" +#include "textdocument.h" +#include "textview.h" +#include "variablelabel.h" +#include "viewiface.h" + +#include +#include + +// #include "kateview.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +//BEGIN class TextView +TextView::TextView( TextDocument * textDocument, ViewContainer *viewContainer, uint viewAreaId, const char *name ) + : View( textDocument, viewContainer, viewAreaId, name ) +{ + m_view = textDocument->createKateView(this); + m_view->insertChildClient(this); + + KActionCollection * ac = actionCollection(); + + + //BEGIN Convert To * Actions + KToolBarPopupAction * pa = new KToolBarPopupAction( i18n("Convert to"), "fork", 0, 0, 0, ac, "program_convert" ); + pa->setDelayed(false); + + KPopupMenu * m = pa->popupMenu(); + + m->insertTitle( i18n("Convert to ...") ); + m->insertItem( KGlobal::iconLoader()->loadIcon( "convert_to_microbe", KIcon::Small ), i18n("Microbe"), TextDocument::MicrobeOutput ); + m->insertItem( KGlobal::iconLoader()->loadIcon( "convert_to_assembly", KIcon::Small ), i18n("Assembly"), TextDocument::AssemblyOutput ); + m->insertItem( KGlobal::iconLoader()->loadIcon( "convert_to_hex", KIcon::Small ), i18n("Hex"), TextDocument::HexOutput ); + m->insertItem( KGlobal::iconLoader()->loadIcon( "convert_to_pic", KIcon::Small ), i18n("PIC (upload)"), TextDocument::PICOutput ); + connect( m, SIGNAL(activated(int)), textDocument, SLOT(slotConvertTo(int)) ); + + m->setItemEnabled( TextDocument::MicrobeOutput, false ); + //END Convert To * Actions + + + new KAction( i18n("Format Assembly Code"), "", Qt::Key_F12, textDocument, SLOT(formatAssembly()), ac, "format_asm" ); + + +#ifndef NO_GPSIM + //BEGIN Debug Actions + new KAction( i18n("Set &Breakpoint"), 0, 0, this, SLOT(toggleBreakpoint()), ac, "debug_toggle_breakpoint" ); + new KAction( i18n("Run"), "dbgrun", 0, textDocument, SLOT(debugRun()), ac, "debug_run" ); + new KAction( i18n("Interrupt"), "player_pause", 0, textDocument, SLOT(debugInterrupt()), ac, "debug_interrupt" ); + new KAction( i18n("Stop"), "stop", 0, textDocument, SLOT(debugStop()), ac, "debug_stop" ); + new KAction( i18n("Step"), "dbgstep", Qt::CTRL|Qt::ALT|Qt::Key_Right, textDocument, SLOT(debugStep()), ac, "debug_step" ); + new KAction( i18n("Step Over"), "dbgnext", 0, textDocument, SLOT(debugStepOver()), ac, "debug_step_over" ); + new KAction( i18n("Step Out"), "dbgstepout", 0, textDocument, SLOT(debugStepOut()), ac, "debug_step_out" ); + //END Debug Actions +#endif + + + setXMLFile( "ktechlabtextui.rc" ); + m_view->setXMLFile( locate( "appdata", "ktechlabkateui.rc" ) ); + + m_savedCursorLine = 0; + m_savedCursorColumn = 0; + m_pViewIface = new TextViewIface(this); + + setAcceptDrops(true); + + m_statusBar->insertItem( "", ViewStatusBar::LineCol ); + + m_view->installPopup( static_cast( p_ktechlab->factory()->container( "ktexteditor_popup", p_ktechlab ) ) ); + + connect( m_view, SIGNAL(cursorPositionChanged()), this, SLOT(slotCursorPositionChanged()) ); + connect( m_view, SIGNAL(gotFocus(Kate::View*)), this, SLOT(setFocused()) ); + + m_layout->insertWidget( 0, m_view ); + + slotCursorPositionChanged(); + slotInitDebugActions(); + initCodeActions(); + +#ifndef NO_GPSIM + m_pTextViewLabel = new VariableLabel( this ); + m_pTextViewLabel->hide(); + + TextViewEventFilter * eventFilter = new TextViewEventFilter( this ); + connect( eventFilter, SIGNAL(wordHoveredOver( const QString&, int, int )), this, SLOT(slotWordHoveredOver( const QString&, int, int )) ); + connect( eventFilter, SIGNAL(wordUnhovered()), this, SLOT(slotWordUnhovered()) ); + + QObject * internalView = m_view->child( 0, "KateViewInternal" ); + internalView->installEventFilter( eventFilter ); +#endif +} + + +TextView::~TextView() +{ + if ( p_ktechlab ) + { + if ( KXMLGUIFactory * f = m_view->factory() ) + f->removeClient( m_view ); + + p_ktechlab->addNoRemoveGUIClient( m_view ); + } + + delete m_pViewIface; + m_pViewIface = 0l; +} + + +bool TextView::closeView() +{ + if ( textDocument() ) + { + const QString path = textDocument()->url().prettyURL(); + if ( !path.isEmpty() ) + fileMetaInfo()->grabMetaInfo( path, this ); + } + + bool doClose = View::closeView(); + if (doClose) + p_ktechlab->factory()->removeClient(m_view); + return View::closeView(); +} + + +TextDocument *TextView::textDocument() const +{ + return static_cast(document()); +} + + +void TextView::disableActions() +{ + KPopupMenu * tb = (dynamic_cast(action("program_convert")))->popupMenu(); + + tb->setItemEnabled( TextDocument::AssemblyOutput, false ); + tb->setItemEnabled( TextDocument::HexOutput, false ); + tb->setItemEnabled( TextDocument::PICOutput, false ); + action("format_asm")->setEnabled(false); + +#ifndef NO_GPSIM + action("debug_toggle_breakpoint")->setEnabled(false); +#endif +} + + +void TextView::setFocused() +{ + View::setFocused(); + +#ifndef NO_GPSIM + GpsimDebugger * debugger = textDocument()->debugger(); + if ( !debugger || !debugger->gpsim() ) + return; + + SymbolViewer::self()->setContext( debugger->gpsim() ); +#endif +} + + +void TextView::initCodeActions() +{ + disableActions(); + + KPopupMenu * tb = (dynamic_cast(action("program_convert")))->popupMenu(); + + switch ( textDocument()->guessedCodeType() ) + { + case TextDocument::ct_asm: + { + tb->setItemEnabled( TextDocument::HexOutput, true ); + tb->setItemEnabled( TextDocument::PICOutput, true ); + action("format_asm")->setEnabled(true); +#ifndef NO_GPSIM + action("debug_toggle_breakpoint")->setEnabled(true); + slotInitDebugActions(); +#endif + break; + } + case TextDocument::ct_c: + { + tb->setItemEnabled( TextDocument::AssemblyOutput, true ); + tb->setItemEnabled( TextDocument::HexOutput, true ); + tb->setItemEnabled( TextDocument::PICOutput, true ); + break; + } + case TextDocument::ct_hex: + { + tb->setItemEnabled( TextDocument::AssemblyOutput, true ); + tb->setItemEnabled( TextDocument::PICOutput, true ); + break; + } + case TextDocument::ct_microbe: + { + tb->setItemEnabled( TextDocument::AssemblyOutput, true ); + tb->setItemEnabled( TextDocument::HexOutput, true ); + tb->setItemEnabled( TextDocument::PICOutput, true ); + break; + } + case TextDocument::ct_unknown: + { + break; + } + } +} + + +unsigned TextView::currentLine() +{ + unsigned l,c ; + m_view->cursorPosition( &l, &c ); + return l; +} +unsigned TextView::currentColumn() +{ + unsigned l,c ; + m_view->cursorPosition( &l, &c ); + return c; +} + + +void TextView::saveCursorPosition() +{ + m_view->cursorPosition( &m_savedCursorLine, &m_savedCursorColumn ); +} + + +void TextView::restoreCursorPosition() +{ + m_view->setCursorPosition( m_savedCursorLine, m_savedCursorColumn ); +} + + +void TextView::slotCursorPositionChanged() +{ + uint line, column; + m_view->cursorPosition( &line, &column ); + + m_statusBar->changeItem( i18n(" Line: %1 Col: %2 ").arg(QString::number(line+1)).arg(QString::number(column+1)), ViewStatusBar::LineCol ); + + slotUpdateMarksInfo(); +} + + +void TextView::slotUpdateMarksInfo() +{ +#ifndef NO_GPSIM + uint l,c ; + m_view->cursorPosition( &l, &c ); + + if ( m_view->getDoc()->mark(l) & TextDocument::Breakpoint ) + action("debug_toggle_breakpoint")->setText( i18n("Clear &Breakpoint") ); + else + action("debug_toggle_breakpoint")->setText( i18n("Set &Breakpoint") ); +#endif +} + + +void TextView::slotInitDebugActions() +{ +#ifndef NO_GPSIM + bool isRunning = textDocument()->debuggerIsRunning(); + bool isStepping = textDocument()->debuggerIsStepping(); + bool ownDebugger = textDocument()->ownDebugger(); + + action("debug_run")->setEnabled( !isRunning || isStepping ); + action("debug_interrupt")->setEnabled(isRunning && !isStepping); + action("debug_stop")->setEnabled(isRunning && ownDebugger); + action("debug_step")->setEnabled(isRunning && isStepping); + action("debug_step_over")->setEnabled(isRunning && isStepping); + action("debug_step_out")->setEnabled(isRunning && isStepping); +#endif // !NO_GPSIM +} + + +void TextView::toggleBreakpoint() +{ +#ifndef NO_GPSIM + uint l,c ; + m_view->cursorPosition( &l, &c ); + textDocument()->setBreakpoint( l, !(m_view->getDoc()->mark(l) & TextDocument::Breakpoint) ); +#endif // !NO_GPSIM +} + + +void TextView::slotWordHoveredOver( const QString & word, int line, int col ) +{ +#ifndef NO_GPSIM + // We're only interested in popping something up if we currently have a debugger running + GpsimProcessor * gpsim = textDocument()->debugger() ? textDocument()->debugger()->gpsim() : 0l; + if ( !gpsim ) + { + m_pTextViewLabel->hide(); + return; + } + + // Find out if the word that we are hovering over is the operand data + KTextEditor::EditInterface * e = (KTextEditor::EditInterface*)textDocument()->kateDocument()->qt_cast("KTextEditor::EditInterface"); + InstructionParts parts( e->textLine( unsigned(line) ) ); + if ( !parts.operandData().contains( word ) ) + return; + + if ( RegisterInfo * info = gpsim->registerMemory()->fromName( word ) ) + m_pTextViewLabel->setRegister( info, info->name() ); + + else + { + int operandAddress = textDocument()->debugger()->programAddress( textDocument()->debugFile(), line ); + if ( operandAddress == -1 ) + { + m_pTextViewLabel->hide(); + return; + } + + int regAddress = gpsim->operandRegister( operandAddress ); + + if ( regAddress != -1 ) + m_pTextViewLabel->setRegister( gpsim->registerMemory()->fromAddress( regAddress ), word ); + + else + { + m_pTextViewLabel->hide(); + return; + } + } + + m_pTextViewLabel->move( mapFromGlobal( QCursor::pos() ) + QPoint( 0, 20 ) ); + m_pTextViewLabel->show(); +#endif // !NO_GPSIM +} + + +void TextView::slotWordUnhovered() +{ +#ifndef NO_GPSIM + m_pTextViewLabel->hide(); +#endif // !NO_GPSIM +} +//END class TextView + + + +//BEGIN class TextViewEventFilter +TextViewEventFilter::TextViewEventFilter( TextView * textView ) +{ + m_hoverStatus = Sleeping; + m_pTextView = textView; + m_lastLine = m_lastCol = -1; + + ((KTextEditor::TextHintInterface*)textView->kateView()->qt_cast("KTextEditor::TextHintInterface"))->enableTextHints(0); + connect( textView->kateView(), SIGNAL(needTextHint(int, int, QString &)), this, SLOT(slotNeedTextHint( int, int, QString& )) ); + + m_pHoverTimer = new QTimer( this ); + connect( m_pHoverTimer, SIGNAL(timeout()), this, SLOT(hoverTimeout()) ); + + m_pSleepTimer = new QTimer( this ); + connect( m_pSleepTimer, SIGNAL(timeout()), this, SLOT(gotoSleep()) ); + + m_pNoWordTimer = new QTimer( this ); + connect( m_pNoWordTimer, SIGNAL(timeout()), this, SLOT(slotNoWordTimeout()) ); +} + + +bool TextViewEventFilter::eventFilter( QObject *, QEvent * e ) +{ + if ( e->type() == QEvent::MouseMove ) + { + if ( !m_pNoWordTimer->isActive() ) + m_pNoWordTimer->start( 10 ); + return false; + } + + if ( e->type() == QEvent::FocusOut || e->type() == QEvent::FocusIn || e->type() == QEvent::MouseButtonPress || e->type() == QEvent::Leave || e->type() == QEvent::Wheel ) + { + // user moved focus somewhere - hide the tip and sleep + if ( ((QFocusEvent*)e)->reason() != QFocusEvent::Popup ) + updateHovering( 0, -1, -1 ); + } + + return false; +} + + +void TextViewEventFilter::hoverTimeout() +{ + m_pSleepTimer->stop(); + m_hoverStatus = Active; + emit wordHoveredOver( m_lastWord, m_lastLine, m_lastCol ); +} + + +void TextViewEventFilter::gotoSleep() +{ + m_hoverStatus = Sleeping; + m_lastWord = QString::null; + emit wordUnhovered(); + m_pHoverTimer->stop(); +} + + +void TextViewEventFilter::slotNoWordTimeout() +{ + updateHovering( 0, -1, -1 ); +} + + +void TextViewEventFilter::updateHovering( const QString & currentWord, int line, int col ) +{ + if ( (currentWord == m_lastWord) && (line == m_lastLine) ) + return; + + m_lastWord = currentWord; + m_lastLine = line; + m_lastCol = col; + + if ( currentWord.isEmpty() ) + { + if ( m_hoverStatus == Active ) + m_hoverStatus = Hidden; + + emit wordUnhovered(); + if ( !m_pSleepTimer->isActive() ) + m_pSleepTimer->start( 2000, true ); + + return; + } + + if ( m_hoverStatus != Sleeping ) + emit wordHoveredOver( currentWord, line, col ); + else + m_pHoverTimer->start( 700, true ); +} + + +static inline bool isWordLetter( const QString & s ) { return (s.length() == 1) && (s[0].isLetterOrNumber() || s[0] == '_'); } + + +void TextViewEventFilter::slotNeedTextHint( int line, int col, QString & ) +{ + m_pNoWordTimer->stop(); + + KTextEditor::EditInterface * e = (KTextEditor::EditInterface*)m_pTextView->textDocument()->kateDocument()->qt_cast("KTextEditor::EditInterface"); + + // Return if we aren't currently in a word + if ( !isWordLetter( e->text( line, col, line, col+1 ) ) ) + { + updateHovering( QString::null, line, col ); + return; + } + + // Find the start of the word + int wordStart = col; + do wordStart--; + while ( wordStart > 0 && isWordLetter( e->text( line, wordStart, line, wordStart+1 ) ) ); + wordStart++; + + // Find the end of the word + int wordEnd = col; + do wordEnd++; + while ( isWordLetter( e->text( line, wordEnd, line, wordEnd+1 ) ) ); + + QString t = e->text( line, wordStart, line, wordEnd ); + + updateHovering( t, line, col ); +} +//END class TextViewEventFilter + + + +#include "textview.moc" diff --git a/src/textview.h b/src/textview.h new file mode 100644 index 0000000..8903843 --- /dev/null +++ b/src/textview.h @@ -0,0 +1,190 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef TEXTVIEW_H +#define TEXTVIEW_H + +#include "config.h" +#include "view.h" + +#include +#include +#include + +class QMouseEvent; +class RegisterInfo; +class TextDocument; +class TextView; +class VariableLabel; + + +/** +@author David Saxton +*/ +class TextView : public View +{ + Q_OBJECT + public: + TextView( TextDocument *textDocument, ViewContainer *viewContainer, uint viewAreaId, const char *name = 0 ); + ~TextView(); + virtual bool closeView(); + /** + * Brings up the goto line dialog. + */ + bool gotoLine( const int line ) { return m_view->setCursorPosition( line, 0/*m_view->cursorColumn()*/ ); } + /** + * Returns a pointer to the document as a text document + */ + TextDocument *textDocument() const; + void cut() { m_view->cut(); } + void copy() { m_view->copy(); } + void paste() { m_view->paste(); } + void saveCursorPosition(); + void restoreCursorPosition(); + /** + * Enable code actions depending on the type of code being edited + */ + void initCodeActions(); + void setCursorPosition( uint line, uint col ) { m_view->setCursorPosition( line, col ); } + unsigned currentLine(); + unsigned currentColumn(); + void disableActions(); + + Kate::View * kateView() const { return m_view; } + + Kate::View::saveResult save() { return m_view->save(); } + Kate::View::saveResult saveAs() { return m_view->saveAs(); } + + virtual void setFocused(); + + public slots: + /** + * Called when change line / toggle marks + */ + void slotUpdateMarksInfo(); + void slotCursorPositionChanged(); + void toggleBreakpoint(); + /** + * Initialize the actions appropriate for when the debugger is running + * or stepping + */ + void slotInitDebugActions(); + + protected slots: + void slotWordHoveredOver( const QString & word, int line, int col ); + void slotWordUnhovered(); + + protected: + Kate::View *m_view; +#ifndef NO_GPSIM + VariableLabel * m_pTextViewLabel; ///< Pops up when the user hovers his mouse over a word +#endif + + private: + uint m_savedCursorLine; + uint m_savedCursorColumn; +}; + + +/** +This class is an event filter to be installed in the kate view, and is used to +do stuff like poping up menus and telling TextView that a word is being hovered +over (used in the debugger). + +@author David Saxton +*/ +class TextViewEventFilter : public QObject +{ + Q_OBJECT + public: + TextViewEventFilter( TextView * textView ); + + bool eventFilter( QObject * watched, QEvent * e ); + + signals: + /** + * When the user hovers the mouse for more than 700 milliseconds over a + * word, "hover mode" is entered. When the user presses a key, clicks + * mouse, etc, this mode is left. During the mode, any word that is + * under the mouse cursor will be emitted as hoveredOver( word ). + */ + void wordHoveredOver( const QString & word, int line, int col ); + /** + * Emitted when focus is lost, the mouse moves to a different word, etc. + */ + void wordUnhovered(); + + protected slots: + void slotNeedTextHint( int line, int col, QString & text ); + /** + * Called when we are not in hover mode, but the user has had his mouse + * in the same position for some time. + */ + void hoverTimeout(); + /** + * Called (from m_pSleepTimer) when we are in hover mode, but no word + * has been hovered over for some time. + */ + void gotoSleep(); + /** + * @see m_pNoWordTimer + */ + void slotNoWordTimeout(); + + protected: + enum HoverStatus + { + /** + * We are currently hovering - wordHoveredOver was emitted, and + * wordUnhovered hasn't been emitted yet. + */ + Active, + /** + * A word was unhovered recently. We will go straight to PoppedUp + * mode if a word is hovered over again. + */ + Hidden, + /** + * A word was not unhovered recentely. There will be a short display + * before going to PoppedUp mode if a word is hovered over. + */ + Sleeping, + }; + + /** + * Starts / stops timers, emits signals, etc. See other functions for an + * idea of what this does. + */ + void updateHovering( const QString & currentWord, int line, int col ); + /** + * Started when the user moves his mouse over a word, and we are in + * Sleeping mode. Reset when the user moves his mouse, etc. + */ + QTimer * m_pHoverTimer; + /** + * Started when a word is unhovered. When this timeouts, we will go to + * Sleeping mode. + */ + QTimer * m_pSleepTimer; + /** + * Activated by the user moving the mouse. Reset by a call to + * slotNeedTextHint. This timer is needed as KateViewInternal doesn't + * bother updating us if the mouse cursor isn't over text. + */ + QTimer * m_pNoWordTimer; + + TextView * m_pTextView; + QString m_lastWord; + int m_lastLine; + int m_lastCol; + HoverStatus m_hoverStatus; +}; + +#endif diff --git a/src/variablelabel.cpp b/src/variablelabel.cpp new file mode 100644 index 0000000..a6a6ed1 --- /dev/null +++ b/src/variablelabel.cpp @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "config.h" +#ifndef NO_GPSIM + +#include "gpsimprocessor.h" +#include "symbolviewer.h" +#include "textview.h" +#include "variablelabel.h" + + +//BEGIN class VariableLabel +VariableLabel::VariableLabel( TextView * parent ) + : QLabel( parent, "toolTipTip", WStyle_StaysOnTop | WStyle_Customize | WStyle_NoBorder | WStyle_Tool | WX11BypassWM ) +{ + m_value = -1; + + setMargin(1); + setAutoMask( FALSE ); + setFrameStyle( QFrame::Plain | QFrame::Box ); + setLineWidth( 1 ); + setAlignment( AlignAuto | AlignTop ); + setIndent(0); + polish(); + adjustSize(); +} + + +void VariableLabel::setRegister( RegisterInfo * info, const QString & name ) +{ + disconnectRegisterInfo(); + + if ( !info ) + return; + + m_value = -1; + m_pRegisterInfo = info; + m_registerName = name; + + connect( m_pRegisterInfo, SIGNAL(destroyed()), this, SLOT(hide()) ); + connect( m_pRegisterInfo, SIGNAL(valueChanged(unsigned)), this, SLOT(updateText()) ); + + updateText(); +} + + +void VariableLabel::disconnectRegisterInfo() +{ + if ( !m_pRegisterInfo ) + return; + + disconnect( m_pRegisterInfo, SIGNAL(destroyed()), this, SLOT(hide()) ); + disconnect( m_pRegisterInfo, SIGNAL(valueChanged(unsigned)), this, SLOT(updateText()) ); + + m_pRegisterInfo = 0l; + m_registerName = QString::null; +} + + +void VariableLabel::setValue( unsigned value ) +{ + disconnectRegisterInfo(); + m_value = value; + + updateText(); +} + + +void VariableLabel::updateText() +{ + if ( m_pRegisterInfo ) + setText( QString("%1 = %2").arg( m_registerName ).arg( SymbolViewer::self()->toDisplayString( m_pRegisterInfo->value() ) ) ); + + else if ( m_value != -1 ) + setText( QString::number( m_value ) ); + + adjustSize(); +} +//END class VariableLabel + +#include "variablelabel.moc" + +#endif // !NO_GPSIM diff --git a/src/variablelabel.h b/src/variablelabel.h new file mode 100644 index 0000000..ba3850e --- /dev/null +++ b/src/variablelabel.h @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "config.h" +#ifndef NO_GPSIM + +#ifndef VARIABLELABEL_H +#define VARIABLELABEL_H + +#include +#include + +class TextView; + + +/** +Used for displaying the value of a variable when the user hovers his mouse over +a variable while debugging. + +@author David Saxton + */ +class VariableLabel : public QLabel +{ + Q_OBJECT + public: + VariableLabel( TextView * parent ); + /** + * Sets the register that this label is displaying the value of. + */ + void setRegister( RegisterInfo * info, const QString & name ); + /** + * Sets the value that this label is displaying. This is an alternative + * to setRegister. + */ + void setValue( unsigned value ); + + protected slots: + /** + * Updates what is displayed from m_pRegisterInfo. + */ + void updateText(); + + protected: + void disconnectRegisterInfo(); + + QGuardedPtr m_pRegisterInfo; + QString m_registerName; + int m_value; +}; + +#endif + +#endif // !NO_GPSIM diff --git a/src/variant.cpp b/src/variant.cpp new file mode 100644 index 0000000..10422cd --- /dev/null +++ b/src/variant.cpp @@ -0,0 +1,139 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "colorcombo.h" +#include "cnitem.h" + +#include +#include + +Variant::Variant( Type::Value type ) + : QObject() +{ + m_type = type; + m_bSetDefault = false; + m_bHidden = false; + m_bAdvanced = false; + m_minValue = 1e-6; + m_maxValue = 1e9; + m_minAbsValue = 1e-6; + m_colorScheme = ColorCombo::QtStandard; + if ( type == Type::Color ) + { + // this value is taken from ColorCombo and should ideally be put somewhere... + m_defaultValue = "#f62a2a"; + m_value = "#f62a2a"; + } +} + + +Variant::~Variant() +{ +} + + +void Variant::setType( Type::Value type ) +{ + m_type = type; +} + + +void Variant::appendAllowed(QString string) +{ + if ( !m_allowed.contains(string) ) { + m_allowed.append(string); + } +} + + +void Variant::setAllowed(QStringList stringList) +{ + // Ideally, we should check for duplicates in whatever is setting the + // allowed strings, but it is a lot easier and permanent to do it here + m_allowed.clear(); + const QStringList::iterator end = stringList.end(); + for ( QStringList::iterator it = stringList.begin(); it != end; ++it ) + { + if ( !m_allowed.contains(*it) ) { + m_allowed.append(*it); + } + } +} + + +void Variant::setMinValue( const double value ) +{ + m_minValue = value; + if ( std::abs(value) < m_minAbsValue && value != 0. ) + { + m_minAbsValue = std::abs(value); + } +} + +void Variant::setMaxValue( const double value ) +{ + m_maxValue = value; + if ( std::abs(value) < m_minAbsValue && value != 0. ) + { + m_minAbsValue = std::abs(value); + } +} + +QString Variant::displayString() const +{ + switch(type()) + { + case Variant::Type::Double: + { + double numValue = m_value.toDouble(); + return QString::number( numValue / CNItem::getMultiplier(numValue) ) + " " + CNItem::getNumberMag(numValue) + m_unit; + } + + case Variant::Type::Int: + return m_value.toString()+" "+m_unit; + + case Variant::Type::Bool: + return m_value.toBool() ? i18n("True") : i18n("False"); + + default: + return m_value.toString(); + } +} + +void Variant::setValue( const QVariant& val ) +{ + if (!m_bSetDefault) + setDefaultValue(val); + + if ( m_value == val ) + return; + + const QVariant old = m_value; + m_value = val; + emit( valueChanged( val, old ) ); +} + +void Variant::setDefaultValue( QVariant val ) +{ + m_defaultValue = val; + m_bSetDefault = true; +} + +void Variant::resetToDefault() +{ + setValue( defaultValue() ); +} + +void Variant::setMinAbsValue( double val ) +{ + m_minAbsValue = val; +} + +#include "variant.moc" diff --git a/src/variant.h b/src/variant.h new file mode 100644 index 0000000..8367026 --- /dev/null +++ b/src/variant.h @@ -0,0 +1,175 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef VARIANT_H +#define VARIANT_H + +#include +#include + +class QColor; +class QString; + +/** +For information: +QVariant::type() returns an enum for the current data type +contained. e.g. returns QVariant::Color or QVariant::Rect +@author Daniel Clarke +@author David Saxton +*/ +class Variant : public QObject +{ +Q_OBJECT +public: + class Type + { + public: + enum Value + { + None, + Int, // Integer + Raw, // QByteArray + Double, // Real number + String, // Editable string + Multiline, // String that may contain linebreaks + Select, // Selection of strings + Combo, // Editable combination of strings + FileName, // Filename + Color, // Color + Bool, // Boolean + VarName, // Variable name + Port, // Port name + Pin, // Pin name + PenStyle, // Pen Style + PenCapStyle, // Pen Cap Style + SevenSegment, // Pin Map for Seven Segment Display + KeyPad // Pin Map for Keypad + }; + }; + + Variant( Type::Value type ); + virtual ~Variant(); + + /** + * Returns the type of Variant (see Variant::Type::Value) + */ + Variant::Type::Value type() const { return m_type; } + /** + * Sets the variant type + */ + void setType( Type::Value type ); + /** + * Returns the filter used for file dialogs (if this is of type Type::FileName) + */ + QString filter() const { return m_filter; } + void setFilter( const QString & filter ) { m_filter = filter; } + /** + * The selection of colours to be used in the combo box - e.g. + * ColorCombo::LED. + * @see ColorCombo::ColorScheme + */ + int colorScheme() const { return m_colorScheme; } + void setColorScheme( int colorScheme ) { m_colorScheme = colorScheme; } + /** + * This function is for convenience; it sets both the toolbar and editor + * caption. + */ + void setCaption( const QString & caption ) { setToolbarCaption(caption); setEditorCaption(caption); } + /** + * This text is displayed to the left of the entry widget in the toolbar + */ + QString toolbarCaption() const { return m_toolbarCaption; } + void setToolbarCaption( const QString & caption ) { m_toolbarCaption = caption; } + /** + * This text is displayed to the left of the entry widget in the item editor + */ + QString editorCaption() const { return m_editorCaption; } + void setEditorCaption( const QString & caption ) { m_editorCaption = caption; } + /** + * Unit of number, (e.g. V (volts) / F (farads)) + */ + QString unit() const { return m_unit; } + void setUnit( const QString & unit ) { m_unit = unit; } + /** + * The smallest (as in negative, not absoluteness) value that the user can + * set this to. + */ + double minValue() const { return m_minValue; } + void setMinValue( double value ); + /** + * The largest (as in positive, not absoluteness) value that the user can + * set this to. + */ + double maxValue() const { return m_maxValue; } + void setMaxValue( double value ); + /** + * The smallest absolute value that the user can set this to, before the + * value is considered zero. + */ + double minAbsValue() const { return m_minAbsValue; } + void setMinAbsValue( double val ); + QVariant defaultValue() const { return m_defaultValue; } + void setDefaultValue( QVariant val ); + /** + * If this data is marked as advanced, it will only display in the item + * editor (and not in the toolbar) + */ + void setAdvanced( bool advanced ) { m_bAdvanced = advanced; } + bool isAdvanced() const { return m_bAdvanced; } + /** + * If this data is marked as hidden, it will not be editable from anywhere + * in the user interface + */ + void setHidden( bool hidden ) { m_bHidden = hidden; } + bool isHidden() const { return m_bHidden; } + /** + * Returns the best possible attempt at representing the data in a string + * for display. Used by the properties list view. + */ + QString displayString() const; + /** + * The list of values that the data is allowed to take (if it is string) + */ + QStringList allowed() const { return m_allowed; } + void setAllowed(QStringList stringList); + void appendAllowed(QString string); + + QVariant value() const { return m_value; } + void setValue( const QVariant& val ); + void resetToDefault(); + +signals: + /** + * Emitted when the value changes. + * NOTE: The order of data given is the new value, and then the old value + * This is done so that slots that don't care about the old value don't + * have to accept it + */ + void valueChanged( QVariant newValue, QVariant oldValue ); + +private: + QVariant m_value; // the actual data + QVariant m_defaultValue; + QString m_unit; + double m_minAbsValue; + double m_minValue; + double m_maxValue; + QString m_toolbarCaption; // Short description shown in e.g. properties dialog + QString m_editorCaption; // Text displayed before the data entry widget in the toolbar + bool m_bAdvanced; // If advanced, only display data in item editor + bool m_bHidden; // If hidden, do not allow user to change data + QString m_filter; // If type() == Type::FileName this is the filter used in file dialogs. + bool m_bSetDefault; // If false, then the default will be set to the first thing this variant is set to + Type::Value m_type; + QStringList m_allowed; + int m_colorScheme; +}; + +#endif diff --git a/src/view.cpp b/src/view.cpp new file mode 100644 index 0000000..07e81ec --- /dev/null +++ b/src/view.cpp @@ -0,0 +1,227 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "document.h" +#include "iteminterface.h" +#include "ktechlab.h" +#include "view.h" +#include "viewiface.h" +#include "viewcontainer.h" + +#include +#include +#include +#include +#include + +//BEGIN KVSSBSep +// Taken from kdebase-3.4.0/kate/app/kateviewspace.cpp, Copyright Anders Lund +/* + "KateViewSpaceStatusBarSeparator" + A 2 px line to separate the statusbar from the view. + It is here to compensate for the lack of a frame in the view, + I think Kate looks very nice this way, as QScrollView with frame + looks slightly clumsy... + Slight 3D effect. I looked for suitable QStyle props or methods, + but found none, though maybe it should use QStyle::PM_DefaultFrameWidth + for height (TRY!). + It does look a bit funny with flat styles (Light, .Net) as is, + but there are on methods to paint panel lines separately. And, + those styles tends to look funny on their own, as a light line + in a 3D frame next to a light contents widget is not functional. + Also, QStatusBar is up to now completely ignorant to style. + -anders +*/ +class KVSSBSep : public QWidget { + public: + KVSSBSep( View * parent=0) : QWidget(parent) + { + setFixedHeight( 2 ); + } + protected: + void paintEvent( QPaintEvent *e ) + { + QPainter p( this ); + p.setPen( colorGroup().shadow() ); + p.drawLine( e->rect().left(), 0, e->rect().right(), 0 ); + p.setPen( ((View*)parentWidget())->isFocused() ? colorGroup().light() : colorGroup().midlight() ); + p.drawLine( e->rect().left(), 1, e->rect().right(), 1 ); + } +}; +//END KVSSBSep + + + +//BEGIN class View +View::View( Document *document, ViewContainer *viewContainer, uint viewAreaId, const char *name ) + : QWidget( viewContainer->viewArea(viewAreaId), name ? name : (const char *)("view_" + QString::number(viewAreaId)) ), + KXMLGUIClient() +{ + m_dcopID = 0; + m_viewAreaId = viewAreaId; + m_pDocument = document; + p_ktechlab = document->ktechlab(); + p_viewContainer = viewContainer; + m_pViewIface = 0l; + + if ( ViewArea * viewArea = viewContainer->viewArea(viewAreaId) ) + viewArea->setView(this); + + else + kdDebug() << k_funcinfo << " viewArea = " << viewArea <addWidget( new KVSSBSep(this) ); + m_layout->addWidget( m_statusBar ); + + connect( p_ktechlab, SIGNAL(configurationChanged()), this, SLOT(slotUpdateConfiguration()) ); + } +} + + +View::~View() +{ + if (p_ktechlab) + p_ktechlab->factory()->removeClient(this); +} + + +KAction * View::action( const QString & name ) const +{ + KAction * action = actionCollection()->action(name); + if ( !action ) + kdError() << k_funcinfo << "No such action: " << name << endl; + return action; +} + + +DCOPObject * View::dcopObject( ) const +{ + return m_pViewIface; +} + + +bool View::closeView() +{ + return p_viewContainer->closeViewArea( viewAreaId() ); +} + + +void View::setFocused() +{ + b_isFocused = true; + p_viewContainer->setActiveViewArea( viewAreaId() ); + + if ( p_ktechlab ) + { + p_ktechlab->action("file_save")->setEnabled(true); + p_ktechlab->action("file_save_as")->setEnabled(true); + p_ktechlab->action("file_close")->setEnabled(true); + p_ktechlab->action("file_print")->setEnabled(true); + p_ktechlab->action("edit_paste")->setEnabled(true); + p_ktechlab->action("view_split_leftright")->setEnabled(true); + p_ktechlab->action("view_split_topbottom")->setEnabled(true); + + ItemInterface::self()->updateItemActions(); + } + + emit viewFocused(this); +} + + +void View::setUnfocused() +{ + b_isFocused = false; + emit viewUnfocused(); +} + + +void View::setDCOPID( unsigned id ) +{ + if ( m_dcopID == id ) + return; + + m_dcopID = id; + if ( m_pViewIface ) + { + QCString docID; + docID.setNum( document()->dcopID() ); + + QCString viewID; + viewID.setNum( dcopID() ); + + m_pViewIface->setObjId( "View#" + docID + "." + viewID ); + } +} +//END class View + + + +//BEGIN class ViewStatusBar +ViewStatusBar::ViewStatusBar( View *view ) + : KStatusBar(view) +{ + p_view = view; + + m_modifiedLabel = new QLabel(this); + addWidget( m_modifiedLabel, 0, false ); + m_fileNameLabel = new KSqueezedTextLabel(this); + addWidget( m_fileNameLabel, 1, false ); + + m_modifiedPixmap = KGlobal::iconLoader()->loadIcon( "filesave", KIcon::Small ); + m_unmodifiedPixmap = KGlobal::iconLoader()->loadIcon( "null", KIcon::Small ); + + connect( view->document(), SIGNAL(modifiedStateChanged()), this, SLOT(slotModifiedStateChanged()) ); + connect( view->document(), SIGNAL(fileNameChanged(const KURL& )), this, SLOT(slotFileNameChanged(const KURL& )) ); + + connect( view, SIGNAL(viewFocused(View* )), this, SLOT(slotViewFocused(View* )) ); + connect( view, SIGNAL(viewUnfocused()), this, SLOT(slotViewUnfocused()) ); + + slotModifiedStateChanged(); + slotFileNameChanged( view->document()->url() ); +} + + +void ViewStatusBar::slotModifiedStateChanged() +{ + m_modifiedLabel->setPixmap( p_view->document()->isModified() ? m_modifiedPixmap : m_unmodifiedPixmap ); +} + + +void ViewStatusBar::slotFileNameChanged( const KURL &url ) +{ + m_fileNameLabel->setText( url.isEmpty() ? i18n("Untitled") : url.fileName(true) ); +} + + +void ViewStatusBar::slotViewFocused( View * ) +{ + setPalette(p_view->palette()); +} + + +void ViewStatusBar::slotViewUnfocused() +{ + QPalette pal( p_view->palette() ); + pal.setColor( QColorGroup::Background, pal.active().mid() ); + pal.setColor( QColorGroup::Light, pal.active().midlight() ); + setPalette(pal); +} +//END class ViewStatusBar + +#include "view.moc" diff --git a/src/view.h b/src/view.h new file mode 100644 index 0000000..d501363 --- /dev/null +++ b/src/view.h @@ -0,0 +1,155 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef VIEW_H +#define VIEW_H + +#include +#include +#include +#include +#include + +class DCOPObject; +class Document; +class KSqueezedTextLabel; +class KTechlab; +class View; +class ViewContainer; +class ViewIface; +class QVBoxLayout; + +class ViewStatusBar : public KStatusBar +{ +Q_OBJECT +public: + ViewStatusBar( View *view ); + + enum InfoId + { + SimulationState, + LineCol, + InsertMode, + SelectionMode + }; + +public slots: + void slotModifiedStateChanged(); + void slotFileNameChanged( const KURL &url ); + void slotViewFocused( View * ); + void slotViewUnfocused(); + +protected: + View *p_view; + QLabel* m_modifiedLabel; + KSqueezedTextLabel* m_fileNameLabel; + QPixmap m_modifiedPixmap; + QPixmap m_unmodifiedPixmap; +}; + +/** +@author David Saxton +*/ +class View : public QWidget, public KXMLGUIClient +{ +Q_OBJECT +public: + View( Document *document, ViewContainer *viewContainer, uint viewAreaId, const char *name = 0 ); + virtual ~View(); + + KAction * action( const QString & name ) const; + bool isFocused() const { return b_isFocused; } + /** + * Pointer to the parent document + */ + Document *document() const { return m_pDocument; } + /** + * Returns the DCOP object from this view + */ + DCOPObject * dcopObject() const; + /** + * Returns the dcop suffix for this view - a unique ID for the current the + * view within all views associated with the parent document. DCOP name + * will become "View#docID#viewID". + */ + unsigned dcopID() const { return m_dcopID; } + /** + * Sets the dcop suffix. The DCOP object for this view will be renamed. + * @see dcopID + */ + void setDCOPID( unsigned id ); + /** + * Pointer to the ViewContainer that we're in + */ + ViewContainer *viewContainer() const { return p_viewContainer; } + /** + * Tells the view container which contains this view to close this view, + * returning true if successful (i.e. not both last view and unsaved, etc) + */ + virtual bool closeView(); + /** + * Returns the unique (for the view container) view area id associated with this view + */ + uint viewAreaId() const { return m_viewAreaId; } + /** + * Zoom in + */ + virtual void viewZoomIn() {}; + /** + * Zoom out + */ + virtual void viewZoomOut() {}; + virtual bool canZoomIn() const { return true; } + virtual bool canZoomOut() const { return true; } + /** + * Restore view to actual size + */ + virtual void actualSize() {}; + + virtual void toggleBreakpoint() {}; + /** + * Called by ktechlab when it has entered its destructor to avoid calls to + * it (such as from the TextView destructor). + */ + void setKTechlabDeleted() { p_ktechlab = 0l; } + +public slots: + /** + * Called when the view is to be focused (enables actions, etc) + */ + virtual void setFocused(); + /** + * Called when the view is to be unfocused (disables actions, etc) + */ + virtual void setUnfocused(); + +protected slots: + /** + * Called when the user changes the configuration. + */ + virtual void slotUpdateConfiguration() {}; + +signals: + void viewFocused( View *view ); + void viewUnfocused(); + +protected: + QGuardedPtr m_pDocument; + KTechlab * p_ktechlab; + QGuardedPtr p_viewContainer; + uint m_viewAreaId; + bool b_isFocused; + ViewStatusBar *m_statusBar; + QVBoxLayout *m_layout; + ViewIface * m_pViewIface; + unsigned m_dcopID; +}; + +#endif diff --git a/src/viewcontainer.cpp b/src/viewcontainer.cpp new file mode 100644 index 0000000..4f145dd --- /dev/null +++ b/src/viewcontainer.cpp @@ -0,0 +1,610 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "docmanager.h" +#include "document.h" +#include "ktechlab.h" +#include "view.h" +#include "viewcontainer.h" + +#include +#include +#include +#include +#include +#include + +ViewContainer::ViewContainer( const QString & caption, KTechlab * ktechlab, QWidget * parent ) + : QWidget( ktechlab ? ktechlab->tabWidget() : parent ) +{ + b_deleted = false; + p_ktechlab = ktechlab; + if (ktechlab) + connect( ktechlab, SIGNAL(needUpdateCaptions()), this, SLOT(updateCaption()) ); + + QHBoxLayout *layout = new QHBoxLayout(this); + m_baseViewArea = new ViewArea( this, this, 0, "viewarea_0" ); + connect( m_baseViewArea, SIGNAL(destroyed(QObject* )), this, SLOT(baseViewAreaDestroyed(QObject* )) ); + + layout->addWidget(m_baseViewArea); + + m_activeViewArea = 0; + b_focused = false; + + if (ktechlab) + ktechlab->tabWidget()->addTab( this, caption ); + + show(); + + if (ktechlab) + ktechlab->tabWidget()->setCurrentPage( ktechlab->tabWidget()->indexOf(this) ); +} + + +ViewContainer::~ViewContainer() +{ + b_deleted = true; +} + + +void ViewContainer::setFocused() +{ + if (b_focused) + return; + b_focused = true; + + View *view = activeView(); + if (view) + view->setFocused(); +} + + +void ViewContainer::setUnfocused() +{ + if (!b_focused) + return; + b_focused = false; + + View *view = activeView(); + if (view) + view->setUnfocused(); +} + + +void ViewContainer::setActiveViewArea( uint id ) +{ + if ( m_activeViewArea == int(id) ) + return; + + View *oldView = view(m_activeViewArea); + if (oldView) + oldView->setUnfocused(); + + m_activeViewArea = id; + + ViewArea *va = viewArea(id); + if ( va && b_focused ) + va->setFocus(); + + View *newView = view(id); + if ( newView && b_focused ); + { + if (newView) + { + setCaption( newView->caption() ); + newView->setFocused(); + } + } +} + + +View *ViewContainer::view( uint id ) const +{ + ViewArea *va = viewArea(id); + if (!va) + return 0l; + + // We do not want a recursive search as ViewAreas also hold other ViewAreas + QObjectList *l = va->queryList( "View", 0, false, false ); + View *view = 0l; + if ( !l->isEmpty() ) + view = dynamic_cast(l->first()); + delete l; + + return view; +} + + +ViewArea *ViewContainer::viewArea( uint id ) const +{ + if ( !m_viewAreaMap.contains(id) ) + return 0l; + + return m_viewAreaMap[id]; +} + + +bool ViewContainer::closeViewContainer() +{ + bool didClose = true; + while ( didClose && !m_viewAreaMap.isEmpty() ) + { + didClose = closeViewArea( m_viewAreaMap.begin().key() ); + } + + return m_viewAreaMap.isEmpty(); +} + + +bool ViewContainer::closeViewArea( uint id ) +{ + ViewArea *va = viewArea(id); + if ( !va ) + return true; + + bool doClose = false; + View *v = view(id); + if ( v && v->document() ) + { + doClose = v->document()->numberOfViews() > 1; + if (!doClose) + doClose = v->document()->fileClose(); + } + else + doClose = true; + + if (!doClose) + return false; + + m_viewAreaMap.remove(id); + va->deleteLater(); + + if ( m_activeViewArea == int(id) ) + { + m_activeViewArea = -1; + findActiveViewArea(); + } + + return true; +} + + +int ViewContainer::createViewArea( int relativeViewArea, ViewArea::Position position ) +{ + if ( relativeViewArea == -1 ) + relativeViewArea = activeViewArea(); + + ViewArea *relative = viewArea(relativeViewArea); + if (!relative) + { + kdError() << k_funcinfo << "Could not find relative view area" << endl; + return -1; + } + + uint id = uniqueNewId(); +// setActiveViewArea(id); + + ViewArea *viewArea = relative->createViewArea( position, id ); +// ViewArea *viewArea = new ViewArea( m_splitter, id, (const char*)("viewarea_"+QString::number(id)) ); + viewArea->show(); // remove? + + return id; +} + + +void ViewContainer::setViewAreaId( ViewArea *viewArea, uint id ) +{ + m_viewAreaMap[id] = viewArea; + m_usedIDs.append(id); +} + + +void ViewContainer::setViewAreaRemoved( uint id ) +{ + if (b_deleted) + return; + + ViewAreaMap::iterator it = m_viewAreaMap.find(id); + if ( it == m_viewAreaMap.end() ) + return; + + m_viewAreaMap.erase(it); + + if ( m_activeViewArea == int(id) ) + findActiveViewArea(); +} + + +void ViewContainer::findActiveViewArea() +{ + if ( m_viewAreaMap.isEmpty() ) + return; + + setActiveViewArea( (--m_viewAreaMap.end()).key() ); +} + + +void ViewContainer::baseViewAreaDestroyed( QObject *obj ) +{ + if (!obj) + return; + + if (!b_deleted) + { + b_deleted = true; + close(); + deleteLater(); + } +} + + +ViewContainer * ViewContainer::duplicateViewContainer() +{ + ViewContainer *viewContainer = new ViewContainer( caption(), p_ktechlab ); + copyViewContainerIntoExisting(viewContainer); + + p_ktechlab->addWindow(viewContainer); + + return viewContainer; +} + + +void ViewContainer::copyViewContainerIntoExisting( ViewContainer *viewContainer ) +{ + if (!viewContainer) + return; + + const ViewAreaMap::iterator end = m_viewAreaMap.end(); + for ( ViewAreaMap::iterator it = m_viewAreaMap.begin(); it != end; ++it ) + { + View *oldView = view(it.key()); + if (!oldView) + continue; + + // See if there is an empty view container to be inserted into with id 0... + uint newId; + if ( viewContainer->view(0) ) + newId = viewContainer->createViewArea( 0, ViewArea::Right ); + else + newId = 0; + + oldView->document()->createView( viewContainer, newId ); + } +} + + +bool ViewContainer::canSaveUsefulStateInfo() const +{ + return m_baseViewArea && m_baseViewArea->canSaveUsefulStateInfo(); +} + + +void ViewContainer::saveState( KConfig *config ) +{ + if (!m_baseViewArea) + return; + + config->writeEntry( "BaseViewArea", m_baseViewArea->id() ); + m_baseViewArea->saveState(config); +} + + +void ViewContainer::restoreState( KConfig *config, const QString &groupName ) +{ + config->setGroup(groupName); + int baseAreaId = config->readNumEntry("BaseViewArea"); + m_baseViewArea->restoreState( config, baseAreaId, groupName ); +} + + +int ViewContainer::uniqueParentId() +{ + int lowest = -1; + const IntList::iterator end = m_usedIDs.end(); + for ( IntList::iterator it = m_usedIDs.begin(); it != end; ++it ) + { + if ( *it < lowest ) + lowest = *it; + } + int newId = lowest-1; + m_usedIDs.append(newId); + return newId; +} + + +int ViewContainer::uniqueNewId() +{ + int highest = 0; + const IntList::iterator end = m_usedIDs.end(); + for ( IntList::iterator it = m_usedIDs.begin(); it != end; ++it ) + { + if ( *it > highest ) + highest = *it; + } + int newId = highest+1; + m_usedIDs.append(newId); + return newId; +} + + +void ViewContainer::setIdUsed( int id ) +{ + m_usedIDs.append(id); +} + + +void ViewContainer::updateCaption() +{ + QString caption; + + if ( !activeView() || !activeView()->document() ) + caption = i18n("(empty)"); + + else + { + Document * doc = activeView()->document(); + caption = doc->url().isEmpty() ? doc->caption() : doc->url().fileName(); + if ( viewCount() > 1 ) + caption += " ..."; + } + + setCaption(caption); + p_ktechlab->tabWidget()->setTabLabel( this, caption ); +} + + +void ViewContainer::setKTechlabDeleted() +{ + p_ktechlab = 0l; + ViewAreaMap::iterator end = m_viewAreaMap.end(); + for ( ViewAreaMap::iterator it = m_viewAreaMap.begin(); it != end; ++it ) + { + if ( *it ) + (*it)->setKTechlabDeleted(); + } +} + + + + + +ViewArea::ViewArea( QWidget *parent, ViewContainer *viewContainer, int id, const char *name ) + : QSplitter( parent, name ) +{ + p_viewContainer = viewContainer; + m_id = id; + p_view = 0l; + p_viewArea1 = 0l; + p_viewArea2 = 0l; + if (id >= 0) + p_viewContainer->setViewAreaId( this, uint(id) ); + p_viewContainer->setIdUsed(id); + setOpaqueResize(KGlobalSettings::opaqueResize()); +} + + +ViewArea::~ViewArea() +{ + if ( m_id >= 0 ) + p_viewContainer->setViewAreaRemoved( uint(m_id) ); +} + + +ViewArea *ViewArea::createViewArea( Position position, uint id ) +{ + if (p_viewArea1 || p_viewArea2) + { + kdError() << k_funcinfo << "Attempting to create ViewArea when already containing ViewAreas!" << endl; + return 0l; + } + if (!p_view) + { + kdError() << k_funcinfo << "We don't have a view yet, so creating a new ViewArea is redundant" << endl; + return 0l; + } + + setOrientation( ( position == Right ) ? Qt::Horizontal : Qt::Vertical ); + + p_viewArea1 = new ViewArea( this, p_viewContainer, m_id, (const char*)("viewarea_"+QString::number(m_id)) ); + p_viewArea2 = new ViewArea( this, p_viewContainer, id, (const char*)("viewarea_"+QString::number(id)) ); + + connect( p_viewArea1, SIGNAL(destroyed(QObject* )), this, SLOT(viewAreaDestroyed(QObject* )) ); + connect( p_viewArea2, SIGNAL(destroyed(QObject* )), this, SLOT(viewAreaDestroyed(QObject* )) ); + + p_view->reparent( p_viewArea1, QPoint(), true ); + p_viewArea1->setView(p_view); + p_view = 0l; + m_id = p_viewContainer->uniqueParentId(); + + QValueList splitPos; + int pos = ((orientation() == Qt::Horizontal) ? width()/2 : height()/2); + splitPos << pos << pos; + setSizes(splitPos); + + p_viewArea1->show(); + p_viewArea2->show(); + return p_viewArea2; +} + + +void ViewArea::viewAreaDestroyed( QObject *obj ) +{ + ViewArea *viewArea = static_cast(obj); + + if ( viewArea == p_viewArea1 ) + p_viewArea1 = 0l; + + if ( viewArea == p_viewArea2 ) + p_viewArea2 = 0l; + + if ( !p_viewArea1 && !p_viewArea2 ) + deleteLater(); +} + + +void ViewArea::setView( View *view ) +{ + if (!view) + return; + if (p_view) + { + kdError() << k_funcinfo << "Attempting to set already contained view!" << endl; + return; + } + p_view = view; + connect( view, SIGNAL(destroyed()), this, SLOT(viewDestroyed()) ); +} + + +void ViewArea::viewDestroyed() +{ + if ( !p_view && !p_viewArea1 && !p_viewArea2 ) + deleteLater(); +} + + +void ViewArea::setKTechlabDeleted() +{ + if ( p_view ) + p_view->setKTechlabDeleted(); +} + + +bool ViewArea::canSaveUsefulStateInfo() const +{ + if ( p_viewArea1 && p_viewArea1->canSaveUsefulStateInfo() ) + return true; + + if ( p_viewArea2 && p_viewArea2->canSaveUsefulStateInfo() ) + return true; + + if ( p_view && p_view->document() && !p_view->document()->url().isEmpty() ) + return true; + + return false; +} + + +void ViewArea::saveState( KConfig *config ) +{ + bool va1Ok = p_viewArea1 && p_viewArea1->canSaveUsefulStateInfo(); + bool va2Ok = p_viewArea2 && p_viewArea2->canSaveUsefulStateInfo(); + + if ( va1Ok || va2Ok ) + { + config->writeEntry( orientationKey(m_id), (orientation() == Qt::Horizontal) ? "LeftRight" : "TopBottom" ); + + QValueList contains; + if (va1Ok) + contains << p_viewArea1->id(); + if (va2Ok) + contains << p_viewArea2->id(); + + config->writeEntry( containsKey(m_id), contains ); + if (va1Ok) + p_viewArea1->saveState(config); + if (va2Ok) + p_viewArea2->saveState(config); + } + else if ( p_view && !p_view->document()->url().isEmpty() ) + { + config->writePathEntry( fileKey(m_id), p_view->document()->url().prettyURL() ); + } +} + + +void ViewArea::restoreState( KConfig *config, int id, const QString &groupName ) +{ + if (!config) + return; + + if ( id != m_id ) + { + if ( m_id >= 0 ) + p_viewContainer->setViewAreaRemoved( uint(m_id) ); + + m_id = id; + + if ( m_id >= 0 ) + p_viewContainer->setViewAreaId( this, uint(m_id) ); + + p_viewContainer->setIdUsed(id); + } + + config->setGroup(groupName); + if ( config->hasKey( orientationKey(id) ) ) + { + QString orientation = config->readEntry( orientationKey(m_id) ); + setOrientation( (orientation == "LeftRight") ? Qt::Horizontal : Qt::Vertical ); + } + + config->setGroup(groupName); + if ( config->hasKey( containsKey(m_id) ) ) + { + typedef QValueList IntList; + IntList contains = config->readIntListEntry( containsKey(m_id) ); + + if ( contains.isEmpty() || contains.size() > 2 ) + kdError() << k_funcinfo << "Contained list has wrong size of " << contains.size() << endl; + + else + { + if ( contains.size() >= 1 ) + { + int viewArea1Id = contains[0]; + p_viewArea1 = new ViewArea( this, p_viewContainer, viewArea1Id, (const char*)("viewarea_"+QString::number(viewArea1Id)) ); + connect( p_viewArea1, SIGNAL(destroyed(QObject* )), this, SLOT(viewAreaDestroyed(QObject* )) ); + p_viewArea1->restoreState( config, viewArea1Id, groupName ); + p_viewArea1->show(); + } + + if ( contains.size() >= 2 ) + { + int viewArea2Id = contains[1]; + p_viewArea2 = new ViewArea( this, p_viewContainer, viewArea2Id, (const char*)("viewarea_"+QString::number(viewArea2Id)) ); + connect( p_viewArea2, SIGNAL(destroyed(QObject* )), this, SLOT(viewAreaDestroyed(QObject* )) ); + p_viewArea2->restoreState( config, viewArea2Id, groupName ); + p_viewArea2->show(); + } + } + } + + config->setGroup(groupName); + if ( config->hasKey( fileKey(m_id) ) ) + { + bool openedOk = DocManager::self()->openURL( config->readPathEntry( fileKey(m_id) ), this ); + if (!openedOk) + deleteLater(); + } +} + +QString ViewArea::fileKey( int id ) +{ + return QString("ViewArea ") + QString::number(id) + QString(" file"); +} +QString ViewArea::containsKey( int id ) +{ + return QString("ViewArea ") + QString::number(id) + QString(" contains"); +} +QString ViewArea::orientationKey( int id ) +{ + return QString("ViewArea ") + QString::number(id) + QString(" orientation"); +} + + + + +ViewContainerDrag::ViewContainerDrag( ViewContainer *viewContainer ) + : QStoredDrag( "dontcare", viewContainer) +{ + p_viewContainer = viewContainer; +} + +#include "viewcontainer.moc" diff --git a/src/viewcontainer.h b/src/viewcontainer.h new file mode 100644 index 0000000..c798530 --- /dev/null +++ b/src/viewcontainer.h @@ -0,0 +1,249 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef VIEWCONTAINER_H +#define VIEWCONTAINER_H + +#include +#include +#include +#include + +class KTechlab; +class View; +class ViewArea; +class ViewContainer; + +class KConfig; +class QHBoxLayout; +class QLayout; +class QSplitter; + +typedef QMap< uint, ViewArea* > ViewAreaMap; +typedef QValueList IntList; + +class ViewContainerDrag : public QStoredDrag +{ +public: + ViewContainerDrag( ViewContainer *viewContainer ); + + ViewContainer *viewContainer() const { return p_viewContainer; } + +protected: + ViewContainer *p_viewContainer; +}; + + +/** +Contains either exactly one View, or two ViewAreas, seperated by a QSplitter. +If it contains one view, then the value returned in id() is that of the view. +If it contains two ViewAreas, then the value returned by id() is -1. +@author David Saxton +*/ +class ViewArea : public QSplitter +{ +Q_OBJECT +public: + enum Position + { + Right, + Bottom + }; + + ViewArea( QWidget *parent, ViewContainer *viewContainer, int id, const char *name = 0 ); + ~ViewArea(); + + ViewContainer *viewContainer() const { return p_viewContainer; } + int id() const { return m_id; } + /** + * Splits this ViewArea into two, and returns a pointer to the new ViewArea + */ + ViewArea *createViewArea( Position position, uint id ); + /** + * Adds the given View to the main part of the layout + */ + void setView( View *view ); + /** + * Saves the state of this ViewArea and any contained ViewAreas + */ + void saveState( KConfig *config ); + /** + * Restores the state of this ViewArea and any contained ViewAreas + * @param groupName e.g. "ViewContainer 1" + */ + void restoreState( KConfig *config, int id, const QString &groupName ); + /** + * Returns true if this ViewArea can save useful information as to its state + * (i.e. it's children can save useful information about their state, or has + * a view with a url in it) + */ + bool canSaveUsefulStateInfo() const; + /** + * Calls View::setKTechlabDeleted. + */ + void setKTechlabDeleted(); + + static QString fileKey( int id ); + static QString containsKey( int id ); + static QString orientationKey( int id ); + +protected slots: + void viewAreaDestroyed( QObject *obj ); + void viewDestroyed(); + +protected: + int m_id; + QGuardedPtr p_view; + ViewArea *p_viewArea1; + ViewArea *p_viewArea2; + ViewContainer *p_viewContainer; +}; + +/** +@author David Saxton +*/ +class ViewContainer : public QWidget +{ +Q_OBJECT +public: + /** + * Constructs a new ViewContainer, along with a default ViewArea ready for + * parenting a View, with an id of 0. parent is only used if ktechlab is + * null; otherwise the parent widget is ktechlab's tabWidget() + */ + ViewContainer( const QString & caption, KTechlab * ktechlab, QWidget * parent = 0 ); + ~ViewContainer(); + + /** + * Returns the view in the ViewArea with the given id + */ + View *view( uint id ) const; + /** + * Returns the ViewArea with the given id + */ + ViewArea *viewArea( uint id ) const; + /** + * The active view area is the one that is focused. + */ + void setActiveViewArea( uint id ); + /** + * Returns the id of the active ViewArea + */ + uint activeViewArea() const { return m_activeViewArea; } + /** + * Returns a pointer to the view of the active view area + */ + View *activeView() const { return view( activeViewArea() ); } + /** + * Attempts to close the given viewarea, returning true if successful (i.e + * if the user did not object to the close request ) + */ + bool closeViewArea( uint id ); + /** + * Creates a view area (parent QWidget, splitter et al) ready for inclusion + * of a view. + * @param relativeViewArea the viewarea to position the new viewarea next to, if -1 then is taken to be the active view area + * @param position Top, Right, Bottom or Left of given relativeViewArea + * @returns id of the the view area, or -1 if unsucessful + */ + int createViewArea( int relativeViewArea, ViewArea::Position position = ViewArea::Right ); + /** + * Attempts to close each view area, returning false if any fail to be + * closed + */ + bool closeViewContainer(); + /** + * @returns number of views in this view container + */ + uint viewCount() const { return m_viewAreaMap.size(); } + /** + * Called when the view container is focused (e.g. user clicks on the tab + * for this view container) + */ + void setFocused(); + /** + * Called when the view container is unfocused (e.g. user clicks on another + * tab). + */ + void setUnfocused(); + /** + * Create a new view container, and make a new instance of each view in + * that view container. + */ + ViewContainer* duplicateViewContainer(); + /** + * Copies each view in this ViewContainer into the given ViewContainer + */ + void copyViewContainerIntoExisting( ViewContainer *viewContainer ); + /** + * Sets the pointer to the view area with the given id + */ + void setViewAreaId( ViewArea *viewArea, uint id ); + /** + * Removes a ViewArea from internal lists + */ + void setViewAreaRemoved( uint id ); + /** + * Sets the id to be "used" + */ + void setIdUsed( int id ); + /** + * Writes the state of the View Container (layout of views and view URLs) + * to the given KConfig. Doesn't change the group - so preset it if + * needed! + */ + void saveState( KConfig *config ); + /** + * Reads in the saved config state (as written by saveState), and restores + * the ViewContainer with all appropriate views open + * @param groupName e.g. "ViewContainer 1" + */ + void restoreState( KConfig *config, const QString &groupName ); + /** + * Returns a unique id (negative) for a ViewArea that is now a Parent of other ViewAreas + */ + int uniqueParentId(); + /** + * Returns a unique id (positive) for a new ViewArea + */ + int uniqueNewId(); + /** + * Returns true if this ViewArea can save useful information as to its state + * (i.e. it's children can save useful information about their state, or has + * a view with a url in it) + */ + bool canSaveUsefulStateInfo() const; + /** + * Calls setKTechlabDeleted for each ViewArea. + */ + void setKTechlabDeleted(); + +public slots: + /** + * Sets the tab caption et al from the contents of this ViewContainer + */ + void updateCaption(); + +protected slots: + void baseViewAreaDestroyed( QObject *obj ); + +protected: + void restoreViewArea( KConfig *config, int id, ViewArea *viewArea ); + void findActiveViewArea(); + int m_activeViewArea; + ViewArea *m_baseViewArea; + ViewAreaMap m_viewAreaMap; + IntList m_usedIDs; + KTechlab *p_ktechlab; + bool b_focused; + bool b_deleted; +}; + +#endif diff --git a/src/viewiface.cpp b/src/viewiface.cpp new file mode 100644 index 0000000..592b0fe --- /dev/null +++ b/src/viewiface.cpp @@ -0,0 +1,142 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "circuitview.h" +#include "document.h" +#include "flowcodeview.h" +#include "mechanicsview.h" +#include "textview.h" +#include "viewiface.h" + + +//BEGIN class ViewIface +ViewIface::ViewIface( View * view ) + : DCOPObject("View") +{ + m_pView = view; +} + +ViewIface::~ ViewIface( ) +{ +} + +DCOPRef ViewIface::document( ) +{ + return DCOPRef( m_pView->document()->dcopObject() ); +} + +bool ViewIface::isFocused( ) +{ + return m_pView->isFocused(); +} + +bool ViewIface::close( ) +{ + return m_pView->closeView(); +} + +void ViewIface::zoomIn( ) +{ + m_pView->viewZoomIn(); +} + +void ViewIface::zoomOut( ) +{ + m_pView->viewZoomOut(); +} + +bool ViewIface::canZoomIn( ) +{ + return m_pView->canZoomIn(); +} + +bool ViewIface::canZoomOut( ) +{ + return m_pView->canZoomOut(); +} + +void ViewIface::actualSize( ) +{ + m_pView->actualSize(); +} +//END class ViewIface + + + +//BEGIN class TextViewIface +TextViewIface::TextViewIface( TextView * view ) + : ViewIface(view) +{ + m_pTextView = view; +} + +void TextViewIface::toggleBreakpoint( ) +{ + m_pTextView->toggleBreakpoint(); +} + +bool TextViewIface::gotoLine( const int line ) +{ + return m_pTextView->gotoLine(line); +} +//END class TextViewIface + + + +//BEGIN class ItemViewIface +ItemViewIface::ItemViewIface( ItemView * view ) + : ViewIface(view) +{ + m_pItemView = view; +} + +double ItemViewIface::zoomLevel( ) +{ + return m_pItemView->zoomLevel(); +} +//END class ItemViewIface + + + +//BEGIN class MechanicsViewIface +MechanicsViewIface::MechanicsViewIface( MechanicsView * view ) + : ItemViewIface(view) +{ + m_pMechanicsView = view; +} +//END class ICNViewIface + + + +//BEGIN class ICNViewIface +ICNViewIface::ICNViewIface( ICNView * view ) + : ItemViewIface(view) +{ + m_pICNView = view; +} +//END class ICNViewIface + + + +//BEGIN class CircuitViewIface +CircuitViewIface::CircuitViewIface( CircuitView * view ) + : ICNViewIface(view) +{ + m_pCircuitView = view; +} +//END class CircuitViewIface + + +//BEGIN class FlowCodeViewIface +FlowCodeViewIface::FlowCodeViewIface( FlowCodeView * view ) + : ICNViewIface(view) +{ +} +//END class FlowCodeViewIface diff --git a/src/viewiface.h b/src/viewiface.h new file mode 100644 index 0000000..71290b5 --- /dev/null +++ b/src/viewiface.h @@ -0,0 +1,123 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef VIEWIFACE_H +#define VIEWIFACE_H + +#include +#include + +class CircuitView; +class FlowCodeView; +class ICNView; +class ItemView; +class MechanicsView; +class TextView; +class View; + +/** +@author David Saxton +*/ +class ViewIface : public DCOPObject +{ + K_DCOP + + public: + ViewIface( View * view ); + virtual ~ViewIface(); + + k_dcop: + DCOPRef document(); + bool isFocused(); + bool close(); + void zoomIn(); + void zoomOut(); + bool canZoomIn(); + bool canZoomOut(); + void actualSize(); + + protected: + View * m_pView; +}; + +class TextViewIface : public ViewIface +{ + K_DCOP + + public: + TextViewIface( TextView * view ); + + k_dcop: + void toggleBreakpoint(); + bool gotoLine( const int line ); + + protected: + TextView * m_pTextView; +}; + +class ItemViewIface : public ViewIface +{ + K_DCOP + + public: + ItemViewIface( ItemView * view ); + + k_dcop: + double zoomLevel(); + + protected: + ItemView * m_pItemView; +}; + +class MechanicsViewIface : public ItemViewIface +{ + K_DCOP + + public: + MechanicsViewIface( MechanicsView * view ); + + protected: + MechanicsView * m_pMechanicsView; +}; + +class ICNViewIface : public ItemViewIface +{ + K_DCOP + + public: + ICNViewIface( ICNView * view ); + + protected: + ICNView * m_pICNView; +}; + +class CircuitViewIface : public ICNViewIface +{ + K_DCOP + + public: + CircuitViewIface( CircuitView * view ); + + protected: + CircuitView * m_pCircuitView; +}; + +class FlowCodeViewIface : public ICNViewIface +{ + K_DCOP + + public: + FlowCodeViewIface( FlowCodeView * view ); + + protected: + FlowCodeView * m_pFlowCodeView; +}; + +#endif diff --git a/src/x-circuit.desktop b/src/x-circuit.desktop new file mode 100644 index 0000000..75b97d4 --- /dev/null +++ b/src/x-circuit.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=MimeType +MimeType=application/x-circuit +Icon=ktechlab_circuit +Patterns=*.circuit +Comment=KTechlab Circuit \ No newline at end of file diff --git a/src/x-flowcode.desktop b/src/x-flowcode.desktop new file mode 100644 index 0000000..6283e40 --- /dev/null +++ b/src/x-flowcode.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=MimeType +MimeType=application/x-flowcode +Icon=ktechlab_flowcode +Patterns=*.flowcode +Comment=KTechlab FlowCode \ No newline at end of file diff --git a/src/x-ktechlab.desktop b/src/x-ktechlab.desktop new file mode 100644 index 0000000..82f6fb2 --- /dev/null +++ b/src/x-ktechlab.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=MimeType +MimeType=application/x-ktechlab +Icon=ktechlab +Patterns=*.ktechlab +Comment=KTechlab Project \ No newline at end of file diff --git a/src/x-microbe.desktop b/src/x-microbe.desktop new file mode 100644 index 0000000..be36ee4 --- /dev/null +++ b/src/x-microbe.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=MimeType +MimeType=application/x-microbe +Icon=ktechlab_microbe +Patterns=*.microbe;*.basic +Comment=KTechlab Microbe diff --git a/stamp-h.in b/stamp-h.in new file mode 100644 index 0000000..e69de29 diff --git a/subdirs b/subdirs new file mode 100644 index 0000000..9cf27b9 --- /dev/null +++ b/subdirs @@ -0,0 +1,5 @@ +doc +icons +microbe +po +src