mirror of https://gitlab.com/pamhyr/pamhyr2
geometry: Profile: Update qtable and add undo commands.
parent
a9c57a9512
commit
a2e1208d42
|
|
@ -1,5 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from Model.Geometry.Point import Point
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
class Profile(object):
|
class Profile(object):
|
||||||
|
|
@ -20,6 +21,14 @@ class Profile(object):
|
||||||
|
|
||||||
self._profile_type = _type
|
self._profile_type = _type
|
||||||
|
|
||||||
|
@property
|
||||||
|
def number_points(self):
|
||||||
|
return len(self._points)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def points(self):
|
||||||
|
return self._points.copy()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def reach(self):
|
def reach(self):
|
||||||
return self._reach
|
return self._reach
|
||||||
|
|
@ -100,6 +109,11 @@ class Profile(object):
|
||||||
def profile_type(self, value: str):
|
def profile_type(self, value: str):
|
||||||
self._profile_type = value
|
self._profile_type = value
|
||||||
|
|
||||||
|
def point(self, i:int):
|
||||||
|
if i < len(self._points):
|
||||||
|
return self._points[i]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
def named_points(self):
|
def named_points(self):
|
||||||
"""List of named point
|
"""List of named point
|
||||||
|
|
@ -110,6 +124,81 @@ class Profile(object):
|
||||||
return [point for point in self._points
|
return [point for point in self._points
|
||||||
if point.point_is_named()]
|
if point.point_is_named()]
|
||||||
|
|
||||||
|
|
||||||
|
def insert_point(self, index: int, point:Point):
|
||||||
|
"""Insert point at index.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
index: The index of new profile.
|
||||||
|
point: The point.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Nothing.
|
||||||
|
"""
|
||||||
|
self._points.insert(index, point)
|
||||||
|
|
||||||
|
|
||||||
|
def delete(self, index: int):
|
||||||
|
"""Delete the point at index
|
||||||
|
|
||||||
|
Args:
|
||||||
|
index: Index of point.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Nothing.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self._points.pop(index)
|
||||||
|
except IndexError:
|
||||||
|
raise IndexError(f"Invalid point index: {index}")
|
||||||
|
|
||||||
|
# Move
|
||||||
|
|
||||||
|
def move_up_point(self, index: int):
|
||||||
|
if index < len(self._points):
|
||||||
|
next = index - 1
|
||||||
|
|
||||||
|
p = self._points
|
||||||
|
p[index], p[next] = p[next], p[index]
|
||||||
|
|
||||||
|
def move_down_point(self, index: int):
|
||||||
|
if index >= 0:
|
||||||
|
prev = index + 1
|
||||||
|
|
||||||
|
p = self._points
|
||||||
|
p[index], p[prev] = p[prev], p[index]
|
||||||
|
|
||||||
|
# Sort
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def sort(self, column, is_reversed: bool = False):
|
||||||
|
predicate = lambda p: p.x
|
||||||
|
if column == 'y':
|
||||||
|
predicate = lambda p: p.y
|
||||||
|
elif column == 'z':
|
||||||
|
predicate = lambda p: p.z
|
||||||
|
|
||||||
|
self._profiles = sorted(
|
||||||
|
self._points,
|
||||||
|
key=predicate,
|
||||||
|
reverse=is_reversed
|
||||||
|
)
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def sort_with_indexes(self, indexes: list):
|
||||||
|
if len(self._points) != len(indexes):
|
||||||
|
print("TODO: CRITICAL ERROR!")
|
||||||
|
|
||||||
|
self._points = list(
|
||||||
|
map(
|
||||||
|
lambda x: x[1],
|
||||||
|
sorted(
|
||||||
|
enumerate(self.points),
|
||||||
|
key=lambda x: indexes[x[0]]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# Abstract method, must be implemented for in non abstract class
|
# Abstract method, must be implemented for in non abstract class
|
||||||
def get_station(self):
|
def get_station(self):
|
||||||
raise NotImplementedMethodeError(self, self.get_station)
|
raise NotImplementedMethodeError(self, self.get_station)
|
||||||
|
|
|
||||||
|
|
@ -117,22 +117,8 @@ class ProfileXYZ(Profile):
|
||||||
point_xyz = PointXYZ(0., 0., 0.)
|
point_xyz = PointXYZ(0., 0., 0.)
|
||||||
self._points.append(point_xyz)
|
self._points.append(point_xyz)
|
||||||
|
|
||||||
def delete(self, index: int):
|
|
||||||
"""Delete the point at index
|
|
||||||
|
|
||||||
Args:
|
|
||||||
index: Index of point.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Nothing.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
self._points.pop(index)
|
|
||||||
except IndexError:
|
|
||||||
raise IndexError(f"Invalid point index: {index}")
|
|
||||||
|
|
||||||
def insert(self, index: int):
|
def insert(self, index: int):
|
||||||
"""Insert a new profile at index.
|
"""Insert a new point at index.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
index: The index of new profile.
|
index: The index of new profile.
|
||||||
|
|
@ -140,35 +126,8 @@ class ProfileXYZ(Profile):
|
||||||
Returns:
|
Returns:
|
||||||
Nothing.
|
Nothing.
|
||||||
"""
|
"""
|
||||||
profile = ProfileXYZ()
|
point = PointXYZ(0., 0., 0.)
|
||||||
self._points.insert(index, profile)
|
self._points.insert(index, point)
|
||||||
|
|
||||||
def delete1(self, list_index: list):
|
|
||||||
"""Delete a list of points
|
|
||||||
|
|
||||||
Args:
|
|
||||||
list_index: Indexes list.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Nothing.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
if list_index:
|
|
||||||
indices = sorted(list(set(list_index)), reverse=True)
|
|
||||||
for idx in indices:
|
|
||||||
# if idx < len(self._list_profiles) :
|
|
||||||
try:
|
|
||||||
self._points.pop(idx)
|
|
||||||
except IndexError:
|
|
||||||
print("Empty list, nothing to delete")
|
|
||||||
except TypeError:
|
|
||||||
if isinstance(list_index, int):
|
|
||||||
self._points.pop(list_index)
|
|
||||||
print(f"\n{list_index} is not a list\n")
|
|
||||||
else:
|
|
||||||
raise TypeError(
|
|
||||||
f"{list_index} is instance of unexpected type '{type(list_index)}'"
|
|
||||||
)
|
|
||||||
|
|
||||||
def filter_isnan(self, lst):
|
def filter_isnan(self, lst):
|
||||||
"""Returns the input list without 'nan' element
|
"""Returns the input list without 'nan' element
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,148 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QMessageBox, QUndoCommand, QUndoStack,
|
||||||
|
)
|
||||||
|
|
||||||
|
from Model.Geometry.Profile import Profile
|
||||||
|
|
||||||
|
|
||||||
|
class SetDataCommand(QUndoCommand):
|
||||||
|
def __init__(self, profile, index, old_value, new_value):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._profile = profile
|
||||||
|
self._index = index
|
||||||
|
self._old = old_value
|
||||||
|
self._new = new_value
|
||||||
|
|
||||||
|
class SetXCommand(SetDataCommand):
|
||||||
|
def undo(self):
|
||||||
|
self._profile.point(self._index).x = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._profile.point(self._index).x = self._new
|
||||||
|
|
||||||
|
class SetYCommand(SetDataCommand):
|
||||||
|
def undo(self):
|
||||||
|
self._profile.point(self._index).y = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._profile.point(self._index).y = self._new
|
||||||
|
|
||||||
|
class SetZCommand(SetDataCommand):
|
||||||
|
def undo(self):
|
||||||
|
self._profile.point(self._index).z = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._profile.point(self._index).z = self._new
|
||||||
|
|
||||||
|
class SetNameCommand(SetDataCommand):
|
||||||
|
def undo(self):
|
||||||
|
self._profile.point(self._index).name = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._profile.point(self._index).name = self._new
|
||||||
|
|
||||||
|
|
||||||
|
class AddCommand(QUndoCommand):
|
||||||
|
def __init__(self, profile, index):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._profile = profile
|
||||||
|
self._index = index
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._profile.delete(self._index)
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._profile.insert(self._index)
|
||||||
|
|
||||||
|
class DelCommand(QUndoCommand):
|
||||||
|
def __init__(self, profile, rows):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._profile = profile
|
||||||
|
self._rows = rows
|
||||||
|
|
||||||
|
self._points = []
|
||||||
|
for row in rows:
|
||||||
|
self._points.append(self._profile.point(row))
|
||||||
|
self._points.reverse()
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
row = self._rows[0]
|
||||||
|
for point in self._points:
|
||||||
|
self._profile.insert_point(row, point)
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
row = self._rows[0]
|
||||||
|
for _ in self._rows:
|
||||||
|
self._profile.delete(row)
|
||||||
|
|
||||||
|
class SortCommand(QUndoCommand):
|
||||||
|
def __init__(self, profile, column _reverse):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._profile = profile
|
||||||
|
self._column = column
|
||||||
|
self._reverse = _reverse
|
||||||
|
|
||||||
|
old = self._profile.points
|
||||||
|
self._profile.sort(self.column, self._reverse)
|
||||||
|
new = self._profile.points
|
||||||
|
|
||||||
|
self._indexes = list(
|
||||||
|
map(
|
||||||
|
lambda p: old.index(p),
|
||||||
|
new
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._profile.sort_with_indexes(self._indexes)
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._profile.sort(self.column, self._reverse)
|
||||||
|
|
||||||
|
|
||||||
|
class MoveCommand(QUndoCommand):
|
||||||
|
def __init__(self, profile, up, i):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._profile = profile
|
||||||
|
self._up = up == "up"
|
||||||
|
self._i = i
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
if self._up:
|
||||||
|
self._profile.move_up_point(self._i)
|
||||||
|
else:
|
||||||
|
self._profile.move_down_point(self._i)
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self._up:
|
||||||
|
self._profile.move_up_point(self._i)
|
||||||
|
else:
|
||||||
|
self._profile.move_down_point(self._i)
|
||||||
|
|
||||||
|
|
||||||
|
class PasteCommand(QUndoCommand):
|
||||||
|
def __init__(self, profile, row, points):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._profile = profile
|
||||||
|
self._row = row
|
||||||
|
self._points = points
|
||||||
|
|
||||||
|
self._points.reverse()
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
for ind in range(len(self._profiles)):
|
||||||
|
self._profile.delete(self._row)
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
for point in self._points:
|
||||||
|
self._profile.insert_point(self._row, point)
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import sys
|
import sys
|
||||||
import csv
|
import csv
|
||||||
|
|
@ -93,7 +95,7 @@ class ProfileWindow(QMainWindow):
|
||||||
|
|
||||||
def graph(self):
|
def graph(self):
|
||||||
"""
|
"""
|
||||||
Returns: Le tracé de la cote z en fonction de l'abscisse (calculée).
|
Returns: Le tracé de la cote z en fonction de l'abscisse (calculée).
|
||||||
"""
|
"""
|
||||||
x = self._model.station # abscisse en travers
|
x = self._model.station # abscisse en travers
|
||||||
y = self._model.z # cote z
|
y = self._model.z # cote z
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from PyQt5.QtGui import QFont
|
from PyQt5.QtGui import QFont
|
||||||
|
|
@ -8,66 +10,80 @@ from PyQt5.QtCore import QModelIndex, Qt, QAbstractTableModel, QVariant, QCoreAp
|
||||||
|
|
||||||
from Model.Geometry.ProfileXYZ import ProfileXYZ
|
from Model.Geometry.ProfileXYZ import ProfileXYZ
|
||||||
|
|
||||||
|
from View.Geometry.Profile.ProfileUndoCommand import *
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
class PandasModelEditable(QAbstractTableModel):
|
class PandasModelEditable(QAbstractTableModel):
|
||||||
def __init__(self, profile: ProfileXYZ, table_header=None):
|
def __init__(self, profile: ProfileXYZ, table_header=None, undo=None):
|
||||||
QAbstractTableModel.__init__(self)
|
QAbstractTableModel.__init__(self)
|
||||||
|
|
||||||
|
self._undo_stack = undo
|
||||||
|
self._profile = profile
|
||||||
|
|
||||||
if table_header is None:
|
if table_header is None:
|
||||||
self.header = ["X (m)", "Y (m)", "Z (m)", _translate("MainWindowProfile", "Nom"),
|
self._header = [
|
||||||
_translate("MainWindowProfile", "Abs en travers (m)")]
|
"X (m)", "Y (m)", "Z (m)",
|
||||||
|
_translate("MainWindowProfile", "Nom"),
|
||||||
|
_translate("MainWindowProfile", "Abs en travers (m)")
|
||||||
|
]
|
||||||
else:
|
else:
|
||||||
self.header = table_header
|
self._header = table_header
|
||||||
|
|
||||||
self.profile = profile
|
|
||||||
|
|
||||||
data = pd.DataFrame({
|
|
||||||
self.header[0]: profile.x(),
|
|
||||||
self.header[1]: profile.y(),
|
|
||||||
self.header[2]: profile.z(),
|
|
||||||
self.header[3]: profile.name(),
|
|
||||||
self.header[4]: profile.get_station()
|
|
||||||
})
|
|
||||||
self._data = data
|
|
||||||
|
|
||||||
def rowCount(self, parent=QModelIndex()):
|
def rowCount(self, parent=QModelIndex()):
|
||||||
return self._data.shape[0]
|
return self._profile.number_points
|
||||||
|
|
||||||
def columnCount(self, parent=QModelIndex()):
|
def columnCount(self, parent=QModelIndex()):
|
||||||
return self._data.shape[1]
|
return len(self._header)
|
||||||
|
|
||||||
def data(self, index, role=Qt.DisplayRole):
|
def data(self, index, role=Qt.DisplayRole):
|
||||||
value = self._data.iloc[index.row()][index.column()]
|
|
||||||
if index.isValid():
|
if index.isValid():
|
||||||
if role == Qt.DisplayRole:
|
if role == Qt.DisplayRole:
|
||||||
if index.column() != 4:
|
value = ""
|
||||||
if isinstance(value, float):
|
|
||||||
return "%.4f" % value
|
|
||||||
else:
|
|
||||||
if isinstance(value, float):
|
|
||||||
return "%.3f" % value
|
|
||||||
|
|
||||||
return str(self._data.iloc[index.row(), index.column()])
|
if index.column() == 0:
|
||||||
|
value = self._profile.point(index.row()).x
|
||||||
|
elif index.column() == 1:
|
||||||
|
value = self._profile.point(index.row()).y
|
||||||
|
elif index.column() == 2:
|
||||||
|
value = self._profile.point(index.row()).z
|
||||||
|
elif index.column() == 3:
|
||||||
|
value = self._profile.point(index.row()).name
|
||||||
|
elif index.column() == 4:
|
||||||
|
value = self._profile.get_station()
|
||||||
|
|
||||||
|
if 0 <= index.column() < 3:
|
||||||
|
return f"{value:.4f}"
|
||||||
|
elif index.column() == 4:
|
||||||
|
return f"{value:.3f}"
|
||||||
|
|
||||||
|
return f"{value}"
|
||||||
|
|
||||||
if role == Qt.TextAlignmentRole:
|
if role == Qt.TextAlignmentRole:
|
||||||
return Qt.AlignHCenter | Qt.AlignVCenter
|
return Qt.AlignHCenter | Qt.AlignVCenter
|
||||||
|
|
||||||
# if index.column() == 2:
|
if index.column() == 2:
|
||||||
# if role == Qt.ForegroundRole:
|
value = self._profile.point(index.row()).z
|
||||||
# if value == min(self._data.iloc[:, index.column()]):
|
if role == Qt.ForegroundRole:
|
||||||
# return QtGui.QColor("red")
|
if value == self._profile.z_min():
|
||||||
# elif value == max(self._data.iloc[:, index.column()]):
|
return QtGui.QColor("red")
|
||||||
# return QtGui.QColor("Blue")
|
elif value == self._profile.z_max():
|
||||||
|
return QtGui.QColor("blue")
|
||||||
|
|
||||||
if role == Qt.ToolTipRole:
|
if role == Qt.ToolTipRole:
|
||||||
if value == min(self._data.iloc[:, index.column()]):
|
if value == self._profile.z_min():
|
||||||
return _translate("MainWindowProfile", "La cote du fond", "Z minimale")
|
return _translate("MainWindowProfile",
|
||||||
elif value == max(self._data.iloc[:, index.column()]):
|
"La cote du fond",
|
||||||
return _translate("MainWindowProfile", "La cote maximale", "Z maximale")
|
"Z minimale")
|
||||||
|
elif value == self._profile.z_max():
|
||||||
|
return _translate("MainWindowProfile",
|
||||||
|
"La cote maximale",
|
||||||
|
"Z maximale")
|
||||||
|
|
||||||
if index.column() == 3:
|
if index.column() == 3:
|
||||||
|
value = self._profile.point(index.row()).name
|
||||||
|
|
||||||
if value.strip().upper() in ["RG", "RD"]:
|
if value.strip().upper() in ["RG", "RD"]:
|
||||||
if role == Qt.FontRole:
|
if role == Qt.FontRole:
|
||||||
font = QFont()
|
font = QFont()
|
||||||
|
|
@ -89,14 +105,13 @@ class PandasModelEditable(QAbstractTableModel):
|
||||||
font.setBold(True)
|
font.setBold(True)
|
||||||
return font
|
return font
|
||||||
|
|
||||||
# if role == Qt.BackgroundRole:
|
|
||||||
# return QtGui.QColor("#ededee")
|
|
||||||
|
|
||||||
return QVariant()
|
return QVariant()
|
||||||
|
|
||||||
def headerData(self, section, orientation, role=Qt.DisplayRole):
|
def headerData(self, section, orientation, role=Qt.DisplayRole):
|
||||||
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
|
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
|
||||||
return self.header[section]
|
return self._header[section]
|
||||||
|
elif orientation == Qt.Vertical and role == Qt.DisplayRole:
|
||||||
|
return return str(section + 1)
|
||||||
|
|
||||||
if role == Qt.ToolTipRole and section == 4:
|
if role == Qt.ToolTipRole and section == 4:
|
||||||
return _translate(
|
return _translate(
|
||||||
|
|
@ -105,268 +120,163 @@ class PandasModelEditable(QAbstractTableModel):
|
||||||
" \nsur le plan défini par les deux points nommés extrêmes "
|
" \nsur le plan défini par les deux points nommés extrêmes "
|
||||||
)
|
)
|
||||||
|
|
||||||
if orientation == Qt.Vertical and role == Qt.DisplayRole:
|
return QVariant()
|
||||||
return self._data.index[section] + 1
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def setData(self, index, value, role=Qt.EditRole):
|
def setData(self, index, value, role=Qt.EditRole):
|
||||||
|
row = index.row()
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
if role == Qt.EditRole:
|
if role == Qt.EditRole:
|
||||||
try:
|
if column == 0:
|
||||||
if index.column() == 3:
|
self._undo_stack.push(
|
||||||
self._data.iat[index.row(), index.column()] = str(value)
|
SetXCommand(
|
||||||
elif index.column() == 0:
|
self._profile, row,
|
||||||
self._data.iat[index.row(), index.column()] = float(value)
|
self._profile.profile(row).x,
|
||||||
elif index.column() == 1:
|
value
|
||||||
self._data.iat[index.row(), index.column()] = float(value)
|
)
|
||||||
elif index.column() == 2:
|
)
|
||||||
self._data.iat[index.row(), index.column()] = float(value)
|
elif column == 1:
|
||||||
|
self._undo_stack.push(
|
||||||
self._data.iloc[:, 4] = projection_pointXYZ.update_station(
|
SetYCommand(
|
||||||
self.header,
|
self._profile, row,
|
||||||
self._data.values.tolist()
|
self._profile.profile(row).y,
|
||||||
|
value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif column == 2:
|
||||||
|
self._undo_stack.push(
|
||||||
|
SetZCommand(
|
||||||
|
self._profile, row,
|
||||||
|
self._profile.profile(row).z,
|
||||||
|
value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif column == 3:
|
||||||
|
self._undo_stack.push(
|
||||||
|
SetNameCommand(
|
||||||
|
self._profile, row,
|
||||||
|
self._profile.profile(row).name,
|
||||||
|
value
|
||||||
|
)
|
||||||
)
|
)
|
||||||
self.dataChanged.emit(index, index)
|
|
||||||
except:
|
|
||||||
print('TODO')
|
|
||||||
self.QMessageBoxCritical(value)
|
|
||||||
|
|
||||||
|
self.dataChanged.emit(index, index)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
self.dataChanged.emit(index, index)
|
self.dataChanged.emit(index, index)
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def QMessageBoxCritical(value):
|
|
||||||
msg = QMessageBox()
|
|
||||||
msg.setIcon(QMessageBox.Warning)
|
|
||||||
msg.setText("{} : Valeur saisie incorrecte ".format(value))
|
|
||||||
msg.setInformativeText("Seules les valeurs numériques sont autorisées.")
|
|
||||||
msg.setWindowTitle("Warning ")
|
|
||||||
msg.setStyleSheet("QLabel{min-width:150 px; font-size: 13px;} QPushButton{ width:20px; font-size: 12px};"
|
|
||||||
"background-color: Ligthgray ; color : gray;font-size: 8pt; color: #888a80;")
|
|
||||||
msg.exec_()
|
|
||||||
|
|
||||||
def index(self, row, column, parent=QModelIndex()):
|
def index(self, row, column, parent=QModelIndex()):
|
||||||
if not self.hasIndex(row, column, parent):
|
if not self.hasIndex(row, column, parent):
|
||||||
return QModelIndex()
|
return QModelIndex()
|
||||||
|
|
||||||
return self.createIndex(row, column, QModelIndex())
|
return self.createIndex(row, column, QModelIndex())
|
||||||
|
|
||||||
def flags(self, index):
|
def flags(self, index):
|
||||||
return Qt.ItemIsEditable | Qt.ItemIsSelectable | Qt.ItemIsEnabled
|
flg = Qt.ItemIsSelectable | Qt.ItemIsEnabled
|
||||||
|
|
||||||
# @QtCore.pyqtSlot()
|
if index.column() == 4:
|
||||||
def insertRows(self, row, count, parent=QModelIndex()):
|
return flg
|
||||||
self.beginInsertRows(parent, row, row + count - 1)
|
|
||||||
indexes = [str(self.rowCount() + i) for i in range(count)]
|
|
||||||
left = self._data[0:row]
|
|
||||||
mid = pd.DataFrame(index=indexes, columns=self._data.columns)
|
|
||||||
right = self._data[row + count - 1:self.rowCount()]
|
|
||||||
|
|
||||||
self._data = pd.concat([left, mid, right])
|
return Qt.ItemIsEditable | flg
|
||||||
|
|
||||||
for i in [3]:
|
def insert_row(self, row, parent=QModelIndex()):
|
||||||
self._data.iloc[:, i].replace(np.nan, '', inplace=True)
|
self.beginInsertRows(parent, row, row - 1)
|
||||||
|
|
||||||
self._data.reset_index(drop=True, inplace=True)
|
self._undo_stack.push(
|
||||||
|
AddCommand(
|
||||||
try:
|
self._profile, row
|
||||||
self._data.iloc[:, 4] = projection_pointXYZ.update_station(
|
|
||||||
self.header,
|
|
||||||
self._data.values.tolist()
|
|
||||||
)
|
)
|
||||||
except:
|
)
|
||||||
print("TODO")
|
|
||||||
|
|
||||||
self.endInsertRows()
|
self.endInsertRows()
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
# @QtCore.pyqtSlot()
|
def remove_rows(self, rows, parent=QModelIndex()):
|
||||||
def removeRows(self, row, count, parent=QModelIndex()):
|
self.beginRemoveRows(parent, rows[0], row[-1])
|
||||||
self.beginRemoveRows(parent, row, row + count + 1)
|
|
||||||
self._data.drop(self._data.index[row], inplace=True)
|
|
||||||
self._data.iloc[:, 4] = projection_pointXYZ.update_station(
|
|
||||||
self.header,
|
|
||||||
self._data.values.tolist()
|
|
||||||
)
|
|
||||||
self.endRemoveRows()
|
|
||||||
self.layoutChanged.emit()
|
|
||||||
|
|
||||||
def remove_rows1(self, row, count, parent=QModelIndex()):
|
self._undo_stack.push(
|
||||||
self.beginRemoveRows(parent, row, row + count - 1)
|
DelCommand(
|
||||||
left = self._data.iloc[0:row]
|
self._profile, rows
|
||||||
right = self._data.iloc[row + count:self.rowCount()]
|
|
||||||
|
|
||||||
self._data = pd.concat([left, right], axis=0, ignore_index=True)
|
|
||||||
self._data.iloc[:, 4] = projection_pointXYZ.update_station(
|
|
||||||
self.header,
|
|
||||||
self._data.values.tolist()
|
|
||||||
)
|
|
||||||
self.endRemoveRows()
|
|
||||||
self.layoutChanged.emit()
|
|
||||||
|
|
||||||
def remove_rows(self, list_row_selected, parent=QModelIndex()):
|
|
||||||
self.beginRemoveRows(parent, list_row_selected[0], list_row_selected[-1])
|
|
||||||
|
|
||||||
try:
|
|
||||||
self._data.drop(self._data.index[list_row_selected], inplace=True)
|
|
||||||
self._data.reset_index(drop=True, inplace=True)
|
|
||||||
except:
|
|
||||||
print('TODO')
|
|
||||||
try:
|
|
||||||
self._data.iloc[:, 4] = projection_pointXYZ.update_station(
|
|
||||||
self.header,
|
|
||||||
self._data.values.tolist()
|
|
||||||
)
|
)
|
||||||
except:
|
)
|
||||||
print("TODO")
|
|
||||||
|
|
||||||
self.endRemoveRows()
|
self.endRemoveRows()
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def sort(self, column, order=Qt.AscendingOrder):
|
def sort(self, column='x', order=Qt.AscendingOrder):
|
||||||
self.layoutAboutToBeChanged.emit()
|
self.layoutAboutToBeChanged.emit()
|
||||||
colname = self._data.columns.tolist()[column]
|
|
||||||
self._data.sort_values(colname, ascending=order == Qt.AscendingOrder, inplace=True)
|
|
||||||
self._data.reset_index(inplace=True, drop=True)
|
|
||||||
|
|
||||||
self._data.iloc[:, 4] = projection_pointXYZ.update_station(
|
reverse = (order != Qt.AscendingOrder)
|
||||||
self.header,
|
|
||||||
self._data.values.tolist()
|
self._undo_stack.push(
|
||||||
|
SortCommand(
|
||||||
|
self._profile, column, reverse
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def moveRowDown(self, row_to_move, parent=QModelIndex()):
|
def move_row_up(self, row, parent=QModelIndex()):
|
||||||
target = row_to_move + 2
|
if row <= 0:
|
||||||
self.beginMoveRows(parent, row_to_move, row_to_move, parent, target)
|
return
|
||||||
block_before_row = self._data.iloc[0:row_to_move]
|
|
||||||
selected_row = self._data.iloc[row_to_move:row_to_move + 1]
|
|
||||||
after_selcted_row = self._data.iloc[row_to_move + 1:row_to_move + 2]
|
|
||||||
block_after_row = self._data.iloc[row_to_move + 2:self.rowCount()]
|
|
||||||
|
|
||||||
self._data = pd.concat([block_before_row, after_selcted_row, selected_row, block_after_row], axis=0)
|
target = row + 2
|
||||||
self._data.reset_index(inplace=True, drop=True)
|
|
||||||
|
self.beginMoveRows(parent, row - 1, row - 1, parent, target)
|
||||||
|
|
||||||
|
self._undo_stack.push(
|
||||||
|
MoveCommand(
|
||||||
|
self._profile, "up", row
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
self.endMoveRows()
|
self.endMoveRows()
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def moveRowUp(self, row_to_move, parent=QModelIndex()):
|
def move_row_down(self, row_to_move, parent=QModelIndex()):
|
||||||
target = row_to_move + 1
|
if row > self._profile.number_points:
|
||||||
self.beginMoveRows(parent, row_to_move - 1, row_to_move - 1, parent, target)
|
return
|
||||||
block_before_row = self._data.iloc[0:row_to_move - 1]
|
|
||||||
before_selected_row = self._data.iloc[row_to_move - 1:row_to_move]
|
|
||||||
selected_row = self._data.iloc[row_to_move:row_to_move + 1]
|
|
||||||
block_after_row = self._data.iloc[row_to_move + 1:self.rowCount()]
|
|
||||||
|
|
||||||
self._data = pd.concat([block_before_row, selected_row, before_selected_row, block_after_row], axis=0)
|
target = row
|
||||||
self._data.reset_index(inplace=True, drop=True)
|
|
||||||
|
self.beginMoveRows(parent, row + 1, row + 1, parent, target)
|
||||||
|
|
||||||
|
self._undo_stack.push(
|
||||||
|
MoveCommand(
|
||||||
|
self._profile, "down", row
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
self.endMoveRows()
|
self.endMoveRows()
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def copyTable(self, start_selection, end_selection):
|
def paste(self, row, points):
|
||||||
end_selection = self.rowCount()
|
if row > self._profile.number_points:
|
||||||
|
return
|
||||||
|
|
||||||
self._data.loc[start_selection:end_selection]\
|
if len(points) == 0:
|
||||||
.to_clipboard(header=None, index=False, excel=True, sep='\t')
|
return
|
||||||
|
|
||||||
def insert_df_to_idx(self, idx, df, df_insert):
|
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
idx: is the index position in df where you want to insert new dataframe (df_insert)
|
|
||||||
df: dataframe
|
|
||||||
df_insert: dataframe to insert
|
|
||||||
Returns:
|
|
||||||
The dataframe df with df_insert inserted at index idx.
|
|
||||||
"""
|
|
||||||
return df.iloc[:idx, ].append(df_insert).append(df.iloc[idx:, ]).reset_index(drop=True)
|
|
||||||
|
|
||||||
def pasteTable(self, insertion_index):
|
|
||||||
self.layoutAboutToBeChanged.emit()
|
self.layoutAboutToBeChanged.emit()
|
||||||
df = pd.read_clipboard(header=None, skip_blank_lines=True,
|
|
||||||
sep="\t", names=self.header)
|
|
||||||
self._data = self.insert_df_to_idx(insertion_index, self._data, df)
|
|
||||||
|
|
||||||
for i in [3]:
|
self._undo_stack.push(
|
||||||
self._data.iloc[:, i].replace(np.nan, '', inplace=True)
|
PasteCommand(
|
||||||
|
self._profile, row, points
|
||||||
self.layoutChanged.emit()
|
)
|
||||||
self._data.iloc[:, 4] = projection_pointXYZ.update_station(
|
|
||||||
self.header,
|
|
||||||
self._data.values.tolist()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
|
||||||
def model_data(self):
|
|
||||||
return self._data
|
|
||||||
|
|
||||||
@model_data.setter
|
|
||||||
def model_data(self, new_data):
|
|
||||||
self._data = new_data
|
|
||||||
self.layoutChanged.emit()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def x(self):
|
|
||||||
return self._data.iloc[:, 0].tolist()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def y(self):
|
|
||||||
return self._data.iloc[:, 1].tolist()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def z(self):
|
|
||||||
return self._data.iloc[:, 2].tolist()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
return self._data.iloc[:, 3].tolist()
|
|
||||||
|
|
||||||
def get_data(self):
|
|
||||||
return self._data
|
|
||||||
|
|
||||||
@property
|
|
||||||
def station(self):
|
|
||||||
return self._data.iloc[:, 4].tolist()
|
|
||||||
|
|
||||||
def remove_duplicates_names(self):
|
|
||||||
counter_list = []
|
|
||||||
list_deleted_names = []
|
|
||||||
ind_ind = []
|
|
||||||
|
|
||||||
for ind, name_point in enumerate(self.name):
|
|
||||||
if name_point not in counter_list:
|
|
||||||
counter_list.append(name_point)
|
|
||||||
elif len(name_point.strip()) > 0 and name_point in counter_list:
|
|
||||||
ind_ind.append(ind)
|
|
||||||
|
|
||||||
if name_point not in list_deleted_names:
|
|
||||||
list_deleted_names.append(name_point)
|
|
||||||
|
|
||||||
for ind in ind_ind:
|
|
||||||
self._data.iat[ind, 3] = ""
|
|
||||||
|
|
||||||
def data_contains_nan(self) -> bool:
|
|
||||||
"""
|
|
||||||
Returns:
|
|
||||||
Returns True if the QTableView() contains np.nan
|
|
||||||
"""
|
|
||||||
return self._data.isnull().values.any()
|
|
||||||
|
|
||||||
def delete_empty_rows(self):
|
|
||||||
self.layoutAboutToBeChanged.emit()
|
self.layoutAboutToBeChanged.emit()
|
||||||
|
|
||||||
self._data.dropna(inplace=True)
|
|
||||||
self._data.reset_index(drop=True, inplace=True)
|
|
||||||
|
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def valide_all_changes(self):
|
def undo(self):
|
||||||
self.profile.x = self._data.iloc[:, 0]
|
self._undo_stack.undo()
|
||||||
self.profile.y = self._data.iloc[:, 1]
|
self.layoutChanged.emit()
|
||||||
self.profile.z = self._data.iloc[:, 2]
|
|
||||||
self.profile.ld = self._data.iloc[:, 3]
|
def redo(self):
|
||||||
|
self._undo_stack.redo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
|
||||||
class Delegate(QtWidgets.QStyledItemDelegate):
|
class Delegate(QtWidgets.QStyledItemDelegate):
|
||||||
|
|
@ -375,48 +285,18 @@ class Delegate(QtWidgets.QStyledItemDelegate):
|
||||||
self.setModelDataEvent = setModelDataEvent
|
self.setModelDataEvent = setModelDataEvent
|
||||||
|
|
||||||
def createEditor(self, parent, option, index):
|
def createEditor(self, parent, option, index):
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
parent:
|
|
||||||
option:
|
|
||||||
index:
|
|
||||||
Returns:
|
|
||||||
Le widget (éditeur) pour éditer l'item se trouvant à l'index index.
|
|
||||||
"""
|
|
||||||
index.model().data(index, Qt.DisplayRole)
|
index.model().data(index, Qt.DisplayRole)
|
||||||
return QtWidgets.QLineEdit(parent)
|
return QtWidgets.QLineEdit(parent)
|
||||||
|
|
||||||
def setEditorData(self, editor, index):
|
def setEditorData(self, editor, index):
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
editor: l'éditeur
|
|
||||||
index: l'index
|
|
||||||
Returns: permet de transmettre à l'éditeur editor les données à afficher à partir du modèle se trouvant
|
|
||||||
à l'index index.
|
|
||||||
"""
|
|
||||||
value = index.model().data(index, Qt.DisplayRole)
|
value = index.model().data(index, Qt.DisplayRole)
|
||||||
editor.setText(str(value))
|
editor.setText(str(value))
|
||||||
|
|
||||||
def setModelData(self, editor, model, index):
|
def setModelData(self, editor, model, index):
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
editor: l'éditeur
|
|
||||||
model: le modèle
|
|
||||||
index: l'index
|
|
||||||
Returns: permet de récupérer les données de l'éditeur et de les stocker à l'intérieur du modèle, à l'index
|
|
||||||
identifié par le paramètre index
|
|
||||||
"""
|
|
||||||
model.setData(index, editor.text())
|
model.setData(index, editor.text())
|
||||||
|
|
||||||
if not self.setModelDataEvent is None:
|
if not self.setModelDataEvent is None:
|
||||||
self.setModelDataEvent()
|
self.setModelDataEvent()
|
||||||
|
|
||||||
def updateEditorGeometry(self, editor, option, index):
|
def updateEditorGeometry(self, editor, option, index):
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
editor: l'éditeur
|
|
||||||
option:
|
|
||||||
index: l'index
|
|
||||||
Returns: Permet de redimensionner l'éditeur à la bonne taille lorsque la taille de la vue change
|
|
||||||
"""
|
|
||||||
editor.setGeometry(option.rect)
|
editor.setGeometry(option.rect)
|
||||||
|
|
|
||||||
|
|
@ -178,11 +178,11 @@ class PandasModelEditable(QAbstractTableModel):
|
||||||
|
|
||||||
|
|
||||||
def move_row_up(self, row, parent=QModelIndex()):
|
def move_row_up(self, row, parent=QModelIndex()):
|
||||||
target = row + 2
|
|
||||||
|
|
||||||
if row <= 0:
|
if row <= 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
target = row + 2
|
||||||
|
|
||||||
self.beginMoveRows(parent, row - 1, row - 1, parent, target)
|
self.beginMoveRows(parent, row - 1, row - 1, parent, target)
|
||||||
|
|
||||||
self._undo_stack.push(
|
self._undo_stack.push(
|
||||||
|
|
@ -195,11 +195,11 @@ class PandasModelEditable(QAbstractTableModel):
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def move_row_down(self, row, parent=QModelIndex()):
|
def move_row_down(self, row, parent=QModelIndex()):
|
||||||
target = row
|
|
||||||
|
|
||||||
if row > self._reach.number_profiles:
|
if row > self._reach.number_profiles:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
target = row
|
||||||
|
|
||||||
self.beginMoveRows(parent, row + 1, row + 1, parent, target)
|
self.beginMoveRows(parent, row + 1, row + 1, parent, target)
|
||||||
|
|
||||||
self._undo_stack.push(
|
self._undo_stack.push(
|
||||||
|
|
@ -249,8 +249,8 @@ class Delegate(QtWidgets.QStyledItemDelegate):
|
||||||
return QtWidgets.QLineEdit(parent)
|
return QtWidgets.QLineEdit(parent)
|
||||||
|
|
||||||
def setEditorData(self, editor, index):
|
def setEditorData(self, editor, index):
|
||||||
value = index.model().data(index, Qt.DisplayRole) # DisplayRole
|
value = index.model().data(index, Qt.DisplayRole)
|
||||||
editor.setText(str(value)) # récupère la valeur de la cellule applique la méthode définie dans setData
|
editor.setText(str(value))
|
||||||
|
|
||||||
def setModelData(self, editor, model, index):
|
def setModelData(self, editor, model, index):
|
||||||
model.setData(index, editor.text())
|
model.setData(index, editor.text())
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue