Line data Source code
1 : /// Including Schema Editor
2 : #include "dbe/SchemaMainWindow.hpp"
3 : #include "dbe/SchemaKernelWrapper.hpp"
4 : #include "dbe/SchemaGraphicsScene.hpp"
5 : #include "dbe/SchemaTab.hpp"
6 : #include "dbe/SchemaClassEditor.hpp"
7 : #include "dbe/SchemaRelationshipEditor.hpp"
8 : #include "dbe/SchemaMethodImplementationEditor.hpp"
9 : #include "dbe/SchemaFileInfo.hpp"
10 : #include "dbe/SchemaStyle.hpp"
11 :
12 : #include "oks/kernel.hpp" // for CanNotSetActiveFile exception
13 :
14 : /// Including Auto-Generated Files
15 : #include "ui_SchemaMainWindow.h"
16 : /// Including QT Headers
17 : #include <QFileDialog>
18 : #include <QMessageBox>
19 : #include <QHeaderView>
20 : #include <QPushButton>
21 : #include <QGraphicsScene>
22 : #include "QInputDialog"
23 : #include <QCloseEvent>
24 : #include <QPrinter>
25 : #include <QPrintDialog>
26 : #include <QSvgGenerator>
27 :
28 : //#include <format>
29 : #include <sstream>
30 :
31 : using namespace dunedaq;
32 : using namespace dunedaq::oks;
33 :
34 :
35 0 : dbse::SchemaMainWindow::SchemaMainWindow ( QString SchemaFile, QWidget * parent )
36 : : QMainWindow ( parent ),
37 0 : ui ( new Ui::SchemaMainWindow ),
38 0 : FileModel ( nullptr ),
39 0 : TableModel ( nullptr ),
40 0 : m_proxyModel ( new QSortFilterProxyModel() ),
41 0 : ContextMenuFileView ( nullptr ),
42 0 : ContextMenuTableView ( nullptr )
43 : {
44 0 : SchemaStyle::load();
45 :
46 0 : InitialSettings();
47 0 : InitialTab();
48 0 : InitialTabCorner();
49 0 : SetController();
50 0 : setFocusPolicy( Qt::StrongFocus );
51 :
52 0 : OpenSchemaFile(SchemaFile);
53 0 : }
54 :
55 0 : dbse::SchemaMainWindow::~SchemaMainWindow() = default;
56 :
57 0 : void dbse::SchemaMainWindow::InitialSettings()
58 : {
59 0 : ui->setupUi ( this );
60 0 : setWindowTitle ( m_title );
61 0 : ui->UndoView->setStack ( KernelWrapper::GetInstance().GetUndoStack() );
62 0 : ui->ClassTableView->horizontalHeader()->setSectionResizeMode ( QHeaderView::Stretch );
63 0 : ui->ClassTableView->setDragEnabled ( true );
64 0 : ui->ClassTableView->setContextMenuPolicy ( Qt::ContextMenuPolicy::CustomContextMenu );
65 0 : ui->FileView->horizontalHeader()->setSectionResizeMode ( QHeaderView::Stretch );
66 0 : ui->FileView->setContextMenuPolicy ( Qt::ContextMenuPolicy::CustomContextMenu );
67 0 : ui->FileView->setSelectionBehavior ( QAbstractItemView::SelectRows );
68 0 : ui->TabWidget->setTabsClosable ( true );
69 0 : ui->ClassTableSearchLine->setProperty ( "placeholderText",
70 0 : QVariant ( QString ( "Search for classes regex" ) ) );
71 0 : ui->ClassTableSearchLine->setClearButtonEnabled(true);
72 0 : m_proxyModel->setFilterCaseSensitivity (Qt::CaseInsensitive);
73 0 : }
74 :
75 0 : void dbse::SchemaMainWindow::InitialTab()
76 : {
77 0 : add_tab();
78 0 : ui->TabWidget->removeTab ( 0 );
79 0 : }
80 :
81 0 : void dbse::SchemaMainWindow::InitialTabCorner()
82 : {
83 0 : QPushButton * RightButton = new QPushButton ( "+" );
84 0 : ui->TabWidget->setCornerWidget ( RightButton, Qt::TopLeftCorner );
85 0 : connect ( RightButton, SIGNAL ( clicked() ), this, SLOT ( add_tab() ) );
86 0 : }
87 :
88 0 : void dbse::SchemaMainWindow::SetController()
89 : {
90 0 : connect ( ui->OpenFileSchema, SIGNAL ( triggered() ), this, SLOT ( OpenSchemaFile() ) );
91 0 : connect ( ui->CreateNewSchema, SIGNAL ( triggered() ), this, SLOT ( CreateNewSchema() ) );
92 0 : connect ( ui->ShowSchema, SIGNAL ( triggered() ), this, SLOT ( show_file_info_active_schema() ) );
93 0 : connect ( ui->SaveSchema, SIGNAL ( triggered() ), this, SLOT ( SaveSchema() ) );
94 0 : connect ( ui->SetRelationship, SIGNAL ( triggered ( bool ) ), this,
95 : SLOT ( ChangeCursorRelationship ( bool ) ) );
96 0 : connect ( ui->SetInheritance, SIGNAL ( triggered ( bool ) ), this,
97 : SLOT ( ChangeCursorInheritance ( bool ) ) );
98 0 : connect ( ui->AddClass, SIGNAL ( triggered() ), this, SLOT ( AddNewClass() ) );
99 0 : connect ( ui->SaveView, SIGNAL ( triggered() ), this, SLOT ( SaveView() ) );
100 0 : connect ( ui->SaveViewAs, SIGNAL ( triggered() ), this, SLOT ( SaveViewAs() ) );
101 0 : connect ( ui->LoadView, SIGNAL ( triggered() ), this, SLOT ( LoadView() ) );
102 0 : connect ( ui->NameView, SIGNAL ( triggered() ), this, SLOT ( NameView() ) );
103 0 : connect ( ui->Exit, SIGNAL ( triggered() ), this, SLOT ( close() ) );
104 :
105 0 : connect ( ui->actionSettings, SIGNAL (triggered() ), this, SLOT ( edit_settings() ));
106 :
107 0 : connect ( ui->ClassTableView, SIGNAL ( activated ( QModelIndex ) ), this,
108 : SLOT ( LaunchClassEditor ( QModelIndex ) ) );
109 0 : connect ( ui->close_tab, SIGNAL ( triggered() ), this, SLOT ( close_tab() ) );
110 :
111 0 : connect ( &KernelWrapper::GetInstance(), SIGNAL ( ClassCreated( QString ) ), this,
112 : SLOT ( update_models() ) );
113 0 : connect ( &KernelWrapper::GetInstance(), SIGNAL ( ClassUpdated ( QString ) ), this,
114 : SLOT ( update_models() ) );
115 0 : connect ( &KernelWrapper::GetInstance(), SIGNAL ( ClassRemoved ( QString ) ), this,
116 : SLOT ( update_models() ) );
117 0 : connect ( &KernelWrapper::GetInstance(), SIGNAL ( active_updated ( ) ), this,
118 : SLOT ( update_models() ) );
119 0 : connect ( ui->TabWidget, SIGNAL ( tabCloseRequested ( int ) ), this,
120 : SLOT ( RemoveTab ( int ) ) );
121 :
122 0 : connect ( ui->FileView, SIGNAL ( customContextMenuRequested ( QPoint ) ), this,
123 : SLOT ( CustomContextMenuFileView ( QPoint ) ) );
124 0 : connect ( ui->FileView, SIGNAL ( activated(QModelIndex) ), this, SLOT ( show_file_info(QModelIndex) ) );
125 :
126 :
127 0 : connect ( ui->ClassTableView, SIGNAL ( customContextMenuRequested ( QPoint ) ), this,
128 : SLOT ( CustomContextMenuTableView ( QPoint ) ) );
129 0 : connect ( ui->PrintView, SIGNAL ( triggered() ), this, SLOT ( PrintCurrentView() ) );
130 0 : connect ( ui->exportView, SIGNAL ( triggered() ), this, SLOT ( export_current_view() ) );
131 0 : connect ( ui->ClassTableSearchLine, SIGNAL( textChanged ( QString ) ), m_proxyModel, SLOT( setFilterRegExp( QString ) ) );
132 0 : connect ( ui->case_sensitive, SIGNAL ( stateChanged(int) ), this,
133 : SLOT (toggle_case_sensitive(int)) );
134 0 : }
135 :
136 0 : void dbse::SchemaMainWindow::show_file_info_active_schema()
137 : {
138 0 : show_file_info(QString::fromStdString(
139 0 : KernelWrapper::GetInstance().GetActiveSchema()));
140 0 : }
141 :
142 0 : void dbse::SchemaMainWindow::show_file_info()
143 : {
144 0 : QModelIndex index = ui->FileView->currentIndex();
145 0 : show_file_info(index);
146 0 : }
147 0 : void dbse::SchemaMainWindow::show_file_info(QModelIndex index)
148 : {
149 0 : QStringList row = FileModel->getRowFromIndex ( index );
150 0 : show_file_info(row.at ( 0 ));
151 0 : }
152 0 : void dbse::SchemaMainWindow::show_file_info(QString fn) {
153 0 : bool widget_found = false;
154 0 : for ( QWidget * widget : QApplication::allWidgets() ) {
155 0 : auto sfi = dynamic_cast<SchemaFileInfo *> ( widget );
156 0 : if ( sfi != nullptr ) {
157 0 : if ( (sfi->objectName() ).compare ( fn ) == 0 ) {
158 0 : sfi->raise();
159 0 : sfi->setVisible ( true );
160 0 : sfi->activateWindow();
161 : widget_found = true;
162 : break;
163 : }
164 : }
165 0 : }
166 0 : if ( !widget_found ) {
167 0 : auto info = new SchemaFileInfo(fn.toStdString());
168 0 : connect (info, &SchemaFileInfo::files_updated,
169 : this, &SchemaMainWindow::update_models);
170 0 : connect (info, &SchemaFileInfo::new_window,
171 : this, &SchemaMainWindow::connect_file_info);
172 0 : info->show();
173 : }
174 0 : }
175 0 : void dbse::SchemaMainWindow::connect_file_info(SchemaFileInfo* win){
176 0 : std::cout << __FUNCTION__ << " New SchemaFileInfo\n";
177 0 : connect (win, &SchemaFileInfo::files_updated,
178 : this, &SchemaMainWindow::update_models);
179 0 : }
180 0 : void dbse::SchemaMainWindow::BuildFileModel()
181 : {
182 0 : QStringList Headers { "File Name", "Access", "Status" };
183 :
184 0 : if ( FileModel != nullptr )
185 : {
186 0 : delete FileModel;
187 : }
188 0 : FileModel = new CustomFileModel ( Headers );
189 :
190 0 : ui->FileView->setModel ( FileModel );
191 0 : ui->FileView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
192 0 : ui->FileView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
193 0 : ui->FileView->horizontalHeader()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
194 0 : }
195 :
196 0 : void dbse::SchemaMainWindow::BuildTableModel()
197 : {
198 0 : QStringList Headers
199 0 : { "Class Name" };
200 :
201 0 : if ( TableModel != nullptr )
202 : {
203 0 : delete TableModel;
204 : }
205 0 : TableModel = new CustomTableModel ( Headers );
206 :
207 0 : m_proxyModel->setSourceModel(TableModel);
208 0 : ui->ClassTableView->setModel ( m_proxyModel );
209 0 : }
210 :
211 0 : int dbse::SchemaMainWindow::ShouldSaveViewChanges() const
212 : {
213 0 : QString modified_views;
214 0 : for (int index=0; index<ui->TabWidget->count(); ++index) {
215 0 : auto tab = dynamic_cast<SchemaTab *> (ui->TabWidget->widget(index));
216 0 : if (tab->GetScene()->IsModified()) {
217 0 : auto label = ui->TabWidget->tabText(index);
218 0 : label = label.remove('*');
219 0 : modified_views.append(" " + label + "\n");
220 0 : }
221 : }
222 0 : if (!modified_views.isEmpty()) {
223 0 : QString message ( "There are unsaved changes in the schema views:\n");
224 0 : message.append (modified_views);
225 0 : message.append ("Do you want to save the changes in the schema views?\n" );
226 0 : return QMessageBox::question (
227 0 : 0, tr ( "SchemaEditor" ),
228 : message,
229 : QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Discard );
230 0 : }
231 :
232 : return QMessageBox::Discard;
233 0 : }
234 :
235 0 : int dbse::SchemaMainWindow::ShouldSaveChanges() const
236 : {
237 : // if ( KernelWrapper::GetInstance().GetUndoStack()->isClean() )
238 0 : auto modified = KernelWrapper::GetInstance().ModifiedSchemaFiles();
239 0 : if (modified.empty())
240 : {
241 : return QMessageBox::Discard;
242 : }
243 :
244 0 : std::string msg = "There are unsaved changes in the following files:\n\n"
245 0 : + modified + "Do you want to save the changes in the schema?\n";
246 0 : return QMessageBox::question (
247 0 : 0, tr ( "SchemaEditor" ),
248 0 : QString ( msg.c_str() ),
249 0 : QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Save );
250 0 : }
251 :
252 0 : void dbse::SchemaMainWindow::AddNewClass()
253 : {
254 0 : SchemaClassEditor::createNewClass();
255 0 : BuildFileModel();
256 0 : }
257 :
258 0 : void dbse::SchemaMainWindow::RemoveClass()
259 : {
260 0 : QModelIndex Index = ui->ClassTableView->currentIndex();
261 0 : QModelIndex proxyIndex = m_proxyModel->mapToSource( Index );
262 0 : QStringList Row = TableModel->getRowFromIndex ( proxyIndex );
263 0 : OksClass * SchemaClass = KernelWrapper::GetInstance().FindClass ( Row.at (
264 0 : 0 ).toStdString() );
265 :
266 0 : if ( SchemaClass->all_sub_classes()->size() != 0 )
267 : {
268 0 : QMessageBox::warning ( 0, "Schema editor",
269 0 : QString ( "Cannot delete class because it has sub-classes." ) );
270 0 : return;
271 : }
272 0 : else if ( KernelWrapper::GetInstance().AnyClassReferenceThis ( SchemaClass ) )
273 : {
274 0 : QMessageBox::warning ( 0, "Schema editor",
275 0 : QString ( "Cannot delete class because some classes references it." ) );
276 0 : return;
277 : }
278 : else
279 : {
280 0 : QString Name = QString::fromStdString ( SchemaClass->get_name() );
281 0 : KernelWrapper::GetInstance().PushRemoveClassCommand ( SchemaClass, SchemaClass->get_name(),
282 0 : SchemaClass->get_description(),
283 0 : SchemaClass->get_is_abstract() );
284 0 : BuildFileModel();
285 0 : }
286 0 : }
287 :
288 0 : void dbse::SchemaMainWindow::editClass() {
289 0 : QModelIndex Index = ui->ClassTableView->currentIndex();
290 0 : QModelIndex proxyIndex = m_proxyModel->mapToSource( Index );
291 0 : QStringList Row = TableModel->getRowFromIndex ( proxyIndex );
292 :
293 0 : if ( !Row.isEmpty() ) {
294 0 : bool widget_found = false;
295 0 : QString class_name = Row.at ( 0 );
296 0 : OksClass * class_info = KernelWrapper::GetInstance().FindClass (
297 0 : class_name.toStdString() );
298 :
299 0 : for ( QWidget * widget : QApplication::allWidgets() ) {
300 0 : auto editor = dynamic_cast<SchemaClassEditor *> ( widget );
301 0 : if ( editor != nullptr ) {
302 0 : if ( ( editor->objectName() ).compare ( class_name ) == 0 ) {
303 0 : editor->raise();
304 0 : editor->setVisible ( true );
305 0 : editor->activateWindow();
306 : widget_found = true;
307 : }
308 : }
309 0 : }
310 0 : if ( !widget_found ) {
311 0 : SchemaClassEditor * editor = new SchemaClassEditor ( class_info );
312 0 : editor->show();
313 : }
314 0 : }
315 0 : }
316 :
317 0 : void dbse::SchemaMainWindow::SetSchemaFileActive()
318 : {
319 0 : QModelIndex index = ui->FileView->currentIndex();
320 0 : QString file = FileModel->getRowFromIndex ( index ).at(0);
321 0 : try {
322 0 : KernelWrapper::GetInstance().SetActiveSchema ( file.toStdString() );
323 : }
324 0 : catch (oks::CanNotSetActiveFile& exc) {
325 0 : QMessageBox::warning(0,
326 : "Set Active Schema",
327 0 : QString("Could not make schema active!\n\n").append(QString(exc.what())),
328 : QMessageBox::Ok);
329 0 : return;
330 0 : }
331 0 : update_window_title(file);
332 :
333 : // In case we are highlighting classes in the active file, redraw current
334 : // view tab now we've changed active file
335 0 : SchemaTab * current_tab = dynamic_cast<SchemaTab *> ( ui->TabWidget->currentWidget() );
336 0 : SchemaGraphicsScene * scene = current_tab->GetScene();
337 0 : scene->update();
338 :
339 0 : BuildFileModel();
340 0 : }
341 :
342 0 : bool dbse::SchemaMainWindow::check_schema_file(QString qfilename){
343 0 : std::string filename = qfilename.toStdString();
344 0 : std::set<std::string> includes;
345 0 : KernelWrapper::GetInstance().get_all_includes(filename, includes);
346 :
347 0 : QString advice{"<br><br>Use the File info window to fix the problem."};
348 0 : for (auto cls: KernelWrapper::GetInstance().get_schema_classes(filename)) {
349 0 : auto relationships = cls->direct_relationships();
350 0 : if (relationships != nullptr) {
351 0 : for (auto rel: *relationships) {
352 0 : auto rel_class = rel->get_class_type();
353 0 : if (rel_class == nullptr) {
354 0 : QString warning = "<b>Warning</b> class <i>"
355 0 : + QString::fromStdString(cls->get_name())
356 0 : + "</i> has relationship "
357 0 : + QString::fromStdString(rel->get_name())
358 0 : + " referring to class <i>"
359 0 : + QString::fromStdString(rel->get_type())
360 0 : + "</i> which is not loaded<br>";
361 0 : QMessageBox::warning(0,
362 : "Check Schema",
363 0 : warning+advice,
364 : QMessageBox::Ok);
365 0 : show_file_info(qfilename);
366 0 : return false;
367 0 : }
368 0 : auto file = rel_class->get_file()->get_full_file_name();
369 0 : if (file != filename && !includes.contains(file)) {
370 0 : QString warning = "<b>Warning</b> class <i>"
371 0 : + QString::fromStdString(cls->get_name())
372 0 : + "</i> has relationship "
373 0 : + QString::fromStdString(rel->get_name())
374 0 : + " referring to class <i>"
375 0 : + QString::fromStdString(rel->get_class_type()->get_name())
376 0 : + "</i> from " + QString::fromStdString(file)
377 0 : + " which is not included by " + qfilename;
378 0 : QMessageBox::warning(0,
379 : "Check Schema",
380 0 : warning+advice,
381 : QMessageBox::Ok);
382 0 : show_file_info(qfilename);
383 0 : return false;
384 0 : }
385 0 : }
386 : }
387 :
388 0 : auto super_classes = cls->direct_super_classes();
389 0 : if (super_classes != nullptr) {
390 0 : for (auto sc: *super_classes) {
391 0 : auto sclass = KernelWrapper::GetInstance().FindClass(*sc);
392 0 : if (sclass == nullptr) {
393 0 : QString warning = "<b>Warning</b> class <i>"
394 0 : + QString::fromStdString(cls->get_name())
395 0 : + "</i> refers to super class <i>" + QString::fromStdString(*sc)
396 0 : + "</i> which is not known<br>";
397 0 : QMessageBox::warning(0,
398 : "Check Schema",
399 0 : warning+advice,
400 : QMessageBox::Ok);
401 0 : show_file_info(qfilename);
402 0 : return false;
403 0 : }
404 0 : auto file = sclass->get_file()->get_full_file_name();
405 0 : if (file != filename && !includes.contains(file)) {
406 0 : QString warning = "<b>Warning</b> class <i>"
407 0 : + QString::fromStdString(cls->get_name())
408 0 : + "</i> refers to super class <i>" + QString::fromStdString(*sc)
409 0 : + "</i> from " + QString::fromStdString(file)
410 0 : + " which is not included by" + qfilename;
411 0 : QMessageBox::warning(0,
412 : "Check Schema",
413 0 : warning+advice,
414 : QMessageBox::Ok);
415 0 : show_file_info(qfilename);
416 0 : return false;
417 0 : }
418 0 : }
419 : }
420 0 : }
421 0 : return true;
422 0 : }
423 :
424 0 : bool dbse::SchemaMainWindow::save_schema_file(QString filename){
425 0 : if (!check_schema_file(filename)) {
426 : return false;
427 : }
428 0 : bool status;
429 0 : QString message;
430 0 : try {
431 0 : KernelWrapper::GetInstance().SaveSchema (filename.toStdString());
432 0 : message = QString ( "File %1 saved" ).arg (filename);
433 0 : status = true;
434 : }
435 0 : catch (const oks::exception& exc) {
436 0 : message = QString ( "Failed to save file %1" ).arg (filename);
437 0 : status = false;
438 0 : }
439 0 : ui->StatusBar->showMessage( message );
440 0 : return status;
441 0 : }
442 :
443 0 : void dbse::SchemaMainWindow::SaveSchemaFile()
444 : {
445 0 : QModelIndex index = ui->FileView->currentIndex();
446 0 : const auto file = FileModel->getRowFromIndex (index).at (0);
447 0 : save_schema_file (file);
448 0 : BuildFileModel();
449 0 : }
450 :
451 0 : void dbse::SchemaMainWindow::PrintCurrentView()
452 : {
453 0 : SchemaTab * CurrentTab = dynamic_cast<SchemaTab *> ( ui->TabWidget->currentWidget() );
454 :
455 0 : QPrinter printer;
456 :
457 0 : if ( QPrintDialog ( &printer ).exec() == QDialog::Accepted )
458 : {
459 0 : QPainter painter ( &printer );
460 0 : painter.setRenderHint ( QPainter::Antialiasing );
461 :
462 0 : SchemaGraphicsScene * Scene = CurrentTab->GetScene();
463 0 : QGraphicsView * View = CurrentTab->GetView();
464 0 : Scene->render ( &painter, QRectF(), View->viewport()->rect() );
465 0 : }
466 0 : }
467 0 : void dbse::SchemaMainWindow::export_current_view(){
468 0 : auto tab = dynamic_cast<SchemaTab *> ( ui->TabWidget->currentWidget() );
469 :
470 0 : auto file = QFileDialog::getSaveFileName(
471 0 : this, tr("Export to SVG"),
472 0 : m_export_path,
473 0 : tr("SVG files (*.svg);;All files (*)"));
474 0 : if (file.isEmpty()) {
475 0 : return;
476 : }
477 :
478 0 : auto spos = file.lastIndexOf('/');
479 0 : if (spos != -1) {
480 0 : m_export_path = file;
481 0 : m_export_path.truncate(spos);
482 : }
483 :
484 0 : auto scene = tab->GetScene();
485 0 : auto view = tab->GetView();
486 :
487 0 : QSvgGenerator generator;
488 0 : generator.setFileName(file);
489 0 : auto vpr=view->viewport()->rect();
490 0 : generator.setSize(QSize(vpr.width(),vpr.height()));
491 0 : generator.setViewBox(vpr);
492 :
493 0 : QPainter painter;
494 0 : painter.begin(&generator);
495 0 : scene->render ( &painter, QRectF(), view->viewport()->rect() );
496 0 : painter.end();
497 0 : }
498 :
499 0 : void dbse::SchemaMainWindow::closeEvent ( QCloseEvent * event )
500 : {
501 0 : int UserChoice = ShouldSaveChanges();
502 :
503 0 : if ( UserChoice == QMessageBox::Save )
504 : {
505 0 : if (!SaveModifiedSchema()) {
506 0 : event->ignore();
507 0 : return;
508 : }
509 : }
510 0 : else if ( UserChoice == QMessageBox::Cancel )
511 : {
512 0 : event->ignore();
513 0 : return;
514 : }
515 :
516 0 : UserChoice = ShouldSaveViewChanges();
517 0 : if ( UserChoice == QMessageBox::Cancel )
518 : {
519 0 : event->ignore();
520 0 : return;
521 : }
522 :
523 0 : KernelWrapper::GetInstance().CloseAllSchema();
524 :
525 0 : for ( QWidget * Widget : QApplication::allWidgets() )
526 : {
527 0 : Widget->close();
528 0 : }
529 :
530 0 : event->accept();
531 : }
532 :
533 0 : void dbse::SchemaMainWindow::update_models() {
534 0 : BuildFileModel();
535 0 : BuildTableModel();
536 0 : }
537 :
538 0 : void dbse::SchemaMainWindow::OpenSchemaFile(QString SchemaFile) {
539 0 : OksFile* file{nullptr};
540 0 : if(!SchemaFile.isEmpty()) {
541 0 : try {
542 0 : file = KernelWrapper::GetInstance().LoadSchema(SchemaFile.toStdString());
543 :
544 0 : if (m_schema_directory == QString(".")) {
545 0 : std::vector<std::string> fnames;
546 0 : KernelWrapper::GetInstance().GetSchemaFiles(fnames);
547 0 : std::string dir = fnames[0].substr(0,fnames[0].find_last_of('/'));
548 0 : m_schema_directory.setPath(QString::fromStdString(dir));
549 0 : }
550 :
551 : #ifdef QT_DEBUG
552 : /// KernelWrapper::GetInstance().ShowSchemaClasses();
553 : #endif
554 : }
555 0 : catch(oks::exception &Ex) {
556 0 : QMessageBox::warning(0,
557 : "Load Schema",
558 0 : QString("Could not load schema!\n\n").append(QString(Ex.what())),
559 : QMessageBox::Ok);
560 0 : }
561 :
562 0 : if (KernelWrapper::GetInstance().GetActiveSchema().empty()) {
563 0 : try {
564 0 : KernelWrapper::GetInstance().SetActiveSchema(SchemaFile.toStdString());
565 : }
566 0 : catch (oks::CanNotSetActiveFile& exc) {
567 0 : QMessageBox::warning(0,
568 : "Load Schema",
569 0 : QString("Could not make schema active!\n\n").append(QString(exc.what())),
570 : QMessageBox::Ok);
571 0 : }
572 : }
573 :
574 0 : BuildTableModel();
575 0 : BuildFileModel();
576 :
577 0 : update_window_title(QFileInfo(SchemaFile).fileName());
578 : //ui->CreateNewSchema->setDisabled (true );
579 : //ui->OpenFileSchema->setDisabled (true );
580 0 : if (file != nullptr) {
581 0 : check_schema_file(QString::fromStdString(file->get_full_file_name()));
582 : }
583 : }
584 0 : }
585 :
586 0 : void dbse:: SchemaMainWindow::update_window_title(QString text) {
587 0 : m_title.remove(QRegularExpression(": --.*"));
588 0 : m_title.append(QString(": -- ") + text);
589 0 : setWindowTitle ( m_title );
590 0 : }
591 :
592 0 : void dbse::SchemaMainWindow::OpenSchemaFile()
593 : {
594 0 : QFileDialog FileDialog ( this, tr ( "Open File" ), ".",
595 0 : tr ( "XML schema files (*.schema.xml);;All files (*)" ) );
596 0 : FileDialog.setAcceptMode ( QFileDialog::AcceptOpen );
597 0 : FileDialog.setFileMode ( QFileDialog::AnyFile );
598 0 : FileDialog.setViewMode ( QFileDialog::Detail );
599 0 : FileDialog.setDirectory ( m_schema_directory );
600 0 : QStringList FilesSelected;
601 0 : QString SchemaPath;
602 :
603 0 : if ( FileDialog.exec() )
604 : {
605 0 : FilesSelected = FileDialog.selectedFiles();
606 : }
607 :
608 0 : if ( FilesSelected.size() )
609 : {
610 0 : m_schema_directory = FileDialog.directory();
611 0 : SchemaPath = FilesSelected.value ( 0 );
612 : }
613 :
614 0 : OpenSchemaFile(SchemaPath);
615 0 : }
616 :
617 0 : bool dbse::SchemaMainWindow::SaveModifiedSchema()
618 : {
619 0 : bool result = true;
620 0 : for (auto file: KernelWrapper::GetInstance().get_modified_schema_files()) {
621 0 : if (!save_schema_file(QString::fromStdString(file))) {
622 0 : result = false;
623 : }
624 0 : }
625 0 : BuildFileModel();
626 0 : return result;
627 : }
628 :
629 0 : void dbse::SchemaMainWindow::SaveSchema()
630 : {
631 0 : auto modified = KernelWrapper::GetInstance().ModifiedSchemaFiles();
632 0 : if (modified.empty())
633 : {
634 0 : QMessageBox::information ( 0, "Schema editor",
635 0 : QString ( "No modified schema files need saving" ) );
636 :
637 : }
638 : else {
639 0 : SaveModifiedSchema();
640 : }
641 0 : BuildFileModel();
642 0 : }
643 :
644 0 : void dbse::SchemaMainWindow::CreateNewSchema()
645 : {
646 0 : QString FileName = QFileDialog::getSaveFileName (
647 0 : this, tr ( "New schema File" ), ".",
648 0 : tr ( "XML schema files (*.schema.xml);;All files (*)" ) );
649 :
650 0 : if ( FileName.isEmpty() )
651 : {
652 0 : QMessageBox::warning ( 0, "Schema editor",
653 0 : QString ( "Please provide a name for the schema !" ) );
654 0 : return;
655 : }
656 :
657 0 : if ( !FileName.endsWith ( ".schema.xml" ) )
658 : {
659 0 : FileName.append ( ".schema.xml" );
660 : }
661 :
662 0 : QFile FileInfo ( FileName );
663 0 : std::string FileNameStd = FileInfo.fileName().toStdString();
664 :
665 0 : try
666 : {
667 0 : KernelWrapper::GetInstance().CreateNewSchema ( FileNameStd );
668 0 : KernelWrapper::GetInstance().SaveSchema ( FileNameStd );
669 0 : BuildTableModel();
670 0 : BuildFileModel();
671 0 : ui->CreateNewSchema->setDisabled (true );
672 0 : ui->OpenFileSchema->setDisabled (true );
673 : }
674 0 : catch ( oks::exception & Ex )
675 : {
676 0 : QMessageBox::warning (
677 : 0,
678 : "Schema editor",
679 0 : QString ( "Could not create file : %1.\n\n%2" ).arg ( QString::fromStdString (
680 0 : FileNameStd ) ).arg (
681 0 : QString ( Ex.what() ) ) );
682 0 : }
683 0 : }
684 :
685 0 : void dbse::SchemaMainWindow::ChangeCursorRelationship ( bool State )
686 : {
687 0 : if ( ui->SetInheritance->isChecked() )
688 : {
689 0 : ui->SetInheritance->setChecked ( false );
690 : }
691 :
692 0 : if ( State )
693 : {
694 0 : ui->TabWidget->setCursor ( Qt::CrossCursor );
695 : }
696 : else
697 : {
698 0 : ui->TabWidget->setCursor ( Qt::ArrowCursor );
699 : }
700 :
701 0 : KernelWrapper::GetInstance().SetInheritanceMode ( false );
702 0 : }
703 :
704 0 : void dbse::SchemaMainWindow::ChangeCursorInheritance ( bool State )
705 : {
706 0 : if ( ui->SetRelationship->isChecked() )
707 : {
708 0 : ui->SetRelationship->setChecked ( false );
709 : }
710 :
711 0 : if ( State )
712 : {
713 0 : ui->TabWidget->setCursor ( Qt::CrossCursor );
714 : }
715 : else
716 : {
717 0 : ui->TabWidget->setCursor ( Qt::ArrowCursor );
718 : }
719 :
720 0 : KernelWrapper::GetInstance().SetInheritanceMode ( true );
721 0 : }
722 :
723 0 : void dbse::SchemaMainWindow::add_tab()
724 : {
725 0 : auto index = ui->TabWidget->addTab ( new SchemaTab(), "unnamed Schema View" );
726 0 : ui->TabWidget->setCurrentIndex ( index );
727 0 : auto tab = dynamic_cast<SchemaTab *> ( ui->TabWidget->currentWidget() );
728 0 : connect (tab->GetScene(), &SchemaGraphicsScene::sceneModified,
729 : this, &dbse::SchemaMainWindow::modifiedView);
730 0 : }
731 :
732 0 : void dbse::SchemaMainWindow::modifiedView(bool modified) {
733 0 : auto index = ui->TabWidget->currentIndex();
734 0 : auto label = ui->TabWidget->tabText(index);
735 0 : if (modified && !label.endsWith("*")) {
736 0 : label += "*";
737 : }
738 0 : if (!modified && label.endsWith("*")) {
739 0 : label = label.remove('*');
740 : }
741 0 : ui->TabWidget->setTabText(index, label);
742 0 : }
743 :
744 0 : void dbse::SchemaMainWindow::NameView() {
745 0 : auto index = ui->TabWidget->currentIndex();
746 0 : bool ok;
747 0 : QString text = QInputDialog::getText(nullptr,
748 : "Schema editor: rename class view",
749 : "New view name:",
750 : QLineEdit::Normal,
751 : "New Class View",
752 0 : &ok);
753 0 : if(ok && !text.isEmpty()) {
754 0 : ui->TabWidget->setTabText(index, text);
755 0 : SchemaTab * CurrentTab = dynamic_cast<SchemaTab *> ( ui->TabWidget->currentWidget() );
756 0 : CurrentTab->setName(text);
757 : }
758 :
759 0 : auto newtext = ui->TabWidget->tabText(index);
760 0 : }
761 :
762 0 : void dbse::SchemaMainWindow::SaveView() {
763 0 : SchemaTab * tab = dynamic_cast<SchemaTab *> ( ui->TabWidget->currentWidget() );
764 0 : if ( tab->GetScene()->items().size() != 0 )
765 : {
766 0 : auto file_name = tab->getFileName();
767 0 : if (file_name == "./") {
768 0 : SaveViewAs();
769 0 : return;
770 : }
771 0 : write_view_file(file_name, tab);
772 0 : }
773 : }
774 0 : void dbse::SchemaMainWindow::SaveViewAs() {
775 0 : SchemaTab * CurrentTab = dynamic_cast<SchemaTab *> ( ui->TabWidget->currentWidget() );
776 0 : if ( CurrentTab->GetScene()->items().size() != 0 )
777 : {
778 0 : auto defName = CurrentTab->getFileName();
779 0 : if (defName == "./") {
780 0 : defName = m_view_dir;
781 : }
782 0 : QString FileName = QFileDialog::getSaveFileName (
783 0 : this, tr ( "Save View" ), defName,
784 0 : tr("View files (*.view);;All files (*)") );
785 :
786 0 : if (! FileName.isEmpty()) {
787 0 : auto spos = FileName.lastIndexOf('/');
788 0 : if (spos != -1) {
789 0 : m_view_dir = FileName;
790 0 : m_view_dir.truncate(spos);
791 : }
792 :
793 0 : if ( !FileName.endsWith ( ".view" ) ) {
794 0 : FileName.append ( ".view" );
795 : }
796 :
797 0 : CurrentTab->setFileName ( FileName );
798 0 : auto text = QFileInfo(FileName).baseName();
799 0 : CurrentTab->setName(text);
800 0 : auto index = ui->TabWidget->currentIndex();
801 0 : ui->TabWidget->setTabText(index, text);
802 :
803 0 : write_view_file(FileName, CurrentTab);
804 0 : }
805 0 : }
806 0 : }
807 :
808 0 : void dbse::SchemaMainWindow::write_view_file (const QString& file_name,
809 : SchemaTab* tab) {
810 0 : QFile file ( file_name );
811 0 : file.open ( QIODevice::WriteOnly );
812 :
813 0 : for ( QGraphicsItem * item : tab->GetScene()->items() ) {
814 0 : auto object = dynamic_cast<SchemaGraphicObject *> ( item );
815 0 : if ( object != nullptr ) {
816 0 : QString description = object->GetClassName() + ","
817 0 : + QString::number ( object->scenePos().x() ) + ","
818 0 : + QString::number ( object->scenePos().y() ) + "\n";
819 0 : file.write ( description.toUtf8() );
820 0 : }
821 : else {
822 0 : auto note = dynamic_cast<SchemaGraphicNote*> (item);
823 0 : if ( note != nullptr && !note->text().isEmpty()) {
824 0 : auto text = note->text().replace("\n", "<br>");
825 0 : text = text.replace(",", "<comma>");
826 0 : QString line = "#,"
827 0 : + QString::number ( note->scenePos().x() ) + ","
828 0 : + QString::number ( note->scenePos().y() ) + ","
829 0 : + text + "\n";
830 0 : file.write ( line.toUtf8() );
831 0 : }
832 : }
833 0 : }
834 :
835 0 : file.close();
836 0 : auto message = QString("Saved view to %1").arg(file_name);
837 0 : ui->StatusBar->showMessage( message );
838 0 : tab->GetScene()->ClearModified();
839 0 : }
840 :
841 0 : void dbse::SchemaMainWindow::LoadView() {
842 0 : QString ViewPath = QFileDialog::getOpenFileName (
843 : this,
844 0 : tr ("Open view file"),
845 0 : m_view_dir,
846 0 : tr("View files (*.view);;All files (*)"));
847 :
848 0 : if ( !ViewPath.isEmpty() )
849 : {
850 0 : auto spos = ViewPath.lastIndexOf('/');
851 0 : if (spos != -1) {
852 0 : m_view_dir = ViewPath;
853 0 : m_view_dir.truncate(spos);
854 : }
855 0 : QFile ViewFile ( ViewPath );
856 0 : ViewFile.open ( QIODevice::ReadOnly );
857 :
858 0 : auto text = QFileInfo(ViewPath).baseName();
859 0 : auto tab = dynamic_cast<SchemaTab *> ( ui->TabWidget->currentWidget() );
860 0 : if (!tab->getName().isEmpty() || tab->GetScene()->IsModified()) {
861 0 : add_tab();
862 0 : tab = dynamic_cast<SchemaTab *> ( ui->TabWidget->currentWidget() );
863 : }
864 0 : auto index = ui->TabWidget->currentIndex();
865 0 : ui->TabWidget->setTabText(index, text);
866 0 : tab->setName(text);
867 0 : tab->setFileName(ViewPath);
868 :
869 0 : QStringList ClassesNames;
870 0 : QList<QPointF> Positions;
871 0 : QList<QPointF> note_positions;
872 0 : QStringList notes;
873 0 : while ( !ViewFile.atEnd() )
874 : {
875 0 : QString Line ( ViewFile.readLine() );
876 0 : if (!Line.isEmpty()) {
877 0 : QStringList ObjectDescription = Line.split ( "," );
878 0 : QPointF Position;
879 0 : Position.setX ( ObjectDescription.at ( 1 ).toInt() );
880 0 : Position.setY ( ObjectDescription.at ( 2 ).toInt() );
881 0 : if (ObjectDescription.at ( 0 ) == "#") {
882 0 : note_positions.append (Position);
883 0 : auto note_text = ObjectDescription.at(3);
884 0 : if (note_text.back() == '\n') {
885 0 : note_text.chop(1);
886 : }
887 0 : note_text = note_text.replace("<br>", "\n");
888 0 : note_text = note_text.replace("<comma>", ",");
889 0 : notes.append ( note_text );
890 0 : }
891 : else {
892 0 : ClassesNames.append ( ObjectDescription.at ( 0 ) );
893 0 : Positions.append ( Position );
894 : }
895 0 : }
896 0 : }
897 0 : ViewFile.close();
898 :
899 0 : auto message = QString("Loaded view from %1").arg(ViewPath);
900 0 : ui->StatusBar->showMessage( message );
901 :
902 0 : auto scene = tab->GetScene();
903 0 : scene->CleanItemMap();
904 0 : auto missing = scene->AddItemsToScene ( ClassesNames, Positions );
905 0 : if (!missing.empty()) {
906 0 : QString warning_text{"The following classes in "};
907 0 : warning_text.append(QFileInfo(ViewPath).fileName());
908 0 : warning_text.append(" are not present in the loaded schema:\n ");
909 0 : warning_text.append(missing.join(",\n "));
910 0 : QMessageBox::warning(this, tr("Load View"), warning_text);
911 0 : }
912 0 : scene->ClearModified();
913 :
914 0 : scene->add_notes(notes, note_positions);
915 0 : }
916 0 : }
917 :
918 0 : void dbse::SchemaMainWindow::LaunchClassEditor ( QModelIndex Index )
919 : {
920 0 : QModelIndex proxyIndex = m_proxyModel->mapToSource( Index );
921 0 : QStringList Row = TableModel->getRowFromIndex ( proxyIndex );
922 :
923 0 : if ( !Row.isEmpty() ) {
924 0 : SchemaClassEditor::launch(Row.at ( 0 ));
925 : }
926 0 : }
927 :
928 0 : void dbse::SchemaMainWindow::close_tab() {
929 0 : RemoveTab(ui->TabWidget->currentIndex());
930 0 : }
931 :
932 0 : void dbse::SchemaMainWindow::RemoveTab ( int index )
933 : {
934 0 : if ( index == -1 || ( ( ui->TabWidget->count() == 1 ) && index == 0 ) ) {
935 0 : return;
936 : }
937 :
938 0 : auto tab = dynamic_cast<SchemaTab *> (ui->TabWidget->widget(index));
939 0 : if (tab->GetScene()->IsModified()) {
940 0 : auto choice = QMessageBox::question (
941 0 : 0, tr ( "SchemaEditor" ),
942 0 : QString ( "There are unsaved changes in the schema view:\n"
943 0 : "Do you really want to delete this schema view?\n" ),
944 : QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel );
945 0 : if (choice == QMessageBox::Cancel) {
946 : return;
947 : }
948 : }
949 0 : ui->TabWidget->removeTab ( index );
950 0 : delete tab;
951 : }
952 :
953 0 : void dbse::SchemaMainWindow::CustomContextMenuFileView ( QPoint Pos )
954 : {
955 0 : if ( ContextMenuFileView == nullptr )
956 : {
957 0 : ContextMenuFileView = new QMenu ( this );
958 :
959 0 : QAction * Act = new QAction ( tr ( "Set as Active Schema" ), this );
960 0 : connect ( Act, SIGNAL ( triggered() ), this, SLOT ( SetSchemaFileActive() ) );
961 0 : QAction * Sav = new QAction ( tr ( "Save Schema File" ), this );
962 0 : connect ( Sav, SIGNAL ( triggered() ), this, SLOT ( SaveSchemaFile() ) );
963 0 : QAction * info = new QAction ( tr ( "Show file info" ), this );
964 0 : connect ( info, SIGNAL ( triggered() ), this, SLOT ( show_file_info() ) );
965 :
966 0 : ContextMenuFileView->addAction ( info );
967 0 : ContextMenuFileView->addAction ( Act );
968 0 : ContextMenuFileView->addAction ( Sav );
969 : }
970 :
971 0 : QModelIndex index = ui->FileView->currentIndex();
972 :
973 0 : if ( index.isValid() )
974 : {
975 0 : QStringList row = FileModel->getRowFromIndex ( index );
976 0 : if (row.at(1) == "RW") {
977 0 : ContextMenuFileView->actions().at(2)->setVisible(true);
978 0 : if (!row.at(2).contains("Active")) {
979 0 : ContextMenuFileView->actions().at(1)->setVisible(true);
980 : }
981 : else {
982 0 : ContextMenuFileView->actions().at(1)->setVisible(false);
983 : }
984 : }
985 : else {
986 0 : ContextMenuFileView->actions().at(2)->setVisible(false);
987 0 : ContextMenuFileView->actions().at(1)->setVisible(false);
988 : }
989 0 : ContextMenuFileView->exec ( ui->FileView->mapToGlobal ( Pos ) );
990 0 : }
991 0 : }
992 :
993 0 : void dbse::SchemaMainWindow::CustomContextMenuTableView ( QPoint Pos )
994 : {
995 0 : if ( ContextMenuTableView == nullptr )
996 : {
997 0 : ContextMenuTableView = new QMenu ( this );
998 :
999 0 : QAction * add = new QAction ( tr ( "&Add New Class" ), this );
1000 0 : connect ( add, SIGNAL ( triggered() ), this, SLOT ( AddNewClass() ) );
1001 :
1002 0 : QAction * remove = new QAction ( tr ( "&Remove Selected Class" ), this );
1003 0 : connect ( remove, SIGNAL ( triggered() ), this, SLOT ( RemoveClass() ) );
1004 :
1005 0 : QAction * edit = new QAction ( tr ( "&Edit Selected Class" ), this );
1006 0 : connect ( edit, SIGNAL ( triggered() ), this, SLOT ( editClass() ) );
1007 :
1008 0 : ContextMenuTableView->addAction ( add );
1009 0 : ContextMenuTableView->addAction ( edit );
1010 0 : ContextMenuTableView->addAction ( remove );
1011 : }
1012 :
1013 0 : QModelIndex Index = ui->ClassTableView->currentIndex();
1014 :
1015 0 : if ( Index.isValid() )
1016 : {
1017 0 : ContextMenuTableView->exec ( ui->ClassTableView->mapToGlobal ( Pos ) );
1018 : }
1019 0 : }
1020 :
1021 0 : void dbse::SchemaMainWindow::toggle_case_sensitive ( int /*state*/ )
1022 : {
1023 0 : if ( ui->case_sensitive->isChecked() ) {
1024 0 : m_proxyModel->setFilterCaseSensitivity ( Qt::CaseSensitive );
1025 : }
1026 : else {
1027 0 : m_proxyModel->setFilterCaseSensitivity ( Qt::CaseInsensitive );
1028 : }
1029 0 : }
1030 0 : void dbse::SchemaMainWindow::update_view() {
1031 0 : auto tab = dynamic_cast<SchemaTab *> ( ui->TabWidget->currentWidget() );
1032 0 : tab->GetScene()->update();
1033 :
1034 0 : BuildTableModel();
1035 0 : BuildFileModel();
1036 0 : }
1037 :
1038 0 : void dbse::SchemaMainWindow::edit_settings() {
1039 0 : if (m_settings == nullptr) {
1040 0 : m_settings = new SchemaSettings(this);
1041 0 : connect(m_settings, SIGNAL(settings_updated()), this, SLOT(update_view()));
1042 : }
1043 0 : m_settings->show();
1044 0 : }
|