Commit d49091a4 authored by Pierre-Antoine Rouby's avatar Pierre-Antoine Rouby
Browse files

BC: Edit: Add table display.

Showing with 463 additions and 6 deletions
+463 -6
...@@ -15,6 +15,9 @@ class BoundaryCondition(object): ...@@ -15,6 +15,9 @@ class BoundaryCondition(object):
self._header = [] self._header = []
self._types = [int, float] self._types = [int, float]
def __len__(self):
return len(self._data)
@property @property
def name(self): def name(self):
return self._name return self._name
...@@ -46,9 +49,16 @@ class BoundaryCondition(object): ...@@ -46,9 +49,16 @@ class BoundaryCondition(object):
def data(self): def data(self):
return self._data.copy() return self._data.copy()
def get_type_column(self, column):
if 0 <= column < 2:
return self._types[column]
return None
@property
def _default_0(self): def _default_0(self):
return self._types[0](0) return self._types[0](0)
@property
def _default_1(self): def _default_1(self):
return self._types[1](0.0) return self._types[1](0.0)
...@@ -56,13 +66,14 @@ class BoundaryCondition(object): ...@@ -56,13 +66,14 @@ class BoundaryCondition(object):
return self._data is not None return self._data is not None
def add(self, index:int): def add(self, index:int):
value = (self.default_0, self_default_1) value = (self._default_0, self._default_1)
self._data.insert(index, value) self._data.insert(index, value)
return value
def insert(self, index:int, value): def insert(self, index:int, value):
self._data.insert(index, value) self._data.insert(index, value)
def delete(self, indexes): def delete_i(self, indexes):
self._data = list( self._data = list(
map( map(
lambda e: e[1], lambda e: e[1],
...@@ -73,12 +84,30 @@ class BoundaryCondition(object): ...@@ -73,12 +84,30 @@ class BoundaryCondition(object):
) )
) )
def sort(self, _reverse): def delete(self, els):
self._data.sort(reverse=_reverse) self._data = list(
filter(
lambda e: e not in els,
self.data
)
)
def sort(self, _reverse=False, key=None):
if key is None:
self._data.sort(reverse=_reverse)
else:
self._data.sort(reverse=_reverse, key=key)
def get_i(self, index): def get_i(self, index):
return self.data[index] return self.data[index]
def get_range(self, _range):
l = []
for r in _range:
l.append(r)
return l
def _set_i_c_v(self, index, column, value): def _set_i_c_v(self, index, column, value):
v = list(self._data[index]) v = list(self._data[index])
v[column] = self._types[column](value) v[column] = self._types[column](value)
...@@ -103,3 +132,15 @@ class BoundaryCondition(object): ...@@ -103,3 +132,15 @@ class BoundaryCondition(object):
new._set_i_c_v(ind, j, v[i]) new._set_i_c_v(ind, j, v[i])
return new return new
def move_up(self, index):
if index < len(self):
next = index - 1
d = self._data
d[index], d[next] = d[next], d[index]
def move_down(self, index):
if index >= 0:
prev = index + 1
d = self._data
d[index], d[prev] = d[prev], d[index]
...@@ -41,5 +41,6 @@ class ZOverDebit(BoundaryCondition): ...@@ -41,5 +41,6 @@ class ZOverDebit(BoundaryCondition):
self._header = ["z", "debit"] self._header = ["z", "debit"]
self._types = [float, float] self._types = [float, float]
@property
def _default_0(self): def _default_0(self):
return 0.0 return 0.0
...@@ -174,5 +174,5 @@ class DuplicateCommand(QUndoCommand): ...@@ -174,5 +174,5 @@ class DuplicateCommand(QUndoCommand):
self._lst.delete(self._bc) self._lst.delete(self._bc)
def redo(self): def redo(self):
for profile in self._profiles: for bc in self._bcs:
self._lst.insert(self._rows[0], profile) self._lst.insert(self._rows[0], bc)
...@@ -319,6 +319,7 @@ class BoundaryConditionWindow(ASubMainWindow, ListedSubWindow): ...@@ -319,6 +319,7 @@ class BoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
def index_selected_rows(self): def index_selected_rows(self):
table = self.find(QTableView, "tableView") table = self.find(QTableView, "tableView")
return list( return list(
# Delete duplicate
set( set(
map( map(
lambda i: i.row(), lambda i: i.row(),
......
# -*- coding: utf-8 -*-
from tools import trace, timer
from View.ASubWindow import ASubMainWindow
from View.ListedSubWindow import ListedSubWindow
from PyQt5.QtCore import (
Qt, QVariant, QAbstractTableModel,
QCoreApplication, QModelIndex, pyqtSlot,
QRect,
)
from PyQt5.QtWidgets import (
QTableView, QAbstractItemView,
)
from View.BoundaryCondition.Edit.UndoCommand import (
SetDataCommand, AddCommand, DelCommand,
SortCommand, MoveCommand, PasteCommand,
DuplicateCommand,
)
from Model.BoundaryCondition.BoundaryConditionTypes import (
NotDefined, PonctualContribution,
TimeOverZ, TimeOverDebit, ZOverDebit
)
_translate = QCoreApplication.translate
table_headers = {
"time": _translate("BoundaryCondition", "Time"),
"debit": _translate("BoundaryCondition", "Debit"),
"z": _translate("BoundaryCondition", "Z (m)")
}
class TableModel(QAbstractTableModel):
def __init__(self, data=None, undo=None):
super(QAbstractTableModel, self).__init__()
self._headers = data.header
self._data = data
self._undo = undo
def flags(self, index):
options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
options |= Qt.ItemIsEditable
return options
def rowCount(self, parent):
return len(self._data)
def columnCount(self, parent):
return len(self._headers)
def data(self, index, role):
if role != Qt.ItemDataRole.DisplayRole:
return QVariant()
row = index.row()
column = index.column()
value = QVariant()
if 0 <= column < 2:
v = self._data.get_i(row)[column]
if self._data.get_type_column(column) == float:
value = f"{v:.4f}"
else:
# TODO: Time format
value = f"{v}"
return value
def headerData(self, section, orientation, role):
if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
return table_headers[self._headers[section]]
return QVariant()
def setData(self, index, value, role=Qt.EditRole):
if not index.isValid() or role != Qt.EditRole:
return False
row = index.row()
column = index.column()
self._undo.push(
SetDataCommand(
self._data, row, column, value
)
)
self.dataChanged.emit(index, index)
return True
def add(self, row, parent=QModelIndex()):
self.beginInsertRows(parent, row, row - 1)
self._undo.push(
AddCommand(
self._data, row
)
)
self.endInsertRows()
self.layoutChanged.emit()
def delete(self, rows, parent=QModelIndex()):
self.beginRemoveRows(parent, rows[0], rows[-1])
self._undo.push(
DelCommand(
self._data, rows
)
)
self.endRemoveRows()
def sort(self, _reverse, parent=QModelIndex()):
self.layoutAboutToBeChanged.emit()
self._undo.push(
SortCommand(
self._data, False
)
)
self.layoutAboutToBeChanged.emit()
self.layoutChanged.emit()
def move_up(self, row, parent=QModelIndex()):
if row <= 0:
return
target = row + 2
self.beginMoveRows(parent, row - 1, row - 1, parent, target)
self._undo_stack.push(
MoveCommand(
self._data, "up", row
)
)
self.endMoveRows()
self.layoutChanged.emit()
def move_down(self, index, parent=QModelIndex()):
if row > len(self._data):
return
target = row
self.beginMoveRows(parent, row + 1, row + 1, parent, target)
self._undo_stack.push(
MoveCommand(
self._data, "down", row
)
)
self.endMoveRows()
self.layoutChanged.emit()
def undo(self):
self._undo.undo()
self.layoutChanged.emit()
def redo(self):
self._undo.redo()
self.layoutChanged.emit()
# -*- coding: utf-8 -*-
from copy import deepcopy
from tools import trace, timer
from PyQt5.QtWidgets import (
QMessageBox, QUndoCommand, QUndoStack,
)
from Model.BoundaryCondition.BoundaryCondition import BoundaryCondition
class SetDataCommand(QUndoCommand):
def __init__(self, data, index, column, new_value):
QUndoCommand.__init__(self)
self._data = data
self._index = index
self._column = column
self._old = self._data.get_i(self._index)[self._column]
self._new = new_value
def undo(self):
self._data._set_i_c_v(self._index, self._column, self._old)
def redo(self):
self._data._set_i_c_v(self._index, self._column, self._new)
class AddCommand(QUndoCommand):
def __init__(self, data, index):
QUndoCommand.__init__(self)
self._data = data
self._index = index
self._new = None
def undo(self):
self._data.delete_i([self._index])
def redo(self):
if self._new is None:
self._new = self._data.add(self._index)
else:
self._data.insert(self._index, self._new)
class DelCommand(QUndoCommand):
def __init__(self, data, rows):
QUndoCommand.__init__(self)
self._data = data
self._rows = rows
self._bc = []
for row in rows:
self._bc.append((row, self._data.get_i(row)))
self._bc.sort()
def undo(self):
for row, el in self._bc:
self._data.insert(row, el)
def redo(self):
self._data.delete_i(self._rows)
class SortCommand(QUndoCommand):
def __init__(self, data, _reverse):
QUndoCommand.__init__(self)
self._data = data
self._reverse = _reverse
self._old = self._data.data
self._indexes = None
def undo(self):
ll = self._data.data
self._data.sort(
key=lambda x: self._indexes[ll.index(x)]
)
def redo(self):
self._data.sort(
reverse=self._reverse,
key=lambda x: x.name
)
if self._indexes is None:
self._indexes = list(
map(
lambda p: self._old.index(p),
self._data.data
)
)
self._old = None
class MoveCommand(QUndoCommand):
def __init__(self, data, up, i):
QUndoCommand.__init__(self)
self._data = data
self._up = up == "up"
self._i = i
def undo(self):
if self._up:
self._data.move_up(self._i)
else:
self._data.move_down(self._i)
def redo(self):
if self._up:
self._data.move_up(self._i)
else:
self._data.move_down(self._i)
class PasteCommand(QUndoCommand):
def __init__(self, data, row, bc):
QUndoCommand.__init__(self)
self._data = data
self._row = row
self._bc = deepcopy(bc)
self._bc.reverse()
def undo(self):
self._data.delete(self._bc)
def redo(self):
for bc in self._bc:
self._data.insert(self._row, bc)
class DuplicateCommand(QUndoCommand):
def __init__(self, data, rows, bc):
QUndoCommand.__init__(self)
self._data = data
self._rows = rows
self._bc = deepcopy(bc)
self._bc.reverse()
def undo(self):
self._data.delete(self._bc)
def redo(self):
for bc in self._bcs:
self._data.insert(self._rows[0], bc)
...@@ -3,6 +3,10 @@ ...@@ -3,6 +3,10 @@
from View.ASubWindow import ASubMainWindow from View.ASubWindow import ASubMainWindow
from View.ListedSubWindow import ListedSubWindow from View.ListedSubWindow import ListedSubWindow
from PyQt5.QtGui import (
QKeySequence,
)
from PyQt5.QtCore import ( from PyQt5.QtCore import (
Qt, QVariant, QAbstractTableModel, QCoreApplication, Qt, QVariant, QAbstractTableModel, QCoreApplication,
) )
...@@ -10,9 +14,11 @@ from PyQt5.QtCore import ( ...@@ -10,9 +14,11 @@ from PyQt5.QtCore import (
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QDialogButtonBox, QPushButton, QLineEdit, QDialogButtonBox, QPushButton, QLineEdit,
QFileDialog, QTableView, QAbstractItemView, QFileDialog, QTableView, QAbstractItemView,
QUndoStack, QShortcut, QAction, QItemDelegate,
) )
from View.BoundaryCondition.translate import long_types from View.BoundaryCondition.translate import long_types
from View.BoundaryCondition.Edit.Table import TableModel
_translate = QCoreApplication.translate _translate = QCoreApplication.translate
...@@ -26,6 +32,9 @@ class EditBoundaryConditionWindow(ASubMainWindow, ListedSubWindow): ...@@ -26,6 +32,9 @@ class EditBoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
self._title = title self._title = title
self.setup_window() self.setup_window()
self.setup_sc()
self.setup_table()
self.setup_connections()
def setup_window(self): def setup_window(self):
if self._data is not None: if self._data is not None:
...@@ -39,3 +48,88 @@ class EditBoundaryConditionWindow(ASubMainWindow, ListedSubWindow): ...@@ -39,3 +48,88 @@ class EditBoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
self.ui.setWindowTitle(title) self.ui.setWindowTitle(title)
else: else:
self.ui.setWindowTitle(_translate("BoundaryCondition", self._title)) self.ui.setWindowTitle(_translate("BoundaryCondition", self._title))
def setup_sc(self):
self._undo_stack = QUndoStack()
self.undo_sc = QShortcut(QKeySequence.Undo, self)
self.redo_sc = QShortcut(QKeySequence.Redo, self)
self.copy_sc = QShortcut(QKeySequence.Copy, self)
self.paste_sc = QShortcut(QKeySequence.Paste, self)
def setup_table(self):
table = self.find(QTableView, "tableView")
self._table = TableModel(
data = self._data,
undo = self._undo_stack
)
table.setModel(self._table)
table.setSelectionBehavior(QAbstractItemView.SelectRows)
table.setAlternatingRowColors(True)
def setup_connections(self):
self.find(QAction, "action_add").triggered.connect(self.add)
self.find(QAction, "action_del").triggered.connect(self.delete)
self.find(QAction, "action_sort").triggered.connect(self.sort)
self.undo_sc.activated.connect(self.undo)
self.redo_sc.activated.connect(self.redo)
self.copy_sc.activated.connect(self.copy)
self.paste_sc.activated.connect(self.paste)
def index_selected_row(self):
table = self.find(QTableView, "tableView")
return table.selectionModel()\
.selectedRows()[0]\
.row()
def index_selected_rows(self):
table = self.find(QTableView, "tableView")
return list(
# Delete duplicate
set(
map(
lambda i: i.row(),
table.selectedIndexes()
)
)
)
def add(self):
rows = self.index_selected_rows()
if len(self._data) == 0 or len(rows) == 0:
self._table.add(0)
else:
self._table.add(rows[0])
def delete(self):
rows = self.index_selected_rows()
if len(rows) == 0:
return
self._table.delete(rows)
def sort(self):
self._table.sort(False)
def move_up(self):
row = self.index_selected_row()
self._table.move_up(row)
def move_down(self):
row = self.index_selected_row()
self._table.move_down(row)
def copy(self):
print("TODO")
def paste(self):
print("TODO")
def undo(self):
self._table.undo()
def redo(self):
self._table.redo()
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment