Merge branch 'browser_formats'
@@ -2,10 +2,29 @@
|
||||
#include "Settings.h"
|
||||
#include "Data.h"
|
||||
|
||||
CondFormat::CondFormat(const QString& filter, const QColor& foreground, const QColor& background, const QString& encoding)
|
||||
CondFormat::Alignment CondFormat::fromCombinedAlignment(Qt::Alignment align)
|
||||
{
|
||||
if (align.testFlag(Qt::AlignLeft))
|
||||
return AlignLeft;
|
||||
if (align.testFlag(Qt::AlignRight))
|
||||
return AlignRight;
|
||||
if (align.testFlag(Qt::AlignCenter))
|
||||
return AlignCenter;
|
||||
if (align.testFlag(Qt::AlignJustify))
|
||||
return AlignJustify;
|
||||
}
|
||||
|
||||
CondFormat::CondFormat(const QString& filter,
|
||||
const QColor& foreground,
|
||||
const QColor& background,
|
||||
const QFont& font,
|
||||
const Alignment alignment,
|
||||
const QString& encoding)
|
||||
: m_filter(filter),
|
||||
m_bgColor(background),
|
||||
m_fgColor(foreground)
|
||||
m_fgColor(foreground),
|
||||
m_font(font),
|
||||
m_align(alignment)
|
||||
{
|
||||
if (!filter.isEmpty())
|
||||
m_sqlCondition = filterToSqlCondition(filter, encoding);
|
||||
@@ -115,3 +134,17 @@ QString CondFormat::filterToSqlCondition(const QString& value, const QString& en
|
||||
return whereClause;
|
||||
}
|
||||
}
|
||||
|
||||
Qt::AlignmentFlag CondFormat::alignmentFlag() const
|
||||
{
|
||||
switch (m_align) {
|
||||
case AlignLeft:
|
||||
return Qt::AlignLeft;
|
||||
case AlignCenter:
|
||||
return Qt::AlignCenter;
|
||||
case AlignRight:
|
||||
return Qt::AlignRight;
|
||||
case AlignJustify:
|
||||
return Qt::AlignJustify;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,36 @@
|
||||
|
||||
#include <QString>
|
||||
#include <QColor>
|
||||
#include <QFont>
|
||||
|
||||
// Conditional formatting for given format to table cells based on a specified condition.
|
||||
class CondFormat
|
||||
{
|
||||
public:
|
||||
|
||||
enum Alignment {
|
||||
AlignLeft = 0,
|
||||
AlignRight,
|
||||
AlignCenter,
|
||||
AlignJustify
|
||||
};
|
||||
|
||||
// List of alignment texts. Order must be as Alignment definition above.
|
||||
static QStringList alignmentTexts() {
|
||||
return {QObject::tr("Left"), QObject::tr("Right"), QObject::tr("Center"), QObject::tr("Justify")};
|
||||
};
|
||||
|
||||
// Get alignment from combined Qt alignment (note that this will lose any combination of our Alignment enum
|
||||
// with other values present in the flag (e.g. vertical alignment).
|
||||
static Alignment fromCombinedAlignment(Qt::Alignment align);
|
||||
|
||||
CondFormat() {}
|
||||
explicit CondFormat(const QString& filter, const QColor& foreground, const QColor& background, const QString& encoding = QString());
|
||||
explicit CondFormat(const QString& filter,
|
||||
const QColor& foreground,
|
||||
const QColor& background,
|
||||
const QFont& font,
|
||||
const Alignment alignment = AlignLeft,
|
||||
const QString& encoding = QString());
|
||||
|
||||
static QString filterToSqlCondition(const QString& value, const QString& encoding = QString());
|
||||
|
||||
@@ -18,13 +41,32 @@ private:
|
||||
QString m_filter;
|
||||
QColor m_bgColor;
|
||||
QColor m_fgColor;
|
||||
QFont m_font;
|
||||
Alignment m_align;
|
||||
|
||||
public:
|
||||
QString sqlCondition() const { return m_sqlCondition; }
|
||||
QString filter() const { return m_filter; }
|
||||
|
||||
QColor backgroundColor() const { return m_bgColor; }
|
||||
QColor foregroundColor() const { return m_fgColor; }
|
||||
void setBackgroundColor(QColor color) { m_bgColor = color; }
|
||||
void setForegroundColor(QColor color) { m_fgColor = color; }
|
||||
|
||||
bool isBold() const { return m_font.bold(); }
|
||||
bool isItalic() const { return m_font.italic(); }
|
||||
bool isUnderline() const { return m_font.underline(); }
|
||||
void setBold(bool value) { m_font.setBold(value); }
|
||||
void setItalic(bool value) { m_font.setItalic(value); }
|
||||
void setUnderline(bool value) { m_font.setUnderline(value); }
|
||||
|
||||
QFont font() const { return m_font; }
|
||||
void setFontFamily(const QString &family) { m_font.setFamily(family); }
|
||||
void setFontPointSize(int pointSize) { m_font.setPointSize(pointSize); }
|
||||
|
||||
Alignment alignment() const { return m_align; }
|
||||
void setAlignment(Alignment value) { m_align = value; }
|
||||
Qt::AlignmentFlag alignmentFlag() const;
|
||||
};
|
||||
|
||||
#endif // CONDFORMAT_H
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
#include <QUrl>
|
||||
#include <QPushButton>
|
||||
#include <QMessageBox>
|
||||
#include <QFontComboBox>
|
||||
#include <QSpinBox>
|
||||
#include <QComboBox>
|
||||
|
||||
CondFormatManager::CondFormatManager(const std::vector<CondFormat>& condFormats, const QString& encoding, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
@@ -20,6 +23,10 @@ CondFormatManager::CondFormatManager(const std::vector<CondFormat>& condFormats,
|
||||
for(const CondFormat& aCondFormat : condFormats)
|
||||
addItem(aCondFormat);
|
||||
|
||||
// Resize columns to contents, except for the condition
|
||||
for(int col = ColumnForeground; col < ColumnFilter; ++col)
|
||||
ui->tableCondFormats->resizeColumnToContents(col);
|
||||
|
||||
ui->tableCondFormats->setEditTriggers(QAbstractItemView::AllEditTriggers);
|
||||
|
||||
connect(ui->buttonAdd, SIGNAL(clicked(bool)), this, SLOT(addNewItem()));
|
||||
@@ -38,22 +45,51 @@ CondFormatManager::~CondFormatManager()
|
||||
|
||||
void CondFormatManager::addNewItem()
|
||||
{
|
||||
QFont font = QFont(Settings::getValue("databrowser", "font").toString());
|
||||
font.setPointSize(Settings::getValue("databrowser", "fontsize").toInt());
|
||||
|
||||
CondFormat newCondFormat("", QColor(Settings::getValue("databrowser", "reg_fg_colour").toString()),
|
||||
m_condFormatPalette.nextSerialColor(Palette::appHasDarkTheme()),
|
||||
font,
|
||||
CondFormat::AlignLeft,
|
||||
m_encoding);
|
||||
addItem(newCondFormat);
|
||||
|
||||
// Resize columns to contents, except for the condition
|
||||
for(int col = ColumnForeground; col < ColumnFilter; ++col)
|
||||
ui->tableCondFormats->resizeColumnToContents(col);
|
||||
}
|
||||
|
||||
void CondFormatManager::addItem(const CondFormat& aCondFormat)
|
||||
{
|
||||
int i = ui->tableCondFormats->topLevelItemCount();
|
||||
QTreeWidgetItem *newItem = new QTreeWidgetItem({"", "", aCondFormat.filter()});
|
||||
QTreeWidgetItem *newItem = new QTreeWidgetItem(ui->tableCondFormats);
|
||||
newItem->setForeground(ColumnForeground, aCondFormat.foregroundColor());
|
||||
newItem->setBackground(ColumnForeground, aCondFormat.foregroundColor());
|
||||
newItem->setForeground(ColumnBackground, aCondFormat.backgroundColor());
|
||||
newItem->setBackground(ColumnBackground, aCondFormat.backgroundColor());
|
||||
newItem->setToolTip(ColumnBackground, tr("Click to select color"));
|
||||
newItem->setToolTip(ColumnForeground, tr("Click to select color"));
|
||||
|
||||
QFontComboBox* fontCombo = new QFontComboBox(ui->tableCondFormats);
|
||||
fontCombo->setCurrentFont(aCondFormat.font());
|
||||
ui->tableCondFormats->setItemWidget(newItem, ColumnFont, fontCombo);
|
||||
|
||||
QSpinBox* sizeBox = new QSpinBox(ui->tableCondFormats);
|
||||
sizeBox->setMinimum(1);
|
||||
sizeBox->setValue(aCondFormat.font().pointSize());
|
||||
ui->tableCondFormats->setItemWidget(newItem, ColumnSize, sizeBox);
|
||||
|
||||
newItem->setCheckState(ColumnBold, aCondFormat.isBold() ? Qt::Checked : Qt::Unchecked);
|
||||
newItem->setCheckState(ColumnItalic, aCondFormat.isItalic() ? Qt::Checked : Qt::Unchecked);
|
||||
newItem->setCheckState(ColumnUnderline, aCondFormat.isUnderline() ? Qt::Checked : Qt::Unchecked);
|
||||
|
||||
QComboBox* alignCombo = new QComboBox(ui->tableCondFormats);
|
||||
alignCombo->addItems(CondFormat::alignmentTexts());
|
||||
alignCombo->setCurrentIndex(aCondFormat.alignment());
|
||||
ui->tableCondFormats->setItemWidget(newItem, ColumnAlignment, alignCombo);
|
||||
|
||||
newItem->setText(ColumnFilter, aCondFormat.filter());
|
||||
ui->tableCondFormats->insertTopLevelItem(i, newItem);
|
||||
ui->tableCondFormats->openPersistentEditor(newItem, ColumnFilter);
|
||||
}
|
||||
@@ -64,48 +100,78 @@ void CondFormatManager::removeItem()
|
||||
delete item;
|
||||
}
|
||||
|
||||
void CondFormatManager::upItem()
|
||||
void CondFormatManager::moveItem(int offset)
|
||||
{
|
||||
if (!ui->tableCondFormats->currentIndex().isValid())
|
||||
return;
|
||||
|
||||
int selectedRow = ui->tableCondFormats->currentIndex().row();
|
||||
if(selectedRow == 0)
|
||||
int newRow = selectedRow + offset;
|
||||
if(newRow < 0 || newRow >= ui->tableCondFormats->topLevelItemCount())
|
||||
return;
|
||||
|
||||
QTreeWidgetItem* item;
|
||||
QTreeWidgetItem* item = ui->tableCondFormats->topLevelItem(selectedRow);
|
||||
|
||||
// Rescue widgets, since they will be deleted, and add them later.
|
||||
QFontComboBox* fontCombo = qobject_cast<QFontComboBox*>(ui->tableCondFormats->itemWidget(item, ColumnFont));
|
||||
QFontComboBox* fontCombo2 = new QFontComboBox(ui->tableCondFormats);
|
||||
fontCombo2->setCurrentFont(fontCombo->currentFont());
|
||||
|
||||
QSpinBox* sizeBox = qobject_cast<QSpinBox*>(ui->tableCondFormats->itemWidget(item, ColumnSize));
|
||||
QSpinBox* sizeBox2 = new QSpinBox(ui->tableCondFormats);
|
||||
sizeBox2->setValue(sizeBox->value());
|
||||
sizeBox2->setMinimum(sizeBox->minimum());
|
||||
|
||||
QComboBox* alignCombo = qobject_cast<QComboBox*>(ui->tableCondFormats->itemWidget(item, ColumnAlignment));
|
||||
QComboBox* alignCombo2 = new QComboBox(ui->tableCondFormats);
|
||||
alignCombo2->addItems(CondFormat::alignmentTexts());
|
||||
alignCombo2->setCurrentIndex(alignCombo->currentIndex());
|
||||
|
||||
item = ui->tableCondFormats->takeTopLevelItem(selectedRow);
|
||||
ui->tableCondFormats->insertTopLevelItem(selectedRow-1, item);
|
||||
ui->tableCondFormats->insertTopLevelItem(newRow, item);
|
||||
|
||||
// Restore widgets and state
|
||||
ui->tableCondFormats->setItemWidget(item, ColumnFont, fontCombo2);
|
||||
ui->tableCondFormats->setItemWidget(item, ColumnSize, sizeBox2);
|
||||
ui->tableCondFormats->setItemWidget(item, ColumnAlignment, alignCombo2);
|
||||
ui->tableCondFormats->openPersistentEditor(item, ColumnFilter);
|
||||
ui->tableCondFormats->setCurrentIndex(ui->tableCondFormats->currentIndex().sibling(selectedRow-1,
|
||||
ui->tableCondFormats->setCurrentIndex(ui->tableCondFormats->currentIndex().sibling(newRow,
|
||||
ui->tableCondFormats->currentIndex().column()));
|
||||
}
|
||||
|
||||
void CondFormatManager::upItem()
|
||||
{
|
||||
moveItem(-1);
|
||||
}
|
||||
|
||||
void CondFormatManager::downItem()
|
||||
{
|
||||
if (!ui->tableCondFormats->currentIndex().isValid()) return;
|
||||
|
||||
int selectedRow = ui->tableCondFormats->currentIndex().row();
|
||||
if(selectedRow == ui->tableCondFormats->topLevelItemCount() - 1)
|
||||
return;
|
||||
|
||||
QTreeWidgetItem* item;
|
||||
item = ui->tableCondFormats->takeTopLevelItem(selectedRow);
|
||||
ui->tableCondFormats->insertTopLevelItem(selectedRow+1, item);
|
||||
ui->tableCondFormats->openPersistentEditor(item, ColumnFilter);
|
||||
ui->tableCondFormats->setCurrentIndex(ui->tableCondFormats->currentIndex().sibling(selectedRow+1,
|
||||
ui->tableCondFormats->currentIndex().column()));
|
||||
moveItem(+1);
|
||||
}
|
||||
|
||||
std::vector<CondFormat> CondFormatManager::getCondFormats()
|
||||
{
|
||||
std::vector<CondFormat> result;
|
||||
|
||||
for (int i = 0; i < ui->tableCondFormats->topLevelItemCount(); ++i)
|
||||
{
|
||||
QTreeWidgetItem* item = ui->tableCondFormats->topLevelItem(i);
|
||||
|
||||
QFontComboBox* fontCombo = qobject_cast<QFontComboBox*>(ui->tableCondFormats->itemWidget(item, ColumnFont));
|
||||
QSpinBox* sizeBox = qobject_cast<QSpinBox*>(ui->tableCondFormats->itemWidget(item, ColumnSize));
|
||||
QFont font = fontCombo->currentFont();
|
||||
font.setPointSize(sizeBox->value());
|
||||
font.setBold(item->checkState(ColumnBold) == Qt::Checked);
|
||||
font.setItalic(item->checkState(ColumnItalic) == Qt::Checked);
|
||||
font.setUnderline(item->checkState(ColumnUnderline) == Qt::Checked);
|
||||
QComboBox* alignCombo = qobject_cast<QComboBox*>(ui->tableCondFormats->itemWidget(item, ColumnAlignment));
|
||||
|
||||
result.emplace_back(item->text(ColumnFilter),
|
||||
item->background(ColumnForeground).color(),
|
||||
item->background(ColumnBackground).color(), m_encoding);
|
||||
item->background(ColumnBackground).color(),
|
||||
font,
|
||||
static_cast<CondFormat::Alignment>(alignCombo->currentIndex()),
|
||||
m_encoding);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -124,7 +190,7 @@ void CondFormatManager::itemClicked(QTreeWidgetItem* item, int column)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ColumnFilter:
|
||||
default:
|
||||
// Nothing to do
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -26,18 +26,25 @@ public:
|
||||
private:
|
||||
enum Columns {
|
||||
ColumnForeground = 0,
|
||||
ColumnBackground = 1,
|
||||
ColumnFilter = 2
|
||||
ColumnBackground,
|
||||
ColumnFont,
|
||||
ColumnSize,
|
||||
ColumnBold,
|
||||
ColumnItalic,
|
||||
ColumnUnderline,
|
||||
ColumnAlignment,
|
||||
ColumnFilter
|
||||
};
|
||||
Ui::CondFormatManager *ui;
|
||||
std::vector<CondFormat> m_condFormats;
|
||||
Palette m_condFormatPalette;
|
||||
QString m_encoding;
|
||||
|
||||
|
||||
private slots:
|
||||
void addNewItem();
|
||||
void addItem(const CondFormat& aCondFormat);
|
||||
void removeItem();
|
||||
void moveItem(int offset);
|
||||
void upItem();
|
||||
void downItem();
|
||||
void on_buttonBox_clicked(QAbstractButton* button);
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>578</width>
|
||||
<height>463</height>
|
||||
<width>700</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -17,7 +17,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="labelTitle">
|
||||
<property name="text">
|
||||
<string>This dialog allows creating and editing conditional formats, where the cell text and background will be colored based on one or more conditions. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower.</string>
|
||||
<string>This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. An empty condition applies to all values.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
@@ -150,19 +150,76 @@
|
||||
<property name="expandsOnDoubleClick">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="headerDefaultSectionSize">
|
||||
<number>150</number>
|
||||
<attribute name="headerMinimumSectionSize">
|
||||
<number>25</number>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Foreground</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Text color</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Background</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Background color</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Font</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Size</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Bold</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="icons/icons.qrc">
|
||||
<normaloff>:/icons/text_bold.png</normaloff>:/icons/text_bold.png</iconset>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Italic</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="icons/icons.qrc">
|
||||
<normaloff>:/icons/text_italic.png</normaloff>:/icons/text_italic.png</iconset>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Underline</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="icons/icons.qrc">
|
||||
<normaloff>:/icons/text_underline.png</normaloff>:/icons/text_underline.png</iconset>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Alignment</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Condition</string>
|
||||
|
||||
@@ -849,6 +849,14 @@ std::unordered_set<int> ExtendedTableWidget::selectedCols() const
|
||||
return selectedCols;
|
||||
}
|
||||
|
||||
std::unordered_set<int> ExtendedTableWidget::colsInSelection() const
|
||||
{
|
||||
std::unordered_set<int> colsInSelection;
|
||||
for(const QModelIndex & idx : selectedIndexes())
|
||||
colsInSelection.insert(idx.column());
|
||||
return colsInSelection;
|
||||
}
|
||||
|
||||
void ExtendedTableWidget::cellClicked(const QModelIndex& index)
|
||||
{
|
||||
// If Ctrl-Shift is pressed try to jump to the row referenced by the foreign key of the clicked cell
|
||||
|
||||
@@ -52,7 +52,11 @@ public:
|
||||
FilterTableHeader* filterHeader() { return m_tableHeader; }
|
||||
|
||||
public:
|
||||
// Get set of selected columns (all cells in column has to be selected)
|
||||
std::unordered_set<int> selectedCols() const;
|
||||
// Get set of columns traversed by selection (only some cells in column has to be selected)
|
||||
std::unordered_set<int> colsInSelection() const;
|
||||
|
||||
int numVisibleRows() const;
|
||||
|
||||
void sortByColumns(const std::vector<sqlb::SortedColumn>& columns);
|
||||
@@ -70,6 +74,8 @@ signals:
|
||||
void openFileFromDropEvent(QString);
|
||||
void selectedRowsToBeDeleted();
|
||||
void editCondFormats(int column);
|
||||
// Make the inherited protected signal public
|
||||
void currentChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
|
||||
private:
|
||||
void copyMimeData(const QModelIndexList& fromIndices, QMimeData* mimeData, const bool withHeaders, const bool inSQL);
|
||||
|
||||
@@ -184,7 +184,7 @@ void FilterLineEdit::showContextMenu(const QPoint &pos)
|
||||
emit clearAllCondFormats();
|
||||
});
|
||||
} else {
|
||||
conditionalFormatAction = new QAction(QIcon(":/icons/cond_formats"), tr("Use for Conditional Format"), editContextMenu);
|
||||
conditionalFormatAction = new QAction(QIcon(":/icons/add_cond_format"), tr("Use for Conditional Format"), editContextMenu);
|
||||
connect(conditionalFormatAction, &QAction::triggered, [&]() {
|
||||
emit addFilterAsCondFormat(text());
|
||||
});
|
||||
|
||||
@@ -17,6 +17,9 @@ FilterTableHeader::FilterTableHeader(QTableView* parent) :
|
||||
// Make sure to not automatically resize the columns according to the contents
|
||||
setSectionResizeMode(QHeaderView::Interactive);
|
||||
|
||||
// Highlight column headers of selected cells to emulate spreadsheet behaviour
|
||||
setHighlightSections(true);
|
||||
|
||||
// Do some connects: Basically just resize and reposition the input widgets whenever anything changes
|
||||
connect(this, &FilterTableHeader::sectionResized, this, &FilterTableHeader::adjustPositions);
|
||||
connect(parent->horizontalScrollBar(), &QScrollBar::valueChanged, this, &FilterTableHeader::adjustPositions);
|
||||
|
||||
@@ -2246,10 +2246,22 @@ static void loadBrowseDataTableSettings(BrowseDataTableSettings& settings, QXmlS
|
||||
int index = xml.attributes().value("index").toInt();
|
||||
while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "column") {
|
||||
if(xml.name() == "format") {
|
||||
QFont font;
|
||||
if (xml.attributes().hasAttribute("font"))
|
||||
font.fromString(xml.attributes().value("font").toString());
|
||||
else
|
||||
Settings::getValue("databrowser", "font").toString();
|
||||
|
||||
CondFormat::Alignment align;
|
||||
if (xml.attributes().hasAttribute("align"))
|
||||
align = static_cast<CondFormat::Alignment>(xml.attributes().value("align").toInt());
|
||||
else
|
||||
align = CondFormat::AlignLeft;
|
||||
|
||||
settings.condFormats[index].emplace_back(xml.attributes().value("condition").toString(),
|
||||
QColor(xml.attributes().value("foreground").toString()),
|
||||
QColor(xml.attributes().value("background").toString()),
|
||||
settings.encoding);
|
||||
font, align, settings.encoding);
|
||||
xml.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
@@ -2587,6 +2599,8 @@ static void saveBrowseDataTableSettings(const BrowseDataTableSettings& object, Q
|
||||
xml.writeAttribute("condition", format.filter());
|
||||
xml.writeAttribute("background", format.backgroundColor().name());
|
||||
xml.writeAttribute("foreground", format.foregroundColor().name());
|
||||
xml.writeAttribute("font", format.font().toString());
|
||||
xml.writeAttribute("align", QString().setNum(format.alignment()));
|
||||
xml.writeEndElement();
|
||||
}
|
||||
xml.writeEndElement();
|
||||
|
||||
@@ -124,6 +124,21 @@ You can drag SQL statements from an object row and drop them into other applicat
|
||||
<string>Browse Data</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="TableBrowser" name="tableBrowser" native="true"/>
|
||||
</item>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <QScrollBar>
|
||||
#include <QShortcut>
|
||||
#include <QTextCodec>
|
||||
#include <QColorDialog>
|
||||
|
||||
QMap<sqlb::ObjectIdentifier, BrowseDataTableSettings> TableBrowser::browseTableSettings;
|
||||
QString TableBrowser::defaultBrowseTableEncoding;
|
||||
@@ -128,6 +129,115 @@ TableBrowser::TableBrowser(QWidget* parent) :
|
||||
connect(ui->dataTable, &ExtendedTableWidget::openFileFromDropEvent, this, &TableBrowser::requestFileOpen);
|
||||
connect(ui->dataTable, &ExtendedTableWidget::selectedRowsToBeDeleted, this, &TableBrowser::deleteRecord);
|
||||
|
||||
connect(ui->fontComboBox, &QFontComboBox::currentFontChanged, this, [this](const QFont &font) {
|
||||
modifyColumnFormat(ui->dataTable->colsInSelection(), [font](CondFormat& format) { format.setFontFamily(font.family()); });
|
||||
});
|
||||
connect(ui->fontSizeBox, QOverload<int>::of(&QSpinBox::valueChanged), this, [this](int pointSize) {
|
||||
modifyColumnFormat(ui->dataTable->colsInSelection(), [pointSize](CondFormat& format) { format.setFontPointSize(pointSize); });
|
||||
});
|
||||
|
||||
connect(ui->actionFontColor, &QAction::triggered, this, [this]() {
|
||||
QColor color = QColorDialog::getColor(QColor(m_browseTableModel->data(currentIndex(), Qt::ForegroundRole).toString()));
|
||||
if(color.isValid())
|
||||
modifyColumnFormat(ui->dataTable->colsInSelection(), [color](CondFormat& format) { format.setForegroundColor(color); });
|
||||
});
|
||||
connect(ui->actionBackgroundColor, &QAction::triggered, this, [this]() {
|
||||
QColor color = QColorDialog::getColor(QColor(m_browseTableModel->data(currentIndex(), Qt::BackgroundRole).toString()));
|
||||
if(color.isValid())
|
||||
modifyColumnFormat(ui->dataTable->colsInSelection(), [color](CondFormat& format) { format.setBackgroundColor(color); });
|
||||
});
|
||||
|
||||
connect(ui->actionBold, &QAction::toggled, this, [this](bool checked) {
|
||||
modifyColumnFormat(ui->dataTable->colsInSelection(), [checked](CondFormat& format) { format.setBold(checked); });
|
||||
});
|
||||
connect(ui->actionItalic, &QAction::toggled, this, [this](bool checked) {
|
||||
modifyColumnFormat(ui->dataTable->colsInSelection(), [checked](CondFormat& format) { format.setItalic(checked); });
|
||||
});
|
||||
connect(ui->actionUnderline, &QAction::toggled, this, [this](bool checked) {
|
||||
modifyColumnFormat(ui->dataTable->colsInSelection(), [checked](CondFormat& format) { format.setUnderline(checked); });
|
||||
});
|
||||
|
||||
connect(ui->actionLeftAlign, &QAction::triggered, this, [this]() {
|
||||
ui->actionLeftAlign->setChecked(true);
|
||||
ui->actionRightAlign->setChecked(false);
|
||||
ui->actionCenter->setChecked(false);
|
||||
ui->actionJustify->setChecked(false);
|
||||
modifyColumnFormat(ui->dataTable->colsInSelection(), [](CondFormat& format) { format.setAlignment(CondFormat::AlignLeft); });
|
||||
});
|
||||
connect(ui->actionRightAlign, &QAction::triggered, this, [this]() {
|
||||
ui->actionLeftAlign->setChecked(false);
|
||||
ui->actionRightAlign->setChecked(true);
|
||||
ui->actionCenter->setChecked(false);
|
||||
ui->actionJustify->setChecked(false);
|
||||
modifyColumnFormat(ui->dataTable->colsInSelection(), [](CondFormat& format) { format.setAlignment(CondFormat::AlignRight); });
|
||||
});
|
||||
connect(ui->actionCenter, &QAction::triggered, this, [this]() {
|
||||
ui->actionLeftAlign->setChecked(false);
|
||||
ui->actionRightAlign->setChecked(false);
|
||||
ui->actionCenter->setChecked(true);
|
||||
ui->actionJustify->setChecked(false);
|
||||
modifyColumnFormat(ui->dataTable->colsInSelection(), [](CondFormat& format) { format.setAlignment(CondFormat::AlignCenter); });
|
||||
});
|
||||
connect(ui->actionJustify, &QAction::triggered, this, [this]() {
|
||||
ui->actionLeftAlign->setChecked(false);
|
||||
ui->actionRightAlign->setChecked(false);
|
||||
ui->actionCenter->setChecked(false);
|
||||
ui->actionJustify->setChecked(true);
|
||||
modifyColumnFormat(ui->dataTable->colsInSelection(), [](CondFormat& format) { format.setAlignment(CondFormat::AlignJustify); });
|
||||
});
|
||||
|
||||
connect(ui->actionEditCondFormats, &QAction::triggered, this, [this]() { editCondFormats(currentIndex().column()); });
|
||||
connect(ui->actionClearFormat, &QAction::triggered, this, [this]() {
|
||||
for (int column : ui->dataTable->colsInSelection())
|
||||
clearAllCondFormats(column);
|
||||
});
|
||||
|
||||
connect(ui->dataTable, &ExtendedTableWidget::currentChanged, this, [this](const QModelIndex ¤t, const QModelIndex &) {
|
||||
// Get cell current format for updating the format toolbar values. Block signals, so the format change is not reapplied.
|
||||
QFont font;
|
||||
font.fromString(m_browseTableModel->data(current, Qt::FontRole).toString());
|
||||
ui->fontComboBox->blockSignals(true);
|
||||
ui->fontComboBox->setCurrentFont(font);
|
||||
ui->fontComboBox->blockSignals(false);
|
||||
|
||||
ui->fontSizeBox->blockSignals(true);
|
||||
ui->fontSizeBox->setValue(font.pointSize());
|
||||
ui->fontSizeBox->blockSignals(false);
|
||||
|
||||
ui->actionBold->blockSignals(true);
|
||||
ui->actionBold->setChecked(font.bold());
|
||||
ui->actionBold->blockSignals(false);
|
||||
|
||||
ui->actionItalic->blockSignals(true);
|
||||
ui->actionItalic->setChecked(font.italic());
|
||||
ui->actionItalic->blockSignals(false);
|
||||
|
||||
ui->actionUnderline->blockSignals(true);
|
||||
ui->actionUnderline->setChecked(font.underline());
|
||||
ui->actionUnderline->blockSignals(false);
|
||||
|
||||
Qt::Alignment align = Qt::Alignment(m_browseTableModel->data(current, Qt::TextAlignmentRole).toInt());
|
||||
ui->actionLeftAlign->blockSignals(true);
|
||||
ui->actionLeftAlign->setChecked(align.testFlag(Qt::AlignLeft));
|
||||
ui->actionLeftAlign->blockSignals(false);
|
||||
|
||||
ui->actionRightAlign->blockSignals(true);
|
||||
ui->actionRightAlign->setChecked(align.testFlag(Qt::AlignRight));
|
||||
ui->actionRightAlign->blockSignals(false);
|
||||
|
||||
ui->actionCenter->blockSignals(true);
|
||||
ui->actionCenter->setChecked(align.testFlag(Qt::AlignCenter));
|
||||
ui->actionCenter->blockSignals(false);
|
||||
|
||||
ui->actionJustify->blockSignals(true);
|
||||
ui->actionJustify->setChecked(align.testFlag(Qt::AlignJustify));
|
||||
ui->actionJustify->blockSignals(false);
|
||||
});
|
||||
|
||||
connect(ui->actionToggleFormatToolbar, &QAction::toggled, ui->formatFrame, &QFrame::setVisible);
|
||||
ui->actionToggleFormatToolbar->setChecked(false);
|
||||
ui->formatFrame->setVisible(false);
|
||||
|
||||
// Set up find frame
|
||||
ui->frameFind->hide();
|
||||
|
||||
@@ -473,10 +583,15 @@ void TableBrowser::updateFilter(int column, const QString& value)
|
||||
|
||||
void TableBrowser::addCondFormat(int column, const QString& value)
|
||||
{
|
||||
QFont font = QFont(Settings::getValue("databrowser", "font").toString());
|
||||
font.setPointSize(Settings::getValue("databrowser", "fontsize").toInt());
|
||||
|
||||
// Create automatically a new conditional format with the next serial background color according to the theme and the regular foreground
|
||||
// color in the settings.
|
||||
// color and font in the settings.
|
||||
CondFormat newCondFormat(value, QColor(Settings::getValue("databrowser", "reg_fg_colour").toString()),
|
||||
m_condFormatPalette.nextSerialColor(Palette::appHasDarkTheme()),
|
||||
font,
|
||||
CondFormat::AlignLeft,
|
||||
m_browseTableModel->encoding());
|
||||
m_browseTableModel->addCondFormat(column, newCondFormat);
|
||||
browseTableSettings[currentlyBrowsedTableName()].condFormats[column].push_back(newCondFormat);
|
||||
@@ -494,6 +609,8 @@ void TableBrowser::editCondFormats(int column)
|
||||
{
|
||||
CondFormatManager condFormatDialog(browseTableSettings[currentlyBrowsedTableName()].condFormats[column],
|
||||
m_browseTableModel->encoding(), this);
|
||||
condFormatDialog.setWindowTitle(tr("Conditional formats for \"%1\"").
|
||||
arg(m_browseTableModel->headerData(column, Qt::Horizontal).toString()));
|
||||
if (condFormatDialog.exec()) {
|
||||
std::vector<CondFormat> condFormatVector = condFormatDialog.getCondFormats();
|
||||
m_browseTableModel->setCondFormats(column, condFormatVector);
|
||||
@@ -502,6 +619,38 @@ void TableBrowser::editCondFormats(int column)
|
||||
}
|
||||
}
|
||||
|
||||
void TableBrowser::modifyColumnFormat(std::unordered_set<int> columns, std::function<void(CondFormat&)> changeFunction)
|
||||
{
|
||||
for (int column : columns) {
|
||||
std::vector<CondFormat>& columnFormats = browseTableSettings[currentlyBrowsedTableName()].condFormats[column];
|
||||
|
||||
auto it = std::find_if(columnFormats.begin(), columnFormats.end(), [](const CondFormat& format) {
|
||||
return format.sqlCondition().isEmpty();
|
||||
});
|
||||
if(it != columnFormats.end()) {
|
||||
changeFunction(*it);
|
||||
m_browseTableModel->addCondFormat(column, *it);
|
||||
} else {
|
||||
// Create a new conditional format based on defaults and then modify it as requested using the passed function.
|
||||
// Alignment is get from the current column since the default is different from text and numbers.
|
||||
QFont font = QFont(Settings::getValue("databrowser", "font").toString());
|
||||
font.setPointSize(Settings::getValue("databrowser", "fontsize").toInt());
|
||||
Qt::Alignment align = Qt::Alignment(m_browseTableModel->data(currentIndex().sibling(currentIndex().row(), column),
|
||||
Qt::TextAlignmentRole).toInt());
|
||||
|
||||
CondFormat newCondFormat(QString(""), QColor(Settings::getValue("databrowser", "reg_fg_colour").toString()),
|
||||
QColor(Settings::getValue("databrowser", "reg_bg_colour").toString()),
|
||||
font,
|
||||
CondFormat::fromCombinedAlignment(align),
|
||||
m_browseTableModel->encoding());
|
||||
changeFunction(newCondFormat);
|
||||
m_browseTableModel->addCondFormat(column, newCondFormat);
|
||||
browseTableSettings[currentlyBrowsedTableName()].condFormats[column].push_back(newCondFormat);
|
||||
}
|
||||
}
|
||||
emit projectModified();
|
||||
}
|
||||
|
||||
void TableBrowser::updateRecordsetLabel()
|
||||
{
|
||||
// Get all the numbers, i.e. the number of the first row and the last row as well as the total number of rows
|
||||
@@ -1239,9 +1388,10 @@ void TableBrowser::find(const QString& expr, bool forward, bool include_first)
|
||||
const auto match = m_browseTableModel->nextMatch(start, column_list, expr, flags, !forward, include_first);
|
||||
|
||||
// Select the next match if we found one
|
||||
if(match.isValid())
|
||||
if(match.isValid()) {
|
||||
ui->dataTable->setCurrentIndex(match);
|
||||
|
||||
ui->dataTable->scrollTo(match);
|
||||
}
|
||||
// Make the expression control red if no results were found
|
||||
if(match.isValid() || expr == "")
|
||||
ui->editFindExpression->setStyleSheet("");
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <QModelIndex>
|
||||
#include <QWidget>
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
class DBBrowserDB;
|
||||
class ExtendedTableWidget;
|
||||
class SqliteTableModel;
|
||||
@@ -172,6 +174,8 @@ private:
|
||||
static QString defaultBrowseTableEncoding;
|
||||
|
||||
Palette m_condFormatPalette;
|
||||
|
||||
void modifyColumnFormat(std::unordered_set<int> columns, std::function<void(CondFormat&)> changeFunction);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>617</width>
|
||||
<width>651</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -14,6 +14,9 @@
|
||||
<string>Browse Data</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
@@ -28,6 +31,12 @@
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
@@ -75,6 +84,7 @@
|
||||
<addaction name="actionNewRecord"/>
|
||||
<addaction name="actionDeleteRecord"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionToggleFormatToolbar"/>
|
||||
<addaction name="actionFind"/>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -99,6 +109,64 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="formatFrame">
|
||||
<layout class="QHBoxLayout" name="horizontalLayoutFormat">
|
||||
<property name="spacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFontComboBox" name="fontComboBox"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="fontSizeBox">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolBar" name="formatToolbar">
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonIconOnly</enum>
|
||||
</property>
|
||||
<addaction name="actionBold"/>
|
||||
<addaction name="actionItalic"/>
|
||||
<addaction name="actionUnderline"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionFontColor"/>
|
||||
<addaction name="actionBackgroundColor"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionLeftAlign"/>
|
||||
<addaction name="actionCenter"/>
|
||||
<addaction name="actionRightAlign"/>
|
||||
<addaction name="actionJustify"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionEditCondFormats"/>
|
||||
<addaction name="actionClearFormat"/>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ExtendedTableWidget" name="dataTable">
|
||||
<property name="acceptDrops">
|
||||
@@ -275,6 +343,18 @@
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonBegin">
|
||||
<property name="enabled">
|
||||
@@ -673,6 +753,186 @@
|
||||
<string>Ctrl+F</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionBold">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="icons/icons.qrc">
|
||||
<normaloff>:/icons/text_bold.png</normaloff>:/icons/text_bold.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Bold</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Bold</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+B</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionItalic">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="icons/icons.qrc">
|
||||
<normaloff>:/icons/text_italic.png</normaloff>:/icons/text_italic.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Italic</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Italic</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionUnderline">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="icons/icons.qrc">
|
||||
<normaloff>:/icons/text_underline.png</normaloff>:/icons/text_underline.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Underline</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Underline</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+U</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRightAlign">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="icons/icons.qrc">
|
||||
<normaloff>:/icons/text_align_right.png</normaloff>:/icons/text_align_right.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Align Right</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Align Right</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLeftAlign">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="icons/icons.qrc">
|
||||
<normaloff>:/icons/text_align_left.png</normaloff>:/icons/text_align_left.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Align Left</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Align Left</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCenter">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="icons/icons.qrc">
|
||||
<normaloff>:/icons/text_align_center.png</normaloff>:/icons/text_align_center.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Center Horizontally</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Center Horizontally</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionJustify">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="icons/icons.qrc">
|
||||
<normaloff>:/icons/text_align_justify.png</normaloff>:/icons/text_align_justify.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Justify</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Justify</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEditCondFormats">
|
||||
<property name="icon">
|
||||
<iconset resource="icons/icons.qrc">
|
||||
<normaloff>:/icons/edit_cond_formats</normaloff>:/icons/edit_cond_formats</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Edit Conditional Formats...</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Edit Conditional Formats...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionClearFormat">
|
||||
<property name="icon">
|
||||
<iconset resource="icons/icons.qrc">
|
||||
<normaloff>:/icons/clear_cond_formats</normaloff>:/icons/clear_cond_formats</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear Format</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Clear All Conditional Formats</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionFontColor">
|
||||
<property name="icon">
|
||||
<iconset resource="icons/icons.qrc">
|
||||
<normaloff>:/icons/foreground_color</normaloff>:/icons/foreground_color</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Font Color</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Font Color</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionBackgroundColor">
|
||||
<property name="icon">
|
||||
<iconset resource="icons/icons.qrc">
|
||||
<normaloff>:/icons/background_color</normaloff>:/icons/background_color</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Background Color</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Background Color</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionToggleFormatToolbar">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="icons/icons.qrc">
|
||||
<normaloff>:/icons/cond_formats</normaloff>:/icons/cond_formats</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Toggle Format Toolbar</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Show/hide format toolbar</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>This button shows or hides the formatting toolbar of the Data Browser</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>This button shows or hides the formatting toolbar of the Data Browser</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
||||
|
Before Width: | Height: | Size: 445 B |
@@ -80,11 +80,23 @@
|
||||
<file alias="field_fk">page_foreign_key.png</file>
|
||||
<file alias="save_all">save_all.png</file>
|
||||
<file alias="word_wrap">page_white_text.png</file>
|
||||
<file alias="cond_formats">color_swatch.png</file>
|
||||
<file alias="clear_cond_formats">clear_cond_formats.png</file>
|
||||
<file alias="edit_cond_formats">edit_cond_formats.png</file>
|
||||
<file>color_swatch.png</file>
|
||||
<file>edit_cond_formats.png</file>
|
||||
<file alias="clear_sorting">clear_sorting.png</file>
|
||||
<file alias="arrow_bottom">bullet_arrow_bottom.png</file>
|
||||
<file alias="arrow_top">bullet_arrow_top.png</file>
|
||||
<file>text_bold.png</file>
|
||||
<file>text_italic.png</file>
|
||||
<file>text_underline.png</file>
|
||||
<file>text_align_center.png</file>
|
||||
<file>text_align_justify.png</file>
|
||||
<file>text_align_left.png</file>
|
||||
<file>text_align_right.png</file>
|
||||
<file alias="background_color">page_paintbrush.png</file>
|
||||
<file alias="foreground_color">text_paintbrush.png</file>
|
||||
<file alias="cond_formats">style.png</file>
|
||||
<file alias="edit_cond_formats">style_edit.png</file>
|
||||
<file alias="clear_cond_formats">style_delete.png</file>
|
||||
<file alias="add_cond_format">style_add.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
BIN
src/icons/page_paintbrush.png
Normal file
|
After Width: | Height: | Size: 813 B |
BIN
src/icons/style.png
Normal file
|
After Width: | Height: | Size: 813 B |
BIN
src/icons/style_add.png
Normal file
|
After Width: | Height: | Size: 844 B |
BIN
src/icons/style_delete.png
Normal file
|
After Width: | Height: | Size: 865 B |
BIN
src/icons/style_edit.png
Normal file
|
After Width: | Height: | Size: 927 B |
BIN
src/icons/text_align_center.png
Normal file
|
After Width: | Height: | Size: 234 B |
BIN
src/icons/text_align_justify.png
Normal file
|
After Width: | Height: | Size: 209 B |
BIN
src/icons/text_align_left.png
Normal file
|
After Width: | Height: | Size: 209 B |
BIN
src/icons/text_align_right.png
Normal file
|
After Width: | Height: | Size: 209 B |
BIN
src/icons/text_bold.png
Normal file
|
After Width: | Height: | Size: 304 B |
BIN
src/icons/text_italic.png
Normal file
|
After Width: | Height: | Size: 223 B |
BIN
src/icons/text_paintbrush.png
Normal file
|
After Width: | Height: | Size: 880 B |
BIN
src/icons/text_underline.png
Normal file
|
After Width: | Height: | Size: 273 B |
@@ -275,13 +275,17 @@ QVariant SqliteTableModel::headerData(int section, Qt::Orientation orientation,
|
||||
return QString("%1").arg(section + 1);
|
||||
}
|
||||
|
||||
QColor SqliteTableModel::getMatchingCondFormatColor(int column, const QString& value, int role) const
|
||||
QVariant SqliteTableModel::getMatchingCondFormat(int column, const QString& value, int role) const
|
||||
{
|
||||
if (m_mCondFormats.find(column) == m_mCondFormats.end())
|
||||
return QVariant();
|
||||
|
||||
bool isNumber;
|
||||
value.toFloat(&isNumber);
|
||||
value.toDouble(&isNumber);
|
||||
QString sql;
|
||||
|
||||
// For each conditional format for this column,
|
||||
// if the condition matches the current data, return the associated colour.
|
||||
// if the condition matches the current data, return the associated format.
|
||||
for (const CondFormat& eachCondFormat : m_mCondFormats.at(column)) {
|
||||
if (isNumber && !eachCondFormat.sqlCondition().contains("'"))
|
||||
sql = QString("SELECT %1 %2").arg(value, eachCondFormat.sqlCondition());
|
||||
@@ -291,9 +295,18 @@ QColor SqliteTableModel::getMatchingCondFormatColor(int column, const QString& v
|
||||
// Empty filter means: apply format to any row.
|
||||
// Query the DB for the condition, waiting in case there is a loading in progress.
|
||||
if (eachCondFormat.filter().isEmpty() || m_db.querySingleValueFromDb(sql, false, DBBrowserDB::Wait) == "1")
|
||||
return role == Qt::ForegroundRole ? eachCondFormat.foregroundColor() : eachCondFormat.backgroundColor();
|
||||
switch (role) {
|
||||
case Qt::ForegroundRole:
|
||||
return eachCondFormat.foregroundColor();
|
||||
case Qt::BackgroundRole:
|
||||
return eachCondFormat.backgroundColor();
|
||||
case Qt::FontRole:
|
||||
return eachCondFormat.font();
|
||||
case Qt::TextAlignmentRole:
|
||||
return static_cast<int>(eachCondFormat.alignmentFlag() | Qt::AlignVCenter);
|
||||
}
|
||||
}
|
||||
return QColor();
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant SqliteTableModel::data(const QModelIndex &index, int role) const
|
||||
@@ -347,6 +360,14 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const
|
||||
QFont font;
|
||||
if(!row_available || cached_row->at(column).isNull() || nosync_isBinary(index))
|
||||
font.setItalic(true);
|
||||
else {
|
||||
QString value = cached_row->at(column);
|
||||
// Unlock before querying from DB
|
||||
lock.unlock();
|
||||
QVariant condFormatFont = getMatchingCondFormat(index.column(), value, role);
|
||||
if (condFormatFont.isValid())
|
||||
return condFormatFont;
|
||||
}
|
||||
return font;
|
||||
} else if(role == Qt::ForegroundRole) {
|
||||
if(!row_available)
|
||||
@@ -359,7 +380,7 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const
|
||||
QString value = cached_row->at(column);
|
||||
// Unlock before querying from DB
|
||||
lock.unlock();
|
||||
QColor condFormatColor = getMatchingCondFormatColor(index.column(), value, role);
|
||||
QVariant condFormatColor = getMatchingCondFormat(index.column(), value, role);
|
||||
if (condFormatColor.isValid())
|
||||
return condFormatColor;
|
||||
}
|
||||
@@ -376,7 +397,7 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const
|
||||
QString value = cached_row->at(column);
|
||||
// Unlock before querying from DB
|
||||
lock.unlock();
|
||||
QColor condFormatColor = getMatchingCondFormatColor(index.column(), value, role);
|
||||
QVariant condFormatColor = getMatchingCondFormat(index.column(), value, role);
|
||||
if (condFormatColor.isValid())
|
||||
return condFormatColor;
|
||||
}
|
||||
@@ -391,6 +412,17 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const
|
||||
.arg(QKeySequence(Qt::CTRL).toString(QKeySequence::NativeText));
|
||||
else
|
||||
return QString();
|
||||
} else if (role == Qt::TextAlignmentRole) {
|
||||
// Align horizontally according to conditional format or default (left for text and right for numbers)
|
||||
// Align vertically to the center, which displays better.
|
||||
QString value = cached_row->at(column);
|
||||
lock.unlock();
|
||||
QVariant condFormat = getMatchingCondFormat(index.column(), value, role);
|
||||
if (condFormat.isValid())
|
||||
return condFormat;
|
||||
bool isNumber;
|
||||
value.toDouble(&isNumber);
|
||||
return static_cast<int>((isNumber ? Qt::AlignRight : Qt::AlignLeft) | Qt::AlignVCenter);
|
||||
} else if(role == Qt::DecorationRole) {
|
||||
if(!row_available)
|
||||
return QVariant();
|
||||
@@ -403,6 +435,7 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
@@ -802,7 +835,15 @@ std::vector<std::string> SqliteTableModel::getColumns(std::shared_ptr<sqlite3> p
|
||||
|
||||
void SqliteTableModel::addCondFormat(int column, const CondFormat& condFormat)
|
||||
{
|
||||
m_mCondFormats[column].push_back(condFormat);
|
||||
// If the condition is already present in the vector, update that entry and respect the order, since two entries with the same
|
||||
// condition do not make sense.
|
||||
auto it = std::find_if(m_mCondFormats[column].begin(), m_mCondFormats[column].end(), [condFormat](const CondFormat& format) {
|
||||
return format.sqlCondition() == condFormat.sqlCondition();
|
||||
});
|
||||
if(it != m_mCondFormats[column].end()) {
|
||||
*it = condFormat;
|
||||
} else
|
||||
m_mCondFormats[column].push_back(condFormat);
|
||||
emit layoutChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QMutex>
|
||||
#include <QColor>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
@@ -163,9 +163,9 @@ private:
|
||||
QByteArray encode(const QByteArray& str) const;
|
||||
QByteArray decode(const QByteArray& str) const;
|
||||
|
||||
// Return matching conditional format color or invalid color, otherwise.
|
||||
// Only Qt::ForegroundRole and Qt::BackgroundRole are expected in role (Qt::ItemDataRole)
|
||||
QColor getMatchingCondFormatColor(int column, const QString& value, int role) const;
|
||||
// Return matching conditional format color/font or invalid value, otherwise.
|
||||
// Only format roles are expected in role (Qt::ItemDataRole)
|
||||
QVariant getMatchingCondFormat(int column, const QString& value, int role) const;
|
||||
|
||||
DBBrowserDB& m_db;
|
||||
|
||||
|
||||