Пример #1
0
    //______________________________________________________________
    void TileSet::initPixmap( PixmapList& pixmaps, const QPixmap &source, int width, int height, const QRect &rect)
    {
        QSize size( width, height );
        if( !( size.isValid() && rect.isValid() ) )
        {
            pixmaps.append( QPixmap() );

        } else if( size != rect.size() ) {

            const qreal dpiRatio( devicePixelRatio( source ) );
            const QRect scaledRect( rect.topLeft()*dpiRatio, rect.size()*dpiRatio );
            const QSize scaledSize( size*dpiRatio );
            const QPixmap tile( source.copy(scaledRect) );
            QPixmap pixmap( scaledSize );

            pixmap.fill(Qt::transparent);
            QPainter painter(&pixmap);
            painter.drawTiledPixmap(0, 0, scaledSize.width(), scaledSize.height(), tile);
            setDevicePixelRatio( pixmap, dpiRatio );
            pixmaps.append( pixmap );

        } else {

            const qreal dpiRatio( devicePixelRatio( source ) );
            const QRect scaledRect( rect.topLeft()*dpiRatio, rect.size()*dpiRatio );
            QPixmap pixmap( source.copy( scaledRect ) );
            setDevicePixelRatio( pixmap, dpiRatio );
            pixmaps.append( pixmap );

        }

    }
Пример #2
0
void CustomHeader::addSection(const QString &txt,
                              const QString &tooltipTxt,
                              QuestionMarkHint questionMark,
                              ClickLabel::HeaderData headerData)
{
    auto headerTextLabel = new QLabel;
    headerTextLabel->setText(txt);
    headerTextLabel->setToolTip(tooltipTxt);

    layout->addWidget(headerTextLabel, layout->rowCount(), 0);

    if (questionMark == QuestionMarkHint::QuestionMark)
    {
        auto questionMarkLabel = new ClickLabel;

        auto pixmap_2x = QPixmap(QStringLiteral(":/icons/qm-enabled"));
#if defined(Q_OS_MAC)
        pixmap_2x.setDevicePixelRatio(2.0);
#endif
        questionMarkLabel->setPixmap(pixmap_2x);
        questionMarkLabel->setHeaderData(headerData);
//        questionMarkLabel->setObjectName(QStringLiteral("questionMarkImg"));
        connect(questionMarkLabel, &ClickLabel::clicked,
                this, &CustomHeader::onlineHelpTrigger);

        layout->addWidget(questionMarkLabel, layout->rowCount() - 1, 1);
    }
}
Пример #3
0
QQuickWebEngineViewPrivate::QQuickWebEngineViewPrivate()
    : adapter(new WebContentsAdapter)
    , e(new QQuickWebEngineViewExperimental(this))
    , v(new QQuickWebEngineViewport(this))
    , m_history(new QQuickWebEngineHistory(this))
    , m_settings(new QQuickWebEngineSettings)
    , contextMenuExtraItems(0)
    , loadProgress(0)
    , inspectable(false)
    , m_isFullScreen(false)
    , isLoading(false)
    , devicePixelRatio(QGuiApplication::primaryScreen()->devicePixelRatio())
    , m_dpiScale(1.0)
{
    // The gold standard for mobile web content is 160 dpi, and the devicePixelRatio expected
    // is the (possibly quantized) ratio of device dpi to 160 dpi.
    // However GUI toolkits on non-iOS platforms may be using different criteria than relative
    // DPI (depending on the history of that platform), dictating the choice of
    // QScreen::devicePixelRatio().
    // Where applicable (i.e. non-iOS mobile platforms), override QScreen::devicePixelRatio
    // and instead use a reasonable default value for viewport.devicePixelRatio to avoid every
    // app having to use this experimental API.
    QString platform = qApp->platformName().toLower();
    if (platform == QLatin1String("qnx")) {
        qreal webPixelRatio = QGuiApplication::primaryScreen()->physicalDotsPerInch() / 160;

        // Quantize devicePixelRatio to increments of 1 to allow JS and media queries to select
        // 1x, 2x, 3x etc assets that fit an integral number of pixels.
        setDevicePixelRatio(qMax(1, qRound(webPixelRatio)));
    }
    QAccessible::installFactory(&webAccessibleFactory);
}
Пример #4
0
QPixmap SendButton::grabContent() {
	auto result = QImage(kWideScale * size() * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
	result.setDevicePixelRatio(cRetinaFactor());
	result.fill(Qt::transparent);
	{
		Painter p(&result);
		p.drawPixmap((kWideScale - 1) / 2 * width(), (kWideScale - 1) / 2 * height(), myGrab(this));
	}
	return App::pixmapFromImageInPlace(std::move(result));
}
Пример #5
0
QMLProfile::QMLProfile(QQuickItem *parent) :
	QQuickPaintedItem(parent),
	m_devicePixelRatio(1.0),
	m_margin(0)
{
	setAntialiasing(true);
	m_profileWidget = new ProfileWidget2(0);
	m_profileWidget->setProfileState();
	m_profileWidget->setPrintMode(true);
	m_profileWidget->setFontPrintScale(0.8);
	connect(QMLManager::instance(), &QMLManager::sendScreenChanged, this, &QMLProfile::screenChanged);
	setDevicePixelRatio(QMLManager::instance()->lastDevicePixelRatio());
}
Пример #6
0
QPixmap PeerData::genUserpicRounded(int size) const {
	if (auto userpic = currentUserpic()) {
		return userpic->pixRounded(size, size, ImageRoundRadius::Small);
	}
	auto result = QImage(QSize(size, size) * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
	result.setDevicePixelRatio(cRetinaFactor());
	result.fill(Qt::transparent);
	{
		Painter p(&result);
		paintUserpicRounded(p, 0, 0, size);
	}
	return App::pixmapFromImageInPlace(std::move(result));
}
Пример #7
0
void Float::prepareShadow() {
	auto shadow = QImage(size() * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
	shadow.fill(Qt::transparent);
	shadow.setDevicePixelRatio(cRetinaFactor());
	{
		Painter p(&shadow);
		PainterHighQualityEnabler hq(p);
		p.setPen(Qt::NoPen);
		p.setBrush(st::shadowFg);
		auto extend = 2 * st::lineWidth;
		p.drawEllipse(getInnerRect().marginsAdded(QMargins(extend, extend, extend, extend)));
	}
	_shadow = App::pixmapFromImageInPlace(Images::prepareBlur(std::move(shadow)));
}
Пример #8
0
QImage RippleAnimation::maskByDrawer(QSize size, bool filled, Fn<void(QPainter &p)> drawer) {
	auto result = QImage(size * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
	result.setDevicePixelRatio(cRetinaFactor());
	result.fill(filled ? QColor(255, 255, 255) : Qt::transparent);
	if (drawer) {
		Painter p(&result);
		PainterHighQualityEnabler hq(p);

		p.setPen(Qt::NoPen);
		p.setBrush(QColor(255, 255, 255));
		drawer(p);
	}
	return result;
}
Пример #9
0
QImage InnerDropdown::grabForPanelAnimation() {
	SendPendingMoveResizeEvents(this);
	auto result = QImage(size() * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
	result.setDevicePixelRatio(cRetinaFactor());
	result.fill(Qt::transparent);
	{
		Painter p(&result);
		App::roundRect(p, rect().marginsRemoved(_st.padding), _st.bg, ImageRoundRadius::Small);
		for (const auto child : children()) {
			if (const auto widget = qobject_cast<QWidget*>(child)) {
				RenderWidget(p, widget, widget->pos());
			}
		}
	}
	return result;
}
Пример #10
0
void RoundImageCheckbox::prepareWideCheckIconCache(Icon *icon) {
	auto cacheWidth = _wideCheckBgCache.width() / _wideCheckBgCache.devicePixelRatio();
	auto cacheHeight = _wideCheckBgCache.height() / _wideCheckBgCache.devicePixelRatio();
	auto wideCache = QImage(cacheWidth * cIntRetinaFactor(), cacheHeight * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
	wideCache.setDevicePixelRatio(cRetinaFactor());
	{
		Painter p(&wideCache);
		p.setCompositionMode(QPainter::CompositionMode_Source);
		auto iconRadius = kWideScale * _st.checkRadius;
		auto divider = qRound((kWideScale - 2) * _st.checkRadius + icon->fadeIn.current(1.) * (kWideScale - 1) * _st.checkRadius);
		p.drawPixmapLeft(QRect(0, 0, divider, iconRadius * 2), cacheWidth, _wideCheckFullCache, QRect(0, 0, divider * cIntRetinaFactor(), _wideCheckFullCache.height()));
		p.drawPixmapLeft(QRect(divider, 0, iconRadius * 2 - divider, iconRadius * 2), cacheWidth, _wideCheckBgCache, QRect(divider * cIntRetinaFactor(), 0, _wideCheckBgCache.width() - divider * cIntRetinaFactor(), _wideCheckBgCache.height()));
	}
	icon->wideCheckCache = App::pixmapFromImageInPlace(std_::move(wideCache));
	icon->wideCheckCache.setDevicePixelRatio(cRetinaFactor());
}
Пример #11
0
QImage InnerDropdown::grabForPanelAnimation() {
	myEnsureResized(this);
	auto result = QImage(size() * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
	result.setDevicePixelRatio(cRetinaFactor());
	result.fill(Qt::transparent);
	{
		Painter p(&result);
		App::roundRect(p, rect().marginsRemoved(_st.padding), _st.bg, ImageRoundRadius::Small);
		for (auto child : children()) {
			if (auto widget = qobject_cast<QWidget*>(child)) {
				widget->render(&p, widget->pos(), widget->rect(), QWidget::DrawChildren | QWidget::IgnoreMask);
			}
		}
	}
	return std_::move(result);
}
Пример #12
0
void LocationManager::init() {
	if (manager) delete manager;
	manager = new QNetworkAccessManager();
	App::setProxySettings(*manager);

	connect(manager, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), this, SLOT(onFailed(QNetworkReply*)));
#ifndef OS_MAC_OLD
	connect(manager, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)), this, SLOT(onFailed(QNetworkReply*)));
#endif // OS_MAC_OLD
	connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*)));

	if (notLoadedPlaceholder) {
		delete notLoadedPlaceholder->v();
		delete notLoadedPlaceholder;
	}
	auto data = QImage(cIntRetinaFactor(), cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
	data.fill(st::white->c);
	data.setDevicePixelRatio(cRetinaFactor());
	notLoadedPlaceholder = new ImagePtr(App::pixmapFromImageInPlace(std_::move(data)), "GIF");
}
Пример #13
0
QImage PopupMenu::grabForPanelAnimation() {
	myEnsureResized(this);
	auto result = QImage(size() * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
	result.setDevicePixelRatio(cRetinaFactor());
	result.fill(Qt::transparent);
	{
		Painter p(&result);
		if (_useTransparency) {
			App::roundRect(p, _inner, _st.menu.itemBg, ImageRoundRadius::Small);
		} else {
			p.fillRect(_inner, _st.menu.itemBg);
		}
		for (auto child : children()) {
			if (auto widget = qobject_cast<QWidget*>(child)) {
				widget->render(&p, widget->pos(), widget->rect(), QWidget::DrawChildren | QWidget::IgnoreMask);
			}
		}
	}
	return result;
}
Пример #14
0
    void PictureWidget::setImage(const QPixmap& _pixmap, int radius)
    {
        pixmapToDraw_ = _pixmap;

        if (radius != -1)
        {
            auto borderPixmap = QPixmap(pixmapToDraw_.size());
            borderPixmap.fill(Qt::transparent);
            QPainter pixPainter(&borderPixmap);
            pixPainter.setBrush(pixmapToDraw_);
            pixPainter.setPen(Qt::transparent);
            pixPainter.setRenderHint(QPainter::Antialiasing);
            pixPainter.drawRoundedRect(0, 0, pixmapToDraw_.width(), pixmapToDraw_.height(), radius, radius);
            Utils::check_pixel_ratio(pixmapToDraw_);
            borderPixmap.setDevicePixelRatio(pixmapToDraw_.devicePixelRatio());
            pixmapToDraw_ = std::move(borderPixmap);
        }

        update();
    }
Пример #15
0
QPixmap Shadow::grab(
		not_null<TWidget*> target,
		const style::Shadow &shadow,
		RectParts sides) {
	SendPendingMoveResizeEvents(target);
	auto rect = target->rect();
	auto extend = QMargins(
		(sides & RectPart::Left) ? shadow.extend.left() : 0,
		(sides & RectPart::Top) ? shadow.extend.top() : 0,
		(sides & RectPart::Right) ? shadow.extend.right() : 0,
		(sides & RectPart::Bottom) ? shadow.extend.bottom() : 0
	);
	auto full = QRect(0, 0, extend.left() + rect.width() + extend.right(), extend.top() + rect.height() + extend.bottom());
	auto result = QPixmap(full.size() * cIntRetinaFactor());
	result.setDevicePixelRatio(cRetinaFactor());
	result.fill(Qt::transparent);
	{
		Painter p(&result);
		Ui::Shadow::paint(p, full.marginsRemoved(extend), full.width(), shadow);
		RenderWidget(p, target, QPoint(extend.left(), extend.top()));
	}
	return result;
}
Пример #16
0
QPixmap FadeAnimation::grabContent() {
	SendPendingMoveResizeEvents(_widget);
	_size = _widget->size();
	if (_size.isEmpty()) {
		auto image = QImage(
			cIntRetinaFactor(),
			cIntRetinaFactor(),
			QImage::Format_ARGB32_Premultiplied);
		image.fill(Qt::transparent);
		return App::pixmapFromImageInPlace(std::move(image));
	}
	auto widgetContent = GrabWidget(_widget);
	if (_scale < 1.) {
		auto result = QImage(kWideScale * _size * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
		result.setDevicePixelRatio(cRetinaFactor());
		result.fill(Qt::transparent);
		{
			Painter p(&result);
			p.drawPixmap((kWideScale - 1) / 2 * _size.width(), (kWideScale - 1) / 2 * _size.height(), widgetContent);
		}
		return App::pixmapFromImageInPlace(std::move(result));
	}
	return widgetContent;
}
Пример #17
0
TimeLagSettingsDialog::TimeLagSettingsDialog(QWidget *parent, EcProject *ecProject, ConfigState* config) :
    QDialog(parent),
    ecProject_(ecProject),
    configState_(config)
{
    setWindowModality(Qt::WindowModal);
    setWindowTitle(tr("Time Lag Optimization Settings"));
    WidgetUtils::removeContextHelpButton(this);

    auto groupTitle = new QLabel;
    groupTitle->setText(tr("Configure smart time lag detection, "
                           "providing quality selection criteria and initial "
                           "time lag windows"));

    auto hrLabel = new QLabel;
    hrLabel->setObjectName(QStringLiteral("hrLabel"));

    existingRadio = new QRadioButton(tr("Time lag file available : "));
    existingRadio->setToolTip(tr("<b>Time lag file available:</b> If you have a satisfactory time lag assessment from a previous run and it applies to the current dataset, you can use it by providing the path to the file 'eddypro_timelag_opt_ID.txt' that was generated by EddyPro in the previous run and contains the results of the assessment. This will shorten program execution time and assure full comparability between the current and previous results."));

    nonExistingRadio = new QRadioButton(tr("Time lag file not available :"));
    nonExistingRadio->setToolTip(tr("<b>Time lag file not available:</b> Choose this option and provide the following information if you need to optimize time lags for your dataset. EddyPro will complete the time lag optimization first and then complete the raw data processing and flux computation procedures."));

    subsetCheckBox = new QCheckBox;
    subsetCheckBox->setProperty("subperiod", true);
    subsetCheckBox->setText(tr("Select a different period"));
    subsetCheckBox->setToolTip(tr("<b>Select a different period:</b> Select this option and set the corresponding dates, to identify the time period EddyPro will use for the Time lag optimization. This subperiod must fall within the time period defined by the available raw data."));

    startDateLabel = new ClickLabel(this);
    startDateLabel->setText(tr("Start :"));
    startDateLabel->setToolTip(tr("<b>Start:</b> Starting date of the time period to be used for time lag optimization. This time should not be shorter than about 1-2 months. As a general recommendation, select a time period during which the instrument setup did not undergo major modifications. Results obtained using a given time period (e.g., 2 months) can be used for processing a longer time period, in which major modifications did not occur in the setup. The stricter the threshold setup in this dialogue, the longer the period should be in order to get robust results."));
    startDateEdit = new QDateEdit;
    startDateEdit->setToolTip(startDateLabel->toolTip());
    startDateEdit->setCalendarPopup(true);
    WidgetUtils::customizeCalendar(startDateEdit->calendarWidget());

    startTimeEdit = new QTimeEdit;
    startTimeEdit->setDisplayFormat(QStringLiteral("hh:mm"));
    startTimeEdit->setAccelerated(true);

    lockedIcon = new QLabel;
    auto pixmap = QPixmap(QStringLiteral(":/icons/vlink-locked"));
#if defined(Q_OS_MAC)
    pixmap.setDevicePixelRatio(2.0);
#endif
    lockedIcon->setPixmap(pixmap);

    endDateLabel = new ClickLabel(this);
    endDateLabel->setText(tr("End :"));
    endDateLabel->setToolTip(tr("<b>End:</b> End date of the time period to be used for time lag optimization. This time should not be shorter than about 1-2 months As a general recommendation, select a time period during which the instrumental setup did not undergo major modifications. Results obtained using a given time period (e.g., 2 months) can be used for processing a longer time period, in which major modifications did not occur in the setup. The stricter the threshold setup in this dialogue, the longer the period should be in order to get robust results."));
    endDateEdit = new QDateEdit;
    endDateEdit->setToolTip(endDateLabel->toolTip());
    endDateEdit->setCalendarPopup(true);
    WidgetUtils::customizeCalendar(endDateEdit->calendarWidget());

    endTimeEdit = new QTimeEdit;
    endTimeEdit->setDisplayFormat(QStringLiteral("hh:mm"));
    endTimeEdit->setAccelerated(true);

    auto dateTimeContainer = new QGridLayout;
    dateTimeContainer->addWidget(startDateEdit, 0, 1);
    dateTimeContainer->addWidget(startTimeEdit, 0, 2);
    dateTimeContainer->addWidget(lockedIcon, 0, 0, 2, 1);
    dateTimeContainer->addWidget(endDateEdit, 1, 1);
    dateTimeContainer->addWidget(endTimeEdit, 1, 2);
    dateTimeContainer->setColumnStretch(1, 1);
    dateTimeContainer->setColumnStretch(2, 1);
    dateTimeContainer->setColumnStretch(3, 2);
    dateTimeContainer->setContentsMargins(0, 0, 0, 0);
    dateTimeContainer->setVerticalSpacing(3);

    fileBrowse = new FileBrowseWidget;
    fileBrowse->setToolTip(tr("<b>Load:</b> Load an existing time lag file"));
    fileBrowse->setDialogTitle(tr("Select the Time Lag Optimization File"));
    fileBrowse->setDialogWorkingDir(WidgetUtils::getSearchPathHint());
    fileBrowse->setDialogFilter(tr("All Files (*.*)"));

    auto existingFileLayout = new QHBoxLayout;
    existingFileLayout->addWidget(existingRadio);
    existingFileLayout->addWidget(fileBrowse);
    existingFileLayout->setStretch(2, 1);
    existingFileLayout->setContentsMargins(0, 0, 0, 0);
    existingFileLayout->setSpacing(0);

    radioGroup = new QButtonGroup(this);
    radioGroup->addButton(existingRadio, 0);
    radioGroup->addButton(nonExistingRadio, 1);

    h2oTitleLabel = WidgetUtils::createBlueLabel(this, tr("Water vapor time lag as a function of relative humidity"));

    pgRangeLabel = new ClickLabel(tr("Plausibility range around median value :"));
    pgRangeLabel->setToolTip(tr("<b>Plausibility range around median value:</b> The plausibility range is defined as the median time lag, %1 <i>n</i> times the MAD (median of the absolute deviations from the median time lag). Specify <i>n</i> here. The value of 1.5 was heuristically found to be optimal.").arg(Defs::PLUSMINUS));
    pgRangeSpin = new QDoubleSpinBox;
    pgRangeSpin->setDecimals(1);
    pgRangeSpin->setRange(0.1, 100.0);
    pgRangeSpin->setSingleStep(0.1);
    pgRangeSpin->setAccelerated(true);
    pgRangeSpin->setSuffix(tr("  [mad]"));
    pgRangeSpin->setToolTip(pgRangeLabel->toolTip());
    pgRangeLabel_2 = new QLabel(tr("(<tt>%1%2n%3mad</tt>, where you set <tt>n</tt>)").arg(Defs::MICRO, Defs::PLUSMINUS, Defs::MID_DOT));

    rhClassLabel = new ClickLabel(tr("Number of RH classes :"));
    rhClassLabel->setToolTip(tr("<b>Number of RH classes:</b> Select the number or relative humidity classes, to assess water vapor time lag as a function of RH. The whole range or RH variation (0-100%) will be evenly divided according to the selected number of classes. For example, selecting 10 classes causes EddyPro to assess water vapor time lags for the classes 0-10%, 10-20%,..., 90-100%. Selecting 1 class, the label <b><i>Do not sort in RH classes</i></b> appears and will cause EddyPro to treat water vapor exactly like other passive gases. This option is only suitable for open path systems, or closed path systems with short and heated sampling lines."));

    rhClassSpin = new QSpinBox;
    rhClassSpin->setRange(1, 20);
    rhClassSpin->setSingleStep(1);
    rhClassSpin->setAccelerated(true);
    rhClassSpin->setSpecialValueText(tr("Do not sort in RH classes"));
    rhClassSpin->setToolTip(rhClassLabel->toolTip());

    gasTitleLabel = WidgetUtils::createBlueLabel(this, tr("Passive gases"));

    co2MinFluxLabel = new ClickLabel(tr("Minimum (absolute) %1 flux :").arg(Defs::CO2_STRING));
    co2MinFluxLabel->setToolTip(tr("<b>Minimum (absolute) %1 flux:</b> %1 time lags corresponding to fluxes smaller (in module) than this value will not be considered in the time lag optimization. Selecting high-enough fluxes assures that well developed turbulent conditions are met and the correlation function is well characterized.").arg(Defs::CO2_STRING));
    co2MinFluxSpin = new QDoubleSpinBox;
    co2MinFluxSpin->setDecimals(3);
    co2MinFluxSpin->setRange(0.0, 100.0);
    co2MinFluxSpin->setSingleStep(0.001);
    co2MinFluxSpin->setAccelerated(true);
    co2MinFluxSpin->setSuffix(tr("  [%1]").arg(Defs::UMOL_M2S_STRING));
    co2MinFluxSpin->setToolTip(co2MinFluxLabel->toolTip());

    ch4MinFluxLabel = new ClickLabel(tr("Minimum (absolute) %1 flux :").arg(Defs::CH4_STRING));
    ch4MinFluxLabel->setToolTip(tr("<b>Minimum (absolute) %1 flux:</b> %1 time lags corresponding to fluxes smaller (in module) than this value will not be considered in the time lag optimization. Selecting high-enough fluxes assures that well developed turbulent conditions are met and the correlation function is well characterized.").arg(Defs::CH4_STRING));
    ch4MinFluxSpin = new QDoubleSpinBox;
    ch4MinFluxSpin->setDecimals(3);
    ch4MinFluxSpin->setRange(0.0, 100.0);
    ch4MinFluxSpin->setSingleStep(0.001);
    ch4MinFluxSpin->setAccelerated(true);
    ch4MinFluxSpin->setSuffix(tr("  [%1]").arg(Defs::UMOL_M2S_STRING));
    ch4MinFluxSpin->setToolTip(ch4MinFluxLabel->toolTip());

    gas4MinFluxLabel = new ClickLabel(tr("Minimum (absolute) %1 gas flux :").arg(Defs::GAS4_STRING));
    gas4MinFluxLabel->setToolTip(tr("<b>Minimum (absolute) %1 gas flux:</b> %1 gas time lags corresponding to fluxes smaller (in module) than this value will not be considered in the time lag optimization. Selecting high-enough fluxes assures that well developed turbulent conditions are met and the correlation function is well characterized.").arg(Defs::GAS4_STRING));
    gas4MinFluxSpin = new QDoubleSpinBox;
    gas4MinFluxSpin->setDecimals(3);
    gas4MinFluxSpin->setRange(0.0, 100.0);
    gas4MinFluxSpin->setSingleStep(0.001);
    gas4MinFluxSpin->setAccelerated(true);
    gas4MinFluxSpin->setSuffix(tr("  [%1]").arg(Defs::UMOL_M2S_STRING));
    gas4MinFluxSpin->setToolTip(gas4MinFluxLabel->toolTip());

    leMinFluxLabel = new ClickLabel(tr("Minimum latent heat flux :"));
    leMinFluxLabel->setToolTip(tr("<b>Minimum latent heat flux:</b> Minimum latent heat flux: H<sub>2</sub>O time lags corresponding to latent heat fluxes smaller than this value will not be considered in the time lag optimization. Selecting high-enough fluxes assures that well developed turbulent conditions are met and the correlation function is well characterized."));
    leMinFluxSpin = new QDoubleSpinBox;
    leMinFluxSpin->setDecimals(1);
    leMinFluxSpin->setRange(0.0, 1000.0);
    leMinFluxSpin->setSingleStep(0.1);
    leMinFluxSpin->setAccelerated(true);
    leMinFluxSpin->setSuffix(tr("  [%1]").arg(Defs::W_M2_STRING));
    leMinFluxSpin->setToolTip(leMinFluxLabel->toolTip());

    searchWindowLabel = WidgetUtils::createBlueLabel(this, tr("Time lag searching windows"));

    minLabel = WidgetUtils::createBlueLabel(this, tr("Minimum"));
    minLabel->setToolTip(tr("<b>Minimum:</b> Minimum time lag for each gas, for initializing the time lag optimization procedure. The searching window defined by Minimum and Maximum should be large enough to accommodate all possible time lags. Leave as <i>Not set</i> if in doubt, EddyPro will initialize it automatically."));

    maxLabel = WidgetUtils::createBlueLabel(this, tr("Maximum"));
    maxLabel->setToolTip(tr("<b>Maximum:</b> Maximum time lag for each gas, for initializing the time lag optimization procedure. The searching window defined by Minimum and Maximum should be large enough to accommodate all possible time lags. In particular, maximum time lags of water vapor in closed path systems can up to ten times higher than its nominal value, or even higher. Leave as <i>Not set</i> if in doubt, EddyPro will initialize it automatically."));

    co2Label = new ClickLabel(tr("%1 :").arg(Defs::CO2_STRING));

    minCo2TlSpin = new QDoubleSpinBox;
    minCo2TlSpin->setDecimals(1);
    minCo2TlSpin->setRange(-1000.1, 1000.0);
    minCo2TlSpin->setSingleStep(0.1);
    minCo2TlSpin->setSpecialValueText(tr("Detect automatically"));
    minCo2TlSpin->setAccelerated(true);
    minCo2TlSpin->setSuffix(tr("  [s]"));
    minCo2TlSpin->setToolTip(minLabel->toolTip());

    maxCo2TlSpin = new QDoubleSpinBox;
    maxCo2TlSpin->setDecimals(1);
    maxCo2TlSpin->setRange(-1000.1, 1000.0);
    maxCo2TlSpin->setSingleStep(0.1);
    maxCo2TlSpin->setSpecialValueText(tr("Detect automatically"));
    maxCo2TlSpin->setAccelerated(true);
    maxCo2TlSpin->setSuffix(tr("  [s]"));
    maxCo2TlSpin->setToolTip(maxLabel->toolTip());

    h2oLabel = new ClickLabel(tr("%1 :").arg(Defs::H2O_STRING));

    minH2oTlSpin = new QDoubleSpinBox;
    minH2oTlSpin->setDecimals(1);
    minH2oTlSpin->setRange(-1000.1, 1000.0);
    minH2oTlSpin->setSingleStep(0.1);
    minH2oTlSpin->setSpecialValueText(tr("Detect automatically"));
    minH2oTlSpin->setAccelerated(true);
    minH2oTlSpin->setSuffix(tr("  [s]"));
    minH2oTlSpin->setToolTip(minLabel->toolTip());

    maxH2oTlSpin = new QDoubleSpinBox;
    maxH2oTlSpin->setDecimals(1);
    maxH2oTlSpin->setRange(-1000.1, 1000.0);
    maxH2oTlSpin->setSingleStep(0.1);
    maxH2oTlSpin->setSpecialValueText(tr("Detect automatically"));
    maxH2oTlSpin->setAccelerated(true);
    maxH2oTlSpin->setSuffix(tr("  [s]"));
    maxH2oTlSpin->setToolTip(maxLabel->toolTip());

    ch4Label = new ClickLabel(tr("%1 :").arg(Defs::CH4_STRING));

    minCh4TlSpin = new QDoubleSpinBox;
    minCh4TlSpin->setDecimals(1);
    minCh4TlSpin->setRange(-1000.1, 1000.0);
    minCh4TlSpin->setSingleStep(0.1);
    minCh4TlSpin->setSpecialValueText(tr("Detect automatically"));
    minCh4TlSpin->setAccelerated(true);
    minCh4TlSpin->setSuffix(tr("  [s]"));
    minCh4TlSpin->setToolTip(minLabel->toolTip());

    maxCh4TlSpin = new QDoubleSpinBox;
    maxCh4TlSpin->setDecimals(1);
    maxCh4TlSpin->setRange(-1000.1, 1000.0);
    maxCh4TlSpin->setSingleStep(0.1);
    maxCh4TlSpin->setSpecialValueText(tr("Detect automatically"));
    maxCh4TlSpin->setAccelerated(true);
    maxCh4TlSpin->setSuffix(tr("  [s]"));
    maxCh4TlSpin->setToolTip(maxLabel->toolTip());

    gas4Label = new ClickLabel(tr("%1 gas :").arg(Defs::GAS4_STRING));

    minGas4TlSpin = new QDoubleSpinBox;
    minGas4TlSpin->setDecimals(1);
    minGas4TlSpin->setRange(-1000.1, 1000.0);
    minGas4TlSpin->setSingleStep(0.1);
    minGas4TlSpin->setSpecialValueText(tr("Detect automatically"));
    minGas4TlSpin->setAccelerated(true);
    minGas4TlSpin->setSuffix(tr("  [s]"));
    minGas4TlSpin->setToolTip(minLabel->toolTip());

    maxGas4TlSpin = new QDoubleSpinBox;
    maxGas4TlSpin->setDecimals(1);
    maxGas4TlSpin->setRange(-1000.1, 1000.0);
    maxGas4TlSpin->setSingleStep(0.1);
    maxGas4TlSpin->setSpecialValueText(tr("Detect automatically"));
    maxGas4TlSpin->setAccelerated(true);
    maxGas4TlSpin->setSuffix(tr("  [s]"));
    maxGas4TlSpin->setToolTip(maxLabel->toolTip());

    auto propertiesLayout = new QGridLayout;
    propertiesLayout->addLayout(existingFileLayout, 0, 0, 1, -1);
    propertiesLayout->addWidget(nonExistingRadio, 1, 0);
    propertiesLayout->addWidget(subsetCheckBox, 1, 1, 1, 1, Qt::AlignLeft);
    propertiesLayout->addWidget(startDateLabel, 1, 1, Qt::AlignRight);
    propertiesLayout->addLayout(dateTimeContainer, 1, 2, 2, 1);
    propertiesLayout->addWidget(endDateLabel, 2, 1, Qt::AlignRight);
    propertiesLayout->addWidget(pgRangeLabel, 3, 1, 1, 1, Qt::AlignRight);
    propertiesLayout->addWidget(pgRangeSpin, 3, 2);
    propertiesLayout->addWidget(pgRangeLabel_2, 3, 3);

    propertiesLayout->addWidget(h2oTitleLabel, 4, 0, 1, 2);

    propertiesLayout->addWidget(rhClassLabel, 5, 1, Qt::AlignRight);
    propertiesLayout->addWidget(rhClassSpin, 5, 2);
    propertiesLayout->addWidget(leMinFluxLabel, 6, 1, Qt::AlignRight);
    propertiesLayout->addWidget(leMinFluxSpin, 6, 2);

    propertiesLayout->addWidget(gasTitleLabel, 7, 0);

    propertiesLayout->addWidget(co2MinFluxLabel, 8, 1, Qt::AlignRight);
    propertiesLayout->addWidget(co2MinFluxSpin, 8, 2);
    propertiesLayout->addWidget(ch4MinFluxLabel, 9, 1, Qt::AlignRight);
    propertiesLayout->addWidget(ch4MinFluxSpin, 9, 2);
    propertiesLayout->addWidget(gas4MinFluxLabel, 10, 1, Qt::AlignRight);
    propertiesLayout->addWidget(gas4MinFluxSpin, 10, 2);

    propertiesLayout->addWidget(searchWindowLabel, 11, 0);
    propertiesLayout->addWidget(minLabel, 12, 1);
    propertiesLayout->addWidget(maxLabel, 12, 2);
    propertiesLayout->addWidget(co2Label, 13, 0, Qt::AlignRight);
    propertiesLayout->addWidget(minCo2TlSpin, 13, 1);
    propertiesLayout->addWidget(maxCo2TlSpin, 13, 2);
    propertiesLayout->addWidget(h2oLabel, 14, 0, Qt::AlignRight);
    propertiesLayout->addWidget(minH2oTlSpin, 14, 1);
    propertiesLayout->addWidget(maxH2oTlSpin, 14, 2);
    propertiesLayout->addWidget(ch4Label, 15, 0, Qt::AlignRight);
    propertiesLayout->addWidget(minCh4TlSpin, 15, 1);
    propertiesLayout->addWidget(maxCh4TlSpin, 15, 2);
    propertiesLayout->addWidget(gas4Label, 16, 0, Qt::AlignRight);
    propertiesLayout->addWidget(minGas4TlSpin, 16, 1);
    propertiesLayout->addWidget(maxGas4TlSpin, 16, 2);
    propertiesLayout->setVerticalSpacing(3);
    propertiesLayout->setRowMinimumHeight(2, 10);
    propertiesLayout->setContentsMargins(3, 3, 3, 3);

    auto propertiesFrame = new QWidget;
    propertiesFrame->setLayout(propertiesLayout);
    propertiesFrame->setMinimumWidth(propertiesFrame->sizeHint().width());

    auto okButton = WidgetUtils::createCommonButton(this, tr("Ok"));

    auto mainLayout = new QGridLayout(this);
    mainLayout->addWidget(groupTitle, 0, 0);
    mainLayout->addWidget(hrLabel, 1, 0);
    mainLayout->addWidget(propertiesFrame, 2, 0);
    mainLayout->addWidget(okButton, 3, 0, 1, 1, Qt::AlignCenter);
    mainLayout->setVerticalSpacing(10);
    mainLayout->setContentsMargins(30, 30, 30, 30);
    mainLayout->setSizeConstraint(QLayout::SetFixedSize);
    setLayout(mainLayout);

    connect(radioGroup, SIGNAL(buttonClicked(int)),
            this, SLOT(updateTlMode(int)));

    connect(radioGroup, SIGNAL(buttonClicked(int)),
            this, SLOT(radioClicked(int)));

    connect(fileBrowse, &FileBrowseWidget::pathChanged,
            this, &TimeLagSettingsDialog::updateFile);
    connect(fileBrowse, &FileBrowseWidget::pathSelected,
        this, &TimeLagSettingsDialog::testSelectedFile);

    connect(subsetCheckBox, &QCheckBox::toggled,
            this, &TimeLagSettingsDialog::updateSubsetSelection);

    connect(startDateLabel, &ClickLabel::clicked,
            this, &TimeLagSettingsDialog::onStartDateLabelClicked);
    connect(startDateEdit, &QDateEdit::dateChanged,
            this, &TimeLagSettingsDialog::updateStartDate);
    connect(startTimeEdit, &QTimeEdit::timeChanged,
            this, &TimeLagSettingsDialog::updateStartTime);

    connect(endDateLabel, &ClickLabel::clicked,
            this, &TimeLagSettingsDialog::onEndDateLabelClicked);
    connect(endDateEdit, &QDateEdit::dateChanged,
            this, &TimeLagSettingsDialog::updateEndDate);
    connect(endTimeEdit, &QTimeEdit::timeChanged,
            this, &TimeLagSettingsDialog::updateEndTime);

    connect(rhClassLabel, &ClickLabel::clicked,
            this, &TimeLagSettingsDialog::onRhClassClicked);
    connect(rhClassSpin, SIGNAL(valueChanged(int)),
            this, SLOT(updateRhClass(int)));

    connect(co2MinFluxLabel, &ClickLabel::clicked,
            this, &TimeLagSettingsDialog::onCo2MinFluxClicked);
    connect(co2MinFluxSpin, SIGNAL(valueChanged(double)),
            this, SLOT(updateCo2MinFlux(double)));

    connect(ch4MinFluxLabel, &ClickLabel::clicked,
            this, &TimeLagSettingsDialog::onCh4MinFluxClicked);
    connect(ch4MinFluxSpin, SIGNAL(valueChanged(double)),
            this, SLOT(updateCh4MinFlux(double)));

    connect(gas4MinFluxLabel, &ClickLabel::clicked,
            this, &TimeLagSettingsDialog::onGas4MinFluxClicked);
    connect(gas4MinFluxSpin, SIGNAL(valueChanged(double)),
            this, SLOT(updateGas4MinFlux(double)));

    connect(leMinFluxLabel, &ClickLabel::clicked,
            this, &TimeLagSettingsDialog::onLeMinFluxClicked);
    connect(leMinFluxSpin, SIGNAL(valueChanged(double)),
            this, SLOT(updateLeMinFlux(double)));

    connect(pgRangeLabel, &ClickLabel::clicked,
            this, &TimeLagSettingsDialog::onPgRangeLabelClicked);
    connect(pgRangeSpin, SIGNAL(valueChanged(double)),
            this, SLOT(updatePgRange(double)));

    connect(co2Label, &ClickLabel::clicked,
            this, &TimeLagSettingsDialog::onCo2LabelClicked);
    connect(minCo2TlSpin, SIGNAL(valueChanged(double)),
            this, SLOT(updateMinCo2Tl(double)));
    connect(maxCo2TlSpin, SIGNAL(valueChanged(double)),
            this, SLOT(updateMaxCo2Tl(double)));

    connect(h2oLabel, &ClickLabel::clicked,
            this, &TimeLagSettingsDialog::onH2oLabelClicked);
    connect(minH2oTlSpin, SIGNAL(valueChanged(double)),
            this, SLOT(updateMinH2oTl(double)));
    connect(maxH2oTlSpin, SIGNAL(valueChanged(double)),
            this, SLOT(updateMaxH2oTl(double)));

    connect(ch4Label, &ClickLabel::clicked,
            this, &TimeLagSettingsDialog::onCh4LabelClicked);
    connect(minCh4TlSpin, SIGNAL(valueChanged(double)),
            this, SLOT(updateMinCh4Tl(double)));
    connect(maxCh4TlSpin, SIGNAL(valueChanged(double)),
            this, SLOT(updateMaxCh4Tl(double)));

    connect(gas4Label, &ClickLabel::clicked,
            this, &TimeLagSettingsDialog::onGas4LabelClicked);
    connect(minGas4TlSpin, SIGNAL(valueChanged(double)),
            this, SLOT(updateMinGas4Tl(double)));
    connect(maxGas4TlSpin, SIGNAL(valueChanged(double)),
            this, SLOT(updateMaxGas4Tl(double)));

    connect(okButton, &QPushButton::clicked,
            this, &TimeLagSettingsDialog::close);

    // init
    forceEndDatePolicy();
    forceEndTimePolicy();
}
Пример #18
0
void QMLProfile::screenChanged(QScreen *screen)
{
	setDevicePixelRatio(screen->devicePixelRatio());
}
Пример #19
0
AboutDialog::AboutDialog(QWidget* parent)
    : QDialog(parent)
{
#if defined(Q_OS_WIN)
    resize(530, 620);
    setMinimumSize(530, 620);
#elif defined(Q_OS_MAC)
    resize(660, 690);
    setMinimumSize(660, 690);
#endif

    setWindowModality(Qt::WindowModal);
    QString titleText = tr("About %1").arg(Defs::APP_NAME);
    setWindowTitle(titleText);
    WidgetUtils::removeContextHelpButton(this);

    auto introduction = new QLabel;
    introduction->setText(
        tr("<h2>%1<sup>&reg;</sup> version %2 %3</h2>"
           "<h6>Built on %4 at %5<br />With %7<br /></h6>"
           ).arg(Defs::APP_NAME)
            .arg(Defs::APP_VERSION_STR)
            .arg(Defs::APP_STAGE_STR)
            .arg(QStringLiteral(__DATE__))
            .arg(QStringLiteral(__TIME__))
        #if defined(Q_OS_WIN)
            .arg(Defs::WIN_COMPILER)
        #elif defined(Q_OS_MAC)
            .arg(Defs::MAC_COMPILER)
        #endif
        );
    auto icon = new QLabel;
    auto app_logo_2x = QPixmap(QStringLiteral(":/icons/app-logo-about"));
#if defined(Q_OS_MAC)
    app_logo_2x.setDevicePixelRatio(2.0);
#endif
    icon->setPixmap(app_logo_2x);

    // About information
    auto infoWidget = new QWidget;
    auto infoLabel = new QLabel;
    infoLabel-> setText(
        tr("<br />%1 is an open source software application that is developed, "
           "maintained, supported by LI-COR Biosciences. It originates from "
           "ECO2S, the Eddy COvariance COmmunity Software project, which was "
           "developed as part of the IMECC-EU research project.</p>"
           "<p>We gratefully acknowledge the IMECC consortium, the ECO2S "
           "development team, the University of Tuscia (Italy) and scientists "
           "around the world who assisted with development and testing of the "
           "original version of this software."
           "<p>Copyright &copy; 2011-%2 LI-COR Inc.</p>"
           "<div>Contact LI-COR Inc.:</div><br />"
           "<div style=\"text-indent: 20px;\">4647 Superior Street</div>"
           "<div style=\"text-indent: 20px;\">P.O. Box 4000</div>"
           "<div style=\"text-indent: 20px;\">Lincoln, Nebraska, 68504, USA</div><br />"
           "<div style=\"text-indent: 20px;\">Phone: 1-402-467-3576</div>"
           "<div style=\"text-indent: 20px;\">Toll Free: 800-447-3576</div>"
           "<div style=\"text-indent: 20px;\">Fax: 1-402-467-2819</div>"
           "<div style=\"text-indent: 20px;\">Email: <a href=\"mailto:[email protected]?subject=EddyPro %3\">[email protected]</a></div>"
           "<div style=\"text-indent: 20px;\">Website: <a href=\"http://www.licor.com\">http://www.licor.com</a></div>"
           ).arg(Defs::APP_NAME).arg(Defs::CURRENT_COPYRIGHT_YEAR).arg(Defs::APP_VERSION_STR)
        );
    infoLabel->setOpenExternalLinks(true);
    infoLabel->setWordWrap(true);

    auto infoLayout = new QVBoxLayout;
    infoLayout->addWidget(infoLabel);
    infoLayout->addStretch();
    infoWidget->setLayout(infoLayout);

    // Thanks
    auto thanksWidget = new QWidget;
    auto thanksLabel = new QLabel;
    thanksLabel->setText(
        tr("<br />We would like to thank the whole "
            "Eddy Covariance community, the authors, testers, the users and the "
            "following people (and the missing ones), in no special "
            "order, for their collaboration and source code contribution "
            "to create this free software." ));
    thanksLabel->setWordWrap(true);

    auto thanksEdit = new QTextEdit;
    thanksEdit->setText(
        tr("<h4>Original Authors</h4>"
           "<ul type=\"square\">"
           "<li>Gerardo Fratini ([email protected]): processing engines designer and developer</li>"
           "<li>Antonio Forgione ([email protected]): GUI designer and developer</li>"
           "<li>Dario Papale ([email protected]): project manager and coordinator</li>"
           "</ul>"

           "<h4>Others contributors</h4>"
           "<ul type=\"square\">"
           "<li>Carlo Trotta: code harmonization and documentation</li>"
           "<li>Natascha Kljun: code for footprint estimation, Kljun et al. (2004, BLM)</li>"
           "<li>Taro Nakai: code for angle of attack correction, Nakai et al. (2006, AFM)</li>"
           "<li>Andreas Ibrom: supervision during implementation of a spectral correction procedure, Ibrom et al. (2007, AFM)</li>"
           "<li>Stephen Chan: Revision, refinement and testing of implementation of Massman 2000/2001 spectral correction.</li>"
           "</ul>"

           "<h4>Software validation (intercomparison)</h4>"
           "<ul type=\"square\">"
           "<li>Juha-Pekka Tuovinen</li>"
           "<li>Andreas Ibrom</li>"
           "<li>Ivan Mammarella</li>"
           "<li>Robert Clement</li>"
           "<li>Meelis Molder</li>"
           "<li>Olaf Kolle</li>"
           "<li>Corinna Rebmann</li>"
           "<li>Matthias Mauder</li>"
           "<li>Jan Elbers</li>"
           "</ul>"

           "<h4>User testing and bug notifications</h4>"
           "<ul type=\"square\">"
           "<li>Tarek El-Madany</li>"
           "<li>Sergiy Medinets</li>"
           "<li>Beniamino Gioli</li>"
           "<li>Nicola Arriga</li>"
           "<li>Luca Belelli</li>"
           "<li>Michal Heliasz</li>"
           "<li>Bernard Heinesch</li>"
           "<li>Arnaud Carrara</li>"
           "<li>Patrik Vestin</li>"
           "<li>Matthias Barthel</li>"
           "<li>Karoline Wischnewski</li>"
           "<li>Matthew Wilkinson</li>"
           "<li>Simone Sabbatini</li>"
           "</ul>"

           "<h4>Software discussions</h4>"
           "<ul type=\"square\">"
           "<li>Ian Elbers</li>"
           "<li>George Burba</li>"
           "<li>Christian Wille</li>"
           "</ul>"

           "<h4>Libraries</h4>"
           "<ul type=\"square\">"
           "<li>Arjan van Dijk: libdate module</li>"
           "<li>Michael Baudin, Arjen Markus: m_logging module</li>"
           "<li>University of Chicago: m_levenberg_marquardt from the MINPACK package</li>"
           "<li>netlib.org: FFT routines from the SLATEC Common Mathematical Library</li>"
           "<li>The Qt Company: Qt framework</li>"
           "<li>Boost::math</li>"
           "<li>Trenton Schulz (Trolltech AS): Fader widget</li>"
           "<li>Morgan Leborgne: QProgressIndicator widget</li>"
           "<li>Witold Wysota: Debug helper class</li>"
           "<li>Sergey A. Tachenov: QuaZIP</li>"
           "<li>Mark Summerfield: classes from the book 'Advanced Qt Programming'</li>"
           "</ul>"

           "<h4>Tools</h4>"
           "<ul type=\"square\">"
           "<li>GFortran compiler</li>"
           "<li>MinGW compiler and GDB debugger</li>"
           "<li>Clang compiler</li>"
           "<li>The Qt Company: Qt Creator IDE</li>"
           "<li>Code::Blocks IDE</li>"
           "<li>\n</li>"
           "</ul>"));
    thanksEdit->setReadOnly(true);

    auto thanksLayout = new QVBoxLayout;
    thanksLayout->addWidget(thanksLabel);
    thanksLayout->addWidget(thanksEdit);
    thanksWidget->setLayout(thanksLayout);

    // License
    auto licenseWidget = new QWidget;
    auto licenseLabel = new QLabel;
    licenseLabel->setText(
        tr("<br />The %1 software application is Copyright &copy; 2011-%2 "
           "LI-COR Inc.\n\n"
           "You may use, distribute and copy the %1 programs suite under "
           "the terms of the GNU General Public License version 3, "
           "which is displayed below. If you would like to obtain "
           "a copy of the source package please contact LI-COR "
           "Biosciences at "
           "<a href=\"mailto:[email protected]?subject=%1 %3&body="
           "Please, send me a copy of the source package."
           "\">[email protected]</a>."
        ).arg(Defs::APP_NAME).arg(Defs::CURRENT_COPYRIGHT_YEAR).arg(Defs::APP_VERSION_STR));
    licenseLabel->setWordWrap(true);
    licenseLabel->setOpenExternalLinks(true);

    auto licenseEdit = new QTextEdit;
    QFile licenseFile(QStringLiteral(":/docs/license"));
    qDebug() << licenseFile.open(QIODevice::ReadOnly | QIODevice::Text);
    licenseEdit->setText(QLatin1String(licenseFile.readAll()));
    licenseEdit->setReadOnly(true);
    licenseFile.close();

    auto licenseLayout = new QVBoxLayout;
    licenseLayout->addWidget(licenseLabel);
    licenseLayout->addWidget(licenseEdit);
    licenseWidget->setLayout(licenseLayout);

    // Changelog
    auto changelogWidget = new QWidget;
    auto changelogLabel = new QLabel;
    changelogLabel->setText(
        tr("<br />Software updates include bug fixes, usability "
           "improvements\n\n and feature enhancements. These are summarized "
           "in the change log below."));
    changelogLabel->setWordWrap(true);
    changelogLabel->setOpenExternalLinks(true);

    auto changelogEdit = new QTextEdit;
    QFile changelogFile(QStringLiteral(":/docs/changelog"));
    qDebug() << changelogFile.open(QIODevice::ReadOnly | QIODevice::Text);
    changelogEdit->setText(QLatin1String(changelogFile.readAll()));
    changelogEdit->setReadOnly(true);
    changelogFile.close();

    auto changelogLayout = new QVBoxLayout;
    changelogLayout->addWidget(changelogLabel);
    changelogLayout->addWidget(changelogEdit);
    changelogWidget->setLayout(changelogLayout);

    // Dialog Tabs
    auto tab = new QTabWidget;
    tab->addTab(infoWidget, tr("About"));
    tab->addTab(thanksWidget, tr("Acknowledgments"));
    tab->addTab(licenseWidget, tr("License"));
    tab->addTab(changelogWidget, tr("Changes"));

    auto okButton = WidgetUtils::createCommonButton(this, tr("Ok"));

    auto dialogLayout = new QVBoxLayout(this);
    dialogLayout->addWidget(icon, 0, Qt::AlignCenter);
    dialogLayout->addWidget(introduction, 0, Qt::AlignCenter);
    dialogLayout->addWidget(tab);
    dialogLayout->addWidget(okButton, 0, Qt::AlignCenter);
    dialogLayout->setContentsMargins(30, 30, 30, 30);
    setLayout(dialogLayout);

    connect(okButton, &QPushButton::clicked,
            [=](){ if (this->isVisible()) hide(); });
}