VPTissue Reference Manual
TissueEditor.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2011-2016 Universiteit Antwerpen
3  *
4  * Licensed under the EUPL, Version 1.1 or as soon they will be approved by
5  * the European Commission - subsequent versions of the EUPL (the "Licence");
6  * You may not use this work except in compliance with the Licence.
7  * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl5
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the Licence is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the Licence for the specific language governing
13  * permissions and limitations under the Licence.
14  */
20 #include "TissueEditor.h"
21 
22 #include "EditControlLogic.h"
23 #include "EditorActions.h"
24 #include "PTreePanels.h"
25 #include "TissueGraphicsView.h"
26 #include "UndoStack.h"
27 
28 #include "fileformats/PTreeFile.h"
31 #include "gui/PTreeContainer.h"
32 
33 #include <boost/property_tree/detail/ptree_implementation.hpp>
34 #include <boost/property_tree/detail/xml_parser_error.hpp>
35 #include <cassert>
36 #include <QCloseEvent>
37 #include <QDockWidget>
38 #include <QFileDialog>
39 #include <QGraphicsItem>
40 #include <QList>
41 #include <QMessageBox>
42 #include <QMimeData>
43 #include <QStatusBar>
44 #include <QUrl>
45 
46 namespace SimPT_Editor {
47 
48 using namespace std;
49 using namespace boost::property_tree::xml_parser;
50 using namespace SimShell::Gui;
51 using namespace SimPT_Sim::Util;
52 
53 
55  HasUnsavedChangesPrompt("Cell Editor"), m_tissue(nullptr), m_undo_stack(new UndoStack()),
56  m_graphics_view(new TissueGraphicsView(this)),
57  m_ptree_panels(new PTreePanels(this)),
58  m_current_path(QDir().homePath().toStdString()),
59  m_actions(new EditorActions(this, m_graphics_view, m_ptree_panels, m_undo_stack)),
60  m_modified(false)
61 {
62  setWindowTitle("simPT - Tissue Editor");
63  setMenuBar(m_actions);
64  setMinimumSize(800, 600);
65  setAcceptDrops(true);
66 
67  CreateLayout();
68 
69  connect(m_graphics_view, SIGNAL(ItemsSelected(unsigned int)),
70  m_actions, SLOT(ItemsSelected(unsigned int)));
71  connect(m_graphics_view, SIGNAL(ModeChanged()), m_actions, SLOT(ModeChanged()));
72 }
73 
75 
76 void TissueEditor::closeEvent(QCloseEvent* event)
77 {
78  if (CloseLeaf()) {
79  event->accept();
80  } else {
81  event->ignore();
82  }
83 }
84 
85 void TissueEditor::dragEnterEvent(QDragEnterEvent *e)
86 {
87  if (e->mimeData()->hasUrls() ) {
88  if (e->mimeData()->urls().size()==1) {
89  const QString &fileName = e->mimeData()->urls().first().toLocalFile();
90  if (PTreeFile::IsPTreeFile(fileName.toStdString()))
91  e->acceptProposedAction();
92  }
93  }
94 }
95 
96 void TissueEditor::dropEvent(QDropEvent *e)
97 {
98  if (e->mimeData()->urls().size()==1) {
99  const QString &fileName = e->mimeData()->urls().first().toLocalFile();
100  OpenPath(fileName.toStdString());
101  }
102 }
103 
104 bool TissueEditor::CloseLeaf()
105 {
106  return PromptClose(this);
107 }
108 
109 void TissueEditor::CreateLayout()
110 {
111  m_graphics_view->setHidden(true);
112  setCentralWidget(m_graphics_view);
113 
114  m_ptree_panels->AttributePanel()->GetDock()->setHidden(true);
115  m_ptree_panels->GeometricPanel()->GetDock()->setHidden(true);
116  m_ptree_panels->ParametersPanel()->GetDock()->setHidden(true);
117  addDockWidget(Qt::RightDockWidgetArea, m_ptree_panels->AttributePanel()->GetDock());
118  addDockWidget(Qt::RightDockWidgetArea, m_ptree_panels->GeometricPanel()->GetDock());
119  addDockWidget(Qt::LeftDockWidgetArea, m_ptree_panels->ParametersPanel()->GetDock());
120 
121  m_status_info = new QLabel("");
122  statusBar()->addWidget(m_status_info); // m_status_info will be deleted by this widget.
123 }
124 
125 void TissueEditor::GenerateRegularPattern()
126 {
127  m_actions->Show(false);
128  m_graphics_view->GenerateRegularPattern();
129  m_actions->Show(true);
130 }
131 
132 void TissueEditor::GenerateVoronoiPattern()
133 {
134  m_actions->Show(false);
135  m_graphics_view->GenerateVoronoiPattern();
136  m_actions->Show(true);
137 }
138 
139 void TissueEditor::InternalForceClose()
140 {
141  m_graphics_view->Cleanup();
142  m_tissue = nullptr;
143  m_modified = false;
144 
145  m_graphics_view->setHidden(true);
146  m_ptree_panels->AttributePanel()->GetDock()->setHidden(true);
147  m_ptree_panels->GeometricPanel()->GetDock()->setHidden(true);
148  m_ptree_panels->ParametersPanel()->GetDock()->setHidden(true);
149 
150  m_actions->LeafClosed();
151  m_status_info->setText("");
152 }
153 
154 bool TissueEditor::InternalIsClean() const
155 {
156  return !m_modified;
157 }
158 
159 bool TissueEditor::InternalSave()
160 {
161  SaveLeaf();
162  return true;
163 }
164 
166 {
167  return (m_tissue != nullptr);
168 }
169 
170 void TissueEditor::NewLeaf()
171 {
172  try {
173  m_actions->Show(false);
174  //Native dialog has been disabled, due to a bug when an item is selected.
175  string fileName = QFileDialog::getOpenFileName(this,
176  "Select a template file with the attributes of the new tissue",
177  QString::fromStdString(m_current_path), "XML files (*.xml *.xml.gz);;All files (*.*)",
178  nullptr, QFileDialog::DontUseNativeDialog | QFileDialog::ReadOnly).toStdString();
179  m_actions->Show(true);
180 
181  if (fileName != "") {
182  if (m_tissue != nullptr) {
183  CloseLeaf();
184  }
185 
186  if (PTreeFile::IsGzipped(fileName)){
187  PTreeFile::ReadXmlGz(fileName, m_ptree);
188  } else {
189  PTreeFile::ReadXml(fileName, m_ptree);
190  }
191 
192  if (m_ptree.find("vleaf2") == m_ptree.not_found()
193  || m_ptree.get_child("vleaf2").find("mesh") == m_ptree.not_found()
194  || m_ptree.get_child("vleaf2.mesh").find("cells") == m_ptree.not_found()
195  || m_ptree.get_child("vleaf2.mesh.cells").find("chemical_count") == m_ptree.not_found()) {
196 
197  QMessageBox messageBox(this);
198  messageBox.critical(this, "Invalid ptree error", "Property tree doesn't contain valid sim data.");
199  }
200 
201  m_tissue = std::make_shared<EditControlLogic>(
202  m_ptree.get<unsigned int>("vleaf2.mesh.cells.chemical_count"));
203  m_ptree.get_child("vleaf2.mesh").clear();
204 
205  m_undo_stack->Initialize(m_tissue->ToPTree());
206  UpdateViews();
207 
208  connect(m_tissue.get(), SIGNAL(Moved(Node*, double, double)),
209  this, SLOT(SetModifiedWithoutUndo()));
210  connect(m_tissue.get(), SIGNAL(Modified()), this, SLOT(SetModified()));
211  connect(m_tissue.get(), SIGNAL(Modified()), m_actions, SLOT(Modified()));
212  connect(m_tissue.get(), SIGNAL(StatusInfoChanged(const std::string&)),
213  this, SLOT(SetStatusBar(const std::string&)));
214 
215  m_current_path = fileName;
216  m_actions->LeafOpened();
217  m_modified = true;
218  }
219  }
220  catch (boost::property_tree::xml_parser::xml_parser_error& e) {
221  QMessageBox messageBox(this);
222  messageBox.critical(this, "XML parsing error", "Sim data file doesn't contain valid property tree.");
223  }
224 }
225 
226 void TissueEditor::OpenLeaf()
227 {
228  try {
229  m_actions->Show(false);
230  //Native dialog has been disabled, due to a bug when an item is selected.
231  string fileName = QFileDialog::getOpenFileName(this,
232  "Open sim data file", QString::fromStdString(m_current_path),
233  "XML files (*.xml *.xml.gz);;All files (*.*)", nullptr,
234  QFileDialog::DontUseNativeDialog | QFileDialog::ReadOnly).toStdString();
235  m_actions->Show(true);
236 
237  OpenPath(fileName);
238  }
239  catch (boost::property_tree::xml_parser::xml_parser_error& e) {
240  QMessageBox messageBox(this);
241  messageBox.critical(this, "XML parsing error", "Sim data file doesn't contain a valid property tree.");
242  }
243  catch (boost::property_tree::ptree_error& e) {
244  QMessageBox messageBox(this);
245  messageBox.critical(this, "Invalid ptree error", "Property tree doesn't contain sim data.");
246  }
247 }
248 
249 bool TissueEditor::OpenPath(const std::string& path)
250 {
251  try {
252  if (path != "") {
253  if (m_tissue != nullptr) {
254  CloseLeaf();
255  }
256  if (PTreeFile::IsGzipped(path)){
257  PTreeFile::ReadXmlGz(path, m_ptree);
258  } else {
259  PTreeFile::ReadXml(path, m_ptree);
260  }
261 
262  m_tissue = make_shared<EditControlLogic>(m_ptree.get_child("vleaf2"));
263 
264  m_undo_stack->Initialize(m_tissue->ToPTree());
265  UpdateViews();
266 
267  connect(m_tissue.get(), SIGNAL(Moved(Node*, double, double)),
268  this, SLOT(SetModifiedWithoutUndo()));
269  connect(m_tissue.get(), SIGNAL(Modified()), this, SLOT(SetModified()));
270  connect(m_tissue.get(), SIGNAL(Modified()), m_actions, SLOT(Modified()));
271  connect(m_tissue.get(), SIGNAL(StatusInfoChanged(const std::string&)),
272  this, SLOT(SetStatusBar(const std::string&)));
273 
274  m_current_path = path;
275  m_actions->LeafOpened();
276 
277  return true;
278  }
279  }
280  catch (boost::property_tree::xml_parser::xml_parser_error& e) {
281  QMessageBox messageBox(this);
282  messageBox.critical(this, "XML parsing error", "Sim data file doesn't contain a valid property tree.");
283  }
284  catch (boost::property_tree::ptree_error& e) {
285  QMessageBox messageBox(this);
286  messageBox.critical(this, "Invalid ptree error", "Property tree doesn't contain valid sim data.");
287  }
288  catch (std::runtime_error& e) {
289  QMessageBox messageBox(this);
290  messageBox.critical(this, "File not found", "File doesn't exist.");
291  }
292 
293  return false;
294 }
295 
296 void TissueEditor::Redo()
297 {
298  assert(m_undo_stack->CanRedo() && "Tried to redo when it can't be done.");
299 
300  m_tissue = std::make_shared<EditControlLogic>(m_undo_stack->Redo());
301  connect(m_tissue.get(), SIGNAL(Moved(Node*, double, double)),
302  this, SLOT(SetModifiedWithoutUndo()));
303  connect(m_tissue.get(), SIGNAL(Modified()), this, SLOT(SetModified()));
304  connect(m_tissue.get(), SIGNAL(Modified()), m_actions, SLOT(Modified()));
305  connect(m_tissue.get(), SIGNAL(StatusInfoChanged(const std::string&)),
306  this, SLOT(SetStatusBar(const std::string&)));
307 
308  Mode mode = m_graphics_view->GetMode();
309  UpdateViews();
310  m_graphics_view->SetMode(mode);
311 
312  m_actions->Modified();
313 }
314 
315 void TissueEditor::SaveLeaf()
316 {
317  m_actions->Show(false);
318  //Native dialog has been disabled, due to a bug when an item is selected.
319  string fileName = QFileDialog::getSaveFileName(this,
320  "Save sim data file", QString::fromStdString(m_current_path),
321  "XML files (*.xml *.xml.gz);;All files (*.*)", nullptr,
322  QFileDialog::DontUseNativeDialog).toStdString();
323  m_actions->Show(true);
324 
325  if (fileName != "") {
326  boost::property_tree::ptree pt = m_tissue->ToPTree();
327  m_ptree.put_child("vleaf2.mesh", pt.get_child("mesh"));
328  m_ptree.put_child("vleaf2.parameters", pt.get_child("parameters"));
329  if (PTreeFile::IsGzipped(fileName)){
330  PTreeFile::WriteXmlGz(fileName, m_ptree);
331  } else {
332  PTreeFile::WriteXml(fileName, m_ptree);
333  }
334  //xml_writer_settings<char> settings('\t', 1);
335  //write_xml(fileName, m_ptree, std::locale(), settings);
336  m_current_path = fileName;
337  m_modified = false; //data has been written to file, so there is no modified data
338  }
339 }
340 
341 void TissueEditor::SetCellMode()
342 {
343  if (m_graphics_view->GetMode() == Mode::CELL) {
344  m_graphics_view->SetMode(Mode::DISPLAY);
345  } else {
346  m_graphics_view->SetMode(Mode::CELL);
347  }
348 }
349 
350 void TissueEditor::SetEdgeMode()
351 {
352  if (m_graphics_view->GetMode() == Mode::EDGE) {
353  m_graphics_view->SetMode(Mode::DISPLAY);
354  } else {
355  m_graphics_view->SetMode(Mode::EDGE);
356  }
357 }
358 
359 void TissueEditor::SetNodeMode()
360 {
361  if (m_graphics_view->GetMode() == Mode::NODE) {
362  m_graphics_view->SetMode(Mode::DISPLAY);
363  } else {
364  m_graphics_view->SetMode(Mode::NODE);
365  }
366 }
367 
368 void TissueEditor::SetStatusBar(const std::string& info)
369 {
370  m_status_info->setText(QString::fromStdString(info));
371 }
372 
373 void TissueEditor::SetModified()
374 {
375  m_undo_stack->Push(m_tissue->ToPTree());
376  m_modified = true;
377 }
378 
379 void TissueEditor::SetModifiedWithoutUndo()
380 {
381  m_modified = true;
382 }
383 
384 void TissueEditor::Undo()
385 {
386  assert(m_undo_stack->CanUndo() && "Tried to undo when it can't be done.");
387 
388  m_tissue = std::make_shared<EditControlLogic>(m_undo_stack->Undo());
389  connect(m_tissue.get(), SIGNAL(Moved(Node*, double, double)),
390  this, SLOT(SetModifiedWithoutUndo()));
391  connect(m_tissue.get(), SIGNAL(Modified()), this, SLOT(SetModified()));
392  connect(m_tissue.get(), SIGNAL(Modified()), m_actions, SLOT(Modified()));
393  connect(m_tissue.get(), SIGNAL(StatusInfoChanged(const std::string&)),
394  this, SLOT(SetStatusBar(const std::string&)));
395 
396  Mode mode = m_graphics_view->GetMode();
397  UpdateViews();
398  m_graphics_view->SetMode(mode);
399 
400  m_actions->Modified();
401 }
402 
403 void TissueEditor::UpdateViews()
404 {
405  assert(m_tissue != nullptr && "The tissue isn't initialized.");
406 
407  m_graphics_view->SetColorComponent(m_ptree.get_child("vleaf2.parameters"));
408  m_graphics_view->Initialize(m_tissue);
409  m_graphics_view->setHidden(false);
410  m_ptree_panels->Initialize(m_tissue);
411  m_ptree_panels->AttributePanel()->GetDock()->setHidden(false);
412  m_ptree_panels->GeometricPanel()->GetDock()->setHidden(false);
413  m_ptree_panels->ParametersPanel()->GetDock()->setHidden(false);
414 }
415 
416 } // namespace
const boost::property_tree::ptree & Redo()
Redo an action.
Definition: UndoStack.cpp:67
STL namespace.
void dragEnterEvent(QDragEnterEvent *e)
Receive a message when something is dragged over the window.
AppController header.
Interface for PTreeFile.
Namespace for SimPT tissue editor package.
Definition: Cell.h:32
void Push(const boost::property_tree::ptree &tissue)
Push a tissue to the stack.
Definition: UndoStack.cpp:35
Node in cell wall.
Definition: Node.h:39
Namespace for miscellaneous utilities.
Definition: PTreeFile.cpp:44
The graphical view on the tissue.
HasUnsavedChanges with the ability of displaying a "save-discard-cancel" dialog to the user before cl...
Mode
Different modes for the graphicsview.
Interface for PTreePanels.
Interface for the TissueEditor.
void Initialize(const boost::property_tree::ptree &tissue)
Initialize the undo stack with a given tissue.
Definition: UndoStack.cpp:28
Gui::PTreeContainer * ParametersPanel() const
Get the parameters panel.
virtual ~TissueEditor()
Destructor.
Namespace for graphical interface classes.
virtual bool IsOpened() const
True if tissue has been opened, false otherwise.
Interface for EditorActions.
const boost::property_tree::ptree & Undo()
Undo an action.
Definition: UndoStack.cpp:58
void Show(bool visible)
Show or hide the menubar.
bool OpenPath(const std::string &path)
True iff file has been successfully opened (if another file is open, it is closed first)...
void GenerateRegularPattern()
Generates a regular cell pattern in the selected cell.
bool PromptClose(QWidget *parent=nullptr)
Display dialog window containing a list (or tree) of widgets that contain unsaved changes...
Undo Stack for actions performed on a tissue.
Definition: UndoStack.h:31
Manages the attribute and geometric ptree panel for a given tissue.
Definition: PTreePanels.h:35
TissueEditor(QWidget *parent=nullptr)
Constructor with the parent of the window.
void SetColorComponent(const boost::property_tree::ptree &parameters)
Set the colorizer map for coloring the cells in 'NONE'-mode.
QDockWidget * GetDock() const
Get the associated dock widget, containing the ptree editor.
Interface for UndoStack.
see the online Qt documentation
Interface for GraphicsView of tissue.
static bool IsPTreeFile(const std::string &path)
Indicates whether the file has the appropriate extension.
Definition: PTreeFile.cpp:53
void Initialize(std::shared_ptr< EditControlLogic > tissue)
Initializes the panels with a given tissue.
ProjectController header.
bool CanUndo() const
True if the current action can be undone.
Definition: UndoStack.cpp:48
void LeafOpened()
A tissue has been opened.
see the online Qt documentation
void LeafClosed()
The tissue has been closed.
The actions in the menu bar of the workspace.
Definition: EditorActions.h:35
void SetMode(Mode mode)
Set the editing mode of the view.
void Modified()
The tissue has been modified.
void dropEvent(QDropEvent *e)
Recive a message when a file is dropped on the window.
void GenerateVoronoiPattern()
Generates a cell pattern using Voronoi Tesselation in the selected cell.
Gui::PTreeContainer * AttributePanel() const
Get the attribute panel.
bool CanRedo() const
True if the current action can be redone.
Definition: UndoStack.cpp:53
Mode GetMode() const
Returns the current mode.
Interface for LeafControlLogic.
void Initialize(std::shared_ptr< EditControlLogic > tissue, Mode mode=Mode::DISPLAY)
Adds the items in the tissue to the scene.
Gui::PTreeContainer * GeometricPanel() const
Get the geometric panel.
Interface for PTreeContainer.