[Kde-print-devel] Open Printing Common Print Dialog

John Layt johnlayt at googlemail.com
Tue Jun 8 02:11:50 CEST 2010


On Monday 07 Jun 2010 19:00:03 you wrote:
> On Monday 07 June 2010 09:15:53 am you wrote:
> I agree with this.  Even though the work is fairly far along and there will
> be a big push through the end of the year there is still a lot that needs
> to be done.  The Open Printing plan calls for things to start appearing in
> distros in the spring of 2011.  This is sort half way between the release
> of 4.6 (Jan. 2011) and 4.7 (summer 2011) which implies that it needs to be
> in 4.6 to meet this time line.  This may be ambitious but if we have a
> little luck it might be possible.  But at the very least this should be
> far enough along to be a Tech Preview by that point.

Agreed.  If we're lucky and derive from Qt classes, an initial limited 
solution may even be API/BIC safe and so be able to be included and later 
changed.  If we try for inclusion directly in Qt that would only delay things 
further.

> This will not work for me but someone else from Open Printing may be able
> to attend.  I have CC'ed Till Kamppeter who is the main person at Open
> Printing and it may be possible for him or someone else closer to Finland
> to attend. I think it would be a very good idea to have someone demo the
> CPD and also work out any issues.  Also as this moves forward I would be
> more than happy to have you and others working on KDE and Qt review the
> work so that we know we are headed in the right direction.

If Akademy is not a option, then it might be possible to arrange other 
meetings.  Looks like you're USA based?  We don't have many people over that 
way, but there are a couple of top KDE guys who could be consulted.  I'm 
London based and between jobs so could easily arrange a visit to anyone Europe 
based.  Funding may even be available from the e.V. to arrange a sprint 
somewhere, I know they're keen to have the printing problem solved.

> This is the $64 question.  Right now it is setup like it will be part of
> KDE (IE. cmake build and so on).  So it could be dropped into the KDE
> source tree fairly easily.   From my perspective I am not sure if this is
> the best possible place since it would be even better if this was part of
> Qt since that would make it even less desktop centric.  I suspect that
> getting this into the Qt tree would be even more difficult than getting it
> into the KDE tree.  But I think that there may need to be some hooks in Qt
> even if the dialog resides somewhere else.

It would definitely be preferable for this to be in Qt, so all Qt apps benefit 
as well, and the maintenance load is in the hands of paid developers.  There 
are some noises coming out from Qt that they want to look at improving 
printing in Qt 4.9, but I have no knowledge when that might be.  On the minus 
side, getting printing stuff into Qt is slow work, as is getting bugs fixed, 
and we are dependent on their schedule and priorities.  However they are 
opening up more and more.

The Qt architecture is designed to allow 3rd parties to add their own print 
engines and dialogs for platforms or print systems Qt doesn't support, so if 
implemented that way it could live in KDE.  However I'm not sure anyone has 
actually done it and I suspect reality may not be so simple and we may find 
hooks are needed in Qt.  Getting small hooks into Qt may be easier than big 
changes.

When running Qt apps under KDE it's possible to intercept their calls to the 
Qt native dialogs and replace them with KDE dialogs (e.g. our file dialog), so 
that might work.

> It appears to be divided into a shared part that handles the basic D-Bus
> stuff and a part that implements the desktop specific parts (Qt and GTK). 
>  The dialogs do have lots of CUPS PPD related code since the contents of
> the dialog depend on what is in the PPD file.   I have just started
> looking at the code so I don't know for sure yet how it is actually
> structured.  Also I am not sure that the DBus stuff in the Qt dialog is
> actually setup to take full advantage of the related Qt classes.

If all the CUPS communication code is OPD implemented, that would be a good 
thing for a KDE based dialog, as all the Qt CUPS interface classes are private 
and couldn't be used.

Using QtDbus would be a good thing.

> At this point I think the biggest issue here is in the area of storing user
> configuration data (IE. default printer, printer settings and stuff like
> that). Since this has not yet been implemented on the Qt dialog the
> details will need to be worked out but I would like to keep this platform
> agnostic if possible. Keep in mind that I have just started looking at the
> code so there may be other platform differences issues that need to be
> resolved.

Saving Qt settings is something I have been thinking about, it's about point 4 
on my Qt todo list.  My basic plan is to use the QSettings class to serialise 
the QPrinter / QPrintDialog / QPrintEngine values into local config files 
(e.g. ~/.config on *nix), modify the X11 and Windows dialogs to save/load 
these, and integrate with the OSX settings system.  However this is something 
that relies on Qt implementing it, and I'm not sure how much can really be 
toolkit/platform agnostic.  It may be better to roll our own OPD-only code for 
now but decide on a shared location and format for the saved settings.

> This I am not sure about.  I will have a look at a KDE app to see how it
> prints and compare that to what the CPD expects.   I have been looking at
> the Qt classes related to printing and as you point out printing appears
> to be a lot like using a QPainter once the QPrinter is instantiated.  The
> CPD expects to get a PDF document and since the Qt print stuff can produce
> a PDF file as an option I don't think interfacing will be too difficult.

I can't really point you at a 'typical' KDE printing app, few have easy to 
read implementations, or don't use many features.  The QPrinter API is not 
particularly good, it puts a lot of unnecessary work onto the coder that 
requires more printing domain knowledge than necessary, and is missing many 
features (broken ranges, odd/even, etc).  A typical print function would look 
a bit like this:

void KApp::slotPrint()
{
    QPrinter printer;

    // Must do certain QPrinter setup before creating QPrintDialog
    // Do defaults for stuff like orientation, page size, page range etc.
    printer.setOrientation( m_document->orientation() );
    printer.setDocName( m_document->name() );

    // Optionally create the apps own tab to add to the dialog
    QWidget *printConfigWidget = new KAppPrintConfigWidget;

    // Create the dialog using the KDE API which adds some other KDE features
    QPrintDialog *printDialog = KdePrint::createPrintDialog( &printer,
                           QList<QWidget*>() << printConfigWidget, widget() );
    // In a Qt app it would be:
    // QPrintDialog *printDialog = new QPrintDialog( &printer );
    // printDialog->setOptionTabs( QList<QWidget*>() << printConfigWidget )

    // Set-up the dialog options

    // Set the available Print Range
    int lastPage = m_document->pageCount();
    printDialog->setMinMax( 1, lastPage );
    printDialog->setFromTo( 1, lastPage );

    // If the user has selected part of the document, then enable Selection
    if ( m_document->hasSelection() ) {
        printDialog->setOption( QAbstractPrintDialog::PrintSelection );
    }

    // Enable the Current Page option in the dialog.
    if ( lastPage > 1 && currentPage() > 0 ) {
        printDialog->setOption( QAbstractPrintDialog::PrintCurrentPage );
    }

    if ( printDialog->exec() ) {
        QPainter painter( &printer );

        if ( printer.printRange() == QPrinter::Selection) {

            m_document->printSelection( painter, printConfigWidget );

        } else {

            int startPage, endPage;

            if ( printer.printRange() == QPrinter::PageRange ) {
                startPage = printer.fromPage();
                endPage = printer.toPage();
            } else if ( printer.printRange() == QPrinter::CurrentPage) {
                startPage = currentPage();
                endPage = startPage;
            } else { //AllPages
                startPage = 1;
                endPage = lastPage;
            }

            for (int i = startPage; i <= endPage; i++ ) {
                // Print each required page,
                // Pass in the config widget to use those settings
                m_document->printPage( painter, printConfigWidget, i );
            }
        }

        // Terminate painting, send job to printer
        painter.end();
    }

    delete printDialog;
}

So ideally if derived from the Qt classes the CPD would be returned by the 
call to KdePrint::createPrintDialog() and the CPD would fall back to working 
with this un-modified code.

You can find at KdePrintDialog at:
  http://websvn.kde.org/trunk/KDE/kdelibs/kdeui/dialogs/kdeprintdialog.cpp?view=markup
Basically it adds tabs and widgets to QPrintDialog for various missing 
features if we detect CUPS is available.

> The CPD uses poppler to render the preview for both versions of the dialog.
> Also since poppler now supports color management it might be possible to
> implement client side printer color management as part of this work flow
> without too much difficulty and color managing the preview should be fairly
> easy to add since I have done this already with the poppler Qt4 demo app. 
> But this is clearly a secondary consideration.

Poppler is an optional runtime requirement for parts of KDE, Okular in 
particular, so that's something we're used to, but we would want to keep it 
optional for future restricted resource platforms (Symbian, Meego, etc).  I 
assume if poppler is not available the preview will be disabled?

Colour management is not something I know about, I'd have to defer to the 
experts.

> Yes I agree totally about deriving an interface class from the existing Qt
> classes.  This would make modifying apps to use the new dialog a very
> simple process and if done correctly it may only require some mods to Qt
> and the change would be transparent to apps.  But again this class would
> need to be part of Qt for this to work for Qt apps if KDE is not
> installed.

We might be able to get away with hosting it in KDE, but it really would take 
some detailed work to determine what if any hooks are needed in Qt.

The general outline would be to derive the CPD print dialog from QPrintDialog 
and the CPD backend interface could be derived from QPrintEngine (or a dummy 
null engine used).  The app would call the KdePrint::createPrintDialog() 
method which would detect if the CPD service is available and return either 
the CPD dialog using the CPD engine or the usual Qt dialog and engine for the 
current platform.  The app would then connect a few signals/slots between the 
dialog and the app to handle the call-backs (would that work with a common 
base class?).  It might then be possible for the app to carry on exactly as it 
currently does via the QPrinter API, other than having to implement the new 
slots to connect the signals to if it wants to use the preview.  When the 
dialog is closed, the CPD dialog would set the QPrinter settings to 'lie' to 
the app as needed (print all pages to PDF file?) and the CPD print engine 
could dispatch the job to the CPD backend.

It's kind-of messy and complex, but the advantage would be we keep the Qt 
based api and cross-platform support without major app changes, and it could 
well be entirely API/BIC safe if it changes or is moved to Qt.  On the other 
hand, I'm not sure it would work without a few extra hooks in Qt.

My less preferred option is the new KDE class and api not based on Qt to wrap 
the dbus calls, that uses QPrinter/QPainter to create the PDF to pass to the 
CPD.  This would be a KDE only solution and would require 2 printing paths in 
each app, so is less desirable.

What I'm not so clear on is how this would work for a Gnome app running under 
KDE, or a KDE app running under Gnome.  Is the thinking a Gnome app would 
still show the Gnome/Gtk version of the dialog, or use the KDE/Qt version via 
some daemon?  I think KDE apps would always have to use the KDE/Qt version due 
to the app config widgets?

Something else I need to mention is we also have a requirement to be able to 
print files directly, which I think CPD solves nicely.  The Okular document 
viewer prefers to send the original source file (pdf, ps, etc) directly to 
CUPS rather than rendering a lower quality version onto QPainter.  We just 
need to make sure it's easy for Okular to give CPD the name of the source file 
instead of a QPainter or a stream.  It would also be useful to have a command 
line program that takes any valid file, displays the print dialog, and then 
sends the result to CUPS (in other words a replacement for the KDE3 kprinter 
program).

> Also one other possible way to view this is that the CPD could be treated
> as the "native" print dialog on *nix systems so that the *nix printing
> system, which currently does not have a native print dialog, works more
> like Windows and OS/X systems when printing from Qt apps.  But I think
> this implies that the dialog, or at least the hooks to use the dialog, are
> part of Qt rather than KDE.

Yep, that's the other option, but very much a Qt dependent one.  It would 
enable us to implement the dialog ourselves and keep most of the code out of 
Qt and therefore be more flexible on that side.  Then Qt would only have to 
make a smaller change in Qt itself which might be more acceptable to them, 
while still keeping their X11 dialog as a fallback.  However there would be a 
longer delay before it can be used anywhere as they would wait for the CPD 
dialog to be finished, and then schedule for their following release.

I think a lot depends on the attitude of Qt and the direction they are willing 
to take.  In the meantime looking into a Qt derived dialog living in KDE seems 
the best option to make the deadline.

Cheers!

John.

P.S. Does CPD support LPR, or only CUPS?


More information about the Kde-print-devel mailing list