15#include "ui_SchemaMainWindow.h"
21#include <QGraphicsScene>
22#include "QInputDialog"
25#include <QPrintDialog>
26#include <QSvgGenerator>
36 : QMainWindow ( parent ),
50 setFocusPolicy( Qt::StrongFocus );
62 ui->ClassTableView->horizontalHeader()->setSectionResizeMode ( QHeaderView::Stretch );
63 ui->ClassTableView->setDragEnabled (
true );
64 ui->ClassTableView->setContextMenuPolicy ( Qt::ContextMenuPolicy::CustomContextMenu );
65 ui->FileView->horizontalHeader()->setSectionResizeMode ( QHeaderView::Stretch );
66 ui->FileView->setContextMenuPolicy ( Qt::ContextMenuPolicy::CustomContextMenu );
67 ui->FileView->setSelectionBehavior ( QAbstractItemView::SelectRows );
68 ui->TabWidget->setTabsClosable (
true );
69 ui->ClassTableSearchLine->setProperty (
"placeholderText",
70 QVariant ( QString (
"Search for classes regex" ) ) );
71 ui->ClassTableSearchLine->setClearButtonEnabled(
true);
72 m_proxyModel->setFilterCaseSensitivity (Qt::CaseInsensitive);
78 ui->TabWidget->removeTab ( 0 );
83 QPushButton * RightButton =
new QPushButton (
"+" );
84 ui->TabWidget->setCornerWidget ( RightButton, Qt::TopLeftCorner );
85 connect ( RightButton, SIGNAL ( clicked() ),
this, SLOT (
add_tab() ) );
90 connect (
ui->OpenFileSchema, SIGNAL ( triggered() ),
this, SLOT (
OpenSchemaFile() ) );
91 connect (
ui->CreateNewSchema, SIGNAL ( triggered() ),
this, SLOT (
CreateNewSchema() ) );
93 connect (
ui->SaveSchema, SIGNAL ( triggered() ),
this, SLOT (
SaveSchema() ) );
94 connect (
ui->SetRelationship, SIGNAL ( triggered (
bool ) ),
this,
96 connect (
ui->SetInheritance, SIGNAL ( triggered (
bool ) ),
this,
98 connect (
ui->AddClass, SIGNAL ( triggered() ),
this, SLOT (
AddNewClass() ) );
99 connect (
ui->SaveView, SIGNAL ( triggered() ),
this, SLOT (
SaveView() ) );
100 connect (
ui->SaveViewAs, SIGNAL ( triggered() ),
this, SLOT (
SaveViewAs() ) );
101 connect (
ui->LoadView, SIGNAL ( triggered() ),
this, SLOT (
LoadView() ) );
102 connect (
ui->NameView, SIGNAL ( triggered() ),
this, SLOT (
NameView() ) );
103 connect (
ui->Exit, SIGNAL ( triggered() ),
this, SLOT ( close() ) );
105 connect (
ui->actionSettings, SIGNAL (triggered() ),
this, SLOT (
edit_settings() ));
107 connect (
ui->ClassTableView, SIGNAL ( activated ( QModelIndex ) ),
this,
109 connect (
ui->close_tab, SIGNAL ( triggered() ),
this, SLOT (
close_tab() ) );
119 connect (
ui->TabWidget, SIGNAL ( tabCloseRequested (
int ) ),
this,
122 connect (
ui->FileView, SIGNAL ( customContextMenuRequested ( QPoint ) ),
this,
124 connect (
ui->FileView, SIGNAL ( activated(QModelIndex) ),
this, SLOT (
show_file_info(QModelIndex) ) );
127 connect (
ui->ClassTableView, SIGNAL ( customContextMenuRequested ( QPoint ) ),
this,
131 connect (
ui->ClassTableSearchLine, SIGNAL( textChanged ( QString ) ),
m_proxyModel, SLOT( setFilterRegExp( QString ) ) );
132 connect (
ui->case_sensitive, SIGNAL ( stateChanged(
int) ),
this,
144 QModelIndex index =
ui->FileView->currentIndex();
149 QStringList row =
FileModel->getRowFromIndex ( index );
153 bool widget_found =
false;
154 for ( QWidget * widget : QApplication::allWidgets() ) {
156 if ( sfi !=
nullptr ) {
157 if ( (sfi->objectName() ).compare ( fn ) == 0 ) {
159 sfi->setVisible (
true );
160 sfi->activateWindow();
166 if ( !widget_found ) {
176 std::cout << __FUNCTION__ <<
" New SchemaFileInfo\n";
182 QStringList Headers {
"File Name",
"Access",
"Status" };
191 ui->FileView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
192 ui->FileView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
193 ui->FileView->horizontalHeader()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
213 QString modified_views;
214 for (
int index=0; index<
ui->TabWidget->count(); ++index) {
215 auto tab =
dynamic_cast<SchemaTab *
> (
ui->TabWidget->widget(index));
216 if (tab->GetScene()->IsModified()) {
217 auto label =
ui->TabWidget->tabText(index);
218 label = label.remove(
'*');
219 modified_views.append(
" " + label +
"\n");
222 if (!modified_views.isEmpty()) {
223 QString message (
"There are unsaved changes in the schema views:\n");
224 message.append (modified_views);
225 message.append (
"Do you want to save the changes in the schema views?\n" );
226 return QMessageBox::question (
227 0, tr (
"SchemaEditor" ),
229 QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Discard );
232 return QMessageBox::Discard;
239 if (modified.empty())
241 return QMessageBox::Discard;
244 std::string msg =
"There are unsaved changes in the following files:\n\n"
245 + modified +
"Do you want to save the changes in the schema?\n";
246 return QMessageBox::question (
247 0, tr (
"SchemaEditor" ),
248 QString ( msg.c_str() ),
249 QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Save );
260 QModelIndex Index =
ui->ClassTableView->currentIndex();
261 QModelIndex proxyIndex =
m_proxyModel->mapToSource( Index );
262 QStringList Row =
TableModel->getRowFromIndex ( proxyIndex );
268 QMessageBox::warning ( 0,
"Schema editor",
269 QString (
"Cannot delete class because it has sub-classes." ) );
274 QMessageBox::warning ( 0,
"Schema editor",
275 QString (
"Cannot delete class because some classes references it." ) );
280 QString Name = QString::fromStdString ( SchemaClass->
get_name() );
289 QModelIndex Index =
ui->ClassTableView->currentIndex();
290 QModelIndex proxyIndex =
m_proxyModel->mapToSource( Index );
291 QStringList Row =
TableModel->getRowFromIndex ( proxyIndex );
293 if ( !Row.isEmpty() ) {
294 bool widget_found =
false;
295 QString class_name = Row.at ( 0 );
297 class_name.toStdString() );
299 for ( QWidget * widget : QApplication::allWidgets() ) {
301 if ( editor !=
nullptr ) {
302 if ( ( editor->objectName() ).compare ( class_name ) == 0 ) {
304 editor->setVisible (
true );
305 editor->activateWindow();
310 if ( !widget_found ) {
319 QModelIndex index =
ui->FileView->currentIndex();
320 QString file =
FileModel->getRowFromIndex ( index ).at(0);
325 QMessageBox::warning(0,
327 QString(
"Could not make schema active!\n\n").append(QString(exc.
what())),
343 std::string
filename = qfilename.toStdString();
344 std::set<std::string> includes;
347 QString advice{
"<br><br>Use the File info window to fix the problem."};
349 auto relationships = cls->direct_relationships();
350 if (relationships !=
nullptr) {
351 for (
auto rel: *relationships) {
352 auto rel_class = rel->get_class_type();
353 if (rel_class ==
nullptr) {
354 QString warning =
"<b>Warning</b> class <i>"
355 + QString::fromStdString(cls->get_name())
356 +
"</i> has relationship "
357 + QString::fromStdString(rel->get_name())
358 +
" referring to class <i>"
359 + QString::fromStdString(rel->get_type())
360 +
"</i> which is not loaded<br>";
361 QMessageBox::warning(0,
368 auto file = rel_class->get_file()->get_full_file_name();
369 if (file !=
filename && !includes.contains(file)) {
370 QString warning =
"<b>Warning</b> class <i>"
371 + QString::fromStdString(cls->get_name())
372 +
"</i> has relationship "
373 + QString::fromStdString(rel->get_name())
374 +
" referring to class <i>"
375 + QString::fromStdString(rel->get_class_type()->get_name())
376 +
"</i> from " + QString::fromStdString(file)
377 +
" which is not included by " + qfilename;
378 QMessageBox::warning(0,
388 auto super_classes = cls->direct_super_classes();
389 if (super_classes !=
nullptr) {
390 for (
auto sc: *super_classes) {
392 if (sclass ==
nullptr) {
393 QString warning =
"<b>Warning</b> class <i>"
394 + QString::fromStdString(cls->get_name())
395 +
"</i> refers to super class <i>" + QString::fromStdString(*sc)
396 +
"</i> which is not known<br>";
397 QMessageBox::warning(0,
404 auto file = sclass->get_file()->get_full_file_name();
405 if (file !=
filename && !includes.contains(file)) {
406 QString warning =
"<b>Warning</b> class <i>"
407 + QString::fromStdString(cls->get_name())
408 +
"</i> refers to super class <i>" + QString::fromStdString(*sc)
409 +
"</i> from " + QString::fromStdString(file)
410 +
" which is not included by" + qfilename;
411 QMessageBox::warning(0,
432 message = QString (
"File %1 saved" ).arg (
filename);
436 message = QString (
"Failed to save file %1" ).arg (
filename);
439 ui->StatusBar->showMessage( message );
445 QModelIndex index =
ui->FileView->currentIndex();
446 const auto file =
FileModel->getRowFromIndex (index).at (0);
457 if ( QPrintDialog ( &printer ).exec() == QDialog::Accepted )
459 QPainter painter ( &printer );
460 painter.setRenderHint ( QPainter::Antialiasing );
463 QGraphicsView * View = CurrentTab->
GetView();
464 Scene->render ( &painter, QRectF(), View->viewport()->rect() );
468 auto tab =
dynamic_cast<SchemaTab *
> (
ui->TabWidget->currentWidget() );
470 auto file = QFileDialog::getSaveFileName(
471 this, tr(
"Export to SVG"),
473 tr(
"SVG files (*.svg);;All files (*)"));
474 if (file.isEmpty()) {
478 auto spos = file.lastIndexOf(
'/');
484 auto scene = tab->GetScene();
485 auto view = tab->GetView();
487 QSvgGenerator generator;
488 generator.setFileName(file);
489 auto vpr=view->viewport()->rect();
490 generator.setSize(QSize(vpr.width(),vpr.height()));
491 generator.setViewBox(vpr);
494 painter.begin(&generator);
495 scene->render ( &painter, QRectF(), view->viewport()->rect() );
503 if ( UserChoice == QMessageBox::Save )
510 else if ( UserChoice == QMessageBox::Cancel )
517 if ( UserChoice == QMessageBox::Cancel )
525 for ( QWidget * Widget : QApplication::allWidgets() )
540 if(!SchemaFile.isEmpty()) {
545 std::vector<std::string> fnames;
547 std::string dir = fnames[0].substr(0,fnames[0].find_last_of(
'/'));
556 QMessageBox::warning(0,
558 QString(
"Could not load schema!\n\n").append(QString(Ex.
what())),
567 QMessageBox::warning(0,
569 QString(
"Could not make schema active!\n\n").append(QString(exc.
what())),
580 if (file !=
nullptr) {
587 m_title.remove(QRegularExpression(
": --.*"));
588 m_title.append(QString(
": -- ") + text);
594 QFileDialog FileDialog (
this, tr (
"Open File" ),
".",
595 tr (
"XML schema files (*.schema.xml);;All files (*)" ) );
596 FileDialog.setAcceptMode ( QFileDialog::AcceptOpen );
597 FileDialog.setFileMode ( QFileDialog::AnyFile );
598 FileDialog.setViewMode ( QFileDialog::Detail );
600 QStringList FilesSelected;
603 if ( FileDialog.exec() )
605 FilesSelected = FileDialog.selectedFiles();
608 if ( FilesSelected.size() )
611 SchemaPath = FilesSelected.value ( 0 );
632 if (modified.empty())
634 QMessageBox::information ( 0,
"Schema editor",
635 QString (
"No modified schema files need saving" ) );
646 QString FileName = QFileDialog::getSaveFileName (
647 this, tr (
"New schema File" ),
".",
648 tr (
"XML schema files (*.schema.xml);;All files (*)" ) );
650 if ( FileName.isEmpty() )
652 QMessageBox::warning ( 0,
"Schema editor",
653 QString (
"Please provide a name for the schema !" ) );
657 if ( !FileName.endsWith (
".schema.xml" ) )
659 FileName.append (
".schema.xml" );
662 QFile FileInfo ( FileName );
663 std::string FileNameStd = FileInfo.fileName().toStdString();
671 ui->CreateNewSchema->setDisabled (
true );
672 ui->OpenFileSchema->setDisabled (
true );
676 QMessageBox::warning (
679 QString (
"Could not create file : %1.\n\n%2" ).arg ( QString::fromStdString (
680 FileNameStd ) ).arg (
681 QString ( Ex.
what() ) ) );
687 if (
ui->SetInheritance->isChecked() )
689 ui->SetInheritance->setChecked (
false );
694 ui->TabWidget->setCursor ( Qt::CrossCursor );
698 ui->TabWidget->setCursor ( Qt::ArrowCursor );
706 if (
ui->SetRelationship->isChecked() )
708 ui->SetRelationship->setChecked (
false );
713 ui->TabWidget->setCursor ( Qt::CrossCursor );
717 ui->TabWidget->setCursor ( Qt::ArrowCursor );
725 auto index =
ui->TabWidget->addTab (
new SchemaTab(),
"unnamed Schema View" );
726 ui->TabWidget->setCurrentIndex ( index );
727 auto tab =
dynamic_cast<SchemaTab *
> (
ui->TabWidget->currentWidget() );
733 auto index =
ui->TabWidget->currentIndex();
734 auto label =
ui->TabWidget->tabText(index);
735 if (modified && !label.endsWith(
"*")) {
738 if (!modified && label.endsWith(
"*")) {
739 label = label.remove(
'*');
741 ui->TabWidget->setTabText(index, label);
745 auto index =
ui->TabWidget->currentIndex();
747 QString text = QInputDialog::getText(
nullptr,
748 "Schema editor: rename class view",
753 if(ok && !text.isEmpty()) {
754 ui->TabWidget->setTabText(index, text);
759 auto newtext =
ui->TabWidget->tabText(index);
764 if ( tab->
GetScene()->items().size() != 0 )
767 if (file_name ==
"./") {
776 if ( CurrentTab->
GetScene()->items().size() != 0 )
779 if (defName ==
"./") {
782 QString FileName = QFileDialog::getSaveFileName (
783 this, tr (
"Save View" ), defName,
784 tr(
"View files (*.view);;All files (*)") );
786 if (! FileName.isEmpty()) {
787 auto spos = FileName.lastIndexOf(
'/');
793 if ( !FileName.endsWith (
".view" ) ) {
794 FileName.append (
".view" );
798 auto text = QFileInfo(FileName).baseName();
800 auto index =
ui->TabWidget->currentIndex();
801 ui->TabWidget->setTabText(index, text);
810 QFile file ( file_name );
811 file.open ( QIODevice::WriteOnly );
813 for ( QGraphicsItem * item : tab->
GetScene()->items() ) {
815 if (
object !=
nullptr ) {
816 QString description =
object->GetClassName() +
","
817 + QString::number ( object->scenePos().x() ) +
","
818 + QString::number ( object->scenePos().y() ) +
"\n";
819 file.write ( description.toUtf8() );
823 if ( note !=
nullptr && !note->text().isEmpty()) {
824 auto text = note->text().replace(
"\n",
"<br>");
825 text = text.replace(
",",
"<comma>");
827 + QString::number ( note->scenePos().x() ) +
","
828 + QString::number ( note->scenePos().y() ) +
","
830 file.write ( line.toUtf8() );
836 auto message = QString(
"Saved view to %1").arg(file_name);
837 ui->StatusBar->showMessage( message );
842 QString ViewPath = QFileDialog::getOpenFileName (
844 tr (
"Open view file"),
846 tr(
"View files (*.view);;All files (*)"));
848 if ( !ViewPath.isEmpty() )
850 auto spos = ViewPath.lastIndexOf(
'/');
855 QFile ViewFile ( ViewPath );
856 ViewFile.open ( QIODevice::ReadOnly );
858 auto text = QFileInfo(ViewPath).baseName();
859 auto tab =
dynamic_cast<SchemaTab *
> (
ui->TabWidget->currentWidget() );
860 if (!tab->getName().isEmpty() || tab->GetScene()->IsModified()) {
862 tab =
dynamic_cast<SchemaTab *
> (
ui->TabWidget->currentWidget() );
864 auto index =
ui->TabWidget->currentIndex();
865 ui->TabWidget->setTabText(index, text);
867 tab->setFileName(ViewPath);
869 QStringList ClassesNames;
870 QList<QPointF> Positions;
871 QList<QPointF> note_positions;
873 while ( !ViewFile.atEnd() )
875 QString Line ( ViewFile.readLine() );
876 if (!Line.isEmpty()) {
877 QStringList ObjectDescription = Line.split (
"," );
879 Position.setX ( ObjectDescription.at ( 1 ).toInt() );
880 Position.setY ( ObjectDescription.at ( 2 ).toInt() );
881 if (ObjectDescription.at ( 0 ) ==
"#") {
882 note_positions.append (Position);
883 auto note_text = ObjectDescription.at(3);
884 if (note_text.back() ==
'\n') {
887 note_text = note_text.replace(
"<br>",
"\n");
888 note_text = note_text.replace(
"<comma>",
",");
889 notes.append ( note_text );
892 ClassesNames.append ( ObjectDescription.at ( 0 ) );
893 Positions.append ( Position );
899 auto message = QString(
"Loaded view from %1").arg(ViewPath);
900 ui->StatusBar->showMessage( message );
902 auto scene = tab->GetScene();
903 scene->CleanItemMap();
904 auto missing = scene->AddItemsToScene ( ClassesNames, Positions );
905 if (!missing.empty()) {
906 QString warning_text{
"The following classes in "};
907 warning_text.append(QFileInfo(ViewPath).fileName());
908 warning_text.append(
" are not present in the loaded schema:\n ");
909 warning_text.append(missing.join(
",\n "));
910 QMessageBox::warning(
this, tr(
"Load View"), warning_text);
912 scene->ClearModified();
914 scene->add_notes(notes, note_positions);
920 QModelIndex proxyIndex =
m_proxyModel->mapToSource( Index );
921 QStringList Row =
TableModel->getRowFromIndex ( proxyIndex );
923 if ( !Row.isEmpty() ) {
934 if ( index == -1 || ( (
ui->TabWidget->count() == 1 ) && index == 0 ) ) {
938 auto tab =
dynamic_cast<SchemaTab *
> (
ui->TabWidget->widget(index));
939 if (tab->GetScene()->IsModified()) {
940 auto choice = QMessageBox::question (
941 0, tr (
"SchemaEditor" ),
942 QString (
"There are unsaved changes in the schema view:\n"
943 "Do you really want to delete this schema view?\n" ),
944 QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel );
945 if (choice == QMessageBox::Cancel) {
949 ui->TabWidget->removeTab ( index );
959 QAction * Act =
new QAction ( tr (
"Set as Active Schema" ),
this );
961 QAction * Sav =
new QAction ( tr (
"Save Schema File" ),
this );
962 connect ( Sav, SIGNAL ( triggered() ),
this, SLOT (
SaveSchemaFile() ) );
963 QAction * info =
new QAction ( tr (
"Show file info" ),
this );
964 connect ( info, SIGNAL ( triggered() ),
this, SLOT (
show_file_info() ) );
971 QModelIndex index =
ui->FileView->currentIndex();
973 if ( index.isValid() )
975 QStringList row =
FileModel->getRowFromIndex ( index );
976 if (row.at(1) ==
"RW") {
978 if (!row.at(2).contains(
"Active")) {
999 QAction * add =
new QAction ( tr (
"&Add New Class" ),
this );
1000 connect ( add, SIGNAL ( triggered() ),
this, SLOT (
AddNewClass() ) );
1002 QAction * remove =
new QAction ( tr (
"&Remove Selected Class" ),
this );
1003 connect ( remove, SIGNAL ( triggered() ),
this, SLOT (
RemoveClass() ) );
1005 QAction * edit =
new QAction ( tr (
"&Edit Selected Class" ),
this );
1006 connect ( edit, SIGNAL ( triggered() ),
this, SLOT (
editClass() ) );
1013 QModelIndex Index =
ui->ClassTableView->currentIndex();
1015 if ( Index.isValid() )
1023 if (
ui->case_sensitive->isChecked() ) {
1024 m_proxyModel->setFilterCaseSensitivity ( Qt::CaseSensitive );
1027 m_proxyModel->setFilterCaseSensitivity ( Qt::CaseInsensitive );
1031 auto tab =
dynamic_cast<SchemaTab *
> (
ui->TabWidget->currentWidget() );
static KernelWrapper & GetInstance()
dunedaq::oks::OksFile * LoadSchema(const std::string &SchemaName) const
void SetActiveSchema(const std::string &ActiveSchema)
dunedaq::oks::OksClass * FindClass(std::string ClassName) const
void SaveSchema(const std::string &file) const
void CloseAllSchema() const
std::string ModifiedSchemaFiles() const
void SetInheritanceMode(bool Mode)
Editor Functions.
void CreateNewSchema(const std::string &SchemaName) const
void PushRemoveClassCommand(dunedaq::oks::OksClass *Class, std::string ClassName, std::string ClassDescription, bool Abstract)
void get_all_includes(const std::string &FileName, std::set< std::string > &IncludedFiles)
void GetSchemaFiles(std::vector< std::string > &SchemaFiles)
static void launch(QString class_name)
static QString createNewClass()
void new_window(SchemaFileInfo *win)
SchemaMainWindow(QString SchemaFile, QWidget *parent=nullptr)
SchemaSettings * m_settings
bool SaveModifiedSchema()
QMenu * ContextMenuFileView
void show_file_info_active_schema()
void connect_file_info(SchemaFileInfo *win)
void LaunchClassEditor(QModelIndex Index)
void OpenSchemaFile(QString SchemaFile)
void toggle_case_sensitive(int)
void CustomContextMenuTableView(QPoint Pos)
void ChangeCursorInheritance(bool State)
void write_view_file(const QString &fn, SchemaTab *tab)
QMenu * ContextMenuTableView
void modifiedView(bool modified)
void CustomContextMenuFileView(QPoint Pos)
int ShouldSaveChanges() const
void SetSchemaFileActive()
bool save_schema_file(QString file)
void update_window_title(QString text)
CustomFileModel * FileModel
int ShouldSaveViewChanges() const
QSortFilterProxyModel * m_proxyModel
void ChangeCursorRelationship(bool State)
CustomTableModel * TableModel
std::unique_ptr< dbse::Ui::SchemaMainWindow > ui
void closeEvent(QCloseEvent *event)
void show_file_info(QModelIndex)
void export_current_view()
bool check_schema_file(QString file)
void setFileName(const QString &)
SchemaGraphicsScene * GetScene() const
void setName(const QString &)
QGraphicsView * GetView() const
Failed to set active file.
bool get_is_abstract() const noexcept
const FList * all_sub_classes() const noexcept
const std::string & get_name() const noexcept
const std::string & get_description() const noexcept
Provides interface to the OKS XML schema and data files.
virtual const char * what() const noexcept