├── LICENSE.txt ├── README.md ├── contributing.md └── pdCalc ├── LICENSE.GPL3.txt ├── common.pri ├── pdCalc.pro ├── src ├── app │ ├── app.pro │ ├── pdCalc-simple-cli │ │ ├── main.cpp │ │ └── pdCalc-simple-cli.pro │ ├── pdCalc-simple-gui │ │ ├── main.cpp │ │ └── pdCalc-simple-gui.pro │ └── pdCalc │ │ ├── main.cpp │ │ └── pdCalc.pro ├── backend │ ├── AppObservers.cpp │ ├── AppObservers.h │ ├── Command.cpp │ ├── Command.h │ ├── CommandDispatcher.cpp │ ├── CommandDispatcher.h │ ├── CommandManager.cpp │ ├── CommandManager.h │ ├── CommandRepository.cpp │ ├── CommandRepository.h │ ├── CoreCommands.cpp │ ├── CoreCommands.h │ ├── DynamicLoader.cpp │ ├── DynamicLoader.h │ ├── PlatformFactory.cpp │ ├── PlatformFactory.h │ ├── Plugin.h │ ├── PluginLoader.cpp │ ├── PluginLoader.h │ ├── PosixDynamicLoader.cpp │ ├── PosixDynamicLoader.h │ ├── PosixFactory.cpp │ ├── PosixFactory.h │ ├── Stack.cpp │ ├── Stack.h │ ├── StackPluginInterface.cpp │ ├── StackPluginInterface.h │ ├── StoredProcedure.cpp │ ├── StoredProcedure.h │ ├── WindowsDynamicLoader.cpp │ ├── WindowsDynamicLoader.h │ ├── WindowsFactory.cpp │ ├── WindowsFactory.h │ └── backend.pro ├── plugins │ ├── hyperbolicLnPlugin │ │ ├── HyperbolicLnPlugin.cpp │ │ ├── HyperbolicLnPlugin.h │ │ └── hyperbolicLnPlugin.pro │ ├── plugins.pdp.unix │ ├── plugins.pdp.win │ └── plugins.pro ├── src.pro ├── ui │ ├── cli │ │ ├── Cli.cpp │ │ ├── Cli.h │ │ └── cli.pro │ └── gui │ │ ├── CommandButton.cpp │ │ ├── CommandButton.h │ │ ├── Display.cpp │ │ ├── Display.h │ │ ├── GuiModel.cpp │ │ ├── GuiModel.h │ │ ├── InputWidget.cpp │ │ ├── InputWidget.h │ │ ├── LookAndFeel.cpp │ │ ├── LookAndFeel.h │ │ ├── MainWindow.cpp │ │ ├── MainWindow.h │ │ ├── StoredProcedureDialog.cpp │ │ ├── StoredProcedureDialog.h │ │ └── gui.pro └── utilities │ ├── Exception.h │ ├── Observer.cpp │ ├── Observer.h │ ├── Publisher.cpp │ ├── Publisher.h │ ├── Tokenizer.cpp │ ├── Tokenizer.h │ ├── UserInterface.cpp │ ├── UserInterface.h │ └── utilities.pro └── test ├── backendTest ├── CommandDispatcherTest.cpp ├── CommandDispatcherTest.h ├── CommandManagerTest.cpp ├── CommandManagerTest.h ├── CommandRepositoryTest.cpp ├── CommandRepositoryTest.h ├── CoreCommandsTest.cpp ├── CoreCommandsTest.h ├── PluginLoaderTest.cpp ├── PluginLoaderTest.h ├── StackTest.cpp ├── StackTest.h ├── StoredProcedureTest.cpp ├── StoredProcedureTest.h ├── backendTest.pro ├── hypotenuse ├── plugins.unix.pdp └── plugins.win.pdp ├── cliTest ├── CliTest.cpp ├── CliTest.h ├── cliTest.pro └── testCases │ ├── baselineCli1.txt │ ├── baselineCli2.txt │ ├── inputCli1.txt │ └── inputCli2.txt ├── guiTest ├── DisplayTest.cpp ├── DisplayTest.h └── guiTest.pro ├── pluginsTest ├── HyperbolicLnPluginTest.cpp ├── HyperbolicLnPluginTest.h └── pluginsTest.pro ├── test.pro ├── testDriver ├── main.cpp └── testDriver.pro └── utilitiesTest ├── PublisherObserverTest.cpp ├── PublisherObserverTest.h ├── TokenizerTest.cpp ├── TokenizerTest.h └── utilitiesTest.pro /LICENSE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/practical-cplusplus-design/96f77bb618e6569574441a679bbcc1dacf3fd438/LICENSE.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Apress Source Code 2 | 3 | This repository accompanies [*Practical C++ Design*](http://www.apress.com/9781484230565) by Adam B. Singer (Apress, 2017). 4 | 5 | [comment]: #cover 6 | 7 | 8 | Download the files as a zip using the green button, or clone the repository to your machine using Git. 9 | 10 | ## Releases 11 | 12 | Release v1.0 corresponds to the code in the published book, without corrections or updates. 13 | 14 | ## Contributions 15 | 16 | See the file Contributing.md for more information on how you can contribute to this repository. 17 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to Apress Source Code 2 | 3 | Copyright for Apress source code belongs to the author(s). However, under fair use you are encouraged to fork and contribute minor corrections and updates for the benefit of the author(s) and other readers. 4 | 5 | ## How to Contribute 6 | 7 | 1. Make sure you have a GitHub account. 8 | 2. Fork the repository for the relevant book. 9 | 3. Create a new branch on which to make your change, e.g. 10 | `git checkout -b my_code_contribution` 11 | 4. Commit your change. Include a commit message describing the correction. Please note that if your commit message is not clear, the correction will not be accepted. 12 | 5. Submit a pull request. 13 | 14 | Thank you for your contribution! -------------------------------------------------------------------------------- /pdCalc/common.pri: -------------------------------------------------------------------------------- 1 | CONFIG(debug, debug|release): DEFINES += DEBUG 2 | CONFIG(release, debug|release): DEFINES += RELEASE 3 | VERSION = 1.0.0 4 | VERSION_STR = '\\"$${VERSION}\\"' 5 | DEFINES += PDCALC_VERSION=\"$${VERSION_STR}\" 6 | CONFIG += c++14 7 | 8 | unix:DEFINES += POSIX 9 | win32:DEFINES += WIN32 10 | 11 | # to avoid declspec nonsense 12 | win32:QMAKE_LFLAGS += -Wl,--no-undefined --enable-runtime-pseudo-reloc 13 | -------------------------------------------------------------------------------- /pdCalc/pdCalc.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += src \ 4 | test 5 | 6 | -------------------------------------------------------------------------------- /pdCalc/src/app/app.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += pdCalc \ 4 | pdCalc-simple-cli \ 5 | pdCalc-simple-gui 6 | -------------------------------------------------------------------------------- /pdCalc/src/app/pdCalc-simple-cli/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include 20 | #include 21 | #include "ui/cli/Cli.h" 22 | #include "backend/CommandDispatcher.h" 23 | #include "backend/AppObservers.h" 24 | #include "backend/Stack.h" 25 | #include "backend/CoreCommands.h" 26 | 27 | // I usually don't make blanket using namespace statements, but this 28 | // example is meant to be simple. 29 | using namespace pdCalc; 30 | 31 | using std::cout; 32 | using std::endl; 33 | using std::make_unique; 34 | 35 | int main() 36 | { 37 | Cli cli{std::cin, std::cout}; 38 | 39 | CommandDispatcher ce{cli}; 40 | 41 | RegisterCoreCommands(cli); 42 | 43 | cli.attach(UserInterface::CommandEntered, make_unique(ce) ); 44 | 45 | Stack::Instance().attach(Stack::StackChanged, make_unique(cli) ); 46 | 47 | cli.execute(); 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /pdCalc/src/app/pdCalc-simple-cli/pdCalc-simple-cli.pro: -------------------------------------------------------------------------------- 1 | HOME = ../../.. 2 | include ($$HOME/common.pri) 3 | TEMPLATE = app 4 | TARGET = pdCalc-simple-cli 5 | DEPENDPATH += . 6 | INCLUDEPATH += $$HOME/src 7 | DESTDIR = $$HOME/bin 8 | 9 | win32:CONFIG += console 10 | 11 | SOURCES += main.cpp 12 | 13 | unix:LIBS += -L$$HOME/lib -lpdCalcCli -lpdCalcBackend -lpdCalcUtilities 14 | win32:LIBS += -L$$HOME/bin -lpdCalcCli1 -lpdCalcBackend1 -lpdCalcUtilities1 15 | -------------------------------------------------------------------------------- /pdCalc/src/app/pdCalc-simple-gui/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include 20 | #include 21 | #include "backend/CommandDispatcher.h" 22 | #include "backend/AppObservers.h" 23 | #include "backend/Stack.h" 24 | #include "backend/CoreCommands.h" 25 | #include "ui/gui/MainWindow.h" 26 | #include 27 | 28 | // I usually don't make blanket using namespace statements, but this 29 | // example is meant to be simple. 30 | using namespace pdCalc; 31 | 32 | using std::cout; 33 | using std::endl; 34 | using std::make_unique; 35 | 36 | int main(int argc, char* argv[]) 37 | { 38 | QApplication app{argc, argv}; 39 | MainWindow gui{argc, argv}; 40 | 41 | CommandDispatcher ce{gui}; 42 | 43 | RegisterCoreCommands(gui); 44 | 45 | gui.attach(UserInterface::CommandEntered, make_unique(ce) ); 46 | 47 | Stack::Instance().attach(Stack::StackChanged, make_unique( gui ) ); 48 | 49 | gui.setupFinalButtons(); 50 | gui.show(); 51 | gui.fixSize(); 52 | 53 | return app.exec(); 54 | } 55 | -------------------------------------------------------------------------------- /pdCalc/src/app/pdCalc-simple-gui/pdCalc-simple-gui.pro: -------------------------------------------------------------------------------- 1 | HOME = ../../.. 2 | include ($$HOME/common.pri) 3 | TEMPLATE = app 4 | TARGET = pdCalc-simple-gui 5 | DEPENDPATH += . 6 | INCLUDEPATH += $$HOME/src 7 | DESTDIR = $$HOME/bin 8 | 9 | QT += widgets 10 | 11 | SOURCES += main.cpp 12 | 13 | unix:LIBS += -L$$HOME/lib -lpdCalcGui -lpdCalcBackend -lpdCalcUtilities 14 | win32:LIBS += -L$$HOME/bin -lpdCalcGui1 -lpdCalcBackend1 -lpdCalcUtilities1 15 | -------------------------------------------------------------------------------- /pdCalc/src/app/pdCalc/pdCalc.pro: -------------------------------------------------------------------------------- 1 | HOME = ../../.. 2 | include ($$HOME/common.pri) 3 | TEMPLATE = app 4 | TARGET = pdCalc 5 | DEPENDPATH += . 6 | INCLUDEPATH += $$HOME/src 7 | DESTDIR = $$HOME/bin 8 | 9 | QT += widgets 10 | 11 | win32:CONFIG += console 12 | 13 | SOURCES += main.cpp 14 | 15 | unix:LIBS += -L$$HOME/lib -lpdCalcGui -lpdCalcCli -lpdCalcBackend -lpdCalcUtilities 16 | win32:LIBS += -L$$HOME/bin -lpdCalcGui1 -lpdCalcCli1 -lpdCalcBackend1 -lpdCalcUtilities1 17 | -------------------------------------------------------------------------------- /pdCalc/src/backend/AppObservers.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "AppObservers.h" 20 | #include "utilities/Exception.h" 21 | #include "ui/cli/Cli.h" 22 | #include "Stack.h" 23 | #include "utilities/UserInterface.h" 24 | #include 25 | #include 26 | 27 | using std::ostringstream; 28 | using std::shared_ptr; 29 | using std::dynamic_pointer_cast; 30 | using std::vector; 31 | 32 | namespace pdCalc { 33 | 34 | CommandIssuedObserver::CommandIssuedObserver(CommandDispatcher& ce) 35 | : Observer("CommandIssued") 36 | , ce_(ce) 37 | { } 38 | 39 | void CommandIssuedObserver::notifyImpl(std::shared_ptr eventData) 40 | { 41 | auto data = dynamic_pointer_cast(eventData); 42 | if(!data) 43 | { 44 | throw Exception("Could not convert CommandData to a command"); 45 | } 46 | else 47 | { 48 | ce_.commandEntered( data->command() ); 49 | } 50 | 51 | return; 52 | } 53 | 54 | StackUpdatedObserver::StackUpdatedObserver(UserInterface& ui) 55 | : Observer("StackUpdated") 56 | , ui_(ui) 57 | { } 58 | 59 | void StackUpdatedObserver::notifyImpl(std::shared_ptr) 60 | { 61 | ui_.stackChanged(); 62 | 63 | return; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /pdCalc/src/backend/AppObservers.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef APP_OBSERVERS_H 20 | #define APP_OBSERVERS_H 21 | 22 | #include "utilities/Observer.h" 23 | #include "CommandDispatcher.h" 24 | 25 | namespace pdCalc { 26 | 27 | class UserInterface; 28 | 29 | class CommandIssuedObserver : public Observer 30 | { 31 | public: 32 | explicit CommandIssuedObserver(CommandDispatcher& ce); 33 | 34 | private: 35 | void notifyImpl(std::shared_ptr) override; 36 | 37 | CommandDispatcher& ce_; 38 | }; 39 | 40 | class StackUpdatedObserver : public Observer 41 | { 42 | public: 43 | explicit StackUpdatedObserver(UserInterface& ui); 44 | 45 | private: 46 | void notifyImpl(std::shared_ptr) override; 47 | 48 | UserInterface& ui_; 49 | }; 50 | 51 | 52 | } 53 | #endif 54 | -------------------------------------------------------------------------------- /pdCalc/src/backend/Command.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "Command.h" 20 | #include "Stack.h" 21 | #include "utilities/Exception.h" 22 | 23 | namespace pdCalc { 24 | 25 | void Command::execute() 26 | { 27 | checkPreconditionsImpl(); 28 | executeImpl(); 29 | return; 30 | } 31 | 32 | void Command::undo() 33 | { 34 | undoImpl(); 35 | return; 36 | } 37 | 38 | Command* Command::clone() const 39 | { 40 | return cloneImpl(); 41 | } 42 | 43 | const char* Command::helpMessage() const 44 | { 45 | return helpMessageImpl(); 46 | } 47 | 48 | void Command::deallocate() 49 | { 50 | delete this; 51 | } 52 | 53 | void Command::checkPreconditionsImpl() const 54 | { 55 | return; 56 | } 57 | 58 | BinaryCommand::BinaryCommand(const BinaryCommand& rhs) 59 | : Command(rhs) 60 | , top_{rhs.top_} 61 | , next_{rhs.next_} 62 | { } 63 | 64 | BinaryCommand::~BinaryCommand() 65 | { } 66 | 67 | void BinaryCommand::checkPreconditionsImpl() const 68 | { 69 | if( Stack::Instance().size() < 2 ) 70 | throw Exception{"Stack must have 2 elements"}; 71 | } 72 | 73 | void BinaryCommand::executeImpl() noexcept 74 | { 75 | // suppress change signal so only one event raised for the execute 76 | top_ = Stack::Instance().pop(true); 77 | next_ = Stack::Instance().pop(true); 78 | Stack::Instance().push( binaryOperation(next_, top_) ); 79 | 80 | return; 81 | } 82 | 83 | void BinaryCommand::undoImpl() noexcept 84 | { 85 | // suppress change signal so only one event raised for the execute 86 | Stack::Instance().pop(true); 87 | Stack::Instance().push(next_, true); 88 | Stack::Instance().push(top_); 89 | 90 | return; 91 | } 92 | 93 | UnaryCommand::UnaryCommand(const UnaryCommand& rhs) 94 | : Command(rhs) 95 | , top_(rhs.top_) 96 | { 97 | } 98 | 99 | UnaryCommand::~UnaryCommand() 100 | { } 101 | 102 | void UnaryCommand::checkPreconditionsImpl() const 103 | { 104 | if( Stack::Instance().size() < 1 ) 105 | throw Exception{"Stack must have one element"}; 106 | } 107 | 108 | void UnaryCommand::executeImpl() noexcept 109 | { 110 | // suppress change signal so only one event raised for the execute 111 | top_ = Stack::Instance().pop(true); 112 | Stack::Instance().push( unaryOperation(top_) ); 113 | 114 | return; 115 | } 116 | 117 | void UnaryCommand::undoImpl() noexcept 118 | { 119 | // suppress change signal so only one event raised for the execute 120 | Stack::Instance().pop(true); 121 | Stack::Instance().push(top_); 122 | 123 | return; 124 | } 125 | 126 | PluginCommand::~PluginCommand() 127 | { } 128 | 129 | void PluginCommand::checkPreconditionsImpl() const 130 | { 131 | const char* p = checkPluginPreconditions(); 132 | if(p) throw Exception(p); 133 | 134 | return; 135 | } 136 | 137 | PluginCommand *PluginCommand::cloneImpl() const 138 | { 139 | auto p = clonePluginImpl(); 140 | if(!p) throw Exception("Problem cloning a plugin command"); 141 | else return p; 142 | } 143 | 144 | BinaryCommandAlternative::BinaryCommandAlternative(const std::string& help, std::function f) 145 | : helpMsg_{help} 146 | , command_{f} 147 | { } 148 | 149 | void BinaryCommandAlternative::checkPreconditionsImpl() const 150 | { 151 | if( Stack::Instance().size() < 2 ) 152 | throw Exception{"Stack must have 2 elements"}; 153 | } 154 | 155 | BinaryCommandAlternative::BinaryCommandAlternative(const BinaryCommandAlternative& rhs) 156 | : Command{rhs} 157 | , top_{rhs.top_} 158 | , next_{rhs.next_} 159 | , helpMsg_{rhs.helpMsg_} 160 | , command_{rhs.command_} 161 | { } 162 | 163 | const char *BinaryCommandAlternative::helpMessageImpl() const noexcept 164 | { 165 | return helpMsg_.c_str(); 166 | } 167 | 168 | BinaryCommandAlternative* BinaryCommandAlternative::cloneImpl() const 169 | { 170 | return new BinaryCommandAlternative{*this}; 171 | } 172 | 173 | void BinaryCommandAlternative::executeImpl() noexcept 174 | { 175 | // suppress change signal so only one event raised for the execute 176 | top_ = Stack::Instance().pop(true); 177 | next_ = Stack::Instance().pop(true); 178 | Stack::Instance().push( command_(next_, top_) ); 179 | 180 | return; 181 | } 182 | 183 | void BinaryCommandAlternative::undoImpl() noexcept 184 | { 185 | // suppress change signal so only one event raised for the execute 186 | Stack::Instance().pop(true); 187 | Stack::Instance().push(next_, true); 188 | Stack::Instance().push(top_); 189 | 190 | return; 191 | } 192 | 193 | 194 | } 195 | -------------------------------------------------------------------------------- /pdCalc/src/backend/Command.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef COMMAND_H 20 | #define COMMAND_H 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | namespace pdCalc { 27 | 28 | class Command 29 | { 30 | public: 31 | virtual ~Command() { } 32 | 33 | // executes the command 34 | void execute(); 35 | 36 | // undoes the command 37 | void undo(); 38 | 39 | // create a polymorphic copy of the command 40 | Command* clone() const; 41 | 42 | // supplies a short help message for the command 43 | const char* helpMessage() const; 44 | 45 | // Deletes commands. This should only be overridden in plugins. By default, 46 | // simply deletes command. In plugins, delete must happen in the plugin. 47 | virtual void deallocate(); 48 | 49 | protected: 50 | Command() { } 51 | Command(const Command&) { } 52 | 53 | private: 54 | // this function is not pure virtual because a command that needs no preconditions 55 | // shouldn't be forced to check for any...thus, this defaults to not throwing 56 | virtual void checkPreconditionsImpl() const; 57 | 58 | virtual void executeImpl() noexcept = 0; 59 | virtual void undoImpl() noexcept = 0; 60 | virtual Command* cloneImpl() const = 0; 61 | 62 | // all commands should have a short help 63 | virtual const char* helpMessageImpl() const noexcept = 0; 64 | 65 | Command(Command&&) = delete; 66 | Command& operator=(const Command&) = delete; 67 | Command& operator=(Command&&) = delete; 68 | }; 69 | 70 | // Base class for binary operations: take two elements from stack and return 71 | // one result. For any binary operation x and stack with top and next, 72 | // the binary operation is applied as next x top 73 | // Precondition: Binary operations must have at least two elements 74 | // on the stack 75 | // The reason to have a binary operations class is because undo, 76 | // redo, and preconditions can be implemented identically 77 | class BinaryCommand : public Command 78 | { 79 | public: 80 | virtual ~BinaryCommand(); 81 | 82 | protected: 83 | // throws an exception if the stack size is less than two 84 | void checkPreconditionsImpl() const override; 85 | 86 | BinaryCommand() { } 87 | BinaryCommand(const BinaryCommand&); 88 | 89 | private: 90 | BinaryCommand(BinaryCommand&&) = delete; 91 | BinaryCommand& operator=(const BinaryCommand&) = delete; 92 | BinaryCommand& operator=(BinaryCommand&&) = delete; 93 | 94 | // takes two elements from the stack, applies the binary operation 95 | // and returns the result to the stack 96 | void executeImpl() noexcept override; 97 | 98 | // drops the result and returns the original two numbers to the stack 99 | void undoImpl() noexcept override; 100 | 101 | virtual double binaryOperation(double next, double top) const noexcept = 0; 102 | 103 | double top_; 104 | double next_; 105 | }; 106 | 107 | // Base class for unary operations: take one element from the stack and return 108 | // one result. 109 | // Precondition: Unary operations must have at least one element on the stack. 110 | // The reason to have a unary operations class is to avoid repetition for 111 | // all classes implementing a unary interface. 112 | class UnaryCommand : public Command 113 | { 114 | public: 115 | virtual ~UnaryCommand(); 116 | 117 | protected: 118 | // throws an exception if the stack size is less than one 119 | void checkPreconditionsImpl() const override; 120 | 121 | UnaryCommand() { } 122 | UnaryCommand(const UnaryCommand&); 123 | 124 | private: 125 | UnaryCommand(UnaryCommand&&) = delete; 126 | UnaryCommand& operator=(const UnaryCommand&) = delete; 127 | UnaryCommand& operator=(UnaryCommand&&) = delete; 128 | 129 | // takes one element from the stack, applies the binary operation 130 | // and returns the result to teh stack 131 | void executeImpl() noexcept override; 132 | 133 | // drops the result and returns the original number to the stack 134 | void undoImpl() noexcept override; 135 | 136 | virtual double unaryOperation(double top) const noexcept = 0; 137 | 138 | double top_; 139 | }; 140 | 141 | class PluginCommand : public Command 142 | { 143 | public: 144 | virtual ~PluginCommand(); 145 | 146 | private: 147 | virtual const char* checkPluginPreconditions() const noexcept = 0; 148 | virtual PluginCommand* clonePluginImpl() const noexcept = 0; 149 | 150 | void checkPreconditionsImpl() const override final; 151 | PluginCommand* cloneImpl() const override final; 152 | }; 153 | 154 | // This shows an entirely different design using function and lambdas. 155 | class BinaryCommandAlternative final : public Command 156 | { 157 | using BinaryCommandOp = double(double, double); 158 | public: 159 | BinaryCommandAlternative(const std::string& help, std::function f); 160 | ~BinaryCommandAlternative() = default; 161 | 162 | private: 163 | BinaryCommandAlternative(BinaryCommandAlternative&&) = delete; 164 | BinaryCommandAlternative& operator=(const BinaryCommandAlternative&) = delete; 165 | BinaryCommandAlternative& operator=(BinaryCommandAlternative&&) = delete; 166 | 167 | // throws an exception if the stack size is less than two 168 | void checkPreconditionsImpl() const override; 169 | 170 | BinaryCommandAlternative(const BinaryCommandAlternative&); 171 | 172 | const char* helpMessageImpl() const noexcept override; 173 | 174 | // takes two elements from the stack, applies the binary operation 175 | // and returns the result to the stack 176 | void executeImpl() noexcept override; 177 | 178 | // drops the result and returns the original two numbers to the stack 179 | void undoImpl() noexcept override; 180 | 181 | BinaryCommandAlternative* cloneImpl() const override; 182 | 183 | double top_; 184 | double next_; 185 | std::string helpMsg_; 186 | std::function command_; 187 | }; 188 | 189 | inline void CommandDeleter(Command* p) 190 | { 191 | p->deallocate(); 192 | return; 193 | } 194 | 195 | using CommandPtr = std::unique_ptr; 196 | 197 | template 198 | auto MakeCommandPtr(Args&&... args) 199 | { 200 | return CommandPtr{new T{std::forward(args)...}, &CommandDeleter}; 201 | } 202 | 203 | inline auto MakeCommandPtr(Command* p) 204 | { 205 | return CommandPtr{p, &CommandDeleter}; 206 | } 207 | 208 | } 209 | 210 | #endif 211 | -------------------------------------------------------------------------------- /pdCalc/src/backend/CommandDispatcher.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "CommandDispatcher.h" 20 | #include "CommandRepository.h" 21 | #include "CommandManager.h" 22 | #include "CoreCommands.h" 23 | #include "utilities/Exception.h" 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "utilities/UserInterface.h" 29 | #include 30 | #include "utilities/Tokenizer.h" 31 | #include "StoredProcedure.h" 32 | 33 | using std::string; 34 | using std::ostringstream; 35 | using std::unique_ptr; 36 | using std::set; 37 | using std::istringstream; 38 | 39 | namespace pdCalc { 40 | 41 | class CommandDispatcher::CommandDispatcherImpl 42 | { 43 | public: 44 | explicit CommandDispatcherImpl(UserInterface& ui); 45 | 46 | void executeCommand(const string& command); 47 | 48 | 49 | private: 50 | bool isNum(const string&, double& d); 51 | void handleCommand(CommandPtr command); 52 | void printHelp() const; 53 | 54 | CommandManager manager_; 55 | UserInterface& ui_; 56 | }; 57 | 58 | CommandDispatcher::CommandDispatcherImpl::CommandDispatcherImpl(UserInterface& ui) 59 | : ui_(ui) 60 | { } 61 | 62 | void CommandDispatcher::CommandDispatcherImpl::executeCommand(const string& command) 63 | { 64 | // entry of a number simply goes onto the the stack 65 | double d; 66 | if( isNum(command, d) ) 67 | manager_.executeCommand(MakeCommandPtr(d)); 68 | else if(command == "undo") 69 | manager_.undo(); 70 | else if(command == "redo") 71 | manager_.redo(); 72 | else if(command == "help") 73 | printHelp(); 74 | else if(command.size() > 6 && command.substr(0, 5) == "proc:") 75 | { 76 | auto filename = command.substr(5, command.size() - 5); 77 | handleCommand( MakeCommandPtr(ui_, filename) ); 78 | } 79 | else 80 | { 81 | auto c = CommandRepository::Instance().allocateCommand(command); 82 | if(!c) 83 | { 84 | ostringstream oss; 85 | oss << "Command " << command << " is not a known command"; 86 | ui_.postMessage( oss.str() ); 87 | } 88 | else handleCommand( std::move(c) ); 89 | } 90 | 91 | return; 92 | } 93 | 94 | void CommandDispatcher::CommandDispatcherImpl::handleCommand(CommandPtr c) 95 | { 96 | try 97 | { 98 | manager_.executeCommand( std::move(c) ); 99 | } 100 | catch(Exception& e) 101 | { 102 | ui_.postMessage( e.what() ); 103 | } 104 | 105 | return; 106 | } 107 | 108 | void CommandDispatcher::CommandDispatcherImpl::printHelp() const 109 | { 110 | ostringstream oss; 111 | set allCommands = CommandRepository::Instance().getAllCommandNames(); 112 | oss << "\n"; 113 | oss << "undo: undo last operation\n" 114 | << "redo: redo last operation\n"; 115 | 116 | for(auto i : allCommands) 117 | { 118 | CommandRepository::Instance().printHelp(i, oss); 119 | oss << "\n"; 120 | } 121 | 122 | ui_.postMessage( oss.str() ); 123 | 124 | } 125 | 126 | // uses a C++11 regular expression to check if this is a valid double number 127 | // if so, converts it into one and returns it 128 | bool CommandDispatcher::CommandDispatcherImpl::isNum(const string& s, double& d) 129 | { 130 | if(s == "+" || s == "-") return false; 131 | 132 | std::regex dpRegex("((\\+|-)?[[:digit:]]*)(\\.(([[:digit:]]+)?))?((e|E)((\\+|-)?)[[:digit:]]+)?"); 133 | bool isNumber{ std::regex_match(s, dpRegex) }; 134 | 135 | if(isNumber) 136 | { 137 | d = std::stod(s); 138 | } 139 | 140 | return isNumber; 141 | } 142 | 143 | void CommandDispatcher::commandEntered(const std::string& command) 144 | { 145 | pimpl_->executeCommand(command); 146 | 147 | return; 148 | } 149 | 150 | CommandDispatcher::CommandDispatcher(UserInterface& ui) 151 | { 152 | pimpl_ = std::make_unique(ui); 153 | } 154 | 155 | CommandDispatcher::~CommandDispatcher() 156 | { } 157 | 158 | } 159 | -------------------------------------------------------------------------------- /pdCalc/src/backend/CommandDispatcher.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef COMMAND_DISPATCHER_H 20 | #define COMMAND_DISPATCHER_H 21 | 22 | #include 23 | #include 24 | #include "Command.h" 25 | #include 26 | 27 | namespace pdCalc { 28 | 29 | class UserInterface; 30 | 31 | class CommandDispatcher 32 | { 33 | class CommandDispatcherImpl; 34 | 35 | public: 36 | explicit CommandDispatcher(UserInterface& ui); 37 | ~CommandDispatcher(); 38 | 39 | void commandEntered(const std::string& command); 40 | 41 | private: 42 | CommandDispatcher(const CommandDispatcher&) = delete; 43 | CommandDispatcher(CommandDispatcher&&) = delete; 44 | CommandDispatcher& operator=(const CommandDispatcher&) = delete; 45 | CommandDispatcher& operator=(CommandDispatcher&&) = delete; 46 | 47 | 48 | std::unique_ptr pimpl_; 49 | }; 50 | 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /pdCalc/src/backend/CommandManager.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef COMMAND_MANAGER_H 20 | #define COMMAND_MANAGER_H 21 | 22 | #include 23 | #include "Command.h" 24 | 25 | namespace pdCalc { 26 | 27 | class CommandManager 28 | { 29 | class CommandManagerImpl; 30 | class UndoRedoStackStrategy; 31 | class UndoRedoListStrategyVector; 32 | class UndoRedoListStrategy; 33 | public: 34 | enum class UndoRedoStrategy { ListStrategy, StackStrategy, ListStrategyVector }; 35 | 36 | explicit CommandManager(UndoRedoStrategy st = UndoRedoStrategy::StackStrategy); 37 | ~CommandManager(); 38 | 39 | size_t getUndoSize() const; 40 | size_t getRedoSize() const; 41 | 42 | // This function call executes the command, enters the new command onto the undo stack, 43 | // and it clears the redo stack. This is consistent with typical undo/redo functionality. 44 | void executeCommand(CommandPtr c); 45 | 46 | // This function undoes the command at the top of the undo stack and moves this command 47 | // to the redo stack. It does nothing if the undo stack is empty. 48 | void undo(); 49 | 50 | // This function executes the command at the top of the redo stack and moves this command 51 | // to the undo stack. It does nothing if the redo stack is empty. 52 | void redo(); 53 | 54 | private: 55 | CommandManager(CommandManager&) = delete; 56 | CommandManager(CommandManager&& ) = delete; 57 | CommandManager& operator=(CommandManager&) = delete; 58 | CommandManager& operator=(CommandManager&&) = delete; 59 | 60 | std::unique_ptr pimpl_; 61 | }; 62 | 63 | } 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /pdCalc/src/backend/CommandRepository.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "CommandRepository.h" 20 | #include "Command.h" 21 | #include 22 | #include "../utilities/Exception.h" 23 | #include 24 | 25 | using std::string; 26 | using std::unordered_map; 27 | using std::set; 28 | 29 | namespace pdCalc { 30 | 31 | class CommandRepository::CommandRepositoryImpl 32 | { 33 | public: 34 | CommandRepositoryImpl(); 35 | void registerCommand(const string& name, CommandPtr c); 36 | CommandPtr deregisterCommand(const string& name); 37 | 38 | size_t getNumberCommands() const { return repository_.size(); } 39 | CommandPtr allocateCommand(const string& name) const; 40 | 41 | bool hasKey(const string& s) const; 42 | set getAllCommandNames() const; 43 | 44 | void printHelp(const std::string& command, std::ostream& os); 45 | 46 | void clearAllCommands(); 47 | 48 | private: 49 | using Repository = unordered_map; 50 | Repository repository_; 51 | }; 52 | 53 | CommandRepository::CommandRepositoryImpl::CommandRepositoryImpl() 54 | { 55 | } 56 | 57 | bool CommandRepository::CommandRepositoryImpl::hasKey(const string& s) const 58 | { 59 | return repository_.find(s) != repository_.end(); 60 | } 61 | 62 | set CommandRepository::CommandRepositoryImpl::getAllCommandNames() const 63 | { 64 | set tmp; 65 | 66 | for(auto i = repository_.begin(); i != repository_.end(); ++i) 67 | tmp.insert(i->first); 68 | 69 | return tmp; 70 | } 71 | 72 | void CommandRepository::CommandRepositoryImpl::printHelp(const std::string& command, std::ostream& os) 73 | { 74 | auto it = repository_.find(command); 75 | if(it != repository_.end()) 76 | os << command << ": " << it->second->helpMessage(); 77 | else 78 | os << command << ": no help entry found"; 79 | 80 | return; 81 | } 82 | 83 | void CommandRepository::CommandRepositoryImpl::clearAllCommands() 84 | { 85 | repository_.clear(); 86 | return; 87 | } 88 | 89 | void CommandRepository::CommandRepositoryImpl::registerCommand(const string& name, CommandPtr c) 90 | { 91 | if( hasKey(name) ) 92 | { 93 | std::ostringstream oss; 94 | oss << "Command " << name << " already registered"; 95 | throw Exception{ oss.str() }; 96 | } 97 | else 98 | repository_.emplace( name, std::move(c) ); 99 | 100 | return; 101 | } 102 | 103 | CommandPtr CommandRepository::CommandRepositoryImpl::deregisterCommand(const string& name) 104 | { 105 | if( hasKey(name) ) 106 | { 107 | auto i = repository_.find(name); 108 | auto tmp = MakeCommandPtr( i->second.release() ); 109 | repository_.erase(i); 110 | return tmp; 111 | } 112 | else return MakeCommandPtr(nullptr); 113 | } 114 | 115 | CommandPtr CommandRepository::CommandRepositoryImpl::allocateCommand(const string &name) const 116 | { 117 | if( hasKey(name) ) 118 | { 119 | const auto& command = repository_.find(name)->second; 120 | return MakeCommandPtr( command->clone() ); 121 | } 122 | else return MakeCommandPtr(nullptr); 123 | } 124 | 125 | CommandRepository::CommandRepository() 126 | : pimpl_{ new CommandRepositoryImpl } 127 | { 128 | } 129 | 130 | CommandRepository::~CommandRepository() 131 | { } 132 | 133 | CommandRepository& CommandRepository::Instance() 134 | { 135 | static CommandRepository instance; 136 | return instance; 137 | } 138 | 139 | void CommandRepository::registerCommand(const string& name, CommandPtr c) 140 | { 141 | pimpl_->registerCommand( name, std::move(c) ); 142 | 143 | return; 144 | } 145 | CommandPtr CommandRepository::deregisterCommand(const string& name) 146 | { 147 | return pimpl_->deregisterCommand(name); 148 | } 149 | 150 | size_t CommandRepository::getNumberCommands() const 151 | { 152 | return pimpl_->getNumberCommands(); 153 | } 154 | 155 | CommandPtr CommandRepository::allocateCommand(const string& name) const 156 | { 157 | return pimpl_->allocateCommand(name); 158 | } 159 | 160 | bool CommandRepository::hasKey(const string& s) const 161 | { 162 | return pimpl_->hasKey(s); 163 | } 164 | 165 | set CommandRepository::getAllCommandNames() const 166 | { 167 | return pimpl_->getAllCommandNames(); 168 | } 169 | 170 | void CommandRepository::printHelp(const std::string& command, std::ostream& os) const 171 | { 172 | pimpl_->printHelp(command, os); 173 | return; 174 | } 175 | 176 | void CommandRepository::clearAllCommands() 177 | { 178 | pimpl_->clearAllCommands(); 179 | return; 180 | } 181 | 182 | } 183 | -------------------------------------------------------------------------------- /pdCalc/src/backend/CommandRepository.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef COMMAND_REPOSITORY_H 20 | #define COMMAND_REPOSITORY_H 21 | 22 | // The CommandRepository class is responsible for returning a Command by name. New commands 23 | // can be dynamically added at runtime (to support) plugins, and commands can also be 24 | // deregistered (if desired if a plugin is removed). New commands are returned as clones 25 | // of the registered Command. This makes use of the Prototype pattern. 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "Command.h" 32 | 33 | namespace pdCalc { 34 | 35 | class CommandRepository 36 | { 37 | class CommandRepositoryImpl; 38 | public: 39 | static CommandRepository& Instance(); 40 | 41 | // register a new command for the factory: throws if a command with the 42 | // same name already exists...deregister first to replace a command 43 | void registerCommand(const std::string& name, CommandPtr c); 44 | 45 | // deregister a command: returns the pointer to a command and subsequently 46 | // removes it from the internal database of commands...returns a nullptr 47 | // if the command does not exist 48 | CommandPtr deregisterCommand(const std::string& name); 49 | 50 | // returns the number of commands currently registered 51 | size_t getNumberCommands() const; 52 | 53 | // returns a pointer to a command without deregistering the command...returns 54 | // a nullptr if the command does not exist 55 | CommandPtr allocateCommand(const std::string& name) const; 56 | 57 | // returns true if the command is present, false otherwise 58 | bool hasKey(const std::string& s) const; 59 | 60 | // returns a set of all the commands 61 | std::set getAllCommandNames() const; 62 | 63 | // prints help for command 64 | void printHelp(const std::string& command, std::ostream&) const; 65 | 66 | // clears all commands; mainly needed for testing 67 | void clearAllCommands(); 68 | 69 | private: 70 | CommandRepository(); 71 | ~CommandRepository(); 72 | 73 | CommandRepository(CommandRepository&) = delete; 74 | CommandRepository(CommandRepository&&) = delete; 75 | CommandRepository& operator=(CommandRepository&) = delete; 76 | CommandRepository& operator=(CommandRepository&&) = delete; 77 | 78 | std::unique_ptr pimpl_; 79 | }; 80 | 81 | } 82 | #endif 83 | -------------------------------------------------------------------------------- /pdCalc/src/backend/DynamicLoader.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "DynamicLoader.h" 20 | 21 | namespace pdCalc { 22 | 23 | DynamicLoader::~DynamicLoader() 24 | { 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /pdCalc/src/backend/DynamicLoader.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef DYNAMIC_LOADER_H 20 | #define DYNAMIC_LOADER_H 21 | 22 | // This is the base class to abstract OS specific dynamic library loading. 23 | // Loading should be the same in any POSIX compliant OS (e.g., Linux, Mac OS X, 24 | // BSD). Windows loads dynamic libraries differently. 25 | 26 | // Note, this class specifies that Plugins must have a function named AllocPlugin with 27 | // signature 28 | // pdCalc::Plugin* AllocPlugin() 29 | // that allocates a pdCalc::Plugin with the global new function. The pdCalc::Plugin base 30 | // class is defined in a separate header. 31 | 32 | #include 33 | 34 | namespace pdCalc { 35 | 36 | class Plugin; 37 | 38 | class DynamicLoader 39 | { 40 | public: 41 | virtual ~DynamicLoader(); 42 | 43 | // derived class must provide an OS specific way of loading a shared library, 44 | // dynamically binding to the AllocPlugin function in the plugin, allocating the 45 | // plugin, and closing the plugin 46 | virtual Plugin* allocatePlugin(const std::string& pluginName) = 0; 47 | virtual void deallocatePlugin(Plugin*) = 0; 48 | 49 | // Get the plugin allocation name for derived classes 50 | static const std::string GetPluginAllocationName() { return "AllocPlugin"; } 51 | static const std::string GetPluginDeallocationName() { return "DeallocPlugin"; } 52 | }; 53 | 54 | } 55 | 56 | // function pointer for the interface to allocate a plugin 57 | extern "C" { typedef void* (*PluginAllocator)(void); } 58 | 59 | // function pointer for the interface to deallocate a plugin 60 | extern "C" { typedef void (*PluginDeallocator)(void*); } 61 | #endif 62 | -------------------------------------------------------------------------------- /pdCalc/src/backend/PlatformFactory.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "PlatformFactory.h" 20 | 21 | #ifdef POSIX 22 | #include "PosixFactory.h" 23 | #elif WIN32 24 | #include "WindowsFactory.h" 25 | #endif 26 | 27 | namespace pdCalc { 28 | 29 | PlatformFactory::PlatformFactory() 30 | { 31 | } 32 | 33 | PlatformFactory& PlatformFactory::Instance() 34 | { 35 | #ifdef POSIX 36 | static PosixFactory instance; 37 | #elif WIN32 38 | static WindowsFactory instance; 39 | #endif 40 | 41 | return instance; 42 | } 43 | 44 | PlatformFactory::~PlatformFactory() 45 | { 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /pdCalc/src/backend/PlatformFactory.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef PLATFORM_FACTORY_H 20 | #define PLATFORM_FACTORY_H 21 | 22 | #include 23 | 24 | namespace pdCalc { 25 | 26 | class DynamicLoader; 27 | 28 | class PlatformFactory 29 | { 30 | public: 31 | static PlatformFactory& Instance(); 32 | virtual ~PlatformFactory(); 33 | 34 | virtual std::unique_ptr createDynamicLoader() = 0; 35 | 36 | protected: 37 | PlatformFactory(); 38 | 39 | private: 40 | PlatformFactory(const PlatformFactory&) = delete; 41 | PlatformFactory& operator=(const PlatformFactory&) = delete; 42 | PlatformFactory(PlatformFactory&&) = delete; 43 | PlatformFactory& operator=(PlatformFactory&&) = delete; 44 | }; 45 | 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /pdCalc/src/backend/Plugin.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef PLUGIN_H 20 | #define PLUGIN_H 21 | 22 | // This is the base class to extend pdCalc with plugin commands. The plugin 23 | // must provide a command with its name (for the command structure), which 24 | // automatically provides a CLI interface. Optionally, a plugin can provide 25 | // a GUI interface. 26 | 27 | #include "Command.h" 28 | 29 | namespace pdCalc { 30 | 31 | class CommandButton; 32 | 33 | // Plugins are responsible for deleting the memory in the descriptors 34 | class Plugin 35 | { 36 | public: 37 | Plugin() { } 38 | virtual ~Plugin() { } 39 | 40 | struct PluginDescriptor 41 | { 42 | int nCommands; 43 | char** commandNames; 44 | Command** commands; 45 | }; 46 | 47 | virtual const PluginDescriptor& getPluginDescriptor() const = 0; 48 | 49 | struct PluginButtonDescriptor 50 | { 51 | int nButtons; 52 | char** dispPrimaryCmd; 53 | char** primaryCmd; 54 | char** dispShftCmd; 55 | char** shftCmd; 56 | }; 57 | 58 | // pointer instead of reference so that nullptr can be returned if buttons are not provided 59 | virtual const PluginButtonDescriptor* getPluginButtonDescriptor() const = 0; 60 | 61 | struct ApiVersion 62 | { 63 | int major; 64 | int minor; 65 | }; 66 | 67 | virtual ApiVersion apiVersion() const = 0; 68 | 69 | private: 70 | Plugin(const Plugin&) = delete; 71 | Plugin& operator=(const Plugin&) = delete; 72 | Plugin(Plugin&&) = delete; 73 | Plugin& operator=(Plugin&&) = delete; 74 | }; 75 | 76 | } 77 | #endif 78 | -------------------------------------------------------------------------------- /pdCalc/src/backend/PluginLoader.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "PluginLoader.h" 20 | #include "utilities/UserInterface.h" 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "DynamicLoader.h" 26 | #include "Plugin.h" 27 | #include "PlatformFactory.h" 28 | 29 | using std::vector; 30 | using std::string; 31 | using std::ifstream; 32 | using std::unique_ptr; 33 | 34 | namespace pdCalc { 35 | 36 | class PluginDeleter 37 | { 38 | public: 39 | explicit PluginDeleter(DynamicLoader& d) : loader_{d} {} 40 | void operator()(Plugin* p) { loader_.deallocatePlugin(p); } 41 | 42 | private: 43 | DynamicLoader& loader_; 44 | }; 45 | 46 | class PluginLoader::PluginLoaderImpl 47 | { 48 | public: 49 | PluginLoaderImpl(); 50 | 51 | void loadPlugins(UserInterface& ui, const string& pluginFileName); 52 | const vector getPlugins(); 53 | 54 | private: 55 | void load(UserInterface& ui, const string&); 56 | 57 | vector> loaders_; 58 | vector> plugins_; 59 | }; 60 | 61 | PluginLoader::PluginLoaderImpl::PluginLoaderImpl() 62 | { 63 | } 64 | 65 | void PluginLoader::PluginLoaderImpl::loadPlugins(UserInterface& ui, const string& pluginFileName) 66 | { 67 | ifstream ifs{ pluginFileName.c_str() }; 68 | if(!ifs) 69 | { 70 | ui.postMessage("Could not open plugin file"); 71 | } 72 | else 73 | { 74 | vector pluginNames{ std::istream_iterator(ifs), std::istream_iterator() }; 75 | 76 | for(auto i : pluginNames) load(ui, i); 77 | } 78 | 79 | return; 80 | } 81 | 82 | const vector PluginLoader::PluginLoaderImpl::getPlugins() 83 | { 84 | vector v; 85 | for(auto& i : plugins_) 86 | v.push_back( i.get() ); 87 | 88 | return v; 89 | } 90 | 91 | void PluginLoader::PluginLoaderImpl::load(UserInterface& ui, const string& name) 92 | { 93 | loaders_.emplace_back( PlatformFactory::Instance().createDynamicLoader() ); 94 | 95 | // may be null 96 | auto p = loaders_.back()->allocatePlugin(name); 97 | if(p) plugins_.emplace_back( p, PluginDeleter( *loaders_.back() ) ); 98 | else ui.postMessage("Error opening plugin"); 99 | 100 | return; 101 | } 102 | 103 | PluginLoader::PluginLoader() 104 | : pimpl_{ new PluginLoaderImpl } 105 | { } 106 | 107 | PluginLoader::~PluginLoader() 108 | { } 109 | 110 | void PluginLoader::loadPlugins(UserInterface& ui, const string& pluginFileName) 111 | { 112 | pimpl_->loadPlugins(ui, pluginFileName); 113 | return; 114 | } 115 | 116 | const std::vector PluginLoader::getPlugins() 117 | { 118 | return pimpl_->getPlugins(); 119 | } 120 | 121 | } 122 | 123 | -------------------------------------------------------------------------------- /pdCalc/src/backend/PluginLoader.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef PLUGIN_LOADER_H 20 | #define PLUGIN_LOADER_H 21 | 22 | // This class can load the plugins specified in a file. 23 | // The file has the path and name of the plugins specified 24 | // on separate lines. 25 | // If a plugin cannot be loaded, the loader fails informs 26 | // the UI but ignores the error. 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | namespace pdCalc { 33 | 34 | class Plugin; 35 | class UserInterface; 36 | 37 | class PluginLoader 38 | { 39 | class PluginLoaderImpl; 40 | public: 41 | PluginLoader(); 42 | ~PluginLoader(); 43 | 44 | void loadPlugins(UserInterface& ui, const std::string& pluginFileName); 45 | const std::vector getPlugins(); 46 | 47 | private: 48 | PluginLoader(const PluginLoader&) = delete; 49 | PluginLoader(PluginLoader&&) = delete; 50 | PluginLoader& operator=(const PluginLoader&) = delete; 51 | PluginLoader& operator=(PluginLoader&&) = delete; 52 | 53 | std::unique_ptr pimpl_; 54 | }; 55 | 56 | } 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /pdCalc/src/backend/PosixDynamicLoader.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "PosixDynamicLoader.h" 20 | #include "utilities/Exception.h" 21 | #include 22 | #include 23 | #include 24 | 25 | using std::cout; 26 | using std::endl; 27 | 28 | namespace pdCalc { 29 | 30 | PosixDynamicLoader::PosixDynamicLoader() 31 | : DynamicLoader{} 32 | , handle_{nullptr} 33 | { 34 | } 35 | 36 | PosixDynamicLoader::~PosixDynamicLoader() 37 | { 38 | if(handle_) dlclose(handle_); 39 | } 40 | 41 | Plugin* PosixDynamicLoader::allocatePlugin(const std::string& pluginName) 42 | { 43 | handle_ = dlopen(pluginName.c_str(), RTLD_LAZY); 44 | 45 | if(!handle_) return nullptr; 46 | else 47 | { 48 | auto alloc = dlsym(handle_, GetPluginAllocationName().c_str()); 49 | PluginAllocator allocator{ reinterpret_cast(alloc) }; 50 | if(allocator) 51 | { 52 | auto p = static_cast((*allocator)()); 53 | return p; 54 | } 55 | else return nullptr; 56 | } 57 | 58 | return nullptr; 59 | } 60 | 61 | void PosixDynamicLoader::deallocatePlugin(Plugin* p) 62 | { 63 | if(!handle_) 64 | throw Exception("Trying to deallocate a plugin, but shared library is not open."); 65 | else 66 | { 67 | auto dealloc = dlsym(handle_, GetPluginDeallocationName().c_str()); 68 | auto deallocator = reinterpret_cast(dealloc); 69 | if(deallocator) 70 | { 71 | (*deallocator)(p); 72 | } 73 | else throw Exception("Could not load the deallocator function in the plugin"); 74 | } 75 | 76 | return; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /pdCalc/src/backend/PosixDynamicLoader.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef POSIX_DYNAMIC_LOADER_H 20 | #define POSIX_DYNAMIC_LOADER_H 21 | 22 | #include 23 | #include "DynamicLoader.h" 24 | 25 | namespace pdCalc { 26 | 27 | class PosixDynamicLoader : public DynamicLoader 28 | { 29 | public: 30 | PosixDynamicLoader(); 31 | ~PosixDynamicLoader(); 32 | 33 | Plugin* allocatePlugin(const std::string& pluginName) override; 34 | void deallocatePlugin(Plugin* p) override; 35 | 36 | private: 37 | void* handle_; 38 | }; 39 | 40 | } 41 | 42 | #endif // POSIXDYNAMICLOADER_H 43 | -------------------------------------------------------------------------------- /pdCalc/src/backend/PosixFactory.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "PosixFactory.h" 20 | #include "PosixDynamicLoader.h" 21 | 22 | using std::unique_ptr; 23 | 24 | namespace pdCalc { 25 | 26 | PosixFactory::PosixFactory() 27 | { 28 | } 29 | 30 | unique_ptr PosixFactory::createDynamicLoader() 31 | { 32 | return std::make_unique(); 33 | } 34 | 35 | } 36 | 37 | -------------------------------------------------------------------------------- /pdCalc/src/backend/PosixFactory.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef POSIX_FACTORY_H 20 | #define POSIX_FACTORY_H 21 | 22 | #include "PlatformFactory.h" 23 | #include 24 | 25 | namespace pdCalc { 26 | 27 | class PosixFactory : public PlatformFactory 28 | { 29 | public: 30 | PosixFactory(); 31 | 32 | std::unique_ptr createDynamicLoader() override; 33 | }; 34 | 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /pdCalc/src/backend/Stack.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "Stack.h" 20 | #include "utilities/Exception.h" 21 | #include 22 | 23 | using std::vector; 24 | using std::string; 25 | 26 | namespace pdCalc { 27 | 28 | const string Stack::StackChanged = "stackChanged"; 29 | const string Stack::StackError = "error"; 30 | 31 | const char* StackEventData::Message(StackEventData::ErrorConditions ec) 32 | { 33 | switch(ec) 34 | { 35 | case ErrorConditions::Empty: return "Attempting to pop empty stack"; 36 | case ErrorConditions::TooFewArguments: return "Need at least two stack elements to swap top"; 37 | default: return "Unknown error"; 38 | }; 39 | } 40 | 41 | const char* StackEventData::message() const 42 | { 43 | return Message(err_); 44 | } 45 | 46 | class Stack::StackImpl 47 | { 48 | public: 49 | explicit StackImpl(const Stack&); 50 | void push(double d, bool suppressChangeEvent); 51 | double pop(bool suppressChangeEvent); 52 | void swapTop(); 53 | vector getElements(size_t n) const; 54 | void getElements(size_t n, vector& v) const; 55 | size_t size() const { return stack_.size(); } 56 | void clear(); 57 | double top() const; 58 | 59 | private: 60 | const Stack& parent_; // for raising events 61 | std::deque stack_; 62 | }; 63 | 64 | Stack::StackImpl::StackImpl(const Stack& s) 65 | : parent_(s) 66 | { 67 | 68 | } 69 | 70 | void Stack::StackImpl::push(double d, bool suppressChangeEvent) 71 | { 72 | stack_.push_back(d); 73 | if(!suppressChangeEvent) parent_.raise(Stack::StackChanged, nullptr); 74 | 75 | return; 76 | } 77 | 78 | double Stack::StackImpl::pop(bool suppressChangeEvent) 79 | { 80 | if( stack_.empty() ) 81 | { 82 | parent_.raise(Stack::StackError, 83 | std::make_shared(StackEventData::ErrorConditions::Empty)); 84 | 85 | throw Exception{StackEventData::Message(StackEventData::ErrorConditions::Empty)}; 86 | } 87 | else 88 | { 89 | auto val = stack_.back(); 90 | stack_.pop_back(); 91 | if(!suppressChangeEvent) parent_.raise(Stack::StackChanged, nullptr); 92 | return val; 93 | } 94 | } 95 | 96 | void Stack::StackImpl::swapTop() 97 | { 98 | if( stack_.size() < 2 ) 99 | { 100 | parent_.raise(Stack::StackError, 101 | std::make_shared(StackEventData::ErrorConditions::TooFewArguments)); 102 | 103 | throw Exception{StackEventData::Message(StackEventData::ErrorConditions::TooFewArguments)}; 104 | } 105 | else 106 | { 107 | auto first = stack_.back(); 108 | stack_.pop_back(); 109 | auto second = stack_.back(); 110 | stack_.pop_back(); 111 | stack_.push_back(first); 112 | stack_.push_back(second); 113 | 114 | parent_.raise(Stack::StackChanged, nullptr); 115 | } 116 | 117 | return; 118 | } 119 | 120 | vector Stack::StackImpl::getElements(size_t n) const 121 | { 122 | vector v; 123 | getElements(n, v); 124 | return v; 125 | } 126 | 127 | void Stack::StackImpl::getElements(size_t n, vector& v) const 128 | { 129 | // if n is > stack's size, just return size of stack 130 | if(n > stack_.size()) n = stack_.size(); 131 | 132 | v.insert(v.end(), stack_.rbegin(), stack_.rbegin() + n); 133 | 134 | return; 135 | } 136 | 137 | void Stack::StackImpl::clear() 138 | { 139 | stack_.clear(); 140 | 141 | parent_.raise(Stack::StackChanged, nullptr); 142 | 143 | return; 144 | } 145 | 146 | double Stack::StackImpl::top() const 147 | { 148 | return stack_.back(); 149 | } 150 | 151 | Stack& Stack::Instance() 152 | { 153 | static Stack instance; 154 | return instance; 155 | } 156 | 157 | void Stack::push(double d, bool suppressChangeEvent) 158 | { 159 | pimpl_->push(d, suppressChangeEvent); 160 | return; 161 | } 162 | 163 | double Stack::pop(bool suppressChangeEvent) 164 | { 165 | return pimpl_->pop(suppressChangeEvent); 166 | } 167 | 168 | void Stack::swapTop() 169 | { 170 | pimpl_->swapTop(); 171 | return; 172 | } 173 | 174 | vector Stack::getElements(size_t n) const 175 | { 176 | return pimpl_->getElements(n); 177 | } 178 | 179 | void Stack::getElements(size_t n, vector& v) const 180 | { 181 | pimpl_->getElements(n, v); 182 | return; 183 | } 184 | 185 | size_t Stack::size() const 186 | { 187 | return pimpl_->size(); 188 | } 189 | 190 | void Stack::clear() const 191 | { 192 | pimpl_->clear(); 193 | return; 194 | } 195 | 196 | Stack::Stack() 197 | { 198 | pimpl_ = std::make_unique(*this); 199 | registerEvent(StackChanged); 200 | registerEvent(StackError); 201 | } 202 | 203 | Stack::~Stack() 204 | { 205 | 206 | } 207 | 208 | } 209 | 210 | -------------------------------------------------------------------------------- /pdCalc/src/backend/Stack.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef STACK_H 20 | #define STACK_H 21 | 22 | #include "../utilities/Publisher.h" 23 | #include 24 | #include 25 | #include 26 | 27 | namespace pdCalc { 28 | 29 | class StackEventData : public EventData 30 | { 31 | public: 32 | enum class ErrorConditions { Empty, TooFewArguments }; 33 | explicit StackEventData(ErrorConditions e) : err_(e) { } 34 | 35 | static const char* Message(ErrorConditions ec); 36 | const char* message() const; 37 | ErrorConditions error() const { return err_; } 38 | 39 | private: 40 | ErrorConditions err_; 41 | }; 42 | 43 | class Stack : private Publisher 44 | { 45 | class StackImpl; // so that the implementation can raise events 46 | 47 | public: 48 | static Stack& Instance(); 49 | void push(double, bool suppressChangeEvent = false); 50 | double pop(bool suppressChangeEvent = false); 51 | void swapTop(); 52 | 53 | // returns first min(n, stackSize) elements of the stack with the top of stack at position 0 54 | std::vector getElements(size_t n) const; 55 | void getElements(size_t n, std::vector&) const; 56 | 57 | using Publisher::attach; 58 | using Publisher::detach; 59 | 60 | // these are just needed for testing 61 | size_t size() const; 62 | void clear() const; 63 | 64 | static const std::string StackChanged; 65 | static const std::string StackError; 66 | 67 | private: 68 | Stack(); 69 | ~Stack(); 70 | Stack(const Stack&) = delete; 71 | Stack(Stack&&) = delete; 72 | Stack& operator=(const Stack&) = delete; 73 | Stack& operator=(const Stack&&) = delete; 74 | 75 | std::unique_ptr pimpl_; 76 | }; 77 | 78 | } 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /pdCalc/src/backend/StackPluginInterface.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "Stack.h" 20 | #include "StackPluginInterface.h" 21 | 22 | using std::vector; 23 | 24 | void StackPush(double d, bool suppressChangeEvent) 25 | { 26 | pdCalc::Stack::Instance().push(d, suppressChangeEvent); 27 | 28 | return; 29 | } 30 | 31 | double StackPop(bool suppressChangeEvent) 32 | { 33 | return pdCalc::Stack::Instance().pop(suppressChangeEvent); 34 | } 35 | 36 | size_t StackSize() 37 | { 38 | return pdCalc::Stack::Instance().size(); 39 | } 40 | 41 | double StackFirstElement() 42 | { 43 | vector v = pdCalc::Stack::Instance().getElements(1); 44 | return v[0]; 45 | } 46 | 47 | double StackSecondElement() 48 | { 49 | vector v = pdCalc::Stack::Instance().getElements(2); 50 | return v[1]; 51 | } 52 | -------------------------------------------------------------------------------- /pdCalc/src/backend/StackPluginInterface.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef STACK_PLUGIN_INTERFACE_H 20 | #define STACK_PLUGIN_INTERFACE_H 21 | 22 | extern "C" void StackPush(double d, bool suppressChangeEvent); 23 | extern "C" double StackPop(bool suppressChangeEvent); 24 | extern "C" size_t StackSize(); 25 | extern "C" double StackFirstElement(); 26 | extern "C" double StackSecondElement(); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /pdCalc/src/backend/StoredProcedure.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "StoredProcedure.h" 20 | #include "CommandDispatcher.h" 21 | #include "utilities/Exception.h" 22 | #include "utilities/Tokenizer.h" 23 | #include 24 | 25 | using std::string; 26 | 27 | namespace pdCalc { 28 | 29 | StoredProcedure::StoredProcedure(UserInterface& ui, const string& filename) 30 | : filename_{filename} 31 | { 32 | ce_ = std::make_unique(ui); 33 | } 34 | 35 | StoredProcedure::~StoredProcedure() 36 | { } 37 | 38 | void StoredProcedure::checkPreconditionsImpl() const 39 | { 40 | if(first_) 41 | { 42 | try 43 | { 44 | std::ifstream ifs{ filename_.c_str() }; 45 | if(!ifs) 46 | throw Exception{"Could not open procedure"}; 47 | 48 | tokenizer_ = std::make_unique(ifs); 49 | } 50 | catch(...) 51 | { 52 | throw Exception{"Could not open procedure"}; 53 | } 54 | } 55 | 56 | return; 57 | } 58 | 59 | void StoredProcedure::executeImpl() noexcept 60 | { 61 | if(first_) 62 | { 63 | for(auto c : *tokenizer_) 64 | { 65 | ce_->commandEntered(c); 66 | } 67 | first_ = false; 68 | } 69 | else 70 | { 71 | for(unsigned int i = 0; i < tokenizer_->nTokens(); ++i) 72 | ce_->commandEntered("redo"); 73 | } 74 | 75 | return; 76 | } 77 | 78 | void StoredProcedure::undoImpl() noexcept 79 | { 80 | for(unsigned int i = 0; i < tokenizer_->nTokens(); ++i) 81 | ce_->commandEntered("undo"); 82 | 83 | return; 84 | } 85 | 86 | Command*StoredProcedure::cloneImpl() const noexcept 87 | { 88 | return 0; 89 | } 90 | 91 | const char* StoredProcedure::helpMessageImpl() const noexcept 92 | { 93 | return "Executes a stored procedure from disk"; 94 | } 95 | 96 | } 97 | 98 | -------------------------------------------------------------------------------- /pdCalc/src/backend/StoredProcedure.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef STORED_PROCEDURE_H 20 | #define STORED_PROCEDURE_H 21 | 22 | #include "Command.h" 23 | #include "utilities/Tokenizer.h" 24 | #include 25 | #include 26 | 27 | namespace pdCalc { 28 | 29 | class CommandDispatcher; 30 | class UserInterface; 31 | 32 | class StoredProcedure : public Command 33 | { 34 | public: 35 | StoredProcedure(UserInterface& ui, const std::string& filename); 36 | ~StoredProcedure(); 37 | 38 | private: 39 | StoredProcedure() = delete; 40 | StoredProcedure(StoredProcedure&&) = delete; 41 | StoredProcedure& operator=(const StoredProcedure&) = delete; 42 | StoredProcedure& operator=(StoredProcedure&&) = delete; 43 | StoredProcedure(const StoredProcedure&) = delete; 44 | 45 | void checkPreconditionsImpl() const override; 46 | void executeImpl() noexcept override; 47 | void undoImpl() noexcept override; 48 | Command* cloneImpl() const noexcept override; 49 | const char* helpMessageImpl() const noexcept override; 50 | 51 | mutable std::unique_ptr tokenizer_; 52 | std::unique_ptr ce_; 53 | std::string filename_; 54 | bool first_ = true; 55 | }; 56 | 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /pdCalc/src/backend/WindowsDynamicLoader.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "WindowsDynamicLoader.h" 20 | #include 21 | #include 22 | #include "utilities/Exception.h" 23 | 24 | using std::wstring; 25 | using std::string; 26 | using std::vector; 27 | 28 | namespace { 29 | wstring toWstring(const string& s) 30 | { 31 | vector ws(s.size()); 32 | std::mbstowcs(&ws[0], s.c_str(), s.size()); 33 | return wstring{ws.begin(), ws.end()}; 34 | } 35 | 36 | } 37 | 38 | namespace pdCalc { 39 | 40 | WindowsDynamicLoader::WindowsDynamicLoader() 41 | : DynamicLoader{} 42 | , handle_{nullptr} 43 | { 44 | 45 | } 46 | 47 | WindowsDynamicLoader::~WindowsDynamicLoader() 48 | { 49 | if(handle_) FreeLibrary(handle_); 50 | } 51 | 52 | Plugin* WindowsDynamicLoader::allocatePlugin(const std::string& pluginName) 53 | { 54 | wstring wPluginName = toWstring(pluginName); 55 | handle_ = LoadLibrary(wPluginName.c_str()); 56 | 57 | if(!handle_) return nullptr; 58 | else 59 | { 60 | auto alloc = GetProcAddress(handle_, GetPluginAllocationName().c_str()); 61 | PluginAllocator allocator{ reinterpret_cast(alloc) }; 62 | if(allocator) 63 | { 64 | auto p = static_cast((*allocator)()); 65 | return p; 66 | } 67 | else return nullptr; 68 | } 69 | } 70 | 71 | void WindowsDynamicLoader::deallocatePlugin(Plugin* p) 72 | { 73 | if(!handle_) 74 | throw Exception("Trying to deallocate a plugin, but shared library is not open."); 75 | else 76 | { 77 | auto dealloc = GetProcAddress(handle_, GetPluginDeallocationName().c_str()); 78 | auto deallocator = reinterpret_cast(dealloc); 79 | if(deallocator) 80 | { 81 | (*deallocator)(p); 82 | } 83 | else throw Exception("Could not load the deallocator function in the plugin"); 84 | } 85 | 86 | return; 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /pdCalc/src/backend/WindowsDynamicLoader.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef WINDOWS_DYNAMIC_LOADER_H 20 | #define WINDOWS_DYNAMIC_LOADER_H 21 | 22 | #include 23 | #include 24 | #include "DynamicLoader.h" 25 | 26 | namespace pdCalc { 27 | 28 | class WindowsDynamicLoader : public DynamicLoader 29 | { 30 | public: 31 | WindowsDynamicLoader(); 32 | ~WindowsDynamicLoader(); 33 | 34 | Plugin* allocatePlugin(const std::string& pluginName) override; 35 | void deallocatePlugin(Plugin* p) override; 36 | 37 | private: 38 | HINSTANCE handle_; 39 | }; 40 | 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /pdCalc/src/backend/WindowsFactory.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "WindowsFactory.h" 20 | #include "WindowsDynamicLoader.h" 21 | 22 | namespace pdCalc { 23 | 24 | WindowsFactory::WindowsFactory() 25 | { } 26 | 27 | std::unique_ptr WindowsFactory::createDynamicLoader() 28 | { 29 | return std::make_unique(); 30 | } 31 | 32 | } 33 | 34 | -------------------------------------------------------------------------------- /pdCalc/src/backend/WindowsFactory.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef WINDOWS_FACTORY_H 20 | #define WINDOWS_FACTORY_H 21 | 22 | #include "PlatformFactory.h" 23 | #include 24 | 25 | namespace pdCalc { 26 | 27 | class WindowsFactory : public PlatformFactory 28 | { 29 | public: 30 | WindowsFactory(); 31 | 32 | std::unique_ptr createDynamicLoader() override; 33 | }; 34 | 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /pdCalc/src/backend/backend.pro: -------------------------------------------------------------------------------- 1 | HOME = ../.. 2 | include ($$HOME/common.pri) 3 | TEMPLATE = lib 4 | TARGET = pdCalcBackend 5 | DEPENDPATH += . 6 | INCLUDEPATH += . $$HOME/src 7 | unix:DESTDIR = $$HOME/lib 8 | win32:DESTDIR = $$HOME/bin 9 | 10 | 11 | win32:DEFINES += _USE_MATH_DEFINES 12 | 13 | # Input 14 | HEADERS += Stack.h \ 15 | StackPluginInterface.h \ 16 | Command.h \ 17 | CommandManager.h \ 18 | CommandRepository.h \ 19 | CommandDispatcher.h \ 20 | CoreCommands.h \ 21 | StoredProcedure.h \ 22 | PluginLoader.h \ 23 | DynamicLoader.h \ 24 | Plugin.h \ 25 | PlatformFactory.h \ 26 | StackPluginInterface.h \ 27 | AppObservers.h 28 | 29 | unix:HEADERS += PosixDynamicLoader.h \ 30 | PosixFactory.h 31 | 32 | win32:HEADERS += WindowsDynamicLoader.h \ 33 | WindowsFactory.h 34 | 35 | SOURCES += Stack.cpp \ 36 | StackPluginInterface.cpp \ 37 | CommandManager.cpp \ 38 | CommandRepository.cpp \ 39 | CommandDispatcher.cpp \ 40 | Command.cpp \ 41 | CoreCommands.cpp \ 42 | StoredProcedure.cpp \ 43 | PluginLoader.cpp \ 44 | DynamicLoader.cpp \ 45 | PlatformFactory.cpp \ 46 | AppObservers.cpp 47 | 48 | unix:SOURCES += PosixDynamicLoader.cpp \ 49 | PosixFactory.cpp 50 | 51 | win32:SOURCES += WindowsDynamicLoader.cpp \ 52 | WindowsFactory.cpp 53 | 54 | unix:LIBS += -ldl 55 | win32:LIBS += -L$$HOME/bin -lpdCalcUtilities1 56 | -------------------------------------------------------------------------------- /pdCalc/src/plugins/hyperbolicLnPlugin/HyperbolicLnPlugin.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef HYPERBOLIC_LN_PLUGIN_H 20 | #define HYPERBOLIC_LN_PLUGIN_H 21 | 22 | #include 23 | #include 24 | #include "backend/Plugin.h" 25 | 26 | class HyperbolicLnPlugin : public pdCalc::Plugin 27 | { 28 | class HyperbolicLnPluginImpl; 29 | public: 30 | HyperbolicLnPlugin(); 31 | ~HyperbolicLnPlugin(); 32 | 33 | const PluginDescriptor& getPluginDescriptor() const override; 34 | const PluginButtonDescriptor* getPluginButtonDescriptor() const override; 35 | pdCalc::Plugin::ApiVersion apiVersion() const; 36 | 37 | private: 38 | std::unique_ptr pimpl_; 39 | }; 40 | 41 | extern "C" void* AllocPlugin(); 42 | extern "C" void DeallocPlugin(void*); 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /pdCalc/src/plugins/hyperbolicLnPlugin/hyperbolicLnPlugin.pro: -------------------------------------------------------------------------------- 1 | HOME = ../../.. 2 | include ($$HOME/common.pri) 3 | TEMPLATE = lib 4 | TARGET = hyperbolicLnPlugin 5 | DEPENDPATH += . 6 | INCLUDEPATH += . $$HOME/src 7 | unix:DESTDIR = $$HOME/lib 8 | win32:DESTDIR = $$HOME/bin 9 | QT += widgets 10 | 11 | # Input 12 | HEADERS += HyperbolicLnPlugin.h 13 | SOURCES += HyperbolicLnPlugin.cpp 14 | 15 | unix:QMAKE_PRE_LINK+=$(COPY_FILE) $$PWD/../plugins.pdp.unix $$HOME/bin/plugins.pdp 16 | win32:QMAKE_PRE_LINK+=$(COPY_FILE) $$shell_path($$PWD/../plugins.pdp.win) $$shell_path($$HOME/bin/plugins.pdp) 17 | 18 | win32:LIBS += -L$$HOME/bin -lpdCalcUtilities1 -lpdCalcBackend1 19 | -------------------------------------------------------------------------------- /pdCalc/src/plugins/plugins.pdp.unix: -------------------------------------------------------------------------------- 1 | ../lib/libhyperbolicLnPlugin.so 2 | -------------------------------------------------------------------------------- /pdCalc/src/plugins/plugins.pdp.win: -------------------------------------------------------------------------------- 1 | hyperbolicLnPlugin1.dll 2 | -------------------------------------------------------------------------------- /pdCalc/src/plugins/plugins.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += hyperbolicLnPlugin 4 | -------------------------------------------------------------------------------- /pdCalc/src/src.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += utilities \ 4 | backend \ 5 | ui/cli \ 6 | ui/gui \ 7 | app \ 8 | plugins 9 | -------------------------------------------------------------------------------- /pdCalc/src/ui/cli/Cli.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "Cli.h" 20 | #include "utilities/Tokenizer.h" 21 | #include "backend/Stack.h" 22 | #include 23 | #include 24 | 25 | using std::vector; 26 | using std::string; 27 | using std::istream; 28 | using std::ostream; 29 | using std::endl; 30 | using std::ostringstream; 31 | 32 | namespace pdCalc { 33 | 34 | class Cli::CliImpl 35 | { 36 | public: 37 | CliImpl(Cli&, istream& in, ostream& out); 38 | void postMessage(const string& m); 39 | void execute(bool suppressStartupMessage, bool echo); 40 | void stackChanged(); 41 | 42 | private: 43 | void startupMessage(); 44 | 45 | Cli& parent_; 46 | istream& in_; 47 | ostream& out_; 48 | }; 49 | 50 | Cli::CliImpl::CliImpl(Cli& p, istream& in, ostream& out) 51 | : parent_(p) 52 | , in_(in) 53 | , out_(out) 54 | { 55 | } 56 | 57 | void Cli::CliImpl::postMessage(const string& m) 58 | { 59 | out_ << m << endl; 60 | return; 61 | } 62 | 63 | void Cli::CliImpl::startupMessage() 64 | { 65 | out_ << "pdCalc v. " << PDCALC_VERSION << ", an RPN calculator\n" 66 | << "type 'help' for a list of commnads\n" 67 | << "'exit' to end program\n" << endl; 68 | 69 | return; 70 | } 71 | 72 | void Cli::CliImpl::execute(bool suppressStartupMessage, bool echo) 73 | { 74 | if(!suppressStartupMessage) startupMessage(); 75 | 76 | for(string line; std::getline(in_, line, '\n'); ) 77 | { 78 | Tokenizer tokenizer{line}; 79 | for(const auto& i : tokenizer) 80 | { 81 | if(echo) out_ << i << endl; 82 | if(i == "exit" || i == "quit") 83 | { 84 | return; 85 | } 86 | else 87 | { 88 | parent_.raise(UserInterface::CommandEntered, std::make_shared(i)); 89 | } 90 | } 91 | } 92 | 93 | return; 94 | } 95 | 96 | void Cli::CliImpl::stackChanged() 97 | { 98 | unsigned int nElements{4}; 99 | auto v = Stack::Instance().getElements(nElements); 100 | ostringstream oss; 101 | oss.precision(12); 102 | size_t size = Stack::Instance().size(); 103 | oss << "\n"; 104 | if(size == 0) 105 | oss << "Stack currently empty.\n"; 106 | else if(size == 1) 107 | oss << "Top element of stack (size = " << size << "):\n"; 108 | else if(size > 1 && size <= nElements) 109 | oss << "Top " << size << " elements of stack (size = " << size << "):\n"; 110 | else 111 | oss << "Top " << nElements << " elements of stack (size = " << size << "):\n"; 112 | 113 | size_t j{ v.size() }; 114 | for(auto i = v.rbegin(); i != v.rend(); ++i) 115 | { 116 | oss << j << ":\t" << *i << "\n"; 117 | --j; 118 | } 119 | 120 | postMessage( oss.str() ); 121 | } 122 | 123 | Cli::Cli(istream& in, ostream& out) 124 | { 125 | pimpl_ = std::make_unique(*this, in, out); 126 | } 127 | 128 | Cli::~Cli() 129 | { } 130 | 131 | void Cli::postMessage(const string& m) 132 | { 133 | pimpl_->postMessage(m); 134 | return; 135 | } 136 | 137 | void Cli::stackChanged() 138 | { 139 | pimpl_->stackChanged(); 140 | return; 141 | } 142 | 143 | void Cli::execute(bool suppressStartupMessage, bool echo) 144 | { 145 | pimpl_->execute(suppressStartupMessage, echo); 146 | 147 | return; 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /pdCalc/src/ui/cli/Cli.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef CLI_H 20 | #define CLI_H 21 | 22 | #include "utilities/UserInterface.h" 23 | #include 24 | #include 25 | #include 26 | 27 | namespace pdCalc { 28 | 29 | class Cli : public UserInterface 30 | { 31 | class CliImpl; 32 | public: 33 | Cli(std::istream&, std::ostream&); 34 | ~Cli(); 35 | 36 | // start the cli run loop 37 | void execute(bool suppressStartupMessage = false, bool echo = false); 38 | 39 | private: 40 | // posts a text message to the output 41 | void postMessage(const std::string& m) override; 42 | 43 | // updates the output when the stack is changed 44 | void stackChanged() override; 45 | 46 | Cli(const Cli&) = delete; 47 | Cli(Cli&&) = delete; 48 | Cli& operator=(const Cli&) = delete; 49 | Cli& operator=(Cli&&) = delete; 50 | 51 | std::unique_ptr pimpl_; 52 | }; 53 | 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /pdCalc/src/ui/cli/cli.pro: -------------------------------------------------------------------------------- 1 | HOME = ../../.. 2 | include ($$HOME/common.pri) 3 | TEMPLATE = lib 4 | TARGET = pdCalcCli 5 | DEPENDPATH += . 6 | INCLUDEPATH += . $$HOME/src 7 | unix:DESTDIR = $$HOME/lib 8 | win32:DESTDIR = $$HOME/bin 9 | 10 | 11 | # Input 12 | HEADERS += Cli.h 13 | SOURCES += Cli.cpp 14 | 15 | win32:LIBS += -L$$HOME/bin -lpdCalcUtilities1 -lpdCalcBackend1 16 | -------------------------------------------------------------------------------- /pdCalc/src/ui/gui/CommandButton.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "CommandButton.h" 20 | #include "LookAndFeel.h" 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | using std::ostringstream; 30 | using std::cout; 31 | using std::endl; 32 | 33 | using std::string; 34 | 35 | namespace pdCalc { 36 | 37 | CommandButton::CommandButton(const string& dispPrimaryCmd, const string& primaryCmd, 38 | const string& dispShftCmd, const string& shftCmd, QWidget* parent) 39 | : QWidget{parent} 40 | , primaryCmd_{primaryCmd} 41 | , shftCmd_{shftCmd} 42 | { 43 | setup(dispPrimaryCmd, dispShftCmd); 44 | } 45 | 46 | CommandButton::CommandButton(const std::string& dispPrimaryCmd, const std::string& primaryCmd, QWidget* parent) 47 | : QWidget{parent} 48 | , primaryCmd_{primaryCmd} 49 | , shftCmd_{""} 50 | { 51 | setup(dispPrimaryCmd, ""); 52 | } 53 | 54 | void CommandButton::registerShortcut(const QKeySequence& sequence) 55 | { 56 | // Use the shortcut mechanism rather than btn_->setShortcut() to allow 57 | // multiple different shortcuts for one button (e.g., plus/minus button) 58 | // shortcuts with both p and m. btn_->setShortcut() releases the current 59 | // shortcut when the next one is set. 60 | 61 | auto sc = new QShortcut(sequence, btn_); 62 | connect(sc, SIGNAL(activated()), this, SLOT(onClicked())); 63 | } 64 | 65 | void CommandButton::registerToolTip(const string& s) 66 | { 67 | btn_->setToolTip( QString::fromStdString(s) ); 68 | return; 69 | } 70 | 71 | void CommandButton::setButtonTextColor(const std::string& color) 72 | { 73 | ostringstream oss; 74 | oss << "QPushButton { color : " << color << "; }"; 75 | btn_->setStyleSheet( oss.str().c_str() ); 76 | 77 | return; 78 | } 79 | 80 | void CommandButton::onClicked() 81 | { 82 | emit clicked(primaryCmd_, shftCmd_); 83 | } 84 | 85 | void CommandButton::setup(const std::string& dispPrimaryCmd, const std::string& dispShftCmd) 86 | { 87 | btn_ = new QPushButton{ QString::fromStdString(dispPrimaryCmd), this}; 88 | btn_->setFont( LookAndFeel::Instance().getButtonFont() ); 89 | btn_->setFixedSize( LookAndFeel::Instance().getMinimumButtonSize() ); 90 | 91 | auto label = new QLabel{ QString::fromStdString(dispShftCmd), this }; 92 | label->setFont( LookAndFeel::Instance().getShiftLabelFont() ); 93 | label->setMinimumSize( ( dispShftCmd.empty() ? QSize(0, 0) : LookAndFeel::Instance().getMinimumShiftLabelSize()) ); 94 | 95 | ostringstream oss; 96 | oss << "QLabel { color : " << LookAndFeel::Instance().getShiftColor() <<"; }"; 97 | label->setStyleSheet( oss.str().c_str() ); 98 | 99 | connect(btn_, SIGNAL(clicked()), this, SLOT(onClicked())); 100 | 101 | auto layout = new QVBoxLayout{this}; 102 | layout->setSpacing(0); 103 | layout->addWidget(label); 104 | layout->addWidget(btn_); 105 | layout->setContentsMargins( LookAndFeel::Instance().getContentsMargins() ); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /pdCalc/src/ui/gui/CommandButton.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef COMMANDBUTTON_H 20 | #define COMMANDBUTTON_H 21 | 22 | #include 23 | #include 24 | 25 | class QPushButton; 26 | 27 | namespace pdCalc { 28 | 29 | // Class capable of emitting a signal with the primary and shift commands when the 30 | // button is clicked. Note that the receiver is responsible for figuring out if the 31 | // calculator is in shifted state. 32 | class CommandButton : public QWidget 33 | { 34 | Q_OBJECT 35 | public: 36 | // Initialize the button with the primary command to be displayed, the string commanad 37 | // this triggers, the shift command to be displayed, and the string command the 38 | // shift triggers 39 | CommandButton(const std::string& dispPrimaryCmd, const std::string& primaryCmd, 40 | const std::string& dispShftCmd, const std::string& shftCmd, QWidget* parent = nullptr); 41 | 42 | CommandButton(const std::string& dispPrimaryCmd, const std::string& primaryCmd, 43 | QWidget* parent = nullptr); 44 | 45 | // registers a keyboard shortcut 46 | void registerShortcut(const QKeySequence &sequence); 47 | 48 | // enter a tooltip so that hovering over the button will cause text to be displayed, 49 | // presumably the text will be the keyboard shortuct 50 | void registerToolTip(const std::string& s); 51 | 52 | // change button color (used, for example, for a shift button) 53 | void setButtonTextColor(const std::string& color); 54 | 55 | private slots: 56 | void onClicked(); 57 | 58 | signals: 59 | void clicked(std::string primCmd, std::string shftCmd); 60 | 61 | private: 62 | void setup(const std::string& dispPrimaryCmd, const std::string& dispShftCommand); 63 | 64 | std::string primaryCmd_; 65 | std::string shftCmd_; 66 | 67 | QPushButton* btn_; 68 | }; 69 | 70 | } 71 | 72 | #endif // COMMANDBUTTON_H 73 | -------------------------------------------------------------------------------- /pdCalc/src/ui/gui/Display.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "Display.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "LookAndFeel.h" 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "GuiModel.h" 32 | 33 | using std::vector; 34 | using std::ostringstream; 35 | using std::string; 36 | 37 | namespace pdCalc { 38 | 39 | class Display::DisplayImpl : public QWidget 40 | { 41 | public: 42 | explicit DisplayImpl(const GuiModel&, int nLinesStack, int nCharWide, QVBoxLayout* layout, Display* parent); 43 | string getText() const; 44 | void showMessage(const string& m); 45 | void onModelChanged(); 46 | 47 | private: 48 | void setupSize(); 49 | void resizeEvent(QResizeEvent*) override; 50 | string createLine(int lineNumber, double value, int stackSize); 51 | QValidator::State validate(const string&); 52 | 53 | const GuiModel& guiModel_; 54 | QLabel* label_; 55 | int nLinesStack_; 56 | int nCharWide_; 57 | QStatusBar* statusBar_; 58 | unsigned int statusBarTimeout; 59 | QLabel* shiftIndicator_; 60 | }; 61 | 62 | Display::DisplayImpl::DisplayImpl(const GuiModel& g, int nLinesStack, int nCharWide, QVBoxLayout* layout, Display* parent) 63 | : QWidget{parent} 64 | , guiModel_{g} 65 | , nLinesStack_{nLinesStack} 66 | , nCharWide_{nCharWide} 67 | , statusBarTimeout{3000} 68 | { 69 | statusBar_ = new QStatusBar{this}; 70 | statusBar_->setFont( LookAndFeel::Instance().getStatusBarFont() ); 71 | statusBar_->setSizeGripEnabled(false); 72 | statusBar_->setPalette( LookAndFeel::Instance().getStatusBarPalette() ); 73 | shiftIndicator_ = new QLabel{"Shift", this}; 74 | statusBar_->addPermanentWidget(shiftIndicator_); 75 | shiftIndicator_->hide(); 76 | 77 | label_ = new QLabel{this}; 78 | 79 | ostringstream oss; 80 | oss << "QLabel { background-color : " << LookAndFeel::Instance().getDisplayBackgroundColor() << "; " 81 | << "border : " << LookAndFeel::Instance().getDisplayBorderStyle() << "; " 82 | << "border-radius : " << LookAndFeel::Instance().getDisplayBorderRadius() << "}"; 83 | label_->setStyleSheet( oss.str().c_str() ); 84 | 85 | layout->addWidget(statusBar_); 86 | layout->addWidget(label_); 87 | 88 | label_->setFont( LookAndFeel::Instance().getDisplayFont() ); 89 | 90 | setupSize(); 91 | 92 | onModelChanged(); 93 | } 94 | 95 | string Display::DisplayImpl::getText() const 96 | { 97 | return label_->text().toStdString(); 98 | } 99 | 100 | void Display::DisplayImpl::showMessage(const string& m) 101 | { 102 | statusBar_->showMessage( QString::fromStdString(m), statusBarTimeout); 103 | return; 104 | } 105 | 106 | void Display::DisplayImpl::setupSize() 107 | { 108 | QFontMetrics fm{LookAndFeel::Instance().getDisplayFont()}; 109 | label_->setFixedHeight( nLinesStack_ * fm.height() + 2); 110 | label_->setMinimumWidth( (nCharWide_ + 2) * fm.maxWidth() ); 111 | 112 | return; 113 | } 114 | 115 | void Display::DisplayImpl::resizeEvent(QResizeEvent* event) 116 | { 117 | QFontMetrics fm{LookAndFeel::Instance().getDisplayFont()}; 118 | int w{ event->size().width() }; 119 | nCharWide_ = w / fm.maxWidth() - 2; 120 | 121 | onModelChanged(); 122 | 123 | return; 124 | } 125 | 126 | string Display::DisplayImpl::createLine(int lineNumber, double sv, int stackSize) 127 | { 128 | string value{""}; 129 | if(lineNumber < stackSize) 130 | { 131 | ostringstream t; 132 | t.precision(12); 133 | t << sv; 134 | value = t.str(); 135 | } 136 | 137 | ostringstream oss; 138 | oss << lineNumber + 1 << ":"; 139 | int lineLabelSize{ static_cast(oss.str().size()) }; 140 | for(int i = 0; i < nCharWide_ - static_cast( value.length() ) - lineLabelSize; ++i) 141 | { 142 | oss << ' '; 143 | } 144 | oss << value; 145 | return oss.str(); 146 | } 147 | 148 | void Display::DisplayImpl::onModelChanged() 149 | { 150 | const GuiModel::State& state = guiModel_.getState(); 151 | if(state.shiftState == GuiModel::ShiftState::Shifted) 152 | { 153 | shiftIndicator_->show(); 154 | } 155 | else shiftIndicator_->hide(); 156 | 157 | ostringstream oss; 158 | auto hasInput = state.curInput.size() != 0; 159 | auto start = nLinesStack_ - ( hasInput ? 1 : 0 ); 160 | 161 | for(int i = start - 1; i > -1; --i) 162 | { 163 | bool valueExists = i < static_cast( state.curStack.size() ); 164 | oss << createLine( i, (valueExists ? state.curStack[i] : 0 /*dummy value*/), state.curStack.size() ) << (i != 0 ? "\n" : ""); 165 | } 166 | 167 | if(hasInput) 168 | { 169 | oss << "\n" 170 | << state.curInput; 171 | } 172 | 173 | label_->setText( QString::fromStdString( oss.str() ) ); 174 | } 175 | 176 | Display::Display(const GuiModel& g, QWidget *parent, int nLinesStack, int nCharWide) 177 | : QWidget{parent} 178 | { 179 | auto layout = new QVBoxLayout{this}; 180 | pimpl_ = new DisplayImpl{g, nLinesStack, nCharWide, layout, this}; 181 | layout->setContentsMargins( LookAndFeel::Instance().getContentsMargins() ); 182 | layout->addWidget(pimpl_); 183 | } 184 | 185 | std::string Display::getText() const 186 | { 187 | return pimpl_->getText(); 188 | } 189 | 190 | void Display::showMessage(const std::string& m) 191 | { 192 | pimpl_->showMessage(m); 193 | 194 | return; 195 | } 196 | 197 | void Display::onModelChanged() 198 | { 199 | pimpl_->onModelChanged(); 200 | } 201 | 202 | 203 | } 204 | -------------------------------------------------------------------------------- /pdCalc/src/ui/gui/Display.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef DISPLAY_H 20 | #define DISPLAY_H 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | namespace pdCalc { 28 | 29 | class GuiModel; 30 | 31 | // This class is the calculator's display. It shows a number of lines of the stack 32 | // as determined by the constructor and shows the input as it is entered 33 | 34 | class Display : public QWidget 35 | { 36 | class DisplayImpl; 37 | Q_OBJECT 38 | public: 39 | // nLinesStack is the number of vertical lines of the stack to be displayed 40 | // minCharWide is the minimum number of characters wide for the display (defaults to min size) 41 | explicit Display(const GuiModel& g, QWidget* parent = nullptr, int nLinesStack = 6, int minCharWide = 25); 42 | 43 | // this is for testing purposes to be able to get the current display 44 | std::string getText() const; 45 | 46 | // show message in the status bar 47 | void showMessage(const std::string& m); 48 | 49 | public slots: 50 | // call this slot when the underlying model changes 51 | void onModelChanged(); 52 | 53 | private: 54 | DisplayImpl* pimpl_; 55 | 56 | }; 57 | 58 | } 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /pdCalc/src/ui/gui/GuiModel.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef GUI_MODEL_H 20 | #define GUI_MODEL_H 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | namespace pdCalc { 29 | 30 | class GuiModel : public QObject 31 | { 32 | class GuiModelImpl; 33 | Q_OBJECT 34 | public: 35 | enum class ShiftState { Unshifted, Shifted }; 36 | 37 | struct State 38 | { 39 | State(); 40 | 41 | std::vector curStack; 42 | std::string curInput; 43 | ShiftState shiftState; 44 | QValidator::State curInputValidity; 45 | }; 46 | 47 | explicit GuiModel(QObject* parent = nullptr); 48 | ~GuiModel(); 49 | 50 | void stackChanged(const std::vector& v); 51 | 52 | const State& getState() const; 53 | 54 | // exposed externally for testing only 55 | bool inputEmpty() const; 56 | void clearInput(); 57 | 58 | public slots: 59 | // called to toggle the calculator's shift state 60 | void onShift(); 61 | 62 | // call this slot when a new character of input is available 63 | void onCharacterEntered(char c); 64 | 65 | // call this slot when enter is pressed. Does nothing if input is invalid else enters number on stack 66 | // and clears input 67 | void onEnter(); 68 | 69 | // call this slot to backspace during input entry 70 | void onBackspace(); 71 | 72 | // call this slot when plus/minus is entered 73 | void onPlusMinus(); 74 | 75 | // called when commands are entered 76 | void onCommandEntered(std::string primaryCmd, std::string secondaryCmd); 77 | 78 | signals: 79 | void modelChanged(); 80 | void commandEntered(std::string s); 81 | void errorDetected(std::string s); 82 | 83 | private: 84 | std::unique_ptr pimpl_; 85 | }; 86 | 87 | } 88 | #endif 89 | -------------------------------------------------------------------------------- /pdCalc/src/ui/gui/InputWidget.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef INPUT_WIDGET_H 20 | #define INPUT_WIDGET_H 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | class QGridLayout; 27 | 28 | namespace pdCalc { 29 | 30 | class InputWidget : public QWidget 31 | { 32 | class InputWidgetImpl; 33 | Q_OBJECT 34 | public: 35 | explicit InputWidget(QWidget *parent = nullptr); 36 | ~InputWidget(); 37 | 38 | void addCommandButton(const std::string& dispPrimaryCmd, const std::string& primaryCmd, 39 | const std::string& dispShftCmd, const std::string& shftCmd); 40 | 41 | void setupFinalButtons(); 42 | 43 | signals: 44 | void characterEntered(char c); 45 | void enterPressed(); 46 | void backspacePressed(); 47 | void plusMinusPressed(); 48 | void commandEntered(std::string, std::string); 49 | void shiftPressed(); 50 | void procedurePressed(); 51 | 52 | private: 53 | std::unique_ptr pimpl_; 54 | }; 55 | 56 | } 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /pdCalc/src/ui/gui/LookAndFeel.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "LookAndFeel.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | using std::string; 29 | 30 | namespace pdCalc { 31 | 32 | class LookAndFeel::LookAndFeelImpl 33 | { 34 | public: 35 | LookAndFeelImpl(); 36 | const QFont& getDisplayFont() const { return displayFont_; } 37 | const QFont& getButtonFont() const { return buttonFont_; } 38 | const QFont& getShiftLabelFont() const { return shiftLabelFont_; } 39 | const QFont& getStatusBarFont() const { return statusBarFont_; } 40 | 41 | const QSize& getMinimumButtonSize() const { return minButtonSize_; } 42 | const QSize& getMinimumShiftLabelSize() const { return minShiftLabelSize_; } 43 | const QPalette& getStatusBarPalette() const { return statusBarPalette_; } 44 | const QMargins& getContentsMargins() const { return contentsMargins_; } 45 | const string& getShiftColor() const { return shiftColor_; } 46 | 47 | private: 48 | void setupDisplayFont(); 49 | void setupButtonFont(); 50 | void setupShiftLabelFont(); 51 | void setupStatusBarMetrics(); 52 | void setupContentsMargins(); 53 | 54 | QFont displayFont_; 55 | QFont buttonFont_; 56 | QFont shiftLabelFont_; 57 | QFont statusBarFont_; 58 | QPalette statusBarPalette_; 59 | 60 | QSize minButtonSize_; 61 | QSize minShiftLabelSize_; 62 | 63 | QMargins contentsMargins_; 64 | 65 | unsigned int displayFontPtSize_; 66 | string shiftColor_; 67 | QString fixedWidthFont_; 68 | }; 69 | 70 | LookAndFeel::LookAndFeelImpl::LookAndFeelImpl() 71 | : displayFontPtSize_{14} 72 | , shiftColor_{"blue"} 73 | , fixedWidthFont_{"courier"} 74 | { 75 | setupDisplayFont(); 76 | setupButtonFont(); 77 | setupShiftLabelFont(); 78 | setupStatusBarMetrics(); 79 | setupContentsMargins(); 80 | } 81 | 82 | void LookAndFeel::LookAndFeelImpl::setupDisplayFont() 83 | { 84 | displayFont_.setFamily(fixedWidthFont_); 85 | displayFont_.setPointSize(displayFontPtSize_); 86 | 87 | return; 88 | } 89 | 90 | void LookAndFeel::LookAndFeelImpl::setupButtonFont() 91 | { 92 | buttonFont_.setFamily(fixedWidthFont_); 93 | buttonFont_.setPointSize(displayFontPtSize_ - 2); 94 | 95 | QFontMetrics fm{buttonFont_}; 96 | minButtonSize_.setHeight( 1.5 * fm.height() ); 97 | minButtonSize_.setWidth( 6 * fm.maxWidth() ); 98 | 99 | return; 100 | } 101 | 102 | void LookAndFeel::LookAndFeelImpl::setupShiftLabelFont() 103 | { 104 | shiftLabelFont_.setFamily(fixedWidthFont_); 105 | shiftLabelFont_.setPointSize(displayFontPtSize_ - 5); 106 | 107 | QFontMetrics fm{shiftLabelFont_}; 108 | minShiftLabelSize_.setHeight( 1.5 * fm.height() ); 109 | minShiftLabelSize_.setWidth( 6 * fm.maxWidth() ); 110 | return; 111 | } 112 | 113 | void LookAndFeel::LookAndFeelImpl::setupStatusBarMetrics() 114 | { 115 | statusBarFont_.setFamily(fixedWidthFont_); 116 | statusBarFont_.setPointSize(displayFontPtSize_ - 4); 117 | 118 | statusBarPalette_.setColor(QPalette::WindowText, QColor(QString::fromStdString(shiftColor_))); 119 | 120 | return; 121 | } 122 | 123 | void LookAndFeel::LookAndFeelImpl::setupContentsMargins() 124 | { 125 | contentsMargins_.setTop(1); 126 | contentsMargins_.setBottom(1); 127 | contentsMargins_.setLeft(1); 128 | contentsMargins_.setRight(1); 129 | 130 | return; 131 | } 132 | 133 | const LookAndFeel& LookAndFeel::Instance() 134 | { 135 | static LookAndFeel instance; 136 | return instance; 137 | } 138 | 139 | const QFont &LookAndFeel::getDisplayFont() const 140 | { 141 | return pimpl_->getDisplayFont(); 142 | } 143 | 144 | const QFont&LookAndFeel::getButtonFont() const 145 | { 146 | return pimpl_->getButtonFont(); 147 | } 148 | 149 | const QFont&LookAndFeel::getShiftLabelFont() const 150 | { 151 | return pimpl_->getShiftLabelFont(); 152 | } 153 | 154 | const QSize&LookAndFeel::getMinimumButtonSize() const 155 | { 156 | return pimpl_->getMinimumButtonSize(); 157 | } 158 | 159 | const QSize&LookAndFeel::getMinimumShiftLabelSize() const 160 | { 161 | return pimpl_->getMinimumShiftLabelSize(); 162 | } 163 | 164 | const QFont&LookAndFeel::getStatusBarFont() const 165 | { 166 | return pimpl_->getStatusBarFont(); 167 | } 168 | 169 | const QPalette&LookAndFeel::getStatusBarPalette() const 170 | { 171 | return pimpl_->getStatusBarPalette(); 172 | } 173 | 174 | const QMargins& LookAndFeel::getContentsMargins() const 175 | { 176 | return pimpl_->getContentsMargins(); 177 | } 178 | 179 | const std::string& LookAndFeel::getShiftColor() const 180 | { 181 | return pimpl_->getShiftColor(); 182 | } 183 | 184 | std::string LookAndFeel::getDisplayBackgroundColor() const 185 | { 186 | return "white"; 187 | } 188 | 189 | std::string LookAndFeel::getDisplayBorderStyle() const 190 | { 191 | return "1px solid gray"; 192 | } 193 | 194 | std::string LookAndFeel::getDisplayBorderRadius() const 195 | { 196 | return "6px"; 197 | } 198 | 199 | LookAndFeel::LookAndFeel() 200 | : pimpl_{ new LookAndFeelImpl } 201 | { } 202 | 203 | LookAndFeel::~LookAndFeel() 204 | { } 205 | 206 | } 207 | -------------------------------------------------------------------------------- /pdCalc/src/ui/gui/LookAndFeel.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef LOOK_AND_FEEL_H 20 | #define LOOK_AND_FEEL_H 21 | 22 | #include 23 | 24 | class QFont; 25 | class QSize; 26 | class QPalette; 27 | class QMargins; 28 | 29 | namespace pdCalc { 30 | 31 | // This is a singleton class that defines the metrics to be used by all 32 | // of the display. An example of such a metric would be a font family or 33 | // button size. 34 | 35 | class LookAndFeel 36 | { 37 | class LookAndFeelImpl; 38 | public: 39 | static const LookAndFeel& Instance(); 40 | 41 | // get the font that should be used by the display 42 | const QFont& getDisplayFont() const; 43 | 44 | // get the font that should be used by the buttons 45 | const QFont& getButtonFont() const; 46 | 47 | // get the font that should be used by the shift labels for the buttons 48 | const QFont& getShiftLabelFont() const; 49 | 50 | // get the minimum size of the buttons 51 | const QSize& getMinimumButtonSize() const; 52 | 53 | // get the minimum size of the shift label 54 | const QSize& getMinimumShiftLabelSize() const; 55 | 56 | // get the font that should be used for the status bar 57 | const QFont& getStatusBarFont() const; 58 | 59 | // get the palette for the status bar to enable color change of status bar text 60 | const QPalette& getStatusBarPalette() const; 61 | 62 | // get contents margins for layouts affecting button spacing 63 | const QMargins& getContentsMargins() const; 64 | 65 | // get the color of the shift label 66 | const std::string& getShiftColor() const; 67 | 68 | // get display background color 69 | std::string getDisplayBackgroundColor() const; 70 | 71 | // get display border style 72 | std::string getDisplayBorderStyle() const; 73 | 74 | // get display border radius 75 | std::string getDisplayBorderRadius() const; 76 | 77 | private: 78 | LookAndFeel(); 79 | ~LookAndFeel(); 80 | LookAndFeel(const LookAndFeel&) = delete; 81 | LookAndFeel& operator=(const LookAndFeel&) = delete; 82 | LookAndFeel(LookAndFeel&&) = delete; 83 | LookAndFeel& operator=(LookAndFeel&&) = delete; 84 | 85 | std::unique_ptr pimpl_; 86 | }; 87 | 88 | } 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /pdCalc/src/ui/gui/MainWindow.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "MainWindow.h" 20 | #include "Display.h" 21 | #include "InputWidget.h" 22 | #include 23 | #include 24 | #include "backend/Stack.h" 25 | #include 26 | #include 27 | #include 28 | #include "LookAndFeel.h" 29 | #include "StoredProcedureDialog.h" 30 | #include 31 | #include "GuiModel.h" 32 | 33 | using std::ostringstream; 34 | using std::cout; 35 | using std::endl; 36 | using std::string; 37 | using std::vector; 38 | 39 | namespace pdCalc { 40 | 41 | class MainWindow::MainWindowImpl : public QWidget 42 | { 43 | Q_OBJECT 44 | public: 45 | explicit MainWindowImpl(MainWindow* parent); 46 | void showMessage(const string& m); 47 | void stackChanged(); 48 | void setupFinalButtons(); 49 | void addCommandButton(const std::string& dispPrimaryCmd, const std::string& primaryCmd, const std::string& dispShftCmd, const std::string& shftCmd); 50 | 51 | public slots: 52 | void onCommandEntered(std::string cmd); 53 | void onShowMessage(std::string m); 54 | 55 | private slots: 56 | void onProcedure(); 57 | 58 | private: 59 | void connectInputToModel(); 60 | void doLayout(); 61 | 62 | MainWindow& parent_; 63 | int nLinesStack_; 64 | Display* display_; 65 | InputWidget* inputWidget_; 66 | GuiModel* guiModel_; 67 | }; 68 | 69 | MainWindow::MainWindowImpl::MainWindowImpl(MainWindow* parent) 70 | : QWidget{parent} 71 | , parent_(*parent) 72 | , nLinesStack_{6} 73 | { 74 | guiModel_ = new GuiModel{this}; 75 | display_ = new Display{*guiModel_, this, nLinesStack_}; 76 | 77 | connect(guiModel_, SIGNAL(modelChanged()), display_, SLOT(onModelChanged())); 78 | 79 | inputWidget_ = new InputWidget{this}; 80 | 81 | doLayout(); 82 | 83 | connectInputToModel(); 84 | } 85 | 86 | void MainWindow::MainWindowImpl::doLayout() 87 | { 88 | auto vblayout = new QVBoxLayout{this}; 89 | vblayout->addWidget(display_); 90 | vblayout->addWidget(inputWidget_); 91 | vblayout->addStretch(); 92 | } 93 | 94 | void MainWindow::MainWindowImpl::showMessage(const string& m) 95 | { 96 | display_->showMessage(m); 97 | 98 | return; 99 | } 100 | 101 | void MainWindow::MainWindowImpl::stackChanged() 102 | { 103 | auto v = Stack::Instance().getElements(nLinesStack_); 104 | guiModel_->stackChanged(v); 105 | 106 | return; 107 | } 108 | 109 | void MainWindow::MainWindowImpl::onProcedure() 110 | { 111 | StoredProcedureDialog dialog; 112 | if(dialog.exec() == QDialog::Accepted) 113 | { 114 | ostringstream oss; 115 | oss << "proc:" << dialog.getProcedure(); 116 | guiModel_->onCommandEntered(oss.str(), ""); 117 | } 118 | 119 | return; 120 | } 121 | 122 | void MainWindow::MainWindowImpl::connectInputToModel() 123 | { 124 | connect(inputWidget_, SIGNAL(backspacePressed()), guiModel_, SLOT(onBackspace())); 125 | connect(inputWidget_, SIGNAL(enterPressed()), guiModel_, SLOT(onEnter())); 126 | connect(inputWidget_, SIGNAL(characterEntered(char)), guiModel_, SLOT(onCharacterEntered(char))); 127 | connect(inputWidget_, SIGNAL(plusMinusPressed()), guiModel_, SLOT(onPlusMinus())); 128 | connect(inputWidget_, SIGNAL(commandEntered(std::string,std::string)), guiModel_, SLOT(onCommandEntered(std::string, std::string))); 129 | connect(inputWidget_, SIGNAL(procedurePressed()), this, SLOT(onProcedure())); 130 | connect(inputWidget_, SIGNAL(shiftPressed()), guiModel_, SLOT(onShift())); 131 | connect(guiModel_, SIGNAL(commandEntered(std::string)), this, SLOT(onCommandEntered(std::string))); 132 | connect(guiModel_, SIGNAL(errorDetected(std::string)), this, SLOT(onShowMessage(std::string))); 133 | 134 | return; 135 | } 136 | 137 | void MainWindow::MainWindowImpl::setupFinalButtons() 138 | { 139 | inputWidget_->setupFinalButtons(); 140 | } 141 | 142 | void MainWindow::MainWindowImpl::addCommandButton(const string& dispPrimaryCmd, const string& primaryCmd, 143 | const string& dispShftCmd, const string& shftCmd) 144 | { 145 | inputWidget_->addCommandButton(dispPrimaryCmd, primaryCmd, dispShftCmd, shftCmd); 146 | 147 | return; 148 | } 149 | 150 | void MainWindow::MainWindowImpl::onCommandEntered(std::string cmd) 151 | { 152 | parent_.UserInterface::raise(UserInterface::CommandEntered, std::make_shared(cmd)); 153 | 154 | return; 155 | } 156 | 157 | void MainWindow::MainWindowImpl::onShowMessage(std::string m) 158 | { 159 | showMessage(m); 160 | } 161 | 162 | MainWindow::MainWindow(int, char*[], QWidget* parent) 163 | : QMainWindow{parent} 164 | { 165 | pimpl_ = new MainWindowImpl{this}; 166 | setCentralWidget(pimpl_); 167 | } 168 | 169 | void MainWindow::postMessage(const std::string& m) 170 | { 171 | pimpl_->showMessage(m); 172 | 173 | return; 174 | } 175 | 176 | void MainWindow::stackChanged() 177 | { 178 | pimpl_->stackChanged(); 179 | } 180 | 181 | void MainWindow::addCommandButton(const string& dispPrimaryCmd, const string& primaryCmd, 182 | const string& dispShftCmd, const string& shftCmd) 183 | { 184 | pimpl_->addCommandButton(dispPrimaryCmd, primaryCmd, dispShftCmd, shftCmd); 185 | } 186 | 187 | void MainWindow::setupFinalButtons() 188 | { 189 | pimpl_->setupFinalButtons(); 190 | 191 | return; 192 | } 193 | 194 | void MainWindow::fixSize() 195 | { 196 | setFixedSize( size() ); 197 | } 198 | 199 | } 200 | 201 | #include "MainWindow.moc" 202 | -------------------------------------------------------------------------------- /pdCalc/src/ui/gui/MainWindow.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef MAIN_WINDOW_H 20 | #define MAIN_WINDOW_H 21 | 22 | #include 23 | #include "utilities/UserInterface.h" 24 | #include 25 | 26 | namespace pdCalc { 27 | 28 | class CommandButton; 29 | 30 | class MainWindow : public QMainWindow, public UserInterface 31 | { 32 | class MainWindowImpl; 33 | public: 34 | MainWindow(int argc, char* argv[], QWidget* parent = nullptr); 35 | 36 | void postMessage(const std::string& m) override; 37 | void stackChanged() override; 38 | 39 | // Add a command button, for example, from a plugin 40 | // Buttons are added in order from left to right just below the 41 | // line undo, redo, proc from the bottom up 42 | // Buttons are reparented to MainWindow 43 | void addCommandButton(const std::string& dispPrimaryCmd, const std::string& primaryCmd, const std::string& dispShftCmd, const std::string& shftCmd); 44 | 45 | // setup the undo, redo, proc buttons after inserting plugin buttons 46 | void setupFinalButtons(); 47 | 48 | // force the window to be fixed size...should be called as a final step once the GUI has fixed its own size 49 | void fixSize(); 50 | 51 | private: 52 | MainWindowImpl* pimpl_; 53 | }; 54 | 55 | } 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /pdCalc/src/ui/gui/StoredProcedureDialog.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "StoredProcedureDialog.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | namespace pdCalc { 28 | 29 | StoredProcedureDialog::StoredProcedureDialog(QWidget *parent) 30 | : QDialog{parent} 31 | { 32 | auto layout = new QVBoxLayout{this}; 33 | 34 | auto label = new QLabel{"Enter procedure name:", this}; 35 | layout->addWidget(label); 36 | 37 | comboBox_ = new QComboBox{this}; 38 | comboBox_->setEditable(true); 39 | comboBox_->setMinimumWidth(200); 40 | layout->addWidget(comboBox_); 41 | 42 | populateComboBox(); 43 | 44 | auto buttonBox = new QDialogButtonBox{QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this}; 45 | connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); 46 | connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); 47 | layout->addWidget(buttonBox); 48 | 49 | setWindowTitle("Procedure"); 50 | } 51 | 52 | std::string StoredProcedureDialog::getProcedure() const 53 | { 54 | return comboBox_->currentText().toStdString(); 55 | } 56 | 57 | void StoredProcedureDialog::populateComboBox() 58 | { 59 | // display all names in current directory with extension of .psp (pdCalc stored procedure) 60 | QDir dir{"."}; 61 | dir.setFilter(QDir::Files); 62 | QStringList lst; 63 | lst << "*.psp"; 64 | dir.setNameFilters(lst); 65 | 66 | comboBox_->addItems( dir.entryList() ); 67 | 68 | return; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /pdCalc/src/ui/gui/StoredProcedureDialog.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef STORED_PROCEDURE_DIALOG_H 20 | #define STORED_PROCEDURE_DIALOG_H 21 | 22 | #include 23 | #include 24 | 25 | class QComboBox; 26 | 27 | namespace pdCalc { 28 | 29 | class StoredProcedureDialog : public QDialog 30 | { 31 | Q_OBJECT 32 | public: 33 | explicit StoredProcedureDialog(QWidget* parent = nullptr); 34 | std::string getProcedure() const; 35 | 36 | private: 37 | void populateComboBox(); 38 | 39 | QComboBox* comboBox_; 40 | }; 41 | 42 | } 43 | #endif 44 | -------------------------------------------------------------------------------- /pdCalc/src/ui/gui/gui.pro: -------------------------------------------------------------------------------- 1 | HOME = ../../.. 2 | include ($$HOME/common.pri) 3 | TEMPLATE = lib 4 | TARGET = pdCalcGui 5 | DEPENDPATH += . 6 | INCLUDEPATH += . $$HOME/src 7 | unix:DESTDIR = $$HOME/lib 8 | win32:DESTDIR = $$HOME/bin 9 | 10 | QT += widgets 11 | 12 | # Input 13 | HEADERS += MainWindow.h \ 14 | Display.h \ 15 | LookAndFeel.h \ 16 | InputWidget.h \ 17 | CommandButton.h \ 18 | StoredProcedureDialog.h \ 19 | GuiModel.h 20 | 21 | SOURCES += MainWindow.cpp \ 22 | Display.cpp \ 23 | LookAndFeel.cpp \ 24 | InputWidget.cpp \ 25 | CommandButton.cpp \ 26 | StoredProcedureDialog.cpp \ 27 | GuiModel.cpp 28 | 29 | win32:LIBS += -L$$HOME/bin -lpdCalcUtilities1 -lpdCalcBackend1 30 | -------------------------------------------------------------------------------- /pdCalc/src/utilities/Exception.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef EXCEPTION_H 20 | #define EXCEPTION_H 21 | 22 | // Simple exception class to be used throughout PdCalc. It can be instantiated with a message, 23 | // and that message can be returned. 24 | 25 | #include 26 | 27 | namespace pdCalc { 28 | 29 | class Exception 30 | { 31 | public: 32 | explicit Exception(const std::string& msg) : msg_(msg) { } 33 | const std::string& what() const { return msg_; } 34 | 35 | private: 36 | std::string msg_; 37 | }; 38 | 39 | } 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /pdCalc/src/utilities/Observer.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "Observer.h" 20 | #include "Publisher.h" 21 | 22 | using std::shared_ptr; 23 | #include 24 | 25 | namespace pdCalc { 26 | 27 | Observer::Observer(const std::string& name) 28 | : observerName_{name} 29 | { } 30 | 31 | Observer::~Observer() 32 | { 33 | 34 | } 35 | 36 | void Observer::notify(std::shared_ptr d) 37 | { 38 | notifyImpl(d); 39 | return; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /pdCalc/src/utilities/Observer.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef OBSERVER_H 20 | #define OBSERVER_H 21 | 22 | // The Observer class serves as the base class for all observer objects. The Observer class 23 | // is a mediator between the Publisher and the actual class that performs the observation. 24 | // A concrete observer should inherit from observer and contain a pointer to the actual observing 25 | // object. This decouples the observing object from knowing about publishers. Note that publishers 26 | // call Observer's notify, which must be implemented in the concrete observer to respond to event 27 | // notifications. 28 | 29 | // Note that the semantics of Publisher to to own the Observer uniquely (enforced by std::unique_ptr) 30 | 31 | #include 32 | #include 33 | 34 | namespace pdCalc { 35 | 36 | class EventData; 37 | 38 | class Observer 39 | { 40 | public: 41 | explicit Observer(const std::string& name); 42 | virtual ~Observer(); 43 | 44 | void notify(std::shared_ptr); 45 | 46 | const std::string name() const { return observerName_; } 47 | 48 | private: 49 | virtual void notifyImpl(std::shared_ptr) = 0; 50 | 51 | std::string observerName_; 52 | }; 53 | 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /pdCalc/src/utilities/Publisher.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "Publisher.h" 20 | #include "Observer.h" 21 | #include "Exception.h" 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | using std::string; 28 | using std::vector; 29 | using std::set; 30 | using std::ostringstream; 31 | using std::unique_ptr; 32 | using std::shared_ptr; 33 | 34 | namespace pdCalc { 35 | 36 | class Publisher::PublisherImpl 37 | { 38 | using ObserversList = std::unordered_map>; 39 | using Events = std::unordered_map; 40 | 41 | public: 42 | PublisherImpl(); 43 | ~PublisherImpl(); 44 | 45 | void attach(const string& eventName, unique_ptr observer); 46 | unique_ptr detach(const string& eventName, const string& observer); 47 | void notify(const string& eventName, shared_ptr d) const; 48 | void registerEvent(const string& eventName); 49 | void registerEvents(const vector& eventNames); 50 | set listEvents() const; 51 | set listEventObservers(const string& eventName) const; 52 | 53 | Events::const_iterator findCheckedEvent(const string& eventName) const; 54 | Events::iterator findCheckedEvent(const string& eventName); 55 | 56 | private: 57 | Events events_; 58 | }; 59 | 60 | Publisher::PublisherImpl::PublisherImpl() 61 | { } 62 | 63 | Publisher::PublisherImpl::~PublisherImpl() 64 | { 65 | 66 | } 67 | 68 | Publisher::PublisherImpl::Events::const_iterator Publisher::PublisherImpl::findCheckedEvent(const string& eventName) const 69 | { 70 | auto ev = events_.find(eventName); 71 | if( ev == events_.end() ) 72 | { 73 | ostringstream oss; 74 | oss << "Publisher does not support event '" << eventName << "'"; 75 | throw Exception{ oss.str() }; 76 | } 77 | 78 | return ev; 79 | } 80 | 81 | Publisher::PublisherImpl::Events::iterator Publisher::PublisherImpl::findCheckedEvent(const string &eventName) 82 | { 83 | auto ev = events_.find(eventName); 84 | if( ev == events_.end() ) 85 | { 86 | ostringstream oss; 87 | oss << "Publisher does not support event '" << eventName << "'"; 88 | throw Exception( oss.str() ); 89 | } 90 | 91 | return ev; 92 | } 93 | 94 | void Publisher::PublisherImpl::attach(const string& eventName, unique_ptr observer) 95 | { 96 | auto ev = findCheckedEvent(eventName); 97 | auto& obsList = ev->second; 98 | 99 | auto obs = obsList.find(observer->name()); 100 | if( obs != obsList.end() ) 101 | throw Exception("Observer already attached to publisher"); 102 | 103 | obsList.insert( std::make_pair(observer->name(), std::move(observer)) ); 104 | 105 | return; 106 | } 107 | 108 | unique_ptr Publisher::PublisherImpl::detach(const string& eventName, const string& observer) 109 | { 110 | auto ev = findCheckedEvent(eventName); 111 | auto& obsList = ev->second; 112 | 113 | auto obs = obsList.find(observer); 114 | if( obs == obsList.end() ) 115 | throw Exception("Cannot detach observer because observer not found"); 116 | 117 | auto tmp = std::move(obs->second); 118 | obsList.erase(obs); 119 | 120 | return tmp; 121 | } 122 | 123 | void Publisher::PublisherImpl::notify(const string& eventName, shared_ptr d) const 124 | { 125 | auto ev = findCheckedEvent(eventName); 126 | const auto& obsList = ev->second; 127 | 128 | for(const auto& obs : obsList) 129 | obs.second->notify(d); 130 | 131 | return; 132 | } 133 | 134 | void Publisher::PublisherImpl::registerEvent(const string& eventName) 135 | { 136 | auto i = events_.find(eventName); 137 | if( i != events_.end() ) 138 | throw Exception{"Event already registered"}; 139 | 140 | events_[eventName] = ObserversList{}; 141 | 142 | return; 143 | } 144 | 145 | void Publisher::PublisherImpl::registerEvents(const vector& eventNames) 146 | { 147 | for(auto i : eventNames) 148 | registerEvent(i); 149 | 150 | return; 151 | } 152 | 153 | set Publisher::PublisherImpl::listEvents() const 154 | { 155 | set tmp; 156 | for(const auto& i : events_) 157 | tmp.insert(i.first); 158 | 159 | 160 | return tmp; 161 | } 162 | 163 | set Publisher::PublisherImpl::listEventObservers(const string& eventName) const 164 | { 165 | auto ev = findCheckedEvent(eventName); 166 | 167 | set tmp; 168 | for(const auto& kvp : ev->second) 169 | tmp.insert(kvp.first); 170 | 171 | return tmp; 172 | } 173 | 174 | Publisher::Publisher() 175 | { 176 | publisherImpl_ = std::make_unique(); 177 | } 178 | 179 | Publisher::~Publisher() 180 | { 181 | // std::unique_ptr requires a definition of the destructor instead 182 | // of using the default because the destructor must appear in a scope 183 | // in which the complete definition of the template argument for 184 | // std::unique_ptr is known 185 | } 186 | 187 | void Publisher::attach(const string& eventName, unique_ptr observer) 188 | { 189 | publisherImpl_->attach(eventName, std::move(observer)); 190 | 191 | return; 192 | } 193 | 194 | unique_ptr Publisher::detach(const string& eventName, const string& observer) 195 | { 196 | return publisherImpl_->detach(eventName, observer); 197 | } 198 | 199 | void Publisher::raise(const string& eventName, std::shared_ptr d) const 200 | { 201 | publisherImpl_->notify(eventName, d); 202 | return; 203 | } 204 | 205 | void Publisher::registerEvent(const string& eventName) 206 | { 207 | publisherImpl_->registerEvent(eventName); 208 | return; 209 | } 210 | 211 | void Publisher::registerEvents(const vector& eventNames) 212 | { 213 | publisherImpl_->registerEvents(eventNames); 214 | return; 215 | } 216 | 217 | set Publisher::listEvents() const 218 | { 219 | return publisherImpl_->listEvents(); 220 | } 221 | 222 | set Publisher::listEventObservers(const string& eventName) const 223 | { 224 | return publisherImpl_->listEventObservers(eventName); 225 | } 226 | 227 | EventData::~EventData() 228 | { 229 | 230 | } 231 | 232 | } 233 | 234 | 235 | -------------------------------------------------------------------------------- /pdCalc/src/utilities/Publisher.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef PUBLISHER_H 20 | #define PUBLISHER_H 21 | 22 | // The Publisher class is a class capable of receiving observers. Note that it is assumed 23 | // that a real publisher may publish multiple separate events. These are stored by string 24 | // name in a table. Since each event may have multiple observers, the table stores 25 | // a collection of observers. 26 | 27 | // Important: Publishers own the memory for their observers (enforced by std::unique_ptr) 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | namespace pdCalc { 35 | 36 | class Observer; 37 | 38 | class EventData 39 | { 40 | public: 41 | virtual ~EventData(); 42 | }; 43 | 44 | class Publisher 45 | { 46 | class PublisherImpl; 47 | public: 48 | Publisher(); 49 | 50 | void attach(const std::string& eventName, std::unique_ptr observer); 51 | std::unique_ptr detach(const std::string& eventName, const std::string& observerName); 52 | 53 | std::set listEvents() const; 54 | std::set listEventObservers(const std::string& eventName) const; 55 | 56 | protected: 57 | ~Publisher(); 58 | 59 | void raise(const std::string& eventName, std::shared_ptr) const; 60 | 61 | void registerEvent(const std::string& eventName); 62 | void registerEvents(const std::vector& eventNames); 63 | 64 | private: 65 | std::unique_ptr publisherImpl_; 66 | }; 67 | 68 | } 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /pdCalc/src/utilities/Tokenizer.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "Tokenizer.h" 20 | #include 21 | #include 22 | #include 23 | 24 | using std::string; 25 | using std::istringstream; 26 | using std::istream_iterator; 27 | 28 | namespace pdCalc { 29 | 30 | Tokenizer::Tokenizer(const string& s) 31 | { 32 | istringstream iss{s}; 33 | 34 | tokenize(iss); 35 | } 36 | 37 | Tokenizer::Tokenizer(std::istream& is) 38 | { 39 | tokenize(is); 40 | } 41 | 42 | 43 | Tokenizer::~Tokenizer() 44 | { } 45 | 46 | void Tokenizer::tokenize(std::istream& is) 47 | { 48 | tokens_.assign( istream_iterator{is}, istream_iterator{}); 49 | 50 | for(auto& i : tokens_) 51 | std::transform(i.begin(), i.end(), i.begin(), ::tolower); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /pdCalc/src/utilities/Tokenizer.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef TOKENIZER_H 20 | #define TOKENIZER_H 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | namespace pdCalc { 27 | 28 | class Tokenizer 29 | { 30 | public: 31 | using Token = std::string; 32 | using Tokens = std::vector; 33 | using const_iterator = Tokens::const_iterator; 34 | 35 | explicit Tokenizer(const std::string&); 36 | explicit Tokenizer(std::istream&); 37 | ~Tokenizer(); 38 | 39 | size_t nTokens() const { return tokens_.size(); } 40 | 41 | const_iterator begin() const { return tokens_.begin(); } 42 | const_iterator end() const { return tokens_.end(); } 43 | 44 | const Token& operator[](size_t i) const { return tokens_[i]; } 45 | 46 | private: 47 | void tokenize(std::istream&); 48 | 49 | Tokenizer() = delete; 50 | Tokenizer(const Tokenizer&) = delete; 51 | Tokenizer(Tokenizer&&) = delete; 52 | Tokenizer& operator=(const Tokenizer&) = delete; 53 | Tokenizer& operator=(Tokenizer&&) = delete; 54 | 55 | Tokens tokens_; 56 | }; 57 | 58 | } 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /pdCalc/src/utilities/UserInterface.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "UserInterface.h" 20 | const std::string pdCalc::UserInterface::CommandEntered = "CommandIssued"; 21 | -------------------------------------------------------------------------------- /pdCalc/src/utilities/UserInterface.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef USER_INTERFACE_H 20 | #define USER_INTERFACE_H 21 | 22 | #include 23 | #include "Publisher.h" 24 | 25 | namespace pdCalc { 26 | 27 | class CommandData : public EventData 28 | { 29 | public: 30 | CommandData(const std::string& s) : command_(s) { } 31 | const std::string& command() const { return command_; } 32 | 33 | private: 34 | std::string command_; 35 | }; 36 | 37 | class UserInterface : protected Publisher 38 | { 39 | public: 40 | UserInterface() { registerEvent(CommandEntered); } 41 | virtual ~UserInterface() { } 42 | 43 | // post a message to the user 44 | virtual void postMessage(const std::string& m) = 0; 45 | 46 | // notifies the interface that the stack has changed 47 | virtual void stackChanged() = 0; 48 | 49 | using Publisher::attach; 50 | using Publisher::detach; 51 | 52 | // defines the event this publisher can raise 53 | // note that the string is defined in main.cpp of the application since 54 | // class UserInterface has no implementation file (in test driver for same 55 | // reason) 56 | static const std::string CommandEntered; 57 | }; 58 | 59 | } 60 | #endif 61 | -------------------------------------------------------------------------------- /pdCalc/src/utilities/utilities.pro: -------------------------------------------------------------------------------- 1 | HOME = ../.. 2 | include ($$HOME/common.pri) 3 | TEMPLATE = lib 4 | TARGET = pdCalcUtilities 5 | DEPENDPATH += . 6 | INCLUDEPATH += . $$HOME/src 7 | unix:DESTDIR = $$HOME/lib 8 | win32:DESTDIR = $$HOME/bin 9 | 10 | DEFINES += BUILDING_UTILITIES 11 | 12 | # Input 13 | HEADERS += Exception.h \ 14 | Observer.h \ 15 | Publisher.h \ 16 | Tokenizer.h \ 17 | UserInterface.h 18 | 19 | SOURCES += Observer.cpp \ 20 | Publisher.cpp \ 21 | Tokenizer.cpp \ 22 | UserInterface.cpp 23 | 24 | OTHER_FILES += \ 25 | Publisher.o \ 26 | Observer.o \ 27 | Makefile 28 | -------------------------------------------------------------------------------- /pdCalc/test/backendTest/CommandDispatcherTest.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "CommandDispatcherTest.h" 20 | #include "src/utilities/UserInterface.h" 21 | #include "src/backend/CoreCommands.h" 22 | #include "src/backend/CommandDispatcher.h" 23 | #include "src/backend/CommandRepository.h" 24 | #include "src/backend/Stack.h" 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | using std::cout; 31 | using std::endl; 32 | using std::vector; 33 | using std::ostringstream; 34 | using std::string; 35 | 36 | namespace { 37 | 38 | class TestInterface : public pdCalc::UserInterface 39 | { 40 | public: 41 | TestInterface() : lastMessage_{""} { } 42 | void postMessage(const string& m) override { lastMessage_ = m; } 43 | void stackChanged() override { } 44 | const string& getLastMessage() const { return lastMessage_; } 45 | 46 | double top() const; 47 | 48 | private: 49 | string lastMessage_; 50 | }; 51 | 52 | double TestInterface::top() const 53 | { 54 | vector v{ pdCalc::Stack::Instance().getElements(1) }; 55 | return v.back(); 56 | } 57 | 58 | } 59 | 60 | void CommandDispatcherTest::testCommandDispatcher() 61 | { 62 | pdCalc::CommandRepository::Instance().clearAllCommands(); 63 | pdCalc::Stack::Instance().clear(); 64 | TestInterface ui; 65 | pdCalc::CommandDispatcher ce{ui}; 66 | 67 | ce.commandEntered("+"); 68 | QCOMPARE(ui.getLastMessage(), string{"Command + is not a known command"}); 69 | 70 | pdCalc::RegisterCoreCommands(ui); 71 | 72 | ce.commandEntered("+"); 73 | 74 | QCOMPARE(ui.getLastMessage(), string{"Stack must have 2 elements"}); 75 | 76 | ce.commandEntered("1.0"); 77 | ce.commandEntered("2.0"); 78 | 79 | ce.commandEntered("+"); 80 | 81 | QCOMPARE( ui.top(), 3.0 ); 82 | 83 | ce.commandEntered("-18.3"); 84 | ce.commandEntered("swap"); 85 | QCOMPARE( ui.top(), 3.0 ); 86 | 87 | ce.commandEntered("drop"); 88 | QCOMPARE( ui.top(), -18.3); 89 | 90 | ce.commandEntered("22"); 91 | ce.commandEntered("undo"); 92 | QCOMPARE( ui.top(), -18.3); 93 | 94 | ce.commandEntered("undo"); 95 | QCOMPARE(ui.top(), 3.0); 96 | 97 | ce.commandEntered("redo"); 98 | QCOMPARE(ui.top(), -18.3); 99 | 100 | ce.commandEntered("undo"); 101 | ce.commandEntered("-"); 102 | QCOMPARE(ui.top(), -21.3); 103 | 104 | ce.commandEntered("neg"); 105 | QCOMPARE(ui.top(), 21.3); 106 | 107 | ce.commandEntered("7.1"); 108 | ce.commandEntered("/"); 109 | QCOMPARE(ui.top(), 21.3 / 7.1 ); 110 | 111 | ce.commandEntered("6"); 112 | ce.commandEntered("2"); 113 | ce.commandEntered("pow"); 114 | QCOMPARE(ui.top(), 36.0); 115 | 116 | ce.commandEntered("27"); 117 | ce.commandEntered("3"); 118 | ce.commandEntered("root"); 119 | QCOMPARE(ui.top(), 3.0); 120 | 121 | ce.commandEntered("*");; 122 | QCOMPARE(ui.top(), 108.0); 123 | 124 | ce.commandEntered("0.8"); 125 | ce.commandEntered("sin"); 126 | QCOMPARE(ui.top(), std::sin(0.8)); 127 | 128 | ce.commandEntered("dup"); 129 | ce.commandEntered("arcsin"); 130 | ce.commandEntered("swap"); 131 | double t = ui.top(); 132 | ce.commandEntered("drop"); 133 | QVERIFY(std::abs(ui.top() - std::asin(t)) < 1e-10); 134 | 135 | ce.commandEntered("0.7"); 136 | ce.commandEntered("cos"); 137 | QCOMPARE(ui.top(), std::cos(0.7)); 138 | 139 | ce.commandEntered("dup"); 140 | ce.commandEntered("arccos"); 141 | ce.commandEntered("swap"); 142 | t = ui.top(); 143 | ce.commandEntered("drop"); 144 | QVERIFY(std::abs(ui.top() - std::acos(t)) < 1e-10); 145 | 146 | ce.commandEntered("0.3"); 147 | ce.commandEntered("tan"); 148 | QCOMPARE(ui.top(), std::tan(0.3)); 149 | 150 | ce.commandEntered("dup"); 151 | ce.commandEntered("arctan"); 152 | ce.commandEntered("swap"); 153 | t = ui.top(); 154 | ce.commandEntered("drop"); 155 | QVERIFY(std::abs(ui.top() - std::atan(t)) < 1e-10); 156 | 157 | return; 158 | } 159 | 160 | -------------------------------------------------------------------------------- /pdCalc/test/backendTest/CommandDispatcherTest.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef COMMAND_DISPATCHER_TEST_H 20 | #define COMMAND_DISPATCHER_TEST_H 21 | 22 | #include 23 | 24 | namespace pdCalc { 25 | class Stack; 26 | class Command; 27 | } 28 | 29 | class CommandDispatcherTest : public QObject 30 | { 31 | Q_OBJECT 32 | 33 | private slots: 34 | void testCommandDispatcher(); 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /pdCalc/test/backendTest/CommandManagerTest.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef COMMAND_MANAGER_TEST_H 20 | #define COMMAND_MANAGER_TEST_H 21 | 22 | #include 23 | #include "backend/CommandManager.h" 24 | 25 | class CommandManagerTest : public QObject 26 | { 27 | Q_OBJECT 28 | private slots: 29 | void testExecuteStackStrategy(); 30 | void testUndoStackStrategy(); 31 | void testRedoStackStrategy(); 32 | void testRedoStackFlushStackStrategy(); 33 | void testResourceCleanupStackStrategy(); 34 | void ignoreErrorStackStrategy(); 35 | 36 | void testExecuteListStrategy(); 37 | void testUndoListStrategy(); 38 | void testRedoListStrategy(); 39 | void testRedoStackFlushListStrategy(); 40 | void testResourceCleanupListStrategy(); 41 | void ignoreErrorListStrategy(); 42 | 43 | void testExecuteListStrategyVector(); 44 | void testUndoListStrategyVector(); 45 | void testRedoListStrategyVector(); 46 | void testRedoStackFlushListStrategyVector(); 47 | void testResourceCleanupListStrategyVector(); 48 | void ignoreErrorListStrategyVector(); 49 | 50 | private: 51 | void testExecute(pdCalc::CommandManager::UndoRedoStrategy); 52 | void testUndo(pdCalc::CommandManager::UndoRedoStrategy); 53 | void testRedo(pdCalc::CommandManager::UndoRedoStrategy); 54 | void testRedoStackFlush(pdCalc::CommandManager::UndoRedoStrategy); 55 | void testResourceCleanup(pdCalc::CommandManager::UndoRedoStrategy); 56 | void ignoreError(pdCalc::CommandManager::UndoRedoStrategy); 57 | }; 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /pdCalc/test/backendTest/CommandRepositoryTest.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "CommandRepositoryTest.h" 20 | #include "src/backend/Command.h" 21 | #include "src/backend/CommandRepository.h" 22 | #include "src/utilities/Exception.h" 23 | #include 24 | 25 | using std::ostringstream; 26 | using std::set; 27 | using std::string; 28 | 29 | namespace { 30 | 31 | class TestCommand : public pdCalc::Command 32 | { 33 | public: 34 | TestCommand(const string& optionalName = ""); 35 | TestCommand(const TestCommand&); 36 | 37 | const string& getOptionalName() const { return optionalName_; } 38 | 39 | private: 40 | void executeImpl() noexcept override { } 41 | void undoImpl() noexcept override { } 42 | TestCommand* cloneImpl() const noexcept override; 43 | const char* helpMessageImpl() const noexcept override { return ""; } 44 | 45 | private: 46 | string optionalName_; 47 | }; 48 | 49 | TestCommand::TestCommand(const string& n) 50 | : Command{} 51 | , optionalName_{n} 52 | { 53 | 54 | } 55 | 56 | TestCommand::TestCommand(const TestCommand& rhs) 57 | : Command{rhs} 58 | , optionalName_{rhs.optionalName_} 59 | { 60 | 61 | } 62 | 63 | TestCommand* TestCommand::cloneImpl() const noexcept 64 | { 65 | return new TestCommand{*this}; 66 | } 67 | 68 | } 69 | 70 | void CommandRepositoryTest::testRegister() 71 | { 72 | pdCalc::CommandRepository& cf = pdCalc::CommandRepository::Instance(); 73 | cf.clearAllCommands(); 74 | 75 | string name1 = "command 1"; 76 | string name2 = "command 2"; 77 | set names = { name1, name2 }; 78 | 79 | cf.registerCommand( name1, pdCalc::MakeCommandPtr() ); 80 | cf.registerCommand( name2, pdCalc::MakeCommandPtr() ); 81 | 82 | QVERIFY( cf.getNumberCommands() == 2 ); 83 | 84 | set registeredCommands = cf.getAllCommandNames(); 85 | 86 | QCOMPARE( registeredCommands, names ); 87 | 88 | QCOMPARE( cf.hasKey(name1), true ); 89 | QCOMPARE( cf.hasKey(name2), true ); 90 | QCOMPARE( cf.hasKey("not present"), false ); 91 | 92 | return; 93 | } 94 | 95 | void CommandRepositoryTest::testDuplicateRegister() 96 | { 97 | pdCalc::CommandRepository& cf = pdCalc::CommandRepository::Instance(); 98 | cf.clearAllCommands(); 99 | 100 | string name = "command"; 101 | 102 | cf.registerCommand( name, pdCalc::MakeCommandPtr() ); 103 | 104 | QVERIFY( cf.getNumberCommands() == 1 ); 105 | 106 | try 107 | { 108 | cf.registerCommand( name, pdCalc::MakeCommandPtr() ); 109 | QVERIFY( false ); 110 | } 111 | catch(pdCalc::Exception& e) 112 | { 113 | ostringstream oss; 114 | oss << "Command " << name << " already registered"; 115 | QCOMPARE( e.what(), oss.str() ); 116 | } 117 | 118 | QVERIFY( cf.getNumberCommands() == 1 ); 119 | 120 | return; 121 | } 122 | 123 | void CommandRepositoryTest::testDeregister() 124 | { 125 | pdCalc::CommandRepository& cf = pdCalc::CommandRepository::Instance(); 126 | cf.clearAllCommands(); 127 | 128 | string name1 = "command 1"; 129 | string name2 = "command 2"; 130 | 131 | cf.registerCommand( name1, pdCalc::MakeCommandPtr() ); 132 | cf.registerCommand( name2, pdCalc::MakeCommandPtr() ); 133 | 134 | QVERIFY( cf.getNumberCommands() == 2 ); 135 | 136 | pdCalc::CommandPtr command = cf.deregisterCommand( name1 ); 137 | 138 | QVERIFY( command != nullptr ); 139 | QVERIFY( cf.getNumberCommands() == 1 ); 140 | QCOMPARE( cf.hasKey(name1), false ); 141 | QCOMPARE( cf.hasKey(name2), true ); 142 | 143 | command = cf.deregisterCommand( "not present" ); 144 | 145 | QVERIFY( command == nullptr ); 146 | QVERIFY( cf.getNumberCommands() == 1 ); 147 | QCOMPARE( cf.hasKey(name1), false ); 148 | QCOMPARE( cf.hasKey(name2), true ); 149 | 150 | return; 151 | } 152 | 153 | void CommandRepositoryTest::testAllocateCommand() 154 | { 155 | pdCalc::CommandRepository& cf = pdCalc::CommandRepository::Instance(); 156 | cf.clearAllCommands(); 157 | 158 | string name = "command"; 159 | 160 | cf.registerCommand( name, pdCalc::MakeCommandPtr(name) ); 161 | 162 | QVERIFY( cf.getNumberCommands() == 1 ); 163 | QCOMPARE( cf.hasKey(name), true ); 164 | 165 | pdCalc::CommandPtr clone = cf.allocateCommand(name); 166 | 167 | QVERIFY( cf.getNumberCommands() == 1 ); 168 | QCOMPARE( cf.hasKey(name), true ); 169 | QVERIFY( clone != nullptr ); 170 | TestCommand* testCommand = dynamic_cast( clone.get() ); 171 | QVERIFY( testCommand != nullptr ); 172 | QCOMPARE( testCommand->getOptionalName(), name ); 173 | 174 | clone = cf.allocateCommand("not present"); 175 | 176 | QVERIFY( clone == nullptr ); 177 | 178 | return; 179 | } 180 | -------------------------------------------------------------------------------- /pdCalc/test/backendTest/CommandRepositoryTest.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef COMMAND_FACTORY_TEST_H 20 | #define COMMAND_FACTORY_TEST_H 21 | 22 | #include 23 | 24 | class CommandRepositoryTest : public QObject 25 | { 26 | Q_OBJECT 27 | 28 | private slots: 29 | void testRegister(); 30 | void testDuplicateRegister(); 31 | void testDeregister(); 32 | void testAllocateCommand(); 33 | }; 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /pdCalc/test/backendTest/CoreCommandsTest.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef CORE_COMMANDS_TEST_H 20 | #define CORE_COMMANDS_TEST_H 21 | 22 | #include 23 | 24 | namespace pdCalc { 25 | class Stack; 26 | class Command; 27 | } 28 | 29 | class CoreCommandsTest : public QObject 30 | { 31 | Q_OBJECT 32 | 33 | private slots: 34 | void init(); 35 | void cleanup(); 36 | 37 | void testEnterNumber(); 38 | void testEnterNumberClone(); 39 | void testSwapTopOfStackPreconditions(); 40 | void testSwapTopOfStackClone(); 41 | void testSwapTopOfStack(); 42 | void testDropTopOfStackPreconditions(); 43 | void testDropTopOfStackClone(); 44 | void testDropTopOfStack(); 45 | void testClearStackClone(); 46 | void testClearStack(); 47 | void testAddPreconditions(); 48 | void testAddClone(); 49 | void testAdd(); 50 | void testSubtractPreconditions(); 51 | void testSubtractClone(); 52 | void testSubtract(); 53 | void testDividePreconditions(); 54 | void testDivideClone(); 55 | void testDivide(); 56 | void testSinePreconditions(); 57 | void testSineClone(); 58 | void testSine(); 59 | void testCosinePreconditions(); 60 | void testCosineClone(); 61 | void testCosine(); 62 | void testTangentPreconditions(); 63 | void testTangentClone(); 64 | void testTangent(); 65 | void testArcsinePreconditions(); 66 | void testArcsineClone(); 67 | void testArcsine(); 68 | void testArccosinePreconditions(); 69 | void testArccosineClone(); 70 | void testArccosine(); 71 | void testArctangentPreconditions(); 72 | void testArctangentClone(); 73 | void testArctangent(); 74 | void testPowerPreconditions(); 75 | void testPowerClone(); 76 | void testPower(); 77 | void testRootPreconditions(); 78 | void testRootClone(); 79 | void testRoot(); 80 | void testNegatePreconditions(); 81 | void testNegateClone(); 82 | void testNegate(); 83 | void testDuplicatePreconditions(); 84 | void testDuplicateClone(); 85 | void testDuplicate(); 86 | 87 | private: 88 | pdCalc::Stack& getCheckedStack(); 89 | void testBinaryCommandPreconditions(pdCalc::Command&); 90 | void testBinaryCommand(pdCalc::Command&, double top, double next, double result); 91 | void testUnaryCommandPreconditions(pdCalc::Command&); 92 | void testUnaryCommand(pdCalc::Command&, double top, double result); 93 | template void testClone(pdCalc::Command& c); 94 | void testArcsinArccosPreconditions(pdCalc::Command* command); 95 | }; 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /pdCalc/test/backendTest/PluginLoaderTest.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "PluginLoaderTest.h" 20 | #include "backend/PluginLoader.h" 21 | #include "utilities/UserInterface.h" 22 | #include "backend/Plugin.h" 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | using std::cout; 29 | using std::endl; 30 | using std::vector; 31 | using std::string; 32 | 33 | class TestInterface : public pdCalc::UserInterface 34 | { 35 | public: 36 | TestInterface() { } 37 | void postMessage(const string&) override { } 38 | void stackChanged() override { } 39 | }; 40 | 41 | void PluginLoaderTest::testLoading() 42 | { 43 | TestInterface ui; 44 | pdCalc::PluginLoader loader; 45 | 46 | std::ostringstream pluginFile; 47 | pluginFile << BACKEND_TEST_DIR << "/" << PLUGIN_TEST_FILE; 48 | loader.loadPlugins(ui, pluginFile.str()); 49 | vector plugins { loader.getPlugins() }; 50 | 51 | QVERIFY(plugins.size() == 1); 52 | 53 | return; 54 | } 55 | 56 | void PluginLoaderTest::testNoPluginFile() 57 | { 58 | TestInterface ui; 59 | pdCalc::PluginLoader loader; 60 | 61 | string pluginFile = "fileDoesNotExist"; 62 | loader.loadPlugins(ui, pluginFile); 63 | vector plugins { loader.getPlugins() }; 64 | 65 | QVERIFY(plugins.size() == 0); 66 | 67 | return; 68 | } 69 | -------------------------------------------------------------------------------- /pdCalc/test/backendTest/PluginLoaderTest.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef PLUGIN_LOADER_TEST_H 20 | #define PLUGIN_LOADER_TEST_H 21 | 22 | #include 23 | 24 | class PluginLoaderTest : public QObject 25 | { 26 | Q_OBJECT 27 | private slots: 28 | void testLoading(); 29 | void testNoPluginFile(); 30 | }; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /pdCalc/test/backendTest/StackTest.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "StackTest.h" 20 | #include "src/backend/Stack.h" 21 | #include "src/utilities/Observer.h" 22 | #include "src/utilities/Exception.h" 23 | #include 24 | 25 | using std::vector; 26 | using std::vector; 27 | using std::string; 28 | using std::shared_ptr; 29 | using std::unique_ptr; 30 | 31 | class StackChangedObserver : public pdCalc::Observer 32 | { 33 | public: 34 | StackChangedObserver(string name); 35 | unsigned int changeCount() const { return changeCount_; } 36 | void notifyImpl(std::shared_ptr); 37 | 38 | private: 39 | unsigned int changeCount_; 40 | }; 41 | 42 | StackChangedObserver::StackChangedObserver(string name) 43 | : pdCalc::Observer{name} 44 | , changeCount_{0} 45 | { 46 | } 47 | 48 | void StackChangedObserver::notifyImpl(std::shared_ptr) 49 | { 50 | ++changeCount_; 51 | } 52 | 53 | class StackErrorObserver : public pdCalc::Observer 54 | { 55 | public: 56 | StackErrorObserver(string name); 57 | const vector& errorMessages() const { return messages_; } 58 | const vector& errors() const { return errors_; } 59 | void notifyImpl(std::shared_ptr); 60 | 61 | private: 62 | vector messages_; 63 | vector errors_; 64 | }; 65 | 66 | StackErrorObserver::StackErrorObserver(string name) 67 | : pdCalc::Observer{name} 68 | { 69 | } 70 | 71 | void StackErrorObserver::notifyImpl(std::shared_ptr data) 72 | { 73 | std::shared_ptr p = std::dynamic_pointer_cast(data); 74 | if(p) 75 | { 76 | messages_.push_back(p->message()); 77 | errors_.push_back(p->error()); 78 | } 79 | 80 | return; 81 | } 82 | 83 | void StackTest::testPushPop() 84 | { 85 | pdCalc::Stack& stack = pdCalc::Stack::Instance(); 86 | stack.clear(); 87 | StackChangedObserver* raw = new StackChangedObserver{"StackChangedObserver"}; 88 | stack.attach( pdCalc::Stack::StackChanged, unique_ptr{raw} ); 89 | 90 | QVERIFY( stack.size() == 0 ); 91 | 92 | vector cur{ stack.getElements(100) }; 93 | 94 | QVERIFY( cur.size() == 0 ); 95 | 96 | stack.push(3.14159); 97 | stack.push(17.3); 98 | 99 | QVERIFY( stack.size() == 2 ); 100 | 101 | stack.push(2.0); 102 | 103 | cur = stack.getElements(2); 104 | 105 | QCOMPARE( cur[0], 2.0 ); 106 | QCOMPARE( cur[1], 17.3 ); 107 | 108 | cur = stack.getElements(3); 109 | 110 | QCOMPARE( cur[0], 2.0 ); 111 | QCOMPARE( cur[1], 17.3 ); 112 | QCOMPARE( cur[2], 3.14159 ); 113 | 114 | double val = stack.pop(); 115 | QCOMPARE(val, 2.0); 116 | QVERIFY( stack.size() == 2 ); 117 | 118 | cur = stack.getElements(2); 119 | QCOMPARE( cur[0], 17.3 ); 120 | QCOMPARE( cur[1], 3.14159 ); 121 | 122 | stack.push(3.0); 123 | 124 | cur = stack.getElements(3); 125 | 126 | QCOMPARE( cur[0], 3.0 ); 127 | QCOMPARE( cur[1], 17.3 ); 128 | QCOMPARE( cur[2], 3.14159 ); 129 | 130 | QCOMPARE(raw->changeCount(), 5u); 131 | 132 | stack.push(5.0, true); 133 | stack.pop(true); 134 | 135 | QCOMPARE(raw->changeCount(), 5u); 136 | 137 | stack.clear(); 138 | stack.detach(pdCalc::Stack::StackChanged, "StackChangedObserver"); 139 | 140 | return; 141 | } 142 | 143 | void StackTest::testSwapTop() 144 | { 145 | pdCalc::Stack& stack = pdCalc::Stack::Instance(); 146 | stack.clear(); 147 | StackChangedObserver* raw = new StackChangedObserver{"StackChangedObserver"}; 148 | stack.attach( pdCalc::Stack::StackChanged, unique_ptr{raw} ); 149 | 150 | QVERIFY( stack.size() == 0 ); 151 | 152 | stack.push(3.14159); 153 | stack.push(17.3); 154 | 155 | vector cur{ stack.getElements(2) }; 156 | QCOMPARE( cur[0], 17.3 ); 157 | QCOMPARE( cur[1], 3.14159 ); 158 | 159 | stack.swapTop(); 160 | 161 | cur = stack.getElements(2); 162 | QCOMPARE( cur[0], 3.14159 ); 163 | QCOMPARE( cur[1], 17.3 ); 164 | 165 | stack.push(2.0); 166 | 167 | cur = stack.getElements(3); 168 | QCOMPARE( cur[0], 2.0 ); 169 | QCOMPARE( cur[1], 3.14159 ); 170 | QCOMPARE( cur[2], 17.3 ); 171 | 172 | stack.swapTop(); 173 | 174 | cur = stack.getElements(3); 175 | QCOMPARE( cur[0], 3.14159 ); 176 | QCOMPARE( cur[1], 2.0 ); 177 | QCOMPARE( cur[2], 17.3 ); 178 | 179 | QCOMPARE(raw->changeCount(), 5u); 180 | 181 | stack.clear(); 182 | stack.detach(pdCalc::Stack::StackChanged, "StackChangedObserver"); 183 | 184 | return; 185 | } 186 | 187 | void StackTest::testErrors() 188 | { 189 | pdCalc::Stack& stack = pdCalc::Stack::Instance(); 190 | stack.clear(); 191 | StackErrorObserver* raw = new StackErrorObserver{"StackErrorObserver"}; 192 | stack.attach( pdCalc::Stack::StackError, unique_ptr{raw} ); 193 | 194 | const string emptyMsg = pdCalc::StackEventData::Message(pdCalc::StackEventData::ErrorConditions::Empty); 195 | const string swapMsg = pdCalc::StackEventData::Message(pdCalc::StackEventData::ErrorConditions::TooFewArguments); 196 | 197 | try 198 | { 199 | stack.pop(); 200 | QVERIFY(false); 201 | } 202 | catch(pdCalc::Exception& e) 203 | { 204 | QCOMPARE(e.what(), emptyMsg); 205 | } 206 | 207 | try 208 | { 209 | stack.swapTop(); 210 | QVERIFY(false); 211 | } 212 | catch(pdCalc::Exception& e) 213 | { 214 | QCOMPARE(e.what(), swapMsg); 215 | } 216 | 217 | const vector& msgs { raw->errorMessages() }; 218 | QVERIFY(msgs.size() == 2); 219 | QCOMPARE(msgs[0], emptyMsg); 220 | QCOMPARE(msgs[1], swapMsg); 221 | 222 | const vector errors { raw->errors() }; 223 | QVERIFY(errors.size() == 2); 224 | QCOMPARE(errors[0], pdCalc::StackEventData::ErrorConditions::Empty); 225 | QCOMPARE(errors[1], pdCalc::StackEventData::ErrorConditions::TooFewArguments); 226 | 227 | stack.clear(); 228 | stack.detach(pdCalc::Stack::StackError, "StackErrorObserver"); 229 | } 230 | 231 | -------------------------------------------------------------------------------- /pdCalc/test/backendTest/StackTest.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef STACK_TEST_H 20 | #define STACK_TEST_H 21 | 22 | #include 23 | 24 | class StackTest : public QObject 25 | { 26 | Q_OBJECT 27 | private slots: 28 | void testPushPop(); 29 | void testSwapTop(); 30 | void testErrors(); 31 | }; 32 | 33 | #endif 34 | 35 | -------------------------------------------------------------------------------- /pdCalc/test/backendTest/StoredProcedureTest.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "StoredProcedureTest.h" 20 | #include "src/backend/StoredProcedure.h" 21 | #include "src/utilities/UserInterface.h" 22 | #include "backend/Stack.h" 23 | #include "utilities/Exception.h" 24 | #include 25 | #include "backend/CoreCommands.h" 26 | #include "backend/CommandRepository.h" 27 | #include 28 | 29 | using std::vector; 30 | using std::string; 31 | 32 | namespace { 33 | 34 | class TestInterface : public pdCalc::UserInterface 35 | { 36 | public: 37 | TestInterface() { } 38 | void postMessage(const string&) override { } 39 | void stackChanged() override { } 40 | }; 41 | 42 | } 43 | 44 | void StoredProcedureTest::testMissingProcedure() 45 | { 46 | TestInterface ui; 47 | 48 | try 49 | { 50 | pdCalc::StoredProcedure sp{ui, "DoesNotExist"}; 51 | sp.execute(); 52 | QVERIFY(false); 53 | } 54 | catch(pdCalc::Exception& e) 55 | { 56 | QCOMPARE(e.what(), string{"Could not open procedure"}); 57 | } 58 | 59 | return; 60 | } 61 | 62 | void StoredProcedureTest::testStoredProcedure() 63 | { 64 | pdCalc::CommandRepository::Instance().clearAllCommands(); 65 | TestInterface ui; 66 | pdCalc::RegisterCoreCommands(ui); 67 | std::ostringstream oss; 68 | oss << BACKEND_TEST_DIR << "/hypotenuse"; 69 | pdCalc::StoredProcedure sp(ui, oss.str()); 70 | 71 | pdCalc::Stack& stack = pdCalc::Stack::Instance(); 72 | stack.push(3.0); 73 | stack.push(4.0); 74 | 75 | try 76 | { 77 | sp.execute(); 78 | QVERIFY(true); 79 | } 80 | catch(pdCalc::Exception&) 81 | { 82 | QVERIFY(false); 83 | } 84 | 85 | vector vals = stack.getElements(1); 86 | 87 | QCOMPARE(vals[0], 5.0); 88 | 89 | sp.undo(); 90 | 91 | vals = stack.getElements(2); 92 | 93 | QCOMPARE(vals[0], 4.0); 94 | QCOMPARE(vals[1], 3.0); 95 | 96 | sp.execute(); 97 | 98 | vals = stack.getElements(1); 99 | 100 | QCOMPARE(vals[0], 5.0); 101 | 102 | QVERIFY(sp.clone() == nullptr); 103 | 104 | return; 105 | } 106 | -------------------------------------------------------------------------------- /pdCalc/test/backendTest/StoredProcedureTest.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef STORED_PROCEDURE_TEST_H 20 | #define STORED_PROCEDURE_TEST_H 21 | 22 | #include 23 | 24 | class StoredProcedureTest : public QObject 25 | { 26 | Q_OBJECT 27 | 28 | private slots: 29 | void testMissingProcedure(); 30 | void testStoredProcedure(); 31 | }; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /pdCalc/test/backendTest/backendTest.pro: -------------------------------------------------------------------------------- 1 | HOME = ../.. 2 | include ($$HOME/common.pri) 3 | TEMPLATE = lib 4 | TARGET = pdCalcBackendTest 5 | DEPENDPATH += $$HOME/src/shared 6 | INCLUDEPATH += . $$HOME $$HOME/src 7 | unix:DESTDIR = $$HOME/lib 8 | win32:DESTDIR = $$HOME/bin 9 | DEFINES += BACKEND_TEST_DIR=\\\"$$PWD\\\" 10 | unix:DEFINES += PLUGIN_TEST_FILE=\\\"plugins.unix.pdp\\\" 11 | win32:DEFINES += PLUGIN_TEST_FILE=\\\"plugins.win.pdp\\\" 12 | 13 | 14 | # Input 15 | HEADERS += StackTest.h \ 16 | CommandManagerTest.h \ 17 | CommandRepositoryTest.h \ 18 | CoreCommandsTest.h \ 19 | CommandDispatcherTest.h \ 20 | StoredProcedureTest.h \ 21 | PluginLoaderTest.h 22 | SOURCES += StackTest.cpp \ 23 | CommandManagerTest.cpp \ 24 | CommandRepositoryTest.cpp \ 25 | CoreCommandsTest.cpp \ 26 | CommandDispatcherTest.cpp \ 27 | StoredProcedureTest.cpp \ 28 | PluginLoaderTest.cpp 29 | 30 | unix:LIBS += -L$$HOME/lib -lpdCalcUtilities -lpdCalcBackend 31 | win32:LIBS += -L$$HOME/bin -lpdCalcUtilities1 -lpdCalcBackend1 32 | 33 | QT -= gui core 34 | QT += testlib 35 | -------------------------------------------------------------------------------- /pdCalc/test/backendTest/hypotenuse: -------------------------------------------------------------------------------- 1 | 2 2 | pow 3 | swap 4 | 2 5 | pow 6 | + 7 | 2 8 | root -------------------------------------------------------------------------------- /pdCalc/test/backendTest/plugins.unix.pdp: -------------------------------------------------------------------------------- 1 | ../lib/libhyperbolicLnPlugin.so 2 | fake_name 3 | -------------------------------------------------------------------------------- /pdCalc/test/backendTest/plugins.win.pdp: -------------------------------------------------------------------------------- 1 | hyperbolicLnPlugin1.dll 2 | fake_name 3 | -------------------------------------------------------------------------------- /pdCalc/test/cliTest/CliTest.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "CliTest.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | using std::ifstream; 28 | using std::string; 29 | using std::ostream; 30 | using std::ostringstream; 31 | using std::vector; 32 | 33 | namespace { 34 | 35 | void checkFile(ifstream& ifs) 36 | { 37 | bool valid{ifs}; 38 | QVERIFY(valid); 39 | } 40 | 41 | string fixupPath(const string& path) 42 | { 43 | #ifdef WIN32 44 | // inefficient, but in test code...who cares 45 | ostringstream oss; 46 | for(auto c : path) 47 | { 48 | if(c == '/') oss << R"(\\)"; 49 | else oss << c; 50 | } 51 | 52 | return oss.str(); 53 | #else 54 | return path; 55 | #endif 56 | } 57 | 58 | // Windows and linux don't print exponents the same way 59 | // windows prints e-00x while linux prints e-0x. To simplify 60 | // comparisons, as lines are read, this function replaces 61 | // e-00x with e-0x 62 | void rationalizeExponent(string& s) 63 | { 64 | string::size_type pos = s.find("e-00"); 65 | if(pos != string::npos) 66 | { 67 | s.erase(pos + 2, 1); 68 | } 69 | } 70 | 71 | } 72 | 73 | std::string CliTest::path() 74 | { 75 | string t = CLI_TEST_DIR; 76 | t += "/testCases/"; 77 | return t; 78 | } 79 | 80 | void CliTest::runCliOnFile(const string& in, const string& out) 81 | { 82 | ostringstream cmd; 83 | string exe(fixupPath("./pdCalc")); 84 | cmd << exe << " --batch " << in << " " << out; 85 | int result = system( cmd.str().c_str() ); 86 | 87 | QCOMPARE(result, 0); 88 | 89 | return; 90 | } 91 | 92 | void CliTest::verifyOutput(const std::string& result, const std::string& baseline) 93 | { 94 | vector res{ vectorizeFile(result) }; 95 | vector base{ vectorizeFile(baseline) }; 96 | 97 | QCOMPARE(res, base); 98 | 99 | return; 100 | } 101 | 102 | std::vector CliTest::vectorizeFile(const std::string& fname) 103 | { 104 | ifstream ifs{ fname.c_str() }; 105 | checkFile(ifs); 106 | 107 | vector tmp; 108 | string line; 109 | while( std::getline(ifs, line, '\n') ) 110 | { 111 | rationalizeExponent(line); 112 | tmp.emplace_back( line ); 113 | } 114 | 115 | return tmp; 116 | } 117 | 118 | void CliTest::removeFile(const std::string& f) 119 | { 120 | int rem = remove( f.c_str() ); 121 | QCOMPARE(rem, 0); 122 | 123 | return; 124 | } 125 | 126 | void CliTest::runTest(const std::string& name) 127 | { 128 | 129 | string input = path() + "input" + name + ".txt"; 130 | string output = path() + "output" + name + ".txt"; 131 | string baseline = path() + "baseline" + name + ".txt"; 132 | 133 | runCliOnFile(input, output); 134 | verifyOutput(output, baseline); 135 | removeFile(output); 136 | } 137 | 138 | void CliTest::testCli1() 139 | { 140 | runTest("Cli1"); 141 | 142 | return; 143 | } 144 | 145 | void CliTest::testCli2() 146 | { 147 | runTest("Cli2"); 148 | 149 | return; 150 | } 151 | -------------------------------------------------------------------------------- /pdCalc/test/cliTest/CliTest.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef CLI_TEST_H 20 | #define CLI_TEST_H 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | class CliTest : public QObject 28 | { 29 | Q_OBJECT 30 | private slots: 31 | void testCli1(); 32 | void testCli2(); 33 | 34 | private: 35 | void runCliOnFile(const std::string& in, const std::string& out); 36 | void verifyOutput(const std::string& result, const std::string& baseline); 37 | std::vector vectorizeFile(const std::string& fname); 38 | void removeFile(const std::string& f); 39 | std::string path(); 40 | void runTest(const std::string&); 41 | }; 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /pdCalc/test/cliTest/cliTest.pro: -------------------------------------------------------------------------------- 1 | HOME = ../.. 2 | include ($$HOME/common.pri) 3 | TEMPLATE = lib 4 | TARGET = pdCalcCliTest 5 | INCLUDEPATH += . $$HOME 6 | unix:DESTDIR = $$HOME/lib 7 | win32:DESTDIR = $$HOME/bin 8 | DEFINES += CLI_TEST_DIR=\\\"$$PWD\\\" 9 | 10 | # Input 11 | HEADERS += CliTest.h 12 | SOURCES += CliTest.cpp 13 | 14 | unix:LIBS += -L$$HOME/lib -lpdCalcCli -lpdCalcBackend -lpdCalcUtilities 15 | win32:LIBS += -L$$HOME/bin -lpdCalcCli1 -lpdCalcBackend1 -lpdCalcUtilities1 16 | QT -= gui core 17 | QT += testlib 18 | -------------------------------------------------------------------------------- /pdCalc/test/cliTest/testCases/baselineCli1.txt: -------------------------------------------------------------------------------- 1 | 4 2 | 3 | Top element of stack (size = 1): 4 | 1: 4 5 | 6 | 7 7 | 8 | Top 2 elements of stack (size = 2): 9 | 2: 4 10 | 1: 7 11 | 12 | + 13 | 14 | Top element of stack (size = 1): 15 | 1: 11 16 | 17 | -------------------------------------------------------------------------------- /pdCalc/test/cliTest/testCases/baselineCli2.txt: -------------------------------------------------------------------------------- 1 | 12.3 2 | 3 | Top element of stack (size = 1): 4 | 1: 12.3 5 | 6 | 123456 7 | 8 | Top 2 elements of stack (size = 2): 9 | 2: 12.3 10 | 1: 123456 11 | 12 | / 13 | 14 | Top element of stack (size = 1): 15 | 1: 9.96306376361e-05 16 | 17 | sin 18 | 19 | Top element of stack (size = 1): 20 | 1: 9.96306374713e-05 21 | 22 | 1 23 | 24 | Top 2 elements of stack (size = 2): 25 | 2: 9.96306374713e-05 26 | 1: 1 27 | 28 | swap 29 | 30 | Top 2 elements of stack (size = 2): 31 | 2: 1 32 | 1: 9.96306374713e-05 33 | 34 | / 35 | 36 | Top element of stack (size = 1): 37 | 1: 10037.0731873 38 | 39 | 2 40 | 41 | Top 2 elements of stack (size = 2): 42 | 2: 10037.0731873 43 | 1: 2 44 | 45 | root 46 | 47 | Top element of stack (size = 1): 48 | 1: 100.185194452 49 | 50 | -543.33 51 | 52 | Top 2 elements of stack (size = 2): 53 | 2: 100.185194452 54 | 1: -543.33 55 | 56 | 12 57 | 58 | Top 3 elements of stack (size = 3): 59 | 3: 100.185194452 60 | 2: -543.33 61 | 1: 12 62 | 63 | arcsin 64 | Invalid argument 65 | neg 66 | 67 | Top 3 elements of stack (size = 3): 68 | 3: 100.185194452 69 | 2: -543.33 70 | 1: -12 71 | 72 | 14 73 | 74 | Top 4 elements of stack (size = 4): 75 | 4: 100.185194452 76 | 3: -543.33 77 | 2: -12 78 | 1: 14 79 | 80 | / 81 | 82 | Top 3 elements of stack (size = 3): 83 | 3: 100.185194452 84 | 2: -543.33 85 | 1: -0.857142857143 86 | 87 | arcsin 88 | 89 | Top 3 elements of stack (size = 3): 90 | 3: 100.185194452 91 | 2: -543.33 92 | 1: -1.02969680084 93 | 94 | undo 95 | 96 | Top 3 elements of stack (size = 3): 97 | 3: 100.185194452 98 | 2: -543.33 99 | 1: -0.857142857143 100 | 101 | undo 102 | 103 | Top 4 elements of stack (size = 4): 104 | 4: 100.185194452 105 | 3: -543.33 106 | 2: -12 107 | 1: 14 108 | 109 | undo 110 | 111 | Top 3 elements of stack (size = 3): 112 | 3: 100.185194452 113 | 2: -543.33 114 | 1: -12 115 | 116 | 18 117 | 118 | Top 4 elements of stack (size = 4): 119 | 4: 100.185194452 120 | 3: -543.33 121 | 2: -12 122 | 1: 18 123 | 124 | / 125 | 126 | Top 3 elements of stack (size = 3): 127 | 3: 100.185194452 128 | 2: -543.33 129 | 1: -0.666666666667 130 | 131 | arcsin 132 | 133 | Top 3 elements of stack (size = 3): 134 | 3: 100.185194452 135 | 2: -543.33 136 | 1: -0.729727656227 137 | 138 | undo 139 | 140 | Top 3 elements of stack (size = 3): 141 | 3: 100.185194452 142 | 2: -543.33 143 | 1: -0.666666666667 144 | 145 | redo 146 | 147 | Top 3 elements of stack (size = 3): 148 | 3: 100.185194452 149 | 2: -543.33 150 | 1: -0.729727656227 151 | 152 | tan 153 | 154 | Top 3 elements of stack (size = 3): 155 | 3: 100.185194452 156 | 2: -543.33 157 | 1: -0.894427191 158 | 159 | arctan 160 | 161 | Top 3 elements of stack (size = 3): 162 | 3: 100.185194452 163 | 2: -543.33 164 | 1: -0.729727656227 165 | 166 | -------------------------------------------------------------------------------- /pdCalc/test/cliTest/testCases/inputCli1.txt: -------------------------------------------------------------------------------- 1 | 4 2 | 7 3 | + -------------------------------------------------------------------------------- /pdCalc/test/cliTest/testCases/inputCli2.txt: -------------------------------------------------------------------------------- 1 | 12.3 2 | 123456 3 | / 4 | sin 5 | 1 6 | swap 7 | / 8 | 2 9 | root 10 | -543.33 11 | 12 12 | arcsin 13 | neg 14 | 14 15 | / 16 | arcsin 17 | undo 18 | undo 19 | undo 20 | 18 21 | / 22 | arcsin 23 | undo 24 | redo 25 | tan 26 | arctan -------------------------------------------------------------------------------- /pdCalc/test/guiTest/DisplayTest.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef DISPLAY_TEST_H 20 | #define DISPLAY_TEST_H 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | namespace pdCalc { 27 | class Display; 28 | class GuiModel; 29 | } 30 | 31 | class DisplayTest : public QObject 32 | { 33 | Q_OBJECT 34 | public: 35 | DisplayTest(); 36 | 37 | private slots: 38 | void init(); 39 | void cleanup(); 40 | 41 | void testUpdateStack(); 42 | void testInput(); 43 | void testState(); 44 | void testPlusMinus(); 45 | 46 | private: 47 | std::string createLine(unsigned int stackLabel, const std::string& txt) const; 48 | bool displayMatches(const std::string& input, const std::vector&) const; 49 | void testInput(const std::vector &input, const std::vector&); 50 | 51 | pdCalc::Display* display_; 52 | pdCalc::GuiModel* guiModel_; 53 | class QApplication* app_; 54 | 55 | int nCharWide_; 56 | int nLinesStack_; 57 | }; 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /pdCalc/test/guiTest/guiTest.pro: -------------------------------------------------------------------------------- 1 | HOME = ../.. 2 | include ($$HOME/common.pri) 3 | TEMPLATE = lib 4 | TARGET = pdCalcGuiTest 5 | INCLUDEPATH += . $$HOME 6 | unix:DESTDIR = $$HOME/lib 7 | win32:DESTDIR = $$HOME/bin 8 | 9 | QT += widgets testlib 10 | 11 | # Input 12 | HEADERS += DisplayTest.h 13 | SOURCES += DisplayTest.cpp 14 | 15 | unix:LIBS += -L$$HOME/lib -lpdCalcBackend -lpdCalcUtilities -lpdCalcGui 16 | win32:LIBS += -L$$HOME/bin -lpdCalcBackend1 -lpdCalcUtilities1 -lpdCalcGui1 17 | -------------------------------------------------------------------------------- /pdCalc/test/pluginsTest/HyperbolicLnPluginTest.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "HyperbolicLnPluginTest.h" 20 | #include "backend/PluginLoader.h" 21 | #include "utilities/UserInterface.h" 22 | #include "plugins/hyperbolicLnPlugin/HyperbolicLnPlugin.h" 23 | #include "backend/Stack.h" 24 | #include "utilities/Exception.h" 25 | #include "backend/Command.h" 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | using std::map; 32 | using std::string; 33 | using std::vector; 34 | using pdCalc::Plugin; 35 | 36 | class TestInterface : public pdCalc::UserInterface 37 | { 38 | public: 39 | TestInterface() { } 40 | void postMessage(const string&) override { } 41 | void stackChanged() override { } 42 | }; 43 | 44 | namespace { 45 | 46 | // this function needed because of how QCOMPARE works 47 | void testStack() 48 | { 49 | QVERIFY( pdCalc::Stack::Instance().size() == 0 ); 50 | } 51 | 52 | } 53 | 54 | pdCalc::Stack& HyperbolicLnPluginTest::getCheckedStack() 55 | { 56 | pdCalc::Stack::Instance().clear(); 57 | testStack(); 58 | return pdCalc::Stack::Instance(); 59 | } 60 | 61 | void HyperbolicLnPluginTest::testPreconditions(pdCalc::Command* command, double number) 62 | { 63 | pdCalc::Stack& stack = getCheckedStack(); 64 | 65 | try 66 | { 67 | command->execute(); 68 | QVERIFY(false); 69 | } 70 | catch(pdCalc::Exception&) 71 | { 72 | QVERIFY(true); 73 | } 74 | 75 | stack.push(number); 76 | 77 | try 78 | { 79 | command->execute(); 80 | QVERIFY(true); 81 | } 82 | catch(pdCalc::Exception&) 83 | { 84 | QVERIFY(false); 85 | } 86 | 87 | return; 88 | } 89 | 90 | void HyperbolicLnPluginTest::testCommand(pdCalc::Command* command, double top, double result) 91 | { 92 | pdCalc::Stack& stack = getCheckedStack(); 93 | 94 | stack.push(top); 95 | 96 | QVERIFY( stack.size() == 1 ); 97 | 98 | command->execute(); 99 | 100 | QVERIFY( stack.size() == 1 ); 101 | vector stackTop{ stack.getElements(1) }; 102 | QVERIFY( std::abs(stackTop[0] - result) < 1e-10 ); 103 | 104 | command->undo(); 105 | 106 | QVERIFY( stack.size() == 1 ); 107 | stackTop = stack.getElements(1); 108 | QCOMPARE( stackTop[0], top); 109 | 110 | return; 111 | } 112 | 113 | void HyperbolicLnPluginTest::testHyperbolicLnPlugin() 114 | { 115 | TestInterface ui; 116 | pdCalc::PluginLoader loader; 117 | 118 | string pluginFile{PLUGIN_TEST_DIR}; 119 | pluginFile += "/../backendTest/"; 120 | pluginFile += PLUGIN_TEST_FILE; 121 | loader.loadPlugins(ui, pluginFile); 122 | 123 | vector plugins{ loader.getPlugins() }; 124 | 125 | QVERIFY(plugins.size() == 1); 126 | 127 | const Plugin* p = plugins[0]; 128 | Plugin::PluginDescriptor descriptor = p->getPluginDescriptor(); 129 | 130 | QCOMPARE(descriptor.nCommands, 8); 131 | 132 | map commands; 133 | for(int i = 0; i < descriptor.nCommands; ++i) 134 | commands[descriptor.commandNames[i]] = descriptor.commands[i]; 135 | 136 | testPreconditions( commands.find("sinh")->second, 1.0 ); 137 | double top = 3.45; 138 | testCommand( commands.find("sinh")->second, top, std::sinh(top)); 139 | 140 | testPreconditions( commands.find("cosh")->second, 1.0 ); 141 | top = -12.3; 142 | testCommand( commands.find("cosh")->second, top, std::cosh(top) ); 143 | 144 | testPreconditions( commands.find("tanh")->second, 1.0 ); 145 | top = -1.34; 146 | testCommand( commands.find("tanh")->second, top, std::tanh(top)); 147 | 148 | testPreconditions( commands.find("arccosh")->second, 1.3 ); 149 | try 150 | { 151 | pdCalc::Stack::Instance().push(0.2); 152 | commands.find("arccosh")->second->execute(); 153 | QVERIFY(false); 154 | } 155 | catch(pdCalc::Exception&) 156 | { 157 | QVERIFY(true); 158 | } 159 | 160 | top = 1.34; 161 | testCommand( commands.find("arccosh")->second, top, std::log(top + std::sqrt(top*top - 1.))); 162 | 163 | testPreconditions( commands.find("arctanh")->second, 0.5 ); 164 | try 165 | { 166 | pdCalc::Stack::Instance().push(1.2); 167 | commands.find("arctanh")->second->execute(); 168 | QVERIFY(false); 169 | } 170 | catch(pdCalc::Exception&) 171 | { 172 | QVERIFY(true); 173 | } 174 | 175 | try 176 | { 177 | pdCalc::Stack::Instance().push(-1.2); 178 | commands.find("arctanh")->second->execute(); 179 | QVERIFY(false); 180 | } 181 | catch(pdCalc::Exception&) 182 | { 183 | QVERIFY(true); 184 | } 185 | 186 | top = 0.3; 187 | testCommand( commands.find("arctanh")->second, top, 0.5 * std::log( (1.0 + top) / (1.0 - top) )); 188 | 189 | testPreconditions( commands.find("exp")->second, 1.0 ); 190 | top = -1.34; 191 | testCommand( commands.find("exp")->second, top, std::exp(top)); 192 | 193 | testPreconditions( commands.find("ln")->second, 1.3 ); 194 | try 195 | { 196 | pdCalc::Stack::Instance().push(-0.2); 197 | commands.find("ln")->second->execute(); 198 | QVERIFY(false); 199 | } 200 | catch(pdCalc::Exception&) 201 | { 202 | QVERIFY(true); 203 | } 204 | 205 | top = 1.34; 206 | testCommand( commands.find("ln")->second, top, std::log(top) ); 207 | return; 208 | } 209 | -------------------------------------------------------------------------------- /pdCalc/test/pluginsTest/HyperbolicLnPluginTest.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef HYPERBOLIC_LN_PLUGIN_TEST_H 20 | #define HYPERBOLIC_LN_PLUGIN_TEST_H 21 | 22 | #include 23 | 24 | namespace pdCalc { 25 | class Stack; 26 | class Command; 27 | } 28 | 29 | class HyperbolicLnPluginTest : public QObject 30 | { 31 | Q_OBJECT 32 | private slots: 33 | void testHyperbolicLnPlugin(); 34 | 35 | private: 36 | pdCalc::Stack& getCheckedStack(); 37 | void testPreconditions(pdCalc::Command* command, double number); 38 | void testCommand(pdCalc::Command* command, double top, double result); 39 | }; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /pdCalc/test/pluginsTest/pluginsTest.pro: -------------------------------------------------------------------------------- 1 | HOME = ../.. 2 | include ($$HOME/common.pri) 3 | TEMPLATE = lib 4 | TARGET = pluginsTest 5 | DEPENDPATH += $$HOME/src/shared $$HOME/src/backend 6 | INCLUDEPATH += . $$HOME $$HOME/src 7 | unix:DESTDIR = $$HOME/lib 8 | win32:DESTDIR = $$HOME/bin 9 | 10 | DEFINES += PLUGIN_TEST_DIR=\\\"$$PWD\\\" 11 | unix:DEFINES += PLUGIN_TEST_FILE=\\\"plugins.unix.pdp\\\" 12 | win32:DEFINES += PLUGIN_TEST_FILE=\\\"plugins.win.pdp\\\" 13 | 14 | QT += testlib 15 | 16 | # Input 17 | HEADERS += HyperbolicLnPluginTest.h 18 | SOURCES += HyperbolicLnPluginTest.cpp 19 | unix:LIBS += -L$$HOME/lib -lpdCalcUtilities -lpdCalcBackend 20 | win32:LIBS += -L$$HOME/bin -lpdCalcUtilities1 -lpdCalcBackend1 21 | -------------------------------------------------------------------------------- /pdCalc/test/test.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += utilitiesTest \ 4 | backendTest \ 5 | cliTest \ 6 | guiTest \ 7 | pluginsTest \ 8 | testDriver 9 | -------------------------------------------------------------------------------- /pdCalc/test/testDriver/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include 20 | #include "../utilitiesTest/PublisherObserverTest.h" 21 | #include "../utilitiesTest/TokenizerTest.h" 22 | #include "../pluginsTest/HyperbolicLnPluginTest.h" 23 | #include "../guiTest/DisplayTest.h" 24 | #include "../cliTest/CliTest.h" 25 | #include "../backendTest/CommandDispatcherTest.h" 26 | #include "../backendTest/CommandManagerTest.h" 27 | #include "../backendTest/CommandRepositoryTest.h" 28 | #include "../backendTest/CoreCommandsTest.h" 29 | #include "../backendTest/PluginLoaderTest.h" 30 | #include "../backendTest/StackTest.h" 31 | #include "../backendTest/StoredProcedureTest.h" 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | using std::cout; 38 | using std::endl; 39 | 40 | int main(int argc, char* argv[]) 41 | { 42 | // I use QStringList instead of argv directly because the QStringList 43 | // argument to qExec is constant. API doc indicates that for the argv 44 | // version, it may alter argv making repeated calls to qExec unstable 45 | // with respect to the arguments. 46 | QStringList args; 47 | for(int i = 0; i < argc; ++i) 48 | args.append( QString{argv[i]} ); 49 | 50 | std::unordered_map passFail; 51 | 52 | PublisherObserverTest pot; 53 | passFail["PublisherObserverTest"] = QTest::qExec(&pot, args); 54 | 55 | TokenizerTest tt; 56 | passFail["TokenizerTest"] = QTest::qExec(&tt, args); 57 | 58 | HyperbolicLnPluginTest hpt; 59 | passFail["HyperbolicPluginTest"] = QTest::qExec(&hpt, args); 60 | 61 | DisplayTest dt; 62 | passFail["DisplayTest"] = QTest::qExec(&dt, args); 63 | 64 | CliTest ct; 65 | passFail["CliTest"] = QTest::qExec(&ct, args); 66 | 67 | CommandDispatcherTest cet; 68 | passFail["CommandDispatcherTest"] = QTest::qExec(&cet, args); 69 | 70 | CommandManagerTest cmt; 71 | passFail["CommandManagerTest"] = QTest::qExec(&cmt, args); 72 | 73 | CommandRepositoryTest crt; 74 | passFail["CommandRepositoryTest"] = QTest::qExec(&crt, args); 75 | 76 | CoreCommandsTest cct; 77 | passFail["CoreCommandsTest"] = QTest::qExec(&cct, args); 78 | 79 | PluginLoaderTest plt; 80 | passFail["PluginLoaderTest"] = QTest::qExec(&plt, args); 81 | 82 | StackTest st; 83 | passFail["StackTest"] = QTest::qExec(&st, args); 84 | 85 | StoredProcedureTest spt; 86 | passFail["StoredProcedureTest"] = QTest::qExec(&spt, args); 87 | 88 | cout << endl; 89 | int errors = 0; 90 | for(const auto& i : passFail) 91 | { 92 | errors += i.second; 93 | if(i.second != 0) 94 | cout << "Failed test in " << i.first << endl; 95 | } 96 | 97 | if(errors == 0) 98 | cout << "All tests passed" << endl; 99 | 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /pdCalc/test/testDriver/testDriver.pro: -------------------------------------------------------------------------------- 1 | HOME = ../.. 2 | include ($$HOME/common.pri) 3 | QMAKE_CXXFLAGS += -Wno-deprecated-declarations 4 | TEMPLATE = app 5 | TARGET = testPdCalc 6 | INCLUDEPATH += $$HOME $$HOME/src 7 | DESTDIR = $$HOME/bin 8 | 9 | QT += testlib 10 | 11 | # Input 12 | SOURCES += main.cpp 13 | 14 | unix:LIBS += -L$$HOME/lib -lpdCalcUtilities -lpdCalcUtilitiesTest \ 15 | -lpdCalcBackend -lpdCalcBackendTest \ 16 | -lpdCalcCliTest -lpdCalcCli \ 17 | -lpdCalcGuiTest -lpdCalcGui \ 18 | -lpluginsTest 19 | 20 | win32:LIBS += -L$$HOME/bin -lpdCalcUtilities1 -lpdCalcUtilitiesTest1 \ 21 | -lpdCalcBackend1 -lpdCalcBackendTest1 \ 22 | -lpdCalcCliTest1 -lpdCalcCli1 \ 23 | -lpdCalcGuiTest1 -lpdCalcGui1 \ 24 | -lpluginsTest1 25 | -------------------------------------------------------------------------------- /pdCalc/test/utilitiesTest/PublisherObserverTest.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef PUBLISHER_OBSERVER_TEST_H 20 | #define PUBLISHER_OBSERVER_TEST_H 21 | 22 | #include 23 | #include "src/utilities/Publisher.h" 24 | #include "src/utilities/Exception.h" 25 | #include "src/utilities/Observer.h" 26 | 27 | class ConcretePublisher; 28 | 29 | class PublisherObserverTest : public QObject 30 | { 31 | Q_OBJECT 32 | private slots: 33 | void init(); 34 | void cleanup(); 35 | 36 | void testRegister(); 37 | void testRegisterDuplicate(); 38 | void testAttachObservers(); 39 | void testRaiseEvent(); 40 | void testDetachObservers(); 41 | void testGetState(); 42 | 43 | private: 44 | ConcretePublisher* pt_; 45 | }; 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /pdCalc/test/utilitiesTest/TokenizerTest.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #include "TokenizerTest.h" 20 | #include "src/utilities/Tokenizer.h" 21 | #include 22 | #include 23 | 24 | using std::endl; 25 | using std::cout; 26 | using std::vector; 27 | using std::string; 28 | using std::ostringstream; 29 | using std::istringstream; 30 | 31 | void TokenizerTest::assertTokenizerMatches(const std::vector& tokens, const pdCalc::Tokenizer& tokenizer) 32 | { 33 | QCOMPARE( tokens.size(), tokenizer.nTokens() ); 34 | 35 | auto j = tokens.begin(); 36 | for(auto i : tokenizer) 37 | { 38 | QCOMPARE(i, *j); 39 | ++j; 40 | } 41 | 42 | for(size_t i = 0; i < tokenizer.nTokens(); ++i) 43 | { 44 | QCOMPARE(tokens[i], tokenizer[i]); 45 | } 46 | } 47 | 48 | void TokenizerTest::testTokenizationFromString() 49 | { 50 | vector tokens = {"7.3454", "8.21", "+", "dup", "dup", "*", "-", "4.35", "tan" }; 51 | 52 | string str; 53 | for(size_t i = 0; i < tokens.size(); ++i) 54 | { 55 | str += tokens[i] + (i == 4 ? "\n" : " "); 56 | } 57 | 58 | pdCalc::Tokenizer tokenizer(str); 59 | 60 | assertTokenizerMatches(tokens, tokenizer); 61 | 62 | return; 63 | } 64 | 65 | void TokenizerTest::testTokenizationFromStream() 66 | { 67 | vector tokens = {"7.3454", "8.21", "sin", "dup", "dup", "/", "pow", "4.35", "arctan" "-18.4" "neg" "root"}; 68 | 69 | ostringstream oss; 70 | for(size_t i = 0; i < tokens.size(); ++i) 71 | { 72 | oss << tokens[i] + (i % 3 == 0 ? "\n" : " "); 73 | } 74 | 75 | istringstream iss( oss.str() ); 76 | 77 | pdCalc::Tokenizer tokenizer(iss); 78 | 79 | assertTokenizerMatches(tokens, tokenizer); 80 | 81 | return; 82 | } 83 | 84 | -------------------------------------------------------------------------------- /pdCalc/test/utilitiesTest/TokenizerTest.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adam B. Singer 2 | // Contact: PracticalDesignBook@gmail.com 3 | // 4 | // This file is part of pdCalc. 5 | // 6 | // pdCalc is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // pdCalc is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with pdCalc; if not, see . 18 | 19 | #ifndef TOKENIZER_TEST_H 20 | #define TOKENIZER_TEST_H 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | namespace pdCalc { 27 | class Tokenizer; 28 | } 29 | 30 | class TokenizerTest : public QObject 31 | { 32 | Q_OBJECT 33 | private slots: 34 | void testTokenizationFromString(); 35 | void testTokenizationFromStream(); 36 | 37 | private: 38 | void assertTokenizerMatches(const std::vector&, const pdCalc::Tokenizer&); 39 | }; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /pdCalc/test/utilitiesTest/utilitiesTest.pro: -------------------------------------------------------------------------------- 1 | HOME = ../.. 2 | include ($$HOME/common.pri) 3 | TEMPLATE = lib 4 | TARGET = pdCalcUtilitiesTest 5 | DEPENDPATH += $$HOME/src/utilities 6 | INCLUDEPATH += . $$HOME 7 | unix:DESTDIR = $$HOME/lib 8 | win32:DESTDIR = $$HOME/bin 9 | 10 | QT -= gui core 11 | QT += testlib 12 | 13 | # Input 14 | HEADERS += PublisherObserverTest.h \ 15 | TokenizerTest.h 16 | SOURCES += PublisherObserverTest.cpp \ 17 | TokenizerTest.cpp 18 | 19 | unix:LIBS += -L$$HOME/lib -lpdCalcUtilities 20 | win32:LIBS += -L$$HOME/bin -lpdCalcUtilities1 21 | --------------------------------------------------------------------------------