diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 3ac04213..472a34f4 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -36,6 +36,8 @@ #include #include #include +#include +#include MainWindow::MainWindow(QWidget* parent) @@ -179,8 +181,8 @@ bool MainWindow::fileOpen(const QString& fileName) setCurrentFile(wFile); retval = true; } else { - QString err = tr("An error occurred: %1").arg(db.lastErrorMessage); - QMessageBox::warning(this, QApplication::applicationName(), err); + // Failed opening file; so it might be a SQLiteBrowser project file + return loadProject(wFile); } loadExtensionsFromSettings(); populateStructure(); @@ -1043,6 +1045,7 @@ void MainWindow::activateFields(bool enable) ui->actionSqlOpenFile->setEnabled(enable); ui->actionSqlOpenTab->setEnabled(enable); ui->actionSqlSaveFile->setEnabled(enable); + ui->actionSaveProject->setEnabled(enable); } void MainWindow::browseTableHeaderClicked(int logicalindex) @@ -1684,3 +1687,221 @@ void MainWindow::updateBrowseDataColumnWidth(int section, int /*old_size*/, int { browseTableColumnWidths[ui->comboBrowseTable->currentText()][section] = new_size; } + +bool MainWindow::loadProject(QString filename) +{ + // Show the open file dialog when no filename was passed as parameter + if(filename.isEmpty()) + { + filename = QFileDialog::getOpenFileName(this, + tr("Choose a file to open"), + QString(), + tr("SQLiteBrowser project(*.sqbpro)")); + } + + if(!filename.isEmpty()) + { + QFile file(filename); + file.open(QFile::ReadOnly | QFile::Text); + + QXmlStreamReader xml(&file); + xml.readNext(); // token == QXmlStreamReader::StartDocument + xml.readNext(); // name == sqlb_project + if(xml.name() != "sqlb_project") + { + QMessageBox::warning(this, qApp->applicationName(), tr("Invalid file format.")); + return false; + } + + while(!xml.atEnd() && !xml.hasError()) + { + // Read next token + QXmlStreamReader::TokenType token = xml.readNext(); + + // Handle element start + if(token == QXmlStreamReader::StartElement) + { + if(xml.name() == "db") + { + // DB file + fileOpen(xml.attributes().value("path").toString()); + ui->dbTreeWidget->collapseAll(); + } else if(xml.name() == "window") { + // Window settings + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "window") + { + // Currently selected tab + if(xml.name() == "current_tab") + ui->mainTab->setCurrentIndex(xml.attributes().value("id").toString().toInt()); + } + } else if(xml.name() == "tab_structure") { + // Database Structure tab settings + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "tab_structure") + { + if(xml.name() == "column_width") + { + // Tree view column widths + ui->dbTreeWidget->setColumnWidth(xml.attributes().value("id").toString().toInt(), + xml.attributes().value("width").toString().toInt()); + xml.skipCurrentElement(); + } else if(xml.name() == "expanded_item") { + // Tree view expanded items + int parent = xml.attributes().value("parent").toString().toInt(); + QModelIndex idx; + if(parent == -1) + idx = ui->dbTreeWidget->model()->index(xml.attributes().value("id").toString().toInt(), 0); + else + idx = ui->dbTreeWidget->model()->index(xml.attributes().value("id").toString().toInt(), 0, ui->dbTreeWidget->model()->index(parent, 0)); + ui->dbTreeWidget->expand(idx); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "tab_browse") { + // Browse Data tab settings + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "tab_browse") + { + if(xml.name() == "current_table") + { + // Currently selected table + ui->comboBrowseTable->setCurrentIndex(ui->comboBrowseTable->findText(xml.attributes().value("name").toString())); + xml.skipCurrentElement(); + } else if(xml.name() == "column_widths") { + // Column widths + QByteArray temp = QByteArray::fromBase64(xml.attributes().value("data").toUtf8()); + QDataStream stream(temp); + stream >> browseTableColumnWidths; + populateTable(ui->comboBrowseTable->currentText()); // Refresh view + xml.skipCurrentElement(); + } else if(xml.name() == "sort") { + // Sort order + ui->dataTable->sortByColumn(xml.attributes().value("column").toString().toInt(), + static_cast(xml.attributes().value("order").toString().toInt())); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "tab_sql") { + // Close existing tab + QWidget* w = ui->tabSqlAreas->widget(0); + ui->tabSqlAreas->removeTab(0); + delete w; + + // Execute SQL tab data + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "tab_sql") + { + if(xml.name() == "sql") + { + // SQL editor tab + unsigned int index = openSqlTab(); + ui->tabSqlAreas->setTabText(index, xml.attributes().value("name").toString()); + qobject_cast(ui->tabSqlAreas->widget(index))->getEditor()->setPlainText(xml.readElementText()); + } else if(xml.name() == "current_tab") { + // Currently selected tab + ui->tabSqlAreas->setCurrentIndex(xml.attributes().value("id").toString().toInt()); + xml.skipCurrentElement(); + } + } + } + } + } + + file.close(); + return !xml.hasError(); + } else { + // No project was opened + return false; + } +} + +static void saveDbTreeState(const QTreeView* tree, QXmlStreamWriter& xml, QModelIndex index = QModelIndex(), int parent_row = -1) +{ + for(int i=0;imodel()->rowCount(index);i++) + { + if(tree->isExpanded(tree->model()->index(i, 0, index))) + { + xml.writeStartElement("expanded_item"); + xml.writeAttribute("id", QString::number(i)); + xml.writeAttribute("parent", QString::number(parent_row)); + xml.writeEndElement(); + } + + saveDbTreeState(tree, xml, tree->model()->index(i, 0, index), i); + } +} + +void MainWindow::saveProject() +{ + QString filename = QFileDialog::getSaveFileName(this, + tr("Choose a filename to save under"), + QString(), + tr("SQLiteBrowser project(*.sqbpro)") + ); + if(!filename.isEmpty()) + { + QFile file(filename); + file.open(QFile::WriteOnly | QFile::Text); + QXmlStreamWriter xml(&file); + xml.writeStartDocument(); + xml.writeStartElement("sqlb_project"); + + // Database file name + xml.writeStartElement("db"); + xml.writeAttribute("path", db.curDBFilename); + xml.writeEndElement(); + + // Window settings + xml.writeStartElement("window"); + xml.writeStartElement("current_tab"); // Currently selected tab + xml.writeAttribute("id", QString::number(ui->mainTab->currentIndex())); + xml.writeEndElement(); + xml.writeEndElement(); + + // Database Structure tab settings + xml.writeStartElement("tab_structure"); + for(int i=0;idbTreeWidget->model()->columnCount();i++) // Widths of tree view columns + { + xml.writeStartElement("column_width"); + xml.writeAttribute("id", QString::number(i)); + xml.writeAttribute("width", QString::number(ui->dbTreeWidget->columnWidth(i))); + xml.writeEndElement(); + } + saveDbTreeState(ui->dbTreeWidget, xml); // Expanded tree items + xml.writeEndElement(); + + // Browse Data tab settings + xml.writeStartElement("tab_browse"); + xml.writeStartElement("current_table"); // Currently selected table + xml.writeAttribute("name", ui->comboBrowseTable->currentText()); + xml.writeEndElement(); + { // Column widths + QByteArray temp; + QDataStream stream(&temp, QIODevice::WriteOnly); + stream << browseTableColumnWidths; + xml.writeStartElement("column_widths"); + xml.writeAttribute("data", temp.toBase64()); + xml.writeEndElement(); + } + xml.writeStartElement("sort"); // Sort order + xml.writeAttribute("column", QString::number(curBrowseOrderByIndex)); + xml.writeAttribute("order", QString::number(curBrowseOrderByMode)); + xml.writeEndElement(); + xml.writeEndElement(); + + // Execute SQL tab data + xml.writeStartElement("tab_sql"); + for(int i=0;itabSqlAreas->count();i++) // All SQL tabs content + { + xml.writeStartElement("sql"); + xml.writeAttribute("name", ui->tabSqlAreas->tabText(i)); + xml.writeCharacters(qobject_cast(ui->tabSqlAreas->widget(i))->getSql()); + xml.writeEndElement(); + } + xml.writeStartElement("current_tab"); // Currently selected tab + xml.writeAttribute("id", QString::number(ui->tabSqlAreas->currentIndex())); + xml.writeEndElement(); + xml.writeEndElement(); + + xml.writeEndElement(); + xml.writeEndDocument(); + file.close(); + } +} diff --git a/src/MainWindow.h b/src/MainWindow.h index 6ab967c6..8eed5c2d 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -174,6 +174,8 @@ private slots: void on_actionBug_report_triggered(); void on_actionWebsite_triggered(); void updateBrowseDataColumnWidth(int section, int /*old_size*/, int new_size); + bool loadProject(QString filename = QString()); + void saveProject(); }; #endif diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 5ad492eb..ba9d49f1 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -797,6 +797,9 @@ + + + @@ -1441,6 +1444,36 @@ Web&site... + + + + :/icons/project_save:/icons/project_save + + + Save Project + + + Save the current session to a file + + + Save the current session to a file + + + + + + :/icons/project_open:/icons/project_open + + + Open Project + + + Load a working session from a file + + + Load a working session from a file + + @@ -2179,6 +2212,38 @@ + + actionOpenProject + triggered() + MainWindow + loadProject() + + + -1 + -1 + + + 399 + 299 + + + + + actionSaveProject + triggered() + MainWindow + saveProject() + + + -1 + -1 + + + 399 + 299 + + + fileOpen() @@ -2225,5 +2290,7 @@ openSqlFile() saveSqlFile() loadExtension() + loadProject() + saveProject() diff --git a/src/icons/icons.qrc b/src/icons/icons.qrc index c4f374c5..9e9a83ae 100644 --- a/src/icons/icons.qrc +++ b/src/icons/icons.qrc @@ -37,5 +37,7 @@ bullet_arrow_up.png sqlitebrowser.png internet-web-browser.png + package.png + package_go.png diff --git a/src/icons/package.png b/src/icons/package.png new file mode 100644 index 00000000..da3c2a2d Binary files /dev/null and b/src/icons/package.png differ diff --git a/src/icons/package_go.png b/src/icons/package_go.png new file mode 100644 index 00000000..aace63ad Binary files /dev/null and b/src/icons/package_go.png differ