2018-10-17 07:55:53 +00:00
|
|
|
#include "common/Helpers.h"
|
2019-04-27 17:58:44 +00:00
|
|
|
#include "Configuration.h"
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2018-02-04 17:27:48 +00:00
|
|
|
#include <cmath>
|
2017-04-05 08:56:59 +00:00
|
|
|
#include <QPlainTextEdit>
|
|
|
|
#include <QTextEdit>
|
2017-04-18 10:03:47 +00:00
|
|
|
#include <QFileInfo>
|
2018-02-04 17:27:48 +00:00
|
|
|
#include <QtCore>
|
2017-04-18 10:03:47 +00:00
|
|
|
#include <QCryptographicHash>
|
2017-04-13 15:04:30 +00:00
|
|
|
#include <QTreeWidget>
|
|
|
|
#include <QString>
|
|
|
|
#include <QAbstractItemView>
|
2017-10-01 14:36:40 +00:00
|
|
|
#include <QAbstractButton>
|
2017-11-03 17:22:54 +00:00
|
|
|
#include <QDockWidget>
|
2019-09-25 14:18:30 +00:00
|
|
|
#include <QMenu>
|
2017-04-05 08:56:59 +00:00
|
|
|
|
2017-04-13 15:04:30 +00:00
|
|
|
static QAbstractItemView::ScrollMode scrollMode()
|
2017-03-29 10:18:37 +00:00
|
|
|
{
|
2017-04-13 15:04:30 +00:00
|
|
|
const bool use_scrollperpixel = true;
|
|
|
|
return use_scrollperpixel ? QAbstractItemView::ScrollPerPixel : QAbstractItemView::ScrollPerItem;
|
|
|
|
}
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2017-04-13 15:04:30 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
namespace qhelpers {
|
|
|
|
|
|
|
|
QString formatBytecount(const long bytecount)
|
2017-04-13 15:04:30 +00:00
|
|
|
{
|
2018-03-21 20:32:32 +00:00
|
|
|
if (bytecount == 0)
|
|
|
|
return "0";
|
|
|
|
const int exp = log(bytecount) / log(1000);
|
|
|
|
constexpr char suffixes[] = {' ', 'k', 'M', 'G', 'T', 'P', 'E'};
|
|
|
|
|
|
|
|
QString str;
|
|
|
|
QTextStream stream(&str);
|
|
|
|
stream << qSetRealNumberPrecision(3) << bytecount / pow(1000, exp)
|
|
|
|
<< ' ' << suffixes[exp] << 'B';
|
|
|
|
return stream.readAll();
|
|
|
|
}
|
2018-02-04 17:27:48 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
void adjustColumns(QTreeView *tv, int columnCount, int padding)
|
|
|
|
{
|
|
|
|
for (int i = 0; i != columnCount; ++i) {
|
|
|
|
tv->resizeColumnToContents(i);
|
|
|
|
if (padding > 0) {
|
|
|
|
int width = tv->columnWidth(i);
|
|
|
|
tv->setColumnWidth(i, width + padding);
|
2017-04-13 15:04:30 +00:00
|
|
|
}
|
|
|
|
}
|
2018-03-21 20:32:32 +00:00
|
|
|
}
|
2017-04-13 15:04:30 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
void adjustColumns(QTreeWidget *tw, int padding)
|
|
|
|
{
|
|
|
|
adjustColumns(tw, tw->columnCount(), padding);
|
|
|
|
}
|
2017-11-03 17:22:54 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
QTreeWidgetItem *appendRow(QTreeWidget *tw, const QString &str, const QString &str2,
|
|
|
|
const QString &str3, const QString &str4, const QString &str5)
|
|
|
|
{
|
|
|
|
QTreeWidgetItem *tempItem = new QTreeWidgetItem();
|
|
|
|
// Fill dummy hidden column
|
|
|
|
tempItem->setText(0, "0");
|
|
|
|
tempItem->setText(1, str);
|
|
|
|
if (!str2.isNull())
|
|
|
|
tempItem->setText(2, str2);
|
|
|
|
if (!str3.isNull())
|
|
|
|
tempItem->setText(3, str3);
|
|
|
|
if (!str4.isNull())
|
|
|
|
tempItem->setText(4, str4);
|
|
|
|
if (!str5.isNull())
|
|
|
|
tempItem->setText(5, str5);
|
|
|
|
|
|
|
|
tw->insertTopLevelItem(0, tempItem);
|
|
|
|
|
|
|
|
return tempItem;
|
|
|
|
}
|
2017-11-03 17:22:54 +00:00
|
|
|
|
2019-03-27 20:40:54 +00:00
|
|
|
/**
|
|
|
|
* @brief select first item of QTreeWidget if tree is not empty.
|
|
|
|
* @param tw - QTreeWidget instance
|
|
|
|
* @return true - setCurrentItem was set, false - tree is empty
|
|
|
|
*/
|
2019-09-01 21:30:25 +00:00
|
|
|
bool selectFirstItem(QTreeWidget *tw)
|
2019-03-27 20:40:54 +00:00
|
|
|
{
|
|
|
|
if (tw->topLevelItem(0)) {
|
|
|
|
tw->setCurrentItem(tw->topLevelItem(0));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-09-01 21:30:25 +00:00
|
|
|
|
|
|
|
bool selectFirstItem(QAbstractItemView *itemView)
|
|
|
|
{
|
|
|
|
auto selectionModel = itemView->selectionModel();
|
|
|
|
auto model = itemView->model();
|
|
|
|
if (model->hasChildren()) {
|
|
|
|
selectionModel->setCurrentIndex(model->index(0, 0), QItemSelectionModel::SelectCurrent);
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
void setVerticalScrollMode(QAbstractItemView *tw)
|
|
|
|
{
|
|
|
|
tw->setVerticalScrollMode(scrollMode());
|
|
|
|
}
|
2017-11-03 17:22:54 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
void setCheckedWithoutSignals(QAbstractButton *button, bool checked)
|
|
|
|
{
|
|
|
|
bool blocked = button->signalsBlocked();
|
|
|
|
button->blockSignals(true);
|
|
|
|
button->setChecked(checked);
|
|
|
|
button->blockSignals(blocked);
|
|
|
|
}
|
2017-11-03 17:22:54 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
SizePolicyMinMax forceWidth(QWidget *widget, int width)
|
|
|
|
{
|
|
|
|
SizePolicyMinMax r;
|
|
|
|
r.sizePolicy = widget->sizePolicy();
|
|
|
|
r.min = widget->minimumWidth();
|
|
|
|
r.max = widget->maximumWidth();
|
|
|
|
|
|
|
|
QSizePolicy sizePolicy = r.sizePolicy;
|
|
|
|
sizePolicy.setHorizontalPolicy(QSizePolicy::Fixed);
|
|
|
|
widget->setSizePolicy(sizePolicy);
|
|
|
|
widget->setMinimumWidth(width);
|
|
|
|
widget->setMaximumWidth(width);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
2017-11-03 17:22:54 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
SizePolicyMinMax forceHeight(QWidget *widget, int height)
|
|
|
|
{
|
|
|
|
SizePolicyMinMax r;
|
|
|
|
r.sizePolicy = widget->sizePolicy();
|
|
|
|
r.min = widget->minimumHeight();
|
|
|
|
r.max = widget->maximumHeight();
|
|
|
|
|
|
|
|
QSizePolicy sizePolicy = r.sizePolicy;
|
|
|
|
sizePolicy.setVerticalPolicy(QSizePolicy::Fixed);
|
|
|
|
widget->setSizePolicy(sizePolicy);
|
|
|
|
widget->setMinimumHeight(height);
|
|
|
|
widget->setMaximumHeight(height);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
2017-11-03 17:22:54 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
void SizePolicyMinMax::restoreWidth(QWidget *widget)
|
|
|
|
{
|
|
|
|
widget->setSizePolicy(sizePolicy);
|
|
|
|
widget->setMinimumWidth(min);
|
|
|
|
widget->setMaximumWidth(max);
|
|
|
|
}
|
2017-11-03 17:22:54 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
void SizePolicyMinMax::restoreHeight(QWidget *widget)
|
|
|
|
{
|
|
|
|
widget->setSizePolicy(sizePolicy);
|
|
|
|
widget->setMinimumHeight(min);
|
|
|
|
widget->setMaximumHeight(max);
|
|
|
|
}
|
2017-11-15 21:56:10 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
int getMaxFullyDisplayedLines(QTextEdit *textEdit)
|
|
|
|
{
|
|
|
|
QFontMetrics fontMetrics(textEdit->document()->defaultFont());
|
|
|
|
return (textEdit->height()
|
|
|
|
- (textEdit->contentsMargins().top()
|
|
|
|
+ textEdit->contentsMargins().bottom()
|
|
|
|
+ (int)(textEdit->document()->documentMargin() * 2)))
|
|
|
|
/ fontMetrics.lineSpacing();
|
|
|
|
}
|
2017-11-15 21:56:10 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
int getMaxFullyDisplayedLines(QPlainTextEdit *plainTextEdit)
|
|
|
|
{
|
|
|
|
QFontMetrics fontMetrics(plainTextEdit->document()->defaultFont());
|
|
|
|
return (plainTextEdit->height()
|
|
|
|
- (plainTextEdit->contentsMargins().top()
|
|
|
|
+ plainTextEdit->contentsMargins().bottom()
|
|
|
|
+ (int)(plainTextEdit->document()->documentMargin() * 2)))
|
|
|
|
/ fontMetrics.lineSpacing();
|
|
|
|
}
|
2017-12-03 14:46:22 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
QByteArray applyColorToSvg(const QByteArray &data, QColor color)
|
|
|
|
{
|
|
|
|
static const QRegularExpression styleRegExp("(?:style=\".*fill:(.*?);.*?\")|(?:fill=\"(.*?)\")");
|
2017-12-03 14:46:22 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
QString replaceStr = QString("#%1").arg(color.rgb() & 0xffffff, 6, 16, QLatin1Char('0'));
|
|
|
|
int replaceStrLen = replaceStr.length();
|
2017-12-03 14:46:22 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
QString xml = QString::fromUtf8(data);
|
2017-12-03 14:46:22 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
int offset = 0;
|
|
|
|
while (true) {
|
|
|
|
QRegularExpressionMatch match = styleRegExp.match(xml, offset);
|
|
|
|
if (!match.hasMatch()) {
|
|
|
|
break;
|
2017-12-03 14:46:22 +00:00
|
|
|
}
|
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
int captureIndex = match.captured(1).isNull() ? 2 : 1;
|
|
|
|
xml.replace(match.capturedStart(captureIndex), match.capturedLength(captureIndex), replaceStr);
|
|
|
|
offset = match.capturedStart(captureIndex) + replaceStrLen;
|
2017-12-03 14:46:22 +00:00
|
|
|
}
|
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
return xml.toUtf8();
|
|
|
|
}
|
2017-12-03 16:26:01 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
QByteArray applyColorToSvg(const QString &filename, QColor color)
|
|
|
|
{
|
|
|
|
QFile file(filename);
|
|
|
|
file.open(QIODevice::ReadOnly);
|
|
|
|
|
|
|
|
return applyColorToSvg(file.readAll(), color);
|
|
|
|
}
|
2017-12-03 16:26:01 +00:00
|
|
|
|
2019-04-27 17:58:44 +00:00
|
|
|
/**
|
|
|
|
* @brief finds the theme-specific icon path and calls `setter` functor providing a pointer of an object which has to be used
|
|
|
|
* and loaded icon
|
|
|
|
* @param supportedIconsNames list of <object ptr, icon name>
|
|
|
|
* @param setter functor which has to be called
|
|
|
|
* for example we need to set an action icon, the functor can be just [](void* o, const QIcon &icon) { static_cast<QAction*>(o)->setIcon(icon); }
|
|
|
|
*/
|
2019-09-01 21:30:25 +00:00
|
|
|
void setThemeIcons(QList<QPair<void *, QString>> supportedIconsNames,
|
|
|
|
std::function<void(void *, const QIcon &)> setter)
|
2019-04-27 17:58:44 +00:00
|
|
|
{
|
|
|
|
if (supportedIconsNames.isEmpty() || !setter) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QString &iconsDirPath = QStringLiteral(":/img/icons/");
|
|
|
|
const QString &currTheme = Config()->getCurrentTheme()->name;
|
|
|
|
const QString &relativeThemeDir = currTheme.toLower() + "/";
|
|
|
|
QString iconPath;
|
|
|
|
|
|
|
|
foreach (const auto &p, supportedIconsNames) {
|
|
|
|
iconPath = iconsDirPath;
|
|
|
|
// Verify that indeed there is an alternative icon in this theme
|
|
|
|
// Otherwise, fallback to the regular icon folder
|
|
|
|
if (QFile::exists(iconPath + relativeThemeDir + p.second)) {
|
|
|
|
iconPath += relativeThemeDir;
|
|
|
|
}
|
|
|
|
setter(p.first, QIcon(iconPath + p.second));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-25 14:18:30 +00:00
|
|
|
void prependQAction(QAction *action, QMenu *menu)
|
|
|
|
{
|
|
|
|
auto actions = menu->actions();
|
|
|
|
if (actions.empty()) {
|
|
|
|
menu->addAction(action);
|
|
|
|
} else {
|
|
|
|
menu->insertAction(actions.first(), action);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-05 08:56:59 +00:00
|
|
|
} // end namespace
|