AddFile: Add deleted flags.

scenarios
Pierre-Antoine Rouby 2024-08-27 17:08:40 +02:00
parent 8c99268bb8
commit ac32995e01
5 changed files with 394 additions and 10 deletions

View File

@ -112,6 +112,7 @@ class AddFile(SQLSubModel):
CREATE TABLE additional_files{ext} (
{cls.create_db_add_pamhyr_id()},
enabled BOOLEAN NOT NULL,
deleted BOOLEAN NOT NULL DEFAULT FALSE,
name TEXT NOT NULL,
path TEXT NOT NULL,
text TEXT NOT NULL,
@ -126,9 +127,9 @@ class AddFile(SQLSubModel):
@classmethod
def _db_update(cls, execute, version, data=None):
major, minor, release = version.strip().split(".")
if major == minor == "0":
release = int(release)
if major == minor == "0":
if release < 8:
cls._db_create(execute)
return True
@ -136,6 +137,13 @@ class AddFile(SQLSubModel):
if 8 < release < 13:
cls._db_update_to_0_0_13(execute, data)
if major == "0" and minor == "1":
if release < 2:
execute(
"ALTER TABLE additional_files " +
"ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE"
)
return True
@classmethod
@ -166,7 +174,7 @@ class AddFile(SQLSubModel):
return new
table = execute(
"SELECT pamhyr_id, enabled, name, path, text, scenario " +
"SELECT pamhyr_id, enabled, deleted, name, path, text, scenario " +
"FROM additional_files " +
f"WHERE scenario = {scenario.id} " +
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))})"
@ -177,6 +185,7 @@ class AddFile(SQLSubModel):
id = next(it)
enabled = (next(it) == 1)
deleted = (next(it) == 1)
name = next(it)
path = next(it)
text = next(it)
@ -186,6 +195,8 @@ class AddFile(SQLSubModel):
id=id, enabled=enabled, name=name, path=path, text=text,
status=data['status'], owner_scenario=owner_scenario
)
if deleted:
f.set_as_deleted()
loaded.add(id)
new.append(f)
@ -200,18 +211,17 @@ class AddFile(SQLSubModel):
if not self.must_be_saved():
return True
sql = (
execute(
"INSERT INTO " +
"additional_files(pamhyr_id, enabled, " +
"additional_files(pamhyr_id, enabled, deleted, " +
"name, path, text, scenario) " +
"VALUES (" +
f"{self._pamhyr_id}, {self._enabled}, " +
f"{self._pamhyr_id}, {self._enabled}, {self.is_deleted()}, " +
f"'{self._db_format(self._name)}', " +
f"'{self._db_format(self._path)}', " +
f"'{self._db_format(self._text)}', " +
f"{self._status.scenario_id}"
")"
)
execute(sql)
return True

View File

@ -19,7 +19,7 @@
from tools import trace, timer
from Model.Except import NotImplementedMethodeError
from Model.Tools.PamhyrList import PamhyrModelList
from Model.Tools.PamhyrListExt import PamhyrModelList
from Model.AdditionalFile.AddFile import AddFile

View File

@ -162,6 +162,17 @@ class SQLSubModel(PamhyrID):
super(SQLSubModel, self).__init__(id)
self._status = status
# Deletion status of the model object. This status MUST be set
# to True if an object that exists in a parent scenario is
# deleted in current scenario.
self._deleted = False
# The 'owner_scenario' is the id of the scenario to which the
# object belongs. This id CAN be different to current
# scenario, but in case of object modification, this id MUST
# be set to current scenario id. (This action is made in
# 'modified' method.)
self._owner_scenario = 0
if owner_scenario == -1:
if status is not None:
@ -170,12 +181,49 @@ class SQLSubModel(PamhyrID):
self._owner_scenario = owner_scenario
def must_be_saved(self):
"""Return True if this object MUST be save in the save file.
Returns:
True if this object MUST be save, otherelse False
"""
return self._owner_scenario == self._status.scenario_id
def modified(self):
"""Set study status to modified and update the object
owner_scenario to current scenario
Returns:
Nothing
"""
self._owner_scenario = self._status.scenario_id
self._status.modified()
def is_deleted(self):
"""This object is deleted?
Returns:
True if this object is deleted, otherelse False
"""
return self._deleted
def set_as_deleted(self):
"""Set object deleted flag to True.
Returns:
Nothing
"""
self._deleted = True
self.modified()
def set_as_not_deleted(self):
"""Set object deleted flag to False.
Returns:
Nothing
"""
self._deleted = False
self.modified()
def _db_format(self, value):
# Replace ''' by '&#39;' to preserve SQL injection
if type(value) is str:

View File

@ -0,0 +1,324 @@
# PamhyrList.py -- Pamhyr Abstract List object for the Model
# Copyright (C) 2023-2024 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 logging
from copy import copy
from tools import trace, timer
from Model.Tools.PamhyrDB import SQLSubModel
from Model.Except import NotImplementedMethodeError
logger = logging.getLogger()
class PamhyrModelList(SQLSubModel):
_sub_classes = []
def __init__(self, status=None):
super(PamhyrModelList, self).__init__()
self._status = status
self._lst = []
#######
# SQL #
#######
@classmethod
def _db_create(cls, execute):
return cls._create_submodel(execute)
@classmethod
def _db_update(cls, execute, version, data=None):
return cls._update_submodel(execute, version, data)
@classmethod
def _db_load(cls, execute, data=None):
raise NotImplementedMethodeError(cls, cls._db_load)
def _db_save(self, execute, data=None):
raise NotImplementedMethodeError(self, self._db_save)
################
# MODEL METHOD #
################
@property
def lst(self):
"""Return the PamhyrList as a Python list
Return the PamhyrList as a Python list. This list is the
current list witout deleted object used in the PamhyrList
object. **If you need to modify it, please make a copy.**
Returns: The Python list
"""
return list(
filter(
lambda el: not el.is_deleted(),
self._lst
)
)
def __len__(self):
return len(self.lst)
def index(self, el):
return self.lst.index(el)
def get(self, index):
return self.lst[index]
def set(self, index, new):
self.lst[index] = new
if self._status is not None:
self._status.modified()
def new(self, index):
"""Create new elements and add it to list
Args:
index: The index of new elements
Returns:
The new elements
"""
raise NotImplementedMethodeError(self, self.new)
def insert(self, index, new):
self._lst.insert(index, new)
if self._status is not None:
self._status.modified()
def undelete(self, lst):
"""Delete a list of elements
Args:
lst: The list of elements
Returns:
Nothing
"""
for el in lst:
el.set_as_not_deleted()
def delete(self, lst):
"""Delete a list of elements
Args:
lst: The list of elements
Returns:
Nothing
"""
for el in lst:
el.set_as_deleted()
def delete_i(self, indexes):
"""Delete elements from list of indexes
Args:
indexes: The elements indexes
Returns:
Nothing
"""
lst = list(
map(
lambda x: x[1],
filter(
lambda x: x[0] in indexes,
enumerate(self.lst)
)
)
)
self.delete(lst)
def sort(self, reverse=False, key=None):
self._lst.sort(reverse=reverse, key=key)
if self._status is not None:
self._status.modified()
def move_up(self, index):
if index < len(self._lst):
next = index - 1
lst = self._lst
lst[index], lst[next] = lst[next], lst[index]
if self._status is not None:
self._status.modified()
def move_down(self, index):
if index >= 0:
prev = index + 1
lst = self._lst
lst[index], lst[prev] = lst[prev], lst[index]
if self._status is not None:
self._status.modified()
class PamhyrModelListWithTab(SQLSubModel):
_tabs_list = []
_sub_classes = []
def __init__(self, status=None):
super(PamhyrModelListWithTab, self).__init__()
self._status = status
self._tabs = {}
for tab in self._tabs_list:
self._tabs[tab] = []
#######
# SQL #
#######
@classmethod
def _db_create(cls, execute):
return cls._create_submodel(execute)
@classmethod
def _db_update(cls, execute, version, data=None):
return cls._update_submodel(execute, version, data)
@classmethod
def _db_load(cls, execute, data=None):
raise NotImplementedMethodeError(cls, cls._db_load)
def _db_save(self, execute, data=None):
raise NotImplementedMethodeError(self, self._db_save)
################
# MODEL METHOD #
################
def len(self, lst):
"""Size of tab list
Args:
lst: The tab name
Returns:
The size of the tab list
"""
return len(self._tabs[lst])
def get_tab(self, lst):
"""Get tab list (copy) from name
Args:
lst: The tab name
Returns:
Nothing
"""
return self._tabs[lst].copy()
def get(self, lst, index):
return self._tabs[lst][index]
def set(self, lst, index, new):
self._tabs[lst][index] = new
self._status.modified()
def new(self, lst, index):
"""Create new elements and add it to list
Args:
lst: The tab name
index: The index of new elements
Returns:
The new elements
"""
raise NotImplementedMethodeError(self, self.new)
def insert(self, lst, index, new):
"""Insert element in tab
Args:
lst: The tab name
index: The index of new element
new: The new elements
Returns:
Nothing
"""
self._tabs[lst].insert(index, new)
self._status.modified()
def delete(self, lst, els):
"""Delete elements from specific tab
Args:
lst: The tab name
els: The elements list
Returns:
Nothing
"""
for el in els:
self._tabs[lst].remove(el)
self._status.modified()
def delete_i(self, lst, indexes):
"""Delete elements from specific tab
Args:
lst: The tab name
indexes: The elements indexes
Returns:
Nothing
"""
els = list(
map(
lambda x: x[1],
filter(
lambda x: x[0] in indexes,
enumerate(self._tabs[lst])
)
)
)
self.delete(lst, els)
def sort(self, lst, reverse=False, key=None):
self._tabs[lst].sort(reverse=reverse, key=key)
self._status.modified()
def move_up(self, lst, index):
if index < len(self._tabs[lst]):
next = index - 1
lst = self._tabs[lst]
lst[index], lst[next] = lst[next], lst[index]
self._status.modified()
def move_down(self, lst, index):
if index >= 0:
prev = index + 1
lst = self._tabs[lst]
lst[index], lst[prev] = lst[prev], lst[index]
self._status.modified()

View File

@ -64,7 +64,8 @@ class AddCommand(QUndoCommand):
if self._new is None:
self._new = self._files.new(self._row)
else:
self._files.insert(self._row, self._new)
self._files.undelete([self._new])
# self._files.insert(self._row, self._new)
class DelCommand(QUndoCommand):
@ -76,7 +77,8 @@ class DelCommand(QUndoCommand):
self._old = self._files.get(row)
def undo(self):
self._files.insert(self._row, self._old)
self._files.undelete([self._old])
# self._files.insert(self._row, self._old)
def redo(self):
self._files.delete_i([self._row])