From 647978ed6834801a4abe8e8167ea1d44fc7dd53a Mon Sep 17 00:00:00 2001 From: Denis Tereshkin Date: Wed, 12 Dec 2018 21:35:17 +0700 Subject: [PATCH] Data source management --- build_ui.sh | 6 +- src/nailab/data/csvfolderdatasource.py | 9 ++ src/nailab/data/datasourcemanager.py | 22 ++- src/nailab/ui/csvdatasourceconfigwidget.py | 19 +++ src/nailab/ui/mainwindow.py | 7 +- src/nailab/ui/newdatasourcedialog.py | 24 +++ src/nailab/ui/strategywidget.py | 54 +++++-- .../ui_gen/csvdatasourceconfigwidget.py | 48 ++++++ src/nailab/ui_gen/mainwindow.py.py | 77 ++++++++++ src/nailab/ui_gen/newdatasourcedialog.py | 60 ++++++++ src/nailab/ui_gen/strategywidget.py | 30 +++- ui/csvdatasourceconfigwidget.ui | 84 +++++++++++ ui/mainwindow.ui | 2 +- ui/newdatasourcedialog.ui | 106 +++++++++++++ ui/strategywidget.ui | 140 ++++++++++++++++-- 15 files changed, 655 insertions(+), 33 deletions(-) create mode 100644 src/nailab/ui/csvdatasourceconfigwidget.py create mode 100644 src/nailab/ui/newdatasourcedialog.py create mode 100644 src/nailab/ui_gen/csvdatasourceconfigwidget.py create mode 100644 src/nailab/ui_gen/mainwindow.py.py create mode 100644 src/nailab/ui_gen/newdatasourcedialog.py create mode 100644 ui/csvdatasourceconfigwidget.ui create mode 100644 ui/newdatasourcedialog.ui diff --git a/build_ui.sh b/build_ui.sh index f9351b9..639c88f 100755 --- a/build_ui.sh +++ b/build_ui.sh @@ -1,4 +1,8 @@ #!/bin/bash -/usr/bin/pyuic5 ui/mainwindow.ui > src/nailab/ui_gen/mainwindow.py +/usr/bin/pyuic5 ui/csvdatasourceconfigwidget.ui > src/nailab/ui_gen/csvdatasourceconfigwidget.py +/usr/bin/pyuic5 ui/mainwindow.ui > src/nailab/ui_gen/mainwindow.py.py +/usr/bin/pyuic5 ui/newdatasourcedialog.ui > src/nailab/ui_gen/newdatasourcedialog.py /usr/bin/pyuic5 ui/strategywidget.ui > src/nailab/ui_gen/strategywidget.py + + diff --git a/src/nailab/data/csvfolderdatasource.py b/src/nailab/data/csvfolderdatasource.py index d458eb8..a11e0de 100644 --- a/src/nailab/data/csvfolderdatasource.py +++ b/src/nailab/data/csvfolderdatasource.py @@ -11,10 +11,19 @@ class CsvFolderDataSource(DataSource): def __init__(self, name, path): super().__init__(name) + self.type = "csv" + self.path = path self.feeds = [] self._discover_feeds() + @classmethod + def deserialize(self, data): + return CsvFolderDataSource(data[0], data[1]) + + def serialize(self): + return (self.name, self.path) + def available_feeds(self): return [f[1] for f in self.feeds] diff --git a/src/nailab/data/datasourcemanager.py b/src/nailab/data/datasourcemanager.py index 8e26855..6d4819f 100644 --- a/src/nailab/data/datasourcemanager.py +++ b/src/nailab/data/datasourcemanager.py @@ -6,11 +6,19 @@ class DataSourceManager: def __init__(self): self.sources = [] - def save_sources(self): - pass + def save_sources(self, settings): + serialized = [] + for source in self.sources: + serialized.append((source.type, source.serialize())) + settings.setValue("data_sources", serialized) - def load_sources(self): - self.add_source(CsvFolderDataSource('default', '/tmp')) + def load_sources(self, settings): + self.sources = [] + serialized = settings.value("data_sources") + if serialized is not None: + for s in serialized: + if s[0] == "csv": + self.add_source(CsvFolderDataSource.deserialize(s[1])) def add_source(self, source): self.sources.append(source) @@ -21,6 +29,12 @@ class DataSourceManager: return source return None + def remove_source(self, name): + for source in self.sources: + if source.name == name: + self.sources.remove(source) + return + def all_sources(self): return self.sources[:] diff --git a/src/nailab/ui/csvdatasourceconfigwidget.py b/src/nailab/ui/csvdatasourceconfigwidget.py new file mode 100644 index 0000000..1ed91a8 --- /dev/null +++ b/src/nailab/ui/csvdatasourceconfigwidget.py @@ -0,0 +1,19 @@ + +from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5.Qsci import * + +from ui_gen.csvdatasourceconfigwidget import Ui_CSVDataSourceConfigWidget + +class CSVDataSourceConfigWidget(QtWidgets.QWidget): + + def __init__(self, parent=None): + super().__init__(parent) + + self.ui = Ui_CSVDataSourceConfigWidget() + self.ui.setupUi(self) + + def browse(self): + dirname = QtWidgets.QFileDialog.getExistingDirectory(self, self.tr("Select a directory..."), "", QtWidgets.QFileDialog.ShowDirsOnly) + if dirname != "": + self.ui.e_path.setText(dirname) + diff --git a/src/nailab/ui/mainwindow.py b/src/nailab/ui/mainwindow.py index ee2b6f3..989fb06 100644 --- a/src/nailab/ui/mainwindow.py +++ b/src/nailab/ui/mainwindow.py @@ -23,7 +23,7 @@ class MainWindow(QtWidgets.QMainWindow): self.sources = [] self.datasourcemanager = DataSourceManager() - self.datasourcemanager.load_sources() + self.datasourcemanager.load_sources(QtCore.QSettings()) self.ui = Ui_MainWindow() self.ui.setupUi(self) @@ -62,16 +62,15 @@ class MainWindow(QtWidgets.QMainWindow): try: selected_feeds.append(self.datasourcemanager.get_source(source_id).get_feed(feed_id)) except e: - print('Error: ' + str(e)) + self.ui.tabs.currentWidget().setError("Error: " + str(e)) try: result = executor.execute_from_file(source_file, selected_feeds, self.ui.tabs.currentWidget().get_time_window()) print(result) self.ui.tabs.currentWidget().set_result(result) except Exception as e: - print(e) + self.ui.tabs.currentWidget().setError(str(e)) - def tabCloseRequested(self, tab_index): del self.sources[tab_index] self.ui.tabs.widget(tab_index).save_state() diff --git a/src/nailab/ui/newdatasourcedialog.py b/src/nailab/ui/newdatasourcedialog.py new file mode 100644 index 0000000..d55ad2e --- /dev/null +++ b/src/nailab/ui/newdatasourcedialog.py @@ -0,0 +1,24 @@ + +from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5.Qsci import * + +from ui_gen.newdatasourcedialog import Ui_NewDataSourceDialog +from ui.csvdatasourceconfigwidget import CSVDataSourceConfigWidget + +from data.csvfolderdatasource import CsvFolderDataSource + +class NewDataSourceDialog(QtWidgets.QDialog): + + def __init__(self, parent): + super().__init__(parent) + + self.ui = Ui_NewDataSourceDialog() + self.ui.setupUi(self) + + index = self.ui.widgets.addWidget(CSVDataSourceConfigWidget()) + self.ui.widgets.setCurrentIndex(index) + + def get_data_source(self): + return CsvFolderDataSource(self.ui.e_sourceName.text(), self.ui.widgets.currentWidget().ui.e_path.text()) + + diff --git a/src/nailab/ui/strategywidget.py b/src/nailab/ui/strategywidget.py index 97b7b95..bcb4e12 100644 --- a/src/nailab/ui/strategywidget.py +++ b/src/nailab/ui/strategywidget.py @@ -4,6 +4,8 @@ from PyQt5.Qsci import * from ui_gen.strategywidget import Ui_StrategyWidget +from ui.newdatasourcedialog import NewDataSourceDialog + ROLE_FEED_ID = QtCore.Qt.UserRole + 1 class StrategyWidget(QtWidgets.QWidget): @@ -16,7 +18,10 @@ class StrategyWidget(QtWidgets.QWidget): self.source_file = source_file + s = QtCore.QSettings() + self.datasourcemanager = datasourcemanager + self.datasourcemanager.load_sources(s) self.update_feeds_list() self.ui.splitter.setSizes([20, 80]) @@ -37,20 +42,49 @@ class StrategyWidget(QtWidgets.QWidget): self.result = [] self.result_widget = None - s = QtCore.QSettings() - if s.value("time_window") is not None: - (from_time, to_time) = s.value("time_window") - self.ui.rb_timeWindow.setChecked(True) - self.ui.dte_from.setDateTime(from_time) - self.ui.dte_to.setDateTime(to_time) + try: + if s.value("time_window") is not None: + (from_time, to_time) = s.value("time_window") + self.ui.rb_timeWindow.setChecked(True) + self.ui.dte_from.setDateTime(from_time) + self.ui.dte_to.setDateTime(to_time) + + self.ui.splitter.restoreState(s.value("strategy_widget_splitter_state")) + self.ui.splitter_editor.restoreState(s.value("strategy_widget_splitter_editor_state")) + + except Exception as e: + print("Exception: ", e) + + def addDataSource(self): + dlg = NewDataSourceDialog(self) + if dlg.exec() == QtWidgets.QDialog.Accepted: + self.datasourcemanager.add_source(dlg.get_data_source()) + self.update_feeds_list() + + def deleteDataSource(self): + selected = self.ui.tw_feeds.selectedItems() + for s in selected: + if self.ui.tw_feeds.indexOfTopLevelItem(s) >= 0: + name = s.data(0, ROLE_FEED_ID) + if name is not None: + self.datasourcemanager.remove_source(name[0]) + self.update_feeds_list() + + def refreshDataSources(self): + self.update_feeds_list() def save_state(self): s = QtCore.QSettings() + self.datasourcemanager.save_sources(s) if self.ui.rb_allData.isChecked(): s.setValue("time_window", None) else: s.setValue("time_window", (self.ui.dte_from.dateTime(), self.ui.dte_to.dateTime())) + s.setValue("strategy_widget_splitter_state", self.ui.splitter.saveState()) + s.setValue("strategy_widget_splitter_editor_state", self.ui.splitter_editor.saveState()) + + def save(self): with open(self.source_file, "w") as f: f.write(self.ui.editor.text()) @@ -62,11 +96,12 @@ class StrategyWidget(QtWidgets.QWidget): return (self.ui.dte_from.dateTime(), self.ui.dte_to.dateTime()) def update_feeds_list(self): + self.ui.tw_feeds.clear() sources = self.datasourcemanager.all_sources() for source in sources: src_item = QtWidgets.QTreeWidgetItem(self.ui.tw_feeds) src_item.setText(0, source.name) - src_item.setData(0, ROLE_FEED_ID, "") + src_item.setData(0, ROLE_FEED_ID, (source.name, "")) for feed in source.available_feeds(): feed_item = QtWidgets.QTreeWidgetItem(src_item) feed_item.setText(0, feed) @@ -155,6 +190,7 @@ class StrategyWidget(QtWidgets.QWidget): self.result_widget.resizeColumnToContents(0) - - + def setError(self, errmsg): + self.ui.te_notes.clear() + self.ui.te_notes.appendPlainText(errmsg) diff --git a/src/nailab/ui_gen/csvdatasourceconfigwidget.py b/src/nailab/ui_gen/csvdatasourceconfigwidget.py new file mode 100644 index 0000000..940fac6 --- /dev/null +++ b/src/nailab/ui_gen/csvdatasourceconfigwidget.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'ui/csvdatasourceconfigwidget.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_CSVDataSourceConfigWidget(object): + def setupUi(self, CSVDataSourceConfigWidget): + CSVDataSourceConfigWidget.setObjectName("CSVDataSourceConfigWidget") + CSVDataSourceConfigWidget.resize(529, 313) + self.gridLayout = QtWidgets.QGridLayout(CSVDataSourceConfigWidget) + self.gridLayout.setObjectName("gridLayout") + self.label = QtWidgets.QLabel(CSVDataSourceConfigWidget) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 0, 0, 1, 1) + self.e_path = QtWidgets.QLineEdit(CSVDataSourceConfigWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.e_path.sizePolicy().hasHeightForWidth()) + self.e_path.setSizePolicy(sizePolicy) + self.e_path.setObjectName("e_path") + self.gridLayout.addWidget(self.e_path, 0, 1, 1, 1) + self.b_browse = QtWidgets.QPushButton(CSVDataSourceConfigWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.b_browse.sizePolicy().hasHeightForWidth()) + self.b_browse.setSizePolicy(sizePolicy) + self.b_browse.setObjectName("b_browse") + self.gridLayout.addWidget(self.b_browse, 0, 2, 1, 1) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout.addItem(spacerItem, 1, 0, 1, 1) + + self.retranslateUi(CSVDataSourceConfigWidget) + self.b_browse.clicked.connect(CSVDataSourceConfigWidget.browse) + QtCore.QMetaObject.connectSlotsByName(CSVDataSourceConfigWidget) + + def retranslateUi(self, CSVDataSourceConfigWidget): + _translate = QtCore.QCoreApplication.translate + CSVDataSourceConfigWidget.setWindowTitle(_translate("CSVDataSourceConfigWidget", "Form")) + self.label.setText(_translate("CSVDataSourceConfigWidget", "CSV folder path")) + self.b_browse.setText(_translate("CSVDataSourceConfigWidget", "...")) + diff --git a/src/nailab/ui_gen/mainwindow.py.py b/src/nailab/ui_gen/mainwindow.py.py new file mode 100644 index 0000000..3f05536 --- /dev/null +++ b/src/nailab/ui_gen/mainwindow.py.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'ui/mainwindow.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(1060, 587) + self.centralwidget = QtWidgets.QWidget(MainWindow) + self.centralwidget.setObjectName("centralwidget") + self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) + self.gridLayout.setContentsMargins(3, 3, 3, 3) + self.gridLayout.setObjectName("gridLayout") + self.tabs = QtWidgets.QTabWidget(self.centralwidget) + self.tabs.setTabsClosable(True) + self.tabs.setObjectName("tabs") + self.gridLayout.addWidget(self.tabs, 0, 0, 1, 1) + MainWindow.setCentralWidget(self.centralwidget) + self.menubar = QtWidgets.QMenuBar(MainWindow) + self.menubar.setGeometry(QtCore.QRect(0, 0, 1060, 19)) + self.menubar.setObjectName("menubar") + self.menuFile = QtWidgets.QMenu(self.menubar) + self.menuFile.setObjectName("menuFile") + self.menuBacktest = QtWidgets.QMenu(self.menubar) + self.menuBacktest.setObjectName("menuBacktest") + MainWindow.setMenuBar(self.menubar) + self.statusbar = QtWidgets.QStatusBar(MainWindow) + self.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(self.statusbar) + self.toolBar = QtWidgets.QToolBar(MainWindow) + self.toolBar.setObjectName("toolBar") + MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar) + self.actionOpenTrades = QtWidgets.QAction(MainWindow) + self.actionOpenTrades.setObjectName("actionOpenTrades") + self.actionNew_strategy = QtWidgets.QAction(MainWindow) + self.actionNew_strategy.setObjectName("actionNew_strategy") + self.actionOpen_strategy = QtWidgets.QAction(MainWindow) + self.actionOpen_strategy.setObjectName("actionOpen_strategy") + self.actionExecute = QtWidgets.QAction(MainWindow) + self.actionExecute.setObjectName("actionExecute") + self.actionSave_strategy = QtWidgets.QAction(MainWindow) + self.actionSave_strategy.setObjectName("actionSave_strategy") + self.menuFile.addAction(self.actionNew_strategy) + self.menuFile.addAction(self.actionOpen_strategy) + self.menuBacktest.addAction(self.actionExecute) + self.menubar.addAction(self.menuFile.menuAction()) + self.menubar.addAction(self.menuBacktest.menuAction()) + self.toolBar.addAction(self.actionSave_strategy) + self.toolBar.addAction(self.actionExecute) + + self.retranslateUi(MainWindow) + self.tabs.setCurrentIndex(-1) + self.actionOpen_strategy.triggered.connect(MainWindow.openStrategy) + self.tabs.tabCloseRequested['int'].connect(MainWindow.tabCloseRequested) + self.actionNew_strategy.triggered.connect(MainWindow.newStrategy) + self.actionExecute.triggered.connect(MainWindow.executeStrategy) + self.actionSave_strategy.triggered.connect(MainWindow.saveStrategy) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "Nailab")) + self.menuFile.setTitle(_translate("MainWindow", "File")) + self.menuBacktest.setTitle(_translate("MainWindow", "Backtest")) + self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar")) + self.actionOpenTrades.setText(_translate("MainWindow", "Open...")) + self.actionNew_strategy.setText(_translate("MainWindow", "New strategy")) + self.actionOpen_strategy.setText(_translate("MainWindow", "Open strategy")) + self.actionExecute.setText(_translate("MainWindow", "Execute")) + self.actionSave_strategy.setText(_translate("MainWindow", "Save strategy")) + diff --git a/src/nailab/ui_gen/newdatasourcedialog.py b/src/nailab/ui_gen/newdatasourcedialog.py new file mode 100644 index 0000000..15e714a --- /dev/null +++ b/src/nailab/ui_gen/newdatasourcedialog.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'ui/newdatasourcedialog.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_NewDataSourceDialog(object): + def setupUi(self, NewDataSourceDialog): + NewDataSourceDialog.setObjectName("NewDataSourceDialog") + NewDataSourceDialog.resize(786, 334) + self.gridLayout = QtWidgets.QGridLayout(NewDataSourceDialog) + self.gridLayout.setObjectName("gridLayout") + self.widgets = QtWidgets.QStackedWidget(NewDataSourceDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.widgets.sizePolicy().hasHeightForWidth()) + self.widgets.setSizePolicy(sizePolicy) + self.widgets.setObjectName("widgets") + self.gridLayout.addWidget(self.widgets, 3, 0, 1, 2) + self.e_sourceName = QtWidgets.QLineEdit(NewDataSourceDialog) + self.e_sourceName.setObjectName("e_sourceName") + self.gridLayout.addWidget(self.e_sourceName, 0, 1, 1, 1) + self.label = QtWidgets.QLabel(NewDataSourceDialog) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 1, 0, 1, 1) + self.cb_sourceType = QtWidgets.QComboBox(NewDataSourceDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.cb_sourceType.sizePolicy().hasHeightForWidth()) + self.cb_sourceType.setSizePolicy(sizePolicy) + self.cb_sourceType.setObjectName("cb_sourceType") + self.cb_sourceType.addItem("") + self.gridLayout.addWidget(self.cb_sourceType, 1, 1, 1, 1) + self.label_2 = QtWidgets.QLabel(NewDataSourceDialog) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 0, 0, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(NewDataSourceDialog) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 4, 0, 1, 2) + + self.retranslateUi(NewDataSourceDialog) + self.widgets.setCurrentIndex(-1) + self.buttonBox.accepted.connect(NewDataSourceDialog.accept) + self.buttonBox.rejected.connect(NewDataSourceDialog.reject) + QtCore.QMetaObject.connectSlotsByName(NewDataSourceDialog) + + def retranslateUi(self, NewDataSourceDialog): + _translate = QtCore.QCoreApplication.translate + NewDataSourceDialog.setWindowTitle(_translate("NewDataSourceDialog", "New data source")) + self.label.setText(_translate("NewDataSourceDialog", "Data source type")) + self.cb_sourceType.setItemText(0, _translate("NewDataSourceDialog", "CSV")) + self.label_2.setText(_translate("NewDataSourceDialog", "Data source name")) + diff --git a/src/nailab/ui_gen/strategywidget.py b/src/nailab/ui_gen/strategywidget.py index 2827d40..7125cd7 100644 --- a/src/nailab/ui_gen/strategywidget.py +++ b/src/nailab/ui_gen/strategywidget.py @@ -29,6 +29,22 @@ class Ui_StrategyWidget(object): self.gridLayoutWidget.setObjectName("gridLayoutWidget") self.gridLayout_2 = QtWidgets.QGridLayout(self.gridLayoutWidget) self.gridLayout_2.setObjectName("gridLayout_2") + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.b_addSource = QtWidgets.QPushButton(self.gridLayoutWidget) + self.b_addSource.setObjectName("b_addSource") + self.horizontalLayout.addWidget(self.b_addSource) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.b_refresh = QtWidgets.QPushButton(self.gridLayoutWidget) + self.b_refresh.setObjectName("b_refresh") + self.horizontalLayout.addWidget(self.b_refresh) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem1) + self.b_deleteSource = QtWidgets.QPushButton(self.gridLayoutWidget) + self.b_deleteSource.setObjectName("b_deleteSource") + self.horizontalLayout.addWidget(self.b_deleteSource) + self.gridLayout_2.addLayout(self.horizontalLayout, 5, 0, 1, 2) self.dte_to = QtWidgets.QDateTimeEdit(self.gridLayoutWidget) self.dte_to.setObjectName("dte_to") self.gridLayout_2.addWidget(self.dte_to, 3, 1, 1, 1) @@ -48,6 +64,7 @@ class Ui_StrategyWidget(object): sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.tw_feeds.sizePolicy().hasHeightForWidth()) self.tw_feeds.setSizePolicy(sizePolicy) + self.tw_feeds.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.tw_feeds.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection) self.tw_feeds.setHeaderHidden(True) self.tw_feeds.setObjectName("tw_feeds") @@ -64,7 +81,10 @@ class Ui_StrategyWidget(object): self.rb_timeWindow = QtWidgets.QRadioButton(self.gridLayoutWidget) self.rb_timeWindow.setObjectName("rb_timeWindow") self.gridLayout_2.addWidget(self.rb_timeWindow, 1, 0, 1, 2) - self.editor = Qsci.QsciScintilla(self.splitter) + self.splitter_editor = QtWidgets.QSplitter(self.splitter) + self.splitter_editor.setOrientation(QtCore.Qt.Vertical) + self.splitter_editor.setObjectName("splitter_editor") + self.editor = Qsci.QsciScintilla(self.splitter_editor) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -72,17 +92,25 @@ class Ui_StrategyWidget(object): self.editor.setSizePolicy(sizePolicy) self.editor.setMinimumSize(QtCore.QSize(300, 0)) self.editor.setObjectName("editor") + self.te_notes = QtWidgets.QPlainTextEdit(self.splitter_editor) + self.te_notes.setObjectName("te_notes") self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1) self.tabs.addTab(self.tab, "") self.gridLayout_3.addWidget(self.tabs, 0, 0, 1, 1) self.retranslateUi(StrategyWidget) self.tabs.setCurrentIndex(0) + self.b_addSource.clicked.connect(StrategyWidget.addDataSource) + self.b_deleteSource.clicked.connect(StrategyWidget.deleteDataSource) + self.b_refresh.clicked.connect(StrategyWidget.refreshDataSources) QtCore.QMetaObject.connectSlotsByName(StrategyWidget) def retranslateUi(self, StrategyWidget): _translate = QtCore.QCoreApplication.translate StrategyWidget.setWindowTitle(_translate("StrategyWidget", "Form")) + self.b_addSource.setText(_translate("StrategyWidget", "Add source")) + self.b_refresh.setText(_translate("StrategyWidget", "Refresh")) + self.b_deleteSource.setText(_translate("StrategyWidget", "Delete source")) self.dte_to.setDisplayFormat(_translate("StrategyWidget", "dd.MM.yyyy H:mm")) self.dte_from.setDisplayFormat(_translate("StrategyWidget", "dd.MM.yyyy H:mm")) self.label_2.setText(_translate("StrategyWidget", "To")) diff --git a/ui/csvdatasourceconfigwidget.ui b/ui/csvdatasourceconfigwidget.ui new file mode 100644 index 0000000..7aed141 --- /dev/null +++ b/ui/csvdatasourceconfigwidget.ui @@ -0,0 +1,84 @@ + + + CSVDataSourceConfigWidget + + + + 0 + 0 + 529 + 313 + + + + Form + + + + + + CSV folder path + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + ... + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + b_browse + clicked() + CSVDataSourceConfigWidget + browse() + + + 482 + 27 + + + 494 + 47 + + + + + + browse() + + diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui index 992b9c5..4973fc1 100644 --- a/ui/mainwindow.ui +++ b/ui/mainwindow.ui @@ -45,7 +45,7 @@ 0 0 1060 - 23 + 19 diff --git a/ui/newdatasourcedialog.ui b/ui/newdatasourcedialog.ui new file mode 100644 index 0000000..27dfc1c --- /dev/null +++ b/ui/newdatasourcedialog.ui @@ -0,0 +1,106 @@ + + + NewDataSourceDialog + + + + 0 + 0 + 786 + 334 + + + + New data source + + + + + + + 0 + 0 + + + + -1 + + + + + + + + + + Data source type + + + + + + + + 0 + 0 + + + + + CSV + + + + + + + + Data source name + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + NewDataSourceDialog + accept() + + + 623 + 323 + + + 600 + 333 + + + + + buttonBox + rejected() + NewDataSourceDialog + reject() + + + 563 + 317 + + + 461 + 331 + + + + + diff --git a/ui/strategywidget.ui b/ui/strategywidget.ui index e083432..f3b8db4 100644 --- a/ui/strategywidget.ui +++ b/ui/strategywidget.ui @@ -55,6 +55,57 @@ + + + + + + Add source + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Refresh + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Delete source + + + + + @@ -94,6 +145,9 @@ 0 + + Qt::CustomContextMenu + QAbstractItemView::MultiSelection @@ -129,19 +183,25 @@ - - - - 0 - 0 - - - - - 300 - 0 - + + + Qt::Vertical + + + + 0 + 0 + + + + + 300 + 0 + + + + @@ -160,5 +220,59 @@ - + + + b_addSource + clicked() + StrategyWidget + addDataSource() + + + 73 + 553 + + + 90 + 568 + + + + + b_deleteSource + clicked() + StrategyWidget + deleteDataSource() + + + 393 + 551 + + + 363 + 568 + + + + + b_refresh + clicked() + StrategyWidget + refreshDataSources() + + + 201 + 545 + + + 225 + 569 + + + + + + addDataSource() + deleteDataSource() + refreshDataSources() +