File indexing completed on 2024-05-05 16:39:05

0001 /* This file is part of the KDE project
0002    Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
0003 
0004    This program is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU General Public
0006    License as published by the Free Software Foundation, version 2.
0007 
0008    This program is distributed in the hope that it will be useful,
0009    but WITHOUT ANY WARRANTY; without even the implied warranty of
0010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0011     General Public License for more details.
0012 
0013    You should have received a copy of the GNU General Public License
0014    along with this program; see the file COPYING.  If not, write to
0015    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0016    Boston, MA 02110-1301, USA.
0017 */
0018 
0019 #include "printing.h"
0020 #include <ui_printing_page.h>
0021 
0022 #include <KLocalizedString>
0023 
0024 #include <QFont>
0025 #include <QFontDatabase>
0026 #include <QFontMetrics>
0027 #include <QImage>
0028 #include <QPainter>
0029 #include <QPrintDialog>
0030 #include <QPrinter>
0031 #include <QScopedPointer>
0032 #include <QTemporaryFile>
0033 #include <QUrl>
0034 
0035 #include "filecache.h"
0036 #include "imagewindow.h"
0037 #include "kuickshow_debug.h"
0038 #include "version.h"
0039 
0040 
0041 bool Printing::printImage( ImageWindow& imageWin, QWidget *parent )
0042 {
0043     QString imageURL = imageWin.url().toDisplayString();
0044     QPrinter printer;
0045     printer.setDocName( imageURL );
0046     printer.setCreator( "KuickShow-" KUICKSHOWVERSION );
0047 
0048     KuickPrintDialogPage* dialogPage = new KuickPrintDialogPage( parent );
0049     dialogPage->setObjectName(QString::fromLatin1("kuick page"));
0050     QPrintDialog *printDialog = new QPrintDialog(&printer, parent);
0051     printDialog->setOptionTabs(QList<QWidget*>() << dialogPage);
0052     printDialog->setWindowTitle(i18n("Print %1", printer.docName().section('/', -1)));
0053 
0054     if (printDialog->exec())
0055     {
0056         QScopedPointer<QTemporaryFile> tmpFilePtr(FileCache::self()->createTempFile(QStringLiteral(".png")));
0057         if ( tmpFilePtr->open() )
0058         {
0059             if ( imageWin.saveImage( QUrl::fromLocalFile(tmpFilePtr->fileName()), true ) )
0060             {
0061 
0062                 bool success = printImageWithQt( tmpFilePtr->fileName(), printer, *dialogPage,
0063                                          imageURL);
0064                 delete printDialog;
0065                 return success;
0066             }
0067         }
0068         delete printDialog;
0069         return false;
0070     }
0071     delete printDialog;
0072     return true; // user aborted
0073 }
0074 
0075 bool Printing::printImageWithQt( const QString& filename, QPrinter& printer, KuickPrintDialogPage& dialogPage,
0076                                  const QString& originalFileName )
0077 {
0078     QImage image( filename );
0079     if ( image.isNull() ) {
0080         qWarning("Can't load image: %s for printing.", qUtf8Printable(filename));
0081         return false;
0082     }
0083 
0084     QPainter p;
0085     p.begin( &printer );
0086 
0087     p.setFont( QFontDatabase::systemFont(QFontDatabase::GeneralFont) );
0088     QFontMetrics fm = p.fontMetrics();
0089 
0090     int w = printer.width();
0091     int h = printer.height();
0092 
0093     // Black & white print?
0094     if ( dialogPage.printBlackWhite() ) {
0095         image = image.convertToFormat( QImage::Format_Mono, Qt::MonoOnly | Qt::ThresholdDither | Qt::AvoidDither );
0096     }
0097 
0098     int filenameOffset = 0;
0099     bool printFilename = dialogPage.printFilename();
0100     if ( printFilename ) {
0101         filenameOffset = fm.lineSpacing() + 14;
0102         h -= filenameOffset; // filename goes into one line!
0103     }
0104 
0105     //
0106     // shrink image to pagesize, if necessary
0107     //
0108     bool shrinkToFit = dialogPage.printShrinkToFit();
0109     QSize imagesize = image.size();
0110     if ( shrinkToFit && (image.width() > w || image.height() > h) ) {
0111         imagesize.scale( w, h, Qt::KeepAspectRatio );
0112     }
0113 
0114 
0115     //
0116     // align image
0117     //
0118     // not currently implemented in print options
0119     //bool ok = false;
0120     //int alignment = printer.option("app-kuickshow-alignment").toInt( &ok );
0121     //if ( !ok )
0122         int alignment = Qt::AlignCenter; // default
0123 
0124     int x = 0;
0125     int y = 0;
0126 
0127     // ### need a GUI for this in KuickPrintDialogPage!
0128     // x - alignment
0129     if ( alignment & Qt::AlignHCenter )
0130         x = (w - imagesize.width())/2;
0131     else if ( alignment & Qt::AlignLeft )
0132         x = 0;
0133     else if ( alignment & Qt::AlignRight )
0134         x = w - imagesize.width();
0135 
0136     // y - alignment
0137     if ( alignment & Qt::AlignVCenter )
0138         y = (h - imagesize.height())/2;
0139     else if ( alignment & Qt::AlignTop )
0140         y = 0;
0141     else if ( alignment & Qt::AlignBottom )
0142         y = h - imagesize.height();
0143 
0144     //
0145     // perform the actual drawing
0146     //
0147     p.drawImage( QRect( x, y, imagesize.width(), imagesize.height()), image );
0148 
0149     if ( printFilename )
0150     {
0151         QString fname = minimizeString( originalFileName, fm, w );
0152         if ( !fname.isEmpty() )
0153         {
0154             int fw = fm.horizontalAdvance(fname);
0155             int x = (w - fw)/2;
0156             int y = printer.height() - filenameOffset/2;
0157             p.drawText( x, y, fname );
0158         }
0159     }
0160 
0161     p.end();
0162 
0163     return true;
0164 }
0165 
0166 QString Printing::minimizeString( QString text, const QFontMetrics&
0167                                   metrics, int maxWidth )
0168 {
0169     if ( text.length() <= 5 )
0170         return QString(); // no sense to cut that tiny little string
0171 
0172     bool changed = false;
0173     while (metrics.horizontalAdvance(text) > maxWidth)
0174     {
0175         int mid = text.length() / 2;
0176         text.remove( mid, 2 ); // remove 2 characters in the middle
0177         changed = true;
0178     }
0179 
0180     if ( changed ) // add "..." in the middle
0181     {
0182         int mid = text.length() / 2;
0183         if ( mid <= 5 ) // sanity check
0184             return QString();
0185 
0186         text.replace( mid - 1, 3, "..." );
0187     }
0188 
0189     return text;
0190 }
0191 
0192 
0193 ///////////////////////////////////////////////////////////////////
0194 ///////////////////////////////////////////////////////////////////
0195 
0196 
0197 KuickPrintDialogPage::KuickPrintDialogPage( QWidget *parent )
0198     : QWidget( parent )
0199 {
0200     ui = new Ui::KuickPrintDialogPage;
0201     ui->setupUi(this);
0202 
0203     connect( ui->scale, SIGNAL( toggled( bool )), SLOT( toggleScaling( bool )));
0204 }
0205 
0206 KuickPrintDialogPage::~KuickPrintDialogPage()
0207 {
0208     delete ui;
0209 }
0210 
0211 //    ### opts["app-kuickshow-alignment"] = ;
0212 
0213 bool KuickPrintDialogPage::printFilename()
0214 {
0215     return ui->addFileName->isChecked();
0216 }
0217 
0218 void KuickPrintDialogPage::setPrintFilename( bool addFilename )
0219 {
0220     ui->addFileName->setChecked( addFilename );
0221 }
0222 
0223 bool KuickPrintDialogPage::printBlackWhite()
0224 {
0225     return ui->blackwhite->isChecked();
0226 }
0227 
0228 void KuickPrintDialogPage::setPrintBlackWhite( bool blackWhite )
0229 {
0230     ui->blackwhite->setChecked( blackWhite );
0231 }
0232 
0233 bool KuickPrintDialogPage::printShrinkToFit()
0234 {
0235     return ui->shrinkToFit->isChecked();
0236 }
0237 
0238 void KuickPrintDialogPage::setPrintShrinkToFit( bool shrinkToFit )
0239 {
0240     toggleScaling( !shrinkToFit );
0241 }
0242 
0243 bool KuickPrintDialogPage::printScale()
0244 {
0245     return ui->scale->isChecked();
0246 }
0247 
0248 void KuickPrintDialogPage::setPrintScale( bool scale )
0249 {
0250     toggleScaling( scale );
0251 }
0252 
0253 QString KuickPrintDialogPage::printScaleUnit()
0254 {
0255     return ui->units->currentText();
0256 }
0257 
0258 void KuickPrintDialogPage::setPrintScaleUnit( QString scaleUnit )
0259 {
0260     for(int i = 0, count = ui->units->count(); i < count; i++) {
0261         if(ui->units->itemText(i) == scaleUnit) {
0262             ui->units->setCurrentIndex(i);
0263             return;
0264         }
0265     }
0266 
0267     ui->units->setCurrentIndex(-1);
0268 }
0269 
0270 int KuickPrintDialogPage::printScaleWidthPixels()
0271 {
0272     return scaleWidth();
0273 }
0274 
0275 void KuickPrintDialogPage::setPrintScaleWidthPixels( int scaleWidth )
0276 {
0277     setScaleWidth(scaleWidth);
0278 }
0279 
0280 int KuickPrintDialogPage::printScaleHeightPixels()
0281 {
0282     return scaleHeight();
0283 }
0284 
0285 void KuickPrintDialogPage::setPrintScaleHeightPixels( int scaleHeight )
0286 {
0287     setScaleHeight(scaleHeight);
0288 }
0289 
0290 void KuickPrintDialogPage::toggleScaling( bool enable )
0291 {
0292     ui->shrinkToFit->setChecked( !enable );
0293     ui->scale->setChecked( enable );
0294     ui->width->setEnabled( enable );
0295     ui->height->setEnabled( enable );
0296     ui->units->setEnabled( enable );
0297 }
0298 
0299 int KuickPrintDialogPage::scaleWidth() const
0300 {
0301     return fromUnitToPixels( ui->width->value() );
0302 }
0303 
0304 int KuickPrintDialogPage::scaleHeight() const
0305 {
0306     return fromUnitToPixels( ui->height->value() );
0307 }
0308 
0309 void KuickPrintDialogPage::setScaleWidth( int pixels )
0310 {
0311     ui->width->setValue( (int) pixelsToUnit( pixels ) );
0312 }
0313 
0314 void KuickPrintDialogPage::setScaleHeight( int pixels )
0315 {
0316     ui->width->setValue( (int) pixelsToUnit( pixels ) );
0317 }
0318 
0319 int KuickPrintDialogPage::fromUnitToPixels( float /*value*/ ) const
0320 {
0321     return 1; // ###
0322 }
0323 
0324 float KuickPrintDialogPage::pixelsToUnit( int /*pixels*/ ) const
0325 {
0326     return 1.0; // ###
0327 }