Skip to content

Commit fc28a70

Browse files
committed
Merge branch 'feature/playbookImport'
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.
2 parents 575efb5 + 8648a2b commit fc28a70

37 files changed

+879
-117
lines changed

.circleci/config.yml

+6-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
- run:
99
name: Install Dependencies
1010
command: |
11-
apt update && apt install -y git build-essential cmake pkg-config qt5-default libboost-serialization-dev libssl-dev python golang-go curl
11+
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
1212
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
1313
- restore_cache:
1414
keys:
@@ -33,6 +33,11 @@ jobs:
3333
command: |
3434
cmake -D BOTAN_LIBRARY=botan/libbotan-2.a -D BOTAN_INCLUDE_DIR=botan/build/include .
3535
make
36+
- run:
37+
name: Test
38+
command: |
39+
make tests
40+
ASAN_OPTIONS=detect_leaks=0 bin/tests -- --test-base-dir "test"
3641
- run:
3742
name: Copy Qt5 shared libaries
3843
command: |

.travis.yml

+15-21
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,25 @@
11
os: osx
22
language: cpp
33
install:
4-
- cmake --version
5-
- brew list git || brew install git
6-
- brew list cmake || brew install cmake
7-
- brew upgrade cmake
8-
- cmake --version
9-
- brew list pkg-config || brew install pkg-config
10-
- brew list qt || brew install qt
11-
- brew list boost || brew install boost
12-
- brew install boost@1.60
13-
- brew unlink boost
14-
- brew link --force boost@1.60
4+
- brew update
5+
- brew list git &>/dev/null || brew install git
6+
- brew list cmake &>/dev/null || brew install cmake
7+
- brew list pkg-config &>/dev/null || brew install pkg-config
8+
- brew list qt &>/dev/null || brew install qt
9+
- brew uninstall --ignore-dependencies boost
10+
- bash ci-scripts/build-boost.sh
11+
- ls boost
12+
- ls boost/lib
1513
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
1614
cache:
1715
directories:
18-
botan
16+
- botan
17+
- boost
1918
script:
20-
- if [[ $SKIP_CACHE_RESTORE == true ]]; then
21-
git clone https://github.com/randombit/botan botan;
22-
cd botan;
23-
git checkout 2.6.0;
24-
python configure.py --disable-shared-library --disable-modules=darwin_secrandom;
25-
make;
26-
cd ..;
27-
fi
28-
- cmake . -DBOTAN_LIBRARY=botan/libbotan-2.a -DBOTAN_INCLUDE_DIR=botan/build/include -DCMAKE_PREFIX_PATH=$(brew --prefix qt5)
19+
- ls botan/
20+
- bash ci-scripts/build-botan.sh
21+
- 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)
2922
- make
23+
- ASAN_OPTIONS=detect_leaks=0 bin/tests -- --test-base-dir "test"
3024
- $(brew --prefix qt5)/bin/macdeployqt bin/PlaybookCreator.app -verbose=3 -dmg -no-strip
3125
- bash deploy.sh bin/PlaybookCreator.dmg PlaybookCreator.dmg "PlaybookCreator for MacOSX" $GITHUB_TOKEN

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ set(PBC_UPDATER_CMAKE_NAME pbc-updater)
3838
add_subdirectory(updater)
3939

4040
add_subdirectory(src)
41+
add_subdirectory(test)
4142

4243

4344
add_custom_target( documentation COMMAND doxygen)

appveyor.yml

+6-5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ environment:
1212
cache:
1313
- C:\projects\botan\botan.lib
1414
- C:\projects\botan\build\include
15+
- C:\Users\appveyor\.cargo
1516

1617
install:
1718
- curl -sSf -o rustup-init.exe https://win.rustup.rs
@@ -32,17 +33,17 @@ before_build:
3233
3334
echo "starting build..."
3435
build:
35-
project: PlaybookCreator.sln
36+
project: ALL_BUILD.vcxproj
3637
verbosity: normal
3738
after_build:
3839
- cmd: >-
3940
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
4041
4142
C:\Qt\5.11\msvc2017_64\bin\windeployqt.exe --release --pdb --compiler-runtime "C:\projects\playbook-creator\bin\Release"
42-
43+
44+
cd bin\Release\ && tests.exe -- --test-base-dir "..\..\test" && cd ..\..
45+
4346
"C:\Program Files (x86)\Inno Setup 5\ISCC" C:\projects\playbook-creator\innosetup.iss
44-
test_script:
45-
- ps: '#$blockRdp = $true; iex ((new-object net.webclient).DownloadString("https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1"))'
4647
artifacts:
4748
- path: bin\release\PlaybookCreator.exe
4849
name: PlaybookCreator.exe
@@ -55,4 +56,4 @@ deploy_script:
5556
bash deploy.sh bin/PlaybookCreatorSetup.exe PlaybookCreatorSetup.exe "PlaybookCreator for Windows" $TOKEN
5657
on_finish:
5758
- ps: >-
58-
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'))}
59+
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'))}

ci-scripts/build-boost.sh

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
if [[ ! -f boost/lib/libboost_serialization.a ]]; then
2+
mkdir boost
3+
curl -O -L https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.gz;
4+
tar -xzf boost_1_66_0.tar.gz;
5+
cd boost_1_66_0;
6+
./bootstrap.sh --with-libraries=serialization,filesystem,test --prefix=../boost
7+
./b2 install link=static runtime-link=static &>/dev/null
8+
cd ..;
9+
fi

ci-scripts/build-botan.sh

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
if [[ ! -f botan/libbotan-2.a ]]; then
2+
echo "hallo"
3+
git clone https://github.com/randombit/botan botan;
4+
cd botan;
5+
git checkout 2.6.0;
6+
python configure.py --disable-shared-library --disable-modules=darwin_secrandom;
7+
make;
8+
cd ..;
9+
fi

src/CMakeLists.txt

+20-16
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ set ( SOURCES
5454
util/pbcSingleton.h
5555
util/pbcStorage.cpp
5656
util/pbcStorage.h
57-
main.cpp
57+
pbcController.cpp
58+
pbcController.h
5859
pbcVersion.h)
5960

6061
set ( MOC_HEADERS
@@ -138,32 +139,35 @@ qt5_wrap_cpp( MOC_SRCS ${MOC_HEADERS} )
138139
# WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tools
139140
#)
140141

141-
# compile
142-
add_executable( ${PROJECT_NAME} ${SOURCES} ${MOC_SRCS} ${UI_HEADERS})
143-
if(APPLE)
144-
set_target_properties(${PROJECT_NAME} PROPERTIES
145-
MACOSX_BUNDLE ON
146-
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/cmake/pbcMacOSXBundleInfo.plist.in)
147-
endif()
148-
#add_dependencies(${PROJECT_NAME} style_checking)
149-
142+
add_library(PBCLib ${SOURCES} ${MOC_SRCS} ${UI_HEADERS})
143+
#add_dependencies(PBCLib style_checking)
150144

151145
# link the updater library
152146
if(WIN32)
153147
find_package(OpenSSL)
154-
target_link_libraries(${PROJECT_NAME} ${PBC_UPDATER_CMAKE_NAME} ws2_32 userenv crypt32 ncrypt schannel Secur32)
148+
target_link_libraries(PBCLib ${PBC_UPDATER_CMAKE_NAME} ws2_32 userenv crypt32 ncrypt schannel Secur32)
155149
elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin")
156150
find_library(SECFW Security)
157151
find_library(COREFW CoreFoundation)
158-
target_link_libraries(${PROJECT_NAME} ${PBC_UPDATER_CMAKE_NAME} resolv ${SECFW} ${COREFW})
152+
target_link_libraries(PBCLib ${PBC_UPDATER_CMAKE_NAME} resolv ${SECFW} ${COREFW})
159153
else()
160-
target_link_libraries(${PROJECT_NAME} ${PBC_UPDATER_CMAKE_NAME} pthread dl ssl crypto) # TODO find out the libs programmatically
154+
target_link_libraries(PBCLib ${PBC_UPDATER_CMAKE_NAME} pthread dl ssl crypto) # TODO find out the libs programmatically
161155
endif()
162156

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

167-
# link libraries
168-
target_link_libraries(${PROJECT_NAME} Qt5::Widgets Qt5::PrintSupport ${Boost_LIBRARIES} ${BOTAN_LIBRARY})
169-
#target_link_libraries(${PROJECT_NAME} ${Qt5Widgets_LIBRARIES} ${Qt5PrintSupport_LIBRARIES} ${Boost_LIBRARIES} ${BOTAN_LIBRARY})
161+
# link external libraries
162+
target_link_libraries(PBCLib Qt5::Widgets Qt5::PrintSupport ${Boost_LIBRARIES} ${BOTAN_LIBRARY})
163+
164+
165+
# link executable
166+
add_executable(${PROJECT_NAME} main.cpp)
167+
target_link_libraries(${PROJECT_NAME} PBCLib)
168+
169+
if(APPLE)
170+
set_target_properties(${PROJECT_NAME} PROPERTIES
171+
MACOSX_BUNDLE ON
172+
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/cmake/pbcMacOSXBundleInfo.plist.in)
173+
endif()

src/dialogs/mainDialog.cpp

+80-12
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
#include "util/pbcConfig.h"
2727
#include "gui/pbcPlayerView.h"
28+
#include "pbcController.h"
2829
#include "models/pbcPlaybook.h"
2930
#include "dialogs/pbcExportPdfDialog.h"
3031
#include "dialogs/pbcDeleteDialog.h"
@@ -116,7 +117,7 @@ void MainDialog::updateTitle(bool saved) {
116117
std::string windowTitle = "Playbook Creator V" +
117118
PBCVersion::getSimpleVersionString() +
118119
" - " +
119-
PBCPlaybook::getInstance()->name();
120+
PBCController::getInstance()->getPlaybook()->name();
120121
if(saved == false) {
121122
windowTitle += "*";
122123
}
@@ -240,7 +241,7 @@ void MainDialog::savePlayAs() {
240241
int returnCode = dialog.exec();
241242
if (returnCode == QDialog::Accepted) {
242243
struct PBCSavePlayAsDialog::ReturnStruct rs = dialog.getReturnStruct();
243-
std::vector<std::string> playNames = PBCPlaybook::getInstance()->getPlayNames();
244+
std::vector<std::string> playNames = PBCController::getInstance()->getPlaybook()->getPlayNames();
244245
const auto& it = std::find(playNames.begin(), playNames.end(), rs.name);
245246
if (it != playNames.end()) {
246247
QMessageBox::StandardButton button =
@@ -289,7 +290,7 @@ void MainDialog::saveFormationAs() {
289290
if (ok == true) {
290291
pbcAssert(qformationname != "");
291292
std::string formationName = qformationname.toStdString();
292-
std::vector<std::string> formationNames = PBCPlaybook::getInstance()->getFormationNames();
293+
std::vector<std::string> formationNames = PBCController::getInstance()->getPlaybook()->getFormationNames();
293294
const auto &it = std::find(formationNames.begin(), formationNames.end(), formationName);
294295
if (it != formationNames.end()) {
295296
QMessageBox::StandardButton button =
@@ -329,7 +330,7 @@ void MainDialog::newPlaybook() {
329330
pbcAssert(name != "");
330331
pbcAssert(playerNumber == 5 || playerNumber == 7 ||
331332
playerNumber == 9 || playerNumber == 11);
332-
PBCPlaybook::getInstance()->resetToNewEmptyPlaybook(name,
333+
PBCController::getInstance()->getPlaybook()->resetToNewEmptyPlaybook(name,
333334
playerNumber);
334335
PBCStorage::getInstance()->init(name);
335336
_playView->resetPlay();
@@ -343,7 +344,7 @@ void MainDialog::newPlaybook() {
343344
* @brief Saves the playbook persistently to a file after asking for a file name.
344345
*/
345346
void MainDialog::savePlaybookAs() {
346-
std::string stdFile = PBCPlaybook::getInstance()->name() + ".pbc";
347+
std::string stdFile = PBCController::getInstance()->getPlaybook()->name() + ".pbc";
347348
QFileDialog fileDialog(
348349
this, "Save Playbook",
349350
QString::fromStdString(stdFile),
@@ -396,8 +397,8 @@ void MainDialog::openPlaybook() {
396397
QLineEdit::Password, "", &ok);
397398
if (ok == true) {
398399
try {
399-
PBCStorage::getInstance()->loadPlaybook(password.toStdString(),
400-
fileName.toStdString());
400+
PBCStorage::getInstance()->loadActivePlaybook(password.toStdString(),
401+
fileName.toStdString());
401402
} catch (PBCDecryptionException &e) {
402403
if (decryptionFailureCount < PASSWORD_MAX_RETRYS - 1) {
403404
decryptionFailureCount++;
@@ -419,6 +420,72 @@ void MainDialog::openPlaybook() {
419420
}
420421
}
421422

423+
424+
/**
425+
* @brief Import a playbook from a file which is specified by an open-dialog.
426+
*/
427+
void MainDialog::importPlaybook() {
428+
QFileDialog fileDialog(this, "Impport Playbook", "",
429+
"PBC Files (*.pbc);;All Files (*.*)");
430+
431+
fileDialog.setFileMode(QFileDialog::ExistingFile);
432+
if (fileDialog.exec() == true) {
433+
QStringList files = fileDialog.selectedFiles();
434+
pbcAssert(files.size() == 1);
435+
QString fileName = files.first();
436+
437+
unsigned int decryptionFailureCount = 0;
438+
while (true) {
439+
bool ok;
440+
std::string msg;
441+
if (decryptionFailureCount == 0) {
442+
msg = "Enter decryption password";
443+
} else {
444+
msg = "Error on decryption. Maybe wrong password. Try again!";
445+
}
446+
QString password = QInputDialog::getText(this, "Import Playbook",
447+
QString::fromStdString(msg),
448+
QLineEdit::Password, "", &ok);
449+
if (ok == true) {
450+
try {
451+
// TODO design dialog to get parameters for playbook importing
452+
PBCStorage::getInstance()->importPlaybook(
453+
password.toStdString(),
454+
fileName.toStdString(),
455+
true,
456+
true,
457+
false,
458+
true,
459+
"imported_");
460+
QMessageBox::information(this,
461+
"Import Playbook",
462+
"Import successful Your playbook has been saved automatically!");
463+
} catch (PBCImportException& e) {
464+
QString msg = e.what();
465+
msg.append("\n\nYou should rename or delete it and try to import again.");
466+
QMessageBox::critical(this, "Import Playbook", msg);
467+
} catch (PBCDecryptionException &e) {
468+
if (decryptionFailureCount < PASSWORD_MAX_RETRYS - 1) {
469+
decryptionFailureCount++;
470+
continue;
471+
} else {
472+
throw e;
473+
}
474+
} catch (PBCDeprecatedVersionException& e) {
475+
QMessageBox::critical(this,
476+
"Import Playbook",
477+
"Cannot load playbook because it's created by a newer version of Playbook-Creator. "
478+
"Please download the latest version of Playbook-Creator!");
479+
}
480+
_playView->resetPlay();
481+
updateTitle(true);
482+
break;
483+
}
484+
}
485+
}
486+
}
487+
488+
422489
/**
423490
* @brief Exports the playbook to a PDF file.
424491
*
@@ -433,7 +500,7 @@ void MainDialog::exportAsPDF() {
433500
boost::shared_ptr<PBCExportPDFDialog::ReturnStruct> returnStruct(new PBCExportPDFDialog::ReturnStruct()); //NOLINT
434501
boost::shared_ptr<QStringList> playListSP = exportDialog.exec(returnStruct);
435502
if(playListSP != NULL && playListSP->size() > 0) {
436-
std::string stdFile = PBCPlaybook::getInstance()->name() + ".pdf";
503+
std::string stdFile = PBCController::getInstance()->getPlaybook()->name() + ".pdf";
437504
QFileDialog fileDialog(
438505
this, "Export Playbook As PDF",
439506
QString::fromStdString(stdFile),
@@ -480,7 +547,7 @@ void MainDialog::deleteRoutes() {
480547
if (deleteDialog.exec() == QDialog::Accepted) {
481548
for (const auto &name : *deleteDialog.get_nameList()) {
482549
try {
483-
PBCPlaybook::getInstance()->deleteRoute(name.toStdString());
550+
PBCController::getInstance()->getPlaybook()->deleteRoute(name.toStdString());
484551
} catch (PBCAutoSaveException &e) {
485552
// TODO log message
486553
/* The exception should not really be an issue here. If the playbook has not been saved to file yet,
@@ -500,7 +567,7 @@ void MainDialog::deletePlays() {
500567
if (deleteDialog.exec() == QDialog::Accepted){
501568
for (const auto& name : *deleteDialog.get_nameList()) {
502569
try {
503-
PBCPlaybook::getInstance()->deletePlay(name.toStdString());
570+
PBCController::getInstance()->getPlaybook()->deletePlay(name.toStdString());
504571
} catch (PBCAutoSaveException &e) {
505572
// TODO log message (see issue #19)
506573
/* The exception should not really be an issue here. If the playbook has not been saved to file yet,
@@ -519,7 +586,7 @@ void MainDialog::deleteFormations() {
519586
if (deleteDialog.exec() == QDialog::Accepted){
520587
for (const auto& name : *deleteDialog.get_nameList()) {
521588
try {
522-
PBCPlaybook::getInstance()->deleteFormation(name.toStdString());
589+
PBCController::getInstance()->getPlaybook()->deleteFormation(name.toStdString());
523590
} catch (PBCAutoSaveException &e) {
524591
// TODO log message (see issue #19)
525592
/* The exception should not really be an issue here. If the playbook has not been saved to file yet,
@@ -538,7 +605,7 @@ void MainDialog::deleteCategories() {
538605
if (deleteDialog.exec() == QDialog::Accepted){
539606
for (const auto& name : *deleteDialog.get_nameList()) {
540607
try {
541-
PBCPlaybook::getInstance()->deleteCategory(name.toStdString());
608+
PBCController::getInstance()->getPlaybook()->deleteCategory(name.toStdString());
542609
} catch (PBCAutoSaveException &e) {
543610
// TODO log message (see issue #19)
544611
/* The exception should not really be an issue here. If the playbook has not been saved to file yet,
@@ -559,3 +626,4 @@ void MainDialog::deleteCategories() {
559626
MainDialog::~MainDialog() {
560627
delete ui;
561628
}
629+

src/dialogs/mainDialog.h

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class MainDialog : public QMainWindow {
5757
void newPlaybook();
5858
void savePlaybookAs();
5959
void openPlaybook();
60+
void importPlaybook();
6061
void exportAsPDF();
6162
void showAboutDialog();
6263
void addPlayToCategory();

0 commit comments

Comments
 (0)