Version 2.0 of the minimpy desktop application
修訂 | 55046a26d22499c8b3f9dc14935b30858870eb58 (tree) |
---|---|
時間 | 2022-02-21 23:15:24 |
作者 | Mahmoud Saghaei <mahmood.saghaei@gmai...> |
Commiter | Mahmoud Saghaei |
File system path for statndalone version
@@ -7,7 +7,8 @@ block_cipher = None | ||
7 | 7 | a = Analysis(['main_window.py'], |
8 | 8 | pathex=['/home/msaghaei/PycharmProjects/minimpy2'], |
9 | 9 | binaries=[], |
10 | - datas=[], | |
10 | + datas=[('db/database.sql', 'db'), ('images/*', 'images'), ('locales/*', 'locales'), ('fa_IR.ts', '.'), | |
11 | + ('minimisation_*.txt', '.'), ('start_*.html', '.'), ('locale_sources.ts', '.')], | |
11 | 12 | hiddenimports=[], |
12 | 13 | hookspath=[], |
13 | 14 | runtime_hooks=[], |
@@ -2,6 +2,7 @@ from PySide2 import QtWidgets as qtw | ||
2 | 2 | from os import path |
3 | 3 | |
4 | 4 | from ui_about_minimisation import Ui_AboutMinimisationDialog |
5 | +from utils import resource_path | |
5 | 6 | |
6 | 7 | |
7 | 8 | class AboutMinimisationDialog(qtw.QDialog): |
@@ -10,9 +11,9 @@ class AboutMinimisationDialog(qtw.QDialog): | ||
10 | 11 | self.ui = Ui_AboutMinimisationDialog() |
11 | 12 | self.ui.setupUi(self) |
12 | 13 | lang = parent.settings.value('language', 'en_US', type=str) |
13 | - filename = 'minimisation_{}.txt'.format(lang) | |
14 | + filename = resource_path('minimisation_{}.txt'.format(lang)) | |
14 | 15 | if not path.exists(filename): |
15 | - filename = 'minimisation_en_US.txt' | |
16 | + filename = resource_path('minimisation_en_US.txt') | |
16 | 17 | if not path.exists(filename): |
17 | 18 | return |
18 | 19 | text = open(filename, encoding='utf8').read() |
@@ -3,6 +3,7 @@ import sys | ||
3 | 3 | from PySide2 import QtWidgets as qtw |
4 | 4 | |
5 | 5 | from config_dialog import Ui_ConfigDialog |
6 | +from utils import resource_path | |
6 | 7 | |
7 | 8 | |
8 | 9 | class Config(qtw.QDialog): |
@@ -11,7 +12,7 @@ class Config(qtw.QDialog): | ||
11 | 12 | self.parent = parent |
12 | 13 | self.ui = Ui_ConfigDialog() |
13 | 14 | self.ui.setupUi(self) |
14 | - lines = open('locales/languages.lst', encoding='utf8').readlines() | |
15 | + lines = open(resource_path('locales/languages.lst'), encoding='utf8').readlines() | |
15 | 16 | self.lang_codes = [] |
16 | 17 | cur_lang = self.parent.settings.value('language', 'en_US', type=str) |
17 | 18 | cur_index = 0 |
@@ -1,12 +1,16 @@ | ||
1 | -from PySide2 import QtSql as qts | |
1 | +from PySide2 import QtSql as qts, QtWidgets | |
2 | 2 | from PySide2 import QtWidgets as qtw |
3 | 3 | from PySide2 import QtCore as qtc |
4 | 4 | |
5 | 5 | import sys |
6 | 6 | import os |
7 | +from os import path | |
7 | 8 | |
8 | 9 | |
9 | 10 | # noinspection PyTypeChecker |
11 | +from utils import resource_path | |
12 | + | |
13 | + | |
10 | 14 | class Database(qtc.QObject): |
11 | 15 | __instance = None |
12 | 16 |
@@ -26,7 +30,7 @@ class Database(qtc.QObject): | ||
26 | 30 | 'open db: ' + self.db.lastError().text() |
27 | 31 | ) |
28 | 32 | sys.exit(1) |
29 | - all_sqls = open('db/database.sql', encoding='utf8').read().split(';') | |
33 | + all_sqls = open(resource_path('db/database.sql'), encoding='utf8').read().split(';') | |
30 | 34 | for sql in all_sqls: |
31 | 35 | query = qts.QSqlQuery(self.db) |
32 | 36 | query.prepare(sql) |
@@ -43,8 +47,16 @@ class Database(qtc.QObject): | ||
43 | 47 | raise Exception("This class is a singleton!") |
44 | 48 | self.mainWindow = mainWindow |
45 | 49 | self.db = qts.QSqlDatabase.addDatabase('QSQLITE') |
46 | - self.db.setDatabaseName('db/minimizer.db') | |
47 | - if not os.path.exists('db/minimizer.db'): | |
50 | + db_path = mainWindow.settings.value('db_path', None, type=str) | |
51 | + if db_path is None or not path.exists(db_path): | |
52 | + db_path = QtWidgets.QFileDialog.getExistingDirectory(mainWindow, 'Select a folder to store your data', '.', QtWidgets.QFileDialog.ShowDirsOnly) | |
53 | + if db_path is None or len(db_path.strip()) == 0: | |
54 | + exit(1) | |
55 | + mainWindow.settings.setValue('db_path', db_path) | |
56 | + if not path.exists(db_path): | |
57 | + os.mkdir(db_path) | |
58 | + self.db.setDatabaseName('{}/minimizer.db'.format(db_path)) | |
59 | + if not os.path.exists('{}/minimizer.db'.format(db_path)): | |
48 | 60 | self.create_db() |
49 | 61 | else: |
50 | 62 | if not self.db.open(): |
@@ -954,6 +954,7 @@ Click and then type over the trial title or code to edit it</source> | ||
954 | 954 | <message> |
955 | 955 | <location filename="main_window.py" line="37"/> |
956 | 956 | <source>Type of subject identifier. It can be Numeric, Alpha or Alphanumeric. |
957 | +Once a subject is enrolled, you can not change identifier type | |
957 | 958 | </source> |
958 | 959 | <translation>نوع شناسه نمایش داده شده برای سوژه ها. گزینه های موجود عددی، حرفی و یا حرفی عددی می باشند.\nهنگامی که اولین سوژه وارده مطالعه شد، دیگر نمی توان نوع شناسه را تغییر دارد |
959 | 960 | </translation> |
@@ -3,6 +3,8 @@ from PySide2 import QtWidgets as qtw | ||
3 | 3 | from PySide2 import QtCore as qtc |
4 | 4 | from PySide2 import QtGui as qtg |
5 | 5 | |
6 | +from utils import resource_path | |
7 | + | |
6 | 8 | |
7 | 9 | class FreqTable: |
8 | 10 | def __init__(self, parent, ui, trial_id): |
@@ -30,11 +32,11 @@ class FreqTable: | ||
30 | 32 | return |
31 | 33 | preload = self.extract_counts() |
32 | 34 | if self.valid_counts(preload): |
33 | - pixmap = qtg.QPixmap("images/tick_mark.png") | |
35 | + pixmap = qtg.QPixmap(resource_path("images/tick_mark.png")) | |
34 | 36 | self.database.clear_preload(self.trial_id) |
35 | 37 | self.database.save_preload(self.trial_id, preload) |
36 | 38 | else: |
37 | - pixmap = qtg.QPixmap("images/error.png") | |
39 | + pixmap = qtg.QPixmap(resource_path("images/error.png")) | |
38 | 40 | self.valid_preload_image.setPixmap(pixmap) |
39 | 41 | |
40 | 42 | def add_to_preload(self): |
@@ -18,6 +18,8 @@ from run_test import RunTest | ||
18 | 18 | from trial import * |
19 | 19 | import sys |
20 | 20 | from tendo import singleton |
21 | +from utils import resource_path | |
22 | + | |
21 | 23 | |
22 | 24 | # noinspection PyTypeChecker |
23 | 25 | class MainWindow(qtw.QMainWindow): |
@@ -57,17 +59,19 @@ class MainWindow(qtw.QMainWindow): | ||
57 | 59 | self.ui = Ui_MainWindow() |
58 | 60 | self.ui.setupUi(self) |
59 | 61 | lang = settings.value('language', 'en_US', type=str) |
60 | - filename = 'start_{}.html'.format(lang) | |
62 | + if lang != 'en_US': | |
63 | + self.setLayoutDirection(qtc.Qt.RightToLeft) | |
64 | + filename = resource_path('start_{}.html'.format(lang)) | |
61 | 65 | start_str = open(filename, encoding='utf8').read() |
62 | 66 | self.ui.textEdit.setHtml(start_str) |
63 | - self.ui.actionNew.setIcon(qtg.QIcon('images/add.png')) | |
64 | - self.ui.actionDelete.setIcon(qtg.QIcon('images/delete.png')) | |
65 | - self.ui.actionLevels.setIcon(qtg.QIcon('images/levels.png')) | |
66 | - self.ui.actionSave.setIcon(qtg.QIcon('images/save.png')) | |
67 | - self.ui.actionHelp.setIcon(qtg.QIcon('images/help.png')) | |
68 | - self.ui.actionQuit.setIcon(qtg.QIcon('images/exit.png')) | |
69 | - self.ui.actionConfig.setIcon(qtg.QIcon('images/config.png')) | |
70 | - self.ui.actionAbout_MinimPy2.setIcon(qtg.QIcon('images/about.png')) | |
67 | + self.ui.actionNew.setIcon(qtg.QIcon(resource_path('images/add.png'))) | |
68 | + self.ui.actionDelete.setIcon(qtg.QIcon(resource_path('images/delete.png'))) | |
69 | + self.ui.actionLevels.setIcon(qtg.QIcon(resource_path('images/levels.png'))) | |
70 | + self.ui.actionSave.setIcon(qtg.QIcon(resource_path('images/save.png'))) | |
71 | + self.ui.actionHelp.setIcon(qtg.QIcon(resource_path('images/help.png'))) | |
72 | + self.ui.actionQuit.setIcon(qtg.QIcon(resource_path('images/exit.png'))) | |
73 | + self.ui.actionConfig.setIcon(qtg.QIcon(resource_path('images/config.png'))) | |
74 | + self.ui.actionAbout_MinimPy2.setIcon(qtg.QIcon(resource_path('images/about.png'))) | |
71 | 75 | self.database = Database.get_instance(self) |
72 | 76 | self.trial = None |
73 | 77 |
@@ -117,8 +121,8 @@ class MainWindow(qtw.QMainWindow): | ||
117 | 121 | |
118 | 122 | self.ui.editPreloadCheckBox.toggled.connect(self.on_edit_preload) |
119 | 123 | self.ui.convertPreloadButton.clicked.connect(self.on_convert_preload) |
120 | - self.ui.factorTableWidget.cellDoubleClicked.connect(self.factor_coloumn_dblclicked) | |
121 | - self.ui.subjectTableWidget.cellDoubleClicked.connect(self.subject_coloumn_dblclicked) | |
124 | + self.ui.factorTableWidget.cellDoubleClicked.connect(self.factor_column_dblclicked) | |
125 | + self.ui.subjectTableWidget.cellDoubleClicked.connect(self.subject_column_dblclicked) | |
122 | 126 | |
123 | 127 | self.ui.trialIdentifierLengthSpinBox.valueChanged.connect(self.on_identifier_length) |
124 | 128 | self.ui.trialBaseProbabilitySlider.valueChanged.connect(self.on_base_prob_change) |
@@ -174,6 +178,10 @@ class MainWindow(qtw.QMainWindow): | ||
174 | 178 | self.ui.showAtStartCheckBox.setChecked(True) |
175 | 179 | self.ui.showAtStartCheckBox.toggled.connect(self.toggle_show_at_start) |
176 | 180 | |
181 | + def on_identifier_length(self, value): | |
182 | + self.trial.identifier_length = value | |
183 | + self.update_sample_size_label() | |
184 | + | |
177 | 185 | def toggle_show_at_start(self, check): |
178 | 186 | self.settings.setValue('show_tutorial_at_start', not check) |
179 | 187 |
@@ -241,7 +249,7 @@ class MainWindow(qtw.QMainWindow): | ||
241 | 249 | def on_base_prob_change(self, value): |
242 | 250 | self.ui.baseProbLabel.setText('{:4.2f}'.format(value / 100.0)) |
243 | 251 | |
244 | - def on_identifier_length(self, value): | |
252 | + def on_idenqdialogbuttonboxtifier_length(self, value): | |
245 | 253 | self.trial.identifier_length = value |
246 | 254 | self.update_sample_size_label() |
247 | 255 |
@@ -367,7 +375,7 @@ class MainWindow(qtw.QMainWindow): | ||
367 | 375 | return |
368 | 376 | self.update_subjects_progress() |
369 | 377 | |
370 | - def subject_coloumn_dblclicked(self, row, col): | |
378 | + def subject_column_dblclicked(self, row, col): | |
371 | 379 | button = qtw.QMessageBox.question(self, self.tr("Warning"), |
372 | 380 | self.tr('''Are you sure you want to edit subject at row "{}" ?\n |
373 | 381 | Editing subject may invalidate your research and the result of minimisation''').format(row), |
@@ -1014,7 +1022,7 @@ ALL subjects will be deleted'''), | ||
1014 | 1022 | self.add_factor_row(factor) |
1015 | 1023 | self.ui.factorTableWidget.blockSignals(False) |
1016 | 1024 | |
1017 | - def factor_coloumn_dblclicked(self, row, col): | |
1025 | + def factor_column_dblclicked(self, row, col): | |
1018 | 1026 | if col != 2: |
1019 | 1027 | return |
1020 | 1028 | self.factor_levels() |
@@ -1264,12 +1272,12 @@ def start_app(): | ||
1264 | 1272 | app = qtw.QApplication(sys.argv) |
1265 | 1273 | except RuntimeError: |
1266 | 1274 | app = qtc.QCoreApplication.instance() |
1267 | - app.setWindowIcon(qtg.QIcon('images/logo.png')) | |
1275 | + app.setWindowIcon(qtg.QIcon(resource_path('images/logo.png'))) | |
1268 | 1276 | settings = qtc.QSettings('net.saghaei', 'minimpy2') |
1269 | 1277 | lang = settings.value('language', 'en_US', type=str) |
1270 | 1278 | if lang != 'en_US': |
1271 | 1279 | translator = qtc.QTranslator() |
1272 | - translator.load('locales/{}'.format(lang)) | |
1280 | + translator.load(resource_path('locales/{}'.format(lang))) | |
1273 | 1281 | app.installTranslator(translator) |
1274 | 1282 | mw = MainWindow(settings) |
1275 | 1283 | app.mainWindow = mw |
@@ -4,6 +4,7 @@ import sys | ||
4 | 4 | |
5 | 5 | class RunTest: |
6 | 6 | def __init__(self, sequence, v1, v2): |
7 | + #sequence = [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1] | |
7 | 8 | self.sequence = sequence |
8 | 9 | self.v1, self.v2 = v1, v2 |
9 | 10 |
@@ -0,0 +1,9 @@ | ||
1 | +ایرادات | |
2 | +MinimPy2 | |
3 | +تغییر عنوان بلافاصله نشان داده نمی شود | |
4 | + | |
5 | +تعداد سوژه های وارد شده در Progressbar بروزرسانی نمیشود | |
6 | + | |
7 | +فیلترها در صفحه سوژه ها بصورت منو باشد | |
8 | + | |
9 | +تولید لیست رندومیزه |
@@ -18,7 +18,7 @@ | ||
18 | 18 | <item> |
19 | 19 | <widget class="QTabWidget" name="tabWidget"> |
20 | 20 | <property name="currentIndex"> |
21 | - <number>7</number> | |
21 | + <number>1</number> | |
22 | 22 | </property> |
23 | 23 | <widget class="QWidget" name="tab"> |
24 | 24 | <attribute name="title"> |
@@ -406,8 +406,8 @@ | ||
406 | 406 | <rect> |
407 | 407 | <x>0</x> |
408 | 408 | <y>0</y> |
409 | - <width>760</width> | |
410 | - <height>422</height> | |
409 | + <width>98</width> | |
410 | + <height>28</height> | |
411 | 411 | </rect> |
412 | 412 | </property> |
413 | 413 | <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0"> |
@@ -0,0 +1,12 @@ | ||
1 | +import sys | |
2 | +import os | |
3 | + | |
4 | + | |
5 | +def resource_path(relative_path): | |
6 | + """ Get absolute path to resource, works for dev and for PyInstaller """ | |
7 | + try: | |
8 | + # PyInstaller creates a temp folder and stores path in _MEIPASS | |
9 | + base_path = sys._MEIPASS | |
10 | + except Exception: | |
11 | + base_path = os.path.abspath(".") | |
12 | + return os.path.join(base_path, relative_path) |