mirror of https://gitlab.com/pamhyr/pamhyr2
306 lines
8.3 KiB
Python
306 lines
8.3 KiB
Python
# Table.py -- Pamhyr
|
|
# Copyright (C) 2023-2025 INRAE
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import numpy as np
|
|
import logging
|
|
import traceback
|
|
|
|
from tools import timer, trace
|
|
|
|
from PyQt5.QtGui import (
|
|
QFont, QColor
|
|
)
|
|
from PyQt5.QtWidgets import (
|
|
QMessageBox, QStyledItemDelegate, QLineEdit
|
|
)
|
|
from PyQt5.QtCore import (
|
|
QModelIndex, Qt, QVariant, QCoreApplication
|
|
)
|
|
|
|
from View.Tools.PamhyrTable import PamhyrTableModel
|
|
|
|
from Model.Geometry.PointXYZ import PointXYZ
|
|
from Model.Geometry.ProfileXYZ import ProfileXYZ
|
|
|
|
from View.Geometry.Profile.UndoCommand import *
|
|
|
|
logger = logging.getLogger()
|
|
|
|
_translate = QCoreApplication.translate
|
|
|
|
|
|
class GeometryProfileTableModel(PamhyrTableModel):
|
|
def get_true_data_row(self, row):
|
|
profile = self._data.point(row)
|
|
|
|
return next(
|
|
map(
|
|
lambda e: e[0],
|
|
filter(
|
|
lambda e: e[1] == profile,
|
|
enumerate(self._data._points)
|
|
)
|
|
), 0
|
|
)
|
|
|
|
def data(self, index, role=Qt.DisplayRole):
|
|
if index.isValid():
|
|
if role == Qt.DisplayRole:
|
|
value = ""
|
|
|
|
if index.column() == 0:
|
|
value = self._data.point(index.row()).x
|
|
elif index.column() == 1:
|
|
value = self._data.point(index.row()).y
|
|
elif index.column() == 2:
|
|
value = self._data.point(index.row()).z
|
|
elif index.column() == 3:
|
|
value = self._data.point(index.row()).name
|
|
elif index.column() == 4:
|
|
station = self._data.get_station()
|
|
if station is None:
|
|
return "-"
|
|
else:
|
|
value = station[index.row()]
|
|
return f"{value:.3f}"
|
|
|
|
if 0 <= index.column() < 3:
|
|
return f"{value:.4f}"
|
|
|
|
return f"{value}"
|
|
|
|
if role == Qt.TextAlignmentRole:
|
|
return Qt.AlignHCenter | Qt.AlignVCenter
|
|
|
|
if index.column() == 2:
|
|
value = self._data.point(index.row()).z
|
|
if role == Qt.ForegroundRole:
|
|
if value == self._data.z_min():
|
|
return QColor("red")
|
|
elif value == self._data.z_max():
|
|
return QColor("blue")
|
|
|
|
if index.column() == 3:
|
|
value = self._data.point(index.row()).name
|
|
|
|
if value.strip().upper() in ["RG", "RD"]:
|
|
if role == Qt.FontRole:
|
|
font = QFont()
|
|
font.setBold(True)
|
|
return font
|
|
|
|
if role == Qt.ForegroundRole:
|
|
return QColor("darkRed")
|
|
|
|
return QVariant()
|
|
|
|
def setData(self, index, value, role=Qt.EditRole):
|
|
row = index.row()
|
|
column = index.column()
|
|
|
|
if role == Qt.EditRole:
|
|
try:
|
|
if column == 0:
|
|
self._undo.push(
|
|
SetXCommand(
|
|
self._data, row,
|
|
self._data.point(row).x,
|
|
value.replace(",", ".")
|
|
)
|
|
)
|
|
elif column == 1:
|
|
self._undo.push(
|
|
SetYCommand(
|
|
self._data, row,
|
|
self._data.point(row).y,
|
|
value.replace(",", ".")
|
|
)
|
|
)
|
|
elif column == 2:
|
|
self._undo.push(
|
|
SetZCommand(
|
|
self._data, row,
|
|
self._data.point(row).z,
|
|
value.replace(",", ".")
|
|
)
|
|
)
|
|
elif column == 3:
|
|
self._undo.push(
|
|
SetNameCommand(
|
|
self._data, row,
|
|
self._data.point(row).name,
|
|
value
|
|
)
|
|
)
|
|
except Exception as e:
|
|
logger.info(e)
|
|
logger.debug(traceback.format_exc())
|
|
|
|
self.dataChanged.emit(index, index)
|
|
return True
|
|
|
|
self.dataChanged.emit(index, index)
|
|
self.layoutChanged.emit()
|
|
return False
|
|
|
|
def index(self, row, column, parent=QModelIndex()):
|
|
if not self.hasIndex(row, column, parent):
|
|
return QModelIndex()
|
|
|
|
return self.createIndex(row, column, QModelIndex())
|
|
|
|
def flags(self, index):
|
|
flg = Qt.ItemIsSelectable
|
|
|
|
if index.column() == 4:
|
|
return flg
|
|
|
|
return Qt.ItemIsEditable | Qt.ItemIsEnabled | flg
|
|
|
|
def insert_row(self, row, parent=QModelIndex()):
|
|
self.beginInsertRows(parent, row, row - 1)
|
|
|
|
row = self.get_true_data_row(row)
|
|
|
|
self._undo.push(
|
|
AddCommand(
|
|
self._data, row
|
|
)
|
|
)
|
|
|
|
self.endInsertRows()
|
|
self.layoutChanged.emit()
|
|
|
|
def remove_rows(self, rows, parent=QModelIndex()):
|
|
self.beginRemoveRows(parent, rows[0], rows[-1])
|
|
|
|
self._undo.push(
|
|
DelCommand(
|
|
self._data, list(
|
|
map(
|
|
lambda r: self._data.point(r),
|
|
rows
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
self.endRemoveRows()
|
|
self.layoutChanged.emit()
|
|
|
|
def sort(self, column='x', order=Qt.AscendingOrder):
|
|
self.layoutAboutToBeChanged.emit()
|
|
|
|
reverse = (order != Qt.AscendingOrder)
|
|
|
|
self._undo.push(
|
|
SortCommand(
|
|
self._data, column, reverse
|
|
)
|
|
)
|
|
|
|
self.layoutChanged.emit()
|
|
|
|
def move_up(self, row, parent=QModelIndex()):
|
|
if row <= 0:
|
|
return
|
|
|
|
target = row + 1
|
|
self.beginMoveRows(parent, row - 1, row - 1, parent, target)
|
|
|
|
row = self.get_true_data_row(row)
|
|
self._undo.push(
|
|
MoveCommand(
|
|
self._data, "up", row
|
|
)
|
|
)
|
|
|
|
self.endMoveRows()
|
|
self.layoutChanged.emit()
|
|
|
|
def move_down(self, row, parent=QModelIndex()):
|
|
if row > self._data.number_points:
|
|
return
|
|
|
|
target = row
|
|
self.beginMoveRows(parent, row + 1, row + 1, parent, target)
|
|
|
|
row = self.get_true_data_row(row)
|
|
self._undo.push(
|
|
MoveCommand(
|
|
self._data, "down", row
|
|
)
|
|
)
|
|
|
|
self.endMoveRows()
|
|
self.layoutChanged.emit()
|
|
|
|
def purge(self, np_purge):
|
|
|
|
self._undo.push(
|
|
PurgeCommand(
|
|
self._data, np_purge
|
|
)
|
|
)
|
|
|
|
self.layoutChanged.emit()
|
|
|
|
def reverse(self):
|
|
self._undo.push(
|
|
ReverseCommand(
|
|
self._data
|
|
)
|
|
)
|
|
|
|
self.layoutChanged.emit()
|
|
|
|
def paste(self, row, header, data):
|
|
if row > self._data.number_points:
|
|
return
|
|
|
|
if len(data) == 0:
|
|
return
|
|
|
|
self.layoutAboutToBeChanged.emit()
|
|
|
|
points = list(
|
|
map(
|
|
lambda d: self._data.point_from_data(header, d),
|
|
data
|
|
)
|
|
)
|
|
|
|
row = self.get_true_data_row(row)
|
|
|
|
self._undo.push(
|
|
PasteCommand(
|
|
self._data, row, points
|
|
)
|
|
)
|
|
|
|
self.layoutAboutToBeChanged.emit()
|
|
self.layoutChanged.emit()
|
|
|
|
def undo(self):
|
|
self._undo.undo()
|
|
self.layoutChanged.emit()
|
|
|
|
def redo(self):
|
|
self._undo.redo()
|
|
self.layoutChanged.emit()
|