/* This file is part of the KDE libraries and the Kate part. * * Copyright (C) 2002-2010 Anders Lund * * Rewritten based on code of Copyright (c) 2002 Michael Goffioul * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kateprinter.h" #include "kateconfig.h" #include "katedocument.h" #include "kateglobal.h" #include "katehighlight.h" #include "katetextlayout.h" #include "katerenderer.h" #include "kateschema.h" #include "katetextline.h" #include "kateview.h" #include "katebuffer.h" #include "katetextfolding.h" #include #include #include #include #include #include #include #include // for loginName #include #include #include #include #include #include #include #include #include #include #include #include #include //BEGIN KatePrinter void KatePrinter::readSettings(QPrinter& printer) { // NOTE: Saving & loading the margins works around QPrinter/QPrintDialog bugs: // - https://bugreports.qt.nokia.com/browse/QTBUG-15351 // - https://bugs.kde.org/show_bug.cgi?id=205802 // - https://bugs.kde.org/show_bug.cgi?id=180051 // Changing the margins now works. However, when you reopen the print dialog // later, the WRONG margins are displayed. The correct ones are still used. // This is a critical bug in Qt. KSharedConfigPtr config = KGlobal::config(); KConfigGroup group(config, "Kate Print Settings"); KConfigGroup margins(&group, "Margins"); qreal left, right, top, bottom; printer.getPageMargins(&left, &top, &right, &bottom, QPrinter::Millimeter); left = margins.readEntry("left", left); top = margins.readEntry("top", top); right = margins.readEntry("right", right); bottom = margins.readEntry("bottom", bottom); printer.setPageMargins(left, top, right, bottom, QPrinter::Millimeter); } void KatePrinter::writeSettings(QPrinter& printer) { KSharedConfigPtr config = KGlobal::config(); KConfigGroup group(config, "Kate Print Settings"); KConfigGroup margins(&group, "Margins"); qreal left, right, top, bottom; printer.getPageMargins(&left, &top, &right, &bottom, QPrinter::Millimeter); margins.writeEntry( "left", left); margins.writeEntry( "top", top); margins.writeEntry( "right", right); margins.writeEntry( "bottom", bottom); } bool KatePrinter::print (KateDocument *doc) { QPrinter printer; readSettings(printer); // docname is now always there, including the right Untitled name printer.setDocName(doc->documentName()); KatePrintTextSettings *kpts = new KatePrintTextSettings; KatePrintHeaderFooter *kphf = new KatePrintHeaderFooter; KatePrintLayout *kpl = new KatePrintLayout; QList tabs; tabs << kpts; tabs << kphf; tabs << kpl; QWidget *parentWidget=doc->widget(); if ( !parentWidget ) parentWidget=QApplication::activeWindow(); QScopedPointer printDialog(KdePrint::createPrintDialog(&printer, KdePrint::SystemSelectsPages, tabs, parentWidget)); if ( doc->activeView()->selection() ) { printer.setPrintRange(QPrinter::Selection); printDialog->setOption(QAbstractPrintDialog::PrintSelection, true); } if ( printDialog->exec() ) { writeSettings(printer); Kate::TextFolding folding (doc->buffer()); KateRenderer renderer(doc, folding, doc->activeKateView()); renderer.config()->setSchema (kpl->colorScheme()); renderer.setPrinterFriendly(true); QPainter paint( &printer ); /* * We work in tree cycles: * 1) initialize variables and retrieve print settings * 2) prepare data according to those settings * 3) draw to the printer */ uint pdmWidth = printer.width(); uint pdmHeight = printer.height(); int y = 0; uint xstart = 0; // beginning point for painting lines uint lineCount = 0; uint maxWidth = pdmWidth; int headerWidth = pdmWidth; bool pageStarted = true; int remainder = 0; // remaining sublines from a wrapped line (for the top of a new page) // Text Settings Page bool selectionOnly = (printDialog->printRange() == QAbstractPrintDialog::Selection); bool useGuide = kpts->printGuide(); bool printLineNumbers = kpts->printLineNumbers(); uint lineNumberWidth( 0 ); // Header/Footer Page QFont headerFont(kphf->font()); // used for header/footer bool useHeader = kphf->useHeader(); QColor headerBgColor(kphf->headerBackground()); QColor headerFgColor(kphf->headerForeground()); uint headerHeight( 0 ); // further init only if needed QStringList headerTagList; // do bool headerDrawBg = false; // do bool useFooter = kphf->useFooter(); QColor footerBgColor(kphf->footerBackground()); QColor footerFgColor(kphf->footerForeground()); uint footerHeight( 0 ); // further init only if needed QStringList footerTagList; // do bool footerDrawBg = false; // do // Layout Page renderer.config()->setSchema( kpl->colorScheme() ); bool useBackground = kpl->useBackground(); bool useBox = kpl->useBox(); int boxWidth(kpl->boxWidth()); QColor boxColor(kpl->boxColor()); int innerMargin = useBox ? kpl->boxMargin() : 6; // Post initialization int maxHeight = (useBox ? pdmHeight-innerMargin : pdmHeight); uint currentPage( 1 ); uint lastline = doc->lastLine(); // necessary to print selection only uint firstline( 0 ); const int fontHeight = renderer.fontHeight(); KTextEditor::Range selectionRange; /* * Now on for preparations... * during preparations, variable names starting with a "_" means * those variables are local to the enclosing block. */ { if ( selectionOnly ) { // set a line range from the first selected line to the last selectionRange = doc->activeView()->selectionRange(); firstline = selectionRange.start().line(); lastline = selectionRange.end().line(); lineCount = firstline; } if ( printLineNumbers ) { // figure out the horiizontal space required QString s( QString("%1 ").arg( doc->lines() ) ); s.fill('5', -1); // some non-fixed fonts haven't equally wide numbers // FIXME calculate which is actually the widest... lineNumberWidth = renderer.currentFontMetrics().width( s ); // a small space between the line numbers and the text int _adj = renderer.currentFontMetrics().width( "5" ); // adjust available width and set horizontal start point for data maxWidth -= (lineNumberWidth + _adj); xstart += lineNumberWidth + _adj; } if ( useHeader || useFooter ) { // Set up a tag map // This retrieves all tags, ued or not, but // none of theese operations should be expensive, // and searcing each tag in the format strings is avoided. QDateTime dt = QDateTime::currentDateTime(); QMap tags; KUser u (KUser::UseRealUserID); tags["u"] = u.loginName(); tags["d"] = KGlobal::locale()->formatDateTime(dt, KLocale::ShortDate); tags["D"] = KGlobal::locale()->formatDateTime(dt, KLocale::LongDate); tags["h"] = KGlobal::locale()->formatTime(dt.time(), false); tags["y"] = KGlobal::locale()->formatDate(dt.date(), KLocale::ShortDate); tags["Y"] = KGlobal::locale()->formatDate(dt.date(), KLocale::LongDate); tags["f"] = doc->url().fileName(); tags["U"] = doc->url().pathOrUrl(); if ( selectionOnly ) { QString s( i18n("(Selection of) ") ); tags["f"].prepend( s ); tags["U"].prepend( s ); } QRegExp reTags( "%([dDfUhuyY])" ); // TODO tjeck for "%%" if (useHeader) { headerDrawBg = kphf->useHeaderBackground(); headerHeight = QFontMetrics( headerFont ).height(); if ( useBox || headerDrawBg ) headerHeight += innerMargin * 2; else headerHeight += 1 + QFontMetrics( headerFont ).leading(); headerTagList = kphf->headerFormat(); QMutableStringListIterator it(headerTagList); while ( it.hasNext() ) { QString tag = it.next(); int pos = reTags.indexIn( tag ); QString rep; while ( pos > -1 ) { rep = tags[reTags.cap( 1 )]; tag.replace( (uint)pos, 2, rep ); pos += rep.length(); pos = reTags.indexIn( tag, pos ); } it.setValue( tag ); } if (!headerBgColor.isValid()) headerBgColor = Qt::lightGray; if (!headerFgColor.isValid()) headerFgColor = Qt::black; } if (useFooter) { footerDrawBg = kphf->useFooterBackground(); footerHeight = QFontMetrics( headerFont ).height(); if ( useBox || footerDrawBg ) footerHeight += 2*innerMargin; else footerHeight += 1; // line only footerTagList = kphf->footerFormat(); QMutableStringListIterator it(footerTagList); while ( it.hasNext() ) { QString tag = it.next(); int pos = reTags.indexIn( tag ); QString rep; while ( pos > -1 ) { rep = tags[reTags.cap( 1 )]; tag.replace( (uint)pos, 2, rep ); pos += rep.length(); pos = reTags.indexIn( tag, pos ); } it.setValue( tag ); } if (!footerBgColor.isValid()) footerBgColor = Qt::lightGray; if (!footerFgColor.isValid()) footerFgColor = Qt::black; // adjust maxheight, so we can know when/where to print footer maxHeight -= footerHeight; } } // if ( useHeader || useFooter ) if ( useBackground ) { if ( ! useBox ) { xstart += innerMargin; maxWidth -= innerMargin * 2; } } if ( useBox ) { if (!boxColor.isValid()) boxColor = Qt::black; if (boxWidth < 1) // shouldn't be pssible no more! boxWidth = 1; // set maxwidth to something sensible maxWidth -= ( ( boxWidth + innerMargin ) * 2 ); xstart += boxWidth + innerMargin; // maxheight too.. maxHeight -= boxWidth; } else boxWidth = 0; // now that we know the vertical amount of space needed, // it is possible to calculate the total number of pages // if needed, that is if any header/footer tag contains "%P". if ( !headerTagList.filter("%P").isEmpty() || !footerTagList.filter("%P").isEmpty() ) { kDebug(13020)<<"'%P' found! calculating number of pages..."; int pageHeight = maxHeight; if ( useHeader ) pageHeight -= ( headerHeight + innerMargin ); if ( useFooter ) pageHeight -= innerMargin; const int linesPerPage = pageHeight / fontHeight; // kDebug() << "Lines per page:" << linesPerPage; // calculate total layouted lines in the document int totalLines = 0; // TODO: right now ignores selection printing for (unsigned int i = firstline; i <= lastline; ++i) { KateLineLayoutPtr rangeptr(new KateLineLayout(renderer)); rangeptr->setLine(i); renderer.layoutLine(rangeptr, (int)maxWidth, false); totalLines += rangeptr->viewLineCount(); } int totalPages = (totalLines / linesPerPage) + ((totalLines % linesPerPage) > 0 ? 1 : 0); // kDebug() << "_______ pages:" << (totalLines / linesPerPage); // kDebug() << "________ rest:" << (totalLines % linesPerPage); // TODO: add space for guide if required // if ( useGuide ) // _lt += (guideHeight + (fontHeight /2)) / fontHeight; // substitute both tag lists QString re("%P"); QStringList::Iterator it; for ( it=headerTagList.begin(); it!=headerTagList.end(); ++it ) (*it).replace( re, QString( "%1" ).arg( totalPages ) ); for ( it=footerTagList.begin(); it!=footerTagList.end(); ++it ) (*it).replace( re, QString( "%1" ).arg( totalPages ) ); } } // end prepare block /* On to draw something :-) */ while ( lineCount <= lastline ) { if ( y + fontHeight > maxHeight ) { kDebug(13020)<<"Starting new page,"<backgroundColor()); } if ( useBox ) { paint.setPen(QPen(boxColor, boxWidth)); paint.drawRect(0, 0, pdmWidth, pdmHeight); if (useHeader) paint.drawLine(0, headerHeight, headerWidth, headerHeight); else y += innerMargin; if ( useFooter ) // drawline is not trustable, grr. paint.fillRect( 0, maxHeight+innerMargin, headerWidth, boxWidth, boxColor ); } if ( useGuide && currentPage == 1 ) { // FIXME - this may span more pages... // draw a box unless we have boxes, in which case we end with a box line int _ystart = y; QString _hlName = doc->highlight()->name(); QList _attributes; // list of highlight attributes for the legend doc->highlight()->getKateExtendedAttributeList(kpl->colorScheme(), _attributes); KateAttributeList _defaultAttributes; KateHlManager::self()->getDefaults ( renderer.config()->schema(), _defaultAttributes ); QColor _defaultPen = _defaultAttributes.at(0)->foreground().color(); paint.setPen(_defaultPen); int _marg = 0; if ( useBox ) _marg += (2*boxWidth) + (2*innerMargin); else { if ( useBackground ) _marg += 2*innerMargin; _marg += 1; y += 1 + innerMargin; } // draw a title string QFont _titleFont = renderer.config()->font(); _titleFont.setBold(true); paint.setFont( _titleFont ); QRect _r; paint.drawText( QRect(_marg, y, pdmWidth-(2*_marg), maxHeight - y), Qt::AlignTop|Qt::AlignHCenter, i18n("Typographical Conventions for %1", _hlName ), &_r ); int _w = pdmWidth - (_marg*2) - (innerMargin*2); int _x = _marg + innerMargin; y += _r.height() + innerMargin; paint.drawLine( _x, y, _x + _w, y ); y += 1 + innerMargin; int _widest( 0 ); foreach (const KateExtendedAttribute::Ptr &attribute, _attributes) _widest = qMax(QFontMetrics(attribute->font()).width(attribute->name().section(':',1,1)), _widest); int _guideCols = _w/( _widest + innerMargin ); // draw attrib names using their styles int _cw = _w/_guideCols; int _i(0); _titleFont.setUnderline(true); QString _currentHlName; foreach (const KateExtendedAttribute::Ptr &attribute, _attributes) { QString _hl = attribute->name().section(':',0,0); QString _name = attribute->name().section(':',1,1); if ( _hl != _hlName && _hl != _currentHlName ) { _currentHlName = _hl; if ( _i%_guideCols ) y += fontHeight; y += innerMargin; paint.setFont(_titleFont); paint.setPen(_defaultPen); paint.drawText( _x, y, _w, fontHeight, Qt::AlignTop, _hl + ' ' + i18n("text") ); y += fontHeight; _i = 0; } KTextEditor::Attribute _attr = *_defaultAttributes[attribute->defaultStyleIndex()]; _attr += *attribute; paint.setPen( _attr.foreground().color() ); paint.setFont( _attr.font() ); if (_attr.hasProperty(QTextFormat::BackgroundBrush) ) { QRect _rect = QFontMetrics(_attr.font()).boundingRect(_name); _rect.moveTo(_x + ((_i%_guideCols)*_cw), y); paint.fillRect(_rect, _attr.background() ); } paint.drawText(( _x + ((_i%_guideCols)*_cw)), y, _cw, fontHeight, Qt::AlignTop, _name ); _i++; if ( _i && ! ( _i%_guideCols ) ) y += fontHeight; } if ( _i%_guideCols ) y += fontHeight;// last row not full // draw a box around the legend paint.setPen ( _defaultPen ); if ( useBox ) paint.fillRect( 0, y+innerMargin, headerWidth, boxWidth, boxColor ); else { _marg -=1; paint.drawRect( _marg, _ystart, pdmWidth-(2*_marg), y-_ystart+innerMargin ); } y += ( useBox ? boxWidth : 1 ) + (innerMargin*2); } // useGuide paint.translate(xstart,y); pageStarted = false; } // pageStarted; move on to contents:) if ( printLineNumbers /*&& ! startCol*/ ) // don't repeat! { paint.setFont( renderer.config()->font() ); paint.setPen( renderer.config()->lineNumberColor() ); paint.drawText( (( useBox || useBackground ) ? innerMargin : 0)-xstart, 0, lineNumberWidth, fontHeight, Qt::AlignRight, QString("%1").arg( lineCount + 1 ) ); } // HA! this is where we print [part of] a line ;]] // FIXME Convert this function + related functionality to a separate KatePrintView KateLineLayoutPtr rangeptr(new KateLineLayout(renderer)); rangeptr->setLine(lineCount); renderer.layoutLine(rangeptr, (int)maxWidth, false); // selectionOnly: clip non-selection parts and adjust painter position if needed int _xadjust = 0; if (selectionOnly) { if (doc->activeView()->blockSelection()) { int _x = renderer.cursorToX(rangeptr->viewLine(0), selectionRange.start()); int _x1 = renderer.cursorToX(rangeptr->viewLine(rangeptr->viewLineCount()-1), selectionRange.end()); _xadjust = _x; paint.translate(-_xadjust, 0); paint.setClipRegion(QRegion( _x, 0, _x1 - _x, rangeptr->viewLineCount()*fontHeight)); } else if (lineCount == firstline || lineCount == lastline) { QRegion region(0, 0, maxWidth, rangeptr->viewLineCount()*fontHeight); if ( lineCount == firstline) { region = region.subtracted(QRegion(0, 0, renderer.cursorToX(rangeptr->viewLine(0), selectionRange.start()), fontHeight)); } if (lineCount == lastline) { int _x = renderer.cursorToX(rangeptr->viewLine(rangeptr->viewLineCount()-1), selectionRange.end()); region = region.subtracted(QRegion(_x, 0, maxWidth-_x, fontHeight)); } paint.setClipRegion(region); } } // If the line is too long (too many 'viewlines') to fit the remaining vertical space, // clip and adjust the painter position as necessary int _lines = rangeptr->viewLineCount(); // number of "sublines" to paint. int proceedLines = _lines; if (remainder) { proceedLines = qMin((maxHeight - y) / fontHeight, remainder); paint.translate(0, -(_lines-remainder)*fontHeight+1); paint.setClipRect(0, (_lines-remainder)*fontHeight+1, maxWidth, proceedLines*fontHeight); //### drop the crosspatch in printerfriendly mode??? remainder -= proceedLines; } else if (y + fontHeight * _lines > maxHeight) { remainder = _lines - ((maxHeight-y)/fontHeight); paint.setClipRect(0, 0, maxWidth, (_lines-remainder)*fontHeight+1); //### drop the crosspatch in printerfriendly mode??? } renderer.paintTextLine(paint, rangeptr, 0, (int)maxWidth); paint.setClipping(false); paint.translate(_xadjust, (fontHeight * (_lines-remainder))); y += fontHeight * proceedLines; if ( ! remainder ) lineCount++; } // done lineCount <= lastline paint.end(); return true; } return false; } //END KatePrinter //BEGIN KatePrintTextSettings KatePrintTextSettings::KatePrintTextSettings( QWidget *parent ) : QWidget( parent ) { setWindowTitle( i18n("Te&xt Settings") ); QVBoxLayout *lo = new QVBoxLayout ( this ); cbLineNumbers = new QCheckBox( i18n("Print line &numbers"), this ); lo->addWidget( cbLineNumbers ); cbGuide = new QCheckBox( i18n("Print &legend"), this ); lo->addWidget( cbGuide ); lo->addStretch( 1 ); // set defaults - nothing to do :-) // whatsthis cbLineNumbers->setWhatsThis(i18n( "

If enabled, line numbers will be printed on the left side of the page(s).

") ); cbGuide->setWhatsThis(i18n( "

Print a box displaying typographical conventions for the document type, as " "defined by the syntax highlighting being used.

") ); readSettings(); } KatePrintTextSettings::~KatePrintTextSettings() { writeSettings(); } bool KatePrintTextSettings::printLineNumbers() { return cbLineNumbers->isChecked(); } bool KatePrintTextSettings::printGuide() { return cbGuide->isChecked(); } void KatePrintTextSettings::readSettings() { KSharedConfigPtr config = KGlobal::config(); KConfigGroup printGroup( config, "Kate Print Settings" ); KConfigGroup textGroup( &printGroup, "Text" ); bool isLineNumbersChecked = textGroup.readEntry( "LineNumbers", false ); cbLineNumbers->setChecked( isLineNumbersChecked ); bool isLegendChecked = textGroup.readEntry( "Legend", false ); cbGuide->setChecked( isLegendChecked ); } void KatePrintTextSettings::writeSettings() { KSharedConfigPtr config = KGlobal::config(); KConfigGroup printGroup( config, "Kate Print Settings" ); KConfigGroup textGroup( &printGroup, "Text" ); textGroup.writeEntry( "LineNumbers", printLineNumbers() ); textGroup.writeEntry( "Legend", printGuide() ); config->sync(); } //END KatePrintTextSettings //BEGIN KatePrintHeaderFooter KatePrintHeaderFooter::KatePrintHeaderFooter( QWidget *parent ) : QWidget( parent ) { setWindowTitle( i18n("Hea&der && Footer") ); QVBoxLayout *lo = new QVBoxLayout ( this ); // enable QHBoxLayout *lo1 = new QHBoxLayout (); lo->addLayout( lo1 ); cbEnableHeader = new QCheckBox( i18n("Pr&int header"), this ); lo1->addWidget( cbEnableHeader ); cbEnableFooter = new QCheckBox( i18n("Pri&nt footer"), this ); lo1->addWidget( cbEnableFooter ); // font QHBoxLayout *lo2 = new QHBoxLayout(); lo->addLayout( lo2 ); lo2->addWidget( new QLabel( i18n("Header/footer font:"), this ) ); lFontPreview = new QLabel( this ); lFontPreview->setFrameStyle( QFrame::Panel|QFrame::Sunken ); lo2->addWidget( lFontPreview ); lo2->setStretchFactor( lFontPreview, 1 ); QPushButton *btnChooseFont = new QPushButton( i18n("Choo&se Font..."), this ); lo2->addWidget( btnChooseFont ); connect( btnChooseFont, SIGNAL(clicked()), this, SLOT(setHFFont()) ); // header gbHeader = new QGroupBox( this ); gbHeader->setTitle(i18n("Header Properties")); QGridLayout* grid = new QGridLayout(gbHeader); lo->addWidget( gbHeader ); QLabel *lHeaderFormat = new QLabel( i18n("&Format:"), gbHeader ); grid->addWidget(lHeaderFormat, 0, 0); KHBox *hbHeaderFormat = new KHBox( gbHeader ); grid->addWidget(hbHeaderFormat, 0, 1); leHeaderLeft = new KLineEdit( hbHeaderFormat ); leHeaderCenter = new KLineEdit( hbHeaderFormat ); leHeaderRight = new KLineEdit( hbHeaderFormat ); lHeaderFormat->setBuddy( leHeaderLeft ); leHeaderLeft->setContextMenuPolicy(Qt::CustomContextMenu); leHeaderCenter->setContextMenuPolicy(Qt::CustomContextMenu); leHeaderRight->setContextMenuPolicy(Qt::CustomContextMenu); connect(leHeaderLeft, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); connect(leHeaderCenter, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); connect(leHeaderRight, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); grid->addWidget(new QLabel( i18n("Colors:"), gbHeader ), 1, 0); KHBox *hbHeaderColors = new KHBox( gbHeader ); grid->addWidget(hbHeaderColors, 1, 1); hbHeaderColors->setSpacing( -1 ); QLabel *lHeaderFgCol = new QLabel( i18n("Foreground:"), hbHeaderColors ); kcbtnHeaderFg = new KColorButton( hbHeaderColors ); lHeaderFgCol->setBuddy( kcbtnHeaderFg ); cbHeaderEnableBgColor = new QCheckBox( i18n("Bac&kground"), hbHeaderColors ); kcbtnHeaderBg = new KColorButton( hbHeaderColors ); gbFooter = new QGroupBox( this ); gbFooter->setTitle(i18n("Footer Properties")); grid = new QGridLayout(gbFooter); lo->addWidget( gbFooter ); // footer QLabel *lFooterFormat = new QLabel( i18n("For&mat:"), gbFooter ); grid->addWidget(lFooterFormat, 0, 0); KHBox *hbFooterFormat = new KHBox( gbFooter ); grid->addWidget(hbFooterFormat, 0, 1); hbFooterFormat->setSpacing( -1 ); leFooterLeft = new KLineEdit( hbFooterFormat ); leFooterCenter = new KLineEdit( hbFooterFormat ); leFooterRight = new KLineEdit( hbFooterFormat ); lFooterFormat->setBuddy( leFooterLeft ); leFooterLeft->setContextMenuPolicy(Qt::CustomContextMenu); leFooterCenter->setContextMenuPolicy(Qt::CustomContextMenu); leFooterRight->setContextMenuPolicy(Qt::CustomContextMenu); connect(leFooterLeft, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); connect(leFooterCenter, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); connect(leFooterRight, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); grid->addWidget(new QLabel( i18n("Colors:"), gbFooter ), 1, 0); KHBox *hbFooterColors = new KHBox( gbFooter ); grid->addWidget(hbFooterColors, 1, 1); hbFooterColors->setSpacing( -1 ); QLabel *lFooterBgCol = new QLabel( i18n("Foreground:"), hbFooterColors ); kcbtnFooterFg = new KColorButton( hbFooterColors ); lFooterBgCol->setBuddy( kcbtnFooterFg ); cbFooterEnableBgColor = new QCheckBox( i18n("&Background"), hbFooterColors ); kcbtnFooterBg = new KColorButton( hbFooterColors ); lo->addStretch( 1 ); // user friendly connect( cbEnableHeader, SIGNAL(toggled(bool)), gbHeader, SLOT(setEnabled(bool)) ); connect( cbEnableFooter, SIGNAL(toggled(bool)), gbFooter, SLOT(setEnabled(bool)) ); connect( cbHeaderEnableBgColor, SIGNAL(toggled(bool)), kcbtnHeaderBg, SLOT(setEnabled(bool)) ); connect( cbFooterEnableBgColor, SIGNAL(toggled(bool)), kcbtnFooterBg, SLOT(setEnabled(bool)) ); // set defaults cbEnableHeader->setChecked( true ); leHeaderLeft->setText( "%y" ); leHeaderCenter->setText( "%f" ); leHeaderRight->setText( "%p" ); kcbtnHeaderFg->setColor( QColor("black") ); cbHeaderEnableBgColor->setChecked( false ); kcbtnHeaderBg->setColor( QColor("lightgrey") ); cbEnableFooter->setChecked( true ); leFooterRight->setText( "%U" ); kcbtnFooterFg->setColor( QColor("black") ); cbFooterEnableBgColor->setChecked( false ); kcbtnFooterBg->setColor( QColor("lightgrey") ); // whatsthis QString s = i18n("

Format of the page header. The following tags are supported:

"); QString s1 = i18n( "
  • %u: current user name
  • " "
  • %d: complete date/time in short format
  • " "
  • %D: complete date/time in long format
  • " "
  • %h: current time
  • " "
  • %y: current date in short format
  • " "
  • %Y: current date in long format
  • " "
  • %f: file name
  • " "
  • %U: full URL of the document
  • " "
  • %p: page number
  • " "
  • %P: total amount of pages
  • " "

"); leHeaderRight->setWhatsThis(s + s1 ); leHeaderCenter->setWhatsThis(s + s1 ); leHeaderLeft->setWhatsThis(s + s1 ); s = i18n("

Format of the page footer. The following tags are supported:

"); leFooterRight->setWhatsThis(s + s1 ); leFooterCenter->setWhatsThis(s + s1 ); leFooterLeft->setWhatsThis(s + s1 ); readSettings(); } KatePrintHeaderFooter::~KatePrintHeaderFooter() { writeSettings(); } QFont KatePrintHeaderFooter::font() { return lFontPreview->font(); } bool KatePrintHeaderFooter::useHeader() { return cbEnableHeader->isChecked(); } QStringList KatePrintHeaderFooter::headerFormat() { QStringList l; l << leHeaderLeft->text() << leHeaderCenter->text() << leHeaderRight->text(); return l; } QColor KatePrintHeaderFooter::headerForeground() { return kcbtnHeaderFg->color(); } QColor KatePrintHeaderFooter::headerBackground() { return kcbtnHeaderBg->color(); } bool KatePrintHeaderFooter::useHeaderBackground() { return cbHeaderEnableBgColor->isChecked(); } bool KatePrintHeaderFooter::useFooter() { return cbEnableFooter->isChecked(); } QStringList KatePrintHeaderFooter::footerFormat() { QStringList l; l<< leFooterLeft->text() << leFooterCenter->text() << leFooterRight->text(); return l; } QColor KatePrintHeaderFooter::footerForeground() { return kcbtnFooterFg->color(); } QColor KatePrintHeaderFooter::footerBackground() { return kcbtnFooterBg->color(); } bool KatePrintHeaderFooter::useFooterBackground() { return cbFooterEnableBgColor->isChecked(); } void KatePrintHeaderFooter::setHFFont() { QFont fnt( lFontPreview->font() ); // display a font dialog if ( KFontDialog::getFont( fnt, KFontChooser::NoDisplayFlags, this ) == KFontDialog::Accepted ) { // set preview lFontPreview->setFont( fnt ); lFontPreview->setText( QString(fnt.family() + ", %1pt").arg( fnt.pointSize() ) ); } } void KatePrintHeaderFooter::showContextMenu(const QPoint& pos) { QLineEdit* lineEdit = qobject_cast(sender()); if (!lineEdit) { return; } QMenu* const contextMenu = lineEdit->createStandardContextMenu(); if (contextMenu == NULL) { return; } contextMenu->addSeparator(); // create original context menu QMenu* menu = contextMenu->addMenu(i18n("Add Placeholder...")); menu->setIcon(KIcon("list-add")); QAction* a = menu->addAction(i18n("Current User Name") + "\t%u"); a->setData("%u"); a = menu->addAction(i18n("Complete Date/Time (short format)") + "\t%d"); a->setData("%d"); a = menu->addAction(i18n("Complete Date/Time (long format)") + "\t%D"); a->setData("%D"); a = menu->addAction(i18n("Current Time") + "\t%h"); a->setData("%h"); a = menu->addAction(i18n("Current Date (short format)") + "\t%y"); a->setData("%y"); a = menu->addAction(i18n("Current Date (long format)") + "\t%Y"); a->setData("%Y"); a = menu->addAction(i18n("File Name") + "\t%f"); a->setData("%f"); a = menu->addAction(i18n("Full document URL") + "\t%U"); a->setData("%U"); a = menu->addAction(i18n("Page Number") + "\t%p"); a->setData("%p"); a = menu->addAction(i18n("Total Amount of Pages") + "\t%P"); a->setData("%P"); QAction* const result = contextMenu->exec(lineEdit->mapToGlobal(pos)); if (result) { QString placeHolder = result->data().toString(); if (!placeHolder.isEmpty()) { lineEdit->insert(placeHolder); } } } void KatePrintHeaderFooter::readSettings() { KSharedConfigPtr config = KGlobal::config(); KConfigGroup printGroup( config, "Kate Print Settings" ); // Header KConfigGroup headerFooterGroup( &printGroup, "HeaderFooter" ); bool isHeaderEnabledChecked = headerFooterGroup.readEntry( "HeaderEnabled", true ); cbEnableHeader->setChecked( isHeaderEnabledChecked ); QString headerFormatLeft = headerFooterGroup.readEntry( "HeaderFormatLeft", "%y" ); leHeaderLeft->setText( headerFormatLeft ); QString headerFormatCenter = headerFooterGroup.readEntry( "HeaderFormatCenter", "%f" ); leHeaderCenter->setText( headerFormatCenter ); QString headerFormatRight = headerFooterGroup.readEntry( "HeaderFormatRight", "%p" ); leHeaderRight->setText( headerFormatRight ); QColor headerForeground = headerFooterGroup.readEntry( "HeaderForeground", QColor("black") ); kcbtnHeaderFg->setColor( headerForeground ); bool isHeaderBackgroundChecked = headerFooterGroup.readEntry( "HeaderBackgroundEnabled", false ); cbHeaderEnableBgColor->setChecked( isHeaderBackgroundChecked ); QColor headerBackground = headerFooterGroup.readEntry( "HeaderBackground", QColor("lightgrey") ); kcbtnHeaderBg->setColor( headerBackground ); // Footer bool isFooterEnabledChecked = headerFooterGroup.readEntry( "FooterEnabled", true ); cbEnableFooter->setChecked( isFooterEnabledChecked ); QString footerFormatLeft = headerFooterGroup.readEntry( "FooterFormatLeft", QString() ); leFooterLeft->setText( footerFormatLeft ); QString footerFormatCenter = headerFooterGroup.readEntry( "FooterFormatCenter", QString() ); leFooterCenter->setText( footerFormatCenter ); QString footerFormatRight = headerFooterGroup.readEntry( "FooterFormatRight", "%U" ); leFooterRight->setText( footerFormatRight ); QColor footerForeground = headerFooterGroup.readEntry( "FooterForeground", QColor("black") ); kcbtnFooterFg->setColor( footerForeground ); bool isFooterBackgroundChecked = headerFooterGroup.readEntry( "FooterBackgroundEnabled", false ); cbFooterEnableBgColor->setChecked( isFooterBackgroundChecked ); QColor footerBackground = headerFooterGroup.readEntry( "FooterBackground", QColor("lightgrey") ); kcbtnFooterBg->setColor( footerBackground ); // Font QFont headerFooterFont = headerFooterGroup.readEntry( "HeaderFooterFont", QFont() ); lFontPreview->setFont( headerFooterFont ); lFontPreview->setText( QString(headerFooterFont.family() + ", %1pt").arg( headerFooterFont.pointSize() ) ); } void KatePrintHeaderFooter::writeSettings() { KSharedConfigPtr config = KGlobal::config(); KConfigGroup printGroup( config, "Kate Print Settings" ); // Header KConfigGroup headerFooterGroup( &printGroup, "HeaderFooter" ); headerFooterGroup.writeEntry( "HeaderEnabled", useHeader() ); QStringList format = headerFormat(); headerFooterGroup.writeEntry( "HeaderFormatLeft", format[0] ); headerFooterGroup.writeEntry( "HeaderFormatCenter", format[1] ); headerFooterGroup.writeEntry( "HeaderFormatRight", format[2] ); headerFooterGroup.writeEntry( "HeaderForeground", headerForeground() ); headerFooterGroup.writeEntry( "HeaderBackgroundEnabled", useHeaderBackground() ); headerFooterGroup.writeEntry( "HeaderBackground", headerBackground() ); // Footer headerFooterGroup.writeEntry( "FooterEnabled", useFooter() ); format = footerFormat(); headerFooterGroup.writeEntry( "FooterFormatLeft", format[0] ); headerFooterGroup.writeEntry( "FooterFormatCenter", format[1] ); headerFooterGroup.writeEntry( "FooterFormatRight", format[2] ); headerFooterGroup.writeEntry( "FooterForeground", footerForeground() ); headerFooterGroup.writeEntry( "FooterBackgroundEnabled", useFooterBackground() ); headerFooterGroup.writeEntry( "FooterBackground", footerBackground() ); // Font headerFooterGroup.writeEntry( "HeaderFooterFont", font() ); config->sync(); } //END KatePrintHeaderFooter //BEGIN KatePrintLayout KatePrintLayout::KatePrintLayout( QWidget *parent) : QWidget( parent ) { setWindowTitle( i18n("L&ayout") ); QVBoxLayout *lo = new QVBoxLayout ( this ); KHBox *hb = new KHBox( this ); lo->addWidget( hb ); QLabel *lSchema = new QLabel( i18n("&Schema:"), hb ); cmbSchema = new KComboBox( hb ); cmbSchema->setEditable( false ); lSchema->setBuddy( cmbSchema ); cbDrawBackground = new QCheckBox( i18n("Draw bac&kground color"), this ); lo->addWidget( cbDrawBackground ); cbEnableBox = new QCheckBox( i18n("Draw &boxes"), this ); lo->addWidget( cbEnableBox ); gbBoxProps = new QGroupBox( this ); gbBoxProps->setTitle(i18n("Box Properties")); QGridLayout* grid = new QGridLayout(gbBoxProps); lo->addWidget( gbBoxProps ); QLabel *lBoxWidth = new QLabel( i18n("W&idth:"), gbBoxProps ); grid->addWidget(lBoxWidth, 0, 0); sbBoxWidth = new KIntSpinBox( gbBoxProps ); sbBoxWidth->setRange( 1, 100 ); sbBoxWidth->setSingleStep( 1 ); grid->addWidget(sbBoxWidth, 0, 1); lBoxWidth->setBuddy( sbBoxWidth ); QLabel *lBoxMargin = new QLabel( i18n("&Margin:"), gbBoxProps ); grid->addWidget(lBoxMargin, 1, 0); sbBoxMargin = new KIntSpinBox( gbBoxProps ); sbBoxMargin->setRange( 0, 100 ); sbBoxMargin->setSingleStep( 1 ); grid->addWidget(sbBoxMargin, 1, 1); lBoxMargin->setBuddy( sbBoxMargin ); QLabel *lBoxColor = new QLabel( i18n("Co&lor:"), gbBoxProps ); grid->addWidget(lBoxColor, 2, 0); kcbtnBoxColor = new KColorButton( gbBoxProps ); grid->addWidget(kcbtnBoxColor, 2, 1); lBoxColor->setBuddy( kcbtnBoxColor ); connect( cbEnableBox, SIGNAL(toggled(bool)), gbBoxProps, SLOT(setEnabled(bool)) ); lo->addStretch( 1 ); // set defaults: sbBoxMargin->setValue( 6 ); gbBoxProps->setEnabled( false ); Q_FOREACH (const KateSchema &schema, KateGlobal::self()->schemaManager()->list()) cmbSchema->addItem (schema.translatedName(), QVariant (schema.rawName)); // default is printing, MUST BE THERE cmbSchema->setCurrentIndex (cmbSchema->findData (QVariant("Printing"))); // whatsthis cmbSchema->setWhatsThis(i18n( "Select the color scheme to use for the print." ) ); cbDrawBackground->setWhatsThis(i18n( "

If enabled, the background color of the editor will be used.

" "

This may be useful if your color scheme is designed for a dark background.

") ); cbEnableBox->setWhatsThis(i18n( "

If enabled, a box as defined in the properties below will be drawn " "around the contents of each page. The Header and Footer will be separated " "from the contents with a line as well.

") ); sbBoxWidth->setWhatsThis(i18n( "The width of the box outline" ) ); sbBoxMargin->setWhatsThis(i18n( "The margin inside boxes, in pixels") ); kcbtnBoxColor->setWhatsThis(i18n( "The line color to use for boxes") ); readSettings(); } KatePrintLayout::~KatePrintLayout() { writeSettings(); } QString KatePrintLayout::colorScheme() { return cmbSchema->itemData(cmbSchema->currentIndex()).toString(); } bool KatePrintLayout::useBackground() { return cbDrawBackground->isChecked(); } bool KatePrintLayout::useBox() { return cbEnableBox->isChecked(); } int KatePrintLayout::boxWidth() { return sbBoxWidth->value(); } int KatePrintLayout::boxMargin() { return sbBoxMargin->value(); } QColor KatePrintLayout::boxColor() { return kcbtnBoxColor->color(); } void KatePrintLayout::readSettings() { KSharedConfigPtr config = KGlobal::config(); KConfigGroup printGroup(config, "Kate Print Settings"); KConfigGroup layoutGroup(&printGroup, "Layout"); // get color schema back QString colorScheme = layoutGroup.readEntry( "ColorScheme", "Printing" ); int index = cmbSchema->findData (QVariant (colorScheme)); if (index != -1) cmbSchema->setCurrentIndex ( index ); bool isBackgroundChecked = layoutGroup.readEntry( "BackgroundColorEnabled", false ); cbDrawBackground->setChecked( isBackgroundChecked ); bool isBoxChecked = layoutGroup.readEntry( "BoxEnabled", false ); cbEnableBox->setChecked( isBoxChecked ); int boxWidth = layoutGroup.readEntry( "BoxWidth", 1 ); sbBoxWidth->setValue( boxWidth ); int boxMargin = layoutGroup.readEntry( "BoxMargin", 6 ); sbBoxMargin->setValue( boxMargin ); QColor boxColor = layoutGroup.readEntry( "BoxColor", QColor() ); kcbtnBoxColor->setColor( boxColor ); } void KatePrintLayout::writeSettings() { KSharedConfigPtr config = KGlobal::config(); KConfigGroup printGroup(config, "Kate Print Settings"); KConfigGroup layoutGroup(&printGroup, "Layout"); layoutGroup.writeEntry( "ColorScheme", colorScheme() ); layoutGroup.writeEntry( "BackgroundColorEnabled", useBackground() ); layoutGroup.writeEntry( "BoxEnabled", useBox() ); layoutGroup.writeEntry( "BoxWidth", boxWidth() ); layoutGroup.writeEntry( "BoxMargin", boxMargin() ); layoutGroup.writeEntry( "BoxColor", boxColor() ); config->sync(); } //END KatePrintLayout #include "moc_kateprinter.cpp" // kate: space-indent on; indent-width 2; replace-tabs on;