Skip to content

Commit

Permalink
Add support for basic project files
Browse files Browse the repository at this point in the history
This add support for saving and loading of SQLiteBrowser project files.
As of now these files contain a reference to the used database file,
store some window and widget settings as well as the content of the SQL
tabs.

Note that while working this is a first draft only. Especially the
parsing code still might contain a bug or two and there is a lot more
information to be added to these files later (like filters, plot
settings, etc.).

Also note that the main intention behind these project files was to make
the life of users easier while not getting into the way of those who don't
need them. The program still remains a database browser and doesn't
become a visual database studio thing.
  • Loading branch information
MKleusberg committed Jun 6, 2014
1 parent 6e5c98b commit 62622ae
Show file tree
Hide file tree
Showing 6 changed files with 294 additions and 2 deletions.
225 changes: 223 additions & 2 deletions src/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#include <QMimeData>
#include <QColorDialog>
#include <QDesktopServices>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>


MainWindow::MainWindow(QWidget* parent)
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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<Qt::SortOrder>(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<SqlExecutionArea*>(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;i<tree->model()->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;i<ui->dbTreeWidget->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;i<ui->tabSqlAreas->count();i++) // All SQL tabs content
{
xml.writeStartElement("sql");
xml.writeAttribute("name", ui->tabSqlAreas->tabText(i));
xml.writeCharacters(qobject_cast<SqlExecutionArea*>(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();
}
}
2 changes: 2 additions & 0 deletions src/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
67 changes: 67 additions & 0 deletions src/MainWindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,9 @@
<addaction name="menuImport"/>
<addaction name="menuExport"/>
<addaction name="separator"/>
<addaction name="actionOpenProject"/>
<addaction name="actionSaveProject"/>
<addaction name="separator"/>
<addaction name="fileExitAction"/>
</widget>
<widget class="QMenu" name="editMenu">
Expand Down Expand Up @@ -1441,6 +1444,36 @@
<string>Web&amp;site...</string>
</property>
</action>
<action name="actionSaveProject">
<property name="icon">
<iconset resource="icons/icons.qrc">
<normaloff>:/icons/project_save</normaloff>:/icons/project_save</iconset>
</property>
<property name="text">
<string>Save Project</string>
</property>
<property name="toolTip">
<string>Save the current session to a file</string>
</property>
<property name="statusTip">
<string>Save the current session to a file</string>
</property>
</action>
<action name="actionOpenProject">
<property name="icon">
<iconset resource="icons/icons.qrc">
<normaloff>:/icons/project_open</normaloff>:/icons/project_open</iconset>
</property>
<property name="text">
<string>Open Project</string>
</property>
<property name="toolTip">
<string>Load a working session from a file</string>
</property>
<property name="statusTip">
<string>Load a working session from a file</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
Expand Down Expand Up @@ -2179,6 +2212,38 @@
</hint>
</hints>
</connection>
<connection>
<sender>actionOpenProject</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>loadProject()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>actionSaveProject</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>saveProject()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>299</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>fileOpen()</slot>
Expand Down Expand Up @@ -2225,5 +2290,7 @@
<slot>openSqlFile()</slot>
<slot>saveSqlFile()</slot>
<slot>loadExtension()</slot>
<slot>loadProject()</slot>
<slot>saveProject()</slot>
</slots>
</ui>
2 changes: 2 additions & 0 deletions src/icons/icons.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,7 @@
<file alias="up">bullet_arrow_up.png</file>
<file alias="appicon">sqlitebrowser.png</file>
<file alias="browser_open">internet-web-browser.png</file>
<file alias="project_save">package.png</file>
<file alias="project_open">package_go.png</file>
</qresource>
</RCC>
Binary file added src/icons/package.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/icons/package_go.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 62622ae

Please sign in to comment.