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

geometry: Copy/Paste with system clipboard.

Showing with 115 additions and 22 deletions
+115 -22
...@@ -116,3 +116,44 @@ class FileFormatError(ExeceptionWithMessageBox): ...@@ -116,3 +116,44 @@ class FileFormatError(ExeceptionWithMessageBox):
_translate("Exception", "format because of") + _translate("Exception", "format because of") +
f" '{self.reason}'" f" '{self.reason}'"
) )
class ClipboardFormatError(ExeceptionWithMessageBox):
def __init__(self, mime=None, header=None, data=None):
super(ClipboardFormatError, self).__init__(
title = _translate("Exception", "Clipboard format error")
)
self.mime = mime
self.header = header
self.data = data
if self.mime is not None:
self.msg = f"Impossible to decode data to mime code '{self.mime}'"
else:
if len(self.header) == 0:
msg = _translate("Exception", "without header")
else:
msg = (
_translate("Exception", "with header") +
f": {self.header}"
)
self.msg = (
_translate("Exception", "Invalid clipboard data format:") +
f" '{self.data}' {msg}"
)
self.alert()
def __str__(self):
return self.msg
def header(self):
return _translate("Exception", "Clipboard format error")
def short_message(self):
return _translate("Exception", "Clipboard format unknown")
def message(self):
return self.msg
...@@ -10,11 +10,12 @@ from Model.Geometry.PointXYZ import PointXYZ ...@@ -10,11 +10,12 @@ from Model.Geometry.PointXYZ import PointXYZ
from Model.Geometry.Vector_1d import Vector1d from Model.Geometry.Vector_1d import Vector1d
class ProfileXYZ(Profile): class ProfileXYZ(Profile):
def __init__(self, num: int = 0, def __init__(self,
code1: int = 0, code2: int = 0, name: str = "",
kp: float = 0.,
reach = None,
nb_point: int = 0, nb_point: int = 0,
kp: float = 0., name: str = "", code1: int = 0, code2: int = 0):
reach = None):
"""ProfileXYZ constructor """ProfileXYZ constructor
Args: Args:
...@@ -28,7 +29,7 @@ class ProfileXYZ(Profile): ...@@ -28,7 +29,7 @@ class ProfileXYZ(Profile):
Nothing. Nothing.
""" """
super(ProfileXYZ, self).__init__( super(ProfileXYZ, self).__init__(
num = num, num = 0,
name = name, name = name,
kp = kp, kp = kp,
code1 = code1, code2 = code2, code1 = code1, code2 = code2,
...@@ -36,6 +37,28 @@ class ProfileXYZ(Profile): ...@@ -36,6 +37,28 @@ class ProfileXYZ(Profile):
reach = reach, reach = reach,
) )
@classmethod
def from_data(cls, header, data):
profile = None
try:
if len(header) == 0:
profile = cls(
*data
)
else:
valid_header = {'name', 'reach', 'kp'}
d = {}
for i, v in enumerate(data):
h = header[i].strip().lower().split(' ')[0]
if h in valid_header:
d[h] = v
profile = cls(**d)
except Exception as e:
raise ClipboardFormatError(header, data)
return profile
def x(self): def x(self):
return [point.x for point in self._points] return [point.x for point in self._points]
......
...@@ -24,14 +24,19 @@ class WindowToolKit(object): ...@@ -24,14 +24,19 @@ class WindowToolKit(object):
def __init__(self, parent=None): def __init__(self, parent=None):
super(WindowToolKit, self).__init__() super(WindowToolKit, self).__init__()
def copyTableIntoClipboard(self, table):
stream = StringIO()
csv.writer(stream, delimiter='\t').writerows(table)
QApplication.clipboard().setText(stream.getvalue())
def parseClipboardTable(self): def parseClipboardTable(self):
clip = QApplication.clipboard() clip = QApplication.clipboard()
mime = clip.mimeData() mime = clip.mimeData()
# print(mime.formats()) if 'text/plain' not in mime.formats():
data = mime.data('text/plain').data().decode() raise ClipboardFormatError(mime='text/plain')
data = mime.data('text/plain').data().decode()
has_header = csv.Sniffer().has_header(data) has_header = csv.Sniffer().has_header(data)
print(f"header? {has_header}")
header = [] header = []
values = [] values = []
......
...@@ -6,7 +6,7 @@ import sys ...@@ -6,7 +6,7 @@ import sys
import time import time
from copy import deepcopy from copy import deepcopy
from tools import timer from tools import timer, trace
from PyQt5 import QtWidgets from PyQt5 import QtWidgets
from PyQt5.QtGui import ( from PyQt5.QtGui import (
...@@ -372,18 +372,27 @@ class GeometryWindow(QMainWindow, WindowToolKit): ...@@ -372,18 +372,27 @@ class GeometryWindow(QMainWindow, WindowToolKit):
.selectionModel()\ .selectionModel()\
.selectedRows() .selectedRows()
self._clipboard = [] table = []
table.append(["name", "kp"])
for row in rows: for row in rows:
self._clipboard.append( profile = self._reach.profile(row.row())
deepcopy( table.append(
self._reach.profile(row.row()) [profile.name, profile.kp]
)
) )
self.copyTableIntoClipboard(table)
def paste(self): def paste(self):
header, data = self.parseClipboardTable()
if len(header) != 0:
header.append("reach")
for row in data:
row.append(self._reach)
row = self.index_selected_row() row = self.index_selected_row()
self._tablemodel.paste(row, self._clipboard) self._tablemodel.paste(row, header, data)
self.select_current_profile() self.select_current_profile()
def undo(self): def undo(self):
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
import time import time
from tools import timer, trace
from PyQt5.QtGui import ( from PyQt5.QtGui import (
QKeySequence, QColor QKeySequence, QColor
) )
...@@ -16,6 +18,7 @@ from PyQt5.QtWidgets import ( ...@@ -16,6 +18,7 @@ from PyQt5.QtWidgets import (
) )
from Model.Geometry import Reach from Model.Geometry import Reach
from Model.Geometry.ProfileXYZ import ProfileXYZ
from View.Geometry.ReachUndoCommand import * from View.Geometry.ReachUndoCommand import *
...@@ -30,11 +33,16 @@ class TableEditableModel(QAbstractTableModel): ...@@ -30,11 +33,16 @@ class TableEditableModel(QAbstractTableModel):
self._undo_stack = undo self._undo_stack = undo
self._reach = reach self._reach = reach
# Hack for qtlinguist
_ = _translate("Geometry", "Name")
_ = _translate("Geometry", "Kp (m)")
_ = _translate("Geometry", "Type")
if headers is None: if headers is None:
self.headers = [ self.headers = [
_translate("Geometry", "Name"), "Name",
_translate("Geometry", "Kp (m)"), "Kp (m)",
_translate("Geometry", "Type") "Type"
] ]
else: else:
self.headers = headers self.headers = headers
...@@ -79,7 +87,7 @@ class TableEditableModel(QAbstractTableModel): ...@@ -79,7 +87,7 @@ class TableEditableModel(QAbstractTableModel):
if role == Qt.DisplayRole: if role == Qt.DisplayRole:
if orientation == Qt.Horizontal: if orientation == Qt.Horizontal:
if section < len(self.headers): if section < len(self.headers):
return self.headers[section] return _translate("Geometry", self.headers[section])
else: else:
return str(section + 1) return str(section + 1)
...@@ -204,18 +212,25 @@ class TableEditableModel(QAbstractTableModel): ...@@ -204,18 +212,25 @@ class TableEditableModel(QAbstractTableModel):
self.endMoveRows() self.endMoveRows()
self.layoutChanged.emit() self.layoutChanged.emit()
def paste(self, row, profiles): @trace
def paste(self, row, header, data):
if row > self._reach.number_profiles: if row > self._reach.number_profiles:
return return
if len(profiles) == 0: if len(data) == 0:
return return
self.layoutAboutToBeChanged.emit() self.layoutAboutToBeChanged.emit()
self._undo_stack.push( self._undo_stack.push(
PasteCommand( PasteCommand(
self._reach, row, profiles self._reach, row,
list(
map(
lambda d: ProfileXYZ.from_data(header, d),
data
)
)
) )
) )
......
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