From 7e89cef018bbfafabf5d24f979bebc18509bc259 Mon Sep 17 00:00:00 2001 From: Maximiliano Curia Date: Wed, 23 Nov 2016 19:54:48 +0000 Subject: [PATCH] Import kalgebra_16.08.3.orig.tar.xz [dgit import orig kalgebra_16.08.3.orig.tar.xz] --- CMakeLists.txt | 75 ++ COPYING | 339 ++++++++ COPYING.DOC | 397 ++++++++++ COPYING.LIB | 481 +++++++++++ Mainpage.dox | 5 + TODO | 17 + calgebra/CMakeLists.txt | 19 + calgebra/main.cpp | 158 ++++ calgebra/test_calgebra.py | 18 + cmake/COPYING-CMAKE-SCRIPTS | 22 + cmake/FindReadline.cmake | 12 + config-kalgebra.h.cmake | 1 + doc/CMakeLists.txt | 4 + doc/commands.docbook | 429 ++++++++++ doc/index.docbook | 508 ++++++++++++ doc/kalgebra-2dgraph-window.png | Bin 0 -> 41762 bytes doc/kalgebra-3dgraph-window.png | Bin 0 -> 54228 bytes doc/kalgebra-console-window.png | Bin 0 -> 48997 bytes doc/kalgebra-dictionary-window.png | Bin 0 -> 60041 bytes doc/kalgebra-main-window.png | Bin 0 -> 46156 bytes doc/view-fullscreen.png | Bin 0 -> 514 bytes icons/64-apps-kalgebra.png | Bin 0 -> 1734 bytes icons/CMakeLists.txt | 5 + icons/sc-apps-kalgebra.svgz | 335 ++++++++ kalgebra.kdev4 | 3 + mobile/CMakeLists.txt | 32 + mobile/kalgebramobile.cpp | 83 ++ mobile/kalgebramobile.desktop | 138 ++++ mobile/kalgebramobile.h | 59 ++ mobile/kalgebramobileharmattan.desktop | 151 ++++ mobile/main.cpp | 65 ++ mobile/plugins/About.qml | 72 ++ mobile/plugins/CMakeLists.txt | 9 + mobile/plugins/Console.qml | 54 ++ mobile/plugins/Dictionary.qml | 71 ++ mobile/plugins/Plot2D.qml | 74 ++ mobile/plugins/Plot3D.qml | 87 ++ mobile/plugins/Tables.qml | 92 +++ mobile/plugins/VariablesView.qml | 14 + mobile/plugins/kalgebraabout.json | 12 + mobile/plugins/kalgebraconsole.json | 13 + mobile/plugins/kalgebradictionary.json | 13 + mobile/plugins/kalgebraplot2d.json | 13 + mobile/plugins/kalgebraplot3d.json | 13 + mobile/plugins/kalgebratables.json | 13 + mobile/plugins/kalgebravariables.json | 13 + mobile/plugins/resources/kde-edu-logo.png | Bin 0 -> 16041 bytes mobile/plugins/widgets/CMakeLists.txt | 6 + mobile/plugins/widgets/kde/CMakeLists.txt | 13 + .../plugins/widgets/kde/ConsoleDelegate.qml | 28 + mobile/plugins/widgets/kde/KAlgebraMobile.qml | 65 ++ mobile/plugins/widgets/kde/KAlgebraPage.qml | 14 + mobile/plugins/widgets/kde/Keyboard.qml | 45 ++ mobile/plugins/widgets/kde/SimpleListView.qml | 14 + mobile/plugins/widgets/material/AddButton.qml | 14 + mobile/plugins/widgets/material/Button.qml | 39 + .../plugins/widgets/material/CMakeLists.txt | 8 + .../plugins/widgets/material/CalcButton.qml | 4 + mobile/plugins/widgets/material/ComboBox.qml | 6 + mobile/plugins/widgets/material/Dialog.qml | 4 + .../widgets/material/ExpressionInput.qml | 19 + .../widgets/material/KAlgebraMobile.qml | 90 +++ .../plugins/widgets/material/KAlgebraPage.qml | 6 + mobile/plugins/widgets/material/Label.qml | 4 + mobile/plugins/widgets/material/RealInput.qml | 46 ++ .../widgets/material/SimpleListView.qml | 23 + 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 | 62 ++ .../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/qmldir | 12 + .../plugins/widgets/qtcontrols/AddButton.qml | 14 + mobile/plugins/widgets/qtcontrols/Button.qml | 4 + .../plugins/widgets/qtcontrols/CMakeLists.txt | 7 + .../plugins/widgets/qtcontrols/CalcButton.qml | 4 + .../plugins/widgets/qtcontrols/ComboBox.qml | 4 + mobile/plugins/widgets/qtcontrols/Dialog.qml | 10 + .../widgets/qtcontrols/ExpressionInput.qml | 7 + .../widgets/qtcontrols/KAlgebraMobile.qml | 75 ++ .../widgets/qtcontrols/KAlgebraPage.qml | 6 + mobile/plugins/widgets/qtcontrols/Label.qml | 4 + .../plugins/widgets/qtcontrols/RealInput.qml | 46 ++ .../widgets/qtcontrols/SimpleListView.qml | 43 + mobile/pluginsmodel.cpp | 105 +++ mobile/pluginsmodel.h | 45 ++ mobile/resources.qrc | 9 + org.kde.kalgebra.appdata.xml | 111 +++ plasmoids/CMakeLists.txt | 6 + plasmoids/calculator/CMakeLists.txt | 11 + plasmoids/calculator/Messages.sh | 2 + plasmoids/calculator/kalgebraplasma.cpp | 159 ++++ plasmoids/calculator/kalgebraplasma.h | 61 ++ plasmoids/calculator/kalgebraplasmoid.desktop | 126 +++ .../graphsplasmoid/contents/ui/config.ui | 28 + plasmoids/graphsplasmoid/contents/ui/main.qml | 68 ++ plasmoids/graphsplasmoid/metadata.desktop | 90 +++ src/CMakeLists.txt | 29 + src/Messages.sh | 2 + src/askname.h | 53 ++ src/consolehtml.cpp | 307 +++++++ src/consolehtml.h | 126 +++ src/dictionary.cpp | 124 +++ src/dictionary.h | 65 ++ src/functionedit.cpp | 321 ++++++++ src/functionedit.h | 129 +++ src/kalgebra.cpp | 749 ++++++++++++++++++ src/kalgebra.h | 131 +++ src/kalgebra.xml | 174 ++++ src/main.cpp | 44 + src/org.kde.kalgebra.desktop | 176 ++++ src/varedit.cpp | 132 +++ src/varedit.h | 73 ++ src/variablesdelegate.cpp | 41 + src/variablesdelegate.h | 32 + src/viewportwidget.cpp | 76 ++ src/viewportwidget.h | 49 ++ utils/CMakeLists.txt | 2 + utils/main.cpp | 59 ++ 124 files changed, 8549 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 calgebra/CMakeLists.txt create mode 100644 calgebra/main.cpp create mode 100644 calgebra/test_calgebra.py create mode 100644 cmake/COPYING-CMAKE-SCRIPTS create mode 100644 cmake/FindReadline.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/64-apps-kalgebra.png create mode 100644 icons/CMakeLists.txt create mode 100644 icons/sc-apps-kalgebra.svgz create mode 100644 kalgebra.kdev4 create mode 100644 mobile/CMakeLists.txt 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/Dictionary.qml create mode 100644 mobile/plugins/Plot2D.qml create mode 100644 mobile/plugins/Plot3D.qml create mode 100644 mobile/plugins/Tables.qml create mode 100644 mobile/plugins/VariablesView.qml create mode 100644 mobile/plugins/kalgebraabout.json create mode 100644 mobile/plugins/kalgebraconsole.json create mode 100644 mobile/plugins/kalgebradictionary.json create mode 100644 mobile/plugins/kalgebraplot2d.json create mode 100644 mobile/plugins/kalgebraplot3d.json create mode 100644 mobile/plugins/kalgebratables.json create mode 100644 mobile/plugins/kalgebravariables.json create mode 100644 mobile/plugins/resources/kde-edu-logo.png create mode 100644 mobile/plugins/widgets/CMakeLists.txt create mode 100644 mobile/plugins/widgets/kde/CMakeLists.txt create mode 100644 mobile/plugins/widgets/kde/ConsoleDelegate.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/SimpleListView.qml create mode 100644 mobile/plugins/widgets/material/AddButton.qml create mode 100644 mobile/plugins/widgets/material/Button.qml create mode 100644 mobile/plugins/widgets/material/CMakeLists.txt create mode 100644 mobile/plugins/widgets/material/CalcButton.qml create mode 100644 mobile/plugins/widgets/material/ComboBox.qml create mode 100644 mobile/plugins/widgets/material/Dialog.qml create mode 100644 mobile/plugins/widgets/material/ExpressionInput.qml create mode 100644 mobile/plugins/widgets/material/KAlgebraMobile.qml create mode 100644 mobile/plugins/widgets/material/KAlgebraPage.qml create mode 100644 mobile/plugins/widgets/material/Label.qml create mode 100644 mobile/plugins/widgets/material/RealInput.qml create mode 100644 mobile/plugins/widgets/material/SimpleListView.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/qmldir create mode 100644 mobile/plugins/widgets/qtcontrols/AddButton.qml create mode 100644 mobile/plugins/widgets/qtcontrols/Button.qml create mode 100644 mobile/plugins/widgets/qtcontrols/CMakeLists.txt create mode 100644 mobile/plugins/widgets/qtcontrols/CalcButton.qml create mode 100644 mobile/plugins/widgets/qtcontrols/ComboBox.qml create mode 100644 mobile/plugins/widgets/qtcontrols/Dialog.qml create mode 100644 mobile/plugins/widgets/qtcontrols/ExpressionInput.qml create mode 100644 mobile/plugins/widgets/qtcontrols/KAlgebraMobile.qml create mode 100644 mobile/plugins/widgets/qtcontrols/KAlgebraPage.qml create mode 100644 mobile/plugins/widgets/qtcontrols/Label.qml create mode 100644 mobile/plugins/widgets/qtcontrols/RealInput.qml create mode 100644 mobile/plugins/widgets/qtcontrols/SimpleListView.qml create mode 100644 mobile/pluginsmodel.cpp create mode 100644 mobile/pluginsmodel.h create mode 100644 mobile/resources.qrc create mode 100644 org.kde.kalgebra.appdata.xml 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 100644 src/kalgebra.h create mode 100644 src/kalgebra.xml create mode 100644 src/main.cpp create mode 100755 src/org.kde.kalgebra.desktop 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..e212d3a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,75 @@ +project(kalgebra) +cmake_minimum_required(VERSION 2.8.11) + +find_package(ECM 1.7.0 REQUIRED NO_MODULE) +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${ECM_MODULE_PATH}) + +find_package(Qt5 5.2 REQUIRED NO_MODULE COMPONENTS Qml Quick Xml Svg OpenGL PrintSupport Test) +include(KDEInstallDirs) +include(KDECompilerSettings NO_POLICY_SCOPE) +include(KDECMakeSettings) +include(ECMInstallIcons) +include(FeatureSummary) +include(ECMAddAppIcon) + +find_package(Analitza5 REQUIRED) + +set(MOBILE_BACKEND "kde" CACHE STRING "Backend to install, currently. Check /mobile/plugins/widgets/*") + +include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR}) + +find_package(OpenGL) +set(HAVE_OPENGL ${OPENGL_FOUND}) +set_package_properties(OpenGL PROPERTIES TYPE OPTIONAL + PURPOSE "Support for 3D graphs in KAlgebra" + URL "http://opengl.org") + +set(CURSES_NEED_NCURSES TRUE) +find_package(Curses) +find_package(Readline) + +set_package_properties(Readline PROPERTIES TYPE OPTIONAL + PURPOSE "Allows KAlgebra to provide a console interface." + URL "http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html") +set_package_properties(Curses PROPERTIES TYPE OPTIONAL + PURPOSE "Allows KAlgebra to provide a console interface." + URL "http://www.gnu.org/software/ncurses/") + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config-kalgebra.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/src/config-kalgebra.h) +add_definitions (-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS) +add_definitions(-DQT_NO_URL_CAST_FROM_STRING) + +if(${MOBILE_BACKEND} STREQUAL "kde") + find_package(KF5I18n ${KF5_VERSION} REQUIRED) + find_package(KF5ConfigWidgets ${KF5_VERSION} REQUIRED) + find_package(KF5WidgetsAddons ${KF5_VERSION} REQUIRED) + find_package(KF5KIO REQUIRED) + find_package(Qt5WebKitWidgets REQUIRED) + find_package(KF5DocTools) + + add_subdirectory(src) + add_subdirectory(plasmoids) +endif() + +add_subdirectory(icons) +add_subdirectory(mobile) + +if(READLINE_FOUND AND CURSES_FOUND) + add_subdirectory(calgebra) +endif() + +if(KF5DocTools_FOUND) + add_subdirectory(utils) + + 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" + ) + + add_subdirectory(doc) +endif() +install(FILES org.kde.kalgebra.appdata.xml DESTINATION ${KDE_INSTALL_DATAROOTDIR}/appdata/) + +feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) 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/calgebra/CMakeLists.txt b/calgebra/CMakeLists.txt new file mode 100644 index 0000000..29bb7f8 --- /dev/null +++ b/calgebra/CMakeLists.txt @@ -0,0 +1,19 @@ +include(CheckFunctionExists) +include(CMakePushCheckState) + +include_directories(${READLINE_INCLUDE_DIR} ${CURSES_INCLUDE_DIR}) + +# check if we have recent version of Readline +cmake_push_check_state(RESET) +set(CMAKE_REQUIRED_LIBRARIES ${READLINE_LIBRARY} ${CURSES_LIBRARIES}) +check_function_exists(free_history_entry HAVE_FREE_HISTORY_ENTRY) +cmake_pop_check_state() +if(HAVE_FREE_HISTORY_ENTRY) + add_definitions(-DHAVE_FREE_HISTORY_ENTRY) +endif() + +add_executable(calgebra main.cpp) +target_link_libraries(calgebra Qt5::Core ${READLINE_LIBRARY} KF5::Analitza) + +install(TARGETS calgebra ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) + diff --git a/calgebra/main.cpp b/calgebra/main.cpp new file mode 100644 index 0000000..3c5a4c9 --- /dev/null +++ b/calgebra/main.cpp @@ -0,0 +1,158 @@ +/************************************************************************************* + * 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 +#include +#include + +using namespace std; + +using Analitza::Expression; + +Analitza::Analyzer a; + +enum CalcType { Evaluate, Calculate }; + +static const char* prompt=">>> "; +static const char* insidePrompt="... "; + +struct Config { + CalcType calcType; + bool showElapsedType; +}; +static Config configuration; + +void calculate(const Expression& e, CalcType t) +{ + Expression ans; + a.setExpression(e); + if(e.isCorrect()) { + QTime time; + if(configuration.showElapsedType) time.start(); + + if(t==Calculate) + ans=a.calculate(); + else + ans=a.evaluate(); + + if(configuration.showElapsedType) qDebug() << "Ellapsed time: " << time.elapsed(); + } + + if(a.isCorrect()) { + qDebug() << qPrintable(ans.toString()); + a.insertVariable(QStringLiteral("ans"), ans); + } else { + QStringList errors = a.errors(); + qDebug() << "Error:"; + foreach(const QString &err, errors) + qDebug() << " -" << qPrintable(err); + } +} + +int main(int argc, char *argv[]) +{ + configuration.calcType=Evaluate; + configuration.showElapsedType=false; + bool hasImports = false; + + for(int i=1; ilength; i++) { + HIST_ENTRY *he = remove_history(i); +#ifdef HAVE_FREE_HISTORY_ENTRY + free_history_entry(he); +#else + free((void*)he->line); + free(he); +#endif + } + qDebug("\nExit."); + return 0; +} diff --git a/calgebra/test_calgebra.py b/calgebra/test_calgebra.py new file mode 100644 index 0000000..1506785 --- /dev/null +++ b/calgebra/test_calgebra.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +import subprocess + +input="fib:=n->piecewise { eq(n,0)?0, eq(n,1)?1, ?fib(n-1)+fib(n-2) }\n" + +i=15 +for a in range(i,29): + input += "fib(%d)\n" % (a) +p = subprocess.Popen(["calgebra", "--calculate", "--print-time"], shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + +output=p.communicate(input) +for line in output[1].split('\n'): + theLine = line.split('time:') + if len(theLine)>1: + #print str(i)+", "+theLine[1] + print theLine[1] + i+=1 + 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/FindReadline.cmake b/cmake/FindReadline.cmake new file mode 100644 index 0000000..844f0a1 --- /dev/null +++ b/cmake/FindReadline.cmake @@ -0,0 +1,12 @@ +# GNU Readline library finder +if(READLINE_INCLUDE_DIR AND READLINE_LIBRARY) + set(READLINE_FOUND TRUE) +else(READLINE_INCLUDE_DIR AND READLINE_LIBRARY) + FIND_PATH(READLINE_INCLUDE_DIR readline/readline.h) + + FIND_LIBRARY(READLINE_LIBRARY NAMES readline) + include(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(Readline DEFAULT_MSG READLINE_INCLUDE_DIR READLINE_LIBRARY ) + + MARK_AS_ADVANCED(READLINE_INCLUDE_DIR READLINE_LIBRARY) +endif(READLINE_INCLUDE_DIR AND READLINE_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..67e1bd7 --- /dev/null +++ b/doc/CMakeLists.txt @@ -0,0 +1,4 @@ +########### install files ############### +# + +kdoctools_create_handbook(index.docbook INSTALL_DESTINATION ${KDE_INSTALL_DOCBUNDLEDIR}/en SUBDIR kalgebra) diff --git a/doc/commands.docbook b/doc/commands.docbook new file mode 100644 index 0000000..4e05137 --- /dev/null +++ b/doc/commands.docbook @@ -0,0 +1,429 @@ + +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) + + conjugate + Name: conjugate + Description: Conjugate + Parameters: conjugate(par1) + Example: x->conjugate(x*i) + + arg + Name: arg + Description: Arg + Parameters: arg(par1) + Example: x->arg(x*i) + + real + Name: real + Description: Real + Parameters: real(par1) + Example: x->real(x*i) + + imaginary + Name: imaginary + Description: Imaginary + Parameters: imaginary(par1) + Example: x->imaginary(x*i) + + 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..daa8418 --- /dev/null +++ b/doc/index.docbook @@ -0,0 +1,508 @@ + + + + + + +]> + + + + +The &kalgebra; Handbook + + + +Aleix +Pol + +
&Aleix.Pol.mail;
+
+
+ +
+ + +2007 +&Aleix.Pol; + + +&FDLNotice; + + +2016-04-19 +0.10 (Applications 16.04) + + + +&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 calculator 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 calculator 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 Calculator 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 Calculator +&kalgebra;'s calculator is useful as a calculator on steroids. The +user may enter expressions for evaluation in Calculate +or Evaluate mode, depending on the Calculator +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 +Calculator 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 calculator window: + +sin(pi) +k:=33 +sum(k*x : x=0..10) +f:=p->p*k +f(pi) + + + +The following shows a screenshot of the calculator window after entering +the above example expressions: + + +Screenshot of &kalgebra; calculator window with example expressions + + + + + + &kalgebra; calculator window + + + + + +A user can control the execution of a series of calculations +using the Calculator menu options: + + + + + +&Ctrl; +L +CalculatorLoad Script + +Executes the instructions in a file sequentially. +Useful if you want to define some libraries or resume some previous work. + + + + +&Ctrl; +G +CalculatorSave 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 +CalculatorExport 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; + + + +&documentation.index; +
+ + diff --git a/doc/kalgebra-2dgraph-window.png b/doc/kalgebra-2dgraph-window.png new file mode 100644 index 0000000000000000000000000000000000000000..2e49ea162e3e447890dc83019f2122c15351fdc6 GIT binary patch literal 41762 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 z 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

DNh|@Lv%cbwn(&INWuq`LjyyW* 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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..3da827731db9d2b3afc8a592eeb4d9bed36f9b87 GIT binary patch literal 48997 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 literal 0 HcmV?d00001 diff --git a/doc/kalgebra-dictionary-window.png b/doc/kalgebra-dictionary-window.png new file mode 100644 index 0000000000000000000000000000000000000000..eebbb0825cfe8c400b23e79d24b4ccea1272f047 GIT binary patch literal 60041 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%0A4p;Hz$%*AKN|j;L##UhD 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∓M~eT^r&vsVNO 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 Ly;6GVdh~w*+&Ac| literal 0 HcmV?d00001 diff --git a/doc/view-fullscreen.png b/doc/view-fullscreen.png new file mode 100644 index 0000000000000000000000000000000000000000..f004b1d1ebe83b690fcf7430d69929b3e44f0be1 GIT binary patch literal 514 zcmV+d0{#7oP) zM6G~#0G@)xJ~u7A7%d6sc>NB5fE#cqjapS|)k{*5_ENi+@Xx`q03}Y=Lh@!LAM73P z%Fz=n`ZM-Zs6o}%xq)Gz8~NR<>UV%*RBaxW zr_Wz_`sDG3oCi#{q45LBW<+2THh|+gOr}#>UOoQ>)0-Py*Tu4|ybWiwpPZdv5XW&X z1{$tQr_-jUO`O_!)M*pjGxxB#Gvh~`%(XpsEaAU2 zvVAji=G=SF|GZ`bV~jDz82@9axDy_K_W9FcC^9HK{qD)*%l@8@6ClE;#`uUa$!RqN zD6P>t6?uHTUl_riz5rHNNrnQ5 z6?Ew5dGcE=8a5S;S1OQc8XFZH`guF~M0^0&3i4EWbf@7}{gR<}RAKT?yr&&D_NiLm z<#4XE6P!?W?#?zC<5z`hwnlDt^xVjVsyjPDCkj|TnHGVOZy3QSAYzC@K@8%ZU=kW# z5fY?8m9vKdm6({M>|d`N7QRoSA8$V+>OPquZaRcl2M==GVJee za#$`ppMM!X_~?@!u9D=UK$Hicb1I$227sRAyX)rU1EReD{4F}JaweOLzE95-m|wgV zt4K47yPLc{IgakrH3IWbrWoo$iKUghl=pY=yc#E!BW|zXCwpzu`TAP5N;Z3~%e%J1 zRc|*6NDx~)RD+$&ER{;JytcvCi@y*t>}>wa`n~s@m0w(51J)Y%=@M2~w`-k>Awe+G zYWAV%_ObA|v9LleKMlaqVUgFz2N#~3^kH>%qkvN$8wra1LHwbB)!X+X8QYuxAja=X zM$bpH&iyVxqpFgwcOpMM%WUB$0B5IfD7|_)6blGAn~Vj7SzxcxZe{J=s5!Z}{T$D$ z_a>+dG>jo33UrVhSw);VW-?h87Og|`ygJ357ek?dE1aDmB5h_C{N3TWxpIe0CJR7m ze}~i4lfhCT&^a**gp=~1~lLs~qdMMyLXgn2;AfwNi86&A_mX8?G8 zd_d)>G(Z}(_AV}ib4Tbh(|21$gE4;eTj_LPR(0vUaCd@EPlj5gM!%b!paaVL+nk-g z0bs7MNPcRjYlr2GF2p)J!G3i0y*kC0oA!n}#p3FE@4_5lEjFoQC~|_PXA11?yukPE zv&Dtw+e~D#12ccCn{jr6?i7GF3UHnl9dLGf!a;c#fJ`RK{KD$sOuq*>QNV4-8xO5CC{6ndZX$+*QW4*)1sm@cxt!k*kalx#E{28x z0kqO6Z71Kn`(g|ST%UKpAO@4U>0n~v7pDV-)?ZrOPST47DVtx$7LggWK{T~vd8K?J4SIByK)(r#ntvGcdP z?+2>I>*n-+!02S|7Uw3f6iNr53KR;1TNlfX0>%UlA!!;8yTyZF9--m$!^wN~S~O-^ zVa;BNwnk~(tkb*Pmw@d`G!iX>ASe)nawv)%DR8yB|K{Y#Y3FU4U^yTdTNK5> ztsIuCjRo1v1R}!OX*G88HXvH3?V__|ISjOQSQ`1ka26(;nE-@Z)gv^1p<(t-aRLme zu!f02?7z%Bc=$-XdJW_Iai%TGI4l(# z{eTgH)*6jQ!jKnH)Gmp&TIKZIE1m+rzulL%1AuP~Mroyjkk_bugM=kq7;khoZHzI- c7-J;yA25tVlylgUTmS$707*qoM6N<$f + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + 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..3629682 --- /dev/null +++ b/mobile/CMakeLists.txt @@ -0,0 +1,32 @@ +add_subdirectory(plugins) + +if(KF5I18n_FOUND) + add_definitions(-DKDECOMPONENTS) +endif() + +qt5_add_resources(KALGEBRAMOBILE_SRCS resources.qrc) +add_executable(kalgebramobile pluginsmodel.cpp + kalgebramobile.cpp main.cpp ${KALGEBRAMOBILE_SRCS}) + +target_link_libraries(kalgebramobile Qt5::Qml Qt5::Quick Qt5::Gui + KF5::Analitza KF5::AnalitzaGui KF5::AnalitzaPlot) + +set(DESKTOPFILE_INSTALL ${KDE_INSTALL_APPDIR}) +if(${MOBILE_BACKEND} STREQUAL "harmattan") + set(DESKTOPFILE_INSTALL ${KDE_INSTALL_APPDIR}/..) +elseif(${MOBILE_BACKEND} STREQUAL "material") +# Material requires QtSvg for icons +# if we don't link it here explicitly, androiddeployqt doesn't bring it + find_package(Qt5Svg REQUIRED) + target_link_libraries(kalgebramobile Qt5::Svg) +elseif(KF5I18n_FOUND) + target_link_libraries(kalgebramobile KF5::I18n) +endif() + +set(DESKTOPFILE kalgebramobile.desktop) +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/kalgebramobile${MOBILE_BACKEND}.desktop) + set(DESKTOPFILE kalgebramobile${MOBILE_BACKEND}.desktop) +endif() + +install(TARGETS kalgebramobile ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) +install(PROGRAMS ${DESKTOPFILE} DESTINATION ${DESKTOPFILE_INSTALL} ) diff --git a/mobile/kalgebramobile.cpp b/mobile/kalgebramobile.cpp new file mode 100644 index 0000000..5522d47 --- /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, &QAbstractItemModel::rowsRemoved, this, &KAlgebraMobile::functionRemoved); + connect(m_functionsModel, &QAbstractItemModel::rowsInserted, this, &KAlgebraMobile::functionInserted); + connect(m_functionsModel, &QAbstractItemModel::dataChanged, this, &KAlgebraMobile::functionModified); + } + + 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..ce5cde2 --- /dev/null +++ b/mobile/kalgebramobile.desktop @@ -0,0 +1,138 @@ +[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[lt]=KAlgebra Mobile +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 bolsín +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[ast]=Iguador y trazador de bolsín d'espresiones matemátiques +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 %u +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..d3cc7dd --- /dev/null +++ b/mobile/kalgebramobile.h @@ -0,0 +1,59 @@ +/************************************************************************************* + * 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 + +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 Q_SLOTS: + Analitza::PlotsModel* functionsModel(); + Analitza::Variables* variables() const; + + private Q_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); + + Q_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..df29dbc --- /dev/null +++ b/mobile/kalgebramobileharmattan.desktop @@ -0,0 +1,151 @@ +[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 bolsín +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[ast]=Iguador y trazador de bolsín d'espresiones matemátiques +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..536eb67 --- /dev/null +++ b/mobile/main.cpp @@ -0,0 +1,65 @@ +/************************************************************************************* + * 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 + +#ifdef KDECOMPONENTS +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kalgebramobile.h" +#include "pluginsmodel.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); + QGuiApplication app(argc, argv); + app.setApplicationName(QStringLiteral("kalgebramobile")); +// app.setWindowIcon(QIcon::fromTheme("kalgebra")); + + KAlgebraMobile widget; + + QString main = PluginsModel::pluginsDirectoryPath()+"/widgets/KAlgebraMobile.qml"; + + QDir dir = QFileInfo(main).dir(); + dir.cdUp(); + + QQmlApplicationEngine engine; + engine.rootContext()->setContextProperty(QStringLiteral("app"), &widget); + engine.addImportPath(dir.path()); + +#ifdef KDECOMPONENTS + engine.rootContext()->setContextObject(new KLocalizedContext(&engine)); +#endif + + engine.load(QUrl::fromLocalFile(main)); + return app.exec(); +} diff --git a/mobile/plugins/About.qml b/mobile/plugins/About.qml new file mode 100644 index 0000000..840cedf --- /dev/null +++ b/mobile/plugins/About.qml @@ -0,0 +1,72 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.0 +import org.kde.analitza 1.0 +import widgets 1.0 + +KAlgebraPage +{ + id: page + ColumnLayout { + anchors.margins: 20*page.dp + anchors.fill: parent + spacing: 20*page.dp + + Image { + id: icon + source: "qrc:/kalgebra.svgz" + Layout.fillWidth: true + fillMode: Image.PreserveAspectFit + + MouseArea { + anchors.fill: parent + onClicked: Qt.openUrlExternally("http://edu.kde.org/applications/mathematics/kalgebra") + } + } + + Label { + Layout.fillWidth: true + + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignJustify + text: ("KAlgebra is brought to you by the lovely community of KDE "+ + "and KDE Edu from a Free Software envionment.") + onLinkActivated: Qt.openUrlExternally(link) + } + + Label { + Layout.fillWidth: true + + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignJustify + 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.") + onLinkActivated: Qt.openUrlExternally(link) + } + + Label { + Layout.fillWidth: true + + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignJustify + text: "Aleix Pol Gonzalez <aleixpol@kde.org>" + onLinkActivated: Qt.openUrlExternally(link) + } + + Image { + source: "qrc:/kde-edu-logo.png" + Layout.fillWidth: true + fillMode: Image.PreserveAspectFit + Layout.maximumHeight: icon.height + + MouseArea { + anchors.fill: parent + onClicked: Qt.openUrlExternally("http://edu.kde.org") + } + } + Item { + Layout.fillHeight: true + } + } +} diff --git a/mobile/plugins/CMakeLists.txt b/mobile/plugins/CMakeLists.txt new file mode 100644 index 0000000..6b17ce8 --- /dev/null +++ b/mobile/plugins/CMakeLists.txt @@ -0,0 +1,9 @@ +add_subdirectory(widgets) + +install( FILES + Console.qml Plot2D.qml Plot3D.qml Tables.qml Dictionary.qml + About.qml VariablesView.qml + kalgebraabout.json + kalgebraconsole.json kalgebraplot2d.json kalgebraplot3d.json kalgebratables.json kalgebravariables.json kalgebradictionary.json + DESTINATION ${KDE_INSTALL_DATADIR}/kalgebramobile/plugins/ +) diff --git a/mobile/plugins/Console.qml b/mobile/plugins/Console.qml new file mode 100644 index 0000000..4e8e43b --- /dev/null +++ b/mobile/plugins/Console.qml @@ -0,0 +1,54 @@ +import QtQuick 2.0 +import org.kde.analitza 1.0 +import widgets 1.0 + +KAlgebraPage +{ + id: page + 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 + } + + anchors { + top: parent.top + left: parent.left + right: parent.right + margins: page.dp*6 + } + } + + SimpleListView { + id: view + model: itemModel + role: "result" + title: "Results" + + anchors { + top: input.bottom + bottom: parent.bottom + left: parent.left + right: parent.right + } + } +} diff --git a/mobile/plugins/Dictionary.qml b/mobile/plugins/Dictionary.qml new file mode 100644 index 0000000..28763d7 --- /dev/null +++ b/mobile/plugins/Dictionary.qml @@ -0,0 +1,71 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.0 +import org.kde.analitza 1.0 +import widgets 1.0 + +KAlgebraPage +{ + id: page + anchors.margins: 0 + + function updateGraph() { + view.model.clear(); + view.resetViewport(); + view.addFunction(operators.data(operators.index(chosebox.currentIndex,3)), app.variables); + } + + ColumnLayout { + id: descriptioncol + + anchors.fill: parent + spacing: 10 + + ComboBox { + id: chosebox + Layout.fillWidth: true + textRole: "display" + + model: OperatorsModel { + id: operators + } + + onCurrentIndexChanged: { + page.updateGraph(); + } + } + + GridLayout { + id: descgrid + columns: 2 + Layout.fillWidth: true + + Label { text: operators.headerData(0,Qt.Horizontal) } + Label { text: operators.data(operators.index(chosebox.currentIndex,0)) } + Label { text: operators.headerData(1,Qt.Horizontal) } + Label { text: operators.data(operators.index(chosebox.currentIndex,1)) } + Label { text: operators.headerData(2,Qt.Horizontal) } + Label { text: operators.data(operators.index(chosebox.currentIndex,2)) } + Label { text: operators.headerData(3,Qt.Horizontal) } + Label { text: operators.data(operators.index(chosebox.currentIndex,3)) } + } + + Rectangle { + color: 'white' + Layout.fillWidth: true + Layout.fillHeight: true + + Graph2D { + id: view + anchors { + fill: parent + } + model: PlotsModel { + id: plotsModel + } + Component.onCompleted: { + page.updateGraph(); + } + } + } + } +} diff --git a/mobile/plugins/Plot2D.qml b/mobile/plugins/Plot2D.qml new file mode 100644 index 0000000..30ddd53 --- /dev/null +++ b/mobile/plugins/Plot2D.qml @@ -0,0 +1,74 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.0 as Controls +import org.kde.analitza 1.0 +import widgets 1.0 + +KAlgebraPage +{ + id: page + anchors.margins: 0 + + Rectangle { + anchors.fill: parent + height: 200 + color: 'white' + + Graph2D { + id: view + anchors.fill: parent + model: app.functionsModel() + + Dialog { + id: dialog + height: Math.min((4*view.height)/5, list.contentHeight)+page.dp*10 + + SimpleListView { + id: list + anchors { + fill: parent + margins: page.dp*4 + } + role: "description" + model: app.functionsModel() + + header: RowLayout { + width: parent.width + ExpressionInput { + id: input + Layout.fillWidth: true + text: "sin x" + focus: true + Component.onCompleted: selectAll() + onAccepted: { + input.selectAll() + view.addFunction(input.text, app.variables) + } + } + Button { + iconName: "list-add" + onClicked: { + input.selectAll() + view.addFunction(input.text, app.variables) + } + } + } + + footer: Button { + text: "Clear All" + onClicked: { + app.functionsModel().clear(); + view.resetViewport(); + } + } + } + } + + AddButton { + onClicked: { + dialog.open(); + } + } + } + } +} diff --git a/mobile/plugins/Plot3D.qml b/mobile/plugins/Plot3D.qml new file mode 100644 index 0000000..5aa07a5 --- /dev/null +++ b/mobile/plugins/Plot3D.qml @@ -0,0 +1,87 @@ +/************************************************************************************* + * Copyright (C) 2015 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 * + *************************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Layouts 1.1 +import org.kde.analitza 1.1 +import widgets 1.0 + +KAlgebraPage +{ + id: page + Graph3D + { + id: view + anchors.fill: parent + + Dialog { + id: dialog + height: Math.min((4*view.height)/5, list.contentHeight)+page.dp*10 + + SimpleListView { + id: list + anchors { + fill: parent + margins: page.dp*4 + } + role: "description" + model: view.model + + header: RowLayout { + width: parent.width + ExpressionInput { + id: input + Layout.fillWidth: true + text: "sin x*sin y" + focus: true + Component.onCompleted: selectAll() + onAccepted: { + input.selectAll() + var err = view.addFunction(input.text, app.variables) + if (err.length>0) + console.warn("errors:", err) + } + } + Button { + iconName: "list-add" + onClicked: { + input.selectAll() + var err = view.addFunction(input.text, app.variables) + if (err.length>0) + console.warn("errors:", err) + } + } + } + + footer: Button { + text: "Clear All" + onClicked: { + view.model.clear() + view.resetView() + } + } + } + } + + AddButton { + onClicked: { + dialog.open(); + } + } + } +} diff --git a/mobile/plugins/Tables.qml b/mobile/plugins/Tables.qml new file mode 100644 index 0000000..0138807 --- /dev/null +++ b/mobile/plugins/Tables.qml @@ -0,0 +1,92 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.1 +import org.kde.analitza 1.0 +import widgets 1.0 + +KAlgebraPage +{ + 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.value = 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) { + resultsModel.append( { element: "Errors: "+ (ret ? ret : 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); + } + + ColumnLayout { + id: inputcol + + anchors { + top: parent.top + left: parent.left + right: parent.right + } + spacing: 10 + + GridLayout { + id: ins + columns: 2 + Layout.fillWidth: true + + Label { text: "Input:" } + ExpressionInput { + id: input + text: "sin x"; + Layout.fillWidth: true + onAccepted: calculateTable(); + } + Label { text: "From:" } RealInput { id: from; text: "0"; Layout.fillWidth: true; onAccepted: calculateTable() } + Label { text: "To:" } RealInput { id: to; text: "10"; Layout.fillWidth: true; onAccepted: calculateTable() } + Label { text: "Step:" } RealInput { id: step; text: "1"; Layout.fillWidth: true; onAccepted: calculateTable() } + } + + Button { + anchors.right: parent.right + text: "Go!" + + onClicked: calculateTable() + } + } + + SimpleListView { + width: parent.width + anchors { + top: inputcol.bottom + bottom: parent.bottom + topMargin: 5 + } + currentIndex: -1 + clip: true + + model: ListModel { id: resultsModel } + role: "element" + title: "Results:" + } +} diff --git a/mobile/plugins/VariablesView.qml b/mobile/plugins/VariablesView.qml new file mode 100644 index 0000000..573b2d4 --- /dev/null +++ b/mobile/plugins/VariablesView.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 +import org.kde.analitza 1.0 +import widgets 1.0 + +KAlgebraPage +{ + SimpleListView { + anchors.fill: parent + model: VariablesModel { variables: app.variables } + currentIndex: -1 + role: "whatsThis" + title: "Variables" + } +} diff --git a/mobile/plugins/kalgebraabout.json b/mobile/plugins/kalgebraabout.json new file mode 100644 index 0000000..a245f61 --- /dev/null +++ b/mobile/plugins/kalgebraabout.json @@ -0,0 +1,12 @@ +{ + "Icon": "help-about", + "Name": "About KAlgebra", + "ServiceTypes": "KAlgebra/Script", + "Type": "Service", + "X-KAlgebra-Priority": "-10", + "X-KDE-PluginInfo-Author": "Aleix Pol Gonzalez", + "X-KDE-PluginInfo-Email": "aleixpol@kde.org", + "X-KDE-PluginInfo-License": "GPL", + "X-KDE-PluginInfo-Name": "About.qml", + "X-KDE-PluginInfo-Version": "1.0" +} diff --git a/mobile/plugins/kalgebraconsole.json b/mobile/plugins/kalgebraconsole.json new file mode 100644 index 0000000..2386f53 --- /dev/null +++ b/mobile/plugins/kalgebraconsole.json @@ -0,0 +1,13 @@ +{ + "Comment": "Scientific calculator", + "Icon": "utilities-terminal", + "Name": "Calculator", + "ServiceTypes": "KAlgebra/Script", + "Type": "Service", + "X-KAlgebra-Priority": "1000", + "X-KDE-PluginInfo-Author": "Aleix Pol Gonzalez", + "X-KDE-PluginInfo-Email": "aleixpol@kde.org", + "X-KDE-PluginInfo-License": "GPL", + "X-KDE-PluginInfo-Name": "Console.qml", + "X-KDE-PluginInfo-Version": "1.0" +} diff --git a/mobile/plugins/kalgebradictionary.json b/mobile/plugins/kalgebradictionary.json new file mode 100644 index 0000000..9145137 --- /dev/null +++ b/mobile/plugins/kalgebradictionary.json @@ -0,0 +1,13 @@ +{ + "Comment": "List of available functions", + "Icon": "documentation", + "Name": "Dictionary", + "ServiceTypes": "KAlgebra/Script", + "Type": "Service", + "X-KAlgebra-Priority": "100", + "X-KDE-PluginInfo-Author": "Artur Puzio", + "X-KDE-PluginInfo-Email": "cytadela8@op.pl", + "X-KDE-PluginInfo-License": "GPL", + "X-KDE-PluginInfo-Name": "Dictionary.qml", + "X-KDE-PluginInfo-Version": "1.0" +} diff --git a/mobile/plugins/kalgebraplot2d.json b/mobile/plugins/kalgebraplot2d.json new file mode 100644 index 0000000..d37b466 --- /dev/null +++ b/mobile/plugins/kalgebraplot2d.json @@ -0,0 +1,13 @@ +{ + "Comment": "Draws any 2D graph you want", + "Icon": "draw-bezier-curves", + "Name": "Graph 2D", + "ServiceTypes": "KAlgebra/Script", + "Type": "Service", + "X-KAlgebra-Priority": "100", + "X-KDE-PluginInfo-Author": "Aleix Pol Gonzalez", + "X-KDE-PluginInfo-Email": "aleixpol@kde.org", + "X-KDE-PluginInfo-License": "GPL", + "X-KDE-PluginInfo-Name": "Plot2D.qml", + "X-KDE-PluginInfo-Version": "1.0" +} diff --git a/mobile/plugins/kalgebraplot3d.json b/mobile/plugins/kalgebraplot3d.json new file mode 100644 index 0000000..437b4f2 --- /dev/null +++ b/mobile/plugins/kalgebraplot3d.json @@ -0,0 +1,13 @@ +{ + "Comment": "Draws any 3D graph you want", + "Icon": "adjustrgb", + "Name": "Graph 3D", + "ServiceTypes": "KAlgebra/Script", + "Type": "Service", + "X-KAlgebra-Priority": "100", + "X-KDE-PluginInfo-Author": "Aleix Pol Gonzalez", + "X-KDE-PluginInfo-Email": "aleixpol@kde.org", + "X-KDE-PluginInfo-License": "GPL", + "X-KDE-PluginInfo-Name": "Plot3D.qml", + "X-KDE-PluginInfo-Version": "1.0" +} diff --git a/mobile/plugins/kalgebratables.json b/mobile/plugins/kalgebratables.json new file mode 100644 index 0000000..c10a32f --- /dev/null +++ b/mobile/plugins/kalgebratables.json @@ -0,0 +1,13 @@ +{ + "Comment": "Easily create value tables", + "Icon": "kspread", + "Name": "Value Tables", + "ServiceTypes": "KAlgebra/Script", + "Type": "Service", + "X-KAlgebra-Priority": "10", + "X-KDE-PluginInfo-Author": "Aleix Pol Gonzalez", + "X-KDE-PluginInfo-Email": "aleixpol@kde.org", + "X-KDE-PluginInfo-License": "GPL", + "X-KDE-PluginInfo-Name": "Tables.qml", + "X-KDE-PluginInfo-Version": "1.0" +} diff --git a/mobile/plugins/kalgebravariables.json b/mobile/plugins/kalgebravariables.json new file mode 100644 index 0000000..8ff056c --- /dev/null +++ b/mobile/plugins/kalgebravariables.json @@ -0,0 +1,13 @@ +{ + "Comment": "Displays the stored values", + "Icon": "document-properties", + "Name": "Variables", + "ServiceTypes": "KAlgebra/Script", + "Type": "Service", + "X-KAlgebra-Priority": "0", + "X-KDE-PluginInfo-Author": "Aleix Pol Gonzalez", + "X-KDE-PluginInfo-Email": "aleixpol@kde.org", + "X-KDE-PluginInfo-License": "GPL", + "X-KDE-PluginInfo-Name": "VariablesView.qml", + "X-KDE-PluginInfo-Version": "1.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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.bottom) { + input.text=(root.value-1) + } + } + } +} diff --git a/mobile/plugins/widgets/material/SimpleListView.qml b/mobile/plugins/widgets/material/SimpleListView.qml new file mode 100644 index 0000000..92035ce --- /dev/null +++ b/mobile/plugins/widgets/material/SimpleListView.qml @@ -0,0 +1,23 @@ +import QtQuick 2.0 +import Material 0.1 +import Material.ListItems 0.1 as ListItem + +ListView +{ + id: viewItem + property string role: "" + property string title + clip: true + + header: ListItem.Subheader { + text: ListView.view.title + } + delegate: ListItem.Standard { + text: model[role] + interactive: false + } + + Scrollbar { + flickableItem: viewItem + } +} diff --git a/mobile/plugins/widgets/neutral/Button.qml b/mobile/plugins/widgets/neutral/Button.qml new file mode 100644 index 0000000..1aafe2e --- /dev/null +++ b/mobile/plugins/widgets/neutral/Button.qml @@ -0,0 +1,31 @@ +import QtQuick 2.0 + +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..5c90774 --- /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 SimpleListView.qml ScrollDecorator.qml + + KAlgebraPage.qml KAlgebraMobile.qml + DESTINATION ${KDE_INSTALL_DATADIR}/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..60bd7e3 --- /dev/null +++ b/mobile/plugins/widgets/neutral/CalcButton.qml @@ -0,0 +1,6 @@ +import QtQuick 2.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..a7b8809 --- /dev/null +++ b/mobile/plugins/widgets/neutral/ExpressionInput.qml @@ -0,0 +1,16 @@ +import QtQuick 2.0 + +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..d96ccd1 --- /dev/null +++ b/mobile/plugins/widgets/neutral/KAlgebraMobile.qml @@ -0,0 +1,62 @@ +import org.kde.analitza 1.0 +import QtQuick 2.0 +import QtQuick.Window 2.1 +import org.kde.kalgebra.mobile 1.0 + +Window +{ + id: rootItem + SystemPalette { id: palette } + color: palette.window + height: 600 + width: 600 + visible: true + + 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 = pluginsView + } 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.png" + 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..de7d79e --- /dev/null +++ b/mobile/plugins/widgets/neutral/KAlgebraPage.qml @@ -0,0 +1,19 @@ +import QtQuick 2.0 + +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..cde67a8 --- /dev/null +++ b/mobile/plugins/widgets/neutral/Label.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 + +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..3160421 --- /dev/null +++ b/mobile/plugins/widgets/neutral/RealInput.qml @@ -0,0 +1,43 @@ +import QtQuick 2.0 + +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..a8a2906 --- /dev/null +++ b/mobile/plugins/widgets/neutral/ScrollDecorator.qml @@ -0,0 +1,17 @@ +import QtQuick 2.0 + +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..52e6425 --- /dev/null +++ b/mobile/plugins/widgets/neutral/SimpleListView.qml @@ -0,0 +1,23 @@ +import QtQuick 2.0 + +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/qmldir b/mobile/plugins/widgets/qmldir new file mode 100644 index 0000000..7b4c37d --- /dev/null +++ b/mobile/plugins/widgets/qmldir @@ -0,0 +1,12 @@ +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 +AddButton 1.0 AddButton.qml +Dialog 1.0 Dialog.qml +ComboBox 1.0 ComboBox.qml diff --git a/mobile/plugins/widgets/qtcontrols/AddButton.qml b/mobile/plugins/widgets/qtcontrols/AddButton.qml new file mode 100644 index 0000000..fe98048 --- /dev/null +++ b/mobile/plugins/widgets/qtcontrols/AddButton.qml @@ -0,0 +1,14 @@ +import QtQuick.Controls 1.1 + +Button +{ + id: root + + anchors { + right: parent.right + bottom: parent.bottom + margins: 20 + } + + iconName: "list-add" +} diff --git a/mobile/plugins/widgets/qtcontrols/Button.qml b/mobile/plugins/widgets/qtcontrols/Button.qml new file mode 100644 index 0000000..e39a24b --- /dev/null +++ b/mobile/plugins/widgets/qtcontrols/Button.qml @@ -0,0 +1,4 @@ +import QtQuick.Controls 1.0 + +Button { +} diff --git a/mobile/plugins/widgets/qtcontrols/CMakeLists.txt b/mobile/plugins/widgets/qtcontrols/CMakeLists.txt new file mode 100644 index 0000000..e77daae --- /dev/null +++ b/mobile/plugins/widgets/qtcontrols/CMakeLists.txt @@ -0,0 +1,7 @@ +install( FILES + Label.qml Button.qml CalcButton.qml ExpressionInput.qml + RealInput.qml SimpleListView.qml + + KAlgebraPage.qml KAlgebraMobile.qml AddButton.qml Dialog.qml ComboBox.qml + DESTINATION ${KDE_INSTALL_DATADIR}/kalgebramobile/plugins/widgets/ +) diff --git a/mobile/plugins/widgets/qtcontrols/CalcButton.qml b/mobile/plugins/widgets/qtcontrols/CalcButton.qml new file mode 100644 index 0000000..8b0571b --- /dev/null +++ b/mobile/plugins/widgets/qtcontrols/CalcButton.qml @@ -0,0 +1,4 @@ +Button +{ + onClicked: doOp(text) +} diff --git a/mobile/plugins/widgets/qtcontrols/ComboBox.qml b/mobile/plugins/widgets/qtcontrols/ComboBox.qml new file mode 100644 index 0000000..030ebfb --- /dev/null +++ b/mobile/plugins/widgets/qtcontrols/ComboBox.qml @@ -0,0 +1,4 @@ +import QtQuick.Controls 1.3 + +ComboBox +{} diff --git a/mobile/plugins/widgets/qtcontrols/Dialog.qml b/mobile/plugins/widgets/qtcontrols/Dialog.qml new file mode 100644 index 0000000..c981c80 --- /dev/null +++ b/mobile/plugins/widgets/qtcontrols/Dialog.qml @@ -0,0 +1,10 @@ +import QtQuick 2.1 +import QtQuick.Dialogs 1.2 + +Dialog { + width: 100 + height: 100 + + default property Item fu + contentItem: fu +} diff --git a/mobile/plugins/widgets/qtcontrols/ExpressionInput.qml b/mobile/plugins/widgets/qtcontrols/ExpressionInput.qml new file mode 100644 index 0000000..632115f --- /dev/null +++ b/mobile/plugins/widgets/qtcontrols/ExpressionInput.qml @@ -0,0 +1,7 @@ +import QtQuick.Controls 1.0 + +TextField +{ + placeholderText: "Expression to calculate..." + inputMethodHints: /*Qt.ImhPreferNumbers |*/ Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase +} diff --git a/mobile/plugins/widgets/qtcontrols/KAlgebraMobile.qml b/mobile/plugins/widgets/qtcontrols/KAlgebraMobile.qml new file mode 100644 index 0000000..db4b8c4 --- /dev/null +++ b/mobile/plugins/widgets/qtcontrols/KAlgebraMobile.qml @@ -0,0 +1,75 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.0 +import org.kde.analitza 1.0 +import org.kde.kalgebra.mobile 1.0 + +ApplicationWindow +{ + id: rootItem + height: 600 + width: 600 + visible: true + + function goToPage(path, deco) { + try { + var component = Qt.createComponent(path) + if (component.status == Component.Ready) + pageStack.push(component); + else + console.log("Error loading component:", component.errorString()); + } catch (e) { + console.log("error: "+e) + } + } + + Component { + id: pluginsView + ListView { + spacing: 10 + header: Image { + source: "qrc:/kalgebra.png" + 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 } + } + } + + Action { + id: backAction + text: "Back" + shortcut: "Back" + tooltip: "Go back" + onTriggered: { + if (pageStack.depth==1) + Qt.quit(); + else + pageStack.pop(); + } + } + + StackView { + id: pageStack + initialItem: pluginsView + anchors.fill: parent + } +} diff --git a/mobile/plugins/widgets/qtcontrols/KAlgebraPage.qml b/mobile/plugins/widgets/qtcontrols/KAlgebraPage.qml new file mode 100644 index 0000000..53fe127 --- /dev/null +++ b/mobile/plugins/widgets/qtcontrols/KAlgebraPage.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 + +Item +{ + property real dp: 1 +} diff --git a/mobile/plugins/widgets/qtcontrols/Label.qml b/mobile/plugins/widgets/qtcontrols/Label.qml new file mode 100644 index 0000000..f34d588 --- /dev/null +++ b/mobile/plugins/widgets/qtcontrols/Label.qml @@ -0,0 +1,4 @@ +import QtQuick.Controls 1.0 + +Label { +} diff --git a/mobile/plugins/widgets/qtcontrols/RealInput.qml b/mobile/plugins/widgets/qtcontrols/RealInput.qml new file mode 100644 index 0000000..c68de44 --- /dev/null +++ b/mobile/plugins/widgets/qtcontrols/RealInput.qml @@ -0,0 +1,46 @@ +import QtQuick.Controls 1.0 +import QtQuick 2.0 + +TextField +{ + id: input + property alias minimumValue: realvalidator.bottom + property alias maximumValue: realvalidator.top + + 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 + rightMargin: 2 + } + spacing: 2 + height: parent.height-4 + y:2 + Button { + text: "+" + height: parent.height + onClicked: { + if(input.value+1minimumValue) { + input.text=(input.value-1) + } + } + height: parent.height + } + } +} diff --git a/mobile/plugins/widgets/qtcontrols/SimpleListView.qml b/mobile/plugins/widgets/qtcontrols/SimpleListView.qml new file mode 100644 index 0000000..a5db36e --- /dev/null +++ b/mobile/plugins/widgets/qtcontrols/SimpleListView.qml @@ -0,0 +1,43 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.1 + +ColumnLayout +{ + id: viewItem + property string role: "" + property string title: "" + property alias currentIndex: table.currentRow + property alias model: table.model + property Component delegate + property Component header + property Component footer + + Loader { + Layout.fillWidth: true + sourceComponent: parent.header + } + + TableView + { + id: table + Layout.fillWidth: true + Layout.fillHeight: true + + TableViewColumn { + role: viewItem.role + title: viewItem.title + } + + itemDelegate: Item { + Label { + anchors.verticalCenter: parent.verticalCenter + text: styleData.value + } + } + } + Loader { + Layout.fillWidth: true + sourceComponent: parent.footer + } +} diff --git a/mobile/pluginsmodel.cpp b/mobile/pluginsmodel.cpp new file mode 100644 index 0000000..0776561 --- /dev/null +++ b/mobile/pluginsmodel.cpp @@ -0,0 +1,105 @@ +/************************************************************************************* + * 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 + +QString PluginsModel::pluginsDirectoryPath() +{ +#ifdef __ANDROID__ + return "/data/data/org.kde.kalgebramobile/qt-reserved-files/share/kalgebramobile/plugins"; +#else + return QStandardPaths::locate(QStandardPaths::DataLocation, QStringLiteral("plugins"), QStandardPaths::LocateDirectory); +#endif +} + +PluginsModel::PluginsModel(QObject* parent) :QStandardItemModel(parent) +{ + QStringList foundPlugins; + QDir dir(pluginsDirectoryPath()); + foreach(const QString& file, dir.entryList(QStringList("*.json"))) { + foundPlugins += dir.absoluteFilePath(file); + } + + qDebug() << "Plugins found:" << foundPlugins; + + QList items; + Q_FOREACH(const QString& file, foundPlugins) { + QFile f(file); + bool ret = f.open(QIODevice::ReadOnly); + if(!ret) { + qWarning() << "error opening " << file; + continue; + } +// qDebug() << "laaaaa" << f.readAll() << file; + + QByteArray data = f.readAll(); + QJsonDocument doc = QJsonDocument::fromJson(data); + + QVariantMap cg = doc.toVariant().toMap(); + QStandardItem* item = new QStandardItem; + + QString scriptPath = dir.absoluteFilePath(cg.value(QStringLiteral("X-KDE-PluginInfo-Name"), QString()).toString()); + + Q_ASSERT(!scriptPath.isEmpty()); + + QVariant priority = cg.value(QStringLiteral("X-KAlgebra-Priority"), QString()); + if(!priority.isValid()) + priority = 1000; + + item->setData(QUrl::fromLocalFile(scriptPath), PathRole); + item->setData(priority, PriorityRole); + item->setData(cg.value(QStringLiteral("Name"), QString()), TitleRole); + item->setData(cg.value(QStringLiteral("Comment"), QStringLiteral("")), SubtitleRole); + item->setData(cg.value(QStringLiteral("Icon"), QString()), Qt::DecorationRole); + + items += item; + } + invisibleRootItem()->appendRows(items); + setSortRole(PriorityRole); + sort(0, Qt::DescendingOrder); +} + +QHash PluginsModel::roleNames() const +{ + QHash rolenames=QStandardItemModel::roleNames(); + rolenames.insert(PathRole, "path"); + rolenames.insert(PriorityRole, "priority"); + rolenames.insert(TitleRole, "title"); + rolenames.insert(SubtitleRole, "subtitle"); + return rolenames; +} + +QString PluginsModel::pluginPath(int row) +{ + return data(index(row, 0), PathRole).toString(); +} + +QStringList PluginsModel::titles() const +{ + QStringList ret; + for (int i=0, c=rowCount(); idata(TitleRole).toString(); + } + return ret; +} diff --git a/mobile/pluginsmodel.h b/mobile/pluginsmodel.h new file mode 100644 index 0000000..1a09a4a --- /dev/null +++ b/mobile/pluginsmodel.h @@ -0,0 +1,45 @@ +/************************************************************************************* + * 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 + Q_PROPERTY(QStringList titles READ titles CONSTANT) + public: + enum Roles { PathRole = Qt::UserRole+1, PriorityRole, TitleRole, SubtitleRole }; + Q_ENUMS(Roles) + + explicit PluginsModel(QObject* parent = 0); + virtual QHash roleNames() const; + + static QString pluginsDirectoryPath(); + + QStringList titles() const; + + public Q_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..5a7038e --- /dev/null +++ b/mobile/resources.qrc @@ -0,0 +1,9 @@ + + + plugins/resources/kde-edu-logo.png + + + ../icons/64-apps-kalgebra.png + ../icons/sc-apps-kalgebra.svgz + + diff --git a/org.kde.kalgebra.appdata.xml b/org.kde.kalgebra.appdata.xml new file mode 100644 index 0000000..dcf2d0f --- /dev/null +++ b/org.kde.kalgebra.appdata.xml @@ -0,0 +1,111 @@ + + + org.kde.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 + KAlgebra + KAlgebra + KAlgebra + KAlgebra + KAlgebra + KAlgebra + KAlgebra + KAlgebra + Kalgebra + KAlgebra + KAlgebra + xxKAlgebraxx + KAlgebra + 數學_KAlgebra +

Graph Calculator + Calculadora gráfica + Graf kalkulator + Calculadora gràfica + Calculadora gràfica + Kalkulačka grafů + Graphenrechner + Graph Calculator + Calculadora gráfica + Graafide arvutaja + Graafinen laskin + Calculatrice graphique + Calculadora gráfica + Grafikus számológép + Calcolatrice grafica + 그래핑 계산기 + Grafinis skaičiuotuvas + Funkschonenreekner + Rekenmachine met grafieken + Grafkalkulator + Kalkulator wykresów + Calculadora de Grafos + Calculadora gráfica + Калькулятор с функцией построения графиков + Grafická kalkulačka + Računalo z grafi + Grafräknare + Grafik Hesap Makinesi + Графічний калькулятор + 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.

+

KAlgebra ye una aplicación que pue trocar la to calculadora gráfica. Tien carauterístiques numbériques, llóxiques, simbóliques y d'analís que te permiten calcular espresiones matemátiques na consola y trazar gráficamente los resultaos en 2D ó 3D. KAlgebra ta arraigonáu nel llinguax matemáticu d'etiquetes (MathML); por embargu, naide necesita saber MathML pa usar KAlgebra

+

KAlgebra és una aplicació que pot reemplaçar la vostra calculadora gràfica. Té capacitats numèriques, lògiques i d'anàlisi que us permetran calcular expressions matemàtiques en una consola i dibuixar una gràfica dels resultats en 2D o 3D. KAlgebra té les seves arrels en el Llenguatge de Marcat Matemàtic (MathML); tanmateix, no us caldrà tenir coneixements de MathML per emprar el KAlgebra.

+

KAlgebra és una aplicació que pot reemplaçar la vostra calculadora gràfica. Té capacitats numèriques, lògiques i d'anàlisi que vos permetran calcular expressions matemàtiques en una consola i dibuixar una gràfica dels resultats en 2D o 3D. KAlgebra té les seues arrels en el Llenguatge de Marcat Matemàtic (MathML); tanmateix, no vos caldrà tindre coneixements de MathML per emprar 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 su calculadora gráfica. Contiene funciones numéricas, lógicas, simbólicas y de análisis que le permiten calcular expresiones matemáticas en la consola y dibujar gráficamente su resultado en dos o tres dimensiones. KAlgebra se basa fuertemente en el «lenguaje de marcado matemático» (MathML); sin embargo, no es necesario saber 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 est une application qui peut remplacer votre calculatrice graphique. Elle fournit des fonctions pour le calcul numérique, logique, symbolique et l'analyse qui vous permettent de calculer des expressions mathématiques dans la console et tracer graphiquement les résultats en 2D ou 3D. KAlgebra repose sur MathML, le langage de balise pour les mathématiques ; cependant, il n'est pas nécessaire de connaître MathML pour utiliser KAlgebra.

+

KAlgebra é un programa que pode substituír as calculadoras gráficas. Ten funcionalidades numéricas, lóxicas, simbólicas e de análise que permiten calcular expresións matemáticas na consola e trazar graficamente os resultados en 2D ou 3D. KAlgebra ten o seu alicerce na Linguaxe de Marcaxe Matemática (MathML); porén, non hai que saber nada do MathML para poder empregar o KAlgebra.

+

A KAlgebra a grafikus számológépe helyébe léphet. Numerikus, logikai, szimbolikus és analízis képességei lehetővé teszik matematikai kifejezések kiértékelését a konzolon, majd grafikus ábrázolását 2D-ben vagy 3D-ben. A KAlgebra erősen épít a MathML matematikai leírónyelv használatára, ugyanakkor nem szükséges MathML ismeret a KAlgebra használatához.

+

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 — программа-калькулятор с функцией построения графиков. Позволяет вычислять значения выражений и строить двумерные и трёхмерные графики функций. В основе KAlgebra лежит язык математической разметки MathML, однако его знания не требуется для использования программы.

+

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, grafik hesap makinanızın yerine geçebilecek bir uygulamadır. Sayısal, mantıksal, sembolik ve analiz özellikleriyle, terminal üzerinden matematiksel ifadeleri hesaplayabilir ve sonuçları 2D veya 3D olarak olarak grafik olarak çizdirebilirsiniz. KAlgebra, Matematiksel İşaret Dili (MathML) üzerine inşa edilmiştir; ancak, KAlgebra kullanmak için MathML bilmek zorunda değilsiniz.

+

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/plasmoids/CMakeLists.txt b/plasmoids/CMakeLists.txt new file mode 100644 index 0000000..1882c04 --- /dev/null +++ b/plasmoids/CMakeLists.txt @@ -0,0 +1,6 @@ +# add_subdirectory(calculator) +# TODO: port to QML + +install(DIRECTORY graphsplasmoid/ DESTINATION ${KDE_INSTALL_DATADIR}/plasma/plasmoids/org.kde.graphsplasmoid) +install(FILES graphsplasmoid/metadata.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} RENAME graphsplasmoid.desktop) + diff --git a/plasmoids/calculator/CMakeLists.txt b/plasmoids/calculator/CMakeLists.txt new file mode 100644 index 0000000..b9d449c --- /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) + +add_library(plasma_applet_kalgebra MODULE ${kalgebraplasma_SRCS}) +target_link_libraries(plasma_applet_kalgebra ${KF5::plasma} KF5::Analitza) + +set(plugin_dir ${KDE_INSTALL_PLUGINDIR}/plugins/kalgebra) +install(TARGETS plasma_applet_kalgebra DESTINATION ${KDE_INSTALL_PLUGINDIR}) +install(FILES kalgebraplasmoid.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) 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..5a2da59 --- /dev/null +++ b/plasmoids/calculator/kalgebraplasma.cpp @@ -0,0 +1,159 @@ +/************************************************************************************* + * 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 + +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"); +} + +QQuickItem* KAlgebraPlasmoid::graphicsWidget() +{ + if(!m_widget) { + m_widget = new QQuickItem(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(QIcon::fromTheme("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()); +} + + diff --git a/plasmoids/calculator/kalgebraplasma.h b/plasmoids/calculator/kalgebraplasma.h new file mode 100644 index 0000000..514aa59 --- /dev/null +++ b/plasmoids/calculator/kalgebraplasma.h @@ -0,0 +1,61 @@ +/************************************************************************************* + * 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 + + +class KAlgebraPlasmoid : public Plasma::Applet +{ + Q_OBJECT + public: + KAlgebraPlasmoid(QObject *parent, const QVariantList &args); + ~KAlgebraPlasmoid(); + + void init(); + virtual QQuickItem* graphicsWidget(); + + private Q_SLOTS: + void simplify(); + void addOperation(); + + private: + static QColor correctColor(); + static QColor errorColor(); + static int simplificationSize(); + + void plasmoidFont(bool big, const QColor& c, bool bold); + + QQuickItem* 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..1169c30 --- /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 2.0 +import org.kde.plasma.components 2.0 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..d9bef59 --- /dev/null +++ b/plasmoids/graphsplasmoid/metadata.desktop @@ -0,0 +1,90 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=Service +ServiceTypes=Plasma/Applet +Name=2D Plots +Name[ast]=Trazaos 2D +Name[bs]=2D crtanja +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]=2D-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]=Двумерный график +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_CN]=二维绘图 +Name[zh_TW]=2D 繪圖 +Comment=Put the weirdest plots on your desktop! +Comment[ast]=¡Pon los trazaos más estraños nel to escritoriu! +Comment[bs]=Postavite najčudnije crteže na vašem desktopu +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[lt]=Dėkite keisčiausius brėžinius ant savo darbalaukio! +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_CN]=在您的桌面上放上奇怪的图表! +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..ef7bb58 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,29 @@ +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") #FIXME: port! + +add_executable(kalgebra ${kalgebra_SRCS}) +target_link_libraries(kalgebra Qt5::Widgets Qt5::PrintSupport Qt5::WebKitWidgets KF5::I18n + KF5::CoreAddons KF5::WidgetsAddons KF5::ConfigWidgets + KF5::XmlGui # HelpMenu + KF5::KIOCore + KF5::I18n + KF5::Analitza KF5::AnalitzaWidgets KF5::AnalitzaGui KF5::AnalitzaPlot) + +install(TARGETS kalgebra ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) +install(PROGRAMS org.kde.kalgebra.desktop DESTINATION ${KDE_INSTALL_APPDIR} ) +install(FILES kalgebra.xml DESTINATION ${KDE_INSTALL_DATADIR}/katepart5/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..b12b2f2 --- /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(QStringLiteral("[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, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::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..a818049 --- /dev/null +++ b/src/consolehtml.cpp @@ -0,0 +1,307 @@ +/************************************************************************************* + * 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 + +ConsoleHtml::ConsoleHtml(QWidget *parent) + : QWebView(parent), m_mode(Evaluation) +{ + page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); + setRenderHint(QPainter::TextAntialiasing); + + connect(this, &QWebView::linkClicked, this, &ConsoleHtml::openClickedUrl); + + 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) +{ + QUrlQuery query(url); + QString id =query.queryItemValue(QStringLiteral("id")); + QString exp=query.queryItemValue(QStringLiteral("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)) { + QUrl url(QStringLiteral("/query")); + QUrlQuery query(url); + query.addQueryItem(QStringLiteral("id"), opt->id()); + query.addQueryItem(QStringLiteral("func"), lambdaexp.toString()); + url.setQuery(query); + + options += i18n(" %2", url.toString(), opt->caption()); + } + } + + if(!options.isEmpty()) + options = "
"+i18n("Options: %1", options)+"
"; + + a.insertVariable(QStringLiteral("ans"), res); + m_script += e; //Script won't have the errors + newEntry = QStringLiteral("%1
=%2").arg(e.toHtml()).arg(result); + } else { + m_htmlLog += i18n("
    Error: %1
  • %2
", input.toHtmlEscaped(), a.errors().join(QStringLiteral("\n
  • "))); + } + + updateView(newEntry, options); + + return a.isCorrect(); +} + +QString temporaryPath() +{ + QTemporaryFile temp(QStringLiteral("consolelog")); + temp.open(); + temp.close(); + temp.setAutoRemove(false); + return QDir::tempPath()+'/'+temp.fileName(); +} + +QString ConsoleHtml::retrieve(const QUrl& remoteUrl) +{ + QString path=temporaryPath(); + + KIO::CopyJob* job=KIO::copyAs(remoteUrl, QUrl(path)); + + bool ret = job->exec(); + if(!ret) + path.clear(); + + return path; +} + +bool ConsoleHtml::loadScript(const QUrl& 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.toString(), a.errors().join(QStringLiteral("
    "))); + updateView(QString(), QString()); + } + else + updateView(i18n("Imported: %1", path.toString()), QString()); + + return correct; +} + +bool ConsoleHtml::saveScript(const QUrl & 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(QUrl(savePath), path); + correct=job->exec(); + } + return correct; +} + +bool ConsoleHtml::saveLog(const QUrl& 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(QUrl(savePath), path); + correct=job->exec(); + } + 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.toUtf8()+"

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

    "+newEntry.toUtf8()+"

    "; + } + 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) +{ + QMenu popup; + if(hasSelection()) { + popup.addAction(KStandardAction::copy(this, SLOT(copy()), &popup)); + QAction *act=new QAction(QIcon::fromTheme(QStringLiteral("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()); +} + + diff --git a/src/consolehtml.h b/src/consolehtml.h new file mode 100644 index 0000000..f4cad41 --- /dev/null +++ b/src/consolehtml.h @@ -0,0 +1,126 @@ +/************************************************************************************* + * 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 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 Q_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 QUrl& path); + + /** Save a script yo @p path. */ + bool saveScript(const QUrl& path) const; + + /** Saves a log to @p path. */ + bool saveLog(const QUrl& path) const; + + /** Flushes the contents. */ + void clear(); + + /** Copies the selected text to the clipboard */ + void copy() const; + + void openClickedUrl(const QUrl& url); + + Q_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 Q_SLOTS: + void initialize(); + + void modifyVariable(const QString& name, const Analitza::Expression& exp); + void removeVariable(const QString& name); + void paste(); + + private: + QString retrieve(const QUrl& 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..a345959 --- /dev/null +++ b/src/dictionary.cpp @@ -0,0 +1,124 @@ +/************************************************************************************* + * 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 + +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); + + m_funcs->addPlot(Analitza::PlotsFactory::self()->requestPlot(e, Analitza::Dim2D, m_vars).create(QColor(0,150,0), QStringLiteral("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); +} + + diff --git a/src/dictionary.h b/src/dictionary.h new file mode 100644 index 0000000..d95fd03 --- /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 Q_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..be9285e --- /dev/null +++ b/src/functionedit.cpp @@ -0,0 +1,321 @@ +/************************************************************************************* + * 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 + +using namespace Analitza; + +namespace { + static const int resolution = 200; +} + +FunctionEdit::FunctionEdit(QWidget *parent) + : QWidget(parent), m_calcUplimit(0), m_calcDownlimit(0), m_modmode(false) +{ + setWindowTitle(i18n("Add/Edit a function")); + + QVBoxLayout *topLayout = new QVBoxLayout(this); + topLayout->setMargin(2); + topLayout->setSpacing(5); + + m_name = new QLineEdit(this); + + m_func = new ExpressionEdit(this); + m_func->setExamples(PlotsFactory::self()->examples(Dim2D)); + m_func->setAns(QStringLiteral("x")); + connect(m_func, &QPlainTextEdit::textChanged, this, &FunctionEdit::edit); + connect(m_func, &ExpressionEdit::returnPressed, this, &FunctionEdit::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 QTabWidget(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->setTicksShown(Qt::Orientation(0)); + + m_viewTabs->addTab(m_graph, QIcon::fromTheme(QStringLiteral("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(QStringLiteral("2*pi")); + m_downlimit->setText(QStringLiteral("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(QStringLiteral("configure")), i18n("Options")); + connect(m_uplimit, &QPlainTextEdit::textChanged, this, &FunctionEdit::updateUplimit); + connect(m_downlimit, &QPlainTextEdit::textChanged, this, &FunctionEdit::updateDownlimit); + + QHBoxLayout *m_butts = new QHBoxLayout; + m_ok = new QPushButton(i18n("OK"), this); + m_ok->setIcon(QIcon::fromTheme(QStringLiteral("dialog-ok"))); + m_remove = new QPushButton(i18nc("@action:button", "Remove"), this); + m_remove->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); + connect(m_ok, &QAbstractButton::clicked, this, &FunctionEdit::ok); + connect(m_remove, &QAbstractButton::clicked, this, &FunctionEdit::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(QStringLiteral("flag-red")).pixmap(QSize(16,16))); + else + m_validIcon->setPixmap(QIcon::fromTheme(QStringLiteral("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(QStringLiteral("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(QStringLiteral("%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(QStringLiteral("
    "))); + 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..daaf767 --- /dev/null +++ b/src/functionedit.h @@ -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 * + *************************************************************************************/ + +#ifndef FUNCTIONEDIT_H +#define FUNCTIONEDIT_H + +#include +#include +#include +#include + +#include + +class QTabWidget; +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 Q_SLOTS: + /** Clears the dialog. */ + void clear(); + +Q_SIGNALS: + /** Tells that the result has been accepted. */ + void accept(); + + /** asks the currently edited plot to be removed. */ + void removeEditingPlot(); + +private Q_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; + QLineEdit *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 = nullptr; + + bool m_modmode; + QTabWidget* m_viewTabs; + QPushButton* m_remove; +}; + +#endif diff --git a/src/kalgebra.cpp b/src/kalgebra.cpp new file mode 100644 index 0000000..a814e70 --- /dev/null +++ b/src/kalgebra.cpp @@ -0,0 +1,749 @@ +/************************************************************************************* + * 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 +#include + +class Add2DOption : public InlineOptions +{ + public: + Add2DOption(KAlgebra* c) + : m_kalgebra(c) + {} + + virtual QString id() const { return QStringLiteral("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 QStringLiteral("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) + : QMainWindow(parent) +{ + resize(900, 500); + + m_tabs = new QTabWidget; + setCentralWidget(m_tabs); + + setStatusBar(new QStatusBar(this)); + setMenuBar(new QMenuBar(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(QStringLiteral("|"))->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() << QStringLiteral("square:=x->x**2") << QStringLiteral("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("&Calculator")); + console->setLayout(c_layo); + c_layo->addWidget(c_results); + c_layo->addWidget(c_exp); + + connect(c_exp, &Analitza::ExpressionEdit::returnPressed, this, &KAlgebra::operate); + connect(c_results, &ConsoleHtml::status, this, &KAlgebra::changeStatusBar); + connect(c_results, &ConsoleHtml::changed, this, &KAlgebra::updateInformation); + connect(c_results, SIGNAL(changed()), c_exp, SLOT(updateCompleter())); + connect(c_results, SIGNAL(paste(QString)), c_exp, SLOT(insertText(QString))); + connect(c_variables, &QAbstractItemView::clicked, this, &KAlgebra::edit_var); + ////////menu + c_menu = menuBar()->addMenu(i18n("C&alculator")); + + c_menu->addAction(QIcon::fromTheme(QStringLiteral("document-open")), i18nc("@item:inmenu", "&Load Script..."), + this, SLOT(loadScript()), Qt::CTRL+Qt::Key_L); + c_recentScripts=new KRecentFilesAction(QIcon::fromTheme(QStringLiteral("document-open-recent")), i18n("Recent Scripts"), this); + connect(c_recentScripts, SIGNAL(urlSelected(QUrl)), this, SLOT(loadScript(QUrl))); + c_menu->addAction(c_recentScripts); + + c_menu->addAction(QIcon::fromTheme(QStringLiteral("document-save")), i18nc("@item:inmenu", "&Save Script..."), + this, SLOT(saveScript()), Qt::CTRL+Qt::Key_G); + c_menu->addAction(QIcon::fromTheme(QStringLiteral("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, &FunctionEdit::accept, this, &KAlgebra::new_func); + connect(b_funced, &FunctionEdit::removeEditingPlot, this, &KAlgebra::remove_func); + b_tools->addTab(b_funced, QIcon::fromTheme(QStringLiteral("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, &QAbstractItemModel::dataChanged, this, &KAlgebra::valueChanged); + connect(b_funcs, &QAbstractItemView::doubleClicked, this, &KAlgebra::edit_func); + connect(b_tools, &QTabWidget::currentChanged, this, &KAlgebra::functools); + connect(m_graph2d, &Analitza::PlotsView2D::status, this, &KAlgebra::changeStatusBar); + 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, &QWidget::customContextMenuRequested, this, &KAlgebra::varsContextMenu); + + ////////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)); + QAction* 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(Analitza::PlotsFactory::self()->examples(Analitza::Dim3D)); + t_exp->setAns(QStringLiteral("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, &Analitza::ExpressionEdit::returnPressed, this, &KAlgebra::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(QIcon::fromTheme(QStringLiteral("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(QStringLiteral("|"))->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 QLineEdit(w); + d_filter->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed)); + connect(d_filter, &QLineEdit::textChanged, dic, &Dictionary::setFilter); + connect(d_filter, &QLineEdit::textChanged, this, &KAlgebra::dictionaryFilterChanged); + 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(), &QItemSelectionModel::currentChanged, + dic, &Dictionary::activated); + + //EODictionary + //Ego's reminder + KHelpMenu* help = new KHelpMenu(this); + menuBar()->addMenu(help->menu()); + +#pragma message("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, &QTabWidget::currentChanged, this, &KAlgebra::tabChanged); + tabChanged(0); +} + +KAlgebra::~KAlgebra() +{ + KConfig conf(QStringLiteral("kalgebrarc")); + KConfigGroup config(&conf, "Default"); + QStringList urls; + foreach(const QUrl& url, c_recentScripts->urls()) + urls += url.toDisplayString(); + + config.writeEntry("recent", urls); +} + +void KAlgebra::initializeRecentScripts() +{ + KConfig conf(QStringLiteral("kalgebrarc")); + KConfigGroup config(&conf, "Default"); + + QStringList urls=config.readEntry("recent", QStringList()); + foreach(const QString& url, urls) { + c_recentScripts->addUrl(QUrl(url)); + } +} + +void KAlgebra::newInstance() +{ + QProcess::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() +{ + QUrl path = QFileDialog::getOpenFileUrl(this, i18n("Choose a script"), QUrl(), i18n("Script (*.kal)")); + + if(!path.isEmpty()) + loadScript(path); +} + +void KAlgebra::loadScript(const QUrl& path) +{ + bool loaded=c_results->loadScript(path); + + if(loaded) + c_recentScripts->addUrl(path); +} + +void KAlgebra::saveScript() +{ + QUrl path = QFileDialog::getSaveFileUrl(this, QString(), QUrl(), i18n("Script (*.kal)")); + bool loaded=false; + if(!path.isEmpty()) + loaded=c_results->saveScript(path); + + if(loaded) + c_recentScripts->addUrl(path); +} + +void KAlgebra::saveLog() +{ + QUrl path = QFileDialog::getSaveFileUrl(this, QString(), QUrl(), i18n("HTML File (*.html)")); + 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, QStringLiteral("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 = QFileDialog::getSaveFileName(this, QString(), QString(), i18n("PNG File (*.png);;PDF Document(*.pdf);;X3D Document (*.x3d)")); + if(!path.isEmpty()) { + if(path.endsWith(QLatin1String(".x3d"))) { + m_graph3d->exportSurfaces(path); + } else if(path.endsWith(QLatin1String(".pdf"))) { + QPixmap px = m_graph3d->renderPixmap(); + 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 { + QPixmap px = m_graph3d->renderPixmap(); + px.save(path); + } + } +#endif +} + +void KAlgebra::toggleSquares() +{ + m_graph2d->setTicksShown(m_graph2d->ticksShown() ? (Qt::Horizontal|Qt::Vertical) : ~(Qt::Horizontal|Qt::Vertical)); +} + +void KAlgebra::toggleKeepAspect() +{ + m_graph2d->setKeepAspectRatio(!m_graph2d->keepAspectRatio()); +} + +void KAlgebra::saveGraph() +{ + QPointer dialog=new QFileDialog(this, i18n("Select where to put the rendered plot"), QString(), i18n("Image File (*.png);;SVG File (*.svg)")); + dialog->setConfirmOverwrite(true); + + if(dialog->exec() && !dialog->selectedFiles().isEmpty()) { + QString filter = dialog->selectedNameFilter(); + QString filename = dialog->selectedFiles().first(); + + bool isSvg = filename.endsWith(QLatin1String(".svg")) || (!filename.endsWith(QLatin1String(".png")) && filter.mid(2, 3)==QLatin1String("svg")); + Analitza::PlotsView2D::Format f = isSvg ? Analitza::PlotsView2D::SVG : Analitza::PlotsView2D::PNG; + 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, QStringLiteral("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.h b/src/kalgebra.h new file mode 100644 index 0000000..68905a3 --- /dev/null +++ b/src/kalgebra.h @@ -0,0 +1,131 @@ +/************************************************************************************* + * 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 + +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 QMainWindow +{ + 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; + QLineEdit *d_filter; + + private Q_SLOTS: + void newInstance(); + void fullScreen(bool isFull); + + void initializeRecentScripts(); + void operate(); + void loadScript(); + void loadScript(const QUrl& 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..152fd04 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,44 @@ +/************************************************************************************* + * 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 +#include "kalgebra.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + KLocalizedString::setApplicationDomain("kalgebra"); + KAboutData about("kalgebra", "KAlgebra", "0.10", i18n("A portable calculator"), + KAboutLicense::GPL, i18n("(C) 2006-2016 Aleix Pol i Gonzalez")); + about.addAuthor( "Aleix Pol i Gonzalez", QString(), "aleixpol@kde.org" ); + about.setTranslator(i18nc("NAME OF TRANSLATORS", "Your names"), i18nc("EMAIL OF TRANSLATORS", "Your emails")); + KAboutData::setApplicationData(about); + + QCommandLineParser parser; + about.setupCommandLine(&parser); + parser.process(app); + about.processCommandLine(&parser); + + KAlgebra widget; + widget.show(); + + return app.exec(); +} diff --git a/src/org.kde.kalgebra.desktop b/src/org.kde.kalgebra.desktop new file mode 100755 index 0000000..3db1391 --- /dev/null +++ b/src/org.kde.kalgebra.desktop @@ -0,0 +1,176 @@ +[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]=Igua y traza 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 %u +MimeType=application/x-kalgebra; +Icon=kalgebra +Type=Application +X-DocPath=kalgebra/index.html +Terminal=false +Categories=Qt;KDE;Education;Math;Science; +X-DBUS-ServiceName=org.kde.kalgebra diff --git a/src/varedit.cpp b/src/varedit.cpp new file mode 100644 index 0000000..af8de17 --- /dev/null +++ b/src/varedit.cpp @@ -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 * + *************************************************************************************/ + +#include "varedit.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +VarEdit::VarEdit(QWidget *parent, bool modal) + : QDialog(parent), vars(0), m_correct(false) +{ + setWindowTitle(i18n("Add/Edit a variable")); + setModal(modal); + + m_buttonBox = new QDialogButtonBox(this); + m_buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + m_removeBtn = m_buttonBox->addButton(i18n("Remove Variable"), QDialogButtonBox::DestructiveRole); + m_removeBtn->setIcon(QIcon::fromTheme(QStringLiteral("edit-table-delete-row"))); + + connect(m_removeBtn, &QAbstractButton::clicked, this, &VarEdit::removeVariable); + + connect( this, SIGNAL(applyClicked()), this, SLOT(accept()) ); + connect( this, SIGNAL(okClicked()), this, SLOT(reject()) ); + + m_exp = new Analitza::ExpressionEdit(this); + connect(m_exp, &QPlainTextEdit::textChanged, this, &VarEdit::edit); + connect(m_exp, &Analitza::ExpressionEdit::returnPressed, this, &VarEdit::ok); + + m_valid = new QLabel(this); + + QVBoxLayout *topLayout = new QVBoxLayout(this); + topLayout->addWidget(m_exp); + topLayout->addWidget(m_valid); + topLayout->addWidget(m_buttonBox); + + 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())); + } + m_removeBtn->setEnabled(vars && 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(QStringLiteral("\n"))); + } + m_buttonBox->button(QDialogButtonBox::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..f100dc4 --- /dev/null +++ b/src/varedit.h @@ -0,0 +1,73 @@ +/************************************************************************************* + * 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 + +class QDialogButtonBox; +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 QDialog +{ + 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; + QDialogButtonBox* m_buttonBox; + QPushButton* m_removeBtn; + + private Q_SLOTS: + void edit(); + void ok(); + void removeVariable(); +}; + +#endif diff --git a/src/variablesdelegate.cpp b/src/variablesdelegate.cpp new file mode 100644 index 0000000..3173878 --- /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..f486877 --- /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..9ef317a --- /dev/null +++ b/src/viewportwidget.cpp @@ -0,0 +1,76 @@ +/************************************************************************************* + * 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 + +ViewportWidget::ViewportWidget(QWidget * parent) + : QWidget (parent) +{ + m_top=new QDoubleSpinBox(this); + m_left=new QDoubleSpinBox(this); + m_width=new QDoubleSpinBox(this); + m_height=new QDoubleSpinBox(this); + +// const double LIMIT=std::numeric_limits::max(); + //Can't use limit, because otherwise Qt uses the value for the sizeHint and + //we get a huge window + const double LIMIT=5000; + m_top->setRange(-LIMIT, LIMIT); + m_left->setRange(-LIMIT, LIMIT); + m_width->setRange(0, LIMIT); + m_height->setRange(0, LIMIT); + + QVBoxLayout* upperLayout=new QVBoxLayout; + 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 QPushButton(QIcon::fromTheme(QStringLiteral("dialog-ok-apply")), i18n("Apply"), this); + connect(apply, &QAbstractButton::clicked, this, &ViewportWidget::emitViewport); + + upperLayout->addLayout(layout); + upperLayout->addWidget(apply); + setLayout(upperLayout); +} + +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..b66a80f --- /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); + + QRectF viewport() const; + + public Q_SLOTS: + void setViewport(const QRectF& current); + + private Q_SLOTS: + void emitViewport(); + + Q_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..36236e4 --- /dev/null +++ b/utils/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(docbook_analitzacommands main.cpp) +target_link_libraries(docbook_analitzacommands KF5::AnalitzaGui Qt5::Widgets Qt5::Core) diff --git a/utils/main.cpp b/utils/main.cpp new file mode 100644 index 0000000..66f88fa --- /dev/null +++ b/utils/main.cpp @@ -0,0 +1,59 @@ +/************************************************************************************* + * 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 + +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(m.index(i,c).data().toString().toHtmlEscaped()) << '\n'; + + str << "\t\n"; + } + str << "\n"; + + return 0; +} -- 2.30.2