Skip to content

Commit

Permalink
Merge branch 'feature/playbookImport'
Browse files Browse the repository at this point in the history
This merges some code which does essentially 2 things:
- setting up a unit test infrastructure with the Boost test framework
- implementing basic functionality to import another playbook, including tests

The implemented importing functionality is one big step for issue #10. 
The API supports importing all plays, categories, formations and routes.
However, you cannot choose which particular plays to import and which not.
Furthermore, there is no exporting functionality, yet to let you choose
which particular plays/categories/.. you want to export.
There is also a GUI dialog missing to fully use the current API.
Currently, it is hardcoded that plays, categories and formations (but no
routes) are imported and that the name of everyone of these are prefixed
with 'imported_'.


To implement playbook importing there are some changes to the codebase:
There is a new class PBCController. This addresses issue #20 and is a first step for centralizing the business logic of PBC.
For now, the PBCController simply does nothing else than maintaining the active instance of PBCPlaybook.
The class PBCPlaybook is no longer a singleton. There is the one "active Playbook" object instead.
This was necessary to be able to instantiate another object of PBCPlaybook for another playbook to be imported.

Moreover several adaptions for the CI scripts were necessary.
  • Loading branch information
obraunsdorf committed Apr 8, 2020
2 parents 575efb5 + 8648a2b commit fc28a70
Show file tree
Hide file tree
Showing 37 changed files with 879 additions and 117 deletions.
7 changes: 6 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
- run:
name: Install Dependencies
command: |
apt update && apt install -y git build-essential cmake pkg-config qt5-default libboost-serialization-dev libssl-dev python golang-go curl
apt update && apt install -y git build-essential cmake pkg-config qt5-default libboost-serialization-dev libboost-test-dev libboost-filesystem-dev libssl-dev python golang-go curl
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
- restore_cache:
keys:
Expand All @@ -33,6 +33,11 @@ jobs:
command: |
cmake -D BOTAN_LIBRARY=botan/libbotan-2.a -D BOTAN_INCLUDE_DIR=botan/build/include .
make
- run:
name: Test
command: |
make tests
ASAN_OPTIONS=detect_leaks=0 bin/tests -- --test-base-dir "test"
- run:
name: Copy Qt5 shared libaries
command: |
Expand Down
36 changes: 15 additions & 21 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,31 +1,25 @@
os: osx
language: cpp
install:
- cmake --version
- brew list git || brew install git
- brew list cmake || brew install cmake
- brew upgrade cmake
- cmake --version
- brew list pkg-config || brew install pkg-config
- brew list qt || brew install qt
- brew list boost || brew install boost
- brew install [email protected]
- brew unlink boost
- brew link --force [email protected]
- brew update
- brew list git &>/dev/null || brew install git
- brew list cmake &>/dev/null || brew install cmake
- brew list pkg-config &>/dev/null || brew install pkg-config
- brew list qt &>/dev/null || brew install qt
- brew uninstall --ignore-dependencies boost
- bash ci-scripts/build-boost.sh
- ls boost
- ls boost/lib
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
cache:
directories:
botan
- botan
- boost
script:
- if [[ $SKIP_CACHE_RESTORE == true ]]; then
git clone https://github.com/randombit/botan botan;
cd botan;
git checkout 2.6.0;
python configure.py --disable-shared-library --disable-modules=darwin_secrandom;
make;
cd ..;
fi
- cmake . -DBOTAN_LIBRARY=botan/libbotan-2.a -DBOTAN_INCLUDE_DIR=botan/build/include -DCMAKE_PREFIX_PATH=$(brew --prefix qt5)
- ls botan/
- bash ci-scripts/build-botan.sh
- cmake . -DBoost_INCLUDE_DIR=$(pwd)/boost/include -DBoost_INCLUDE_DIR=$(pwd)/boost/include -DBoost_LIBRARY_DIR=$(pwd)/boost/lib -DBOTAN_LIBRARY=botan/libbotan-2.a -DBOTAN_INCLUDE_DIR=botan/build/include -DCMAKE_PREFIX_PATH=$(brew --prefix qt5)
- make
- ASAN_OPTIONS=detect_leaks=0 bin/tests -- --test-base-dir "test"
- $(brew --prefix qt5)/bin/macdeployqt bin/PlaybookCreator.app -verbose=3 -dmg -no-strip
- bash deploy.sh bin/PlaybookCreator.dmg PlaybookCreator.dmg "PlaybookCreator for MacOSX" $GITHUB_TOKEN
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ set(PBC_UPDATER_CMAKE_NAME pbc-updater)
add_subdirectory(updater)

add_subdirectory(src)
add_subdirectory(test)


add_custom_target( documentation COMMAND doxygen)
11 changes: 6 additions & 5 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ environment:
cache:
- C:\projects\botan\botan.lib
- C:\projects\botan\build\include
- C:\Users\appveyor\.cargo

install:
- curl -sSf -o rustup-init.exe https://win.rustup.rs
Expand All @@ -32,17 +33,17 @@ before_build:
echo "starting build..."
build:
project: PlaybookCreator.sln
project: ALL_BUILD.vcxproj
verbosity: normal
after_build:
- cmd: >-
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
C:\Qt\5.11\msvc2017_64\bin\windeployqt.exe --release --pdb --compiler-runtime "C:\projects\playbook-creator\bin\Release"
cd bin\Release\ && tests.exe -- --test-base-dir "..\..\test" && cd ..\..
"C:\Program Files (x86)\Inno Setup 5\ISCC" C:\projects\playbook-creator\innosetup.iss
test_script:
- ps: '#$blockRdp = $true; iex ((new-object net.webclient).DownloadString("https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1"))'
artifacts:
- path: bin\release\PlaybookCreator.exe
name: PlaybookCreator.exe
Expand All @@ -55,4 +56,4 @@ deploy_script:
bash deploy.sh bin/PlaybookCreatorSetup.exe PlaybookCreatorSetup.exe "PlaybookCreator for Windows" $TOKEN
on_finish:
- ps: >-
if($env:ENABLE_REMOTE_DESKTOP -eq $true) {$blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))}
if($env:ENABLE_REMOTE_DESKTOP -eq $true) {$blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))}
9 changes: 9 additions & 0 deletions ci-scripts/build-boost.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
if [[ ! -f boost/lib/libboost_serialization.a ]]; then
mkdir boost
curl -O -L https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.gz;
tar -xzf boost_1_66_0.tar.gz;
cd boost_1_66_0;
./bootstrap.sh --with-libraries=serialization,filesystem,test --prefix=../boost
./b2 install link=static runtime-link=static &>/dev/null
cd ..;
fi
9 changes: 9 additions & 0 deletions ci-scripts/build-botan.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
if [[ ! -f botan/libbotan-2.a ]]; then
echo "hallo"
git clone https://github.com/randombit/botan botan;
cd botan;
git checkout 2.6.0;
python configure.py --disable-shared-library --disable-modules=darwin_secrandom;
make;
cd ..;
fi
36 changes: 20 additions & 16 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ set ( SOURCES
util/pbcSingleton.h
util/pbcStorage.cpp
util/pbcStorage.h
main.cpp
pbcController.cpp
pbcController.h
pbcVersion.h)

set ( MOC_HEADERS
Expand Down Expand Up @@ -138,32 +139,35 @@ qt5_wrap_cpp( MOC_SRCS ${MOC_HEADERS} )
# WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tools
#)

# compile
add_executable( ${PROJECT_NAME} ${SOURCES} ${MOC_SRCS} ${UI_HEADERS})
if(APPLE)
set_target_properties(${PROJECT_NAME} PROPERTIES
MACOSX_BUNDLE ON
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/cmake/pbcMacOSXBundleInfo.plist.in)
endif()
#add_dependencies(${PROJECT_NAME} style_checking)

add_library(PBCLib ${SOURCES} ${MOC_SRCS} ${UI_HEADERS})
#add_dependencies(PBCLib style_checking)

# link the updater library
if(WIN32)
find_package(OpenSSL)
target_link_libraries(${PROJECT_NAME} ${PBC_UPDATER_CMAKE_NAME} ws2_32 userenv crypt32 ncrypt schannel Secur32)
target_link_libraries(PBCLib ${PBC_UPDATER_CMAKE_NAME} ws2_32 userenv crypt32 ncrypt schannel Secur32)
elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin")
find_library(SECFW Security)
find_library(COREFW CoreFoundation)
target_link_libraries(${PROJECT_NAME} ${PBC_UPDATER_CMAKE_NAME} resolv ${SECFW} ${COREFW})
target_link_libraries(PBCLib ${PBC_UPDATER_CMAKE_NAME} resolv ${SECFW} ${COREFW})
else()
target_link_libraries(${PROJECT_NAME} ${PBC_UPDATER_CMAKE_NAME} pthread dl ssl crypto) # TODO find out the libs programmatically
target_link_libraries(PBCLib ${PBC_UPDATER_CMAKE_NAME} pthread dl ssl crypto) # TODO find out the libs programmatically
endif()

# link Microsoft Visual Studio Runtime statically by default (on Windows builds)
include(ConfigureMSVCRT)
configure_msvc_runtime()

# link libraries
target_link_libraries(${PROJECT_NAME} Qt5::Widgets Qt5::PrintSupport ${Boost_LIBRARIES} ${BOTAN_LIBRARY})
#target_link_libraries(${PROJECT_NAME} ${Qt5Widgets_LIBRARIES} ${Qt5PrintSupport_LIBRARIES} ${Boost_LIBRARIES} ${BOTAN_LIBRARY})
# link external libraries
target_link_libraries(PBCLib Qt5::Widgets Qt5::PrintSupport ${Boost_LIBRARIES} ${BOTAN_LIBRARY})


# link executable
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} PBCLib)

if(APPLE)
set_target_properties(${PROJECT_NAME} PROPERTIES
MACOSX_BUNDLE ON
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/cmake/pbcMacOSXBundleInfo.plist.in)
endif()
92 changes: 80 additions & 12 deletions src/dialogs/mainDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include "util/pbcConfig.h"
#include "gui/pbcPlayerView.h"
#include "pbcController.h"
#include "models/pbcPlaybook.h"
#include "dialogs/pbcExportPdfDialog.h"
#include "dialogs/pbcDeleteDialog.h"
Expand Down Expand Up @@ -116,7 +117,7 @@ void MainDialog::updateTitle(bool saved) {
std::string windowTitle = "Playbook Creator V" +
PBCVersion::getSimpleVersionString() +
" - " +
PBCPlaybook::getInstance()->name();
PBCController::getInstance()->getPlaybook()->name();
if(saved == false) {
windowTitle += "*";
}
Expand Down Expand Up @@ -240,7 +241,7 @@ void MainDialog::savePlayAs() {
int returnCode = dialog.exec();
if (returnCode == QDialog::Accepted) {
struct PBCSavePlayAsDialog::ReturnStruct rs = dialog.getReturnStruct();
std::vector<std::string> playNames = PBCPlaybook::getInstance()->getPlayNames();
std::vector<std::string> playNames = PBCController::getInstance()->getPlaybook()->getPlayNames();
const auto& it = std::find(playNames.begin(), playNames.end(), rs.name);
if (it != playNames.end()) {
QMessageBox::StandardButton button =
Expand Down Expand Up @@ -289,7 +290,7 @@ void MainDialog::saveFormationAs() {
if (ok == true) {
pbcAssert(qformationname != "");
std::string formationName = qformationname.toStdString();
std::vector<std::string> formationNames = PBCPlaybook::getInstance()->getFormationNames();
std::vector<std::string> formationNames = PBCController::getInstance()->getPlaybook()->getFormationNames();
const auto &it = std::find(formationNames.begin(), formationNames.end(), formationName);
if (it != formationNames.end()) {
QMessageBox::StandardButton button =
Expand Down Expand Up @@ -329,7 +330,7 @@ void MainDialog::newPlaybook() {
pbcAssert(name != "");
pbcAssert(playerNumber == 5 || playerNumber == 7 ||
playerNumber == 9 || playerNumber == 11);
PBCPlaybook::getInstance()->resetToNewEmptyPlaybook(name,
PBCController::getInstance()->getPlaybook()->resetToNewEmptyPlaybook(name,
playerNumber);
PBCStorage::getInstance()->init(name);
_playView->resetPlay();
Expand All @@ -343,7 +344,7 @@ void MainDialog::newPlaybook() {
* @brief Saves the playbook persistently to a file after asking for a file name.
*/
void MainDialog::savePlaybookAs() {
std::string stdFile = PBCPlaybook::getInstance()->name() + ".pbc";
std::string stdFile = PBCController::getInstance()->getPlaybook()->name() + ".pbc";
QFileDialog fileDialog(
this, "Save Playbook",
QString::fromStdString(stdFile),
Expand Down Expand Up @@ -396,8 +397,8 @@ void MainDialog::openPlaybook() {
QLineEdit::Password, "", &ok);
if (ok == true) {
try {
PBCStorage::getInstance()->loadPlaybook(password.toStdString(),
fileName.toStdString());
PBCStorage::getInstance()->loadActivePlaybook(password.toStdString(),
fileName.toStdString());
} catch (PBCDecryptionException &e) {
if (decryptionFailureCount < PASSWORD_MAX_RETRYS - 1) {
decryptionFailureCount++;
Expand All @@ -419,6 +420,72 @@ void MainDialog::openPlaybook() {
}
}


/**
* @brief Import a playbook from a file which is specified by an open-dialog.
*/
void MainDialog::importPlaybook() {
QFileDialog fileDialog(this, "Impport Playbook", "",
"PBC Files (*.pbc);;All Files (*.*)");

fileDialog.setFileMode(QFileDialog::ExistingFile);
if (fileDialog.exec() == true) {
QStringList files = fileDialog.selectedFiles();
pbcAssert(files.size() == 1);
QString fileName = files.first();

unsigned int decryptionFailureCount = 0;
while (true) {
bool ok;
std::string msg;
if (decryptionFailureCount == 0) {
msg = "Enter decryption password";
} else {
msg = "Error on decryption. Maybe wrong password. Try again!";
}
QString password = QInputDialog::getText(this, "Import Playbook",
QString::fromStdString(msg),
QLineEdit::Password, "", &ok);
if (ok == true) {
try {
// TODO design dialog to get parameters for playbook importing
PBCStorage::getInstance()->importPlaybook(
password.toStdString(),
fileName.toStdString(),
true,
true,
false,
true,
"imported_");
QMessageBox::information(this,
"Import Playbook",
"Import successful Your playbook has been saved automatically!");
} catch (PBCImportException& e) {
QString msg = e.what();
msg.append("\n\nYou should rename or delete it and try to import again.");
QMessageBox::critical(this, "Import Playbook", msg);
} catch (PBCDecryptionException &e) {
if (decryptionFailureCount < PASSWORD_MAX_RETRYS - 1) {
decryptionFailureCount++;
continue;
} else {
throw e;
}
} catch (PBCDeprecatedVersionException& e) {
QMessageBox::critical(this,
"Import Playbook",
"Cannot load playbook because it's created by a newer version of Playbook-Creator. "
"Please download the latest version of Playbook-Creator!");
}
_playView->resetPlay();
updateTitle(true);
break;
}
}
}
}


/**
* @brief Exports the playbook to a PDF file.
*
Expand All @@ -433,7 +500,7 @@ void MainDialog::exportAsPDF() {
boost::shared_ptr<PBCExportPDFDialog::ReturnStruct> returnStruct(new PBCExportPDFDialog::ReturnStruct()); //NOLINT
boost::shared_ptr<QStringList> playListSP = exportDialog.exec(returnStruct);
if(playListSP != NULL && playListSP->size() > 0) {
std::string stdFile = PBCPlaybook::getInstance()->name() + ".pdf";
std::string stdFile = PBCController::getInstance()->getPlaybook()->name() + ".pdf";
QFileDialog fileDialog(
this, "Export Playbook As PDF",
QString::fromStdString(stdFile),
Expand Down Expand Up @@ -480,7 +547,7 @@ void MainDialog::deleteRoutes() {
if (deleteDialog.exec() == QDialog::Accepted) {
for (const auto &name : *deleteDialog.get_nameList()) {
try {
PBCPlaybook::getInstance()->deleteRoute(name.toStdString());
PBCController::getInstance()->getPlaybook()->deleteRoute(name.toStdString());
} catch (PBCAutoSaveException &e) {
// TODO log message
/* The exception should not really be an issue here. If the playbook has not been saved to file yet,
Expand All @@ -500,7 +567,7 @@ void MainDialog::deletePlays() {
if (deleteDialog.exec() == QDialog::Accepted){
for (const auto& name : *deleteDialog.get_nameList()) {
try {
PBCPlaybook::getInstance()->deletePlay(name.toStdString());
PBCController::getInstance()->getPlaybook()->deletePlay(name.toStdString());
} catch (PBCAutoSaveException &e) {
// TODO log message (see issue #19)
/* The exception should not really be an issue here. If the playbook has not been saved to file yet,
Expand All @@ -519,7 +586,7 @@ void MainDialog::deleteFormations() {
if (deleteDialog.exec() == QDialog::Accepted){
for (const auto& name : *deleteDialog.get_nameList()) {
try {
PBCPlaybook::getInstance()->deleteFormation(name.toStdString());
PBCController::getInstance()->getPlaybook()->deleteFormation(name.toStdString());
} catch (PBCAutoSaveException &e) {
// TODO log message (see issue #19)
/* The exception should not really be an issue here. If the playbook has not been saved to file yet,
Expand All @@ -538,7 +605,7 @@ void MainDialog::deleteCategories() {
if (deleteDialog.exec() == QDialog::Accepted){
for (const auto& name : *deleteDialog.get_nameList()) {
try {
PBCPlaybook::getInstance()->deleteCategory(name.toStdString());
PBCController::getInstance()->getPlaybook()->deleteCategory(name.toStdString());
} catch (PBCAutoSaveException &e) {
// TODO log message (see issue #19)
/* The exception should not really be an issue here. If the playbook has not been saved to file yet,
Expand All @@ -559,3 +626,4 @@ void MainDialog::deleteCategories() {
MainDialog::~MainDialog() {
delete ui;
}

1 change: 1 addition & 0 deletions src/dialogs/mainDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class MainDialog : public QMainWindow {
void newPlaybook();
void savePlaybookAs();
void openPlaybook();
void importPlaybook();
void exportAsPDF();
void showAboutDialog();
void addPlayToCategory();
Expand Down
Loading

0 comments on commit fc28a70

Please sign in to comment.