mirror of
https://github.com/sqlitebrowser/sqlitebrowser.git
synced 2026-01-20 02:50:46 -06:00
Merge pull request #1422 from GortiZ6/sql_export
As said by the author GortiZ6: > I've added the ability to copy fields from tables in SQL format. > I found much robust and easier copy data in SQL from one DB to another so that if the number of columns differs or if I want to build a single SQL file to share several fields from several table with someone I can do it.
This commit is contained in:
@@ -157,6 +157,7 @@ ExtendedTableWidget::ExtendedTableWidget(QWidget* parent) :
|
||||
QAction* nullAction = new QAction(tr("Set to NULL"), m_contextMenu);
|
||||
QAction* copyAction = new QAction(QIcon(":/icons/copy"), tr("Copy"), m_contextMenu);
|
||||
QAction* copyWithHeadersAction = new QAction(QIcon(":/icons/special_copy"), tr("Copy with Headers"), m_contextMenu);
|
||||
QAction* copyAsSQLAction = new QAction(QIcon(":/icons/sql_copy"), tr("Copy as SQL"), m_contextMenu);
|
||||
QAction* pasteAction = new QAction(QIcon(":/icons/paste"), tr("Paste"), m_contextMenu);
|
||||
QAction* filterAction = new QAction(tr("Use as Filter"), m_contextMenu);
|
||||
m_contextMenu->addAction(filterAction);
|
||||
@@ -165,6 +166,7 @@ ExtendedTableWidget::ExtendedTableWidget(QWidget* parent) :
|
||||
m_contextMenu->addSeparator();
|
||||
m_contextMenu->addAction(copyAction);
|
||||
m_contextMenu->addAction(copyWithHeadersAction);
|
||||
m_contextMenu->addAction(copyAsSQLAction);
|
||||
m_contextMenu->addAction(pasteAction);
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
@@ -177,6 +179,7 @@ ExtendedTableWidget::ExtendedTableWidget(QWidget* parent) :
|
||||
nullAction->setShortcut(QKeySequence(tr("Alt+Del")));
|
||||
copyAction->setShortcut(QKeySequence::Copy);
|
||||
copyWithHeadersAction->setShortcut(QKeySequence(tr("Ctrl+Shift+C")));
|
||||
copyAsSQLAction->setShortcut(QKeySequence(tr("Ctrl+Alt+C")));
|
||||
pasteAction->setShortcut(QKeySequence::Paste);
|
||||
|
||||
// Set up context menu actions
|
||||
@@ -188,6 +191,7 @@ ExtendedTableWidget::ExtendedTableWidget(QWidget* parent) :
|
||||
filterAction->setEnabled(enabled);
|
||||
copyAction->setEnabled(enabled);
|
||||
copyWithHeadersAction->setEnabled(enabled);
|
||||
copyAsSQLAction->setEnabled(enabled);
|
||||
|
||||
// Try to find out whether the current view is editable and (de)activate menu options according to that
|
||||
bool editable = editTriggers() != QAbstractItemView::NoEditTriggers;
|
||||
@@ -205,10 +209,13 @@ ExtendedTableWidget::ExtendedTableWidget(QWidget* parent) :
|
||||
model()->setData(index, QVariant());
|
||||
});
|
||||
connect(copyAction, &QAction::triggered, [&]() {
|
||||
copy(false);
|
||||
copy(false, false);
|
||||
});
|
||||
connect(copyWithHeadersAction, &QAction::triggered, [&]() {
|
||||
copy(true);
|
||||
copy(true, false);
|
||||
});
|
||||
connect(copyAsSQLAction, &QAction::triggered, [&]() {
|
||||
copy(false, true);
|
||||
});
|
||||
connect(pasteAction, &QAction::triggered, [&]() {
|
||||
paste();
|
||||
@@ -226,7 +233,7 @@ void ExtendedTableWidget::reloadSettings()
|
||||
verticalHeader()->setDefaultSectionSize(verticalHeader()->fontMetrics().height()+10);
|
||||
}
|
||||
|
||||
void ExtendedTableWidget::copy(const bool withHeaders)
|
||||
void ExtendedTableWidget::copy(const bool withHeaders, const bool inSQL )
|
||||
{
|
||||
QModelIndexList indices = selectionModel()->selectedIndexes();
|
||||
|
||||
@@ -249,7 +256,7 @@ void ExtendedTableWidget::copy(const bool withHeaders)
|
||||
m_buffer.clear();
|
||||
|
||||
// If a single cell is selected, copy it to clipboard
|
||||
if (!withHeaders && indices.size() == 1) {
|
||||
if (!inSQL && !withHeaders && indices.size() == 1) {
|
||||
QImage img;
|
||||
QVariant data = m->data(indices.first(), Qt::EditRole);
|
||||
|
||||
@@ -294,6 +301,7 @@ void ExtendedTableWidget::copy(const bool withHeaders)
|
||||
}
|
||||
m_buffer.push_back(lst);
|
||||
|
||||
QString sqlResult;
|
||||
QString result;
|
||||
QString htmlResult = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">";
|
||||
htmlResult.append("<html><head><meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">");
|
||||
@@ -314,8 +322,9 @@ void ExtendedTableWidget::copy(const bool withHeaders)
|
||||
const QString fieldSepText = "\t";
|
||||
const QString rowSepText = "\r\n";
|
||||
|
||||
QString sqlInsertStatement = QString("INSERT INTO %1 ( '").arg(sqlb::escapeIdentifier(m->currentTableName().toString()));
|
||||
// Table headers
|
||||
if (withHeaders) {
|
||||
if (withHeaders || inSQL) {
|
||||
htmlResult.append("<tr><th>");
|
||||
int firstColumn = indices.front().column();
|
||||
for(int i = firstColumn; i <= indices.back().column(); i++) {
|
||||
@@ -323,26 +332,32 @@ void ExtendedTableWidget::copy(const bool withHeaders)
|
||||
if (i != firstColumn) {
|
||||
result.append(fieldSepText);
|
||||
htmlResult.append("</th><th>");
|
||||
sqlInsertStatement.append("', '");
|
||||
}
|
||||
|
||||
result.append(escapeCopiedData(headerText));
|
||||
htmlResult.append(headerText);
|
||||
sqlInsertStatement.append(escapeCopiedData(headerText));
|
||||
}
|
||||
result.append(rowSepText);
|
||||
htmlResult.append("</th></tr>");
|
||||
sqlInsertStatement.append("') VALUES (\"");
|
||||
}
|
||||
|
||||
// Table data rows
|
||||
for(const QModelIndex& index : indices) {
|
||||
// Separators. For first cell, only opening table row tags must be added for the HTML and nothing for the text version.
|
||||
if (indices.first() == index)
|
||||
if (indices.first() == index) {
|
||||
htmlResult.append("<tr><td>");
|
||||
else if (index.row() != currentRow) {
|
||||
sqlResult.append(sqlInsertStatement);
|
||||
} else if (index.row() != currentRow) {
|
||||
result.append(rowSepText);
|
||||
htmlResult.append(rowSepHtml);
|
||||
sqlResult.append("\");\r\n"+sqlInsertStatement);
|
||||
} else {
|
||||
result.append(fieldSepText);
|
||||
htmlResult.append(fieldSepHtml);
|
||||
sqlResult.append("\", \"");
|
||||
}
|
||||
currentRow = index.row();
|
||||
|
||||
@@ -362,6 +377,7 @@ void ExtendedTableWidget::copy(const bool withHeaders)
|
||||
htmlResult.append("<img src=\"data:image/png;base64,");
|
||||
htmlResult.append(imageBase64);
|
||||
result.append(QString());
|
||||
sqlResult.append( "X\'" + ba.toHex() + "\'" );
|
||||
htmlResult.append("\" alt=\"Image\">");
|
||||
} else {
|
||||
QByteArray text;
|
||||
@@ -375,12 +391,19 @@ void ExtendedTableWidget::copy(const bool withHeaders)
|
||||
htmlResult.append(QString(text).toHtmlEscaped());
|
||||
|
||||
result.append(escapeCopiedData(text));
|
||||
sqlResult.append(text.replace("\"", "\"\""));
|
||||
}
|
||||
}
|
||||
sqlResult.append("\");");
|
||||
|
||||
QMimeData *mimeData = new QMimeData;
|
||||
mimeData->setHtml(htmlResult + "</td></tr></table></body></html>");
|
||||
mimeData->setText(result);
|
||||
if ( inSQL )
|
||||
{
|
||||
mimeData->setText(sqlResult);
|
||||
} else {
|
||||
mimeData->setHtml(htmlResult + "</td></tr></table></body></html>");
|
||||
mimeData->setText(result);
|
||||
}
|
||||
qApp->clipboard()->setMimeData(mimeData);
|
||||
}
|
||||
|
||||
@@ -541,14 +564,17 @@ void ExtendedTableWidget::keyPressEvent(QKeyEvent* event)
|
||||
// Call a custom copy method when Ctrl-C is pressed
|
||||
if(event->matches(QKeySequence::Copy))
|
||||
{
|
||||
copy(false);
|
||||
copy(false, false);
|
||||
return;
|
||||
} else if(event->matches(QKeySequence::Paste)) {
|
||||
// Call a custom paste method when Ctrl-V is pressed
|
||||
paste();
|
||||
} else if(event->modifiers().testFlag(Qt::ControlModifier) && event->modifiers().testFlag(Qt::ShiftModifier) && (event->key() == Qt::Key_C)) {
|
||||
// Call copy with headers when Ctrl-Shift-C is pressed
|
||||
copy(true);
|
||||
copy(true, false);
|
||||
} else if(event->modifiers().testFlag(Qt::ControlModifier) && event->modifiers().testFlag(Qt::AltModifier) && (event->key() == Qt::Key_C)) {
|
||||
// Call copy in SQL format when Ctrl-Alt-C is pressed
|
||||
copy(false, true);
|
||||
} else if(event->key() == Qt::Key_Tab && hasFocus() &&
|
||||
selectedIndexes().count() == 1 &&
|
||||
selectedIndexes().at(0).row() == model()->rowCount()-1 && selectedIndexes().at(0).column() == model()->columnCount()-1) {
|
||||
|
||||
@@ -50,7 +50,7 @@ signals:
|
||||
void selectedRowsToBeDeleted();
|
||||
|
||||
private:
|
||||
void copy(const bool withHeaders = false);
|
||||
void copy(const bool withHeaders, const bool inSQL );
|
||||
void paste();
|
||||
QString escapeCopiedData(const QByteArray& data) const;
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
<file alias="find">page_find.png</file>
|
||||
<file alias="close">cross.png</file>
|
||||
<file alias="special_copy">page_white_copy.png</file>
|
||||
<file alias="sql_copy">page_copy_sql.png</file>
|
||||
<file alias="text_replace">text_replace.png</file>
|
||||
<file alias="image_save">picture_save.png</file>
|
||||
<file alias="log_dock">application_side_list.png</file>
|
||||
|
||||
BIN
src/icons/page_copy_sql.png
Normal file
BIN
src/icons/page_copy_sql.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 833 B |
Reference in New Issue
Block a user