From 19aefc486bb3cf3960a57119187588518934c77d Mon Sep 17 00:00:00 2001 From: Maximiliano Curia Date: Mon, 20 Oct 2014 16:13:37 +0100 Subject: [PATCH] Import kalgebra_4.14.2.orig.tar.xz [dgit import orig kalgebra_4.14.2.orig.tar.xz] --- CMakeLists.txt | 46 ++ COPYING | 339 ++++++++ COPYING.DOC | 397 ++++++++++ COPYING.LIB | 481 +++++++++++ Mainpage.dox | 5 + TODO | 17 + cmake/COPYING-CMAKE-SCRIPTS | 22 + cmake/FindAnalitza.cmake | 28 + config-kalgebra.h.cmake | 1 + doc/CMakeLists.txt | 4 + doc/commands.docbook | 405 ++++++++++ doc/index.docbook | 529 +++++++++++++ doc/kalgebra-2dgraph-window.png | Bin 0 -> 56109 bytes doc/kalgebra-3dgraph-window.png | Bin 0 -> 69348 bytes doc/kalgebra-console-window.png | Bin 0 -> 16260 bytes doc/kalgebra-dictionary-window.png | Bin 0 -> 20554 bytes doc/kalgebra-main-window.png | Bin 0 -> 15624 bytes doc/view-fullscreen.png | Bin 0 -> 329 bytes icons/CMakeLists.txt | 2 + icons/hi128-app-kalgebra.png | Bin 0 -> 10549 bytes icons/hi16-app-kalgebra.png | Bin 0 -> 696 bytes icons/hi32-app-kalgebra.png | Bin 0 -> 1536 bytes icons/hi48-app-kalgebra.png | Bin 0 -> 2645 bytes icons/hi64-app-kalgebra.png | Bin 0 -> 3473 bytes icons/hisc-app-kalgebra.svgz | Bin 0 -> 1587 bytes kalgebra.appdata.xml | 81 ++ kalgebra.kdev4 | 3 + mobile/CMakeLists.txt | 30 + mobile/declarative/CMakeLists.txt | 18 + .../declarative/analitzadeclarativeplugin.cpp | 35 + .../declarative/analitzadeclarativeplugin.h | 31 + mobile/declarative/analitzawrapper.cpp | 156 ++++ mobile/declarative/analitzawrapper.h | 87 ++ mobile/declarative/graph2dmobile.cpp | 132 ++++ mobile/declarative/graph2dmobile.h | 72 ++ mobile/declarative/qml/Graph2D.qml | 57 ++ mobile/declarative/qmldir | 3 + mobile/kalgebramobile.cpp | 83 ++ mobile/kalgebramobile.desktop | 136 ++++ mobile/kalgebramobile.h | 60 ++ mobile/kalgebramobileharmattan.desktop | 150 ++++ mobile/main.cpp | 81 ++ mobile/plugins/About.qml | 57 ++ mobile/plugins/CMakeLists.txt | 8 + mobile/plugins/Console.qml | 59 ++ mobile/plugins/Plot2D.qml | 54 ++ mobile/plugins/Tables.qml | 88 +++ mobile/plugins/VariablesView.qml | 13 + mobile/plugins/kalgebraabout.desktop | 53 ++ mobile/plugins/kalgebraconsole.desktop | 97 +++ mobile/plugins/kalgebraplot2d.desktop | 92 +++ mobile/plugins/kalgebratables.desktop | 90 +++ mobile/plugins/kalgebravariables.desktop | 89 +++ mobile/plugins/resources/kde-edu-logo.png | Bin 0 -> 16041 bytes mobile/plugins/widgets/CMakeLists.txt | 6 + mobile/plugins/widgets/desktop/Button.qml | 3 + mobile/plugins/widgets/desktop/CMakeLists.txt | 7 + mobile/plugins/widgets/desktop/CalcButton.qml | 6 + .../widgets/desktop/ConsoleDelegate.qml | 28 + .../widgets/desktop/ExpressionInput.qml | 24 + .../widgets/desktop/KAlgebraMobile.qml | 76 ++ .../plugins/widgets/desktop/KAlgebraPage.qml | 9 + mobile/plugins/widgets/desktop/Keyboard.qml | 45 ++ mobile/plugins/widgets/desktop/Label.qml | 6 + mobile/plugins/widgets/desktop/RealInput.qml | 6 + .../widgets/desktop/SimpleListView.qml | 17 + mobile/plugins/widgets/desktop/ToolTip.qml | 13 + mobile/plugins/widgets/harmattan/Button.qml | 3 + .../plugins/widgets/harmattan/CMakeLists.txt | 7 + .../plugins/widgets/harmattan/CalcButton.qml | 6 + .../widgets/harmattan/ExpressionInput.qml | 24 + .../widgets/harmattan/KAlgebraMobile.qml | 72 ++ .../widgets/harmattan/KAlgebraPage.qml | 12 + mobile/plugins/widgets/harmattan/Keyboard.qml | 45 ++ mobile/plugins/widgets/harmattan/Label.qml | 6 + .../plugins/widgets/harmattan/RealInput.qml | 18 + .../widgets/harmattan/SimpleListView.qml | 15 + mobile/plugins/widgets/harmattan/ToolTip.qml | 13 + mobile/plugins/widgets/kde/Button.qml | 3 + mobile/plugins/widgets/kde/CMakeLists.txt | 7 + mobile/plugins/widgets/kde/CalcButton.qml | 6 + .../plugins/widgets/kde/ConsoleDelegate.qml | 28 + .../plugins/widgets/kde/ExpressionInput.qml | 23 + mobile/plugins/widgets/kde/KAlgebraMobile.qml | 133 ++++ mobile/plugins/widgets/kde/KAlgebraPage.qml | 18 + mobile/plugins/widgets/kde/Keyboard.qml | 45 ++ mobile/plugins/widgets/kde/Label.qml | 6 + mobile/plugins/widgets/kde/RealInput.qml | 18 + mobile/plugins/widgets/kde/SimpleListView.qml | 26 + mobile/plugins/widgets/kde/ToolTip.qml | 13 + mobile/plugins/widgets/neutral/Button.qml | 31 + mobile/plugins/widgets/neutral/CMakeLists.txt | 7 + mobile/plugins/widgets/neutral/CalcButton.qml | 6 + .../widgets/neutral/ExpressionInput.qml | 16 + .../widgets/neutral/KAlgebraMobile.qml | 61 ++ .../plugins/widgets/neutral/KAlgebraPage.qml | 19 + mobile/plugins/widgets/neutral/Label.qml | 7 + mobile/plugins/widgets/neutral/RealInput.qml | 43 + .../widgets/neutral/ScrollDecorator.qml | 17 + .../widgets/neutral/SimpleListView.qml | 23 + mobile/plugins/widgets/neutral/ToolTip.qml | 14 + mobile/plugins/widgets/qmldir | 9 + mobile/pluginsmodel.cpp | 72 ++ mobile/pluginsmodel.h | 38 + mobile/resources.qrc | 9 + plasmoids/CMakeLists.txt | 5 + plasmoids/calculator/CMakeLists.txt | 11 + plasmoids/calculator/Messages.sh | 2 + plasmoids/calculator/kalgebraplasma.cpp | 162 ++++ plasmoids/calculator/kalgebraplasma.h | 64 ++ plasmoids/calculator/kalgebraplasmoid.desktop | 126 +++ .../graphsplasmoid/contents/ui/config.ui | 28 + plasmoids/graphsplasmoid/contents/ui/main.qml | 68 ++ plasmoids/graphsplasmoid/metadata.desktop | 85 ++ src/CMakeLists.txt | 34 + src/Messages.sh | 2 + src/askname.h | 53 ++ src/consolehtml.cpp | 308 ++++++++ src/consolehtml.h | 127 +++ src/dictionary.cpp | 129 +++ src/dictionary.h | 65 ++ src/functionedit.cpp | 323 ++++++++ src/functionedit.h | 130 +++ src/kalgebra.cpp | 746 ++++++++++++++++++ src/kalgebra.desktop | 175 ++++ src/kalgebra.h | 132 ++++ src/kalgebra.xml | 174 ++++ src/main.cpp | 42 + src/varedit.cpp | 139 ++++ src/varedit.h | 74 ++ src/variablesdelegate.cpp | 41 + src/variablesdelegate.h | 32 + src/viewportwidget.cpp | 75 ++ src/viewportwidget.h | 49 ++ utils/CMakeLists.txt | 2 + utils/main.cpp | 60 ++ 136 files changed, 8819 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 COPYING create mode 100644 COPYING.DOC create mode 100644 COPYING.LIB create mode 100644 Mainpage.dox create mode 100644 TODO create mode 100644 cmake/COPYING-CMAKE-SCRIPTS create mode 100644 cmake/FindAnalitza.cmake create mode 100644 config-kalgebra.h.cmake create mode 100644 doc/CMakeLists.txt create mode 100644 doc/commands.docbook create mode 100644 doc/index.docbook create mode 100644 doc/kalgebra-2dgraph-window.png create mode 100644 doc/kalgebra-3dgraph-window.png create mode 100644 doc/kalgebra-console-window.png create mode 100644 doc/kalgebra-dictionary-window.png create mode 100644 doc/kalgebra-main-window.png create mode 100644 doc/view-fullscreen.png create mode 100644 icons/CMakeLists.txt create mode 100644 icons/hi128-app-kalgebra.png create mode 100644 icons/hi16-app-kalgebra.png create mode 100644 icons/hi32-app-kalgebra.png create mode 100644 icons/hi48-app-kalgebra.png create mode 100644 icons/hi64-app-kalgebra.png create mode 100644 icons/hisc-app-kalgebra.svgz create mode 100644 kalgebra.appdata.xml create mode 100644 kalgebra.kdev4 create mode 100644 mobile/CMakeLists.txt create mode 100644 mobile/declarative/CMakeLists.txt create mode 100644 mobile/declarative/analitzadeclarativeplugin.cpp create mode 100644 mobile/declarative/analitzadeclarativeplugin.h create mode 100644 mobile/declarative/analitzawrapper.cpp create mode 100644 mobile/declarative/analitzawrapper.h create mode 100644 mobile/declarative/graph2dmobile.cpp create mode 100644 mobile/declarative/graph2dmobile.h create mode 100644 mobile/declarative/qml/Graph2D.qml create mode 100644 mobile/declarative/qmldir create mode 100644 mobile/kalgebramobile.cpp create mode 100644 mobile/kalgebramobile.desktop create mode 100644 mobile/kalgebramobile.h create mode 100644 mobile/kalgebramobileharmattan.desktop create mode 100644 mobile/main.cpp create mode 100644 mobile/plugins/About.qml create mode 100644 mobile/plugins/CMakeLists.txt create mode 100644 mobile/plugins/Console.qml create mode 100644 mobile/plugins/Plot2D.qml create mode 100644 mobile/plugins/Tables.qml create mode 100644 mobile/plugins/VariablesView.qml create mode 100644 mobile/plugins/kalgebraabout.desktop create mode 100644 mobile/plugins/kalgebraconsole.desktop create mode 100644 mobile/plugins/kalgebraplot2d.desktop create mode 100644 mobile/plugins/kalgebratables.desktop create mode 100644 mobile/plugins/kalgebravariables.desktop create mode 100644 mobile/plugins/resources/kde-edu-logo.png create mode 100644 mobile/plugins/widgets/CMakeLists.txt create mode 100644 mobile/plugins/widgets/desktop/Button.qml create mode 100644 mobile/plugins/widgets/desktop/CMakeLists.txt create mode 100644 mobile/plugins/widgets/desktop/CalcButton.qml create mode 100644 mobile/plugins/widgets/desktop/ConsoleDelegate.qml create mode 100644 mobile/plugins/widgets/desktop/ExpressionInput.qml create mode 100644 mobile/plugins/widgets/desktop/KAlgebraMobile.qml create mode 100644 mobile/plugins/widgets/desktop/KAlgebraPage.qml create mode 100644 mobile/plugins/widgets/desktop/Keyboard.qml create mode 100644 mobile/plugins/widgets/desktop/Label.qml create mode 100644 mobile/plugins/widgets/desktop/RealInput.qml create mode 100644 mobile/plugins/widgets/desktop/SimpleListView.qml create mode 100644 mobile/plugins/widgets/desktop/ToolTip.qml create mode 100644 mobile/plugins/widgets/harmattan/Button.qml create mode 100644 mobile/plugins/widgets/harmattan/CMakeLists.txt create mode 100644 mobile/plugins/widgets/harmattan/CalcButton.qml create mode 100644 mobile/plugins/widgets/harmattan/ExpressionInput.qml create mode 100644 mobile/plugins/widgets/harmattan/KAlgebraMobile.qml create mode 100644 mobile/plugins/widgets/harmattan/KAlgebraPage.qml create mode 100644 mobile/plugins/widgets/harmattan/Keyboard.qml create mode 100644 mobile/plugins/widgets/harmattan/Label.qml create mode 100644 mobile/plugins/widgets/harmattan/RealInput.qml create mode 100644 mobile/plugins/widgets/harmattan/SimpleListView.qml create mode 100644 mobile/plugins/widgets/harmattan/ToolTip.qml create mode 100644 mobile/plugins/widgets/kde/Button.qml create mode 100644 mobile/plugins/widgets/kde/CMakeLists.txt create mode 100644 mobile/plugins/widgets/kde/CalcButton.qml create mode 100644 mobile/plugins/widgets/kde/ConsoleDelegate.qml create mode 100644 mobile/plugins/widgets/kde/ExpressionInput.qml create mode 100644 mobile/plugins/widgets/kde/KAlgebraMobile.qml create mode 100644 mobile/plugins/widgets/kde/KAlgebraPage.qml create mode 100644 mobile/plugins/widgets/kde/Keyboard.qml create mode 100644 mobile/plugins/widgets/kde/Label.qml create mode 100644 mobile/plugins/widgets/kde/RealInput.qml create mode 100644 mobile/plugins/widgets/kde/SimpleListView.qml create mode 100644 mobile/plugins/widgets/kde/ToolTip.qml create mode 100644 mobile/plugins/widgets/neutral/Button.qml create mode 100644 mobile/plugins/widgets/neutral/CMakeLists.txt create mode 100644 mobile/plugins/widgets/neutral/CalcButton.qml create mode 100644 mobile/plugins/widgets/neutral/ExpressionInput.qml create mode 100644 mobile/plugins/widgets/neutral/KAlgebraMobile.qml create mode 100644 mobile/plugins/widgets/neutral/KAlgebraPage.qml create mode 100644 mobile/plugins/widgets/neutral/Label.qml create mode 100644 mobile/plugins/widgets/neutral/RealInput.qml create mode 100644 mobile/plugins/widgets/neutral/ScrollDecorator.qml create mode 100644 mobile/plugins/widgets/neutral/SimpleListView.qml create mode 100644 mobile/plugins/widgets/neutral/ToolTip.qml create mode 100644 mobile/plugins/widgets/qmldir create mode 100644 mobile/pluginsmodel.cpp create mode 100644 mobile/pluginsmodel.h create mode 100644 mobile/resources.qrc create mode 100644 plasmoids/CMakeLists.txt create mode 100644 plasmoids/calculator/CMakeLists.txt create mode 100644 plasmoids/calculator/Messages.sh create mode 100644 plasmoids/calculator/kalgebraplasma.cpp create mode 100644 plasmoids/calculator/kalgebraplasma.h create mode 100644 plasmoids/calculator/kalgebraplasmoid.desktop create mode 100644 plasmoids/graphsplasmoid/contents/ui/config.ui create mode 100644 plasmoids/graphsplasmoid/contents/ui/main.qml create mode 100644 plasmoids/graphsplasmoid/metadata.desktop create mode 100644 src/CMakeLists.txt create mode 100755 src/Messages.sh create mode 100644 src/askname.h create mode 100644 src/consolehtml.cpp create mode 100644 src/consolehtml.h create mode 100644 src/dictionary.cpp create mode 100644 src/dictionary.h create mode 100644 src/functionedit.cpp create mode 100644 src/functionedit.h create mode 100644 src/kalgebra.cpp create mode 100755 src/kalgebra.desktop create mode 100644 src/kalgebra.h create mode 100644 src/kalgebra.xml create mode 100644 src/main.cpp create mode 100644 src/varedit.cpp create mode 100644 src/varedit.h create mode 100644 src/variablesdelegate.cpp create mode 100644 src/variablesdelegate.h create mode 100644 src/viewportwidget.cpp create mode 100644 src/viewportwidget.h create mode 100644 utils/CMakeLists.txt create mode 100644 utils/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a37fdbf --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,46 @@ +project(kalgebra) + +find_package(KDE4 REQUIRED) +include(KDE4Defaults) +set(CMAKE_MODULE_PATH ${kalgebra_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH}) + +find_package(Analitza REQUIRED) + +find_package(Qt4 COMPONENTS QtWebKit REQUIRED) + +include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES} ${LIBKDEEDU_INCLUDE_DIR}/qtmml ${ANALITZA_INCLUDE_DIR}) + +macro_optional_find_package(OpenGL) +macro_bool_to_01(OPENGL_FOUND HAVE_OPENGL) +macro_log_feature(OPENGL_FOUND "OpenGL" "Support for 3D graphs in KAlgebra" "http://mesa3d.sourceforge.net" FALSE "" "") + +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/config-kalgebra.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/src/config-kalgebra.h) + +include_directories(.) +add_definitions (-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS) + +set(MOBILE_BACKEND "kde" CACHE STRING "Backend to install, currently. Check /mobile/plugins/widgets/*") + +if(NOT MOBILE_BACKEND STREQUAL "harmattan") + add_subdirectory(doc) + add_subdirectory(src) + add_subdirectory(plasmoids) +endif(NOT MOBILE_BACKEND STREQUAL "harmattan") +add_subdirectory(icons) +add_subdirectory(utils) + +macro_optional_add_subdirectory(mobile) + +add_custom_target(commandsdoc + ${CMAKE_CURRENT_BINARY_DIR}/utils/docbook_analitzacommands commands.docbook + DEPENDS docbook_analitzacommands + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/doc/ + COMMENT "Generating commands docbook information" +) + +install(FILES kalgebra.appdata.xml DESTINATION ${SHARE_INSTALL_PREFIX}/appdata/) + +if (${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_SOURCE_DIR}) + macro_display_feature_log() +endif (${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_SOURCE_DIR}) + diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + 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 Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/COPYING.DOC b/COPYING.DOC new file mode 100644 index 0000000..4a0fe1c --- /dev/null +++ b/COPYING.DOC @@ -0,0 +1,397 @@ + GNU Free Documentation License + Version 1.2, November 2002 + + + Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + +0. PREAMBLE + +The purpose of this License is to make a manual, textbook, or other +functional and useful document "free" in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, +with or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible +for modifications made by others. + +This License is a kind of "copyleft", which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. + +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. + + +1. APPLICABILITY AND DEFINITIONS + +This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The "Document", below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as "you". You accept the license if you +copy, modify or distribute the work in a way requiring permission +under copyright law. + +A "Modified Version" of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. + +A "Secondary Section" is a named appendix or a front-matter section of +the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall subject +(or to related matters) and contains nothing that could fall directly +within that overall subject. (Thus, if the Document is in part a +textbook of mathematics, a Secondary Section may not explain any +mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. + +The "Invariant Sections" are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. If a +section does not fit the above definition of Secondary then it is not +allowed to be designated as Invariant. The Document may contain zero +Invariant Sections. If the Document does not identify any Invariant +Sections then there are none. + +The "Cover Texts" are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. A Front-Cover Text may +be at most 5 words, and a Back-Cover Text may be at most 25 words. + +A "Transparent" copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, that is suitable for revising the document +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup, or absence of markup, has been arranged to thwart +or discourage subsequent modification by readers is not Transparent. +An image format is not Transparent if used for any substantial amount +of text. A copy that is not "Transparent" is called "Opaque". + +Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, LaTeX input format, SGML +or XML using a publicly available DTD, and standard-conforming simple +HTML, PostScript or PDF designed for human modification. Examples of +transparent image formats include PNG, XCF and JPG. Opaque formats +include proprietary formats that can be read and edited only by +proprietary word processors, SGML or XML for which the DTD and/or +processing tools are not generally available, and the +machine-generated HTML, PostScript or PDF produced by some word +processors for output purposes only. + +The "Title Page" means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, "Title Page" means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. + +A section "Entitled XYZ" means a named subunit of the Document whose +title either is precisely XYZ or contains XYZ in parentheses following +text that translates XYZ in another language. (Here XYZ stands for a +specific section name mentioned below, such as "Acknowledgements", +"Dedications", "Endorsements", or "History".) To "Preserve the Title" +of such a section when you modify the Document means that it remains a +section "Entitled XYZ" according to this definition. + +The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this +License, but only as regards disclaiming warranties: any other +implication that these Warranty Disclaimers may have is void and has +no effect on the meaning of this License. + + +2. VERBATIM COPYING + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. + + +3. COPYING IN QUANTITY + +If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a computer-network location from which the general network-using +public has access to download using public-standard network protocols +a complete Transparent copy of the Document, free of added material. +If you use the latter option, you must take reasonably prudent steps, +when you begin distribution of Opaque copies in quantity, to ensure +that this Transparent copy will remain thus accessible at the stated +location until at least one year after the last time you distribute an +Opaque copy (directly or through your agents or retailers) of that +edition to the public. + +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to give +them a chance to provide you with an updated version of the Document. + + +4. MODIFICATIONS + +You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: + +A. Use in the Title Page (and on the covers, if any) a title distinct + from that of the Document, and from those of previous versions + (which should, if there were any, be listed in the History section + of the Document). You may use the same title as a previous version + if the original publisher of that version gives permission. +B. List on the Title Page, as authors, one or more persons or entities + responsible for authorship of the modifications in the Modified + Version, together with at least five of the principal authors of the + Document (all of its principal authors, if it has fewer than five), + unless they release you from this requirement. +C. State on the Title page the name of the publisher of the + Modified Version, as the publisher. +D. Preserve all the copyright notices of the Document. +E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. +F. Include, immediately after the copyright notices, a license notice + giving the public permission to use the Modified Version under the + terms of this License, in the form shown in the Addendum below. +G. Preserve in that license notice the full lists of Invariant Sections + and required Cover Texts given in the Document's license notice. +H. Include an unaltered copy of this License. +I. Preserve the section Entitled "History", Preserve its Title, and add + to it an item stating at least the title, year, new authors, and + publisher of the Modified Version as given on the Title Page. If + there is no section Entitled "History" in the Document, create one + stating the title, year, authors, and publisher of the Document as + given on its Title Page, then add an item describing the Modified + Version as stated in the previous sentence. +J. Preserve the network location, if any, given in the Document for + public access to a Transparent copy of the Document, and likewise + the network locations given in the Document for previous versions + it was based on. These may be placed in the "History" section. + You may omit a network location for a work that was published at + least four years before the Document itself, or if the original + publisher of the version it refers to gives permission. +K. For any section Entitled "Acknowledgements" or "Dedications", + Preserve the Title of the section, and preserve in the section all + the substance and tone of each of the contributor acknowledgements + and/or dedications given therein. +L. Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers + or the equivalent are not considered part of the section titles. +M. Delete any section Entitled "Endorsements". Such a section + may not be included in the Modified Version. +N. Do not retitle any existing section to be Entitled "Endorsements" + or to conflict in title with any Invariant Section. +O. Preserve any Warranty Disclaimers. + +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. + +You may add a section Entitled "Endorsements", provided it contains +nothing but endorsements of your Modified Version by various +parties--for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. + + +5. COMBINING DOCUMENTS + +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice, and that you preserve all their Warranty Disclaimers. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. + +In the combination, you must combine any sections Entitled "History" +in the various original documents, forming one section Entitled +"History"; likewise combine any sections Entitled "Acknowledgements", +and any sections Entitled "Dedications". You must delete all sections +Entitled "Endorsements". + + +6. COLLECTIONS OF DOCUMENTS + +You may make a collection consisting of the Document and other documents +released under this License, and replace the individual copies of this +License in the various documents with a single copy that is included in +the collection, provided that you follow the rules of this License for +verbatim copying of each of the documents in all other respects. + +You may extract a single document from such a collection, and distribute +it individually under this License, provided you insert a copy of this +License into the extracted document, and follow this License in all +other respects regarding verbatim copying of that document. + + +7. AGGREGATION WITH INDEPENDENT WORKS + +A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, is called an "aggregate" if the copyright +resulting from the compilation is not used to limit the legal rights +of the compilation's users beyond what the individual works permit. +When the Document is included in an aggregate, this License does not +apply to the other works in the aggregate which are not themselves +derivative works of the Document. + +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on +covers that bracket the Document within the aggregate, or the +electronic equivalent of covers if the Document is in electronic form. +Otherwise they must appear on printed covers that bracket the whole +aggregate. + + +8. TRANSLATION + +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between +the translation and the original version of this License or a notice +or disclaimer, the original version will prevail. + +If a section in the Document is Entitled "Acknowledgements", +"Dedications", or "History", the requirement (section 4) to Preserve +its Title (section 1) will typically require changing the actual +title. + + +9. TERMINATION + +You may not copy, modify, sublicense, or distribute the Document except +as expressly provided for under this License. Any other attempt to +copy, modify, sublicense or distribute the Document is void, and will +automatically terminate your rights under this License. However, +parties who have received copies, or rights, from you under this +License will not have their licenses terminated so long as such +parties remain in full compliance. + + +10. FUTURE REVISIONS OF THIS LICENSE + +The Free Software Foundation may publish new, revised versions +of the GNU Free Documentation License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. See +http://www.gnu.org/copyleft/. + +Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License "or any later version" applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. + + +ADDENDUM: How to use this License for your documents + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: + + Copyright (c) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.2 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + A copy of the license is included in the section entitled "GNU + Free Documentation License". + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the "with...Texts." line with this: + + with the Invariant Sections being LIST THEIR TITLES, with the + Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. + +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. diff --git a/COPYING.LIB b/COPYING.LIB new file mode 100644 index 0000000..5bc8fb2 --- /dev/null +++ b/COPYING.LIB @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 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. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, 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 library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, 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 companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/Mainpage.dox b/Mainpage.dox new file mode 100644 index 0000000..0322cd8 --- /dev/null +++ b/Mainpage.dox @@ -0,0 +1,5 @@ +/** @mainpage KAlgebra + +Here you will find the API documentation both for KAlgebra's Analitza library and KAlgebra code. + +*/ diff --git a/TODO b/TODO new file mode 100644 index 0000000..1fa5c2c --- /dev/null +++ b/TODO @@ -0,0 +1,17 @@ + +Analitza: +- Partial derivatives +- Simplification for x^3*3/x-> 3*x^2 + +Expression: +- Copy on write for m_tree + +2D: +- Shared functions Console <-> 2D +- Sort 2D functions +- Moving on small viewport step is too large. +- Review keyBindings for zooming out. + +Doc: +- Document about piecewise +- Document about anything else diff --git a/cmake/COPYING-CMAKE-SCRIPTS b/cmake/COPYING-CMAKE-SCRIPTS new file mode 100644 index 0000000..4b41776 --- /dev/null +++ b/cmake/COPYING-CMAKE-SCRIPTS @@ -0,0 +1,22 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/cmake/FindAnalitza.cmake b/cmake/FindAnalitza.cmake new file mode 100644 index 0000000..49daf95 --- /dev/null +++ b/cmake/FindAnalitza.cmake @@ -0,0 +1,28 @@ +# Find libanalitza +# Once done this will define +# +# ANALITZA_FOUND - system has Analitza Library +# ANALITZA_INCLUDES - the Analitza include directory +# ANALITZA_LIBS - link these to use Analitza +# ANALITZA_VERSION - the version of the Analitza Library + +# Copyright (c) 2011, Aleix Pol Gonzalez +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +find_library(ANALITZA_LIBRARY NAMES analitza HINTS ${KDE4_LIB_INSTALL_DIR} ${QT_LIBRARY_DIR}) +find_library(ANALITZAGUI_LIBRARY NAMES analitzagui HINTS ${KDE4_LIB_INSTALL_DIR} ${QT_LIBRARY_DIR}) +find_library(ANALITZAPLOT_LIBRARY NAMES analitzaplot HINTS ${KDE4_LIB_INSTALL_DIR} ${QT_LIBRARY_DIR}) + +find_path(ANALITZA_INCLUDE_DIR NAMES analitza/analitzaexport.h HINTS ${KDE4_INCLUDE_INSTALL_DIR} ${QT_INCLUDE_DIR} ${INCLUDE_INSTALL_DIR}) + +if(ANALITZA_INCLUDE_DIR AND ANALITZA_LIBRARY) + set(ANALITZA_LIBS ${analitza_LIB_DEPENDS} ${ANALITZA_LIBRARY} ${ANALITZAGUI_LIBRARY}) + set(ANALITZA_INCLUDES ${ANALITZA_INCLUDE_DIR}/KDE ${ANALITZA_INCLUDE_DIR}) +endif(ANALITZA_INCLUDE_DIR AND ANALITZA_LIBRARY) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Analitza DEFAULT_MSG ANALITZA_INCLUDE_DIR ANALITZA_LIBRARY) + +mark_as_advanced(ANALITZA_INCLUDE_DIR ANALITZA_LIBRARY ANALITZAPLOT_LIBRARY ANALITZAGUI_LIBRARY) diff --git a/config-kalgebra.h.cmake b/config-kalgebra.h.cmake new file mode 100644 index 0000000..d3f2b49 --- /dev/null +++ b/config-kalgebra.h.cmake @@ -0,0 +1 @@ +#cmakedefine HAVE_OPENGL 1 diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt new file mode 100644 index 0000000..e7b92a4 --- /dev/null +++ b/doc/CMakeLists.txt @@ -0,0 +1,4 @@ +########### install files ############### +# + +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kalgebra) diff --git a/doc/commands.docbook b/doc/commands.docbook new file mode 100644 index 0000000..a4b3747 --- /dev/null +++ b/doc/commands.docbook @@ -0,0 +1,405 @@ + +Commands supported by KAlgebra + plus + Name: plus + Description: Addition + Parameters: plus(... parameters, ...) + Example: x->x+2 + + times + Name: times + Description: Multiplication + Parameters: times(... parameters, ...) + Example: x->x*2 + + minus + Name: minus + Description: Subtraction. Will remove all values from the first one. + Parameters: minus(... parameters, ...) + Example: x->x-2 + + divide + Name: divide + Description: Division + Parameters: divide(par1, par2) + Example: x->x/2 + + quotient + Name: quotient + Description: Quotient + Parameters: quotient(par1, par2) + Example: x->quotient(x, 2) + + power + Name: power + Description: Power + Parameters: power(par1, par2) + Example: x->x^2 + + root + Name: root + Description: Root + Parameters: root(par1, par2) + Example: x->root(x, 2) + + factorial + Name: factorial + Description: Factorial. factorial(n)=n! + Parameters: factorial(par1) + Example: x->factorial(x) + + and + Name: and + Description: Boolean and + Parameters: and(... parameters, ...) + Example: x->piecewise { and(x>-2, x<2) ? 1, ? 0 } + + or + Name: or + Description: Boolean or + Parameters: or(... parameters, ...) + Example: x->piecewise { or(x>2, x>-2) ? 1, ? 0 } + + xor + Name: xor + Description: Boolean xor + Parameters: xor(... parameters, ...) + Example: x->piecewise { xor(x>0, x<3) ? 1, ? 0 } + + not + Name: not + Description: Boolean not + Parameters: not(par1) + Example: x->piecewise { not(x>0) ? 1, ? 0 } + + gcd + Name: gcd + Description: Greatest common divisor + Parameters: gcd(... parameters, ...) + Example: x->gcd(x, 3) + + lcm + Name: lcm + Description: Least common multiple + Parameters: lcm(... parameters, ...) + Example: x->lcm(x, 4) + + rem + Name: rem + Description: Remainder + Parameters: rem(par1, par2) + Example: x->rem(x, 5) + + factorof + Name: factorof + Description: The factor of + Parameters: factorof(par1, par2) + Example: x->factorof(x, 3) + + max + Name: max + Description: Maximum + Parameters: max(... parameters, ...) + Example: x->max(x, 4) + + min + Name: min + Description: Minimum + Parameters: min(... parameters, ...) + Example: x->min(x, 4) + + lt + Name: lt + Description: Less than. lt(a,b)=a<b + Parameters: lt(par1, par2) + Example: x->piecewise { x<4 ? 1, ? 0 } + + gt + Name: gt + Description: Greater than. gt(a,b)=a>b + Parameters: gt(par1, par2) + Example: x->piecewise { x>4 ? 1, ? 0 } + + eq + Name: eq + Description: Equal. eq(a,b) = a=b + Parameters: eq(par1, par2) + Example: x->piecewise { x=4 ? 1, ? 0 } + + neq + Name: neq + Description: Not equal. neq(a,b)=a≠b + Parameters: neq(par1, par2) + Example: x->piecewise { x!=4 ? 1, ? 0 } + + leq + Name: leq + Description: Less or equal. leq(a,b)=a≤b + Parameters: leq(par1, par2) + Example: x->piecewise { x<=4 ? 1, ? 0 } + + geq + Name: geq + Description: Greater or equal. geq(a,b)=a≥b + Parameters: geq(par1, par2) + Example: x->piecewise { x>=4 ? 1, ? 0 } + + implies + Name: implies + Description: Boolean implication + Parameters: implies(par1, par2) + Example: x->piecewise { implies(x<0, x<3) ? 1, ? 0 } + + approx + Name: approx + Description: Approximation. approx(a)=a±n + Parameters: approx(par1, par2) + Example: x->piecewise { approx(x, 4) ? 1, ? 0 } + + abs + Name: abs + Description: Absolute value. abs(n)=|n| + Parameters: abs(par1) + Example: x->abs(x) + + floor + Name: floor + Description: Floor value. floor(n)=⌊n⌋ + Parameters: floor(par1) + Example: x->floor(x) + + ceiling + Name: ceiling + Description: Ceil value. ceil(n)=⌈n⌉ + Parameters: ceiling(par1) + Example: x->ceiling(x) + + sin + Name: sin + Description: Function to calculate the sine of a given angle + Parameters: sin(par1) + Example: x->sin(x) + + cos + Name: cos + Description: Function to calculate the cosine of a given angle + Parameters: cos(par1) + Example: x->cos(x) + + tan + Name: tan + Description: Function to calculate the tangent of a given angle + Parameters: tan(par1) + Example: x->tan(x) + + sec + Name: sec + Description: Secant + Parameters: sec(par1) + Example: x->sec(x) + + csc + Name: csc + Description: Cosecant + Parameters: csc(par1) + Example: x->csc(x) + + cot + Name: cot + Description: Cotangent + Parameters: cot(par1) + Example: x->cot(x) + + sinh + Name: sinh + Description: Hyperbolic sine + Parameters: sinh(par1) + Example: x->sinh(x) + + cosh + Name: cosh + Description: Hyperbolic cosine + Parameters: cosh(par1) + Example: x->cosh(x) + + tanh + Name: tanh + Description: Hyperbolic tangent + Parameters: tanh(par1) + Example: x->tanh(x) + + sech + Name: sech + Description: Hyperbolic secant + Parameters: sech(par1) + Example: x->sech(x) + + csch + Name: csch + Description: Hyperbolic cosecant + Parameters: csch(par1) + Example: x->csch(x) + + coth + Name: coth + Description: Hyperbolic cotangent + Parameters: coth(par1) + Example: x->coth(x) + + arcsin + Name: arcsin + Description: Arc sine + Parameters: arcsin(par1) + Example: x->arcsin(x) + + arccos + Name: arccos + Description: Arc cosine + Parameters: arccos(par1) + Example: x->arccos(x) + + arctan + Name: arctan + Description: Arc tangent + Parameters: arctan(par1) + Example: x->arctan(x) + + arccot + Name: arccot + Description: Arc cotangent + Parameters: arccot(par1) + Example: x->arccot(x) + + arccosh + Name: arccosh + Description: Hyperbolic arc cosine + Parameters: arccosh(par1) + Example: x->arccosh(x) + + arccsc + Name: arccsc + Description: Arc cosecant + Parameters: arccsc(par1) + Example: x->arccsc(x) + + arccsch + Name: arccsch + Description: Hyperbolic arc cosecant + Parameters: arccsch(par1) + Example: x->arccsch(x) + + arcsec + Name: arcsec + Description: Arc secant + Parameters: arcsec(par1) + Example: x->arcsec(x) + + arcsech + Name: arcsech + Description: Hyperbolic arc secant + Parameters: arcsech(par1) + Example: x->arcsech(x) + + arcsinh + Name: arcsinh + Description: Hyperbolic arc sine + Parameters: arcsinh(par1) + Example: x->arcsinh(x) + + arctanh + Name: arctanh + Description: Hyperbolic arc tangent + Parameters: arctanh(par1) + Example: x->arctanh(x) + + exp + Name: exp + Description: Exponent (e^x) + Parameters: exp(par1) + Example: x->exp(x) + + ln + Name: ln + Description: Base-e logarithm + Parameters: ln(par1) + Example: x->ln(x) + + log + Name: log + Description: Base-10 logarithm + Parameters: log(par1) + Example: x->log(x) + + sum + Name: sum + Description: Summatory + Parameters: sum(par1 : var=from..to) + Example: x->x*sum(t*t:t=0..3) + + product + Name: product + Description: Productory + Parameters: product(par1 : var=from..to) + Example: x->product(t+t:t=1..3) + + diff + Name: diff + Description: Differentiation + Parameters: diff(par1 : var) + Example: x->(diff(x^2:x))(x) + + card + Name: card + Description: Cardinal + Parameters: card(par1) + Example: x->card(vector { x, 1, 2 }) + + scalarproduct + Name: scalarproduct + Description: Scalar product + Parameters: scalarproduct(... parameters, ...) + Example: x->scalarproduct(vector { 0, x }, vector { x, 0 })[1] + + selector + Name: selector + Description: Select the par1-th element of par2 list or vector + Parameters: selector(par1, par2) + Example: x->scalarproduct(vector { 0, x }, vector { x, 0 })[1] + + union + Name: union + Description: Joins several items of the same type + Parameters: union(... parameters, ...) + Example: x->union(list { 1, 2, 3 }, list { 4, 5, 6 })[rem(floor(x), 5)+3] + + forall + Name: forall + Description: For all + Parameters: forall(par1 : var) + Example: x->piecewise { forall(t:t@list { true, false, false }) ? 1, ? 0 } + + exists + Name: exists + Description: Exists + Parameters: exists(par1 : var) + Example: x->piecewise { exists(t:t@list { true, false, false }) ? 1, ? 0 } + + map + Name: map + Description: Applies a function to every element in a list + Parameters: map(par1, par2) + Example: x->map(x->x+x, list { 1, 2, 3, 4, 5, 6 })[rem(floor(x), 5)+3] + + filter + Name: filter + Description: Removes all elements that don't fit a condition + Parameters: filter(par1, par2) + Example: x->filter(u->rem(u, 2)=0, list { 2, 4, 3, 4, 8, 6 })[rem(floor(x), 5)+3] + + transpose + Name: transpose + Description: Transpose + Parameters: transpose(par1) + Example: x->transpose(matrix { matrixrow { 1, 2, 3, 4, 5, 6 } })[rem(floor(x), 5)+3][1] + + diff --git a/doc/index.docbook b/doc/index.docbook new file mode 100644 index 0000000..69e3ae0 --- /dev/null +++ b/doc/index.docbook @@ -0,0 +1,529 @@ + + + + + + + + +]> + + + + +The &kalgebra; Handbook + + + +Aleix +Pol + +
&Aleix.Pol.mail;
+
+
+ +
+ + +2007 +&Aleix.Pol; + + +&FDLNotice; + + +2013-06-27 +0.11 (&kde; 4.11) + + + +&kalgebra; is an application that can replace your graphing calculator. +It has numerical, logical, symbolic, and analysis features that let you calculate +mathematical expressions on the console and graphically plot the results +in 2D or 3D. &kalgebra; is rooted in the Mathematical Markup Language +(MathML); however, one does not need to know MathML to use &kalgebra;. + + + + +KDE +kdeedu +graph +mathematics +2D +3D +mathML + + +
+ + +Introduction + + +&kalgebra; has numerous features that allow the user to perform all sorts +of mathematical operations and show graphically. At one time, this +program was MathML oriented. Now it can be used by anyone with a little +mathematical knowledge to solve simple and advanced problems alike. + + + +It includes such features as: + + + + + +A user console for quick and easy evaluation of math +functions. + + +Scripting capability for advanced series of calculations + + +Language capabilities including function definition and syntax autocompletion. + + +Calculus functions including symbolic differentiation, vector calculus, +and list manipulation. + + +Function plotting with live cursor for graphical root finding and other +types of analysis. + + +3D plotting for useful visualization of 3D functions. + + +A built-in operator dictionary for quick reference to the many available +functions. + + + + +Below is a screenshot of the &kalgebra; application in action: + + + +Here's a screenshot of &kalgebra; main window + + + + + + &kalgebra; main window + + + + + +When the user begins a &kalgebra; session, they are presented with a +single window consisting of a Console tab, +a 2D Graph tab, +a 3D Graph tab and a +Dictionary tab. Within each tab, you will find an +input field to enter your functions or calculations, and a display field +which shows the results. + + +At any time the user may manage their session with the main menu +Session options: + + + + + +&Ctrl; +N +SessionNew + +Opens a new &kalgebra; window. + + + + +&Ctrl;&Shift; +F +SessionFull Screen Mode + +Toogle full screen mode for &kalgebra; window. The full +screen mode can also be switched on and off using + + button at the top right part of +&kalgebra; window. + + + + +&Ctrl; +Q +SessionQuit + +Shuts the program down. + + + + + + + +Syntax + +&kalgebra; uses an intuitive algebraic syntax for entering user functions, +similar to that used on most modern graphing calculators. This section +lists the fundamental built-in operators available in &kalgebra;. The +author of &kalgebra; modeled this syntax after +Maxima and + maple for users +that may be familiar with these programs. + + + +For users that are interested in the inner workings of &kalgebra;, user +entered expressions are converted to MathML on the backend. A rudimentary +understanding of the capabilities supported by MathML will go a long way +toward revealing the inner capabilities of &kalgebra;. + + +Here is a list of the available operators we have by now: + ++ - * / : Addition, subtraction, multiplication and +division. +^, **: Power, you can use them both. Also it is possible to use +the unicode ² characters. Powers are one way to make roots too, you can do it +like: a**(1/b) +-> : lambda. It is the way to specify one or more free +variables that will be bound in a function. For example, in the expression, +length:=(x,y)->(x*x+y*y)^0.5, the lambda operator is used to denote +that x and y will be bound when the length function is used. + +x=a..b : This is used when we need to delimit a range +(bounded variable+uplimit+downlimit). This means that x goes from a to b. +() : It is used to specify a higher priority. +abc(params) : Functions. When the parser finds a function, it checks +if abc is an operator. If it is, it will be treated as an operator, if it is +not, it will be treated as a user function. +:= : Definition. It is used to define a variable value. You can +do things like x:=3, x:=y being y defined or not or perimeter:=r->2*pi*r. + +? : Piecewise condition definition. Piecewise is the way we can define +conditional operations in &kalgebra;. Put another way, this is a way of +specifying an if, elseif, else condition. If we introduce the condition before the '?' it will +use this condition only if it is true, if it finds a '?' without any condition, it will +enter in the last instance. +Example: piecewise { x=0 ? 0, x=1 ? x+1, ? x**2 } + +{ } : MathML container. It can be used to define a container. Mainly +useful for working with piecewise. + += > >= < <= : Value comparators for equal, +greater, greater or equal, less and less or equal respectively + + +Now you could ask me, why should the user mind about MathML? That’s easy. +With this, we can operate with functions like cos(), sin(), any other +trigonometrical functions, sum() or product(). It does not matter what kind it is. +We can use plus(), times() and everything which has its operator. Boolean +functions are implemented as well, so we can do something like or(1,0,0,0,0). + + + + +Using the Console +&kalgebra;'s console is useful as a calculator on steroids. The +user may enter expressions for evaluation in Calculate +or Evaluate mode, depending on the Console +menu selection. + + +In evaluation mode &kalgebra; simplifies the expression even if it sees an undefined variable. +When in calculation mode &kalgebra;, calculates everything and if it finds an undefined +variable shows an error. + + +In addition to displaying the user entered equations and results in the +console display, all variables that are declared are displayed in a +persistent frame to the right. By double clicking on a variable you will see a +dialog that lets you change their values (just a way to trick the log). + + + +The "ans" variable is special, every time you enter an expression, the +"ans" variable value will be changed to the last result. + + +The following are example functions that can be entered in +the input field of the console window: + +sin(pi) +k:=33 +sum(k*x : x=0..10) +f:=p->p*k +f(pi) + + + +The following shows a screenshot of the console window after entering +the above example expressions: + + +Screenshot of &kalgebra; console window with example expressions + + + + + + &kalgebra; console window + + + + + +A user can control the execution of a series of calculations +using the Console menu options: + + + + + +&Ctrl; +L +ConsoleLoad Script + +Executes the instructions in a file sequentially. +Useful if you want to define some libraries or resume some previous work. + + + + +&Ctrl; +G +ConsoleSave Script + +Saves the instructions you have typed since the session began to be able to reuse. Generates text files so it should be easy to fix +using any text editor, like Kate. + + + + +&Ctrl; +S +ConsoleExport Log + +Saves the log with all results into an &HTML; file to be able to print or publish. + + + + + + + +2D Graphs +To add a new 2D graph on &kalgebra;, select the 2D +Graph tab and click the Add tab to add +a new function. Your focus will go to an input text box where you can +type your function. + + +Syntax +If you want to use a typical f(x) function it is not necessary to specify +it, but if you want a f(y) or a polar function, you will have to add y-> and q-> +as the bounded variables. + +Examples: + +sin(x) +x² +y->sin(y) +q->3*sin(7*q) +t->vector{sin t, t**2} + +If you have entered the function click on the OK button to display the graph in the main window. + + + + +Features +You can set several graphs on the same view. Just use the Add button when +you are in List mode. You can set each graph its own color. + +The view can be zoomed and moved with the mouse. Using the wheel +you can zoom in and out. You can also select an area with the left button +of the mouse and this area will be zoomed in. Move the view with the arrow keys. + + + The viewport of 2D graphs can be explicitly defined using the Viewport tab on a 2D Graph tab. + + +In the List tab, you can open an Editing tab to edit or remove a function with double-click and check or uncheck the check box next to the function name to show or hide it. +In the 2D Graph menu you find these options: + +Show or hide the grid +Keep the aspect ratio while zooming +Zoom in (&Ctrl; ++) and zoom out (&Ctrl; +-) +Save (&Ctrl; +S) the graph as image file +Reset the view to the original zoom +Select a resolution for the graphs + + + + Below is a screenshot of a user who's cursor is at the rightmost root + of the function, sin(1/x). The user who graphed it used very fine + resolution to make this graph (as it oscillates at higher and higher + frequency near the origin). There is also a live cursor feature + where whenever you move your cursor over a spot, it shows you the x + and y values in the bottom left corner of the screen. A live "tangent + line" is plotted on the function at the live cursor location. + + + +Here's a screenshot of &kalgebra; 2D graph window + + + + + + &kalgebra; 2D graph window + + + + + + + + + + +3D Graphs + +To draw a 3D Graph with &kalgebra; select the 3D Graph tab +and you will see an input field at the bottom where you will type your function. +Z cannot be defined yet. For the moment &kalgebra; only supports +3D graphs explicitly dependent only on the x and y, such as (x,y)->x*y, +where z=x*y. + + +Examples: + +(x,y)->sin(x)*sin(y) +(x,y)->x/y + + +The view can be zoomed and moved with the mouse. Using the wheel +you can zoom in and out. Hold the &LMB; and move the mouse to rotate the graph. + + The left and right arrow keys rotate the graph around the z axis, the up and down arrow keys rotate around the horizontal axis of the view. Press W to zoom in the plot and S to zoom it out. + +In the 3D Graph menu you find these options: + + +Save (&Ctrl; +S) the graph as image file +Reset the view to the original zoom in the 3D graph menu +You can draw the graphs with dots, lines or solid styles in the 3D graph menu + + + +Below is a screenshot of the so-called "sombrero" function. This particular +graph is shown using the 3D graph line-style. + + + +Here's a screenshot of &kalgebra; 3D graph window + + + + + + &kalgebra; 3D graph window + + + + + + + +Dictionary + + + The dictionary provides a list of all &kalgebra; built in functions. It can be +used to find the definition of an operation and its input parameters. It's a useful +place to go to find the many capabilities of &kalgebra;. + + + + Below is a screenshot of the &kalgebra; dictionary lookup of the cosine function. + + + +Here's a screenshot of the &kalgebra; dictionary window + + + + + + &kalgebra; dictionary window + + + + + + + +&commands; + + +Credits and License + + +Program copyright 2005-2009 &Aleix.Pol; + + + + +Documentation copyright 2007 &Aleix.Pol; &Aleix.Pol.mail; + + + +&underFDL; +&underGPL; + + + + + +Installation + + +How to obtain &kalgebra; + +&install.intro.documentation; + + + + +Compilation and installation + +&install.compile.documentation; + + + + +&documentation.index; +
+ + diff --git a/doc/kalgebra-2dgraph-window.png b/doc/kalgebra-2dgraph-window.png new file mode 100644 index 0000000000000000000000000000000000000000..2853005f0550128669ef87940fee43beb70f954b GIT binary patch literal 56109 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°>0jl1<(JEh?in5d;R?q=xU$jt4NUaK zVEv@mQ4%**Z*1TNtN=7F*hdzyO&m}=W@Se7VKa|zvAqk?0=j|e*dCKS!z7v4W1igPjvx3B@fva{>uFhU`{faQSw`d@4@{xSFC;kkT$(J zzzAzdpXT!THwRy(l^$#%U$%){%v1!lB3Wy>*^~r0E?>=GO7IjOY8ZUS8Iq8N4b*oa z%^}9{Y8g0*8`F59ahB>8DJu1|)@9><_S(Zxf7K08w$fNX3@)>e33i3gRp^R2yP?~)LH9cd8QB}EE={WE0y>pjL&D(niN3!Zv~$DLVSOIhPWUuh^tcF zur4l==gO}6hz5i_LJbXgEF;_+@S2$mZJY%M^IyX>l5S;j!p$^_zpKhe-1HU%QX&eC zJJ38! z_h>_8nFeT`$U>}k!Ejnh^~@?X4PpeG{nrC$UnO=*|J@$0={4C2lm9#|4dR^+Am*qa zT>#_Ry3Y?F=<~0i2l@iq2nVHnZ`LT0_L_*SLPW|C(WV{*29VR(F`qh*CzNnIrbJrI z(hMjJ?NJ#Auu9W`DH7w|LQXa(TSinxT$!*eNKr@ve-xH@uv3^7seuNc$IG$)wA&N1 z5VUhD<~4mVlrHC@lr*r3`k50{q{69yTSO~qmpdLBlY^>J5R~W)ofCZs;nud$l7kRw zNOA{l!Q)^qAikAD@mc>?A@iUltaujaTPgQfICnS;_+mARh94AwIpHa72-^@u?3}Z=D0n3SABUTWaK8XtU>| zPq5`a^>ox|yCu^`M~qMqNpU+EsW?bZRidz#eVk-NlR{pplelyI-a3ab(_BzFqn`fwjxysM0j@uFh6OQLreAWHm%hX1rNc4US)DO{P*Kvvg5n)j&aZnH9&LkR z6x}fKZx029?c;@SQHqT4hZ^%z>CkeHo?^0v2!$x;alNAq!ARBA+vZhFT#l)|NkMIs zavnRC`1WU2mVv}gfH?o{wA| z+C77i5gC991}J;cIZ=cN`PJ0B8u|%$EeV3XkQ~;08nK{+8#C@)vw|#5-tv9e;)?to znYPNtIs$wY|LI~nA~NaAX6r&B zNk})7eQ%vGV~G5tuMol;T=LLKf8X7FIZ8OTp`q5w!Ib#w2N@3_eM-MZA68}_KuUh_ z^f1>?p-jdHB;1GeormUQZG0if>sF&1BLg=n7#bDuAo1<+kq>GP8Ygc|q84tgU)Uf1 z3baHW+D!OJA4aNkzf{Plvgg$O^Hjs2&MNixk2oJN5Lpt`n z=R0vXq~~YI6KP3|;zE5r0ynq4Gw47CSh*M;M+nDz!i+G7HlKeq1gjY+__{Yz{D#iI zZv_qd5ut~c$Ok&06o(y97gI54?B5!Ov9 zfI*Q+MW%XmSBnpm9oKQ*P~{A+eh>`tM6Y>oO~*=F@~IC5;)-Fuc~!M{mfe` zB>cEtu7WaQiOcDjx%Q36@ z66FbGQlxO{2artFgG9Yybaq#H;74k+|VEA?Mzm>wz|#VB1}gW@VG!9zzF=ORZIWXq+39+eLt4tuL{;;E(tl z4XGRVQUX;&7T4}TZZkM{LuttMZ{{pi;#aihjUOMs;s%j~$A#AKu4f!W`S*XUH|KfB z5E2AbApTGVVjUj)u^GIh*~y2439~>oSMvCU-h&V<0aq;tM*wgk7-(2P`bw>J1TBFg zSls&BcAWpx#Fx})j(65V?#7Rsu4pA1KfVkI*8?4l{k^;Es1|{>6k}R>&?m0H+s)uPd7PtyiFjjE0g?R2}1mpce#+JO?QC ztMrwr_f?(qnlN>^BKmY!dVH{OvhulZ@<@6fphRpdX%Gc(k#E@6Ksi5Cd#!~yRs2P< zztjrU=tFpx@8T(P zVppjY1T%^NhY#ksfql?8mNF=XT0aLKJgVID;U4q~!!<|h+aKedm^Qe2<^q-7xWWVF zta`N#oG={|41I*4`mqY}z^6uv9UKB7tTq@<|vpb+^J@RRYA zi9s~*AFLX5s8HC97aQih9uo&{2h8`RzqR{@M+~MRwdM8Zc0{y9!|n>}tA22%W9SbB zbE_H>F69a77DH-N+?1P;mq);PmD7iZD*V&D>wc+k@uNWY3hZGQnV&5)5Kv_Vru-M^ z3kn+QwWMdgJV99poVtgM*<#fxlJ5=k{JaApZ<@L(*Xh-AAATG~tPS5}-ox$;985Kq{g`T$r$S=&P5(b|rpQ7G6xG&o!zZA|1HupB`2*F%<|cEe;M%Q_f<8<@HN@+gb5kpNysX3pjK{GTq1X`NpcB;^1Ax=y(!DvNd^-ZhU|<4)?t%irK1oRn zF=3=7y?jl#1queciVyU_W@P%XNDKqBUCZm$b-hPSNLqci~44Jx8+V zhyWkmla!1XyPP0GG9DwoZ(pf{{y6p=S`;4^V!mOwZ3L9D_7Qx&87%`eG1oA4@}xYd zF)(PqI`;H2b91eFlm*0J*JDTk;jK+5^Ay*N!JfX^oN{zIZ0>y|A=vtF!K9NO z>#k`$uE6WIEwnb=-Xt^Jv!Ii?i&4nAyM~}a_U%j6tV}A}scE@i+plSY^={r6kO!?l z=0()whZU`1{%zsMs_Zt97ATof=I^nXj{VrG4gU^OPO3e0$NM$Olp1^At?^fAlsoBg z2z6|o|LhW0x!$jBRt_kV>d*DI?PI1z4Vu!uSmPIF{^i`3EeMis63S?Snzd;5*-~L? z{n%T(gJ$h)voY+>y9I=^;5-N)pZ9uGw=d{?g-qR94GJII@ zLtp-n)Qzccdb(Xecg!&94fpKEqO;jl;G)8XUDCD=zZreyVCSHq7@$R9D2EW;96pFD zDfl1`4aX@Y^B(GPy}{{l@H)Ns>p-A>xX|7_mXjN4oA26qp3$c}runf4=69&-cJZ z|A;nBHW*Tv!wrfocaZshf9zaUW%o5%0W%+eiJCfE7OH4i?SiTc*6~+$Tf46+2EBb8 zoWiVnfRWm){Qz1LZ*X|20=|&VG5)Fv1f8aW86zD>O<@W#rf)Idr43g;Xtf`wuVm@n zU%_m5VDzy)+0#PUF2Xa!%{G`kY`k1nTAxPer1(3}kmFG%H*oC}o#+gHvVSy`j=;y+^2fLJi~YvWHOz55}ics$ZlIzkVe zjg?@x>f69!`oBu**a0kb*61TDuD+ z-rBsvX!*2!{N2K2YinnojEu&zC4WqhM%8SaGpg&9stN}}{5X2AbfZRT*Wk!uU3P)D z@X13R&jTrthH42M#EKxWcF!%+Uny^>zY}(h1w&SvAcY z`$7y3CRSx7JyZHQyRII-u0@61W6NuK17D9LDVERbX+aA^F_~$1%FDZbv3~xrc=-B{ z;-T8@e-#h2ft_7|(%g2CQWgq7(nq)xhjnP4G$b4TyFH?tV{>YtOciy|vqE14&C`j) znesf)3Vz<=YI;zyQ$FZpR-DD1Hu&ujixjq=Q4$V_1jl<13*vpzJpbFN#6A|BL>~0( z-dpO9DR%^E;@_iDJFm2XIXk!5Cj4Y#dV|9f9pn_0waq8(SLWNz=$Jg58sxB@-ZXO7xd#*Lal=jRs?ee z{wsZ|`rZ8%02nPyaE^fmalBJG@yE&HTTQT$c9@-A)WKxNRgmq&E7%V^6>>VQMD z;OsR7l4c6wd^09TUv)uRe-mgMh#ybENjDCQ!DC=*Uq$7hQ&Oc+enn^l7hfGE#Z^gv zs{+%qB0{k-?da(P4$XR}l^Sh3q_F}J{j(u}t-V=cQ8jx#1TA@fLH`_>9Q*SqHTXJi zbnIez^|1@7iv$7PxqG&8dud!!)=}1-d zZNLYD;x}0llGlfs3i(E(D8pbIsipXm1grrt21Lp%LB)J>>#D-OgPdE=nRCR&ifw9! zq#HUa`B9S6<;2BR~$0|?Tx~f8Ww$aUa#QR3xK)=m{W#$Fy%7w)o>7Jf<@6uJ$iJ69N{bjd zCOM`8A*4kR=s{$@R+1rC@+BL5^Tm`12nM|;NQTI4@W2&Ho6tnYKsg&H_15fx6vi<^1!bvMm3)Mj9dzRbAao7q}=FnDpnjjnT%DRH-9GfL7JG(`4P_O@x(L5`8Hh0*|N|2>6INxb{ItyM9AX?lBM8 zCxPT2`}8f&7m~k_a{|X6tm6E}p7M6o*6J`H4?cD?tbfp(TH&UnFOz=yU$=SBir4cH ztK)Khh9!yfp}|-g|G%vUj*#NsxUV+pRI`hUPX**3}86<(4P!X z_EeqVk)&6_%IPoqcc@j4*281n6Keqg<$dK8pS}Ipi^KFJLn>u zSMFK_E0*Ln{6m1m-Tz5XRG3-;SSUMb_!C5Iw^^`yR_c4-Aj%_09Wt0?CWMpj2@D9` zbCt0s#p2&iS-tlq(PONCk6>`*od^COdg!zBqG4sX<;)@A0M#YIsqffn9ia9nO4{eT8MINIfTTyB7uWQv(d7|2q9JGjynOmOYKaj!V=$a4~0hT`}U7LV(@B#>X zQW=0XjDVK2P(5O-+N}r*eUn}d-D(wjp%el;;ti+7?lX`YhaR=+c7`{#YZR)_`$Yrp zR$}#)0dbMy2kOWcy%SJr`)~}g5yEIk63BW0NES_yuo#hhvP z_xm-4Fb)sWMkZ50fIE2l2DwD(=UU2YM}Orz;+(7G2jK1VPyiZ8{{sxR5Ydqn-@;3r zsR2^bUrOsjXhx+nRXHJ=VT6b(c=J0-QJarp9;>8 z5sV#(0XT}&!^(sEWV(iypVWos3q{?wPdkniUg@|p4oL?exA#zcSk6f^7%>&eisI0j z)sBP+hkVExSu$W5mGobc(VRE#2_0xKJQ79{rw1tk8iRG+YqFJ4-o|!&po>5$eyw}M zkZ0~MWu^N)-~ukf`a^b|&czLn-rPS}FsU{W7Yn#Og>k$A%Hrc+SAO>W;?Z9W`%H#p zZvzlw)QG*jU!30gu?83f7V)sW#u|jGw2tIh`sP$ZsfmZC8QFnSEOX<6n#C)#-$*KL z9>}p7aaLUW>%K%*!&@H4J?%^@Lx=SI!Rzt7{&kV}rHAQrA7WPw%|DJ z%%f)7_xjjRwjlNK570g&9=N8J6}pB_&R_S%g}_DxK`=B;Dp?6|Ey8}ti0hZB+`@%( zL9B)u@vil4-PXUX_7GPc;4O>i7fhTilYsbwK2!dP0lifLd|H94?v4531v^-;g!L`J zrVo6CMCtf+cL{%t@9+<=1cX#ZZ~)}gLZsd|8qV0C3;!i|x0r+Q5iB|1NVwAG`229m zAesYnUnKA*tECqD(yKtw)5ET4SKHG>2UFvbbj4} zc~}@Em-$PNevybS*GR=^xS0Qvw=>ZXZv8jE*#tKJo89sL*x6IH!HJCo*MITj#axj{ zZjRzV$ncrmkI1r;KlxKI)nmZwa<2ljYas(0*b1BYhLRKbdAa@gkG=K#epB*sGqe0n zEq{^u!mgij)cezKYWZ{HyT$LsQ9hR0KiP%m#wSCn0IwuOQ#x*5@0>Ilto0j+|5As( zro0I1+|Yk%ifSlh!^%?&z)j|y-vS(U0&ggsT8JI(J-JpQ5dANitAQ{P*rxPvdW#D~ zScjHHKW3dmCEPy5_wz&t4y8RNP~?7GYb>YHvD*wi)8A`S#1}jm5b^U%;*`ih_xn*I zDiDkjR;AEHU=gSFm#c^&zxp$WhTm}JN8kYTE%a~SGfVM9r9Qc_$MUHPME;ZJ@y060 zw#kJeh$A_VwI0vXJBNW69C*ZQHN-+a$6{>CpE zGP|Y>|4V^_;1m-!Mrl7~hRY3NT=KvkK!W1f!_LS3OS^nU@QK_Oz$=}hYfN??cW+k7 z`0dt{{9-UReZoPvF*Y@VJyiL}rSUTwc40bwOCY}Z!+m0XR<*}$#Dk$>o}WqyaxQ0O z2-cl<^)apl8dLK8A_m~-Y#0n11(;jUc5ZbIoB!G$R!9dyK;;Jm5gVt&;O>u*!(o(< zT4aCy^iLW$P7%-|sKK4HXNHzn;a3;lzPg|P7h|xo%5tz~%iHvYm%m?XKOVSv#Tni* zciv)BvG2G_2=3x}rNe}?!nFd%VdDT-vu%33HUG`&=QDqKJ7c%$BuDty=zneEo7AAm zWzE9hAIN~f#ZAjW;R|m(oZ}BJwSBpa3vwzhL1;t)TH5;+i4Ba-{~ZAVR_o8nd7jQ= zGNi|)%)f^*;9_Die5J@+hx{+E>A` zV6^=_AjOC?H=;`b{Y!VT+3-OK*AdMh4FcU?poq=vvD{S4W0PBP^FcN$<5E{_i2Eb@ z0bc8FpU>I-m3@kzyxcfNN{bMP9s~=wa{|Eex~n=QTc!OA8*z>o>k65~vjtP{b%AIT zo1vUPd0_u`^oSs0fQ%@(wP{0d$v;WmHM#1-z8&AMwQ1(WF$JM;Y>rtELiL~C z9H_;g?&psvwXkK-bZX81aQ9SN2XPw6iM_{wQR`XQguicb`v-3*M!le-=U9&X>rz_z z`;$k$C;t|b0FW4bjFo$TpRcIAZ_5PmWZoJeE%@Cea)yc(KuY*4Q2R|guUYEtTHXIw z=TONGUTe_B>`%?{Z zC8Pr^=JJ{rNEi>l0=dyaUMG}{cH$tCH~}pz*)=4rD0^)Pw)&b{ zNqc)E25d5*Z*!P_MvLf4Xg9T|u!}ekIAfP#99q6r>S(XOw&exvR8aab5p8@aY1P|Q zyN5O%X(^n19&e%CP;d(Sc^dH8E0=B$$>d);!pMjh=?vYWGMO}91V=`fC{j&0eeXW%nVgVYScZe_0Di4zZsi_@HG@C@-g4VOqCEI+@PgZMspGu)JJ~_+)8X zxrLrx^|F$*m&R1JSHngnjdoj8#3y(8lNHXqU}UU3hT}G1(<);hLw!P_Z_w!<+^+I- z-44)LS}~nfFz3^&{I)BLL3VfgPF>+Qx)aye?fm`0MwQ|6Qj(Bgfq$=bQqNx9JwRb4 zps;vpE*#8u(=q=Noq@q!k+E*fQW<7c@9tGi`HqI2>g|bH15HrybQ=LdaK6@3IH#PZ zTow>R5O4@|2-e;lj^*vO@jF|ovvWPMjqa2+-;I#T zo~b2977=kz`BLDU7m-=7nB&h1a!(LJFWsp-+F7c2Q?vgPZA5y&!-2pz*BG9iA`xzk zd#A2(TJWkgyUgkHPp?WpMSb_5S37=h;;rHF(2$2i-tCy?icMc5@Ex0La{kpiG<>dw zn!{SnPB(? z6ICe@4bpwJmm)+-9}_T^Qn+3E;Bp$KeL3}HpvKtMtWRvtmMxDN&R)EDON1&Ybmk)g zVgr5L|B-)N`!**l5yFKuX`eB1>o1-e-KDCCF%TMmCD5(n#lZN+6cU!ziY<#gM+bJ?Kh21IEn0z9*q4q*z!qVz>@lNg{Qa zxX-U7{0WZfXiu80lx%jK|+{q*C zcnZZ!g&ex2c0#M!0_b_Gn@`z7isU&Q+!Lahof(Z)FQ5K&Pn%V+#!1s+De<{f*fO1| zk+C?!&&!gZ!7I%1%00qj10$v*{%JSqTRdb7*v_aH^FNGFqSPOrf%G#tr>wb8oerrP z%pVu+7 zuJJOrZcx;@=jnn?={JSQw3ieOJ;mo+I=GCdsjj=4#-djHLg!@~LJHuz0{Y?SMSI@5 zw!|3ce%`!IZ1K_Vv)9Sg&!N}e2fQw)wKT3?HcX-_>RrwHSV1|H8>t!?6=+h^6gzFX zJ2`wB?yO}LJNvlQOTtI7@aCYupg|G2o$q*&l~BR84>ye-2OUcaUhYpO5lG5D&8|1o zrugl1}DU#@mLJm_3dF*ad(C8wiTk5TEzRUA&I8B^KoX^?;N_ zibuh<_rGrtShVBO(ZK=RcYLU1jR>Q5Wwt-9TFDg$^$+tV|RM*SiN#I_U6kd_p!Bm%Ac5Crk-%+_`y*^x{dW zFso=wJ)Q>g&-yu61tk?@xG7(AiR5R4G`AcrSkEZSKNMb-uBe$!(iRYe7v0{ zCyHj1-7!|5Bhrgc(X4zirezQ0D6IHjNenWEsy&k(T`Cgsdy!=nTN7CGfKrfmr!Bp? z(azqe@}e(QzT zc-da|SOxMdJqvS}4tP1*Hicg-{avz^RgoTR4w)OfRS)kDkBrh`f!E;OXV%qI@8@mV zbcR??0frBE;-5UTM(B1gk=dzcpG6paZRS0z5HsiHSc|mRxA2YpEMMIE?6kYK);A|> z>K-RKMU5{pIHSFAiin)x=7<%~sCJ-(J-!=TTkyTnhkc$+&ekU!tUh!*S=EK7LGCt~ z*FR6wCg5Frf8Mq)S#eC3Ty#p?bm~21?CEV&)v6f1n2k2Gvm=oWBeiF5 zzAQdIhnSP&bZj_xTbmk<(aS|?=G&(e(l}mDRM!_Y7Lp0)o*DF#n_IG$N68 zn%ASfgQzY&llG*3IHfYL?!xf^%5-MLcnJmL6bnbJ4cnOv__KA5-7JP zs#W}Kg**!};C0(YNx>sqTc$@Y&V(!Mks}J5{9rLrVzG0P`PC*;;6zFO8fl6JK%x*l z^!-iiq4HagP8j2v>DWvgDO)s%L*ugm2*N0p@G*Ivz^yyN0X)X2#h z>-c$681?;vtSgFiOLOOT+=KgESA<~i-eitzZwS3K*rrm7@DEm!JZ`ZbPT1~#*Ns*! zQ{C+1_REaxYfX*`Bp2l!Ghn`T zk|0N&D$uM!^Xvk0`ASMq3irySt0jE}yltLvKSo>hoA$S@N;WabC^o?0u)Q=ACzL0m zQi(K!P*dZLU4V?1;wQ`RU4S&zzkIzt9Us`JGB#+>+2ibl7u`tJONG=r z_oC3>Z(lmaVk@YU%bpB6ikzG1?J*I)m{)3LQC-0vT{gaa%r>ZCxNlFS9BQuTKYqL#W_0|z10;u`hkR|kYM*VMC1;gdym|0Mz{%G{(IlrL+&wRq zo<0(9^;NjnjGMQau%le)QeNU>ht6y-1Z~$mim$M8A4wYtl`*nxw=Vpse4@Ul=GLQf zX#tjVq7G)=`qvlqf_5s&M{@d1Qwp6c(Ppil2vde5xhs$Cbp=^=I?Qh>7WZ+EToP$M zms@LIMUhxXUvE1a!5#fR?{i}wyGZHHJH)0{N5w7N>vW)W%J(GPUhX=%w2`pWU!@$I z8;?<5xg}OGd3uDg@P0e&iK6)fQN;M;OW|))E|U?MYUA ze2w}v4AoFI^}Ba?&!5MxruiSKZz}9C21uR^Ut9Y+CksDzfaFz4dbSL4c7>1avz4YO zub#an`8qS3U7c|g68J#o8GFXPP%5sG{Ryh<>=~sisq^89BL0;1ew}d(>ko1T>O04XUz9wG{3ycBLOIKSsrtoYi_vV? zE41BNxUs)Z>vC++o7X}{l&;s#YLgF*N%s?TtTCAAeU;~**9+Pp&~7g@jCE~qUvc)K zWBkalf4-l!z{2?IvRYhEuXAfduWoSi-oi(hRMw2L>%o~uv>WNy9Qz-9VD8Dfz#LLE zf^skyU$H`}XJ4k&7*$+|H?_XMp0Uc*>dwf0?*s9m-Lq=Ej}?*=Ev`06qdYB+PBshN zWCHedM%6tbq1RQ8Uwab|w;nio-EmeSl?R^K{HwtTQksBo-&6-JItZ?%ue(F4x2 z(S2n-cO%4m?FlRrtB-0$XH-` zr+Qd2Xm&lpxIYbDNJ5mE9Zl`Fu+$y}|6X7*mhafm;j|wZc&o%o3hMUu>mw+rc>I;A!~isGC|s7!;OTGQcQLQc$ie+}RL&;~nq z48r&|rcwbL;F)f4s{@cAFDQx2@r%dvrst3}HZCrSZd4UgnvAHF9fQ;K^GqPmx4CDU ziw@e;X}`4UGIK3e5$m(-63`$unh*GzT= z(AHWh=I)Q(c@`h!y@{HLM)iH^ACNuWWJs)6yvrc@H%q$g}SDww?(Bs z;4k^Frr##`E&p;KLC4a?uP5qJuVA$+~j%dDy(HMG)xHF8%Z5`^{MRKy@_qAwazzTyUC@`LKz zv=Eu5VTDu~dn)=U>Eq9yPsbf+jN$#5s%y`{#IjTUS!gvB&)WkZ{el>p%Slu2mm4J5 zrN{=jdQ@*9vb%hg4$|#-9-s*}KH6SY*(}00a{1cbf28Uf{zmM4u?k_wu)=KFnp?v& z3-{utCwUIvrKfzK8corJB1V1PjzDG!+-{tJahSl0{bav&qtnJP{be=uMX%2Wz|lrm zF4=srw6eOsr&=4_9%G_so%(~gI?oY~(5 zU*AE#dFxga`Qc@K>@>Gqw*7F;e%1bTuIWXJ`Ni@W&wbt)drnYobi(TvQ|}gQlW&b@ zWKY-0UUEIICE{CdCdBxVkmO{_w#&w>ryH6eZ*l6(1oqQ-0r>pV1G)2q{z41fu})7K z$`iwnFvY2hM>?&F%nPMWcCndMe2@X9VOuHKMLawP_VkwT+nZbxTFmCD$|4*MF5h3z z2DtQEbn{C@<~!OYc~iP!tDa5)`1pAI(%0N!-T7%NCAJfoxeHVmrPt<=qcYI9pyCF{ z2hRro;^E#I|0QQ?681}8Mp#UJ=u=31@88jG*jK#nq&;?>$zC&M1_(O zJY>6g^Mx|QSyDGfU8P4#$EeN)tw63H4`ZRxdVKSC1EI-r$xGqfcNpjpK`q=AVZFjJ zMV2yU3)gMDyR%0!x+9IYL&dA#C?%J06V^m_Ak8-0WIFi0*Vd&fwUR_%QLd=o%wp(I ziiP#c*B7x%h;j1O-Fr(yNw`Z(f0TGKBKLxC1FE_)ynRR1rakJC*()Ie0ywSxx%zQ0 zRoK?uSHzP_H(ymykp$($%|6Ly_X|Wvj5#MbepjL)Z(QUVGCRDd*|ZvL|&`B>DiIt?|V0KC(`-LY(f?@ebI1R zC{#ZwB!aJx9^Z$;Q{??tozvoUlo2yxen}PgK(Prsj6XqA;NEZvO)43(eW2}1%xHkL zH^yJa>gKcL2)TG995add@HkVwwv#X7MD?vBZ#N9S4usJ4#i%4>T8W0c2njWp3dSD9 zFx)+LrqjgzRf~3PVS`Hj^fUOzo$nMV1gpc6P@DP|I^0}}dA?UC<6%eERn3-t zh_*;ih^oZ)oN9u&9>E;&;QI#=XgW1B;v6A5p9Zx_>K1CE;d1^){@1$FLWX#E=D32+ zsF)b84HgCK(U0r&1#iAz7|hrTD$=TZceP1JQShzy$S5iPxSAt$-0`csxNpqvS^q6G zl~45vt5fF^**Ypa+CmnE>t`w^i;fp@&c}IwB9{~L+a+{?oY1jSSpef{|DP|+4GKoG2FP2{esJDMbymF1z|XQWSB0o_Jtf`<|xl6UX&bS zk^1a;!4S(q#|91?Ig_psU6bL?M<1p|nx%#w*;Ozv90f1?>5(#-WHgAb38}{H}E{-GUqh5^PGik@MYM8An%X?Pr8aJ`jv@m`bD2PkZM_iPj1&o zhRQ4JztPUWl);N1Y%y$%E@-qDH}$ zT95Vhhd{Eyo1NU3Wa$v*ArEr09$YS&pkJA4-Fx6#)$II^b-Ju0jCw;60ww8BqVMqK zV9R3H);(fd@4aG7wz{r(rIaB<>y)sOtE}GDhitC9#g@TPmQpcwrD8rK-w2 z>}k8`=P)-;vzaBv5TpU4!(U7~Lvtm#s+$*{k@>`hWU0CT%A=s!kdwR@nb^KMd|PGuacR_@Y(i{2jBImwVx zOV@n{2RGaLs{=KN-JXqzN!o2+Gg90ye>G(ETq%cdukFdif9J!^U0*~rTKmt^SRbyX zQdIfhszXApyi@=7O%~02nu(eNnk={O-AZ(FfT($23%VA0?di3on0%N-p5QYf-h$o==I@IGQg017@$=KAy&^;Q4Fx5CcMe<}XFn?1aOR}bywBp3xl1eI zhIF4Br9|$Qtvy-mZPhR;krK0?9m!IkKK^k~!~gjmZ3~g)2d?+;jD9n?*S*%Zb?HC^ zT@Sk+b%k_=bwzYVb;WeWbv@~N*7c(6WmjTXatAr`D$31QoeptK#U0}9b%U75kQ5oXxxqAUjXJ_u$nP&98o9niyLP@oFPf*#{ zNLmQ#j&0xY*rLZYXr@w{xONYn3GbLo8}Jv4WUnlEFkAPKaJrL|Q~u*r_c`aGyuu8lfKqW8tF(T-P0Uw=oV&U-jM#p?>S}UWlLx# z?c=SIxtI$c4aMx^)*Eb5`u@u$tL9en@3UAG4q)TTy?;sm7K`&TzD3uYu6JD-U0Gcp zQ1??V+#}Fq?mrgd`=x)(e8RboK|Zx1Ms4+8mPS&#xOs~hCiZcPW+|_*g_>qF`cy@o z{7{*Y&pN6LQ{*n0>!{_()|7BvJ$&ws)>NsJp`~8^lZpM5q&9J34AB^cr|KW`-@Fks-*MyP+Q&k;P>hq&{<^A0&HLtR=iRk@snwdzMNWTC zzsMCGs_m~svFK3a)S%wDVzB+fpXc_ z6D9Va`sx>~CoD1%OFml;{_A6o@^AMi0%biX-%e&8@0XhI=o`~E+FRWn>Fe-U@Yonk zb2svN=*tEk@Q%3qktJNr+EdzUPPMD>St4 zZSFpaLoaXJ?DT7`Y;yXil0G%!Tz%+;>Kxri_HTN6WWVL~`!A@K5;+MLJ|Xb(^mWz@ zy6yyj%k$K_yat-ZrTRU$&VwUVHeKDFG&2v{b zG*KP1r`BaZ`Pj)}EMFL%T@`Kuap}c-!s;(2uJdFZ?~bx;5;MCes*YVU(XzdLZhfW? zZs8pWaeV%$k#zUwE@(%VU2Ih@pN5ob4w+m&J0@-Z6K_ST=t$W9?h) zSk?&n1MTbu)W$R1`!n zY*=kgwT!n_^zC&o^rxBhX|3!G=2@D}rurDF4qb|N0F#!^<7ly*-7_D3 zH&4*efgE7v9eH<%W&I};)?UlcV$)KNRqo~!<(vq{G_$_GhPD3hmJeo8J{-C+JA9=; zP)r($!nQ9}uJh%QFX*ioEw?1=yAybiWFo4X^YSBS8AHIwJrrni9)e^dz)_1c<9McV zN=8n8@a9ChyH^$UV_!FOpQ8hke8p=Iy{7O9@bH9R&DTZDiy7qed7Lofh{R=k=2ahdAfVUlIEtBBkL73E!Wzg|`7(BM{ zGQ@Q=Wudtkl;d`!J{oLb3GT{vym6-qCDF95{JJVR#O+Km`0J}Ae4KV5qrvrR=A zH`YGvCkN~%pBw7hJL~r`#FH(Sy4`Rf1kx;OEa2=-AHMLKy+ynhWKDQ2;VGK%^5Hk8 z7SX4`uZn|rO*=cUKhRhNzX-o;n7&&K{u9uaFa~J5crz*C|NW<53xP56^St-k7_9&v Pg?Cl?hEm>T$ix2w^o8dE literal 0 HcmV?d00001 diff --git a/doc/kalgebra-3dgraph-window.png b/doc/kalgebra-3dgraph-window.png new file mode 100644 index 0000000000000000000000000000000000000000..7fe546c341e93824aeb0921caec4283eb529c6e3 GIT binary patch literal 69348 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 literal 0 HcmV?d00001 diff --git a/doc/kalgebra-console-window.png b/doc/kalgebra-console-window.png new file mode 100644 index 0000000000000000000000000000000000000000..740cc8b73b7c8add7b9ac1211ecf98657a0b0a17 GIT binary patch literal 16260 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 NO?5rB1{IrE{}0iifEWM( literal 0 HcmV?d00001 diff --git a/doc/kalgebra-dictionary-window.png b/doc/kalgebra-dictionary-window.png new file mode 100644 index 0000000000000000000000000000000000000000..bf4ae53f26836e98c39ef14e50ca4cdcd98dc139 GIT binary patch literal 20554 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 z z?VP564T5uyLgC%YMr!(<3TR>Q0oe^67+u2sCqt8yE|Qzw=JJ6Z_1GLKba{XD1GHYj z)}}jwSwe2Fy{cC0VNXsToZY$`vnjpxGfU80Zcn#me3P#(b8}jLzI+d?vwR+o+xzUo zqM04M;>L>sn2QXZ@WOjq#M7i`^w=%ACH>E}2kEE{+ZSci_ed%C5CoH??qlk<#Etcb zM{uM8>saz$HA~%=W0TW+fFv2jL19*0_Ytc3il~~D0)m$ER4*99D3d{;8od=_TByJ6 z0S3jY%~$4->V_f4PAFRm2O_U+@voQE6%jQlSwvhz>B)TCt2T>YBhd6T$)lrv z@^u-cd)P0ReF*U6GM(kUYAqJv*ID3+DXdTnZ>$)@ImWot}#W1TgJ;KM9xNDWNtE_Eb}LAo=(nwBqYW0B(@}d~beX;?J0+twF9C|4 z?)tT(*d*P@#lI9QzvA}J=?R5=gogwRG()J3HPvPvj zx|&YVQ_&H6QQgb+ppMzL5@jTK3mKc4xW_$< zI}w669&8HE{{T-`>NiIE6#0D6hSDsbbQakR)tExy`m@pMiLe1zU-cnw4qrRB3-@D~Y%LjTA6c_5QYXvHW{BA~87A5C&&1@*rzEMvtj0Sj zD4_a1k{!G>g`w24!rVt_!dG){E<~FHc1<7JkZvJMHN&^CRKLf;bSw$-C;7b~`t~4-=Ym0QPtKb^ea9ru zIob?R2BW?Q4Nooo%Dow!z;n#x6iAcBfrJ$h&gZWfVIHW<{mcbxt;@5f~c*SiKSyRUr47$wH zA-CKcIvduB^Mk9QKz1jU!u+)vC@Itka)W4`@7b_g44sb_AW*%lIu!zj~k6R&6>OAIh4bV5^2#L`$3_Sc+%7dN?M+M15}~6 zv|j@LB^k03{XD;aH-caTa#s1I^GJp{N0 zZm{4(2#T*XobRAm=%6(jeIsw6Eu$ehwGlWp;6W`_>NgCA@aH^g{c&Uz)I1NPEgJz@ zRCko}SCa7Tay2|86zb}n!z6?Pt#4eQ@tO;#pGTOWQHt@jbNvZq0V7PrItVGUW@&1H uh9p73JH}*;An(N_6d_0v)&E7dr1Cs}-<;X-vfsH8@X`f)Ymyb>{(k_CCOe7% literal 0 HcmV?d00001 diff --git a/doc/kalgebra-main-window.png b/doc/kalgebra-main-window.png new file mode 100644 index 0000000000000000000000000000000000000000..1eefdd10ddd5aa3388ad6fc244587930897c65d9 GIT binary patch literal 15624 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

y{3h;OMuU@>@m8y za#twYUz!}c?f$5a1#adjw--=)rjy#cqcAR_Pss4AdKH35m0k$dzf?=KTFPxxf@wgC zW;WZs(y#;WhZsgQ*3G}&N;Eb##7k>MuNIvS-5x(P4q37CY3-i3f1ig$fI%3M(Hz{| zrE~~lIb#!%0rXzU8E7z}e7d@87HF6x$^to#hte7OgcZH`pL)~lrvy0!j^CEAK| z>xH{~8!&_56EIc_s0ASSjyYa|C*Uck$%DAWxez?@*eiKun&eqm%8nO4*sk zM0aQP@#4qKYHE`2e+mazqL~g-^x24XrY9%0qY@=r-_uj0pT=}VJ$V>=`Csbkqe2ujw`xR;!1z^@Y#gc#rOqZI8@KyC^k6xb4bJo}KJ2-Y%#9y;`F%dKSu!EJy9yK*m7Wd%- zYD)X%RRQM}7o(9=a67OLszNeQUG@vkM}QCg%gx%I3?9W6uKW&HYcS9U(^X35WVIo) z`;JbUyB_I1ki>IlE+Si#>;F18;FR6GITz$>>v8BhdCEv|S(IkMQf^4ePPivjUIeVw zYmk=DsQ98Ogd0pp-2G2i5f>)Z8Q#V*DfeLnssASN6$G0_Olsmzm!&aGo)7nsDZfnalBQ zTF>7Mr=u5UE}ku%5QKh)m4x&9u*%OLyn4p)*3UKxcJa}rSLq`l7PPz(#sed@U;XV3 zGDHteE+@)MB&ZDOx^>6{F42F9gLbW0S?>^;IbuccX20Ql>4h-(=}w1_LC@MPCb;+> zm-4&VU=ZQIT0SUvx5Ed?kO2VBBbX~Fmfk1@@0X5=Nq!KQ8f74mkztlSVFVTxtsRH6 z#bMrM^id=9p*^wpBhZ^`0gmf^1hZ2djG5o;Km~EcVH!auD%g=?3+aG1Y?;m%XynAk zF^X2Fv|XeE8%nn1hZQ_gW}3q8H?#Qo)h-N}eNBN}HzeyeB80F|tUav@Neh zZf%AVURR(GG)5`mNKDwA&3ZhM=OPJsq??L|sNYNz2S&}wA451^fJc~|{05xyC&MHK zZ@LvVsmOiQ-Vd`Q(1zs@po@jJ1?0iMQh9E&(fKA77hI0OMj)UdEyUe)REz%JyF^H#0p^{2}b9q z%|XB%Cal?xd;j?+8y4w;}Icm7qUpmuP$}>r1QE3sWqAW->Y1X3jQ&hb|aHlpe-3a}WIWBm`or zavc}Zw}HKCYlPQ#FiZpwA%?bEHwN#t0Mn2ha*(ggDLArGF*-dx4F@ND)?`Fr>Af}K zNhvYOCh{;QLu;A+J4VqsT(7~=F|ot5&qRm0fGekj5G(puD3*qD%UlA+AAj&MK1k{>05vL^X-9m^>r&f^Q?U} z;g9*Z8>hi!{L2RtjxJhCS7uZ8h=f?LWW^`BW(sVDUZZ=KY(atQ05tN}V4hilE#Z-| z<5Li$cyzKfEs-x=J^+pdqPuI92z;R+S(PmvME((k69P zJn$tNT&LCNOQO+CPgX+FQ{c2jAR;p!25HDWAlls@`nAarz=cXLrN)x;ed$-AB~p+x znPLPwA;N5=3fYD)Q>?J~I0D`JR@s!;l6Ifp%@T5zx>F(_fEruqeaG++3i%^nqKN~2 z$;zUka*sm6Brnz+Na#y|{(PYxPP)El&dI3RSjX78)!ScFJV+Of3kZItb&S^tj2rn9 zG&#Gg(VIi|!HEv7S^GET>!lufqr-Dv zo$LPM?i)!8k`2L?G=sCdd(V`97RV=0;U6;Q|MiRAt$NMwxa`#wYUJ_=5af(2IP!9V zuIEr7n}uR8qGR3lkfRnanSe6>E0^y~OvY@1i9-2M2zvR&Ns95CDoYA4giV3oaJk}k zyI-ItyCo24`#A(U=hb1oWc!&%Gh548aAT}+LUJT#N+(0wgo~D&i-9B9t&(Hku1?DAEdt0IDCwgI@?Ls?+DP8p{OT1o3s%9)YhOy17*;#A zDEHE~^D+0g=!;Iy0}x%zJY#4?$QypQ0{B-4>R&XL{CGZj*!CxKkD=1p#JenqFtIPd za}(~rps)$%m=?^R3b)S|(9r_nF+oQ_KXgbX_UA5`Nd8C=2Wof00*&cP__lGWlelr& z>F@wl#vNVv?HdLGYRN+)pyj#)6)3CY-%vZ3%eRgr-p8*6 zncsPd&~w7Xixy43=2^`-c5Ez&I4AC+nkwDrt3A;n2k+#ZJGt6v9%jJ#iQ2YxL5bRV zXP!21*UY}^6p`%a*sU{u=a9keEVA!9S3HtW-UJ4t+1DL51b1{b*rb zqY?}!_{#g%5&0o>NL0WV?&I1A`Ws!qkf@Q=vp48=IHUg3*w#Y59qz=xYIc=lCQ4MU{IS9 z-u;e#;?IN)aB+@ci!ezjGwl_%(+1T?zU9kQ>w%s^z)&Jk?QkQkf;jm0TtTn=_4d*9 zj#0S`mPa?f9%N#_WW?HIP8lIS6Bb^HVyBp(mR{zA-fE>j8G z0Q%j$-dWmF3}~G!L?8|AjNeaef$@ix$sE?>kMAoO5mGJw91E^0DwB^(V2=UqM7$~+>A_KM* z#1V!Bwk!vmlB;uzGbgpbHZHHAqOM_Nhxdo*K=nVjHm>HJnljwyR}IXv(Yd9YS#hP4 zVYbG5Ld%}Jicy087)UiGW;OLQb#cg;in$GL5|xdZ?!PZ&aE|-TpAP9=uO=60X&;Cx&z4;v#g5sAo zA$|a;y(@!*2>nrNR6sF+8X^SAh54blMp&pLzOy;w7=Y3o(T)}S?d zKn@dR-ws$GBn7>N7GVOFdI0q2=>$v-y0g7K%Q)ovTLgd%xw6Dqh>`#`BbKvWim_ih zV^JpG(cpRI)0G?897XU!aw-#0H7HDh_=Q3Rw7ia~SpmB5UXwCmTLNWni6Q@qdIp?l z%T+Fiom*&cuX`jhteyKrp9R4Anaas+u0DkAqU4>Ca*2p9%^}M1N%^O)0UGop}Y<~rE6Eri~6vUXx9stH~)-82h zbxd@=tWT{>NiQ*is{8sz0#Qt%q#%_R#jF2VkCZi`?1s*9?mq>Pau9%1z7dIbFi62G zCaz%YWhT3V*rmbJ(7DtE19dtLQbGR}^yE^?q($WpIywOUecd54`3q6In-~YBi$Mj^ zJ92Ftd-}I!pcN^jV?}Ki9Xe>#AmA?GT;!lZ=)Qk;{(Z&BFLj`mWX08G%5R-sx+y`q z=NZsHF9?3}Zvq2IA-+Ka#K76AfQ}qR^h7~{f3xGa<590c6JS6gHX0q1HZShfzc5KX z@oeH_K;xSXy$iKa6jb5PUJdjP1B5%$6s?c z{Wm4%A9^cV5ZeB=PZk{XA@<(_&ICad#DIU>N7N-l^W9PkL_i8xqIcY|qh0$UZqg6! zGAh6tKrM11M;4>uf&%}OxBtfpdWo7!4F8*!JL(QdmXjEoVQOe-X!Lgr9D9DZ_)0dR z9~D6i=++3Ix6mE3f6Ras{x7p$NHifW@c)F%e~3pL`G2Dtp8Rv55INre^2D7<$UfSl zC+>fHjG=7yj>tRa(bWB$ahC$rZkQ2Etp7hl8vjOk$z+eixc>zhn#2E!5eP7ByK1Je zl=~2^%G~wZoVCI7uV*GdT@1VsQPzTTd|8{MKR5zI>qyvN|9gAny6O2UYuyoyw%K=- zb@=z!`md`Z#obu>r8E+y_`U;Mm*eUw$+^UVJ4A{5J7HTa=Ghj-80 z@2ULkXn(tVxVX4Xm7s}Sx}C01nuOKd4__v=5csMps41!{*&0Laq)hP988X|Jc8Ck;ZE#Lv-`;0u;GY`iV`J@| zt53{Cy-uOty|Col&;PQqwoc~~GcCc%iVCyNIyZy%8>J4cLwH2n-&lbXCVw%?m(T%V z<2R~!D$lchL8b#l9;R!q0{nX~l?U<6P4S65SY1V*S!WLX6uey3ZYaTLKGevHuka|u z)JYI(;5PmI*TBw>U+}}bO|WR}*f?CP0T1AZmOFd?mO=e-V1!aI#XK|>w3vJf6}?Vx zL7x6mSQit|+)7A+*cNbsXIbJ0a&F63*r$HUoLVwp$b!#2rXK^<(ET@Wg;pL0avn*c zLHYM&`n4=x9QaEkf~FVzYH$uIHpc7%SK`5 z@*xKrVs0bk{K_w7nV_=t#q8jfh^gfdwpHHKKbI|(O!)k3hv(sWHghTNx(g?C=*^LA zXdzNv<*=|Y+CD|E^f;Iz><8Ps%jNv7bNfnx+^>N7VPsDs2LYY@Oceiq66NW7_&M%0 zb${}hH;mgkkyV2IcQi}6S7y4+!U_G|USsa-uiSV!oj*NXX;a{ZV-4|xQ;oxa6M*`I z`dkT?MTn%9nqM>ODoy}oA0}_2GR9HEPe?psmTLw^mhTvz5xrKC7`gSQf?CPo(0ka* zWdsj`TQty@uvf0l$|yIR=GZ$n(CdVw`>b%$&VZmV3|0Yqf|t?movribQUyxx579&} z)y_uGJ(M6q6KvMv78;$|MEnr?5}g)&?o;0R%OoTCAFtRx9b=XmnDSSie()g|-{O9b zI@C5u#?~7(`J^I~kQ=CNygt&ReCqKsI3ip%BzOLOG1HK^gbxLA1paXbHH}*_2=E_u zacwv?Kv#nxMxTk_7re{V?hE_fs*_3<*MvP0>_ogHvG9d3@9){U-DxCn$vN4C?@Dj zb}S$=R^Z~mT|v2fa(c{0M5?xfb?W#->2(vI;*()^`Nqw&3YaW-I4&W%`_@O-GcaQW_gu3&q{F?_nC-*1+va=+6B*tBr%E2|GYk>2?@ZMlRa&o6_EcfZW` zKFpv_ries3gy-G#&xf!~GVJtR5xRhx8iDnXv{z(i3@g0GbZ&S5;f$g1LK*&5+Q{$! E0EM2y3IG5A literal 0 HcmV?d00001 diff --git a/doc/view-fullscreen.png b/doc/view-fullscreen.png new file mode 100644 index 0000000000000000000000000000000000000000..7e684b43ef69bc918e7fea6b7d577391cff5cb6e GIT binary patch literal 329 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 literal 0 HcmV?d00001 diff --git a/icons/hi16-app-kalgebra.png b/icons/hi16-app-kalgebra.png new file mode 100644 index 0000000000000000000000000000000000000000..2398b2064b5c257b8805ce598b8abefca5a4964a GIT binary patch literal 696 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 DB2WpC literal 0 HcmV?d00001 diff --git a/icons/hi64-app-kalgebra.png b/icons/hi64-app-kalgebra.png new file mode 100644 index 0000000000000000000000000000000000000000..d533686b3f9d763d4b1310e637b7a49acac86ab4 GIT binary patch literal 3473 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 literal 0 HcmV?d00001 diff --git a/kalgebra.appdata.xml b/kalgebra.appdata.xml new file mode 100644 index 0000000..5c7c286 --- /dev/null +++ b/kalgebra.appdata.xml @@ -0,0 +1,81 @@ + + + kalgebra.desktop + CC0-1.0 + GPL-2.0+ + KAlgebra + KAlgebra + KAlgebra + KAlgebra + KAlgebra + KAlgebra + KAlgebra + KAlgebra + KAlgebra + KAlgebra + KAlgebra + KAlgebra + KAlgebra + KAlgebra + KAlgebra + KAlgebra + KAlgebra + Kalgebra + KAlgebra + xxKAlgebraxx + 數學_KAlgebra +

Graph Calculator + Calculadora gràfica + Kalkulačka grafů + Graphenrechner + Graph Calculator + Calculadora gráfica + Graafide arvutaja + Graafinen laskin + Grafikonszámoló + Calcolatrice grafica + Funkschonenreekner + Rekenmachine met grafieken + Kalkulator wykresów + Calculadora de Grafos + Calculadora gráfica + Grafická kalkulačka + Računalo z grafi + Grafräknare + Графічний калькулятор + xxGraph Calculatorxx + 圖形計算器 + +

KAlgebra is an application that can replace your graphing calculator. It has numerical, logical, symbolic, and analysis features that let you calculate mathematical expressions on the console and graphically plot the results in 2D or 3D. KAlgebra is rooted in the Mathematical Markup Language (MathML); however, one does not need to know MathML to use KAlgebra.

+

El KAlgebra és una aplicació que pot substituir la calculadora gràfica. Té característiques numèriques, lògiques, simbòliques i d'anàlisi que us permetran calcular expressions matemàtiques a la consola i traçar gràfics dels resultats en 2D o 3D. El KAlgebra té les seves arrels en el llenguatge de marques matemàtic (Mathematical Markup Language -MathML-). Però un no us caldrà saber MathML per utilitzar el KAlgebra.

+

KAlgebra ist eine Anwendung, die Ihren grafischen Taschenrechner ersetzt. KAlgebra hat numerische, logische, symbolische und analytische Fähigkeiten, mit denen Sie mathematische Ausdrücke in der Konsole auswerten und die Ergebnisse zwei- oder dreidimensional darstellen können. KAlgebra basiert auf der Sprache „Mathematical Markup Language“ (MathML), es sind jedoch keine Kenntnisse von MathML erforderlich, um KAlgebra erfolgreich einsetzen zu können.

+

KAlgebra is an application that can replace your graphing calculator. It has numerical, logical, symbolic, and analysis features that let you calculate mathematical expressions on the console and graphically plot the results in 2D or 3D. KAlgebra is rooted in the Mathematical Markup Language (MathML); however, one does not need to know MathML to use KAlgebra.

+

KAlgebra es una aplicación que puede sustituir a su calculadora gráfica. Tiene funciones numéricas, lógicas, simbólicas y analíticas que le permiten calcular expresiones matemáticas en la consola y dibujar gráficamente el resultado en 2D o 3D. KAlgebra tiene su origen en el «Lenguaje de marcas matemático» (MathML); no obstante, no es necesario conocer MathML para usar KAlgebra.

+

KAlgebra on rakendus, mis võib asendada su senist graafikalkulaatorit Sel on arvulisi, loogilisi, sümbolilisi ja analüüsiomadusi, mis võimaldavad arvutada matemaatilisi avaldisi konsoolis ja lasta tulemusi kujutada graafiliselt nii tasapinnaliselt (2D) kui ka ruumiliselt (3D). KAlgebra juured on matemaatilises märkekeeles (MathML), kuid KAlgebra kasutamiseks ei ole MathML-i tundmine sugugi vajalik.

+

KAlgebralla voi korvata graafisen laskimen. Siinä on numeeriset, loogiset, symboliset ja analyysiominaisuudet, jotka tarvitaan matemaattisten lausekkeiden laskemiseen sekä tulosten piirtämiseen kaksi- tai kolmiulotteisesti. KAlgebra perustuu MathML:ään (Mathematical Markup Language), mutta sitä ei tarvitse osata käyttääkseen KAlgebraa.

+

KAlgebra è un'applicazione che può sostituire la tua calcolatrice grafica. Ha funzionalità numeriche, logiche, simboliche e di analisi che ti permettono di calcolare espressioni matematiche sulla console e visualizzarne il grafico in 2D o 3D. KAlgebra si basa sul linguaggio a marcatori di matematica («Mathematical Markup Language», MathML); tuttavia, non è necessario conoscere MathML per usare KAlgebra.

+

KAlgebra kannst Du ansteed Dien Grafik-Taschenreekner bruken. Dat gifft numeersche, logische, symboolsche un Analysis-Funkschonen, mit de Du mathemaatsch Utdrück op de Konsool utreken un de Resultaten graafsch in 2- un 3-D utgeven kannst. KAlgebra buut op de Mathemaatsch Schriftsatzspraak („Mathematical Markup Language – MathML“); man Du kannst KAlgebra ok bruken, wenn Du nix vun MathML afweetst.

+

KAlgebra kan uw grafische rekenmachine vervangen. Het heeft numerieke, logische, symbolische en analytische functies waarmee u wiskundige uitdrukkingen kunt berekenen in de console, en de resultaten in 2D of 3D kunt plotten. KAlgebra is gebaseerd op de Mathematical Markup Language (MathML), maar kennis daarvan is niet nodig om KAlgebra te kunnen gebruiken.

+

KAlgebra jest programem, który może zastąpić twój kalkulator graficzny. Ma możliwość przeprowadzania analiz numerycznych, logicznych i symbolicznych, które umożliwiają obliczanie wyrażeń matematycznych w konsoli i rysowanie wyników w 2D lub 3D. KAlgebra jest zakorzeniona w Mathematical Markup Language (MathML); lecz nie trzeba znać MathML, aby używać KAlgebra.

+

O KAlgebra é uma aplicação que poderá substituir a sua calculadora gráfica. Ela tem funcionalidades numéricas, lógicas, simbólicas e de análise que lhe permitem calcular expressões matemáticas na consola e desenhar os resultados respectivos em 2D ou 3D. O KAlgebra baseia-se na Mathematical Markup Language (MathML); contudo, ninguém precisa de saber MathML para usar o KAlgebra.

+

KAlgebra é um aplicativo que pode substituir a sua calculadora gráfica. Ele tem funcionalidades numéricas, lógicas, simbólicas e analíticas que lhe permitem calcular expressões matemáticas no console e desenhar graficamente os resultados em 2D ou 3D. O KAlgebra é baseado na Mathematical Markup Language (MathML). Entretanto, não é preciso conhecer o MathML para usar o KAlgebra.

+

KAlgebra je aplikácia, ktorá môže nahradiť vašu grafickú kalkulačku. Má numerické, logické, symbolické a analytické funkcie, ktoré vám umožnia vypočítať matematické výrazy na konzole a graficky zakresliť výsledky v 3D alebo 3D. KAlgebra je založená na jazyku MathML; avšak nemusíte poznať tento jazyk na používanie tohto programu.

+

KAlgebra je program, ki lahko zamenja vaše grafično računalo. Ima zmožnosti za obdelavo številk, logike, simbolov in omogoča izračun matematičnih izrazov v konzoli ter njihov izris v 2D ali 3D. KAlgebra temelji na Matematičnem označevalnem jeziku (MathML), vendar ga za uporabo KAlgebre ni potrebno poznati.

+

Kalgebra; är ett program som kan ersätta en grafisk miniräknare. Det har numeriska, logiska, symboliska och analytiska funktioner som gör det möjligt att beräkna matematiska uttryck i terminalen och rita upp resultatet grafiskt i två eller tre dimensioner. Kalgebra är grundat på det matematiska taggspråket (MathML), men man behöver dock inte känna till MathML för att använda Kalgebra.

+

KAlgebra; — програма, яка може замінити вам калькулятор з можливістю побудови графіків У програмі передбачено числові, логічні, символічні та аналітичні можливості, за допомогою яких ви зможете виконувати обчислення за формулами у консолі або будувати результати у форматі плоских кривих або просторових графіків. KAlgebra засновано на мові математичної розмітки (Mathematical Markup Language і MathML). Втім, для користування KAlgebra знати MathML не потрібно.

+

xxKAlgebra is an application that can replace your graphing calculator. It has numerical, logical, symbolic, and analysis features that let you calculate mathematical expressions on the console and graphically plot the results in 2D or 3D. KAlgebra is rooted in the Mathematical Markup Language (MathML); however, one does not need to know MathML to use KAlgebra.xx

+

KAlgebra 是一套可以取代您的圖形計算器的應用程式。它有數值、邏輯、符號與分析等功能,讓您計算您的數學式,並繪出平面或立體的圖形。KAlgebra 是基於 Mathematical Markup Language (MathML)。不過即使您不知道 MathML 也可以使用 KAlgebra。

+
+ http://edu.kde.org/kalgebra/ + https://bugs.kde.org/enter_bug.cgi?format=guided&product=kalgebra + http://docs.kde.org/stable/en/kdeedu/kalgebra/index.html + + + http://kde.org/images/screenshots/kalgebra.png + + + KDE + + kalgebra + + diff --git a/kalgebra.kdev4 b/kalgebra.kdev4 new file mode 100644 index 0000000..ea6725c --- /dev/null +++ b/kalgebra.kdev4 @@ -0,0 +1,3 @@ +[Project] +Manager=KDevCMakeManager +Name=kalgebra diff --git a/mobile/CMakeLists.txt b/mobile/CMakeLists.txt new file mode 100644 index 0000000..6cf6f1b --- /dev/null +++ b/mobile/CMakeLists.txt @@ -0,0 +1,30 @@ +add_subdirectory(declarative) +add_subdirectory(plugins) + +if(${MOBILE_BACKEND} STREQUAL "kde") + add_definitions(-DKDECOMPONENTS) +endif(${MOBILE_BACKEND} STREQUAL "kde") + +qt4_add_resources(KALGEBRAMOBILE_SRCS resources.qrc) +kde4_add_executable(kalgebramobile pluginsmodel.cpp + kalgebramobile.cpp main.cpp ${KALGEBRAMOBILE_SRCS}) + +target_link_libraries(kalgebramobile ${KDE4_KDECORE_LIBS} ${QT_QTDECLARATIVE_LIBRARY} + ${QT_QTGUI_LIBRARY} ${ANALITZA_LIBRARY} ${ANALITZAGUI_LIBRARY} ${ANALITZAPLOT_LIBRARY}) + +add_definitions("-DPREFIX=\\\"${CMAKE_INSTALL_PREFIX}\\\"") + +set(DESKTOPFILE_INSTALL ${XDG_APPS_INSTALL_DIR}) +if(${MOBILE_BACKEND} STREQUAL "harmattan") + set(DESKTOPFILE_INSTALL ${XDG_APPS_INSTALL_DIR}/..) +elseif(${MOBILE_BACKEND} STREQUAL "kde") + target_link_libraries(kalgebramobile kdeclarative) +endif(${MOBILE_BACKEND} STREQUAL "harmattan") + +set(DESKTOPFILE kalgebramobile.desktop) +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/kalgebramobile${MOBILE_BACKEND}.desktop) + set(DESKTOPFILE kalgebramobile${MOBILE_BACKEND}.desktop) +endif() + +install(TARGETS kalgebramobile ${INSTALL_TARGETS_DEFAULT_ARGS}) +install(PROGRAMS ${DESKTOPFILE} DESTINATION ${DESKTOPFILE_INSTALL} ) diff --git a/mobile/declarative/CMakeLists.txt b/mobile/declarative/CMakeLists.txt new file mode 100644 index 0000000..758c187 --- /dev/null +++ b/mobile/declarative/CMakeLists.txt @@ -0,0 +1,18 @@ +project(analitza-declarative) + +include_directories( + ${CMAKE_SOURCE_DIR} + ${CMAKE_BINARY_DIR} +) + +kde4_add_library(analitzadeclarativeplugin SHARED analitzadeclarativeplugin.cpp graph2dmobile.cpp analitzawrapper.cpp) + +target_link_libraries(analitzadeclarativeplugin ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTDECLARATIVE_LIBRARY} ${ANALITZA_LIBRARY} ${ANALITZAGUI_LIBRARY} ${ANALITZAPLOT_LIBRARY}) + +install(TARGETS analitzadeclarativeplugin DESTINATION ${IMPORTS_INSTALL_DIR}/org/kde/analitza) +install(FILES qmldir DESTINATION ${IMPORTS_INSTALL_DIR}/org/kde/analitza) + +install( FILES + qml/Graph2D.qml + DESTINATION ${IMPORTS_INSTALL_DIR}/org/kde/analitza +) \ No newline at end of file diff --git a/mobile/declarative/analitzadeclarativeplugin.cpp b/mobile/declarative/analitzadeclarativeplugin.cpp new file mode 100644 index 0000000..79704eb --- /dev/null +++ b/mobile/declarative/analitzadeclarativeplugin.cpp @@ -0,0 +1,35 @@ +/************************************************************************************* + * Copyright (C) 2012 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 "analitzadeclarativeplugin.h" +#include "analitzawrapper.h" +#include +#include +#include +#include +#include + +void AnalitzaDeclarativePlugin::registerTypes(const char* uri) +{ + qmlRegisterType("org.kde.analitza", 1, 0, "Analitza"); + qmlRegisterType("org.kde.analitza", 1, 0, "Expression"); + qmlRegisterType("org.kde.analitza", 1, 0, "Graph2DView"); + qmlRegisterType("org.kde.analitza", 1, 0, "PlotsModel"); + qmlRegisterType("org.kde.analitza", 1, 0, "VariablesModel"); + qmlRegisterInterface("Analitza::Variables"); +} diff --git a/mobile/declarative/analitzadeclarativeplugin.h b/mobile/declarative/analitzadeclarativeplugin.h new file mode 100644 index 0000000..39881d5 --- /dev/null +++ b/mobile/declarative/analitzadeclarativeplugin.h @@ -0,0 +1,31 @@ +/************************************************************************************* + * Copyright (C) 2012 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 ANALITZADECLARATIVEPLUGIN_H +#define ANALITZADECLARATIVEPLUGIN_H + +#include + +class AnalitzaDeclarativePlugin : public QDeclarativeExtensionPlugin +{ + virtual void registerTypes(const char* uri); +}; + +Q_EXPORT_PLUGIN2(analitzadeclarativeplugin, AnalitzaDeclarativePlugin); + +#endif // ANALITZADECLARATIVEPLUGIN_H diff --git a/mobile/declarative/analitzawrapper.cpp b/mobile/declarative/analitzawrapper.cpp new file mode 100644 index 0000000..0bab206 --- /dev/null +++ b/mobile/declarative/analitzawrapper.cpp @@ -0,0 +1,156 @@ +/************************************************************************************* + * Copyright (C) 2010 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 "analitzawrapper.h" +#include +#include +#include +#include +#include + +#include + +Q_DECLARE_METATYPE(ExpressionWrapper*); + +ExpressionWrapper::ExpressionWrapper(QObject* parent) + : QObject(parent) +{} + + +ExpressionWrapper::ExpressionWrapper(const Analitza::Expression& e, QObject* parent) + : QObject(parent) + , m_exp(e) +{} + +void ExpressionWrapper::setText(const QString& exp) { m_exp.setText(exp); } + +bool ExpressionWrapper::isCorrect() const { return m_exp.isCorrect(); } +QString ExpressionWrapper::toString() const { return m_exp.toString(); } +QVariant ExpressionWrapper::value() const { return AnalitzaUtils::expressionToVariant(m_exp); } +QStringList ExpressionWrapper::errors() const { return m_exp.error(); } + +////////////////////////// + +AnalitzaWrapper::AnalitzaWrapper(QObject* parent) + : QObject(parent) + , m_wrapped(0), m_calc(false) +{ + initWrapped(); +} + +void AnalitzaWrapper::initWrapped() +{ + if(!m_wrapped) { + if(m_vars) + m_wrapped = new Analitza::Analyzer(m_vars); + else { + m_wrapped = new Analitza::Analyzer; + m_vars = m_wrapped->variables(); + } + } +} + +void AnalitzaWrapper::setVariables(Analitza::Variables* v) +{ + delete m_wrapped; + m_wrapped = 0; + m_vars = v; + initWrapped(); +} + +QVariant AnalitzaWrapper::execute(const QString& expression) +{ + initWrapped(); + Analitza::Expression e(expression, false); + if(!e.isCorrect()) { + return e.error(); + } + m_wrapped->setExpression(e); + + Analitza::Expression res; + if(m_calc) + res = m_wrapped->calculate(); + else + res = m_wrapped->evaluate(); + + if(!m_wrapped->isCorrect()) + return QVariant(); + + return qVariantFromValue(new ExpressionWrapper(res)); +} + +QVariant AnalitzaWrapper::executeFunc(const QString& name, const QVariantList& args) +{ + if(m_vars && !m_vars->contains(name)) + return QVariant(); + + QStack stack; + QList exps; + foreach(const QVariant& v, args) { + exps += AnalitzaUtils::variantToExpression(v); + stack << exps.last().tree(); + } + + m_wrapped->setExpression(Analitza::Expression(name, false)); + m_wrapped->setExpression(m_wrapped->calculate()); + m_wrapped->setStack(stack); + Analitza::Expression expr = m_wrapped->calculateLambda(); + + if(!m_wrapped->isCorrect()) + return QVariant(); + else + return qVariantFromValue(new ExpressionWrapper(expr)); +} + +QString AnalitzaWrapper::dependenciesToLambda(const QString& expression) const +{ + m_wrapped->setExpression(Analitza::Expression(expression, false)); + return m_wrapped->dependenciesToLambda().toString(); +} + +void AnalitzaWrapper::insertVariable(const QString& name, const QString& expression) const +{ + m_wrapped->insertVariable(name, Analitza::Expression(expression, false)); +} + +QString AnalitzaWrapper::unusedVariableName() const +{ + QString candidate; + char curr='a'; + + for(candidate=curr; m_vars->contains(candidate); ) { + curr+=1; + if(curr>'z') + curr='a'; + else + candidate.chop(1); + + candidate += curr; + } + + return candidate; +} + +void AnalitzaWrapper::removeVariable(const QString& name) +{ + m_vars->remove(name); +} + +bool AnalitzaWrapper::isCorrect() const { return m_wrapped->isCorrect(); } + +QStringList AnalitzaWrapper::errors() const { return m_wrapped->errors(); } diff --git a/mobile/declarative/analitzawrapper.h b/mobile/declarative/analitzawrapper.h new file mode 100644 index 0000000..d397008 --- /dev/null +++ b/mobile/declarative/analitzawrapper.h @@ -0,0 +1,87 @@ +/************************************************************************************* + * Copyright (C) 2010 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 ANALITZAWRAPPER_H +#define ANALITZAWRAPPER_H + +#include +#include +#include + +namespace Analitza { + class Analyzer; + class Variables; +} + +class ExpressionWrapper : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString expression READ toString WRITE setText); + public: + ExpressionWrapper(QObject* parent=0); + explicit ExpressionWrapper(const Analitza::Expression & e, QObject* parent = 0); + + void setText(const QString& exp); + + public slots: + QString toString() const; + bool isCorrect() const; + QVariant value() const; + QStringList errors() const; + + private: + Analitza::Expression m_exp; +}; + +class AnalitzaWrapper : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool calculate READ isCalculate WRITE setCalculate) + Q_PROPERTY(bool isCorrect READ isCorrect) + Q_PROPERTY(QStringList errors READ errors) + Q_PROPERTY(Analitza::Variables* variables READ variables WRITE setVariables) + public: + explicit AnalitzaWrapper(QObject* parent = 0); + + void setCalculate(bool calc) { m_calc = calc; } + bool isCalculate() const { return m_calc; } + + Analitza::Analyzer* wrapped() const { return m_wrapped; } + + Q_SCRIPTABLE QVariant execute(const QString& expression); + Q_SCRIPTABLE QVariant executeFunc(const QString& name, const QVariantList& args); + Q_SCRIPTABLE QString unusedVariableName() const; + Q_SCRIPTABLE QString dependenciesToLambda(const QString& expression) const; + Q_SCRIPTABLE void insertVariable(const QString& name, const QString& expression) const; + Q_SCRIPTABLE void removeVariable(const QString& name); + + QStringList errors() const; + bool isCorrect() const; + + Analitza::Variables* variables() const { return m_vars; } + void setVariables(Analitza::Variables* v); + + private: + void initWrapped(); + + Analitza::Analyzer* m_wrapped; + Analitza::Variables* m_vars; + bool m_calc; +}; + +#endif // ANALITZAWRAPPER_H diff --git a/mobile/declarative/graph2dmobile.cpp b/mobile/declarative/graph2dmobile.cpp new file mode 100644 index 0000000..2a3abae --- /dev/null +++ b/mobile/declarative/graph2dmobile.cpp @@ -0,0 +1,132 @@ +/************************************************************************************* + * Copyright (C) 2011 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 "graph2dmobile.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Analitza; + +Graph2DMobile::Graph2DMobile(QDeclarativeItem* parent) + : QDeclarativeItem(parent), Plotter2D(boundingRect().size()) + , m_dirty(true), m_currentFunction(-1) +{ + setSize(QSizeF(100,100)); + setFlag(QGraphicsItem::ItemHasNoContents, false); + + defViewport = QRectF(QPointF(-10.0, 10.0), QSizeF(20.0, -20.0)); + resetViewport(); +} + +void Graph2DMobile::paint(QPainter* p, const QStyleOptionGraphicsItem* options, QWidget* ) +{ +// qDebug() << "hellooo" << boundingRect(); + if(boundingRect().size().isEmpty()) + return; + + if(m_buffer.size()!=boundingRect().size()) { + m_buffer = QPixmap(boundingRect().size().toSize()); + setPaintedSize(boundingRect().size().toSize()); + } + + Q_ASSERT(!m_buffer.isNull()); + + if(m_dirty) { + m_buffer.fill(Qt::transparent); + drawGrid(&m_buffer); + drawFunctions(&m_buffer); + m_dirty=false; + } + + p->drawPixmap(QPoint(0,0), m_buffer); +} + +void Graph2DMobile::forceRepaint() +{ + m_dirty=true; + update(); +} + +void Graph2DMobile::resetViewport() +{ + setViewport(defViewport); +} + +void Graph2DMobile::modelChanged() +{ + connect(model(), SIGNAL(dataChanged( const QModelIndex&, const QModelIndex& )), + this, SLOT(updateFuncs(const QModelIndex&, const QModelIndex))); + connect(model(), SIGNAL( rowsInserted ( const QModelIndex &, int, int ) ), + this, SLOT(addFuncs(const QModelIndex&, int, int))); + connect(model(), SIGNAL( rowsRemoved ( const QModelIndex &, int, int ) ), + this, SLOT(removeFuncs(const QModelIndex&, int, int))); +} + +void Graph2DMobile::addFuncs(const QModelIndex& parent, int start, int end) { updateFunctions(parent, start, end); } + +void Graph2DMobile::removeFuncs(const QModelIndex&, int, int) { forceRepaint(); } +void Graph2DMobile::updateFuncs(const QModelIndex& start, const QModelIndex& end) { updateFunctions(QModelIndex(), start.row(), end.row()); } + +void Graph2DMobile::scale(qreal s, int x, int y) +{ + QRectF userViewport = lastUserViewport(); + if(s<1 || (userViewport.height() < -3. && userViewport.width() > 3.)) { + scaleViewport(s, QPoint(x,y)); + } +} + +void Graph2DMobile::translate(qreal x, qreal y) +{ + moveViewport(QPoint(x,y)); +} + +QColor randomFunctionColor() { return QColor::fromHsv(qrand()%255, 255, 225); } + +QStringList Graph2DMobile::addFunction(const QString& expression, Analitza::Variables* vars) +{ + Analitza::Expression e(expression, Analitza::Expression::isMathML(expression)); + PlotsModel* plotsmodel = qobject_cast(model()); + if(!plotsmodel) + qWarning() << "only can add plots to a PlotsModel instance"; + QString fname; + do { + fname = plotsmodel->freeId(); + } while(vars && vars->contains(fname)); + QColor fcolor = randomFunctionColor(); + + QStringList err; + PlotBuilder req = PlotsFactory::self()->requestPlot(e, Dim2D, vars); + if(req.canDraw()) { + PlaneCurve* it = static_cast(req.create(fcolor, fname)); + + if(it->isCorrect()) + plotsmodel->addPlot(it); + else { + err = it->errors(); + delete it; + } + } + + return err; +} \ No newline at end of file diff --git a/mobile/declarative/graph2dmobile.h b/mobile/declarative/graph2dmobile.h new file mode 100644 index 0000000..d40abaf --- /dev/null +++ b/mobile/declarative/graph2dmobile.h @@ -0,0 +1,72 @@ +/************************************************************************************* + * Copyright (C) 2010 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 GRAPH2DMOBILE_H +#define GRAPH2DMOBILE_H + +#include +#include + +namespace Analitza { +class Variables; +} + +class Graph2DMobile : public QDeclarativeItem, public Analitza::Plotter2D +{ + Q_OBJECT + Q_PROPERTY(QAbstractItemModel* model READ model WRITE setModel) + Q_PROPERTY(QRectF viewport READ lastViewport WRITE setViewport) + Q_PROPERTY(bool showGrid READ showGrid WRITE setShowGrid) + Q_PROPERTY(bool keepAspectRatio READ keepAspectRatio WRITE setKeepAspectRatio) + Q_PROPERTY(bool currentFunction READ currentFunction WRITE setCurrentFunction) + Q_PROPERTY(bool ticksShown READ ticksShownAtAll WRITE setTicksShownAtAll) + public: + Graph2DMobile(QDeclarativeItem* parent = 0); + + virtual void forceRepaint(); + virtual void viewportChanged() {} + virtual void modelChanged(); + virtual int currentFunction() const { return m_currentFunction; } + + virtual void paint(QPainter* p, const QStyleOptionGraphicsItem* options, QWidget* w); + + void setCurrentFunction(int f) { m_currentFunction = f; } + bool ticksShownAtAll() const { return ticksShown()!=0; } + void setTicksShownAtAll(bool shown) { setShowTickLabels(shown ? Qt::Vertical|Qt::Horizontal : Qt::Orientations(0));} + + public slots: + void translate(qreal x, qreal y); + void scale(qreal s, int x, int y); + void resetViewport(); + QStringList addFunction(const QString& expression, Analitza::Variables* vars=0); + + private slots: + void updateFuncs(const QModelIndex& start, const QModelIndex& end); + void addFuncs(const QModelIndex& parent, int start, int end); + void removeFuncs(const QModelIndex& parent, int start, int end); + + private: + bool m_dirty; + int m_currentFunction; + + QPixmap m_buffer; + QRectF defViewport; +}; + +#endif // GRAPH2DMOBILE_H diff --git a/mobile/declarative/qml/Graph2D.qml b/mobile/declarative/qml/Graph2D.qml new file mode 100644 index 0000000..5197088 --- /dev/null +++ b/mobile/declarative/qml/Graph2D.qml @@ -0,0 +1,57 @@ +import QtQuick 1.1 +import org.kde.analitza 1.0 + +Graph2DView { + id: view + anchors.fill: parent + + showGrid: true + + PinchArea { + anchors.fill: parent + property double thePreviousScale: 1 +// dragAxis: YAxis + +// onPinchFinished +// onPinchStarted: + + function distance(p1, p2) + { + var w=p2.x-p1.x + var h=p2.y-p1.y + return Math.sqrt(w*w+h*h) + } + + onPinchStarted: thePreviousScale=1 + + onPinchUpdated: { + var currentDistance = distance(pinch.point1, pinch.point2) + if(currentDistance>0) { + var startDistance = distance(pinch.startPoint1, pinch.startPoint2) + + var theCurrentScale = startDistance/currentDistance + + var doScale = theCurrentScale/thePreviousScale + view.scale(doScale, view.width/2, view.height/2) +// console.log("scale...", startDistance, theCurrentScale, doScale) + thePreviousScale = theCurrentScale + } + } + } + + MouseArea { + anchors.fill: parent + property int lastX: 0 + property int lastY: 0 + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton + + onPressed: { lastX=mouse.x; lastY=mouse.y } + + onPositionChanged: { + view.translate(mouse.x-lastX, mouse.y-lastY) + + lastX=mouse.x + lastY=mouse.y + } + } +} diff --git a/mobile/declarative/qmldir b/mobile/declarative/qmldir new file mode 100644 index 0000000..f276293 --- /dev/null +++ b/mobile/declarative/qmldir @@ -0,0 +1,3 @@ +plugin analitzadeclarativeplugin + +Graph2D 1.0 Graph2D.qml diff --git a/mobile/kalgebramobile.cpp b/mobile/kalgebramobile.cpp new file mode 100644 index 0000000..61482e0 --- /dev/null +++ b/mobile/kalgebramobile.cpp @@ -0,0 +1,83 @@ +/************************************************************************************* + * Copyright (C) 2010 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 "kalgebramobile.h" + +#include +#include +#include + +#include +#include "pluginsmodel.h" + +using namespace Analitza; + +KAlgebraMobile* KAlgebraMobile::s_self=0; +KAlgebraMobile* KAlgebraMobile::self() { return s_self; } + +KAlgebraMobile::KAlgebraMobile(QObject* parent) + : QObject(parent), m_functionsModel(0), m_vars(new Analitza::Variables) +{ + Q_ASSERT(s_self==0); + s_self=this; + + qmlRegisterType("org.kde.kalgebra.mobile", 1, 0, "PluginsModel"); + qmlRegisterType(); +} + +PlotsModel* KAlgebraMobile::functionsModel() +{ + if(!m_functionsModel) { + m_functionsModel = new Analitza::PlotsModel(this); + connect(m_functionsModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), SLOT(functionRemoved(QModelIndex,int,int))); + connect(m_functionsModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(functionInserted(QModelIndex,int,int))); + connect(m_functionsModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(functionModified(QModelIndex, QModelIndex))); + } + + return m_functionsModel; +} + +void KAlgebraMobile::functionInserted(const QModelIndex& parent, int start, int end) +{ + Q_ASSERT(!parent.isValid()); + for(int i=start; i<=end; i++) { + QModelIndex idx = functionsModel()->index(i, 1); + m_vars->modify(idx.sibling(i,0).data().toString(), Analitza::Expression(idx.data().toString())); + } +} + +void KAlgebraMobile::functionRemoved(const QModelIndex& parent, int start, int end) +{ + Q_ASSERT(!parent.isValid()); + for(int i=start; i<=end; i++) { + QModelIndex idx = functionsModel()->index(i); + m_vars->remove(functionsModel()->data(idx, Qt::DisplayRole).toString()); + } +} + +void KAlgebraMobile::functionModified(const QModelIndex& idxA, const QModelIndex& idxB) +{ + if(idxB.column()==1) { + for(int i=idxA.row(); iindex(i, 1); + m_vars->modify(idx.sibling(i,0).data().toString(), Analitza::Expression(idx.data().toString())); + } + } //else TODO: figure out how to control a "rename" +} + +Analitza::Variables* KAlgebraMobile::variables() const { return m_vars; } diff --git a/mobile/kalgebramobile.desktop b/mobile/kalgebramobile.desktop new file mode 100644 index 0000000..70110db --- /dev/null +++ b/mobile/kalgebramobile.desktop @@ -0,0 +1,136 @@ +[Desktop Entry] +Name=KAlgebra Mobile +Name[ast]=KAlgebra Mobile +Name[bg]=KAlgebra (мобилен) +Name[bs]=KAlgebra Mobile +Name[ca]=KAlgebra mòbil +Name[ca@valencia]=KAlgebra mòbil +Name[cs]=Mobilní KAlgebra +Name[da]=KAlgebra Mobile +Name[de]=KAlgebra Mobil +Name[el]=KAlgebra Mobile +Name[en_GB]=KAlgebra Mobile +Name[es]=KAlgebra móvil +Name[et]=KAlgebra mobiilis +Name[eu]=KAlgebra mugikorra +Name[fi]=KAlgebra mobiililaitteille +Name[fr]=KAlgebra Mobile +Name[ga]=KAlgebra Soghluaiste +Name[gl]=KAlgebra Mobile +Name[hu]=KAlgebra Mobile +Name[it]=KAlgebra Mobile +Name[ja]=KAlgebra モバイル +Name[kk]=KAlgebra Mobile +Name[km]=KAlgebra Mobile +Name[ko]=KAlgebra 모바일 +Name[lv]=KAlgebra Mobile +Name[mr]=के-एल्जिब्रा मोबाईल +Name[nb]=KAlgebra mobil +Name[nds]=KAlgebra för Mobilreedschappen +Name[nl]=KAlgebra-mobiel +Name[pa]=ਕੇ-ਐਲਜਬਰਾ ਮੋਬਾਇਲ +Name[pl]=Mobilna KAlgebra +Name[pt]=KAlgebra Móvel +Name[pt_BR]=KAlgebra Móvel +Name[ru]=Мобильная KAlgebra +Name[sk]=KAlgebra Mobile +Name[sl]=KAlgebra Mobile +Name[sv]=Kalgebra för mobil +Name[te]=కె అల్జీబ్రా మొబైలు +Name[tr]=KAlgebra Mobil +Name[ug]=كۆچمە ئۈسكۈنىلەر ئۈچۈن KAlgebra +Name[uk]=Мобільна KAlgebra +Name[x-test]=xxKAlgebra Mobilexx +Name[zh_CN]=KAlgebra 移动 +Name[zh_TW]=KAlgebra 行動版 +GenericName=Pocket Graph Calculator +GenericName[ast]=Calculadora gráfica de bolsiellu +GenericName[bg]=Джобен графичен калкулатор +GenericName[bs]=Džepni graf kalkulator +GenericName[ca]=Calculadora gràfica de butxaca +GenericName[ca@valencia]=Calculadora gràfica de butxaca +GenericName[cs]=Kapesní grafická kalkulačka +GenericName[da]=Graflommeregner +GenericName[de]=Graphen-Taschenrechner +GenericName[el]=Φορητός γραφικός υπολογιστής +GenericName[en_GB]=Pocket Graph Calculator +GenericName[es]=Calculadora gráfica de bolsillo +GenericName[et]=Graafikute arvutaja taskus +GenericName[eu]=Sakeleko grafikoen kalkulagailua +GenericName[fi]=Graafinen laskin mobiililaitteille +GenericName[fr]=Calculatrice graphique de poche +GenericName[ga]=Áireamhán Grafach Póca +GenericName[gl]=Calculadora gráfica de peto +GenericName[hu]=Zsebszámológép +GenericName[it]=Calcolatrice grafica tascabile +GenericName[ja]=ポケットグラフ計算機 +GenericName[kk]=Ықшам график калькуляторы +GenericName[km]=ម៉ាស៊ីន​គិត​លេខ​ក្រាហ្វិក​ដែល​ដាក់​តាម​ខ្លួន​បាន +GenericName[ko]=포켓 그래핑 계산기 +GenericName[lt]=Kišeninis grafinis skaičiuotuvas +GenericName[lv]=Kabatas grafiskais kalkulators +GenericName[mr]=पाकिट आलेख गणकयंत्र +GenericName[nb]=Grafikk-lommekalkulator +GenericName[nds]=Taschenreekner för Diagrammen +GenericName[nl]=Zakrekenmachine met grafieken +GenericName[pa]=ਪਾਕਟ ਗਰਾਫ਼ ਕੈਲਕੂਲੇਟਰ +GenericName[pl]=Kieszonkowy kalkulator graficzny +GenericName[pt]=Calculadora Gráfica Portátil +GenericName[pt_BR]=Calculadora gráfica portátil +GenericName[ru]=Карманный графический калькулятор +GenericName[sk]=Vrecková grafická kalkulačka +GenericName[sl]=Žepno računalo z grafi +GenericName[sv]=Grafminiräknare +GenericName[te]=జేబులొ పట్టే రేఖాచిత్రం గనన యంత్రము +GenericName[tr]=Cep Grafik Hesap Makinesi +GenericName[uk]=Кишеньковий графічний калькулятор +GenericName[x-test]=xxPocket Graph Calculatorxx +GenericName[zh_CN]=口袋图形计算器 +GenericName[zh_TW]=行動版圖形計算器 +Comment=Pocket Math Expression Solver and Plotter +Comment[bg]=Джобен инструмент за решаване на математически задачи +Comment[bs]=Matematski sistem za rješavanje i crtač +Comment[ca]=Solucionador i representador gràfic de butxaca d'expressions matemàtiques +Comment[ca@valencia]=Solucionador i representador gràfic de butxaca d'expressions matemàtiques +Comment[cs]=Kapesní řešitel a souřadnicový zapisovač matematických výrazů +Comment[da]=Lommeregner til at løse og plotte matematiske udtryk +Comment[de]=Mathematischer Taschengleichungslöser und -zeichner +Comment[el]=Φορητός σχεδιαστής και επιλυτής μαθηματικών εκφράσεων +Comment[en_GB]=Pocket Maths Expression Solver and Plotter +Comment[es]=Resuelve y dibuja expresiones matemáticas +Comment[et]=Matemaatiliste avaldiste lahendaja ja joonistaja taskus +Comment[eu]=Sakeleko matematika adierazpenen ebazlea edo marrazlea +Comment[fi]=Matemaattisten yhtälöiden ratkaisut ja kuvaajat mobiililaitteille +Comment[fr]=Traceur et résolveur de poche d'expressions mathématiques +Comment[ga]=Réiteoir agus Breacaire Matamaiticiúil don Phóca +Comment[gl]=Resolve e debuxa expresións matemáticas +Comment[hu]=Zsebszámológép matematikai kifejezések megoldására, görberajzolásra +Comment[it]=Risolutore e disegnatore tascabile di espressioni matematiche +Comment[ja]=ポケット数式ソルバー&プロッタ +Comment[kk]=Математикалық теңеуді шешіп графигін салу +Comment[km]=ឧបករណ៍​គូស​ក្រាហ្វិក និង​កម្មវិធី​ដោះស្រាយ​កន្សោម​​​គណិត​ដែល​ដាក់​តាម​ខ្លួន​បាន​ +Comment[ko]=포켓 수식 계산기와 그래핑 도구 +Comment[lt]=Matematinių reiškinių sprendikas ir grafikų braižiklis +Comment[lv]=Kabatas matemātisko izteiksmju risinātājs un attēlotājs +Comment[nb]=Matematisk uttrykksløser og plotter i lomma +Comment[nds]=Taschenreekner för't Lösen un Utdrucken vun Diagrammen +Comment[nl]=Op zak oplossen en plotten van wiskundige uitdrukkingen +Comment[pl]=Kieszonkowe rozwiązywanie równań i rysowanie wykresów +Comment[pt]=Resolução e Desenho de Expressões Matemáticas Portátil +Comment[pt_BR]=Solucionador e visualizador portátil de expressões matemáticas +Comment[ru]=Карманное решение и построение графиков математических выражений +Comment[sk]=Vreckový riešiteľ a zapisovač matematických výrazov +Comment[sl]=Žepni reševalnik matematičnih enačb in risalnik grafov +Comment[sv]=Lösning och uppritning av matematiska uttryck i fickformat +Comment[tr]=Cep Matematiksel İfade Çözücü ve Çizici +Comment[ug]=كۆچمە ئۈسكۈنىلەر ئۈچۈن ماتېماتىكىلىق ئىپادىلەرنى يېشىش ۋە سىزىش قورالى +Comment[uk]=Кишеньковий розв’язувач математичних рівнянь та графопобудовник +Comment[x-test]=xxPocket Math Expression Solver and Plotterxx +Comment[zh_CN]=口袋数学式解决与绘图工具 +Comment[zh_TW]=行動版數學解題與繪圖 +Exec=kalgebramobile +MimeType=application/x-kalgebra; +Icon=kalgebra +Type=Application +Terminal=false +Categories=Qt;KDE;Education;Math;Science; diff --git a/mobile/kalgebramobile.h b/mobile/kalgebramobile.h new file mode 100644 index 0000000..1566608 --- /dev/null +++ b/mobile/kalgebramobile.h @@ -0,0 +1,60 @@ +/************************************************************************************* + * Copyright (C) 2010 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 KALGEBRAMOBILE_H +#define KALGEBRAMOBILE_H + +#include +#include + +class QModelIndex; +namespace Analitza { + class Variables; + class PlotsModel; +} + +class KAlgebraMobile : public QObject +{ + Q_OBJECT + Q_PROPERTY(Analitza::Variables* variables READ variables NOTIFY variablesChanged) + public: + explicit KAlgebraMobile(QObject* parent=0); + + static KAlgebraMobile* self(); + void notifyVariablesChanged() { variablesChanged(); } + + public slots: + Analitza::PlotsModel* functionsModel(); + Analitza::Variables* variables() const; + + private slots: + void functionRemoved(const QModelIndex& parent, int start, int end); + void functionModified(const QModelIndex& idxA, const QModelIndex& idxB); + void functionInserted(const QModelIndex& parent, int start, int end); + + signals: + void variablesChanged(); + + private: + static KAlgebraMobile* s_self; + + Analitza::PlotsModel* m_functionsModel; + Analitza::Variables* m_vars; +}; + +#endif // KALGEBRAMOBILE_H diff --git a/mobile/kalgebramobileharmattan.desktop b/mobile/kalgebramobileharmattan.desktop new file mode 100644 index 0000000..2c23dfd --- /dev/null +++ b/mobile/kalgebramobileharmattan.desktop @@ -0,0 +1,150 @@ +[Desktop Entry] +Name=KAlgebra +Name[ast]=KAlgebra +Name[bg]=KAlgebra +Name[bs]=Kalgebra +Name[ca]=KAlgebra +Name[ca@valencia]=KAlgebra +Name[cs]=KAlgebra +Name[csb]=KAlgebra +Name[da]=KAlgebra +Name[de]=KAlgebra +Name[el]=KAlgebra +Name[en_GB]=KAlgebra +Name[eo]=KAlgebra +Name[es]=KAlgebra +Name[et]=KAlgebra +Name[eu]=KAlgebra +Name[fi]=KAlgebra +Name[fr]=KAlgebra +Name[ga]=KAlgebra +Name[gl]=KAlgebra +Name[gu]=KAlgebra +Name[he]=KAlgebra +Name[hi]=के-अलजेब्रा +Name[hne]=के-अलजेब्रा +Name[hr]=KAlgebra +Name[hu]=KAlgebra +Name[is]=KAlgebra +Name[it]=KAlgebra +Name[ja]=KAlgebra +Name[kk]=KAlgebra +Name[km]=KAlgebra +Name[ko]=KAlgebra +Name[lt]=KAlgebra +Name[lv]=KAlgebra +Name[ml]=കെ-ആള്‍ജിബ്ര +Name[mr]=के-एल्जिब्रा +Name[nb]=KAlgebra +Name[nds]=KAlgebra +Name[ne]=केडीई बीजगणित +Name[nl]=KAlgebra +Name[nn]=KAlgebra +Name[pa]=ਕੇ-ਐਲਜਬਰਾ +Name[pl]=KAlgebra +Name[pt]=KAlgebra +Name[pt_BR]=KAlgebra +Name[ro]=KAlgebra +Name[ru]=KAlgebra +Name[si]=KAlgebra +Name[sk]=KAlgebra +Name[sl]=KAlgebra +Name[sv]=Kalgebra +Name[te]=కె అల్జీబ్రా +Name[tr]=KAlgebra +Name[ug]=KAlgebra +Name[uk]=KАлгебра +Name[x-test]=xxKAlgebraxx +Name[zh_CN]=KAlgebra +Name[zh_TW]=數學_KAlgebra +GenericName=Pocket Graph Calculator +GenericName[ast]=Calculadora gráfica de bolsiellu +GenericName[bg]=Джобен графичен калкулатор +GenericName[bs]=Džepni graf kalkulator +GenericName[ca]=Calculadora gràfica de butxaca +GenericName[ca@valencia]=Calculadora gràfica de butxaca +GenericName[cs]=Kapesní grafická kalkulačka +GenericName[da]=Graflommeregner +GenericName[de]=Graphen-Taschenrechner +GenericName[el]=Φορητός γραφικός υπολογιστής +GenericName[en_GB]=Pocket Graph Calculator +GenericName[es]=Calculadora gráfica de bolsillo +GenericName[et]=Graafikute arvutaja taskus +GenericName[eu]=Sakeleko grafikoen kalkulagailua +GenericName[fi]=Graafinen laskin mobiililaitteille +GenericName[fr]=Calculatrice graphique de poche +GenericName[ga]=Áireamhán Grafach Póca +GenericName[gl]=Calculadora gráfica de peto +GenericName[hu]=Zsebszámológép +GenericName[it]=Calcolatrice grafica tascabile +GenericName[ja]=ポケットグラフ計算機 +GenericName[kk]=Ықшам график калькуляторы +GenericName[km]=ម៉ាស៊ីន​គិត​លេខ​ក្រាហ្វិក​ដែល​ដាក់​តាម​ខ្លួន​បាន +GenericName[ko]=포켓 그래핑 계산기 +GenericName[lt]=Kišeninis grafinis skaičiuotuvas +GenericName[lv]=Kabatas grafiskais kalkulators +GenericName[mr]=पाकिट आलेख गणकयंत्र +GenericName[nb]=Grafikk-lommekalkulator +GenericName[nds]=Taschenreekner för Diagrammen +GenericName[nl]=Zakrekenmachine met grafieken +GenericName[pa]=ਪਾਕਟ ਗਰਾਫ਼ ਕੈਲਕੂਲੇਟਰ +GenericName[pl]=Kieszonkowy kalkulator graficzny +GenericName[pt]=Calculadora Gráfica Portátil +GenericName[pt_BR]=Calculadora gráfica portátil +GenericName[ru]=Карманный графический калькулятор +GenericName[sk]=Vrecková grafická kalkulačka +GenericName[sl]=Žepno računalo z grafi +GenericName[sv]=Grafminiräknare +GenericName[te]=జేబులొ పట్టే రేఖాచిత్రం గనన యంత్రము +GenericName[tr]=Cep Grafik Hesap Makinesi +GenericName[uk]=Кишеньковий графічний калькулятор +GenericName[x-test]=xxPocket Graph Calculatorxx +GenericName[zh_CN]=口袋图形计算器 +GenericName[zh_TW]=行動版圖形計算器 +Comment=Pocket Math Expression Solver and Plotter +Comment[bg]=Джобен инструмент за решаване на математически задачи +Comment[bs]=Matematski sistem za rješavanje i crtač +Comment[ca]=Solucionador i representador gràfic de butxaca d'expressions matemàtiques +Comment[ca@valencia]=Solucionador i representador gràfic de butxaca d'expressions matemàtiques +Comment[cs]=Kapesní řešitel a souřadnicový zapisovač matematických výrazů +Comment[da]=Lommeregner til at løse og plotte matematiske udtryk +Comment[de]=Mathematischer Taschengleichungslöser und -zeichner +Comment[el]=Φορητός σχεδιαστής και επιλυτής μαθηματικών εκφράσεων +Comment[en_GB]=Pocket Maths Expression Solver and Plotter +Comment[es]=Resuelve y dibuja expresiones matemáticas +Comment[et]=Matemaatiliste avaldiste lahendaja ja joonistaja taskus +Comment[eu]=Sakeleko matematika adierazpenen ebazlea edo marrazlea +Comment[fi]=Matemaattisten yhtälöiden ratkaisut ja kuvaajat mobiililaitteille +Comment[fr]=Traceur et résolveur de poche d'expressions mathématiques +Comment[ga]=Réiteoir agus Breacaire Matamaiticiúil don Phóca +Comment[gl]=Resolve e debuxa expresións matemáticas +Comment[hu]=Zsebszámológép matematikai kifejezések megoldására, görberajzolásra +Comment[it]=Risolutore e disegnatore tascabile di espressioni matematiche +Comment[ja]=ポケット数式ソルバー&プロッタ +Comment[kk]=Математикалық теңеуді шешіп графигін салу +Comment[km]=ឧបករណ៍​គូស​ក្រាហ្វិក និង​កម្មវិធី​ដោះស្រាយ​កន្សោម​​​គណិត​ដែល​ដាក់​តាម​ខ្លួន​បាន​ +Comment[ko]=포켓 수식 계산기와 그래핑 도구 +Comment[lt]=Matematinių reiškinių sprendikas ir grafikų braižiklis +Comment[lv]=Kabatas matemātisko izteiksmju risinātājs un attēlotājs +Comment[nb]=Matematisk uttrykksløser og plotter i lomma +Comment[nds]=Taschenreekner för't Lösen un Utdrucken vun Diagrammen +Comment[nl]=Op zak oplossen en plotten van wiskundige uitdrukkingen +Comment[pl]=Kieszonkowe rozwiązywanie równań i rysowanie wykresów +Comment[pt]=Resolução e Desenho de Expressões Matemáticas Portátil +Comment[pt_BR]=Solucionador e visualizador portátil de expressões matemáticas +Comment[ru]=Карманное решение и построение графиков математических выражений +Comment[sk]=Vreckový riešiteľ a zapisovač matematických výrazov +Comment[sl]=Žepni reševalnik matematičnih enačb in risalnik grafov +Comment[sv]=Lösning och uppritning av matematiska uttryck i fickformat +Comment[tr]=Cep Matematiksel İfade Çözücü ve Çizici +Comment[ug]=كۆچمە ئۈسكۈنىلەر ئۈچۈن ماتېماتىكىلىق ئىپادىلەرنى يېشىش ۋە سىزىش قورالى +Comment[uk]=Кишеньковий розв’язувач математичних рівнянь та графопобудовник +Comment[x-test]=xxPocket Math Expression Solver and Plotterxx +Comment[zh_CN]=口袋数学式解决与绘图工具 +Comment[zh_TW]=行動版數學解題與繪圖 +Exec=/opt/kalgebra/bin/kalgebra_hack.sh +MimeType=application/x-kalgebra; +Icon=kalgebraharmattan +Type=Application +Terminal=false +Categories=Qt;KDE;Education;Math; diff --git a/mobile/main.cpp b/mobile/main.cpp new file mode 100644 index 0000000..82dcca5 --- /dev/null +++ b/mobile/main.cpp @@ -0,0 +1,81 @@ +/************************************************************************************* + * Copyright (C) 2010 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 +#include +#include +#include + +#ifdef KDECOMPONENTS +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "kalgebramobile.h" + +int main(int argc, char *argv[]) +{ +// KAboutData about("kalgebra", 0, ki18n(("KAlgebra Mobile")), "0.10", ki18n("A portable calculator"), +// KAboutData::License_GPL, ki18n("(C) 2006-2010 Aleix Pol Gonzalez")); +// about.addAuthor( ki18n("Aleix Pol Gonzalez"), KLocalizedString(), "aleixpol@kde.org" ); +// KCmdLineArgs::init(argc, argv, &about); + QApplication app(argc, argv); + app.setApplicationName("kalgebramobile"); + app.setWindowIcon(QIcon::fromTheme("kalgebra")); + + KAlgebraMobile widget; + + QDeclarativeView view; + view.setWindowTitle("KAlgebra Mobile"); + view.setResizeMode(QDeclarativeView::SizeRootObjectToView); + view.engine()->rootContext()->setContextProperty("app", &widget); + +// KGlobal::dirs()->addResourceDir("appdata", PREFIX "/share/apps"); + +#ifdef KDECOMPONENTS + KDeclarative kdeclarative; + kdeclarative.setDeclarativeEngine(view.engine()); + kdeclarative.initialize(); + //binds things like kconfig and icons + kdeclarative.setupBindings(); +#endif + + QString main = KStandardDirs::locate("appdata", "plugins/widgets/KAlgebraMobile.qml"); +// QString main = KStandardDirs::locate("appdata", "plugins/Tables.qml"); + QDir dir = QFileInfo(main).dir(); + dir.cdUp(); + + view.engine()->addImportPath(dir.path()); + view.setSource(main); + + #if defined(__arm__) && !defined(ANDROID) + view.showFullScreen(); + #else + view.resize(view.initialSize().width(), view.initialSize().height()); + view.show(); + #endif + + return app.exec(); +} diff --git a/mobile/plugins/About.qml b/mobile/plugins/About.qml new file mode 100644 index 0000000..9f0dff8 --- /dev/null +++ b/mobile/plugins/About.qml @@ -0,0 +1,57 @@ +import QtQuick 1.0 +import org.kde.analitza 1.0 +import widgets 1.0 + +KAlgebraPage +{ + Column { + anchors.margins: 20 + anchors.fill: parent + spacing: 20 + + Image { + source: "qrc:/kalgebra.svgz" + anchors.horizontalCenter: parent.horizontalCenter + } + + Label { + anchors.left: parent.left + anchors.right: parent.right + + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignHCenter + text: ("KAlgebra is brought to you by the lovely community of KDE and KDE Edu from a Free Software envionment.") + } + + Label { + anchors.left: parent.left + anchors.right: parent.right + + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignHCenter + text: ("In case you want to learn more about KAlgebra, you can find more information "+ + "in the official site and in "+ + "the users wiki.
"+ + "If you have any problem with your software, please report it to our bug tracker.") + } + + Label { + anchors.left: parent.left + anchors.right: parent.right + + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignHCenter + text: "Aleix Pol Gonzalez <aleixpol@kde.org>" + } + + Image { + source: "qrc:/kde-edu-logo.png" + anchors.horizontalCenter: parent.horizontalCenter + + MouseArea { + anchors.fill: parent + onClicked: Qt.openUrlExternally("http://edu.kde.org") + } + } + } +} \ No newline at end of file diff --git a/mobile/plugins/CMakeLists.txt b/mobile/plugins/CMakeLists.txt new file mode 100644 index 0000000..79eefad --- /dev/null +++ b/mobile/plugins/CMakeLists.txt @@ -0,0 +1,8 @@ +add_subdirectory(widgets) + +install( FILES + Console.qml Plot2D.qml Tables.qml + About.qml VariablesView.qml + kalgebraconsole.desktop kalgebraplot2d.desktop kalgebratables.desktop kalgebraabout.desktop kalgebravariables.desktop + DESTINATION ${DATA_INSTALL_DIR}/kalgebramobile/plugins/ +) diff --git a/mobile/plugins/Console.qml b/mobile/plugins/Console.qml new file mode 100644 index 0000000..1349aeb --- /dev/null +++ b/mobile/plugins/Console.qml @@ -0,0 +1,59 @@ +import QtQuick 1.0 +import org.kde.analitza 1.0 +import widgets 1.0 + +KAlgebraPage +{ + ListModel { id: itemModel } + + ExpressionInput { + id: input + focus: true + + Analitza { + id: a + variables: app.variables + } + + Keys.onReturnPressed: { + var res = a.execute(text) + + var toadd = "" + if(!a.isCorrect) + toadd = "Error: " + (res ? res : a.errors) + else + toadd = text + " = " + res.expression + + itemModel.insert(0, { result: toadd, resultsInput: text }) + input.selectAll() + view.currentIndex = 0 + } + + width: parent.width + anchors.top: parent.top + } + + SimpleListView { + model: itemModel + id: view + + delegate: Label { + text: result + MouseArea { + anchors.fill: parent + onClicked: { + input.text = resultsInput + input.selectAll() + input.focus = true + } + } + } + + anchors { + top: input.bottom + bottom: parent.bottom + left: parent.left + right: parent.right + } + } +} \ No newline at end of file diff --git a/mobile/plugins/Plot2D.qml b/mobile/plugins/Plot2D.qml new file mode 100644 index 0000000..828b979 --- /dev/null +++ b/mobile/plugins/Plot2D.qml @@ -0,0 +1,54 @@ +import QtQuick 1.0 +import org.kde.analitza 1.0 +import widgets 1.0 + +KAlgebraPage +{ + anchors.margins: 0 + + Row { + id: controls + spacing: 10 + + width: parent.width + ExpressionInput { + id: input + width: parent.width-exec.width + anchors.verticalCenter: exec.verticalCenter + text: "sin x" + focus: true + Component.onCompleted: selectAll() + + Keys.onReturnPressed: view.addFunction(input.text, app.variables) + } + + Button { + id: exec + text: "Clear" + width: 100 + + onClicked: { + app.functionsModel().clear() + view.resetViewport() + input.focus = true + } + } + } + + + Rectangle { + width: parent.width + anchors { + fill: parent + topMargin: controls.height + } + height: 200 + color: 'white' + + Graph2D { + id: view + anchors.fill: parent + model: app.functionsModel() + } + } +} diff --git a/mobile/plugins/Tables.qml b/mobile/plugins/Tables.qml new file mode 100644 index 0000000..2583029 --- /dev/null +++ b/mobile/plugins/Tables.qml @@ -0,0 +1,88 @@ +import QtQuick 1.0 +import org.kde.analitza 1.0 +import widgets 1.0 + +KAlgebraPage +{ + ListModel { id: resultsModel } + Analitza { + id: a + variables: app.variables + } + + function calculateTable() { + resultsModel.clear(); + + var tmp = a.unusedVariableName() + var ret = a.insertVariable(tmp, a.dependenciesToLambda(input.text)) + var ffrom=from.value, fto=to.value, fstep=step.value; +// console.log("chancho (" + ffrom + ", " + fto + " : " + fstep + ") " + ret); + if((fto-ffrom>0)!=(fstep>0)) { + fstep *= -1; + step = fstep + } +// console.log("chancho2 (" + ffrom + ", " + fto + " : " + fstep + ") " + ret); + + if(fstep==0) { + resultsModel.append( { element: "Errors: The step can't be 0" } ); + } else if(!a.isCorrect) { + if(ret) + resultsModel.append( { element: "Errors: "+ret } ); + else + resultsModel.append( { element: "Errors: "+a.errors } ); + } else { + for (var i=ffrom; i<=fto && a.isCorrect; i+=fstep) { + var args = new Array(); + args[0]=i; + // console.log("!!! " + i); + var expr = a.executeFunc(tmp, args); + resultsModel.append( { element: i +" = "+ expr.expression } ); + } + } + + a.removeVariable(tmp); + } + + Column { + id: inputcol + + anchors { + top: parent.top + left: parent.left + right: parent.right + } + spacing: 10 + + Grid { + id: ins + columns: 2 + spacing: 5 + width: parent.width + + Label { text: "Input:" } ExpressionInput { id: input; text: "sin x"; width: ins.width-input.x-5; onAccepted: calculateTable() } + Label { text: "From:" } RealInput { id: from; value: 0; width: ins.width-from.x-5; onAccepted: calculateTable() } + Label { text: "To:" } RealInput { id: to; value: 10; width: ins.width-to.x-5; onAccepted: calculateTable() } + Label { text: "Step:" } RealInput { id: step; value: 1; width: ins.width-step.x-5; onAccepted: calculateTable() } + } + + Button { + text: "Go!" + + onClicked: calculateTable() + } + } + + SimpleListView { + width: parent.width + anchors { + top: inputcol.bottom + bottom: parent.bottom + topMargin: 5 + } + currentIndex: -1 + + model: resultsModel + role: "element" + title: "Results:" + } +} diff --git a/mobile/plugins/VariablesView.qml b/mobile/plugins/VariablesView.qml new file mode 100644 index 0000000..71b687b --- /dev/null +++ b/mobile/plugins/VariablesView.qml @@ -0,0 +1,13 @@ +import QtQuick 1.0 +import org.kde.analitza 1.0 +import widgets 1.0 + +KAlgebraPage +{ + SimpleListView { + anchors.fill: parent + model: VariablesModel { variables: app.variables } + delegate: Label { text: display+": "+toolTip } + currentIndex: -1 + } +} \ No newline at end of file diff --git a/mobile/plugins/kalgebraabout.desktop b/mobile/plugins/kalgebraabout.desktop new file mode 100644 index 0000000..906ee9e --- /dev/null +++ b/mobile/plugins/kalgebraabout.desktop @@ -0,0 +1,53 @@ +[Desktop Entry] +Icon=help-about +Type=Service +ServiceTypes=KAlgebra/Script + +Name=About KAlgebra +Name[bg]=Относно KAlgebra +Name[bs]=O programu KAlgebra +Name[ca]=Quant a KAlgebra +Name[ca@valencia]=Quant a KAlgebra +Name[cs]=O aplikaci KAlgebra +Name[da]=Om KAlgebra +Name[de]=Über KAlgebra +Name[el]=Σχετικά με το KAlgebra +Name[en_GB]=About KAlgebra +Name[es]=Acerca de KAlgebra +Name[et]=Teave KAlgebra kohta +Name[fi]=Tietoja KAlgebrasta +Name[fr]=À propos de KAlgebra +Name[ga]=Maidir le KAlgebra +Name[gl]=Sobre o KAlgebra +Name[hu]=A KAlgebra névjegye +Name[it]=Informazioni su KAlgebra +Name[ja]=KAlgebra について +Name[kk]=KAlgebra туралы +Name[km]=អំពី KAlgebra +Name[ko]=KAlgebra 정보 +Name[lt]=Apie KAlgebrą +Name[mr]=के-एल्जिब्रा बद्दल +Name[nb]=Om KAlgebra +Name[nds]=Vertell wat över KAlgebra +Name[nl]=Over KAlgebra +Name[pa]=ਕੇ-ਐਲਜਬਰਾ ਬਾਰੇ +Name[pl]=O KAlgebra +Name[pt]=Acerca do KAlgebra +Name[pt_BR]=Sobre o KAlgebra +Name[ru]=О программе KAlgebra +Name[sk]=O programe KAlgebra +Name[sl]=O KAlgebri +Name[sv]=Om Kalgebra +Name[te]=కె అల్జీబ్రా గురించి +Name[tr]=KAlgebra Hakkında +Name[uk]=Про KAlgebra +Name[x-test]=xxAbout KAlgebraxx +Name[zh_CN]=关于 KAlgebra +Name[zh_TW]=關於 KAlgebra + +X-KDE-PluginInfo-Author=Aleix Pol Gonzalez +X-KDE-PluginInfo-Email=aleixpol@kde.org +X-KDE-PluginInfo-Name=About.qml +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-License=GPL +X-KAlgebra-Priority=-10 diff --git a/mobile/plugins/kalgebraconsole.desktop b/mobile/plugins/kalgebraconsole.desktop new file mode 100644 index 0000000..3f1e8fc --- /dev/null +++ b/mobile/plugins/kalgebraconsole.desktop @@ -0,0 +1,97 @@ +[Desktop Entry] +Icon=utilities-terminal +Type=Service +ServiceTypes=KAlgebra/Script + +Name=Console +Name[bg]=Конзола +Name[bs]=Konzola +Name[ca]=Consola +Name[ca@valencia]=Consola +Name[cs]=Konzole +Name[da]=Konsol +Name[de]=Konsole +Name[el]=Κονσόλα +Name[en_GB]=Console +Name[es]=Consola +Name[et]=Konsool +Name[eu]=Kontsola +Name[fi]=Konsoli +Name[fr]=Console +Name[ga]=Consól +Name[gl]=Consola +Name[hu]=Konzol +Name[it]=Console +Name[ja]=コンソール +Name[kk]=Консоль +Name[km]=កុងសូល +Name[ko]=콘솔 +Name[lt]=Pultas +Name[lv]=Konsole +Name[mr]=कन्सोल +Name[nb]=Konsoll +Name[nds]=Konsool +Name[nl]=Console +Name[pa]=ਕਨਸੋਲ +Name[pl]=Konsola +Name[pt]=Consola +Name[pt_BR]=Console +Name[ru]=Консоль +Name[sk]=Konzola +Name[sl]=Konzola +Name[sv]=Terminal +Name[tr]=Konsol +Name[ug]=تىزگىن سۇپا +Name[uk]=Консоль +Name[x-test]=xxConsolexx +Name[zh_CN]=控制台 +Name[zh_TW]=主控台 +Comment=Scientific calculator +Comment[bg]=Научен калкулатор +Comment[bs]=Naučni kalkulator +Comment[ca]=Calculadora científica +Comment[ca@valencia]=Calculadora científica +Comment[cs]=Vědecká kalkulačka +Comment[da]=Videnskabelig regnemaskine +Comment[de]=Wissenschaftlicher Taschenrechner +Comment[el]=Επιστημονικός υπολογιστής +Comment[en_GB]=Scientific calculator +Comment[es]=Calculadora científica +Comment[et]=Teaduslik kalkulaator +Comment[eu]=Kalkulagailu zientifikoa +Comment[fi]=Tieteellinen laskin +Comment[fr]=Calculatrice scientifique +Comment[ga]=Áireamhán eolaíoch +Comment[gl]=Calculadora científica +Comment[hu]=Tudományos számológép +Comment[it]=Calcolatrice scientifica +Comment[ja]=科学計算機 +Comment[kk]=Ғылыми калькулятор +Comment[km]=ម៉ាស៊ីន​គិតលេខ​បែប​វិទ្យាសាស្ត្រ +Comment[ko]=공학용 계산기 +Comment[lt]=Mokslinis skaičiuotuvas +Comment[lv]=Zinātniskais kalkulators +Comment[mr]=शास्त्रीय गणकयंत्र +Comment[nb]=Vitenskapelig kalkulator +Comment[nds]=Wetenschaplich Taschenreekner +Comment[nl]=Wetenschappelijke rekenmachine +Comment[pa]=ਵਿਗਿਆਨਿਕ ਕੈਲਕੂਲੇਟਰ +Comment[pl]=Kalkulator naukowy +Comment[pt]=Calculadora científica +Comment[pt_BR]=Calculadora científica +Comment[ru]=Научный калькулятор +Comment[sk]=Vedecká kalkulačka +Comment[sl]=Znanstveno računalo +Comment[sv]=Vetenskaplig miniräknare +Comment[tr]=Bilimsel hesap makinesi +Comment[uk]=Калькулятор для науковців +Comment[x-test]=xxScientific calculatorxx +Comment[zh_CN]=科学计算器 +Comment[zh_TW]=科學計算機 + +X-KDE-PluginInfo-Author=Aleix Pol Gonzalez +X-KDE-PluginInfo-Email=aleixpol@kde.org +X-KDE-PluginInfo-Name=Console.qml +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-License=GPL +X-KAlgebra-Priority=1000 diff --git a/mobile/plugins/kalgebraplot2d.desktop b/mobile/plugins/kalgebraplot2d.desktop new file mode 100644 index 0000000..d8005e0 --- /dev/null +++ b/mobile/plugins/kalgebraplot2d.desktop @@ -0,0 +1,92 @@ +[Desktop Entry] +Icon=draw-bezier-curves +Type=Service +ServiceTypes=KAlgebra/Script + +Name=Graph 2D +Name[bg]=Двуизмерна графика +Name[bs]=Graf 2D +Name[ca]=Gràfic 2D +Name[ca@valencia]=Gràfic 2D +Name[cs]=Graf 2D +Name[da]=Graph 2D +Name[de]=Graph 2D +Name[el]=Γράφημα 2D +Name[en_GB]=Graph 2D +Name[es]=Gráfico 2D +Name[et]=2D graaf +Name[eu]=2D grafikoa +Name[fi]=2U-kuvaaja +Name[fr]=Graphe 2D +Name[ga]=Graf 2T +Name[gl]=Gráficas 2D +Name[hu]=2D függvény +Name[it]=Grafico 2D +Name[ja]=グラフ 2D +Name[kk]=2D график +Name[km]=ក្រាហ្វិក​ទ្វេមាត្រ +Name[ko]=2차원 그래프 +Name[lv]=Grafiks 2D +Name[mr]=आलेख 2D +Name[nb]=Graf 2D +Name[nds]=2D-Diagramm +Name[nl]=2D-grafiek +Name[pa]=ਗਰਾਫ਼ 2D +Name[pl]=Wykres 2D +Name[pt]=Gráfico 2D +Name[pt_BR]=Gráfico em 2D +Name[ru]=График 2D +Name[sk]=2D Graf +Name[sl]=2D graf +Name[sv]=Graf-2D +Name[te]=2D రేఖాచిత్రం +Name[tr]=Graph 2D +Name[uk]=Двовимірний графік +Name[x-test]=xxGraph 2Dxx +Name[zh_CN]=二维图 +Name[zh_TW]=平面圖形 +Comment=Draws any 2D graph you want +Comment[bg]=Изчертаване на двуизмерна графика +Comment[bs]=Crta svaki 2D graf koji želite +Comment[ca]=Dibuixa qualsevol gràfic 2D que desitgeu +Comment[ca@valencia]=Dibuixa qualsevol gràfic 2D que desitgeu +Comment[cs]=Nakreslí jakýkoliv 2D graf, který si přejete +Comment[da]=Tegner enhver 2D-graf du måtte ønske +Comment[de]=Zeichnet jeden gewünschten 2D-Graphen +Comment[el]=Σχεδιάζει οποιοδήποτε γράφημα 2D επιθυμείτε +Comment[en_GB]=Draws any 2D graph you want +Comment[es]=Dibuja cualquier gráfico 2D que desee +Comment[et]=Suvalise 2D graafi joonistamine +Comment[eu]=Nahi duzun edozein 2D grafiko marraztuko du +Comment[fi]=Piirtää kaksiulotteisia kuvaajia +Comment[fr]=Dessine n'importe quel graphe 2D +Comment[gl]=Debuxa todas as gráficas en 2D que queiras +Comment[hu]=Kirajzolja a kívánt 2D-s függvényt +Comment[it]=Disegna qualsiasi grafico 2D tu voglia +Comment[kk]=Қалаған 2D графигін салу +Comment[km]=គូស​ក្រាហ្វិក​ទ្វេ​មាត្រ​ដែល​អ្នក​ត្រូវ​ការ +Comment[ko]=임의의 2차원 그래프 그리기 +Comment[lv]=Zīmē jebkādu 2D grafiku +Comment[nb]=Tegner den 2D-grafen du vil +Comment[nds]=2D-Diagrammen teken +Comment[nl]=Tekent elke wenselijke 2D-grafiek +Comment[pl]=Rysuje wykres 2D jakikolwiek chcesz +Comment[pt]=Desenha qualquer gráfico 2D que desejar +Comment[pt_BR]=Desenha qualquer gráfico 2D que desejar +Comment[ru]=Рисование любых 2D графиков +Comment[sk]=Nakreslí ľubovoľný 2D graf +Comment[sl]=Nariše poljuben 2D graf +Comment[sv]=Ritar vilken tvådimensionell graf som helst +Comment[te]=మీకు కవాల్సీన 2D రేఖాచిత్రం గీస్తది +Comment[tr]=İstediğiniz herhangi bir 2D grafiği çizer +Comment[uk]=Креслить будь-які двовимірні графіки +Comment[x-test]=xxDraws any 2D graph you wantxx +Comment[zh_CN]=绘制想要的二维图 +Comment[zh_TW]=讓您繪製平面圖形 + +X-KDE-PluginInfo-Author=Aleix Pol Gonzalez +X-KDE-PluginInfo-Email=aleixpol@kde.org +X-KDE-PluginInfo-Name=Plot2D.qml +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-License=GPL +X-KAlgebra-Priority=100 diff --git a/mobile/plugins/kalgebratables.desktop b/mobile/plugins/kalgebratables.desktop new file mode 100644 index 0000000..6bbafac --- /dev/null +++ b/mobile/plugins/kalgebratables.desktop @@ -0,0 +1,90 @@ +[Desktop Entry] +Icon=kspread +Type=Service +ServiceTypes=KAlgebra/Script + +Name=Value Tables +Name[bg]=Таблици със стойности +Name[bs]=Tabele vrijednosti +Name[ca]=Taules de valors +Name[ca@valencia]=Taules de valors +Name[cs]=Tabulky hodnot +Name[da]=Værditabeller +Name[de]=Wertetabellen +Name[el]=Πίνακες τιμών +Name[en_GB]=Value Tables +Name[es]=Tablas de valores +Name[et]=Väärtustabelid +Name[eu]=Balio taulak +Name[fi]=Arvotaulukot +Name[fr]=Tableaux de valeurs +Name[gl]=Táboas de valores +Name[hu]=Értéktáblázatok +Name[it]=Tabelle di valori +Name[kk]=Мән кестелері +Name[km]=តារាង​តម្លៃ +Name[ko]=값 테이블 +Name[lt]=Reikšmių lentelės +Name[lv]=Vērtību tabulas +Name[mr]=मूल्य कोष्टके +Name[nb]=Verditabeller +Name[nds]=Weertentabellen +Name[nl]=Waardetabellen +Name[pl]=Tablice wartości +Name[pt]=Tabelas de Valores +Name[pt_BR]=Tabelas de valores +Name[ru]=Таблицы значений +Name[sk]=Tabuľky hodnôt +Name[sl]=Razpredelnice vrednosti +Name[sv]=Värdetabeller +Name[te]=విలువ పట్టికలు +Name[tr]=Değer Tabloları +Name[uk]=Таблиці значень +Name[x-test]=xxValue Tablesxx +Name[zh_CN]=数值表 +Name[zh_TW]=數值表 +Comment=Easily create value tables +Comment[bs]=Jednostavno kreiranje tablica vrijednosti +Comment[ca]=Crea taules de valors de forma senzilla +Comment[ca@valencia]=Crea taules de valors de forma senzilla +Comment[cs]=Jednoduše vytvářejte tabulky hodnot +Comment[da]=Nem oprettelse af værditabeller +Comment[de]=Wertetabellen einfach erstellen +Comment[el]=Δημιουργείστε εύκολα πίνακες τιμών +Comment[en_GB]=Easily create value tables +Comment[es]=Proporciona una miniaplicación que le permite crear tablas de valores fácilmente +Comment[et]=Lihtne väärtustabelite loomine +Comment[eu]=Sortu balio taulak era errazean +Comment[fi]=Luo arvotaulukoita helposti +Comment[fr]=Crée facilement des tableaux de valeurs +Comment[gl]=Crea facilmente táboas de valores +Comment[hu]=Értéktáblázatok egyszerű létrehozása +Comment[it]=Crea facilmente tabelle di valori +Comment[kk]=Мәндерді оңай кестелеу +Comment[km]=ងាយស្រួល​បង្កើត​តារាង​តម្លៃ +Comment[ko]=값 테이블 쉽게 만들기 +Comment[lv]=Vienkārši izveido vērtību tabulas +Comment[mr]=सहज मूल्य कोष्टके निर्माण करा +Comment[nb]=Lag verditabeller lett +Comment[nds]=Weertentabellen opstellen +Comment[nl]=gemakkelijk waardetabellen aanmaken +Comment[pl]=Łatwo twórz tabele wartości +Comment[pt]=Criar facilmente tabelas de valores +Comment[pt_BR]=Criar facilmente tabelas de valores +Comment[ru]=Простое создание таблицы значений +Comment[sk]=Jednoducho vytvoriť tabuľky hodnôt +Comment[sl]=Enostavno ustvarite razpredelnice vrednosti +Comment[sv]=Skapa enkelt värdetabeller +Comment[te]=సులభంగా విలువ పట్టికలు సృష్టించంది +Comment[tr]=Kolayca değer tabloları oluşturun +Comment[uk]=Спрощує створення таблиць значень +Comment[x-test]=xxEasily create value tablesxx +Comment[zh_CN]=方便的创建数值表 +Comment[zh_TW]=輕易建立數值表格 + +X-KDE-PluginInfo-Author=Aleix Pol Gonzalez +X-KDE-PluginInfo-Email=aleixpol@kde.org +X-KDE-PluginInfo-Name=Tables.qml +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-License=GPL +X-KAlgebra-Priority=10 diff --git a/mobile/plugins/kalgebravariables.desktop b/mobile/plugins/kalgebravariables.desktop new file mode 100644 index 0000000..430185c --- /dev/null +++ b/mobile/plugins/kalgebravariables.desktop @@ -0,0 +1,89 @@ +[Desktop Entry] +Icon=document-properties +Type=Service +ServiceTypes=KAlgebra/Script + +Name=Variables +Name[bg]=Променливи +Name[bs]=Promjenljive +Name[ca]=Variables +Name[ca@valencia]=Variables +Name[cs]=Proměnné +Name[da]=Variabler +Name[de]=Variablen +Name[el]=Μεταβλητές +Name[en_GB]=Variables +Name[es]=Variables +Name[et]=Muutujad +Name[fi]=Muuttujat +Name[fr]=Variables +Name[gl]=Variábeis +Name[hu]=Változók +Name[it]=Variabili +Name[ja]=変数 +Name[kk]=Айнымалылар +Name[km]=អថេរ +Name[ko]=변수 +Name[lt]=Kintamieji +Name[lv]=Mainīgie +Name[mr]=व्हेरिएबल्स +Name[nb]=Variabler +Name[nds]=Variabeln +Name[nl]=Variabelen +Name[pa]=ਵੇਰੀਬਲ +Name[pl]=Zmienne +Name[pt]=Variáveis +Name[pt_BR]=Variáveis +Name[ru]=Переменные +Name[sk]=Premenné +Name[sl]=Spremenljivke +Name[sv]=Variabler +Name[te]=చరరాశులు +Name[tr]=Değişkenler +Name[ug]=ئۆزگەرگۈچىلەر +Name[uk]=Змінні +Name[x-test]=xxVariablesxx +Name[zh_CN]=变量 +Name[zh_TW]=變數 +Comment=Displays the stored values +Comment[bs]=Prikaz smještenih vrijednosti +Comment[ca]=Mostra els valors desats +Comment[ca@valencia]=Mostra els valors guardats +Comment[cs]=Zobrazuje uložené hodnoty +Comment[da]=Vis de lagrede værdier +Comment[de]=Zeigt die gespeicherten Werte an +Comment[el]=Εμφανίζει τις αποθηκευμένες τιμές +Comment[en_GB]=Displays the stored values +Comment[es]=Muestra los valores almacenados +Comment[et]=Salvestatud väärtuste näitamine +Comment[fi]=Näyttää tallennetut arvot +Comment[fr]=Affiche les valeurs enregistrées +Comment[gl]=Mostra os valores almacenados +Comment[hu]=Megjeleníti a tárolt értékeket +Comment[it]=Mostra i valori memorizzati +Comment[kk]=Сақталған мәндерін көрсетеді +Comment[km]=បង្ហាញ​តម្លៃ​ដែល​បាន​រក្សាទុក +Comment[ko]=저장된 값 표시 +Comment[nb]=Viser de lagrede verdiene +Comment[nds]=Wiest de sekerten Weerten +Comment[nl]=De opgeslagen waarden tonen +Comment[pl]=Wyświetla zapamiętane wartości +Comment[pt]=Mostra os valores guardados +Comment[pt_BR]=Mostra os valores armazenados +Comment[ru]=Отображает сохраненные значения +Comment[sk]=Zobrazí uložené hodnoty +Comment[sl]=Prikaže shranjene vrednosti +Comment[sv]=Visar de lagrade värdena +Comment[te]=నిల్వ విలువలు ప్రదర్శిస్తుంది +Comment[tr]=Saklanan değerleri görüntüler +Comment[uk]=Показує збережені значення +Comment[x-test]=xxDisplays the stored valuesxx +Comment[zh_CN]=显示存储的值 +Comment[zh_TW]=顯示已儲存的值 + +X-KDE-PluginInfo-Author=Aleix Pol Gonzalez +X-KDE-PluginInfo-Email=aleixpol@kde.org +X-KDE-PluginInfo-Name=VariablesView.qml +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-License=GPL +X-KAlgebra-Priority=0 diff --git a/mobile/plugins/resources/kde-edu-logo.png b/mobile/plugins/resources/kde-edu-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f652c4003b4455cba1c16171ba47689aee07f927 GIT binary patch literal 16041 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\n%2", title, subtitle) + } + } + + onClicked: goToPage(model.path, decoration) + } + + model: PluginsModel { id: plugins } + } + } + + tools: ToolBarLayout {} + } + + ToolBar { + id: toolBar + z: 10 + width: parent.width + height: 40 + anchors.top: parent.top + + + Image { + anchors { + left: parent.left + verticalCenter: parent.verticalCenter + leftMargin: 5 + } + + source: "qrc:/kde-edu-logo.png" + height: parent.height + fillMode: Image.PreserveAspectFit + smooth: true + + MouseArea { + anchors.fill: parent + onClicked: Qt.openUrlExternally("http://edu.kde.org") + } + } + } + + PageStack + { + id: pageStack + width: parent.width + anchors { + top: toolBar.bottom + bottom: parent.bottom + } + + initialPage: init + + toolBar: toolBar + } +} diff --git a/mobile/plugins/widgets/kde/KAlgebraPage.qml b/mobile/plugins/widgets/kde/KAlgebraPage.qml new file mode 100644 index 0000000..82931a3 --- /dev/null +++ b/mobile/plugins/widgets/kde/KAlgebraPage.qml @@ -0,0 +1,18 @@ +import org.kde.plasma.components 0.1 + +Page { + id: page + height: 100 + width: 100 + + anchors.margins: 10 + + tools: ToolBarLayout { + ToolButton { + iconSource: "go-previous" + text: i18n("Back") + + onClicked: page.pageStack.pop() + } + } +} diff --git a/mobile/plugins/widgets/kde/Keyboard.qml b/mobile/plugins/widgets/kde/Keyboard.qml new file mode 100644 index 0000000..10b19a7 --- /dev/null +++ b/mobile/plugins/widgets/kde/Keyboard.qml @@ -0,0 +1,45 @@ +import QtQuick 1.0 + +Row { + signal clear + + Grid { + id:nums + columns: 3 + rows: 4 + height: 300 + anchors.top: parent.top + anchors.bottom: parent.bottom + + signal newInput(string text) + signal deleteChar + + CalcButton { text: "1" } + CalcButton { text: "2" } + CalcButton { text: "3" } + CalcButton { text: "4" } + CalcButton { text: "5" } + CalcButton { text: "6" } + CalcButton { text: "7" } + CalcButton { text: "8" } + CalcButton { text: "9" } + CalcButton { text: "." } + CalcButton { text: "0" } + } + + Flow { + flow: Flow.TopToBottom + + CalcButton { text: "-" } + CalcButton { text: "+" } + CalcButton { text: "*" } + CalcButton { text: "/" } + CalcButton { text: "(" } + CalcButton { text: ")" } + + Button { text: "AC"; onClicked: clear();} + + anchors.bottom: nums.bottom + anchors.top: nums.top + } +} \ No newline at end of file diff --git a/mobile/plugins/widgets/kde/Label.qml b/mobile/plugins/widgets/kde/Label.qml new file mode 100644 index 0000000..41af19f --- /dev/null +++ b/mobile/plugins/widgets/kde/Label.qml @@ -0,0 +1,6 @@ +import org.kde.plasma.components 0.1 +import QtQuick 1.1 + +Label { + onLinkActivated: Qt.openUrlExternally(link) +} diff --git a/mobile/plugins/widgets/kde/RealInput.qml b/mobile/plugins/widgets/kde/RealInput.qml new file mode 100644 index 0000000..900ed94 --- /dev/null +++ b/mobile/plugins/widgets/kde/RealInput.qml @@ -0,0 +1,18 @@ +import QtQuick 1.1 +import org.kde.plasma.components 0.1 + +TextField +{ + property double value: parseFloat(text) + property alias minimumValue: realvalidator.bottom + property alias maximumValue: realvalidator.top + inputMethodHints: Qt.ImhDigitsOnly | Qt.ImhNoPredictiveText + + text: value.toString() + + validator: DoubleValidator { id: realvalidator } + + onTextChanged: value=parseFloat(text) + + Component.onCompleted: text=value +} \ No newline at end of file diff --git a/mobile/plugins/widgets/kde/SimpleListView.qml b/mobile/plugins/widgets/kde/SimpleListView.qml new file mode 100644 index 0000000..ce441ef --- /dev/null +++ b/mobile/plugins/widgets/kde/SimpleListView.qml @@ -0,0 +1,26 @@ +import org.kde.plasma.components 0.1 +import QtQuick 1.0 + +ListView +{ + id: scrollList + property string role: "" + property string title: "" + delegate: Label { text: model[role] } + header: Label { visible: ListView.view.title!=""; text: ListView.view.title } + clip: true + + ScrollBar { + id: scrollBar + orientation: Qt.Vertical + flickableItem: scrollList + stepSize: 40 + scrollButtonInterval: 50 + anchors { + top: scrollList.top + right: scrollList.right + bottom: scrollList.bottom + } + } +} + diff --git a/mobile/plugins/widgets/kde/ToolTip.qml b/mobile/plugins/widgets/kde/ToolTip.qml new file mode 100644 index 0000000..7744f85 --- /dev/null +++ b/mobile/plugins/widgets/kde/ToolTip.qml @@ -0,0 +1,13 @@ +import org.kde.plasma.components 0.1 + +Rectangle { + id: tooltip + property string text + Text { + text: tooltip.text + + anchors.fill: parent + } + + color: "blue" +} \ No newline at end of file diff --git a/mobile/plugins/widgets/neutral/Button.qml b/mobile/plugins/widgets/neutral/Button.qml new file mode 100644 index 0000000..0bd35ae --- /dev/null +++ b/mobile/plugins/widgets/neutral/Button.qml @@ -0,0 +1,31 @@ +import QtQuick 1.1 + +Item { + property alias text: display.text + signal clicked + width: display.width+15 + height: display.height+15 + property alias implicitWidth: display.implicitWidth + property alias implicitHeight: display.implicitHeight + + SystemPalette { id: palette } + + Rectangle { + radius: 5 + opacity: 0.3 + anchors.fill: parent + anchors.margins: 2 + color: palette.button + border.width: buttonArea.containsMouse ? 5 : 1 + border.color: palette.buttonText + } + + Text { id: display; anchors.centerIn: parent; color: palette.buttonText } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + id: buttonArea + onClicked: parent.clicked() + } +} diff --git a/mobile/plugins/widgets/neutral/CMakeLists.txt b/mobile/plugins/widgets/neutral/CMakeLists.txt new file mode 100644 index 0000000..82fa6d8 --- /dev/null +++ b/mobile/plugins/widgets/neutral/CMakeLists.txt @@ -0,0 +1,7 @@ +install( FILES + Label.qml Button.qml CalcButton.qml ExpressionInput.qml + RealInput.qml ToolTip.qml SimpleListView.qml ScrollDecorator.qml + + KAlgebraPage.qml KAlgebraMobile.qml + DESTINATION ${DATA_INSTALL_DIR}/kalgebramobile/plugins/widgets/ +) diff --git a/mobile/plugins/widgets/neutral/CalcButton.qml b/mobile/plugins/widgets/neutral/CalcButton.qml new file mode 100644 index 0000000..fa5dce7 --- /dev/null +++ b/mobile/plugins/widgets/neutral/CalcButton.qml @@ -0,0 +1,6 @@ +import QtQuick 1.0 + +Button +{ + onClicked: doOp(text) +} \ No newline at end of file diff --git a/mobile/plugins/widgets/neutral/ExpressionInput.qml b/mobile/plugins/widgets/neutral/ExpressionInput.qml new file mode 100644 index 0000000..0477dd4 --- /dev/null +++ b/mobile/plugins/widgets/neutral/ExpressionInput.qml @@ -0,0 +1,16 @@ +import QtQuick 1.1 + +TextInput +{ + SystemPalette { id: palette } + + height: input.font.pixelSize+5 + Rectangle { + color: palette.base + anchors.fill: parent + z: parent.z-1 + } + +// placeholderText: "Expression to calculate..." + inputMethodHints: Qt.ImhPreferNumbers | Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase +} diff --git a/mobile/plugins/widgets/neutral/KAlgebraMobile.qml b/mobile/plugins/widgets/neutral/KAlgebraMobile.qml new file mode 100644 index 0000000..42f0af7 --- /dev/null +++ b/mobile/plugins/widgets/neutral/KAlgebraMobile.qml @@ -0,0 +1,61 @@ +import org.kde.analitza 1.0 +import QtQuick 1.1 +import org.kde.kalgebra.mobile 1.0 + +Rectangle +{ + id: rootItem + SystemPalette { id: palette } + color: palette.window + height: 600 + width: 600 + + function goToPage(path) { + try { + var component = Qt.createComponent(path) + if (component.status == Component.Ready) { + var obj = component.createObject(rootItem) +// obj.z = rootItem+1 + obj.anchors.fill = rootItem + + } else { + console.log("Error loading component:", component.errorString()); + } + } catch (e) { + console.log("error: "+e) + } + } + + ListView { + id: pluginsView + anchors.fill: parent + spacing: 10 + header: Image { + source: "qrc:/kalgebra.svgz" + anchors.horizontalCenter: parent.horizontalCenter + + MouseArea { + anchors.fill: parent + onClicked: Qt.openUrlExternally("http://edu.kde.org/applications/mathematics/kalgebra/") + } + } + footer: Image { + source: "qrc:/kde-edu-logo.png" + anchors.horizontalCenter: parent.horizontalCenter + + MouseArea { + anchors.fill: parent + onClicked: Qt.openUrlExternally("http://edu.kde.org") + } + } + delegate: + Button { + text: title + onClicked: goToPage(model.path) + anchors.horizontalCenter: parent.horizontalCenter + } + + + model: PluginsModel { id: plugins } + } +} diff --git a/mobile/plugins/widgets/neutral/KAlgebraPage.qml b/mobile/plugins/widgets/neutral/KAlgebraPage.qml new file mode 100644 index 0000000..56c02c5 --- /dev/null +++ b/mobile/plugins/widgets/neutral/KAlgebraPage.qml @@ -0,0 +1,19 @@ +import QtQuick 1.1 + +Rectangle +{ + SystemPalette { id: palette } + color: palette.window + + Button { + text: "<-" + width: 50 + height: 50 + anchors { + bottom: parent.bottom + right: parent.right + } + onClicked: parent.destroy() + z: parent.z+1 + } +} diff --git a/mobile/plugins/widgets/neutral/Label.qml b/mobile/plugins/widgets/neutral/Label.qml new file mode 100644 index 0000000..43466eb --- /dev/null +++ b/mobile/plugins/widgets/neutral/Label.qml @@ -0,0 +1,7 @@ +import QtQuick 1.1 + +Text { + SystemPalette { id: palette } + color: palette.text + onLinkActivated: Qt.openUrlExternally(link) +} diff --git a/mobile/plugins/widgets/neutral/RealInput.qml b/mobile/plugins/widgets/neutral/RealInput.qml new file mode 100644 index 0000000..14da1ef --- /dev/null +++ b/mobile/plugins/widgets/neutral/RealInput.qml @@ -0,0 +1,43 @@ +import QtQuick 1.1 + +TextInput +{ + id: input + property alias minimumValue: realvalidator.bottom + property alias maximumValue: realvalidator.top + SystemPalette { id: palette } + + Rectangle { color: palette.base; anchors.fill: parent; z: parent.z-1; opacity: 1 } + + property double value: parseFloat(text) + inputMethodHints: Qt.ImhDigitsOnly | Qt.ImhNoPredictiveText + + validator: DoubleValidator { id: realvalidator } + + onTextChanged: value=parseFloat(text) + + Component.onCompleted: text=value + + Row { + anchors.right: parent.right + height: parent.height + Button { + text: "+" + height: parent.height + onClicked: { + if(input.value+1minimumValue) { + input.text=(input.value-1) + } + } + height: parent.height + } + } +} \ No newline at end of file diff --git a/mobile/plugins/widgets/neutral/ScrollDecorator.qml b/mobile/plugins/widgets/neutral/ScrollDecorator.qml new file mode 100644 index 0000000..1f5ea52 --- /dev/null +++ b/mobile/plugins/widgets/neutral/ScrollDecorator.qml @@ -0,0 +1,17 @@ +import QtQuick 1.1 + +Rectangle { + property Flickable flickableItem: null + anchors { + right: flickableItem.right + rightMargin: 5 + } + visible: flickableItem!=null + width: 5 + opacity: 0.5 + height: flickableItem.height/(flickableItem.contentHeight/flickableItem.height) + y: (flickableItem.contentY/flickableItem.contentHeight)*flickableItem.height + + SystemPalette { id: palette } + color: palette.text +} \ No newline at end of file diff --git a/mobile/plugins/widgets/neutral/SimpleListView.qml b/mobile/plugins/widgets/neutral/SimpleListView.qml new file mode 100644 index 0000000..fd52766 --- /dev/null +++ b/mobile/plugins/widgets/neutral/SimpleListView.qml @@ -0,0 +1,23 @@ +import QtQuick 1.1 + +ListView +{ + id: viewItem + property string role: "" + property string title + + SystemPalette { id: palette } + clip: true + header: Label { + height: ListView.view.title=="" ? 0 : 1.5*implicitHeight + text: ListView.view.title + font.weight: Font.Bold + verticalAlignment: Text.AlignVCenter + } + delegate: Label { text: model[role] } + highlight: Rectangle { color: palette.midlight } + + ScrollDecorator { + flickableItem: viewItem + } +} diff --git a/mobile/plugins/widgets/neutral/ToolTip.qml b/mobile/plugins/widgets/neutral/ToolTip.qml new file mode 100644 index 0000000..1149985 --- /dev/null +++ b/mobile/plugins/widgets/neutral/ToolTip.qml @@ -0,0 +1,14 @@ +import QtQuick 1.0 + +Rectangle { + id: tooltip + property string text + Text { + text: tooltip.text + + anchors.fill: parent + } + + SystemPalette { id: palette } + color: palette.light +} \ No newline at end of file diff --git a/mobile/plugins/widgets/qmldir b/mobile/plugins/widgets/qmldir new file mode 100644 index 0000000..cb080ad --- /dev/null +++ b/mobile/plugins/widgets/qmldir @@ -0,0 +1,9 @@ +Label 1.0 Label.qml +Button 1.0 Button.qml +CalcButton 1.0 CalcButton.qml +ExpressionInput 1.0 ExpressionInput.qml +RealInput 1.0 RealInput.qml +ToolTip 1.0 ToolTip.qml +SimpleListView 1.0 SimpleListView.qml +KAlgebraPage 1.0 KAlgebraPage.qml +KAlgebraMobile 1.0 KAlgebraMobile.qml \ No newline at end of file diff --git a/mobile/pluginsmodel.cpp b/mobile/pluginsmodel.cpp new file mode 100644 index 0000000..de0e27a --- /dev/null +++ b/mobile/pluginsmodel.cpp @@ -0,0 +1,72 @@ +/************************************************************************************* + * Copyright (C) 2010 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 "pluginsmodel.h" +#include +#include +#include +#include +#include +#include + +PluginsModel::PluginsModel(QObject* parent) :QStandardItemModel(parent) +{ + QHash rolenames=QStandardItemModel::roleNames(); + rolenames.insert(PathRole, "path"); + rolenames.insert(PriorityRole, "priority"); + rolenames.insert(TitleRole, "title"); + rolenames.insert(SubtitleRole, "subtitle"); + setRoleNames(rolenames); + + QStringList foundPlugins = KGlobal::dirs()->findAllResources("appdata", "plugins/*.desktop"); + + qDebug() << "Plugins found:" << foundPlugins; + + QList items; + Q_FOREACH(const QString& file, foundPlugins) { + KConfig info(file, KConfig::SimpleConfig, "appdata"); + KConfigGroup cg = info.group("Desktop Entry"); + QStandardItem* item = new QStandardItem; + + QString postfix = "plugins/"+cg.readEntry("X-KDE-PluginInfo-Name", QString()); + QString scriptPath = KStandardDirs::locate("appdata", postfix); + + Q_ASSERT(!scriptPath.isEmpty()); + + QVariant priority = cg.readEntry("X-KAlgebra-Priority", QString()); + if(!priority.isValid()) + priority = 1000; + + item->setData(scriptPath, PathRole); + item->setData(priority, PriorityRole); + item->setData(cg.readEntry("Name", QString()), TitleRole); + item->setData(cg.readEntry("Comment", QString()), SubtitleRole); + item->setData(cg.readEntry("Icon", QString()), Qt::DecorationRole); + + items += item; + } + invisibleRootItem()->appendRows(items); + setSortRole(PriorityRole); + sort(0, Qt::DescendingOrder); +} + +QString PluginsModel::pluginPath(int row) +{ + return data(index(row, 0), PathRole).toString(); +} diff --git a/mobile/pluginsmodel.h b/mobile/pluginsmodel.h new file mode 100644 index 0000000..987e421 --- /dev/null +++ b/mobile/pluginsmodel.h @@ -0,0 +1,38 @@ +/************************************************************************************* + * Copyright (C) 2010 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 PLUGINSMODEL_H +#define PLUGINSMODEL_H + +#include + +class PluginsModel : public QStandardItemModel +{ + Q_OBJECT + public: + enum Roles { PathRole = Qt::UserRole+1, PriorityRole, TitleRole, SubtitleRole }; + + explicit PluginsModel(QObject* parent = 0); + + public slots: + ///qml can't access data. Yay! + QString pluginPath(int row); +}; + +#endif // PLUGINSMODEL_H diff --git a/mobile/resources.qrc b/mobile/resources.qrc new file mode 100644 index 0000000..a48b1ad --- /dev/null +++ b/mobile/resources.qrc @@ -0,0 +1,9 @@ + + + plugins/resources/kde-edu-logo.png + + + ../icons/hi64-app-kalgebra.png + ../icons/hisc-app-kalgebra.svgz + + diff --git a/plasmoids/CMakeLists.txt b/plasmoids/CMakeLists.txt new file mode 100644 index 0000000..b730f25 --- /dev/null +++ b/plasmoids/CMakeLists.txt @@ -0,0 +1,5 @@ +add_subdirectory(calculator) + +install(DIRECTORY graphsplasmoid/ DESTINATION ${DATA_INSTALL_DIR}/plasma/plasmoids/org.kde.graphsplasmoid) +install(FILES graphsplasmoid/metadata.desktop DESTINATION ${SERVICES_INSTALL_DIR} RENAME graphsplasmoid.desktop) + diff --git a/plasmoids/calculator/CMakeLists.txt b/plasmoids/calculator/CMakeLists.txt new file mode 100644 index 0000000..abf0005 --- /dev/null +++ b/plasmoids/calculator/CMakeLists.txt @@ -0,0 +1,11 @@ +project(kalgebra-plasmoid) + +add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS}) +set(kalgebraplasma_SRCS kalgebraplasma.cpp) + +kde4_add_plugin(plasma_applet_kalgebra ${kalgebraplasma_SRCS}) +target_link_libraries(plasma_applet_kalgebra ${KDE4_PLASMA_LIBS} ${KDE4_KDECORE_LIBS} ${ANALITZA_LIBRARY}) + +set(plugin_dir ${PLUGIN_INSTALL_DIR}/plugins/kalgebra) +install(TARGETS plasma_applet_kalgebra DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES kalgebraplasmoid.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/plasmoids/calculator/Messages.sh b/plasmoids/calculator/Messages.sh new file mode 100644 index 0000000..0af2da1 --- /dev/null +++ b/plasmoids/calculator/Messages.sh @@ -0,0 +1,2 @@ +#! /bin/sh +$XGETTEXT *.cpp -o $podir/plasma_applet_kalgebraplasmoid.pot diff --git a/plasmoids/calculator/kalgebraplasma.cpp b/plasmoids/calculator/kalgebraplasma.cpp new file mode 100644 index 0000000..976295f --- /dev/null +++ b/plasmoids/calculator/kalgebraplasma.cpp @@ -0,0 +1,162 @@ +/************************************************************************************* + * Copyright (C) 2008 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 "kalgebraplasma.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +using namespace Plasma; +using Analitza::Expression; + +QColor KAlgebraPlasmoid::correctColor() { return Theme::defaultTheme()->color(Theme::TextColor);} +QColor KAlgebraPlasmoid::errorColor() { return Qt::red; } +int KAlgebraPlasmoid::simplificationSize() { return Theme::defaultTheme()->font(Theme::DefaultFont).pointSize(); } + +KAlgebraPlasmoid::KAlgebraPlasmoid(QObject *parent, const QVariantList &args) + : PopupApplet(parent, args), m_widget(0), m_layout(0) +{ + KGlobal::locale()->insertCatalog("kalgebra"); + setAspectRatioMode(IgnoreAspectRatio); + setAssociatedApplication("kalgebra"); +} + +KAlgebraPlasmoid::~KAlgebraPlasmoid() {} + +void KAlgebraPlasmoid::init() +{ +// updateFactor(); + + setPopupIcon("kalgebra"); +} + +QGraphicsWidget* KAlgebraPlasmoid::graphicsWidget() +{ + if(!m_widget) { + m_widget = new QGraphicsWidget(this); + m_input = new Plasma::LineEdit(m_widget); + m_input->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + m_input->setClearButtonShown(true); + + m_output = new Plasma::Label(m_widget); + m_output->setMinimumSize(20, 20); + m_output->nativeWidget()->setAlignment(Qt::AlignCenter); + m_output->setText(i18n("Enter some expression.")); + + m_layout = new QGraphicsLinearLayout(m_widget); + m_layout->setOrientation(Qt::Vertical); + m_layout->addItem(m_input); + m_layout->addItem(m_output); + m_widget->setPreferredSize(300,300); + + connect(m_input, SIGNAL(editingFinished()), this, SLOT(addOperation())); + connect(m_input->nativeWidget(), SIGNAL(textChanged(QString)), this, SLOT(simplify())); + } + m_input->nativeWidget()->selectAll(); + m_input->setFocus(); + + return m_widget; +} + +void KAlgebraPlasmoid::addOperation() +{ + if ( m_input->text().isEmpty() ) + return; + + Expression res; + a.setExpression(Expression(m_input->text(), false)); + if(a.isCorrect()) { + res=a.evaluate(); + } + + QColor c; + if(a.isCorrect()) { + QString result=res.toString(); + m_output->setText(result); + + Plasma::ToolTipContent data; + data.setMainText(i18n("KAlgebra")); + data.setSubText(i18n("%1 = %2", m_input->text(), result)); + data.setImage(KIcon("kalgebra").pixmap(IconSize(KIconLoader::Desktop))); + Plasma::ToolTipManager::self()->setContent(this, data); + + c=correctColor(); + } else { + m_output->setText(a.errors().join("\n")); + c=errorColor(); + } + plasmoidFont(true, c, true); + update(); +} + +void KAlgebraPlasmoid::plasmoidFont(bool big, const QColor& c, bool bold) +{ + QFont f=m_output->nativeWidget()->font(); + f.setBold(bold); + int size; + + if(big) { + size=(m_output->size().height()*2)/3; + f.setPointSize(size); + QFontMetrics fm(f); + + int w=m_output->size().width(); + Q_ASSERT(w>0); + for(; fm.width(m_output->text()) > w; size--) { + f.setPointSize(size); + fm=QFontMetrics(f); + } + } else + size=simplificationSize(); + f.setPointSize(size); + + QPalette palette = m_output->palette(); + palette.setColor(QPalette::WindowText, c); + m_output->nativeWidget()->setPalette(palette); + m_output->nativeWidget()->setFont(f); +} + +void KAlgebraPlasmoid::simplify() +{ + Expression e(m_input->text(), false); + if(e.isCorrect()) + a.setExpression(e); + + if(e.isCorrect() && a.isCorrect()) { + a.simplify(); + m_output->setText(a.expression().toString()); + + plasmoidFont(false, correctColor(), true); + } else + m_output->setText(QString()); +} + +#include "kalgebraplasma.moc" diff --git a/plasmoids/calculator/kalgebraplasma.h b/plasmoids/calculator/kalgebraplasma.h new file mode 100644 index 0000000..8a1710c --- /dev/null +++ b/plasmoids/calculator/kalgebraplasma.h @@ -0,0 +1,64 @@ +/************************************************************************************* + * Copyright (C) 2008 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 KALGEBRAPLASMA_HEADER +#define KALGEBRAPLASMA_HEADER + +#include +#include +#include +#include +#include +#include + +class QSizeF; +class QLabel; + +class KAlgebraPlasmoid : public Plasma::PopupApplet +{ + Q_OBJECT + public: + KAlgebraPlasmoid(QObject *parent, const QVariantList &args); + ~KAlgebraPlasmoid(); + + void init(); + virtual QGraphicsWidget* graphicsWidget(); + + private slots: + void simplify(); + void addOperation(); + + private: + static QColor correctColor(); + static QColor errorColor(); + static int simplificationSize(); + + void plasmoidFont(bool big, const QColor& c, bool bold); + + QGraphicsWidget* m_widget; + QGraphicsLinearLayout* m_layout; + Plasma::LineEdit *m_input; + Plasma::Label *m_output; + Analitza::Analyzer a; +}; + +// This is the command that links your applet to the .desktop file +K_EXPORT_PLASMA_APPLET(kalgebraplasmoid, KAlgebraPlasmoid) + +#endif diff --git a/plasmoids/calculator/kalgebraplasmoid.desktop b/plasmoids/calculator/kalgebraplasmoid.desktop new file mode 100644 index 0000000..f3782f8 --- /dev/null +++ b/plasmoids/calculator/kalgebraplasmoid.desktop @@ -0,0 +1,126 @@ +[Desktop Entry] +Name=KAlgebra +Name[ast]=KAlgebra +Name[bg]=KAlgebra +Name[bs]=Kalgebra +Name[ca]=KAlgebra +Name[ca@valencia]=KAlgebra +Name[cs]=KAlgebra +Name[csb]=KAlgebra +Name[da]=KAlgebra +Name[de]=KAlgebra +Name[el]=KAlgebra +Name[en_GB]=KAlgebra +Name[eo]=KAlgebra +Name[es]=KAlgebra +Name[et]=KAlgebra +Name[eu]=KAlgebra +Name[fi]=KAlgebra +Name[fr]=KAlgebra +Name[ga]=KAlgebra +Name[gl]=KAlgebra +Name[gu]=KAlgebra +Name[he]=KAlgebra +Name[hi]=के-अलजेब्रा +Name[hne]=के-अलजेब्रा +Name[hr]=KAlgebra +Name[hu]=KAlgebra +Name[is]=KAlgebra +Name[it]=KAlgebra +Name[ja]=KAlgebra +Name[kk]=KAlgebra +Name[km]=KAlgebra +Name[ko]=KAlgebra +Name[lt]=KAlgebra +Name[lv]=KAlgebra +Name[ml]=കെ-ആള്‍ജിബ്ര +Name[mr]=के-एल्जिब्रा +Name[nb]=KAlgebra +Name[nds]=KAlgebra +Name[ne]=केडीई बीजगणित +Name[nl]=KAlgebra +Name[nn]=KAlgebra +Name[pa]=ਕੇ-ਐਲਜਬਰਾ +Name[pl]=KAlgebra +Name[pt]=KAlgebra +Name[pt_BR]=KAlgebra +Name[ro]=KAlgebra +Name[ru]=KAlgebra +Name[si]=KAlgebra +Name[sk]=KAlgebra +Name[sl]=KAlgebra +Name[sv]=Kalgebra +Name[te]=కె అల్జీబ్రా +Name[tr]=KAlgebra +Name[ug]=KAlgebra +Name[uk]=KАлгебра +Name[x-test]=xxKAlgebraxx +Name[zh_CN]=KAlgebra +Name[zh_TW]=數學_KAlgebra +Icon=kalgebra +Comment=A Calculator +Comment[ast]=Una calculadora +Comment[bg]=Калкулатор +Comment[bs]=Kalkulator +Comment[ca]=Una calculadora +Comment[ca@valencia]=Una calculadora +Comment[cs]=Kalkulačka +Comment[da]=En regnemaskine +Comment[de]=Ein Taschenrechner +Comment[el]=Ένας μικροϋπολογιστής +Comment[en_GB]=A Calculator +Comment[es]=Una calculadora +Comment[et]=Arvutaja +Comment[eu]=Kalkulagailu bat +Comment[fi]=Laskin +Comment[fr]=Une calculatrice +Comment[ga]=Áireamhán +Comment[gl]=Unha calculadora +Comment[gu]=કેલ્ક્યુલેટર +Comment[he]=מחשבון +Comment[hne]=गनक +Comment[hr]=Kalkulator +Comment[hu]=Algebrai számológép +Comment[is]=Reiknivél +Comment[it]=Una calcolatrice +Comment[ja]=計算機 +Comment[kk]=Калькулятор +Comment[km]=ម៉ាស៊ីន​គិត​លេខ +Comment[ko]=계산기 +Comment[lt]=Skaičiuotuvas +Comment[lv]=Kalkulators +Comment[ml]=ഗണനി +Comment[mr]=गणकयंत्र +Comment[nb]=En kalkulator +Comment[nds]=En Rekenprogramm +Comment[nl]=Een rekenmachine +Comment[nn]=Tekstbasert kalkulator +Comment[pa]=ਇੱਕ ਕੈਲਕੂਲੇਟਰ +Comment[pl]=Kalkulator +Comment[pt]=Uma Calculadora +Comment[pt_BR]=Uma calculadora +Comment[ro]=Un calculator +Comment[ru]=Калькулятор +Comment[sk]=Kalkulačka +Comment[sl]=Računalo +Comment[sv]=Kalkylator +Comment[te]=గనన యంత్రము +Comment[tr]=Bir Hesap Makinesi +Comment[ug]=ھېسابلىغۇچ +Comment[uk]=Калькулятор +Comment[x-test]=xxA Calculatorxx +Comment[zh_CN]=一个计算器 +Comment[zh_TW]=計算器 +Type=Service +ServiceTypes=Plasma/Applet + +X-KDE-Library=plasma_applet_kalgebra +X-KDE-PluginInfo-Author=Aleix Pol Gonzalez +X-KDE-PluginInfo-Email=aleixpol@kde.org +X-KDE-PluginInfo-Name=kalgebraplasmoid +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://edu.kde.org/ +X-KDE-PluginInfo-Category=Education +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/plasmoids/graphsplasmoid/contents/ui/config.ui b/plasmoids/graphsplasmoid/contents/ui/config.ui new file mode 100644 index 0000000..22ecd73 --- /dev/null +++ b/plasmoids/graphsplasmoid/contents/ui/config.ui @@ -0,0 +1,28 @@ + + + nowplayingConfig + + + + 0 + 0 + 351 + 341 + + + + + + + Function + + + + + + + + + + + diff --git a/plasmoids/graphsplasmoid/contents/ui/main.qml b/plasmoids/graphsplasmoid/contents/ui/main.qml new file mode 100644 index 0000000..6bf3da7 --- /dev/null +++ b/plasmoids/graphsplasmoid/contents/ui/main.qml @@ -0,0 +1,68 @@ +/* + * Copyright 2012 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 1.1 +import org.kde.plasma.components 0.1 as PlasmaComponents +import org.kde.analitza 1.0 + +Item { + property Component compactRepresentation: Component { + PlasmaComponents.Button { + iconSource: "kalgebra" + onClicked: plasmoid.togglePopup() + } + } + property string displayedFunction + onDisplayedFunctionChanged: { + plots.clear() + view.addFunction(displayedFunction) + } + + PlasmaComponents.TextField { + id: input + anchors { + top: parent.top + left: parent.left + right: parent.right + } + onAccepted: { + displayedFunction = text + plasmoid.writeConfig("function", text) + } + } + + Component.onCompleted: { + plasmoid.addEventListener('ConfigChanged', function() { + displayedFunction = plasmoid.readConfig("function") + input.text = displayedFunction + }); + } + + Graph2D { + id: view + anchors { + fill: parent + topMargin: input.height + } + + model: PlotsModel { id: plots } + + ticksShown: false + } +} diff --git a/plasmoids/graphsplasmoid/metadata.desktop b/plasmoids/graphsplasmoid/metadata.desktop new file mode 100644 index 0000000..eca356c --- /dev/null +++ b/plasmoids/graphsplasmoid/metadata.desktop @@ -0,0 +1,85 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=Service +ServiceTypes=Plasma/Applet +Name=2D Plots +Name[bs]=2D crtanje +Name[ca]=Gràfiques 2D +Name[ca@valencia]=Gràfiques 2D +Name[cs]=2D grafy +Name[da]=2D-plot +Name[de]=2D-Plots +Name[el]=2D Γραφικές απεικονίσεις +Name[en_GB]=2D Plots +Name[es]=Gráficas 2D +Name[et]=2D joonised +Name[fi]=2U-kuvaajat +Name[fr]=Tracés 2D +Name[gl]=Gráficas en 2D +Name[hu]=2D görbék +Name[it]=Grafici 2D +Name[kk]=2D графиктер +Name[km]=ការ​គ្រោង​ធ្វេមាត្រ +Name[ko]=2차원 플롯 +Name[lt]=2D grafikai +Name[nb]=2D-plott +Name[nds]=2D-Plots +Name[nl]=2d-plots +Name[pa]=2ਡੀ ਪਲਾਟ +Name[pl]=Wykresy 2D +Name[pt]=Gráficos 2D +Name[pt_BR]=Gráficos em 2D +Name[ru]=2D чертежи +Name[sk]=2D zákresy +Name[sl]=2D grafi +Name[sv]=Tvådimensionella diagram +Name[te]=2D ప్లాట్ +Name[tr]=2D Çizimler +Name[uk]=Плоскі графіки +Name[x-test]=xx2D Plotsxx +Name[zh_TW]=2D 繪圖 +Comment=Put the weirdest plots on your desktop! +Comment[bs]=Stavite divlje crteže na vaš desktop! +Comment[ca]=Poseu les gràfiques més estranyes al vostre escriptori! +Comment[ca@valencia]=Poseu les gràfiques més estranyes al vostre escriptori! +Comment[cs]=Přidejte na svou plochu ty nejdivnější tvary. +Comment[da]=Sæt de særeste plot på dit skrivebord! +Comment[de]=Erstellt Plots für Ihre Arbeitsfläche. +Comment[el]=Βάλτε τις πιο περίεργες γραφικές απεικονίσεις στην επιφάνεια εργασίας σας! +Comment[en_GB]=Put the weirdest plots on your desktop! +Comment[es]=Traza las gráficas más retorcidas en su escritorio +Comment[et]=Aseta oma töölauale kõige veidramad joonised! +Comment[fi]=Laita mitä ihmeellisimpiä kuvaajia työpöydällesi! +Comment[fr]=Placez les tracés les plus étranges sur votre bureau ! +Comment[gl]=Poña as gráficas máis charramangueiras no seu escritorio! +Comment[hu]=Tegye a legfurább görbéket az asztalára! +Comment[it]=Metti i grafici più strani sul tuo desktop! +Comment[kk]=Үстеліңізге сиқырлы графиктерді шығарыңыз! +Comment[km]=Put the weirdest plots on your desktop! +Comment[ko]=데스크톱에 재미있는 플롯을 그리십시오! +Comment[nb]=Legg de merkeligste plott på skrivebordet! +Comment[nds]=De snaakschsten Plots för Dien Schriefdisch! +Comment[nl]=Zet de wonderlijkste plots op uw bureaublad! +Comment[pl]=Rysuj najdziwniejsze wykresy na swoim pulpicie! +Comment[pt]=Coloque os gráficos mais estranhos no seu ecrã! +Comment[pt_BR]=Coloque os gráficos mais estranhos na sua área de trabalho! +Comment[ru]=Разместите на рабочем столе причудливые чертежи! +Comment[sk]=Vložte najpodivnejšie zákresy na vašu plochu! +Comment[sl]=Na namizje postavite čudaške grafe! +Comment[sv]=Rita riktigt konstiga diagram på skrivbordet. +Comment[tr]=Masaüstünüzde en tuhaf çizimleri koyun! +Comment[uk]=Розташуйте на вашій стільниці найвигадливіше креслення! +Comment[x-test]=xxPut the weirdest plots on your desktop!xx +Comment[zh_TW]=在您的桌面上放最詭異的繪圖! +Icon=kalgebra +X-Plasma-API=declarativeappletscript +X-Plasma-MainScript=ui/main.qml +X-KDE-PluginInfo-Author=Aleix Pol Gonzalez +X-KDE-PluginInfo-Email=aleixpol@kde.org +X-KDE-PluginInfo-Name=org.kde.graphsplasmoid +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=http://edu.kde.org/kalgebra +X-KDE-PluginInfo-Category=Education +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..eba240f --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,34 @@ +if(OPENGL_FOUND) + include_directories(${OPENGL_INCLUDE_DIR}) +endif(OPENGL_FOUND) + +set(kalgebra_SRCS + kalgebra.cpp + dictionary.cpp + #console.cpp + consolehtml.cpp + varedit.cpp + main.cpp + variablesdelegate.cpp + viewportwidget.cpp + functionedit.cpp +) + +#uncomment this if oxygen icons for kalgebra are available +#kde4_add_app_icon(kalgebra_SRCS "${CMAKE_INSTALL_PREFIX}/share/icons/oxygen/*/apps/kalgebra.png") +kde4_add_app_icon(kalgebra_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/../icons/hi*-app-kalgebra.png") + +kde4_add_executable(kalgebra ${kalgebra_SRCS}) +target_link_libraries(kalgebra + ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY} ${QT_QTXML_LIBRARY} ${QT_QTWEBKIT_LIBRARY} + ${KDE4_KPARTS_LIBS} + ${ANALITZA_LIBRARY} ${ANALITZAGUI_LIBRARY} ${ANALITZAPLOT_LIBRARY} +) + +if(OPENGL_FOUND) + target_link_libraries(kalgebra ${QT_QTOPENGL_LIBRARY} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY}) +endif(OPENGL_FOUND) + +install(TARGETS kalgebra ${INSTALL_TARGETS_DEFAULT_ARGS}) +install(PROGRAMS kalgebra.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} ) +install(FILES kalgebra.xml DESTINATION ${DATA_INSTALL_DIR}/katepart/syntax ) diff --git a/src/Messages.sh b/src/Messages.sh new file mode 100755 index 0000000..77523eb --- /dev/null +++ b/src/Messages.sh @@ -0,0 +1,2 @@ +#! /bin/sh +$XGETTEXT *.cpp -o $podir/kalgebra.pot diff --git a/src/askname.h b/src/askname.h new file mode 100644 index 0000000..9adf090 --- /dev/null +++ b/src/askname.h @@ -0,0 +1,53 @@ +/************************************************************************************* + * Copyright (C) 2009 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 ASKNAME_H +#define ASKNAME_H + +#include +#include +#include +#include +#include +#include + +class AskName : public QDialog +{ + public: + AskName(const QString& text, QWidget* parent) : QDialog(parent) + { + edit=new QLineEdit(this); + edit->setValidator(new QRegExpValidator(QRegExp("[a-zA-Z][\\w]*"), edit)); + + QDialogButtonBox * buttonBox; + QVBoxLayout *items=new QVBoxLayout(this); + items->addWidget(new QLabel(text, this)); + items->addWidget(edit); +// items->addItem(new QSpacerItem()); + items->addWidget(buttonBox=new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok, Qt::Horizontal, this)); + + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + } + + QString name() const { return edit->text(); } + private: + QLineEdit *edit; +}; + +#endif diff --git a/src/consolehtml.cpp b/src/consolehtml.cpp new file mode 100644 index 0000000..4f878ac --- /dev/null +++ b/src/consolehtml.cpp @@ -0,0 +1,308 @@ +/************************************************************************************* + * Copyright (C) 2007 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 "consolehtml.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +ConsoleHtml::ConsoleHtml(QWidget *parent) + : QWebView(parent), m_mode(Evaluation) +{ + page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); + setRenderHint(QPainter::TextAntialiasing); + + connect(this, SIGNAL(linkClicked(QUrl)), SLOT(openClickedUrl(QUrl))); + + QMetaObject::invokeMethod(this, "initialize", Qt::QueuedConnection); +} + +ConsoleHtml::~ConsoleHtml() +{ + qDeleteAll(m_options); +} + +void ConsoleHtml::initialize() +{ + QPalette p=qApp->palette(); + + m_css ="\n"; +} + +void ConsoleHtml::openClickedUrl(const QUrl& url) +{ + QString id =url.queryItemValue("id"); + QString exp=url.queryItemValue("func"); + + foreach(InlineOptions* opt, m_options) { + if(opt->id() == id) { + opt->triggerOption(Analitza::Expression(exp, false)); + } + } +} + +bool ConsoleHtml::addOperation(const Analitza::Expression& e, const QString& input) +{ + QString result, newEntry; + Analitza::Expression res; + + a.setExpression(e); + if(a.isCorrect()) { + if(m_mode==Evaluation) { + res=a.evaluate(); + } else { + res=a.calculate(); + } + } + + QString options; + if(a.isCorrect()) { + result = res.toHtml(); + + Analitza::Analyzer lambdifier(a.variables()); + lambdifier.setExpression(res); + Analitza::Expression lambdaexp = lambdifier.dependenciesToLambda(); + lambdifier.setExpression(lambdaexp); + + Analitza::ExpressionType functype = lambdifier.type(); + + foreach(InlineOptions* opt, m_options) { + if(opt->matchesExpression(lambdaexp, functype)) { + KUrl url("/query"); + url.addQueryItem("id", opt->id()); + url.addQueryItem("func", lambdaexp.toString()); + + options += i18n(" %2", url.url(), opt->caption()); + } + } + + if(!options.isEmpty()) + options = "
"+i18n("Options: %1", options)+"
"; + + a.insertVariable("ans", res); + m_script += e; //Script won't have the errors + newEntry = QString("%1
=%2").arg(e.toHtml()).arg(result); + } else { + m_htmlLog += i18n("
    Error: %1
  • %2
", Qt::escape(input), a.errors().join("\n
  • ")); + } + + updateView(newEntry, options); + + return a.isCorrect(); +} + +QString temporaryPath() +{ + QTemporaryFile temp("consolelog"); + temp.open(); + temp.close(); + temp.setAutoRemove(false); + return QDir::tempPath()+'/'+temp.fileName(); +} + +QString ConsoleHtml::retrieve(const KUrl& remoteUrl) +{ + QString path=temporaryPath(); + + KIO::CopyJob* job=KIO::copyAs(remoteUrl, KUrl(path)); + + bool ret = KIO::NetAccess::synchronousRun(job, 0); + if(!ret) + path.clear(); + + return path; +} + +bool ConsoleHtml::loadScript(const KUrl& path) +{ + Q_ASSERT(!path.isEmpty()); + + //FIXME: We have expression-only script support + bool correct=false; + QFile file(path.isLocalFile() ? path.toLocalFile() : retrieve(path)); + + if(file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream stream(&file); + + a.importScript(&stream); + correct=a.isCorrect(); + } + + if(!correct) { + m_htmlLog += i18n("
      Error: Could not load %1.
      %2
    ", path.pathOrUrl(), a.errors().join("
    ")); + updateView(QString(), QString()); + } + else + updateView(i18n("Imported: %1", path.pathOrUrl()), QString()); + + return correct; +} + +bool ConsoleHtml::saveScript(const KUrl & path) const +{ + bool correct=false; + Q_ASSERT(!path.isEmpty()); + + QString savePath=path.isLocalFile() ? path.toLocalFile() : temporaryPath(); + QFile file(savePath); + correct=file.open(QIODevice::WriteOnly | QIODevice::Text); + + if(correct) { + QTextStream out(&file); + foreach(const Analitza::Expression& exp, m_script) + out << exp.toString() << endl; + } + + if(!path.isLocalFile()) { + KIO::CopyJob* job=KIO::move(savePath, path); + correct=KIO::NetAccess::synchronousRun(job, 0); + } + return correct; +} + +bool ConsoleHtml::saveLog(const KUrl& path) const +{ + Q_ASSERT(!path.isEmpty()); + //FIXME: We have to choose between txt and html + bool correct=false; + QString savePath=path.isLocalFile() ? path.toLocalFile() : temporaryPath(); + QFile file(savePath); + correct=file.open(QIODevice::WriteOnly | QIODevice::Text); + + if(correct) { + QTextStream out(&file); + out << "\n" << m_css << "" << endl; + out << "" << endl; + foreach(const QString &entry, m_htmlLog) + out << "

    " << entry << "

    " << endl; + out << "\n" << endl; + } + + if(!path.isLocalFile()) { + KIO::CopyJob* job=KIO::move(savePath, path); + correct=KIO::NetAccess::synchronousRun(job, 0); + } + return correct; +} + +void ConsoleHtml::updateView(const QString& newEntry, const QString& options) +{ + QByteArray code; + code += "\n"; + code += "\n\n\t :) \n"; + code += m_css; + code += "\n"; + foreach(const QString &entry, m_htmlLog) + code += "

    "+entry+"

    "; + + if(!newEntry.isEmpty()) { + m_htmlLog += newEntry; + code += options; + code += "

    "+newEntry+"

    "; + } + code += ""; + + setContent(code); + + emit changed(); + + QWebFrame* mf = page()->mainFrame(); + mf->setScrollBarValue(Qt::Vertical, mf->scrollBarMaximum(Qt::Vertical)); +} + +void ConsoleHtml::copy() const +{ + QApplication::clipboard()->setText(selectedText()); +} + +void ConsoleHtml::contextMenuEvent(QContextMenuEvent* ev) +{ + KMenu popup; + if(hasSelection()) { + popup.addAction(KStandardAction::copy(this, SLOT(copy()), &popup)); + KAction *act=new KAction(KIcon("edit-paste"), i18n("Paste \"%1\" to input", selectedText()), &popup); + connect(act, SIGNAL(triggered()), SLOT(paste())); + popup.addAction(act); + popup.addSeparator(); + } + popup.addAction(KStandardAction::clear(this, SLOT(clear()), &popup)); + + popup.exec(ev->pos()); +} + +void ConsoleHtml::clear() +{ + m_script.clear(); + m_htmlLog.clear(); + updateView(QString(), QString()); +} + +void ConsoleHtml::modifyVariable(const QString& name, const Analitza::Expression& exp) +{ + a.variables()->modify(name, exp); +} + +void ConsoleHtml::removeVariable(const QString & name) +{ + a.variables()->remove(name); +} + +void ConsoleHtml::paste() +{ + emit paste(selectedText()); +} + +#include "consolehtml.moc" diff --git a/src/consolehtml.h b/src/consolehtml.h new file mode 100644 index 0000000..815d8dd --- /dev/null +++ b/src/consolehtml.h @@ -0,0 +1,127 @@ +/************************************************************************************* + * Copyright (C) 2007 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 CONSOLE_H +#define CONSOLE_H + +#include +#include + +#include + +class KUrl; +class InlineOptions +{ + public: + virtual ~InlineOptions() {} + + virtual QString id() const = 0; + virtual QString caption() const = 0; + virtual bool matchesExpression(const Analitza::Expression& exp, const Analitza::ExpressionType& functype) const = 0; + virtual void triggerOption(const Analitza::Expression& exp) = 0; +}; + +/** + * The Console widget is able to receive an operation, solve it and show the value. + * It also is able to load scripts and save logs. + * @author Aleix Pol Gonzalez + */ + +class ConsoleHtml : public QWebView +{ + Q_OBJECT + public: + /** This enumeration controles the way the console will calculate and show his results. */ + enum ConsoleMode { + Evaluation, /**< Simplifies the expression, tries to simplify when sees a variable not defined. */ + Calculation /**< Calculates everything, if it finds a not defined variable shows an error. */ + }; + + /** Constructor. Creates a console widget. */ + ConsoleHtml(QWidget *parent = 0); + + /** Destructor. */ + virtual ~ConsoleHtml(); + + /** Retrieves a pointer to the Analitza calculator associated. */ + Analitza::Analyzer* analitza() { return &a; } + + /** Sets a @p newMode console mode. */ + void setMode(ConsoleMode newMode) { m_mode = newMode; } + + /** Retrieves the console mode. */ + ConsoleMode mode() const { return m_mode; } + + void addOptionsObserver(InlineOptions* opt) { m_options += opt; } + + virtual void contextMenuEvent(QContextMenuEvent* ev); + + public slots: + /** Adds the operation defined by the expression @p e. */ + bool addOperation(const Analitza::Expression& e, const QString& input); + + /** Loads a script from @p path. */ + bool loadScript(const KUrl& path); + + /** Save a script yo @p path. */ + bool saveScript(const KUrl& path) const; + + /** Saves a log to @p path. */ + bool saveLog(const KUrl& path) const; + + /** Flushes the contents. */ + void clear(); + + /** Copies the selected text to the clipboard */ + void copy() const; + + void openClickedUrl(const QUrl& url); + + signals: + /** Emits a notification that tells that the widget status. */ + void status(const QString &msg); + + /** Emits that something has changed. */ + void changed(); + + /** Emits the selected code to be pasted somewhere */ + void paste(const QString& code); + + private slots: + void initialize(); + + void modifyVariable(const QString& name, const Analitza::Expression& exp); + void removeVariable(const QString& name); + void paste(); + + private: + QString retrieve(const KUrl& remoteUrl); + + Analitza::Analyzer a; + void sendStatus(const QString& msg) { emit status(msg); } + ConsoleMode m_mode; + QList m_script; + QStringList m_htmlLog; + + void updateView(const QString& newEntry, const QString& options); + + QByteArray m_css; + QList m_options; +}; + +#endif diff --git a/src/dictionary.cpp b/src/dictionary.cpp new file mode 100644 index 0000000..56b6475 --- /dev/null +++ b/src/dictionary.cpp @@ -0,0 +1,129 @@ +/************************************************************************************* + * Copyright (C) 2007 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 "dictionary.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +Dictionary::Dictionary(QWidget *p) : QWidget(p) +{ + m_ops=new OperatorsModel(this); + m_sortProxy = new QSortFilterProxyModel(this); + m_sortProxy->setSourceModel(m_ops); + m_sortProxy->sort(2, Qt::AscendingOrder); + m_sortProxy->setFilterKeyColumn(2); + + m_vars = new Analitza::Variables; + + QGroupBox *descr=new QGroupBox(i18n("Information"), this); + descr->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + QFormLayout *descrLayo=new QFormLayout; + QVBoxLayout *graphLayo=new QVBoxLayout(this); + m_name=new QLabel(descr); + m_descr=new QLabel(descr); + m_sample=new QLabel(descr); + m_example=new QLabel(descr); + m_funcs=new Analitza::PlotsModel(descr); + m_graph=new Analitza::PlotsView2D(descr); + m_graph->setTicksShown(0); + m_graph->setModel(m_funcs); + m_graph->setReadOnly(true); + m_graph->setViewport(QRect(QPoint(-30, 7), QPoint(30, -7))); + m_graph->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + m_name->setIndent(10); + m_descr->setIndent(10); + m_sample->setIndent(10); + m_example->setIndent(10); + + m_example->setTextInteractionFlags(Qt::TextSelectableByMouse); + + descrLayo->addRow(i18n("%1", m_ops->headerData(0, Qt::Horizontal).toString()), m_name); + descrLayo->addRow(i18n("%1", m_ops->headerData(1, Qt::Horizontal).toString()), m_descr); + descrLayo->addRow(i18n("%1", m_ops->headerData(2, Qt::Horizontal).toString()), m_sample); + descrLayo->addRow(i18n("%1", m_ops->headerData(3, Qt::Horizontal).toString()), m_example); + descrLayo->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); + graphLayo->addWidget(descr); + graphLayo->addWidget(m_graph); + descr->setLayout(descrLayo); + + m_funcs->clear(); +// connect(m_list, SIGNAL(clicked(QModelIndex)), this, SLOT(activated(QModelIndex))); +} + +Dictionary::~Dictionary() +{ + delete m_vars; +} + +void Dictionary::activated(const QModelIndex& idx, const QModelIndex& prev) +{ + Q_UNUSED(prev); + + m_funcs->clear(); + if(idx.isValid()) { + QModelIndex nameIdx, descriptionIdx, sampleIdx, exampleIdx; + nameIdx = idx.sibling(idx.row(), 0); + descriptionIdx = idx.sibling(idx.row(), 1); + sampleIdx = idx.sibling(idx.row(), 2); + exampleIdx = idx.sibling(idx.row(), 3); + + QString name=m_sortProxy->data(nameIdx).toString(); + QString description=m_sortProxy->data(descriptionIdx).toString(); + QString sample=m_sortProxy->data(sampleIdx).toString(); + QString example=m_sortProxy->data(exampleIdx).toString(); + + Analitza::Expression e(example, false); + + m_name->setText(name); + m_descr->setText(description); + m_sample->setText(sample); + m_example->setText(example); + + QString error; + if(!error.isEmpty()) + qDebug() << "dict formula error: " << error << e.toMathMLPresentation(); + + m_funcs->addPlot(Analitza::PlotsFactory::self()->requestPlot(e, Analitza::Dim2D, m_vars).create(QColor(0,150,0), "dict")); + } else { + QString error; + m_name->setText(QString()); + m_descr->setText(QString()); + m_sample->setText(QString()); + m_example->setText(QString()); + } +} + +void Dictionary::setFilter(const QString &filter) +{ + m_sortProxy->setFilterFixedString(filter); +} + +#include "dictionary.moc" diff --git a/src/dictionary.h b/src/dictionary.h new file mode 100644 index 0000000..e12198f --- /dev/null +++ b/src/dictionary.h @@ -0,0 +1,65 @@ +/************************************************************************************* + * Copyright (C) 2007 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 DICTIONARY_H +#define DICTIONARY_H + +#include +#include + +namespace Analitza +{ +class Variables; +class PlotsView2D; +class PlotsModel; +} + +class QLabel; +class QModelIndex; +class OperatorsModel; + +/** + @author Aleix Pol +*/ +class Dictionary : public QWidget +{ +Q_OBJECT + public: + Dictionary(QWidget *p=0); + virtual ~Dictionary(); + + QSortFilterProxyModel* model() const { return m_sortProxy; } + + public slots: + void activated(const QModelIndex& prev, const QModelIndex& ); + void setFilter(const QString&); + + private: + QLabel *m_name; + QLabel *m_descr; + QLabel *m_sample; + QLabel *m_example; + + Analitza::PlotsView2D *m_graph; + Analitza::PlotsModel *m_funcs; + OperatorsModel *m_ops; + Analitza::Variables* m_vars; + QSortFilterProxyModel *m_sortProxy; +}; + +#endif diff --git a/src/functionedit.cpp b/src/functionedit.cpp new file mode 100644 index 0000000..8958367 --- /dev/null +++ b/src/functionedit.cpp @@ -0,0 +1,323 @@ +/************************************************************************************* + * Copyright (C) 2007-2009 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 "functionedit.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Analitza; + +namespace { + static const int resolution = 200; +} + +FunctionEdit::FunctionEdit(QWidget *parent) + : QWidget(parent), m_calcUplimit(0), m_calcDownlimit(0) +{ + setWindowTitle(i18n("Add/Edit a function")); + + QVBoxLayout *topLayout = new QVBoxLayout(this); + topLayout->setMargin(2); + topLayout->setSpacing(5); + + m_name = new KLineEdit(this); + + m_func = new ExpressionEdit(this); + m_func->setExamples(PlotsFactory::self()->examples(Dim2D)); + m_func->setAns("x"); + connect(m_func, SIGNAL(textChanged()), this, SLOT(edit())); + connect(m_func, SIGNAL(returnPressed()), this, SLOT(ok())); + + m_valid = new QLabel(this); + m_valid->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + + QPalette p=palette(); + p.setColor(QPalette::Active, QPalette::Base, Qt::white); + m_valid->setPalette(p); + + m_validIcon = new QLabel(this); + m_validIcon->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + QLayout* validLayout=new QHBoxLayout; + validLayout->addWidget(m_validIcon); + validLayout->addWidget(m_valid); + + m_color = new KColorCombo(this); + m_color->setColor(QColor(0,150,0)); + connect(m_color, SIGNAL(currentIndexChanged(int)), this, SLOT(colorChange(int))); + + m_funcsModel=new PlotsModel(this); + m_funcsModel->setResolution(resolution); + + m_viewTabs=new KTabWidget(this); + + m_graph = new PlotsView2D(m_viewTabs); + m_graph->setModel(m_funcsModel); + m_graph->setViewport(QRectF(QPointF(-10.0, 10.0), QSizeF(20.0, -20.0))); + m_graph->setFocusPolicy(Qt::NoFocus); + m_graph->setMouseTracking(false); + m_graph->setFramed(true); + m_graph->setReadOnly(true); + m_graph->setShowGrid(false); + m_graph->setTicksShown(Qt::Orientation(0)); + + m_viewTabs->addTab(m_graph, QIcon::fromTheme("document-preview"), i18n("Preview")); + QWidget *options=new QWidget(m_viewTabs); + options->setLayout(new QVBoxLayout); + m_uplimit=new ExpressionEdit(options); + m_downlimit=new ExpressionEdit(options); + m_uplimit->setText("2*pi"); + m_downlimit->setText("0"); + options->layout()->addWidget(new QLabel(i18n("From:"), options)); + options->layout()->addWidget(m_downlimit); + options->layout()->addWidget(new QLabel(i18n("To:"), options)); + options->layout()->addWidget(m_uplimit); + options->layout()->addItem(new QSpacerItem(0,0, QSizePolicy::Expanding, QSizePolicy::Expanding)); + m_viewTabs->addTab(options, QIcon::fromTheme("configure"), i18n("Options")); + connect(m_uplimit, SIGNAL(textChanged()), this, SLOT(updateUplimit())); + connect(m_downlimit, SIGNAL(textChanged()), this, SLOT(updateDownlimit())); + + QHBoxLayout *m_butts = new QHBoxLayout; + m_ok = new QPushButton(i18n("OK"), this); + m_ok->setIcon(QIcon::fromTheme("dialog-ok")); + m_remove = new QPushButton(i18nc("@action:button", "Remove"), this); + m_remove->setIcon(QIcon::fromTheme("list-remove")); + connect(m_ok, SIGNAL(clicked()), this, SLOT(ok())); + connect(m_remove, SIGNAL(clicked()), this, SIGNAL(removeEditingPlot())); + + topLayout->addWidget(m_name); + topLayout->addWidget(m_func); + topLayout->addWidget(m_color); + topLayout->addLayout(validLayout); + topLayout->addWidget(m_viewTabs); + topLayout->addLayout(m_butts); + + m_name->hide(); //FIXME: Remove this when the name has any sense + + m_butts->addWidget(m_ok); + m_butts->addWidget(m_remove); + + m_func->setFocus(); + m_ok->setEnabled(false); + + QFont errorFont=m_valid->font(); + errorFont.setBold(true); + m_valid->setFont(errorFont); +} + +FunctionEdit::~FunctionEdit() +{} + +void FunctionEdit::clear() +{ + m_func->setText(QString()); + m_funcsModel->clear(); + edit(); +} + +void FunctionEdit::setFunction(const QString &newText) +{ + m_func->setText(newText); + m_func->document()->setModified(true); +} + +void FunctionEdit::setColor(const QColor &newColor) +{ + m_color->setColor(newColor); + if(m_funcsModel->rowCount()>0) + m_funcsModel->setData(m_funcsModel->index(0), newColor); +} + +void FunctionEdit::colorChange(int) +{ + setColor(m_color->color()); +} + +static double calcExp(const Analitza::Expression& exp, Analitza::Variables* v, bool* corr) +{ + Q_ASSERT(exp.isCorrect()); + Analitza::Analyzer d(v); + d.setExpression(exp); + Analitza::Expression r=d.calculate(); + + *corr=r.isCorrect() && r.isReal(); + + if(*corr) + return r.toReal().value(); + else + return 0.; +} + +void FunctionEdit::updateUplimit() +{ + bool corr = m_uplimit->isCorrect(); + if(corr) { + Analitza::Expression e=m_uplimit->expression(); + m_calcUplimit=calcExp(e, m_vars, &corr); + m_uplimit->setCorrect(corr); + if(corr) + edit(); + } +} + +void FunctionEdit::updateDownlimit() +{ + bool corr = m_downlimit->isCorrect(); + if(corr) { + Analitza::Expression e=m_downlimit->expression(); + m_calcDownlimit=calcExp(e, m_vars, &corr); + m_downlimit->setCorrect(corr); + if(corr) + edit(); + } +} + +void FunctionEdit::setState(const QString& text, bool negative) +{ + QFontMetrics fm(m_valid->font()); + m_valid->setText(fm.elidedText(text, Qt::ElideRight, m_valid->width())); + m_valid->setToolTip(text); + + KColorScheme scheme(QPalette::Normal); + KColorScheme::ForegroundRole role = negative? KColorScheme::NegativeText : KColorScheme::PositiveText; + + QPalette p=m_valid->palette(); + p.setColor(foregroundRole(), scheme.foreground(role).color()); + m_valid->setPalette(p); + + if(negative) + m_validIcon->setPixmap(QIcon::fromTheme("flag-red").pixmap(QSize(16,16))); + else + m_validIcon->setPixmap(QIcon::fromTheme("flag-green").pixmap(QSize(16,16))); +} + +///Let's see if the exp is correct +void FunctionEdit::edit() +{ + if(m_func->text().isEmpty()) { + m_func->setCorrect(true); + m_ok->setEnabled(false); + m_valid->clear(); + m_valid->setToolTip(QString()); + m_validIcon->setPixmap(QIcon::fromTheme("flag-yellow").pixmap(QSize(16,16))); + + m_funcsModel->clear(); + m_graph->forceRepaint(); + return; + } + + if(!m_uplimit->isCorrect() || !m_downlimit->isCorrect()) { + setState(i18n("The options you specified are not correct"), true); + return; + } + + if(m_calcDownlimit>m_calcUplimit) { + setState(i18n("Downlimit cannot be greater than uplimit"), true); + return; + } + bool added = false; + + PlaneCurve* f = 0; + PlotBuilder req = PlotsFactory::self()->requestPlot(expression(), Dim2D, m_vars); + if(req.canDraw()) + f = createFunction(); + + if(f && f->isCorrect()) + f->update(QRect(-10, 10, 20, -20)); + + m_funcsModel->clear(); + if(f && f->isCorrect()) { + m_funcsModel->addPlot(f); + added=true; + setState(QString("%1:=%2") + .arg(m_name->text()).arg(f->expression().toString()), false); + } else { + QStringList errors = req.errors(); + if(f) + errors = f->errors(); + Q_ASSERT(!errors.isEmpty()); + + setState(errors.first(), true); + m_valid->setToolTip(errors.join("
    ")); + delete f; + } + m_func->setCorrect(added); + m_ok->setEnabled(added); +} + +void FunctionEdit::ok() +{ + if(m_ok->isEnabled()) + emit accept(); +} + +void FunctionEdit::focusInEvent(QFocusEvent *) +{ + m_func->setFocus(); +} + +PlaneCurve* FunctionEdit::createFunction() const +{ + PlotBuilder req = PlotsFactory::self()->requestPlot(expression(), Dim2D, m_vars); + PlaneCurve* curve = static_cast(req.create(color(), name())); + curve->setResolution(resolution); + if(m_calcUplimit != m_calcDownlimit) { + foreach(const QString& var, curve->parameters()) + curve->setInterval(var, m_calcUplimit, m_calcDownlimit); + } + return curve; +} + +Analitza::Expression FunctionEdit::expression() const +{ + return m_func->expression(); +} + +void FunctionEdit::setOptionsShown(bool shown) +{ + m_viewTabs->setVisible(shown); +} + +void FunctionEdit::resizeEvent(QResizeEvent*) +{ + QFontMetrics fm(m_valid->font()); + m_valid->setText(fm.elidedText(m_valid->toolTip(), Qt::ElideRight, m_valid->width())); +} + +void FunctionEdit::setEditing(bool m) +{ + m_modmode=m; + m_remove->setVisible(m); +} diff --git a/src/functionedit.h b/src/functionedit.h new file mode 100644 index 0000000..532f359 --- /dev/null +++ b/src/functionedit.h @@ -0,0 +1,130 @@ +/************************************************************************************* + * Copyright (C) 2007 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 FUNCTIONEDIT_H +#define FUNCTIONEDIT_H + +#include +#include +#include +#include + +#include +#include + +class KTabWidget; +namespace Analitza +{ +class Variables; +class Expression; +class PlotsView2D; +class PlotsModel; +class PlaneCurve; +class ExpressionEdit; +} + +/** + * The FunctionEdit dialog provides a way to specify functions. + * @author Aleix Pol i Gonzalez + */ + +class FunctionEdit : public QWidget +{ +Q_OBJECT +public: + /** Constructor. */ + explicit FunctionEdit(QWidget *parent=0); + + /** Destructor. */ + ~FunctionEdit(); + + /** Retrieves the resulting expression text. */ + Analitza::Expression expression() const; + + Analitza::PlaneCurve* createFunction() const; + + /** Sets an expression text to the ExpressionEdit widget. */ + void setFunction(const QString &newText); + + /** Retrieves the selected color for the function */ + QColor color() const { return m_color->color(); } + + /** Sets the selected color for the function.*/ + void setColor(const QColor &newColor); + + /** Returns whether we are editing or adding a function. */ + bool editing() const { return m_modmode; } + + /** Sets whether we are editing or adding a function. */ + void setEditing(bool m); + + /** Sets a name to the function. (Not used YET) */ + void setName(const QString& name) { m_name->setText(name); } + + /** Retrieves a name for the function. (Not used YET) */ + QString name() const { return m_name->text(); } + + /** Sets the variables class to be used with the graph functions*/ + void setVariables(Analitza::Variables* v) { m_vars=v; } + + Analitza::Variables* variables() const { return m_vars; } + + void setOptionsShown(bool shown); + + virtual void resizeEvent(QResizeEvent* ev); + +public slots: + /** Clears the dialog. */ + void clear(); + +signals: + /** Tells that the result has been accepted. */ + void accept(); + + /** asks the currently edited plot to be removed. */ + void removeEditingPlot(); + +private slots: + void edit(); + void ok(); + void colorChange(int); + void updateUplimit(); + void updateDownlimit(); + +private: + void setState(const QString& text, bool negative); + void focusInEvent(QFocusEvent*); + + Analitza::ExpressionEdit *m_func; + Analitza::ExpressionEdit *m_uplimit, *m_downlimit; + double m_calcUplimit, m_calcDownlimit; + KLineEdit *m_name; + QPushButton *m_ok; + QLabel *m_valid; + QLabel *m_validIcon; + Analitza::PlotsView2D *m_graph; + KColorCombo *m_color; + Analitza::PlotsModel *m_funcsModel; + Analitza::Variables* m_vars; + + bool m_modmode; + KTabWidget* m_viewTabs; + QPushButton* m_remove; +}; + +#endif diff --git a/src/kalgebra.cpp b/src/kalgebra.cpp new file mode 100644 index 0000000..263b3dd --- /dev/null +++ b/src/kalgebra.cpp @@ -0,0 +1,746 @@ +/************************************************************************************* + * Copyright (C) 2007 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 "kalgebra.h" +#include "varedit.h" +#include "consolehtml.h" +#include "dictionary.h" +#include "askname.h" +#include "variablesdelegate.h" +#include "viewportwidget.h" +#include "functionedit.h" +#ifdef HAVE_OPENGL +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class Add2DOption : public InlineOptions +{ + public: + Add2DOption(KAlgebra* c) + : m_kalgebra(c) + {} + + virtual QString id() const { return "add2d"; } + virtual bool matchesExpression(const Analitza::Expression& exp, const Analitza::ExpressionType& functype) const { + return Analitza::PlotsFactory::self()->requestPlot(exp, Analitza::Dim2D).canDraw(); + } + + virtual QString caption() const { return i18n("Plot 2D"); } + + virtual void triggerOption(const Analitza::Expression& exp) { m_kalgebra->add2D(exp); } + + private: + KAlgebra* m_kalgebra; +}; + +#ifdef HAVE_OPENGL +class Add3DOption : public InlineOptions +{ + public: + Add3DOption(KAlgebra* c) + : m_kalgebra(c) + {} + + virtual QString id() const { return "add3d"; } + virtual bool matchesExpression(const Analitza::Expression& exp, const Analitza::ExpressionType& functype) const + { + return Analitza::PlotsFactory::self()->requestPlot(exp, Analitza::Dim3D).canDraw(); + } + + virtual QString caption() const { return i18n("Plot 3D"); } + + virtual void triggerOption(const Analitza::Expression& exp) { m_kalgebra->add3D(exp); } + + private: + KAlgebra* m_kalgebra; +}; +#endif + +QColor randomFunctionColor() { return QColor::fromHsv(qrand()%255, 255, 255); } + +KAlgebra::KAlgebra(QWidget *parent) : KMainWindow(parent) +{ + resize(900, 500); + + m_tabs = new QTabWidget; + setCentralWidget(m_tabs); + + setStatusBar(new KStatusBar(this)); + setMenuBar(new KMenuBar(this)); + + KToggleFullScreenAction* fullScreenAction = KStandardAction::fullScreen(this, SLOT(fullScreen(bool)), this, this); + + QMenu* g_menu = menuBar()->addMenu(i18n("Session")); + g_menu->addAction(KStandardAction::openNew(this, SLOT(newInstance()), this)); + g_menu->addAction(fullScreenAction); + g_menu->addAction(KStandardAction::quit(this, SLOT(close()), this)); + + QToolButton* fullScreenButton = new QToolButton(this); + fullScreenButton->setDefaultAction(fullScreenAction); + m_tabs->setCornerWidget(fullScreenButton); + + m_status = new QLabel(this); + statusBar()->insertWidget(0, m_status); + menuBar()->addMenu("|")->setEnabled(false); + + ///////Console + QWidget *console = new QWidget(m_tabs); + QVBoxLayout *c_layo = new QVBoxLayout(console); + c_results = new ConsoleHtml(console); + c_results->setFocusPolicy(Qt::NoFocus); + c_dock_vars = new QDockWidget(i18n("Variables"), this); + c_dock_vars->setFeatures(QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable); + addDockWidget(Qt::RightDockWidgetArea, c_dock_vars); + + c_varsModel=new Analitza::VariablesModel(c_results->analitza()->variables()); + c_varsModel->setEditable(false); + + c_variables = new QTreeView(c_dock_vars); + c_variables->setModel(c_varsModel); + c_variables->setRootIsDecorated(false); + c_variables->header()->setStretchLastSection(true); + c_variables->setSelectionBehavior(QAbstractItemView::SelectRows); + c_variables->setSelectionMode(QAbstractItemView::SingleSelection); + + c_exp = new Analitza::ExpressionEdit(console); + c_exp->setAnalitza(c_results->analitza()); + c_exp->setExamples(QStringList() << "square:=x->x**2" << "fib:=n->piecewise { eq(n,0)?0, eq(n,1)?1, ?fib(n-1)+fib(n-2) }"); + c_dock_vars->setWidget(c_variables); + + m_tabs->addTab(console, i18n("&Console")); + console->setLayout(c_layo); + c_layo->addWidget(c_results); + c_layo->addWidget(c_exp); + + connect(c_exp, SIGNAL(returnPressed()), this, SLOT(operate())); + connect(c_results, SIGNAL(status(QString)), this, SLOT(changeStatusBar(QString))); + connect(c_results, SIGNAL(changed()), this, SLOT(updateInformation())); + connect(c_results, SIGNAL(changed()), c_exp, SLOT(updateCompleter())); + connect(c_results, SIGNAL(paste(QString)), c_exp, SLOT(insertText(QString))); + connect(c_variables, SIGNAL(clicked(QModelIndex)), this, SLOT(edit_var(QModelIndex))); + ////////menu + c_menu = menuBar()->addMenu(i18n("C&onsole")); + + c_menu->addAction(KIcon("document-open"), i18nc("@item:inmenu", "&Load Script..."), + this, SLOT(loadScript()), Qt::CTRL+Qt::Key_L); + c_recentScripts=new KRecentFilesAction(KIcon("document-open-recent"), i18n("Recent Scripts"), this); + connect(c_recentScripts, SIGNAL(urlSelected(KUrl)), this, SLOT(loadScript(KUrl))); + c_menu->addAction(c_recentScripts); + + c_menu->addAction(KIcon("document-save"), i18nc("@item:inmenu", "&Save Script..."), + this, SLOT(saveScript()), Qt::CTRL+Qt::Key_G); + c_menu->addAction(KIcon("document-save"), i18nc("@item:inmenu", "&Export Log..."), + this, SLOT(saveLog()), QKeySequence::Save); + c_menu->addSeparator()->setText(i18n("Execution Mode")); + QActionGroup *execGroup = new QActionGroup(c_menu); + QAction* calc = c_menu->addAction(i18nc("@item:inmenu", "Calculate"), this, SLOT(consoleCalculate())); + QAction* eval = c_menu->addAction(i18nc("@item:inmenu", "Evaluate"), this, SLOT(consoleEvaluate())); + + calc->setCheckable(true); + eval->setCheckable(true); + eval->setChecked(true); + execGroup->addAction(calc); + execGroup->addAction(eval); + c_menu->addSeparator(); + c_menu->addAction(KStandardAction::clear(c_results, SLOT(clear()), this)); + initializeRecentScripts(); + //////////// + //////EOConsola + + //////2D Graph + b_funcsModel=new Analitza::PlotsModel(this); + + m_graph2d = new Analitza::PlotsView2D(m_tabs); + m_graph2d->setTicksShown(0); + m_graph2d->setModel(b_funcsModel); + + b_dock_funcs = new QDockWidget(i18n("Functions"), this); + b_tools = new QTabWidget(b_dock_funcs); + b_tools->setTabPosition(QTabWidget::South); + addDockWidget(Qt::RightDockWidgetArea, b_dock_funcs); + + b_funcs = new QTreeView(b_tools); + b_funcs->setRootIsDecorated(false); + b_funcs->setModel(b_funcsModel); + b_funcs->header()->resizeSections(QHeaderView::ResizeToContents); + b_funcs->setSelectionMode(QAbstractItemView::SingleSelection); + m_graph2d->setSelectionModel(b_funcs->selectionModel()); + + b_tools->addTab(b_funcs, i18n("List")); + + b_funced = new FunctionEdit(b_tools); + b_funced->setVariables(c_varsModel->variables()); + connect(b_funced, SIGNAL(accept()), this, SLOT(new_func())); + connect(b_funced, SIGNAL(removeEditingPlot()), this, SLOT(remove_func())); + b_tools->addTab(b_funced, KIcon("list-add"), i18n("&Add")); + + QTableView* b_varsView=new QTableView(b_tools); + b_varsModel=new Analitza::VariablesModel(b_funced->variables()); + b_varsView->setModel(b_varsModel); + b_varsView->setShowGrid(false); + b_varsView->verticalHeader()->hide(); + b_varsView->horizontalHeader()->setStretchLastSection(true); + b_varsView->setSelectionBehavior(QAbstractItemView::SelectRows); + b_varsView->setContextMenuPolicy(Qt::CustomContextMenu); + VariablesDelegate* delegate=new VariablesDelegate(b_varsView); + b_varsView->setItemDelegate(delegate); + b_tools->addTab(b_varsView, i18n("Variables")); + + ViewportWidget* b_viewport = new ViewportWidget(this); + b_viewport->setViewport(m_graph2d->definedViewport()); + b_tools->addTab(b_viewport, i18n("Viewport")); + + b_dock_funcs->setWidget(b_tools); + b_dock_funcs->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); + m_tabs->addTab(m_graph2d, i18n("&2D Graph")); + c_results->addOptionsObserver(new Add2DOption(this)); + + connect(b_varsModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(valueChanged())); + connect(b_funcs, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(edit_func(QModelIndex))); + connect(b_tools, SIGNAL(currentChanged(int)), this, SLOT(functools(int))); + connect(m_graph2d, SIGNAL(status(QString)), this, SLOT(changeStatusBar(QString))); + connect(m_graph2d, SIGNAL(viewportChanged(QRectF)), b_viewport, SLOT(setViewport(QRectF))); + connect(b_viewport, SIGNAL(viewportChange(QRectF)), m_graph2d, SLOT(changeViewport(QRectF))); + connect(b_varsView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(varsContextMenu(QPoint))); + + ////////menu + b_menu = menuBar()->addMenu(i18n("2&D Graph")); + QAction* b_actions[6]; + b_actions[0] = b_menu->addAction(i18n("&Grid"), this, SLOT(toggleSquares())); + b_actions[1] = b_menu->addAction(i18n("&Keep Aspect Ratio"), this, SLOT(toggleKeepAspect())); + b_menu->addAction(KStandardAction::save(this, SLOT(saveGraph()), this)); + b_menu->addSeparator(); + b_menu->addAction(KStandardAction::zoomIn(m_graph2d, SLOT(zoomIn()), this)); + b_menu->addAction(KStandardAction::zoomOut(m_graph2d, SLOT(zoomOut()), this)); + KAction* ac=KStandardAction::actualSize(m_graph2d, SLOT(resetViewport()), this); + ac->setShortcut(Qt::ControlModifier + Qt::Key_0); + b_menu->addAction(ac); + b_menu->addSeparator()->setText(i18n("Resolution")); + b_actions[2] = b_menu->addAction(i18nc("@item:inmenu", "Poor"), this, SLOT(set_res_low())); + b_actions[3] = b_menu->addAction(i18nc("@item:inmenu", "Normal"), this, SLOT(set_res_std())); + b_actions[4] = b_menu->addAction(i18nc("@item:inmenu", "Fine"), this, SLOT(set_res_fine())); + b_actions[5] = b_menu->addAction(i18nc("@item:inmenu", "Very Fine"), this, SLOT(set_res_vfine())); + m_graph2d->setContextMenuPolicy(Qt::ActionsContextMenu); + m_graph2d->addActions(b_menu->actions()); + + QActionGroup *res = new QActionGroup(b_menu); + res->addAction(b_actions[2]); + res->addAction(b_actions[3]); + res->addAction(b_actions[4]); + res->addAction(b_actions[5]); + + b_actions[0]->setCheckable(true); + b_actions[0]->setChecked(true); + b_actions[1]->setCheckable(true); + b_actions[1]->setChecked(true); + b_actions[2]->setCheckable(true); + b_actions[3]->setCheckable(true); + b_actions[3]->setChecked(true); + b_actions[4]->setCheckable(true); + b_actions[5]->setCheckable(true); + set_res_std(); + //////EO2D Graph + + /////3DGraph +#ifdef HAVE_OPENGL + QWidget *tridim = new QWidget(m_tabs); + QVBoxLayout *t_layo = new QVBoxLayout(tridim); + t_exp = new Analitza::ExpressionEdit(tridim); + t_exp->setExamples(QStringList() << "sin x+sin y" << "(x,y)->x" << "x*y"); + t_exp->setAns("x"); + t_model3d = new Analitza::PlotsModel(this); + m_graph3d = new Analitza::PlotsView3D(tridim); + m_graph3d->setModel(t_model3d); + m_graph3d->setUseSimpleRotation(true); + + tridim->setLayout(t_layo); + m_tabs->addTab(tridim, i18n("&3D Graph")); + t_layo->addWidget(m_graph3d); + t_layo->addWidget(t_exp); + + connect(t_exp, SIGNAL(returnPressed()), this, SLOT(new_func3d())); + c_results->addOptionsObserver(new Add3DOption(this)); + + ////////menu + t_menu = menuBar()->addMenu(i18n("3D &Graph")); + QAction* t_actions[5]; + t_menu->addAction(KStandardAction::save(this, SLOT(save3DGraph()), this)); + t_menu->addAction(KIcon("zoom-original"), i18n("&Reset View"), m_graph3d, SLOT(resetView())); + t_menu->addSeparator(); + t_actions[2] = t_menu->addAction(i18n("Dots"), this, SLOT(set_dots())); + t_actions[3] = t_menu->addAction(i18n("Lines"), this, SLOT(set_lines())); + t_actions[4] = t_menu->addAction(i18n("Solid"), this, SLOT(set_solid())); + + QActionGroup *t_type = new QActionGroup(t_menu); + t_type->addAction(t_actions[2]); + t_type->addAction(t_actions[3]); + t_type->addAction(t_actions[4]); + + t_actions[2]->setCheckable(true); + t_actions[3]->setCheckable(true); + t_actions[4]->setCheckable(true); + t_actions[4]->setChecked(true); +#endif + //////////// + //////EO3D Graph + menuBar()->addMenu("|")->setEnabled(false); + + //Dictionary tab + d_dock = new QDockWidget(i18n("Operations"), this); + d_dock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); + addDockWidget(Qt::RightDockWidgetArea, d_dock); + Dictionary *dic = new Dictionary(m_tabs); + m_tabs->addTab(dic, i18n("&Dictionary")); + + QWidget *w=new QWidget; + QLayout *leftLayo=new QVBoxLayout(w); + d_filter=new KLineEdit(w); + d_filter->setClearButtonShown(true); + d_filter->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed)); + connect(d_filter, SIGNAL(textChanged(QString)), dic, SLOT(setFilter(QString))); + connect(d_filter, SIGNAL(textChanged(QString)), this, SLOT(dictionaryFilterChanged(QString))); + d_list = new QListView(w); + d_list->setModel(dic->model()); + d_list->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding)); + leftLayo->addWidget(new QLabel(i18n("Look for:"), d_dock)); + leftLayo->addWidget(d_filter); + leftLayo->addWidget(d_list); + d_dock->setWidget(w); + + connect(d_list->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), + dic, SLOT(activated(QModelIndex,QModelIndex))); + + //EODictionary + //Ego's reminder + KHelpMenu* help = new KHelpMenu(this, KGlobal::mainComponent().aboutData()); + menuBar()->addMenu(help->menu()); + +#warning TODO: Port to PlotsModel +// connect(b_funcsModel, SIGNAL(functionModified(QString,Analitza::Expression)), +// c_results, SLOT(modifyVariable(QString,Analitza::Expression))); +// connect(b_funcsModel, SIGNAL(functionRemoved(QString)), +// c_results, SLOT(removeVariable(QString))); + + connect(m_tabs, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int))); + tabChanged(0); +} + +KAlgebra::~KAlgebra() +{ + KConfig conf("kalgebrarc"); + KConfigGroup config(&conf, "Default"); + QStringList urls; + foreach(const KUrl& url, c_recentScripts->urls()) + urls += url.prettyUrl(); + + config.writeEntry("recent", urls); +} + +void KAlgebra::initializeRecentScripts() +{ + KConfig conf("kalgebrarc"); + KConfigGroup config(&conf, "Default"); + + QStringList urls=config.readEntry("recent", QStringList()); + foreach(const QString& url, urls) { + c_recentScripts->addUrl(KUrl(url)); + } +} + +void KAlgebra::newInstance() +{ + KProcess::startDetached(QApplication::applicationFilePath()); +} + +void KAlgebra::add2D(const Analitza::Expression& exp) +{ + qDebug() << "adding" << exp.toString(); + + Analitza::PlotBuilder req = Analitza::PlotsFactory::self()->requestPlot(exp, Analitza::Dim2D, c_results->analitza()->variables()); + Analitza::PlotItem* curve = req.create(randomFunctionColor(), b_funcsModel->freeId()); + b_funcsModel->addPlot(curve); + + m_tabs->setCurrentIndex(1); +} + +void KAlgebra::new_func() +{ + Analitza::FunctionGraph* f=b_funced->createFunction(); + + if(b_funced->editing()) { + QModelIndex idx = b_funcsModel->indexForName(f->name()); + b_funcsModel->updatePlot(idx.row(), f); + } else { + b_funcsModel->addPlot(f); + } + + b_funced->setEditing(false); + b_funced->clear(); + b_tools->setCurrentIndex(0); + b_funcs->setCurrentIndex(b_funcsModel->indexForName(f->name())); + m_graph2d->setFocus(); +} + +void KAlgebra::remove_func() +{ + Q_ASSERT(b_funced->editing()); + b_funcsModel->removeRow(b_funcs->currentIndex().row()); + + b_funced->setEditing(false); + b_funced->clear(); + b_tools->setCurrentIndex(0); + b_funcs->setCurrentIndex(QModelIndex()); + m_graph2d->setFocus(); +} + +void KAlgebra::edit_func(const QModelIndex &idx) +{ + b_tools->setTabText(1, i18n("&Editing")); + b_tools->setCurrentIndex(1); + b_funced->setName(b_funcsModel->data(idx.sibling(idx.row(), 0)).toString()); + b_funced->setFunction(b_funcsModel->data(idx.sibling(idx.row(), 1)).toString()); + b_funced->setEditing(true); + b_funced->setFocus(); +} + +void KAlgebra::functools(int i) +{ + if(i==0) + b_tools->setTabText(1, i18n("&Add")); + else { + b_funced->setName(b_funcsModel->freeId()); + b_funced->setColor(randomFunctionColor()); + b_funced->setEditing(false); + b_funced->setFocus(); + } +} + +void KAlgebra::edit_var(const QModelIndex &idx) +{ + if(idx.column()==0) { + c_exp->insertText(idx.data().toString()); + } else { + QModelIndex idxName=idx.sibling(idx.row(), 0); + + QPointer e(new VarEdit(this, false)); + QString var = c_variables->model()->data(idxName, Qt::DisplayRole).toString(); + + e->setAnalitza(c_results->analitza()); + e->setName(var); + + if(e->exec() == QDialog::Accepted) { + QString str=var+" := "+e->val().toString(); + c_results->addOperation(Analitza::Expression(str, false), str); + } + delete e; + } +} + +void KAlgebra::operate() +{ + if(!c_exp->text().isEmpty()){ + c_exp->setCorrect(c_results->addOperation(c_exp->expression(), c_exp->toPlainText())); + c_exp->selectAll(); + } +} + +void KAlgebra::changeStatusBar(const QString& msg) +{ +// statusBar()->showMessage(msg); + m_status->setText(msg); +} + +void KAlgebra::loadScript() +{ + KUrl path = KFileDialog::getOpenUrl(KUrl(), "*.kal|"+i18n("Script (*.kal)"), this, i18n("Choose a script")); + + if(!path.isEmpty()) + loadScript(path); +} + +void KAlgebra::loadScript(const KUrl& path) +{ + bool loaded=c_results->loadScript(path); + + if(loaded) + c_recentScripts->addUrl(path); +} + +void KAlgebra::saveScript() +{ + KUrl path = KFileDialog::getSaveUrl(KUrl(), "*.kal|"+i18n("Script (*.kal)"), this, QString(), KFileDialog::ConfirmOverwrite); + bool loaded=false; + if(!path.isEmpty()) + loaded=c_results->saveScript(path); + + if(loaded) + c_recentScripts->addUrl(path); +} + +void KAlgebra::saveLog() +{ + KUrl path = KFileDialog::getSaveUrl(KUrl(), "*.html|"+i18n("HTML File (*.html)"), this, QString(), KFileDialog::ConfirmOverwrite); + if(!path.isEmpty()) + c_results->saveLog(path); +} + +void KAlgebra::set_res_low() { b_funcsModel->setResolution(416); } +void KAlgebra::set_res_std() { b_funcsModel->setResolution(832); } +void KAlgebra::set_res_fine() { b_funcsModel->setResolution(1664);} +void KAlgebra::set_res_vfine() { b_funcsModel->setResolution(3328);} + +void KAlgebra::new_func3d() +{ +#ifdef HAVE_OPENGL + Analitza::Expression exp = t_exp->expression(); + Analitza::PlotBuilder plot = Analitza::PlotsFactory::self()->requestPlot(exp, Analitza::Dim3D, c_results->analitza()->variables()); + if(plot.canDraw()) { + t_model3d->clear(); + t_model3d->addPlot(plot.create(Qt::yellow, "func3d")); + } else + changeStatusBar(i18n("Errors: %1", plot.errors().join(i18n(", ")))); +#endif +} + +void KAlgebra::set_dots() +{ +#ifdef HAVE_OPENGL + m_graph3d->setPlotStyle(Analitza::Dots); +#endif +} + +void KAlgebra::set_lines() +{ +#ifdef HAVE_OPENGL + m_graph3d->setPlotStyle(Analitza::Wired); +#endif +} + +void KAlgebra::set_solid() +{ +#ifdef HAVE_OPENGL + m_graph3d->setPlotStyle(Analitza::Solid); +#endif +} + +void KAlgebra::save3DGraph() +{ +#ifdef HAVE_OPENGL + QString path = KFileDialog::getSaveFileName(KUrl(), i18n("*.png|PNG File\n*.pdf|PDF Document"), this, QString(), KFileDialog::ConfirmOverwrite); + if(!path.isEmpty()) { + QPixmap px = m_graph3d->renderPixmap(); + if(path.endsWith(".pdf")) { + QPrinter printer; + printer.setOutputFormat(QPrinter::PdfFormat); + printer.setOutputFileName(path); + printer.setPaperSize(px.size(), QPrinter::DevicePixel); + printer.setPageMargins(0,0,0,0, QPrinter::DevicePixel); + QPainter painter; + painter.begin(&printer); + painter.drawPixmap(QPoint(0,0), px); + painter.end(); + } else { + px.save(path); + } + } +#endif +} + +void KAlgebra::toggleSquares() +{ + m_graph2d->setShowGrid(!m_graph2d->showGrid()); +} + +void KAlgebra::toggleKeepAspect() +{ + m_graph2d->setKeepAspectRatio(!m_graph2d->keepAspectRatio()); +} + +void KAlgebra::saveGraph() +{ + QPointer dialog=new KFileDialog(KUrl(), i18n("*.png|Image File\n*.svg|SVG File"), this); + dialog->setOperationMode(KFileDialog::Saving); + dialog->setConfirmOverwrite(true); + + if(dialog->exec()) { + QString filter = dialog->fileWidget()->currentFilter(); + QString filename = dialog->selectedFile(); + + bool isSvg = filename.endsWith(".svg") || (!filename.endsWith(".png") && filter.mid(2, 3)=="svg"); + Analitza::PlotsView2D::Format f = isSvg ? Analitza::PlotsView2D::PNG : Analitza::PlotsView2D::SVG; + m_graph2d->toImage(filename, f); + } + delete dialog; +} + +void menuEnabledHelper(QMenu* m, bool enabled) +{ + m->setEnabled(enabled); + foreach(QAction* action, m->actions()) { + action->setEnabled(enabled); + } +} + +void KAlgebra::tabChanged(int n) +{ + c_dock_vars->hide(); + b_dock_funcs->hide(); + d_dock->hide(); + + menuEnabledHelper(c_menu, n==0); + menuEnabledHelper(b_menu, n==1); +#ifdef HAVE_OPENGL + menuEnabledHelper(t_menu, n==2); +#endif + m_status->clear(); + + switch(n) { + case 0: + c_dock_vars->show(); + c_dock_vars->raise(); + c_exp->setFocus(); + break; + case 1: + b_dock_funcs->show(); + b_dock_funcs->raise(); + + if(b_funcsModel->rowCount()==0) + b_tools->setCurrentIndex(1); //We set the Add tab +// b_add->setFocus(); + break; +#ifdef HAVE_OPENGL + case 2: + t_exp->setFocus(); + break; +#endif + case 3: + d_filter->setFocus(); + d_dock->show(); + d_dock->raise(); + default: + break; + } + changeStatusBar(i18nc("@info:status", "Ready")); +} + +void KAlgebra::select(const QModelIndex & idx) +{ + b_funcs->selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect); +} + +void KAlgebra::updateInformation() +{ + c_varsModel->updateInformation(); + c_variables->header()->resizeSections(QHeaderView::ResizeToContents); +} + +void KAlgebra::consoleCalculate() +{ + c_results->setMode(ConsoleHtml::Calculation); +} + +void KAlgebra::consoleEvaluate() +{ + c_results->setMode(ConsoleHtml::Evaluation); +} + +void KAlgebra::valueChanged() +{ + //FIXME: Should only repaint the affected ones. + if(b_funcsModel->rowCount()>0) + m_graph2d->updateFunctions(QModelIndex(), 0, b_funcsModel->rowCount()-1); +} + +void KAlgebra::varsContextMenu(const QPoint& p) +{ + QPointer m=new QMenu; + m->addAction(i18n("Add variable")); + QAction* ac=m->exec(b_dock_funcs->widget()->mapToGlobal(p)); + + if(ac) { + QPointer a=new AskName(i18n("Enter a name for the new variable"), 0); + + if(a->exec()==QDialog::Accepted) + b_varsModel->insertVariable(a->name(), Analitza::Expression(Analitza::Cn(0))); + delete a; + } + delete m; +} + +void KAlgebra::add3D(const Analitza::Expression& exp) +{ +#ifdef HAVE_OPENGL + t_model3d->clear(); + Analitza::PlotBuilder plot = Analitza::PlotsFactory::self()->requestPlot(exp, Analitza::Dim3D, c_results->analitza()->variables()); + Q_ASSERT(plot.canDraw()); + t_model3d->addPlot(plot.create(Qt::yellow, "func3d_console")); + m_tabs->setCurrentIndex(2); +#endif +} + +void KAlgebra::dictionaryFilterChanged(const QString&) +{ + if(d_list->model()->rowCount()==1) + d_list->setCurrentIndex(d_list->model()->index(0,0)); +} + +void KAlgebra::fullScreen(bool isFull) +{ + m_tabs->setDocumentMode(isFull); + m_tabs->setTabEnabled(3, !isFull); + if(isFull) { + hide(); + m_tabs->setParent(0); + setCentralWidget(0); + m_tabs->showFullScreen(); + } else { + setCentralWidget(m_tabs); + show(); + } +} diff --git a/src/kalgebra.desktop b/src/kalgebra.desktop new file mode 100755 index 0000000..cbba8eb --- /dev/null +++ b/src/kalgebra.desktop @@ -0,0 +1,175 @@ +[Desktop Entry] +Name=KAlgebra +Name[ast]=KAlgebra +Name[bg]=KAlgebra +Name[bs]=Kalgebra +Name[ca]=KAlgebra +Name[ca@valencia]=KAlgebra +Name[cs]=KAlgebra +Name[csb]=KAlgebra +Name[da]=KAlgebra +Name[de]=KAlgebra +Name[el]=KAlgebra +Name[en_GB]=KAlgebra +Name[eo]=KAlgebra +Name[es]=KAlgebra +Name[et]=KAlgebra +Name[eu]=KAlgebra +Name[fi]=KAlgebra +Name[fr]=KAlgebra +Name[ga]=KAlgebra +Name[gl]=KAlgebra +Name[gu]=KAlgebra +Name[he]=KAlgebra +Name[hi]=के-अलजेब्रा +Name[hne]=के-अलजेब्रा +Name[hr]=KAlgebra +Name[hu]=KAlgebra +Name[is]=KAlgebra +Name[it]=KAlgebra +Name[ja]=KAlgebra +Name[kk]=KAlgebra +Name[km]=KAlgebra +Name[ko]=KAlgebra +Name[lt]=KAlgebra +Name[lv]=KAlgebra +Name[ml]=കെ-ആള്‍ജിബ്ര +Name[mr]=के-एल्जिब्रा +Name[nb]=KAlgebra +Name[nds]=KAlgebra +Name[ne]=केडीई बीजगणित +Name[nl]=KAlgebra +Name[nn]=KAlgebra +Name[pa]=ਕੇ-ਐਲਜਬਰਾ +Name[pl]=KAlgebra +Name[pt]=KAlgebra +Name[pt_BR]=KAlgebra +Name[ro]=KAlgebra +Name[ru]=KAlgebra +Name[si]=KAlgebra +Name[sk]=KAlgebra +Name[sl]=KAlgebra +Name[sv]=Kalgebra +Name[te]=కె అల్జీబ్రా +Name[tr]=KAlgebra +Name[ug]=KAlgebra +Name[uk]=KАлгебра +Name[x-test]=xxKAlgebraxx +Name[zh_CN]=KAlgebra +Name[zh_TW]=數學_KAlgebra +GenericName=Graph Calculator +GenericName[ast]=Calculadora gráfica +GenericName[bg]=Графичен калкулатор +GenericName[bs]=Graf kalkulator +GenericName[ca]=Calculadora gràfica +GenericName[ca@valencia]=Calculadora gràfica +GenericName[cs]=Kalkulačka grafů +GenericName[csb]=Kalkùlator +GenericName[da]=Diagramberegner +GenericName[de]=Graphenrechner +GenericName[el]=Γραφικός υπολογιστής +GenericName[en_GB]=Graph Calculator +GenericName[eo]=Kalkulilo de grafikaĵoj +GenericName[es]=Calculadora gráfica +GenericName[et]=Graafikute arvutaja +GenericName[eu]=Grafikoen kalkulagailua +GenericName[fa]=ماشین حساب گراف +GenericName[fi]=Graafinen laskin +GenericName[fr]=Calculatrice graphique +GenericName[ga]=Áireamhán Grafach +GenericName[gl]=Calculadora gráfica +GenericName[gu]=આલેખ કેલ્ક્યુલેટર +GenericName[he]=מחשבון גרפי +GenericName[hi]=ग्राफ गणक +GenericName[hne]=ग्राफ गनक +GenericName[hu]=Függvényszámító +GenericName[is]=Reiknivél fyrir gröf +GenericName[it]=Calcolatrice grafica +GenericName[ja]=グラフ計算機 +GenericName[kk]=График калькуляторы +GenericName[km]=ម៉ាស៊ីន​គិតលេខ​ក្រាហ្វិក​ +GenericName[ko]=그래핑 계산기 +GenericName[lt]=Grafinis skaičiuotuvas +GenericName[lv]=Grafiskais kalkulators +GenericName[ml]=ഗ്രാഫ് ഗണനി +GenericName[mr]=आलेख गणकयंत्र +GenericName[nb]=Grafikk-kalkulator +GenericName[nds]=Funkschonenreekner +GenericName[ne]=ग्राफ गणकयन्त्र +GenericName[nl]=Rekenmachine met grafieken +GenericName[nn]=Ein grafkalkulator +GenericName[pa]=ਗਰਾਫ਼ ਕੈਲਕੂਲੇਟਰ +GenericName[pl]=Kalkulator wykresów +GenericName[pt]=Calculadora Gráfica +GenericName[pt_BR]=Calculadora gráfica +GenericName[ru]=Графический калькулятор +GenericName[sk]=Grafická kalkulačka +GenericName[sl]=Računalo z grafi +GenericName[sv]=Grafräknare +GenericName[te]=రేఖాచిత్ర గనన యంత్రము +GenericName[tr]=Grafik Hesap Makinesi +GenericName[uk]=Графічний калькулятор +GenericName[x-test]=xxGraph Calculatorxx +GenericName[zh_CN]=图形计算器 +GenericName[zh_TW]=圖形計算器 +Comment=Math Expression Solver and Plotter +Comment[ast]=Resolver y trazar espresiones matemátiques +Comment[bg]=Решаване на математически задачи +Comment[bs]=Matematski Sistem za rješavanje i crtač +Comment[ca]=Soluciona i representa gràficament expressions matemàtiques +Comment[ca@valencia]=Soluciona i representa gràficament expressions matemàtiques +Comment[cs]=Řešitel a souřadnicový zapisovač matematických výrazů +Comment[csb]=Rozrzeszëwôcz matematicznëch równaniów ë rësowôcz grafów +Comment[da]=Løser og plotter til matematiske udtryk +Comment[de]=Mathematische Gleichungslösung und -zeichnung +Comment[el]=Σχεδιαστής και επιλυτής μαθηματικών εκφράσεων +Comment[en_GB]=Mathematical Expression Solver and Plotter +Comment[eo]=Solvilo kaj desegnilo de matematikaj esprimoj +Comment[es]=Resuelve y dibuja expresiones matemáticas +Comment[et]=Matemaatiliste avaldiste lahendaja ja joonistaja +Comment[eu]=Matematika adierazpenen ebazlea edo marrazlea +Comment[fa]=حل‌کننده و رسام عبارت ریاضی +Comment[fi]=Matemaattisten yhtälöiden ratkaisut ja kuvaajat +Comment[fr]=Traceur et résolveur d'expressions mathématiques +Comment[ga]=Réiteoir agus Breacaire Sloinn Mhatamaiticiúla +Comment[gl]=Ferramenta para resolver e debuxar expresións matemáticas +Comment[gu]=ગાણિતિક સૂત્રો ઉકેલનાર અને આલેખનાર +Comment[he]=פותר ומשרטט ביטויים מתמטיים +Comment[hi]=गणित एक्सप्रेशन सुलझाने वाला तथा प्लॉटर +Comment[hne]=गनित एक्सप्रेसन सुलझाने वाला अउ प्लाटर +Comment[hr]=Rješavač i crtač za matematičke izraze +Comment[hu]=Matematikai egyenletek megoldása, görberajzolás +Comment[is]=Stærðfræðilausnir og plottun +Comment[it]=Risolutore e disegnatore di espressioni matematiche +Comment[ja]=数式ソルバー&プロッタ +Comment[kk]=Математикалық өрнегін есептеп графигін салу +Comment[km]=ឧបករណ៍​គូស​ក្រាហ្វិក និង​កម្មវិធី​ដោះស្រាយ​កន្សោម​​​គណិត +Comment[ko]=수식 계산기와 그래핑 도구 +Comment[lt]=Matematinių reiškinių sprendikas ir grafikų braižiklis +Comment[lv]=Matemātisko izteiksmju risinātājs un attēlotājs +Comment[ml]=ഗണിതസൂത്ര പരിഹാരകനും പ്ലോട്ടറും +Comment[nb]=Matematisk uttrykksløser og plotter +Comment[nds]=Löser för mathemaatsche Utdrück un Bagenschriever +Comment[ne]=म्याथ अभिव्यक्ति समाधानकर्ता र प्लोटर +Comment[nl]=Oplossen en plotten van wiskundige expressies +Comment[nn]=Matteoppgåveløysar og grafplottar +Comment[pl]=Rozwiązywanie równań i rysowanie wykresów +Comment[pt]=Resolução e Desenho de Expressões Matemáticas +Comment[pt_BR]=Solucionador e visualizador de expressões matemáticas +Comment[ru]=Решение и построение графиков математических выражений +Comment[sk]=Riešiteľ a zapisovač matematických výrazov +Comment[sl]=Reševalnik matematičnih enačb in risalnik grafov +Comment[sv]=Lösning och uppritning av matematiska uttryck +Comment[tr]=Matematiksel İfade Çözücü ve Çizici +Comment[ug]=ماتېماتىكىلىق ئىپادىلەرنى يېشىش ۋە سىزىش قورالى +Comment[uk]=Розв’язувач математичних виразів та графопобудовник +Comment[x-test]=xxMath Expression Solver and Plotterxx +Comment[zh_CN]=解数学式与绘图的工具 +Comment[zh_TW]=數學解題與繪圖 +Exec=kalgebra +MimeType=application/x-kalgebra; +Icon=kalgebra +Type=Application +X-DocPath=kalgebra/index.html +Terminal=false +Categories=Qt;KDE;Education;Math;Science; diff --git a/src/kalgebra.h b/src/kalgebra.h new file mode 100644 index 0000000..b03a72e --- /dev/null +++ b/src/kalgebra.h @@ -0,0 +1,132 @@ +/************************************************************************************* + * Copyright (C) 2007 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 KALGEBRA_H +#define KALGEBRA_H + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Analitza { +class PlotsView2D; +class PlotsView3D; +class PlotsModel; +class VariablesModel; +class ExpressionEdit; +} + +class ConsoleHtml; +class FunctionEdit; +class KRecentFilesAction; + +namespace Analitza { class Expression; } + +class KAlgebra : public KMainWindow +{ + Q_OBJECT + public: + KAlgebra ( QWidget *parent=0 ); + ~KAlgebra(); + + void add2D(const Analitza::Expression& exp); + void add3D(const Analitza::Expression& exp); + private: + QLabel *m_status; + QTabWidget* m_tabs; + + //consoleeWidget + QMenu* c_menu; + KRecentFilesAction* c_recentScripts; + Analitza::ExpressionEdit *c_exp; + ConsoleHtml *c_results; + QTreeView *c_variables; + QDockWidget *c_dock_vars; + Analitza::VariablesModel* c_varsModel; + + //graf 2d + QMenu* b_menu; + Analitza::PlotsModel* b_funcsModel; + QTreeView *b_funcs; + QTabWidget *b_tools; + Analitza::PlotsView2D *m_graph2d; + QDockWidget *b_dock_funcs; + FunctionEdit *b_funced; + Analitza::VariablesModel* b_varsModel; + +#ifdef HAVE_OPENGL + //graph 3d + QMenu* t_menu; + Analitza::ExpressionEdit *t_exp; + Analitza::PlotsView3D *m_graph3d; + Analitza::PlotsModel* t_model3d; +#endif + //Dictionary + QDockWidget *d_dock; + QListView *d_list; + KLineEdit *d_filter; + + private slots: + void newInstance(); + void fullScreen(bool isFull); + + void initializeRecentScripts(); + void operate(); + void loadScript(); + void loadScript(const KUrl& path); + void saveScript(); + void saveLog(); + void updateInformation(); + void consoleCalculate(); + void consoleEvaluate(); + + void select(const QModelIndex& idx); + void new_func(); + void remove_func(); + void edit_func ( const QModelIndex & ); + void edit_var ( const QModelIndex & ); + void toggleSquares(); + void toggleKeepAspect(); + void set_res_low(); + void set_res_std(); + void set_res_fine(); + void set_res_vfine(); + void valueChanged(); + void varsContextMenu(const QPoint&); + + void new_func3d(); + void set_dots(); + void set_lines(); + void set_solid(); + void save3DGraph(); + + void saveGraph(); + void functools ( int ); + + void dictionaryFilterChanged(const QString& filter); + + void changeStatusBar ( const QString & ); + void tabChanged ( int ); +}; + +#endif diff --git a/src/kalgebra.xml b/src/kalgebra.xml new file mode 100644 index 0000000..d9b95c2 --- /dev/null +++ b/src/kalgebra.xml @@ -0,0 +1,174 @@ + + + + + + + + + + + + piecewise + list + vector + ? + + + + e + euler + false + pi + true + ans + + + + @ + abs + and + approx + arccos + arccosh + arccot + arcsc + arcsch + arcsec + arcsech + arcsin + arcsinh + arctan + arctanh + card + ceiling + cos + cosh + cot + coth + csc + csch + diff + divide + eq + exp + factorial + factorof + floor + fmod + gcd + geq + gt + implies + lcm + leq + ln + log + lt + max + min + minus + neq + not + or + plus + power + product + quotient + rem + root + scalarprod + sec + sech + selector + sin + sinh + sum em> + tan + tanh + times + union + xor + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..6020697 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,42 @@ +/************************************************************************************* + * Copyright (C) 2007 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 +#include +#include +#include "kalgebra.h" + +int main(int argc, char *argv[]) +{ + KAboutData about("kalgebra", 0, ki18n(("KAlgebra")), "0.11", ki18n("A calculator"), + KAboutData::License_GPL, ki18n("(C) 2006-2010 Aleix Pol Gonzalez")); + about.addAuthor( ki18n("Aleix Pol Gonzalez"), KLocalizedString(), "aleixpol@kde.org" ); + about.addAuthor( ki18n("Percy Camilo Triveño Aucahuasi"), ki18n("Developed feature for drawing implicit curves. Improvements for plotting functions."), + "percy.camilo.ta@gmail.com" ); + KCmdLineArgs::init(argc, argv, &about); + KApplication app; + + /*if(app.isSessionRestored()) { + RESTORE(KAlgebra); + } else {*/ + KAlgebra* widget = new KAlgebra; + widget->show(); + //} + + return app.exec(); +} diff --git a/src/varedit.cpp b/src/varedit.cpp new file mode 100644 index 0000000..20e2007 --- /dev/null +++ b/src/varedit.cpp @@ -0,0 +1,139 @@ +/************************************************************************************* + * Copyright (C) 2007 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 "varedit.h" +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +VarEdit::VarEdit(QWidget *parent, bool modal) : + KDialog(parent), vars(0), m_correct(false) +{ + QWidget *widget = new QWidget( this ); + setCaption(i18n("Add/Edit a variable")); + setModal(modal); + setButtons(KDialog::User1 | KDialog::Ok | KDialog::Cancel); + enableButtonApply( false ); + setMainWidget( widget ); + + setButtonText(KDialog::User1, i18n("Remove Variable")); + + setButtonIcon(KDialog::User1, KIcon("edit-table-delete-row")); + setButtonIcon(KDialog::Ok, KIcon("dialog-ok")); + setButtonIcon(KDialog::Cancel, KIcon("dialog-cancel")); + + connect(button(KDialog::User1), SIGNAL(clicked(bool)), SLOT(removeVariable())); + + connect( this, SIGNAL(applyClicked()), this, SLOT(accept()) ); + connect( this, SIGNAL(okClicked()), this, SLOT(reject()) ); + + m_exp = new Analitza::ExpressionEdit(widget); + connect(m_exp, SIGNAL(textChanged()), this, SLOT(edit())); + connect(m_exp, SIGNAL(returnPressed()), this, SLOT(ok())); + + m_valid = new QLabel(widget); + + QVBoxLayout *topLayout = new QVBoxLayout(widget); + topLayout->addWidget(m_exp); + topLayout->addWidget(m_valid); + + m_exp->setFocus(); +} + +void VarEdit::setName(const QString& newVar) +{ + m_var=newVar; + setWindowTitle(i18n("Edit '%1' value", newVar)); + if(!vars) + m_exp->setText(i18n("not available")); + else { + m_exp->setExpression(Analitza::Expression(vars->value(newVar)->copy())); + } + + button(KDialog::User1)->setEnabled(canRemove(newVar)); +} + +bool VarEdit::canRemove(const QString& name) const +{ + QHash::const_iterator it = vars->constBegin(), itEnd = vars->constEnd(); + for(; it!=itEnd; ++it) { + QStringList deps = AnalitzaUtils::dependencies(*it, QStringList()); + if(deps.contains(name)) { + return false; + } + } + return true; +} + +Analitza::Expression VarEdit::val() +{ + Analitza::Expression val; + Analitza::Analyzer a(vars); + + a.setExpression(m_exp->expression()); + + if(a.isCorrect()) { + a.simplify(); + val=a.expression(); + } + + m_correct = a.isCorrect(); + if(m_correct) { + m_valid->setText(i18n("%1 := %2", m_var, val.toString())); + m_valid->setToolTip(QString()); + } else { + m_valid->setText(i18n("WRONG")); + m_valid->setToolTip(a.errors().join("\n")); + } + button(Ok)->setEnabled(m_correct); + m_exp->setCorrect(m_correct); + + return val; +} + +void VarEdit::edit() +{ + val(); +} + +void VarEdit::ok() +{ + if(m_correct) + accept(); +} + +void VarEdit::setAnalitza(Analitza::Analyzer * na) +{ + vars= na->variables(); + m_exp->setAnalitza(na); +} + +void VarEdit::removeVariable() +{ + vars->remove(m_var); + close(); +} diff --git a/src/varedit.h b/src/varedit.h new file mode 100644 index 0000000..320b362 --- /dev/null +++ b/src/varedit.h @@ -0,0 +1,74 @@ +/************************************************************************************* + * Copyright (C) 2007 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 VAREDIT_H +#define VAREDIT_H + +#include + +#include +#include + +#include + +namespace Analitza +{ +class Analyzer; +class Variables; +class Expression; +class ExpressionEdit; +} + +/** + * The VarEdit provides a dialog to allow users to edit/create a variable. + * @author Aleix Pol i Gonzalez + */ + +class VarEdit : public KDialog +{ + Q_OBJECT + public: + /** Constructor. Creates a variable editing dialog. */ + explicit VarEdit(QWidget *parent = 0, bool modal = false); + + /** Sets the editing variable name */ + void setName(const QString& newVar); + + /** Sets an Analitza which will evaluate it. It may be interesting because variables can change. */ + void setAnalitza(Analitza::Analyzer *na); + + /** Returns the resulting variable expression */ + Analitza::Expression val(); + + private: + bool canRemove(const QString& name) const; + + Analitza::ExpressionEdit *m_exp; + + QLabel *m_valid; + Analitza::Variables *vars; + bool m_correct; + QString m_var; + + private slots: + void edit(); + void ok(); + void removeVariable(); +}; + +#endif diff --git a/src/variablesdelegate.cpp b/src/variablesdelegate.cpp new file mode 100644 index 0000000..ff6ce70 --- /dev/null +++ b/src/variablesdelegate.cpp @@ -0,0 +1,41 @@ +/************************************************************************************* + * Copyright (C) 2009 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 "variablesdelegate.h" + +#include + +QWidget* VariablesDelegate::createEditor(QWidget* p, const QStyleOptionViewItem& opt, const QModelIndex& idx) const +{ + QVariant val=idx.model()->data(idx); + if(val.type()==QVariant::Double) { + QDoubleSpinBox* spin=new QDoubleSpinBox(p); + spin->setDecimals(10); + return spin; + } else + return QItemDelegate::createEditor(p, opt, idx); +} + +void VariablesDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const +{ + QDoubleSpinBox* spin=qobject_cast(editor); + if(spin) + spin->setValue(index.model()->data(index).value()); + else + QItemDelegate::setEditorData(editor, index); +} diff --git a/src/variablesdelegate.h b/src/variablesdelegate.h new file mode 100644 index 0000000..2783ed2 --- /dev/null +++ b/src/variablesdelegate.h @@ -0,0 +1,32 @@ +/************************************************************************************* + * Copyright (C) 2009 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 VARIABLESDELEGATE_H +#define VARIABLESDELEGATE_H + +#include + +class VariablesDelegate : public QItemDelegate +{ + public: + VariablesDelegate(QObject* parent=0) : QItemDelegate(parent) {} + virtual QWidget* createEditor (QWidget*, const QStyleOptionViewItem&, const QModelIndex&) const; + virtual void setEditorData(QWidget* editor, const QModelIndex& index) const; +}; + +#endif // VARIABLESDELEGATE_H diff --git a/src/viewportwidget.cpp b/src/viewportwidget.cpp new file mode 100644 index 0000000..e99c3ea --- /dev/null +++ b/src/viewportwidget.cpp @@ -0,0 +1,75 @@ +/************************************************************************************* + * Copyright (C) 2009 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 "viewportwidget.h" + +#include +#include +#include +#include +#include +#include + +ViewportWidget::ViewportWidget(QWidget * parent, Qt::WFlags flags) + : QWidget (parent, flags) +{ + const double LIMIT=std::numeric_limits::max(); + + m_top=new QDoubleSpinBox(this); + m_left=new QDoubleSpinBox(this); + m_width=new QDoubleSpinBox(this); + m_height=new QDoubleSpinBox(this); + + m_top->setRange(-LIMIT, LIMIT); + m_left->setRange(-LIMIT, LIMIT); + m_width->setRange(0, LIMIT); + m_height->setRange(0, LIMIT); + + QVBoxLayout* upperLayout=new QVBoxLayout; + setLayout(upperLayout); + QFormLayout* layout=new QFormLayout; + layout->addRow(i18n("Left:"), m_left); + layout->addRow(i18n("Top:"), m_top); + layout->addRow(i18n("Width:"), m_width); + layout->addRow(i18n("Height:"), m_height); + + QPushButton *apply=new KPushButton(KIcon("dialog-ok-apply"), i18n("Apply"), this); + connect(apply, SIGNAL(clicked()), SLOT(emitViewport())); + + upperLayout->addLayout(layout); + upperLayout->addWidget(apply); +} + +QRectF ViewportWidget::viewport() const +{ + return QRectF(m_left->value(), m_top->value(), + m_width->value(), -m_height->value()); +} + +void ViewportWidget::setViewport(const QRectF& current) +{ + m_top->setValue(current.top()); + m_left->setValue(current.left()); + m_width->setValue(current.width()); + m_height->setValue(-current.height()); +} + +void ViewportWidget::emitViewport () +{ + emit viewportChange(viewport()); +} diff --git a/src/viewportwidget.h b/src/viewportwidget.h new file mode 100644 index 0000000..8a35dc0 --- /dev/null +++ b/src/viewportwidget.h @@ -0,0 +1,49 @@ +/************************************************************************************* + * Copyright (C) 2009 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 VIEWPORTWIDGET_H +#define VIEWPORTWIDGET_H + +#include +class QDoubleSpinBox; + +class ViewportWidget : public QWidget +{ + Q_OBJECT + public: + explicit ViewportWidget(QWidget * parent = 0, Qt::WFlags flags = 0); + + QRectF viewport() const; + + public slots: + void setViewport(const QRectF& current); + + private slots: + void emitViewport(); + + signals: + void viewportChange(const QRectF& newViewport); + + private: + QDoubleSpinBox* m_left; + QDoubleSpinBox* m_top; + QDoubleSpinBox* m_width; + QDoubleSpinBox* m_height; +}; + +#endif // VIEWPORTDIALOG_H diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt new file mode 100644 index 0000000..a52a9e6 --- /dev/null +++ b/utils/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(docbook_analitzacommands main.cpp) +target_link_libraries(docbook_analitzacommands ${ANALITZAGUI_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY}) diff --git a/utils/main.cpp b/utils/main.cpp new file mode 100644 index 0000000..646e378 --- /dev/null +++ b/utils/main.cpp @@ -0,0 +1,60 @@ +/************************************************************************************* + * Copyright (C) 2010 by Aleix Pol * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the 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 +#include +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + QApplication app(argc, argv); + OperatorsModel m; + + QFile f(app.arguments().last()); + bool fileopened = f.open(QFile::WriteOnly); + Q_ASSERT(fileopened); + + QTextStream str(&f); + str.setCodec("UTF-8"); + + str << ""; + str << "\n" + "Commands supported by KAlgebra\n"; + + int rows = m.rowCount(), cols = m.columnCount(); + QStringList colHeaders; + for(int i=0; i" << id << "\n"; + for(int c=0; c%1: %2").arg(colHeaders[c]).arg(Qt::escape(m.index(i,c).data().toString())) << '\n'; + + str << "\t\n"; + } + str << "\n"; + + return 0; +} -- 2.30.2