diff --git a/glabels/CMakeLists.txt b/glabels/CMakeLists.txt index 89ad357..7ef4010 100644 --- a/glabels/CMakeLists.txt +++ b/glabels/CMakeLists.txt @@ -26,6 +26,7 @@ set (glabels_sources NotebookUtil.cpp ObjectEditor.cpp PreferencesDialog.cpp + PrinterMonitor.cpp PrintView.cpp PropertiesView.cpp Preview.cpp @@ -59,6 +60,7 @@ set (glabels_qobject_headers MergeView.h ObjectEditor.h PreferencesDialog.h + PrinterMonitor.h PrintView.h PropertiesView.h Preview.h diff --git a/glabels/PrintView.cpp b/glabels/PrintView.cpp index 19c7ce9..f2b28db 100644 --- a/glabels/PrintView.cpp +++ b/glabels/PrintView.cpp @@ -21,11 +21,16 @@ #include "PrintView.h" +#include "PrinterMonitor.h" + #include "model/Settings.h" +#include +#include +#include #include +#include #include -#include namespace glabels @@ -40,6 +45,13 @@ namespace glabels setupUi( this ); titleLabel->setText( QString( "%1" ).arg( tr("Print") ) ); + + auto* printerMonitor = PrinterMonitor::instance(); + loadDestinations( printerMonitor->availablePrinters() ); + connect( printerMonitor, SIGNAL(availablePrintersChanged(const QStringList&)), + this, SLOT(onAvailablePrintersChanged(const QStringList&)) ); + + setDestination( model::Settings::recentPrinter() ); preview->setRenderer( &mRenderer ); } @@ -59,6 +71,17 @@ namespace glabels } + /// + /// Available printers changed handler + /// + void PrintView::onAvailablePrintersChanged( const QStringList& printers ) + { + auto savedSelection = destinationCombo->currentText(); + loadDestinations( printers ); + setDestination( savedSelection ); + } + + /// /// Model changed handler /// @@ -185,9 +208,62 @@ namespace glabels /// void PrintView::onPrintButtonClicked() { + auto printerName = destinationCombo->currentText(); + auto printerInfo = QPrinterInfo::printerInfo( printerName ); + bool isPrinter = !printerInfo.isNull(); + QPrinter printer( QPrinter::HighResolution ); printer.setColorMode( QPrinter::Color ); - printer.setPrinterName( model::Settings::recentPrinter() ); + + if ( isPrinter ) + { + printer.setPrinterName( printerName ); + mRenderer.print( &printer ); + model::Settings::setRecentPrinter( printerName ); + } + else + { + QString fileName = + QFileDialog::getSaveFileName( this, + tr("Print to file (PDF)"), + defaultPdf(), + tr("PDF files (*.pdf);;All files (*)"), + nullptr, + QFileDialog::DontConfirmOverwrite ); + if ( !fileName.isEmpty() ) + { + if ( QFileInfo::exists(fileName) ) + { + QMessageBox msgBox( this ); + msgBox.setWindowTitle( tr("Print to file (PDF)") ); + msgBox.setIcon( QMessageBox::Warning ); + msgBox.setText( tr("%1 already exists.").arg(fileName) ); + msgBox.setInformativeText( tr("Do you want to overwrite it?") ); + msgBox.setStandardButtons( QMessageBox::Yes | QMessageBox::No ); + msgBox.setDefaultButton( QMessageBox::No ); + + if ( msgBox.exec() == QMessageBox::No ) + { + return; + } + } + + printer.setOutputFileName( fileName ); + printer.setOutputFormat( QPrinter::PdfFormat ); + mRenderer.print( &printer ); + } + } + } + + + /// + /// System Dialog Button Clicked handler + /// + void PrintView::onSystemDialogButtonClicked() + { + QPrinter printer( QPrinter::HighResolution ); + printer.setColorMode( QPrinter::Color ); + printer.setPrinterName( destinationCombo->currentText() ); QPrintDialog printDialog( &printer, this ); printDialog.setOption( QAbstractPrintDialog::PrintToFile, true ); @@ -201,9 +277,82 @@ namespace glabels { mRenderer.print( &printer ); - model::Settings::setRecentPrinter( printer.printerName() ); + if ( !printer.printerName().isEmpty() ) + { + model::Settings::setRecentPrinter( printer.printerName() ); + } } } + /// + /// Load available printers + /// + void PrintView::loadDestinations( const QStringList& printers ) + { + destinationCombo->blockSignals( true ); + + destinationCombo->clear(); + for ( auto& printerName : printers ) + { + destinationCombo->addItem( QIcon::fromTheme( "glabels-print" ), printerName ); + } + + if ( destinationCombo->count() ) + { + destinationCombo->insertSeparator( destinationCombo->count() ); + } + destinationCombo->addItem( QIcon::fromTheme( "glabels-file-new" ), tr( "Print to file (PDF)" ) ); + + destinationCombo->blockSignals( false ); + } + + + /// + /// Generate default PDF filename + /// + QString PrintView::defaultPdf() + { + if ( !mModel ) + { + return "output.pdf"; + } + return mModel->dirPath() + "/" + mModel->shortName() + ".pdf"; + } + + + /// + /// Set destination to printerName if valid, or to a fallback value + /// + void PrintView::setDestination( const QString& printerName ) + { + destinationCombo->blockSignals( true ); + + auto printerInfo = QPrinterInfo::printerInfo( printerName ); + + if ( !printerInfo.isNull() ) + { + // printerName is a valid printer + destinationCombo->setCurrentText( printerName ); + } + else + { + auto defaultPrinterName = QPrinterInfo::defaultPrinterName(); + auto defaultPrinterInfo = QPrinterInfo::printerInfo( defaultPrinterName ); + if ( !defaultPrinterInfo.isNull() ) + { + // defaultPinterName is a valid printer + destinationCombo->setCurrentText( defaultPrinterName ); + } + else + { + // No default printer available, set to first item in combo (probably "print to file") + destinationCombo->setCurrentIndex( 0 ); + } + } + + destinationCombo->blockSignals( false ); + } + + } // namespace glabels diff --git a/glabels/PrintView.h b/glabels/PrintView.h index bbcc87c..bd12b14 100644 --- a/glabels/PrintView.h +++ b/glabels/PrintView.h @@ -57,10 +57,21 @@ namespace glabels // Slots ///////////////////////////////// private slots: + void onAvailablePrintersChanged( const QStringList& printers ); void onModelChanged(); void updateView(); void onFormChanged(); void onPrintButtonClicked(); + void onSystemDialogButtonClicked(); + + + ///////////////////////////////// + // Private methods + ///////////////////////////////// + private: + void loadDestinations( const QStringList& printers ); + QString defaultPdf(); + void setDestination( const QString& printerName ); ///////////////////////////////// diff --git a/glabels/PrinterMonitor.cpp b/glabels/PrinterMonitor.cpp new file mode 100644 index 0000000..358a9fd --- /dev/null +++ b/glabels/PrinterMonitor.cpp @@ -0,0 +1,88 @@ +/* PrinterMonitor.cpp + * + * Copyright (C) 2025 Jaye Evins + * + * This file is part of gLabels-qt. + * + * gLabels-qt is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * gLabels-qt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with gLabels-qt. If not, see . + */ + + +#include "PrinterMonitor.h" + +#include +#include + + +namespace glabels +{ + + /// + /// Static data + /// + std::unique_ptr PrinterMonitor::mInstance; + + + /// + /// Constructor + /// + PrinterMonitor::PrinterMonitor() + { + mCurrentAvailablePrinters = QPrinterInfo::availablePrinterNames(); + + mTimer.reset( new QTimer( this ) ); + connect( mTimer.get(), SIGNAL(timeout()), this, SLOT(onTimerTimeout()) ); + mTimer->start( 1000 ); + } + + + /// + /// Get singleton instance + /// + PrinterMonitor* PrinterMonitor::instance() + { + if ( !mInstance ) + { + mInstance.reset( new PrinterMonitor() ); + } + + return mInstance.get(); + } + + + /// + /// Get available printers + /// + const QStringList& PrinterMonitor::availablePrinters() const + { + return mCurrentAvailablePrinters; + } + + + /// + /// On timer timeout + /// + void PrinterMonitor::onTimerTimeout() + { + auto newAvailablePrinters = QPrinterInfo::availablePrinterNames(); + if ( newAvailablePrinters != mCurrentAvailablePrinters ) + { + mCurrentAvailablePrinters = newAvailablePrinters; + + emit availablePrintersChanged( mCurrentAvailablePrinters ); + } + } + + +} // namespace glabels diff --git a/glabels/PrinterMonitor.h b/glabels/PrinterMonitor.h new file mode 100644 index 0000000..0639b25 --- /dev/null +++ b/glabels/PrinterMonitor.h @@ -0,0 +1,87 @@ +/* PrinterMonitor.h + * + * Copyright (C) 2025 Jaye Evins + * + * This file is part of gLabels-qt. + * + * gLabels-qt is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * gLabels-qt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with gLabels-qt. If not, see . + */ + +#ifndef PrinterMonitor_h +#define PrinterMonitor_h + + +#include +#include +#include + +#include + + +namespace glabels +{ + + /// + /// Printer Monitor + /// + class PrinterMonitor : public QObject + { + Q_OBJECT + + ///////////////////////////////// + // Life Cycle + ///////////////////////////////// + private: + PrinterMonitor(); + + public: + static PrinterMonitor* instance(); + + + ///////////////////////////////// + // Public methods + ///////////////////////////////// + public: + const QStringList& availablePrinters() const; + + + ///////////////////////////////// + // Slots + ///////////////////////////////// + private slots: + void onTimerTimeout(); + + + ///////////////////////////////// + // Signals + ///////////////////////////////// + signals: + void availablePrintersChanged( const QStringList& availablePrinters ); + + + ///////////////////////////////// + // Private Members + ///////////////////////////////// + private: + static std::unique_ptr mInstance; + + std::unique_ptr mTimer; + QStringList mCurrentAvailablePrinters; + + }; + +} + + +#endif // PrinterMonitor_h diff --git a/glabels/ui/PrintView.ui b/glabels/ui/PrintView.ui index b5d18fd..2c8f89a 100644 --- a/glabels/ui/PrintView.ui +++ b/glabels/ui/PrintView.ui @@ -7,7 +7,7 @@ 0 0 852 - 796 + 874 @@ -53,6 +53,34 @@ + + + + Destination + + + + + + text-align:left; padding:3px; + + + + + + + 32 + 32 + + + + + + + + + + @@ -449,7 +477,7 @@ text-align:left; padding:3px; - Print... + Print @@ -531,6 +559,13 @@ + + + + Use system print dialog... + + + @@ -645,8 +680,8 @@ onFormChanged() - 175 - 122 + 164 + 260 2 @@ -661,8 +696,8 @@ onFormChanged() - 182 - 444 + 216 + 574 2 @@ -677,8 +712,8 @@ onFormChanged() - 152 - 475 + 186 + 608 6 @@ -693,8 +728,8 @@ onFormChanged() - 156 - 506 + 190 + 642 6 @@ -709,8 +744,8 @@ onFormChanged() - 641 - 760 + 639 + 827 1 @@ -725,8 +760,8 @@ onPrintButtonClicked() - 291 - 589 + 312 + 724 5 @@ -741,8 +776,8 @@ onFormChanged() - 159 - 243 + 156 + 390 7 @@ -757,8 +792,8 @@ onFormChanged() - 59 - 108 + 93 + 258 6 @@ -773,8 +808,8 @@ onFormChanged() - 142 - 149 + 188 + 299 5 @@ -789,8 +824,8 @@ onFormChanged() - 226 - 145 + 275 + 299 8 @@ -805,8 +840,8 @@ onFormChanged() - 52 - 261 + 85 + 401 3 @@ -821,8 +856,8 @@ onFormChanged() - 231 - 314 + 264 + 449 5 @@ -837,8 +872,8 @@ onFormChanged() - 199 - 362 + 254 + 679 4 @@ -846,11 +881,45 @@ + + destinationCombo + currentIndexChanged(int) + PrintView + onFormChanged() + + + 289 + 110 + + + 254 + 6 + + + + + systemDialogButton + clicked() + PrintView + onSystemDialogButtonClicked() + + + 316 + 836 + + + 373 + 871 + + + onPrintButtonClicked() onFormChanged() onPrinterPropertiesButtonClicked() + onBrowseButtonClicked() + onSystemDialogButtonClicked() diff --git a/translations/glabels_C.ts b/translations/glabels_C.ts index 4001933..85d887c 100644 --- a/translations/glabels_C.ts +++ b/translations/glabels_C.ts @@ -619,11 +619,19 @@ - Print... + Start groups at position: - Start groups at position: + Destination + + + + Print + + + + Use system print dialog... @@ -2113,6 +2121,22 @@ (Will print a total of %1 items on 1 page.) + + Print to file (PDF) + + + + PDF files (*.pdf);;All files (*) + + + + %1 already exists. + + + + Do you want to overwrite it? + + glabels::PropertiesView