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::save_schema_file(QString filename){
343 0 : bool status;
344 0 : QString message;
345 0 : try {
346 0 : KernelWrapper::GetInstance().SaveSchema (filename.toStdString());
347 0 : message = QString ( "File %1 saved" ).arg (filename);
348 0 : status = true;
349 : }
350 0 : catch (const oks::exception& exc) {
351 0 : message = QString ( "Failed to save file %1" ).arg (filename);
352 0 : status = false;
353 0 : }
354 0 : ui->StatusBar->showMessage( message );
355 0 : return status;
356 0 : }
357 :
358 0 : void dbse::SchemaMainWindow::SaveSchemaFile()
359 : {
360 0 : QModelIndex index = ui->FileView->currentIndex();
361 0 : const auto file = FileModel->getRowFromIndex (index).at (0);
362 0 : save_schema_file (file);
363 0 : BuildFileModel();
364 0 : }
365 :
366 0 : void dbse::SchemaMainWindow::PrintCurrentView()
367 : {
368 0 : SchemaTab * CurrentTab = dynamic_cast<SchemaTab *> ( ui->TabWidget->currentWidget() );
369 :
370 0 : QPrinter printer;
371 :
372 0 : if ( QPrintDialog ( &printer ).exec() == QDialog::Accepted )
373 : {
374 0 : QPainter painter ( &printer );
375 0 : painter.setRenderHint ( QPainter::Antialiasing );
376 :
377 0 : SchemaGraphicsScene * Scene = CurrentTab->GetScene();
378 0 : QGraphicsView * View = CurrentTab->GetView();
379 0 : Scene->render ( &painter, QRectF(), View->viewport()->rect() );
380 0 : }
381 0 : }
382 0 : void dbse::SchemaMainWindow::export_current_view(){
383 0 : auto tab = dynamic_cast<SchemaTab *> ( ui->TabWidget->currentWidget() );
384 :
385 0 : auto file = QFileDialog::getSaveFileName(
386 0 : this, tr("Export to SVG"),
387 0 : m_export_path,
388 0 : tr("SVG files (*.svg);;All files (*)"));
389 0 : if (file.isEmpty()) {
390 0 : return;
391 : }
392 :
393 0 : auto spos = file.lastIndexOf('/');
394 0 : if (spos != -1) {
395 0 : m_export_path = file;
396 0 : m_export_path.truncate(spos);
397 : }
398 :
399 0 : auto scene = tab->GetScene();
400 0 : auto view = tab->GetView();
401 :
402 0 : QSvgGenerator generator;
403 0 : generator.setFileName(file);
404 0 : auto vpr=view->viewport()->rect();
405 0 : generator.setSize(QSize(vpr.width(),vpr.height()));
406 0 : generator.setViewBox(vpr);
407 :
408 0 : QPainter painter;
409 0 : painter.begin(&generator);
410 0 : scene->render ( &painter, QRectF(), view->viewport()->rect() );
411 0 : painter.end();
412 0 : }
413 :
414 0 : void dbse::SchemaMainWindow::closeEvent ( QCloseEvent * event )
415 : {
416 0 : int UserChoice = ShouldSaveChanges();
417 :
418 0 : if ( UserChoice == QMessageBox::Save )
419 : {
420 0 : SaveModifiedSchema();
421 : }
422 0 : else if ( UserChoice == QMessageBox::Cancel )
423 : {
424 0 : event->ignore();
425 0 : return;
426 : }
427 :
428 0 : UserChoice = ShouldSaveViewChanges();
429 0 : if ( UserChoice == QMessageBox::Cancel )
430 : {
431 0 : event->ignore();
432 0 : return;
433 : }
434 :
435 0 : KernelWrapper::GetInstance().CloseAllSchema();
436 :
437 0 : for ( QWidget * Widget : QApplication::allWidgets() )
438 : {
439 0 : Widget->close();
440 0 : }
441 :
442 0 : event->accept();
443 : }
444 :
445 0 : void dbse::SchemaMainWindow::update_models() {
446 0 : BuildFileModel();
447 0 : BuildTableModel();
448 0 : }
449 :
450 0 : void dbse::SchemaMainWindow::OpenSchemaFile(QString SchemaFile) {
451 0 : if(!SchemaFile.isEmpty()) {
452 0 : try {
453 0 : KernelWrapper::GetInstance().LoadSchema(SchemaFile.toStdString());
454 :
455 0 : if (m_schema_directory == QString(".")) {
456 0 : std::vector<std::string> fnames;
457 0 : KernelWrapper::GetInstance().GetSchemaFiles(fnames);
458 0 : std::string dir = fnames[0].substr(0,fnames[0].find_last_of('/'));
459 0 : m_schema_directory.setPath(QString::fromStdString(dir));
460 0 : }
461 :
462 : #ifdef QT_DEBUG
463 : /// KernelWrapper::GetInstance().ShowSchemaClasses();
464 : #endif
465 : }
466 0 : catch(oks::exception &Ex) {
467 0 : QMessageBox::warning(0,
468 : "Load Schema",
469 0 : QString("Could not load schema!\n\n").append(QString(Ex.what())),
470 : QMessageBox::Ok);
471 0 : }
472 :
473 0 : if (KernelWrapper::GetInstance().GetActiveSchema().empty()) {
474 0 : try {
475 0 : KernelWrapper::GetInstance().SetActiveSchema(SchemaFile.toStdString());
476 : }
477 0 : catch (oks::CanNotSetActiveFile& exc) {
478 0 : QMessageBox::warning(0,
479 : "Load Schema",
480 0 : QString("Could not make schema active!\n\n").append(QString(exc.what())),
481 : QMessageBox::Ok);
482 0 : }
483 : }
484 :
485 0 : BuildTableModel();
486 0 : BuildFileModel();
487 :
488 0 : update_window_title(QFileInfo(SchemaFile).fileName());
489 : //ui->CreateNewSchema->setDisabled (true );
490 : //ui->OpenFileSchema->setDisabled (true );
491 : }
492 0 : }
493 :
494 0 : void dbse:: SchemaMainWindow::update_window_title(QString text) {
495 0 : m_title.remove(QRegularExpression(": --.*"));
496 0 : m_title.append(QString(": -- ") + text);
497 0 : setWindowTitle ( m_title );
498 0 : }
499 :
500 0 : void dbse::SchemaMainWindow::OpenSchemaFile()
501 : {
502 0 : QFileDialog FileDialog ( this, tr ( "Open File" ), ".",
503 0 : tr ( "XML schema files (*.schema.xml);;All files (*)" ) );
504 0 : FileDialog.setAcceptMode ( QFileDialog::AcceptOpen );
505 0 : FileDialog.setFileMode ( QFileDialog::AnyFile );
506 0 : FileDialog.setViewMode ( QFileDialog::Detail );
507 0 : FileDialog.setDirectory ( m_schema_directory );
508 0 : QStringList FilesSelected;
509 0 : QString SchemaPath;
510 :
511 0 : if ( FileDialog.exec() )
512 : {
513 0 : FilesSelected = FileDialog.selectedFiles();
514 : }
515 :
516 0 : if ( FilesSelected.size() )
517 : {
518 0 : m_schema_directory = FileDialog.directory();
519 0 : SchemaPath = FilesSelected.value ( 0 );
520 : }
521 :
522 0 : OpenSchemaFile(SchemaPath);
523 0 : }
524 0 : void dbse::SchemaMainWindow::SaveModifiedSchema()
525 : {
526 0 : for (auto file: KernelWrapper::GetInstance().get_modified_schema_files()) {
527 0 : save_schema_file(QString::fromStdString(file));
528 0 : }
529 0 : BuildFileModel();
530 0 : }
531 :
532 0 : void dbse::SchemaMainWindow::SaveSchema()
533 : {
534 0 : auto modified = KernelWrapper::GetInstance().ModifiedSchemaFiles();
535 0 : if (modified.empty())
536 : {
537 0 : QMessageBox::information ( 0, "Schema editor",
538 0 : QString ( "No modified schema files need saving" ) );
539 :
540 : }
541 : else {
542 0 : SaveModifiedSchema();
543 : }
544 0 : BuildFileModel();
545 0 : }
546 :
547 0 : void dbse::SchemaMainWindow::CreateNewSchema()
548 : {
549 0 : QString FileName = QFileDialog::getSaveFileName (
550 0 : this, tr ( "New schema File" ), ".",
551 0 : tr ( "XML schema files (*.schema.xml);;All files (*)" ) );
552 :
553 0 : if ( FileName.isEmpty() )
554 : {
555 0 : QMessageBox::warning ( 0, "Schema editor",
556 0 : QString ( "Please provide a name for the schema !" ) );
557 0 : return;
558 : }
559 :
560 0 : if ( !FileName.endsWith ( ".schema.xml" ) )
561 : {
562 0 : FileName.append ( ".schema.xml" );
563 : }
564 :
565 0 : QFile FileInfo ( FileName );
566 0 : std::string FileNameStd = FileInfo.fileName().toStdString();
567 :
568 0 : try
569 : {
570 0 : KernelWrapper::GetInstance().CreateNewSchema ( FileNameStd );
571 0 : KernelWrapper::GetInstance().SaveSchema ( FileNameStd );
572 0 : BuildTableModel();
573 0 : BuildFileModel();
574 0 : ui->CreateNewSchema->setDisabled (true );
575 0 : ui->OpenFileSchema->setDisabled (true );
576 : }
577 0 : catch ( oks::exception & Ex )
578 : {
579 0 : QMessageBox::warning (
580 : 0,
581 : "Schema editor",
582 0 : QString ( "Could not create file : %1.\n\n%2" ).arg ( QString::fromStdString (
583 0 : FileNameStd ) ).arg (
584 0 : QString ( Ex.what() ) ) );
585 0 : }
586 0 : }
587 :
588 0 : void dbse::SchemaMainWindow::ChangeCursorRelationship ( bool State )
589 : {
590 0 : if ( ui->SetInheritance->isChecked() )
591 : {
592 0 : ui->SetInheritance->setChecked ( false );
593 : }
594 :
595 0 : if ( State )
596 : {
597 0 : ui->TabWidget->setCursor ( Qt::CrossCursor );
598 : }
599 : else
600 : {
601 0 : ui->TabWidget->setCursor ( Qt::ArrowCursor );
602 : }
603 :
604 0 : KernelWrapper::GetInstance().SetInheritanceMode ( false );
605 0 : }
606 :
607 0 : void dbse::SchemaMainWindow::ChangeCursorInheritance ( bool State )
608 : {
609 0 : if ( ui->SetRelationship->isChecked() )
610 : {
611 0 : ui->SetRelationship->setChecked ( false );
612 : }
613 :
614 0 : if ( State )
615 : {
616 0 : ui->TabWidget->setCursor ( Qt::CrossCursor );
617 : }
618 : else
619 : {
620 0 : ui->TabWidget->setCursor ( Qt::ArrowCursor );
621 : }
622 :
623 0 : KernelWrapper::GetInstance().SetInheritanceMode ( true );
624 0 : }
625 :
626 0 : void dbse::SchemaMainWindow::add_tab()
627 : {
628 0 : auto index = ui->TabWidget->addTab ( new SchemaTab(), "unnamed Schema View" );
629 0 : ui->TabWidget->setCurrentIndex ( index );
630 0 : auto tab = dynamic_cast<SchemaTab *> ( ui->TabWidget->currentWidget() );
631 0 : connect (tab->GetScene(), &SchemaGraphicsScene::sceneModified,
632 : this, &dbse::SchemaMainWindow::modifiedView);
633 0 : }
634 :
635 0 : void dbse::SchemaMainWindow::modifiedView(bool modified) {
636 0 : auto index = ui->TabWidget->currentIndex();
637 0 : auto label = ui->TabWidget->tabText(index);
638 0 : if (modified && !label.endsWith("*")) {
639 0 : label += "*";
640 : }
641 0 : if (!modified && label.endsWith("*")) {
642 0 : label = label.remove('*');
643 : }
644 0 : ui->TabWidget->setTabText(index, label);
645 0 : }
646 :
647 0 : void dbse::SchemaMainWindow::NameView() {
648 0 : auto index = ui->TabWidget->currentIndex();
649 0 : bool ok;
650 0 : QString text = QInputDialog::getText(nullptr,
651 : "Schema editor: rename class view",
652 : "New view name:",
653 : QLineEdit::Normal,
654 : "New Class View",
655 0 : &ok);
656 0 : if(ok && !text.isEmpty()) {
657 0 : ui->TabWidget->setTabText(index, text);
658 0 : SchemaTab * CurrentTab = dynamic_cast<SchemaTab *> ( ui->TabWidget->currentWidget() );
659 0 : CurrentTab->setName(text);
660 : }
661 :
662 0 : auto newtext = ui->TabWidget->tabText(index);
663 0 : }
664 :
665 0 : void dbse::SchemaMainWindow::SaveView() {
666 0 : SchemaTab * tab = dynamic_cast<SchemaTab *> ( ui->TabWidget->currentWidget() );
667 0 : if ( tab->GetScene()->items().size() != 0 )
668 : {
669 0 : auto file_name = tab->getFileName();
670 0 : if (file_name == "./") {
671 0 : SaveViewAs();
672 0 : return;
673 : }
674 0 : write_view_file(file_name, tab);
675 0 : }
676 : }
677 0 : void dbse::SchemaMainWindow::SaveViewAs() {
678 0 : SchemaTab * CurrentTab = dynamic_cast<SchemaTab *> ( ui->TabWidget->currentWidget() );
679 0 : if ( CurrentTab->GetScene()->items().size() != 0 )
680 : {
681 0 : auto defName = CurrentTab->getFileName();
682 0 : if (defName == "./") {
683 0 : defName = m_view_dir;
684 : }
685 0 : QString FileName = QFileDialog::getSaveFileName (
686 0 : this, tr ( "Save View" ), defName,
687 0 : tr("View files (*.view);;All files (*)") );
688 :
689 0 : if (! FileName.isEmpty()) {
690 0 : auto spos = FileName.lastIndexOf('/');
691 0 : if (spos != -1) {
692 0 : m_view_dir = FileName;
693 0 : m_view_dir.truncate(spos);
694 : }
695 :
696 0 : if ( !FileName.endsWith ( ".view" ) ) {
697 0 : FileName.append ( ".view" );
698 : }
699 :
700 0 : CurrentTab->setFileName ( FileName );
701 0 : auto text = QFileInfo(FileName).baseName();
702 0 : CurrentTab->setName(text);
703 0 : auto index = ui->TabWidget->currentIndex();
704 0 : ui->TabWidget->setTabText(index, text);
705 :
706 0 : write_view_file(FileName, CurrentTab);
707 0 : }
708 0 : }
709 0 : }
710 :
711 0 : void dbse::SchemaMainWindow::write_view_file (const QString& file_name,
712 : SchemaTab* tab) {
713 0 : QFile file ( file_name );
714 0 : file.open ( QIODevice::WriteOnly );
715 :
716 0 : for ( QGraphicsItem * item : tab->GetScene()->items() ) {
717 0 : auto object = dynamic_cast<SchemaGraphicObject *> ( item );
718 0 : if ( object != nullptr ) {
719 0 : QString description = object->GetClassName() + ","
720 0 : + QString::number ( object->scenePos().x() ) + ","
721 0 : + QString::number ( object->scenePos().y() ) + "\n";
722 0 : file.write ( description.toUtf8() );
723 0 : }
724 : else {
725 0 : auto note = dynamic_cast<SchemaGraphicNote*> (item);
726 0 : if ( note != nullptr && !note->text().isEmpty()) {
727 0 : auto text = note->text().replace("\n", "<br>");
728 0 : text = text.replace(",", "<comma>");
729 0 : QString line = "#,"
730 0 : + QString::number ( note->scenePos().x() ) + ","
731 0 : + QString::number ( note->scenePos().y() ) + ","
732 0 : + text + "\n";
733 0 : file.write ( line.toUtf8() );
734 0 : }
735 : }
736 0 : }
737 :
738 0 : file.close();
739 0 : auto message = QString("Saved view to %1").arg(file_name);
740 0 : ui->StatusBar->showMessage( message );
741 0 : tab->GetScene()->ClearModified();
742 0 : }
743 :
744 0 : void dbse::SchemaMainWindow::LoadView() {
745 0 : QString ViewPath = QFileDialog::getOpenFileName (
746 : this,
747 0 : tr ("Open view file"),
748 0 : m_view_dir,
749 0 : tr("View files (*.view);;All files (*)"));
750 :
751 0 : if ( !ViewPath.isEmpty() )
752 : {
753 0 : auto spos = ViewPath.lastIndexOf('/');
754 0 : if (spos != -1) {
755 0 : m_view_dir = ViewPath;
756 0 : m_view_dir.truncate(spos);
757 : }
758 0 : QFile ViewFile ( ViewPath );
759 0 : ViewFile.open ( QIODevice::ReadOnly );
760 :
761 0 : auto text = QFileInfo(ViewPath).baseName();
762 0 : auto tab = dynamic_cast<SchemaTab *> ( ui->TabWidget->currentWidget() );
763 0 : if (!tab->getName().isEmpty() || tab->GetScene()->IsModified()) {
764 0 : add_tab();
765 0 : tab = dynamic_cast<SchemaTab *> ( ui->TabWidget->currentWidget() );
766 : }
767 0 : auto index = ui->TabWidget->currentIndex();
768 0 : ui->TabWidget->setTabText(index, text);
769 0 : tab->setName(text);
770 0 : tab->setFileName(ViewPath);
771 :
772 0 : QStringList ClassesNames;
773 0 : QList<QPointF> Positions;
774 0 : QList<QPointF> note_positions;
775 0 : QStringList notes;
776 0 : while ( !ViewFile.atEnd() )
777 : {
778 0 : QString Line ( ViewFile.readLine() );
779 0 : if (!Line.isEmpty()) {
780 0 : QStringList ObjectDescription = Line.split ( "," );
781 0 : QPointF Position;
782 0 : Position.setX ( ObjectDescription.at ( 1 ).toInt() );
783 0 : Position.setY ( ObjectDescription.at ( 2 ).toInt() );
784 0 : if (ObjectDescription.at ( 0 ) == "#") {
785 0 : note_positions.append (Position);
786 0 : auto note_text = ObjectDescription.at(3);
787 0 : if (note_text.back() == '\n') {
788 0 : note_text.chop(1);
789 : }
790 0 : note_text = note_text.replace("<br>", "\n");
791 0 : note_text = note_text.replace("<comma>", ",");
792 0 : notes.append ( note_text );
793 0 : }
794 : else {
795 0 : ClassesNames.append ( ObjectDescription.at ( 0 ) );
796 0 : Positions.append ( Position );
797 : }
798 0 : }
799 0 : }
800 0 : ViewFile.close();
801 :
802 0 : auto message = QString("Loaded view from %1").arg(ViewPath);
803 0 : ui->StatusBar->showMessage( message );
804 :
805 0 : auto scene = tab->GetScene();
806 0 : scene->CleanItemMap();
807 0 : auto missing = scene->AddItemsToScene ( ClassesNames, Positions );
808 0 : if (!missing.empty()) {
809 0 : QString warning_text{"The following classes in "};
810 0 : warning_text.append(QFileInfo(ViewPath).fileName());
811 0 : warning_text.append(" are not present in the loaded schema:\n ");
812 0 : warning_text.append(missing.join(",\n "));
813 0 : QMessageBox::warning(this, tr("Load View"), warning_text);
814 0 : }
815 0 : scene->ClearModified();
816 :
817 0 : scene->add_notes(notes, note_positions);
818 0 : }
819 0 : }
820 :
821 0 : void dbse::SchemaMainWindow::LaunchClassEditor ( QModelIndex Index )
822 : {
823 0 : QModelIndex proxyIndex = m_proxyModel->mapToSource( Index );
824 0 : QStringList Row = TableModel->getRowFromIndex ( proxyIndex );
825 :
826 0 : if ( !Row.isEmpty() ) {
827 0 : SchemaClassEditor::launch(Row.at ( 0 ));
828 : }
829 0 : }
830 :
831 0 : void dbse::SchemaMainWindow::close_tab() {
832 0 : RemoveTab(ui->TabWidget->currentIndex());
833 0 : }
834 :
835 0 : void dbse::SchemaMainWindow::RemoveTab ( int index )
836 : {
837 0 : if ( index == -1 || ( ( ui->TabWidget->count() == 1 ) && index == 0 ) ) {
838 0 : return;
839 : }
840 :
841 0 : auto tab = dynamic_cast<SchemaTab *> (ui->TabWidget->widget(index));
842 0 : if (tab->GetScene()->IsModified()) {
843 0 : auto choice = QMessageBox::question (
844 0 : 0, tr ( "SchemaEditor" ),
845 0 : QString ( "There are unsaved changes in the schema view:\n"
846 : "Do you really want to delete this schema view?\n" ),
847 : QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel );
848 0 : if (choice == QMessageBox::Cancel) {
849 : return;
850 : }
851 : }
852 0 : ui->TabWidget->removeTab ( index );
853 0 : delete tab;
854 : }
855 :
856 0 : void dbse::SchemaMainWindow::CustomContextMenuFileView ( QPoint Pos )
857 : {
858 0 : if ( ContextMenuFileView == nullptr )
859 : {
860 0 : ContextMenuFileView = new QMenu ( this );
861 :
862 0 : QAction * Act = new QAction ( tr ( "Set as Active Schema" ), this );
863 0 : connect ( Act, SIGNAL ( triggered() ), this, SLOT ( SetSchemaFileActive() ) );
864 0 : QAction * Sav = new QAction ( tr ( "Save Schema File" ), this );
865 0 : connect ( Sav, SIGNAL ( triggered() ), this, SLOT ( SaveSchemaFile() ) );
866 0 : QAction * info = new QAction ( tr ( "Show file info" ), this );
867 0 : connect ( info, SIGNAL ( triggered() ), this, SLOT ( show_file_info() ) );
868 :
869 0 : ContextMenuFileView->addAction ( info );
870 0 : ContextMenuFileView->addAction ( Act );
871 0 : ContextMenuFileView->addAction ( Sav );
872 : }
873 :
874 0 : QModelIndex index = ui->FileView->currentIndex();
875 :
876 0 : if ( index.isValid() )
877 : {
878 0 : QStringList row = FileModel->getRowFromIndex ( index );
879 0 : if (row.at(1) == "RW") {
880 0 : ContextMenuFileView->actions().at(2)->setVisible(true);
881 0 : if (!row.at(2).contains("Active")) {
882 0 : ContextMenuFileView->actions().at(1)->setVisible(true);
883 : }
884 : else {
885 0 : ContextMenuFileView->actions().at(1)->setVisible(false);
886 : }
887 : }
888 : else {
889 0 : ContextMenuFileView->actions().at(2)->setVisible(false);
890 0 : ContextMenuFileView->actions().at(1)->setVisible(false);
891 : }
892 0 : ContextMenuFileView->exec ( ui->FileView->mapToGlobal ( Pos ) );
893 0 : }
894 0 : }
895 :
896 0 : void dbse::SchemaMainWindow::CustomContextMenuTableView ( QPoint Pos )
897 : {
898 0 : if ( ContextMenuTableView == nullptr )
899 : {
900 0 : ContextMenuTableView = new QMenu ( this );
901 :
902 0 : QAction * add = new QAction ( tr ( "&Add New Class" ), this );
903 0 : connect ( add, SIGNAL ( triggered() ), this, SLOT ( AddNewClass() ) );
904 :
905 0 : QAction * remove = new QAction ( tr ( "&Remove Selected Class" ), this );
906 0 : connect ( remove, SIGNAL ( triggered() ), this, SLOT ( RemoveClass() ) );
907 :
908 0 : QAction * edit = new QAction ( tr ( "&Edit Selected Class" ), this );
909 0 : connect ( edit, SIGNAL ( triggered() ), this, SLOT ( editClass() ) );
910 :
911 0 : ContextMenuTableView->addAction ( add );
912 0 : ContextMenuTableView->addAction ( edit );
913 0 : ContextMenuTableView->addAction ( remove );
914 : }
915 :
916 0 : QModelIndex Index = ui->ClassTableView->currentIndex();
917 :
918 0 : if ( Index.isValid() )
919 : {
920 0 : ContextMenuTableView->exec ( ui->ClassTableView->mapToGlobal ( Pos ) );
921 : }
922 0 : }
923 :
924 0 : void dbse::SchemaMainWindow::toggle_case_sensitive ( int /*state*/ )
925 : {
926 0 : if ( ui->case_sensitive->isChecked() ) {
927 0 : m_proxyModel->setFilterCaseSensitivity ( Qt::CaseSensitive );
928 : }
929 : else {
930 0 : m_proxyModel->setFilterCaseSensitivity ( Qt::CaseInsensitive );
931 : }
932 0 : }
933 0 : void dbse::SchemaMainWindow::update_view() {
934 0 : auto tab = dynamic_cast<SchemaTab *> ( ui->TabWidget->currentWidget() );
935 0 : tab->GetScene()->update();
936 :
937 0 : BuildTableModel();
938 0 : BuildFileModel();
939 0 : }
940 :
941 0 : void dbse::SchemaMainWindow::edit_settings() {
942 0 : if (m_settings == nullptr) {
943 0 : m_settings = new SchemaSettings(this);
944 0 : connect(m_settings, SIGNAL(settings_updated()), this, SLOT(update_view()));
945 : }
946 0 : m_settings->show();
947 0 : }
|