From 47d455dd55be855e4cc691c32f687f723d9247ee Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdegraphics@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- kviewshell/plugins/djvu/Makefile.am | 33 + kviewshell/plugins/djvu/djvumultipage.cpp | 357 +++ kviewshell/plugins/djvu/djvumultipage.desktop | 57 + kviewshell/plugins/djvu/djvumultipage.h | 149 ++ kviewshell/plugins/djvu/djvumultipage.kcfg | 18 + kviewshell/plugins/djvu/djvumultipage.rc | 15 + kviewshell/plugins/djvu/djvurenderer.cpp | 719 +++++ kviewshell/plugins/djvu/djvurenderer.h | 146 + .../kprintDialogPage_DJVUconversionoptions.cpp | 118 + .../djvu/kprintDialogPage_DJVUconversionoptions.h | 50 + ...tDialogPage_DJVUconversionoptions_basewidget.ui | 145 + .../djvu/kprintDialogPage_DJVUpageoptions.cpp | 119 + .../djvu/kprintDialogPage_DJVUpageoptions.h | 42 + kviewshell/plugins/djvu/libdjvu/Arrays.cpp | 305 +++ kviewshell/plugins/djvu/libdjvu/Arrays.h | 997 +++++++ kviewshell/plugins/djvu/libdjvu/BSByteStream.cpp | 465 ++++ kviewshell/plugins/djvu/libdjvu/BSByteStream.h | 275 ++ .../plugins/djvu/libdjvu/BSEncodeByteStream.cpp | 1010 +++++++ kviewshell/plugins/djvu/libdjvu/ByteStream.cpp | 1445 ++++++++++ kviewshell/plugins/djvu/libdjvu/ByteStream.h | 416 +++ kviewshell/plugins/djvu/libdjvu/DataPool.cpp | 1837 +++++++++++++ kviewshell/plugins/djvu/libdjvu/DataPool.h | 627 +++++ kviewshell/plugins/djvu/libdjvu/DjVmDir.cpp | 839 ++++++ kviewshell/plugins/djvu/libdjvu/DjVmDir.h | 451 ++++ kviewshell/plugins/djvu/libdjvu/DjVmDir0.cpp | 169 ++ kviewshell/plugins/djvu/libdjvu/DjVmDir0.h | 217 ++ kviewshell/plugins/djvu/libdjvu/DjVmDoc.cpp | 663 +++++ kviewshell/plugins/djvu/libdjvu/DjVmDoc.h | 274 ++ kviewshell/plugins/djvu/libdjvu/DjVmNav.cpp | 338 +++ kviewshell/plugins/djvu/libdjvu/DjVmNav.h | 146 + kviewshell/plugins/djvu/libdjvu/DjVuAnno.cpp | 1514 +++++++++++ kviewshell/plugins/djvu/libdjvu/DjVuAnno.h | 295 ++ kviewshell/plugins/djvu/libdjvu/DjVuDocEditor.cpp | 2193 +++++++++++++++ kviewshell/plugins/djvu/libdjvu/DjVuDocEditor.h | 460 ++++ kviewshell/plugins/djvu/libdjvu/DjVuDocument.cpp | 1845 +++++++++++++ kviewshell/plugins/djvu/libdjvu/DjVuDocument.h | 1071 ++++++++ kviewshell/plugins/djvu/libdjvu/DjVuDumpHelper.cpp | 353 +++ kviewshell/plugins/djvu/libdjvu/DjVuDumpHelper.h | 126 + kviewshell/plugins/djvu/libdjvu/DjVuErrorList.cpp | 174 ++ kviewshell/plugins/djvu/libdjvu/DjVuErrorList.h | 194 ++ kviewshell/plugins/djvu/libdjvu/DjVuFile.cpp | 2831 ++++++++++++++++++++ kviewshell/plugins/djvu/libdjvu/DjVuFile.h | 848 ++++++ kviewshell/plugins/djvu/libdjvu/DjVuFileCache.cpp | 272 ++ kviewshell/plugins/djvu/libdjvu/DjVuFileCache.h | 292 ++ kviewshell/plugins/djvu/libdjvu/DjVuGlobal.cpp | 255 ++ kviewshell/plugins/djvu/libdjvu/DjVuGlobal.h | 398 +++ .../plugins/djvu/libdjvu/DjVuGlobalMemory.cpp | 306 +++ kviewshell/plugins/djvu/libdjvu/DjVuImage.cpp | 1486 ++++++++++ kviewshell/plugins/djvu/libdjvu/DjVuImage.h | 449 ++++ kviewshell/plugins/djvu/libdjvu/DjVuInfo.cpp | 205 ++ kviewshell/plugins/djvu/libdjvu/DjVuInfo.h | 193 ++ kviewshell/plugins/djvu/libdjvu/DjVuMessage.cpp | 647 +++++ kviewshell/plugins/djvu/libdjvu/DjVuMessage.h | 135 + .../plugins/djvu/libdjvu/DjVuMessageLite.cpp | 478 ++++ kviewshell/plugins/djvu/libdjvu/DjVuMessageLite.h | 227 ++ kviewshell/plugins/djvu/libdjvu/DjVuNavDir.cpp | 237 ++ kviewshell/plugins/djvu/libdjvu/DjVuNavDir.h | 192 ++ kviewshell/plugins/djvu/libdjvu/DjVuPalette.cpp | 590 ++++ kviewshell/plugins/djvu/libdjvu/DjVuPalette.h | 339 +++ kviewshell/plugins/djvu/libdjvu/DjVuPort.cpp | 710 +++++ kviewshell/plugins/djvu/libdjvu/DjVuPort.h | 518 ++++ kviewshell/plugins/djvu/libdjvu/DjVuText.cpp | 971 +++++++ kviewshell/plugins/djvu/libdjvu/DjVuText.h | 281 ++ kviewshell/plugins/djvu/libdjvu/DjVuToPS.cpp | 2582 ++++++++++++++++++ kviewshell/plugins/djvu/libdjvu/DjVuToPS.h | 425 +++ kviewshell/plugins/djvu/libdjvu/GBitmap.cpp | 1658 ++++++++++++ kviewshell/plugins/djvu/libdjvu/GBitmap.h | 673 +++++ kviewshell/plugins/djvu/libdjvu/GContainer.cpp | 802 ++++++ kviewshell/plugins/djvu/libdjvu/GContainer.h | 1366 ++++++++++ kviewshell/plugins/djvu/libdjvu/GException.cpp | 284 ++ kviewshell/plugins/djvu/libdjvu/GException.h | 356 +++ kviewshell/plugins/djvu/libdjvu/GIFFManager.cpp | 663 +++++ kviewshell/plugins/djvu/libdjvu/GIFFManager.h | 394 +++ kviewshell/plugins/djvu/libdjvu/GMapAreas.cpp | 1066 ++++++++ kviewshell/plugins/djvu/libdjvu/GMapAreas.h | 565 ++++ kviewshell/plugins/djvu/libdjvu/GOS.cpp | 370 +++ kviewshell/plugins/djvu/libdjvu/GOS.h | 161 ++ kviewshell/plugins/djvu/libdjvu/GPixmap.cpp | 1676 ++++++++++++ kviewshell/plugins/djvu/libdjvu/GPixmap.h | 531 ++++ kviewshell/plugins/djvu/libdjvu/GRect.cpp | 458 ++++ kviewshell/plugins/djvu/libdjvu/GRect.h | 407 +++ kviewshell/plugins/djvu/libdjvu/GScaler.cpp | 706 +++++ kviewshell/plugins/djvu/libdjvu/GScaler.h | 321 +++ kviewshell/plugins/djvu/libdjvu/GSmartPointer.cpp | 256 ++ kviewshell/plugins/djvu/libdjvu/GSmartPointer.h | 489 ++++ kviewshell/plugins/djvu/libdjvu/GString.cpp | 2811 +++++++++++++++++++ kviewshell/plugins/djvu/libdjvu/GString.h | 1676 ++++++++++++ kviewshell/plugins/djvu/libdjvu/GThreads.cpp | 1887 +++++++++++++ kviewshell/plugins/djvu/libdjvu/GThreads.h | 639 +++++ kviewshell/plugins/djvu/libdjvu/GURL.cpp | 1965 ++++++++++++++ kviewshell/plugins/djvu/libdjvu/GURL.h | 446 +++ kviewshell/plugins/djvu/libdjvu/GUnicode.cpp | 790 ++++++ kviewshell/plugins/djvu/libdjvu/IFFByteStream.cpp | 558 ++++ kviewshell/plugins/djvu/libdjvu/IFFByteStream.h | 312 +++ .../plugins/djvu/libdjvu/IW44EncodeCodec.cpp | 1797 +++++++++++++ kviewshell/plugins/djvu/libdjvu/IW44Image.cpp | 1935 +++++++++++++ kviewshell/plugins/djvu/libdjvu/IW44Image.h | 761 ++++++ kviewshell/plugins/djvu/libdjvu/JB2EncodeCodec.cpp | 564 ++++ kviewshell/plugins/djvu/libdjvu/JB2Image.cpp | 1427 ++++++++++ kviewshell/plugins/djvu/libdjvu/JB2Image.h | 805 ++++++ kviewshell/plugins/djvu/libdjvu/JPEGDecoder.cpp | 413 +++ kviewshell/plugins/djvu/libdjvu/JPEGDecoder.h | 133 + kviewshell/plugins/djvu/libdjvu/MMRDecoder.cpp | 961 +++++++ kviewshell/plugins/djvu/libdjvu/MMRDecoder.h | 238 ++ kviewshell/plugins/djvu/libdjvu/MMX.cpp | 209 ++ kviewshell/plugins/djvu/libdjvu/MMX.h | 194 ++ kviewshell/plugins/djvu/libdjvu/Makefile.am | 18 + kviewshell/plugins/djvu/libdjvu/README.djvulibre | 85 + kviewshell/plugins/djvu/libdjvu/Template.h | 258 ++ .../plugins/djvu/libdjvu/UnicodeByteStream.cpp | 368 +++ .../plugins/djvu/libdjvu/UnicodeByteStream.h | 199 ++ kviewshell/plugins/djvu/libdjvu/XMLParser.cpp | 1128 ++++++++ kviewshell/plugins/djvu/libdjvu/XMLParser.h | 123 + kviewshell/plugins/djvu/libdjvu/XMLTags.cpp | 417 +++ kviewshell/plugins/djvu/libdjvu/XMLTags.h | 242 ++ kviewshell/plugins/djvu/libdjvu/ZPCodec.cpp | 1292 +++++++++ kviewshell/plugins/djvu/libdjvu/ZPCodec.h | 747 ++++++ kviewshell/plugins/djvu/libdjvu/configure.in.in | 674 +++++ kviewshell/plugins/djvu/libdjvu/debug.cpp | 299 +++ kviewshell/plugins/djvu/libdjvu/debug.h | 304 +++ kviewshell/plugins/djvu/pageRangeWidget.cpp | 68 + kviewshell/plugins/djvu/pageRangeWidget.h | 45 + kviewshell/plugins/djvu/pageRangeWidget_base.ui | 75 + kviewshell/plugins/djvu/prefs.kcfgc | 5 + 124 files changed, 76604 insertions(+) create mode 100644 kviewshell/plugins/djvu/Makefile.am create mode 100644 kviewshell/plugins/djvu/djvumultipage.cpp create mode 100644 kviewshell/plugins/djvu/djvumultipage.desktop create mode 100644 kviewshell/plugins/djvu/djvumultipage.h create mode 100644 kviewshell/plugins/djvu/djvumultipage.kcfg create mode 100644 kviewshell/plugins/djvu/djvumultipage.rc create mode 100644 kviewshell/plugins/djvu/djvurenderer.cpp create mode 100644 kviewshell/plugins/djvu/djvurenderer.h create mode 100644 kviewshell/plugins/djvu/kprintDialogPage_DJVUconversionoptions.cpp create mode 100644 kviewshell/plugins/djvu/kprintDialogPage_DJVUconversionoptions.h create mode 100644 kviewshell/plugins/djvu/kprintDialogPage_DJVUconversionoptions_basewidget.ui create mode 100644 kviewshell/plugins/djvu/kprintDialogPage_DJVUpageoptions.cpp create mode 100644 kviewshell/plugins/djvu/kprintDialogPage_DJVUpageoptions.h create mode 100644 kviewshell/plugins/djvu/libdjvu/Arrays.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/Arrays.h create mode 100644 kviewshell/plugins/djvu/libdjvu/BSByteStream.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/BSByteStream.h create mode 100644 kviewshell/plugins/djvu/libdjvu/BSEncodeByteStream.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/ByteStream.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/ByteStream.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DataPool.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DataPool.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVmDir.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVmDir.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVmDir0.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVmDir0.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVmDoc.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVmDoc.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVmNav.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVmNav.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuAnno.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuAnno.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuDocEditor.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuDocEditor.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuDocument.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuDocument.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuDumpHelper.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuDumpHelper.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuErrorList.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuErrorList.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuFile.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuFile.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuFileCache.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuFileCache.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuGlobal.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuGlobal.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuGlobalMemory.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuImage.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuImage.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuInfo.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuInfo.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuMessage.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuMessage.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuMessageLite.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuMessageLite.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuNavDir.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuNavDir.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuPalette.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuPalette.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuPort.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuPort.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuText.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuText.h create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuToPS.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/DjVuToPS.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GBitmap.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GBitmap.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GContainer.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GContainer.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GException.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GException.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GIFFManager.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GIFFManager.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GMapAreas.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GMapAreas.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GOS.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GOS.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GPixmap.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GPixmap.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GRect.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GRect.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GScaler.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GScaler.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GSmartPointer.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GSmartPointer.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GString.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GString.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GThreads.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GThreads.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GURL.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/GURL.h create mode 100644 kviewshell/plugins/djvu/libdjvu/GUnicode.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/IFFByteStream.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/IFFByteStream.h create mode 100644 kviewshell/plugins/djvu/libdjvu/IW44EncodeCodec.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/IW44Image.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/IW44Image.h create mode 100644 kviewshell/plugins/djvu/libdjvu/JB2EncodeCodec.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/JB2Image.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/JB2Image.h create mode 100644 kviewshell/plugins/djvu/libdjvu/JPEGDecoder.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/JPEGDecoder.h create mode 100644 kviewshell/plugins/djvu/libdjvu/MMRDecoder.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/MMRDecoder.h create mode 100644 kviewshell/plugins/djvu/libdjvu/MMX.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/MMX.h create mode 100644 kviewshell/plugins/djvu/libdjvu/Makefile.am create mode 100644 kviewshell/plugins/djvu/libdjvu/README.djvulibre create mode 100644 kviewshell/plugins/djvu/libdjvu/Template.h create mode 100644 kviewshell/plugins/djvu/libdjvu/UnicodeByteStream.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/UnicodeByteStream.h create mode 100644 kviewshell/plugins/djvu/libdjvu/XMLParser.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/XMLParser.h create mode 100644 kviewshell/plugins/djvu/libdjvu/XMLTags.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/XMLTags.h create mode 100644 kviewshell/plugins/djvu/libdjvu/ZPCodec.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/ZPCodec.h create mode 100644 kviewshell/plugins/djvu/libdjvu/configure.in.in create mode 100644 kviewshell/plugins/djvu/libdjvu/debug.cpp create mode 100644 kviewshell/plugins/djvu/libdjvu/debug.h create mode 100644 kviewshell/plugins/djvu/pageRangeWidget.cpp create mode 100644 kviewshell/plugins/djvu/pageRangeWidget.h create mode 100644 kviewshell/plugins/djvu/pageRangeWidget_base.ui create mode 100644 kviewshell/plugins/djvu/prefs.kcfgc (limited to 'kviewshell/plugins/djvu') diff --git a/kviewshell/plugins/djvu/Makefile.am b/kviewshell/plugins/djvu/Makefile.am new file mode 100644 index 00000000..c0124821 --- /dev/null +++ b/kviewshell/plugins/djvu/Makefile.am @@ -0,0 +1,33 @@ +INCLUDES = -I$(top_srcdir) $(all_includes) \ + -I$(top_srcdir)/kviewshell \ + -I$(top_builddir)/kviewshell \ + -I$(kde_includes)/kviewshell \ + -I$(srcdir)/libdjvu + +SUBDIRS = libdjvu . + +KDE_CXXFLAGS = -Wno-deprecated + +METASOURCES = AUTO + +# this is where the desktop file will go +kde_services_DATA = djvumultipage.desktop + +# this is where the shell's XML-GUI resource file goes +shellrcdir = $(kde_datadir)/kviewshell/plugins/djvu + +kde_module_LTLIBRARIES = djvuviewpart.la +djvuviewpart_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module +djvuviewpart_la_LIBADD = -lkdeprint -lkparts $(top_builddir)/kviewshell/libkmultipage.la libdjvu/libdjvu.la +djvuviewpart_la_SOURCES = djvumultipage.cpp djvurenderer.cpp kprintDialogPage_DJVUpageoptions.cpp \ + kprintDialogPage_DJVUconversionoptions.cpp kprintDialogPage_DJVUconversionoptions_basewidget.ui \ + pageRangeWidget_base.ui pageRangeWidget.cpp \ + prefs.kcfgc + +kde_kcfg_DATA = djvumultipage.kcfg + +pluginsdir = $(kde_datadir) +plugins_DATA = djvumultipage.rc + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/kdjview.pot diff --git a/kviewshell/plugins/djvu/djvumultipage.cpp b/kviewshell/plugins/djvu/djvumultipage.cpp new file mode 100644 index 00000000..2599cc29 --- /dev/null +++ b/kviewshell/plugins/djvu/djvumultipage.cpp @@ -0,0 +1,357 @@ +/*************************************************************************** + * Copyright (C) 2005 by Stefan Kebekus * + * kebekus@kde.org * + * * + * Copyright (C) 2005 by Wilfried Huss * + * Wilfried.Huss@gmx.at * + * * + * This program 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 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "kvsprefs.h" +#include +#include +#include +#include + +#include "ByteStream.h" +#include "DjVuToPS.h" +#include "kprintDialogPage_DJVUpageoptions.h" +#include "kprintDialogPage_DJVUconversionoptions.h" +#include "djvumultipage.h" +#include "pageRangeWidget.h" +#include "prefs.h" + +#include "kmessagebox.h" + +typedef KParts::GenericFactory DjVuMultiPageFactory; +K_EXPORT_COMPONENT_FACTORY(djvuviewpart, DjVuMultiPageFactory) + + +DjVuMultiPage::DjVuMultiPage(QWidget *parentWidget, const char *widgetName, QObject *parent, + const char *name, const QStringList&) + : KMultiPage(parentWidget, widgetName, parent, name), djvuRenderer(parentWidget) +{ + /* This is kparts wizardry that cannot be understood by man. Simply + change the names to match your implementation. */ + setInstance(DjVuMultiPageFactory::instance()); + djvuRenderer.setName("DjVu renderer"); + + // Render modes + QStringList renderModes; + renderModes.append(i18n("Color")); + renderModes.append(i18n("Black and White")); + renderModes.append(i18n("Show foreground only")); + renderModes.append(i18n("Show background only")); + renderModeAction = new KSelectAction (i18n("Render Mode"), 0, 0, 0, actionCollection(), "render_mode"); + renderModeAction->setItems(renderModes); + + renderModeAction->setCurrentItem(Prefs::renderMode()); + + deletePagesAction = new KAction(i18n("Delete Pages..."), 0, this, SLOT(slotDeletePages()), actionCollection(), "delete_pages"); + + // change the rendermode + connect(renderModeAction, SIGNAL(activated(int)), this, SLOT(setRenderMode(int))); + + /* It is very important that this method is called in the + constructor. Otherwise kmultipage does not know how to render + files, and crashes may result. */ + setRenderer(&djvuRenderer); + + setXMLFile("djvumultipage.rc"); + + enableActions(false); +} + + +DjVuMultiPage::~DjVuMultiPage() +{ + ; +} + + +KAboutData* DjVuMultiPage::createAboutData() +{ + /* You obviously want to change this to match your setup */ + KAboutData* about = new KAboutData("djvumultipage", I18N_NOOP("KDjView"), "0.1", + I18N_NOOP("KViewshell DjVu Plugin."), + KAboutData::License_GPL, + "Wilfried Huss", + I18N_NOOP("This program displays DjVu files.")); + + about->addAuthor ("Stefan Kebekus", + I18N_NOOP("KViewShell plugin"), + "kebekus@kde.org", + "http://www.mi.uni-koeln.de/~kebekus"); + + about->addAuthor ("Wilfried Huss", + I18N_NOOP("DjVu file loading"), + "Wilfried.Huss@gmx.at"); + + return about; +} + +void DjVuMultiPage::enableActions(bool b) +{ + KMultiPage::enableActions(b); + + deletePagesAction->setEnabled(b); +} + +void DjVuMultiPage::setFile(bool r) +{ + enableActions(r); +} + +QStringList DjVuMultiPage::fileFormats() const +{ + /* This list is used in the file selection dialog when the file is + saved */ + QStringList r; + r << i18n("*.djvu|DjVu file (*.djvu)"); + return r; +} + + +void DjVuMultiPage::setRenderMode(int mode) +{ + // Save renderMode for future uses + switch (mode) + { + case Prefs::EnumRenderMode::BlackAndWhite: + Prefs::setRenderMode(Prefs::EnumRenderMode::BlackAndWhite); + + break; + case Prefs::EnumRenderMode::Foreground: + Prefs::setRenderMode(Prefs::EnumRenderMode::Foreground); + + break; + case Prefs::EnumRenderMode::Background: + Prefs::setRenderMode(Prefs::EnumRenderMode::Background); + + break; + default: //Prefs::EnumRenderMode::Color + Prefs::setRenderMode(Prefs::EnumRenderMode::Color); + } + Prefs::writeConfig(); + renderModeChanged(); +} + + +void DjVuMultiPage::slotDeletePages() +{ + if (numberOfPages() == 0) + return; + + KDialogBase dialog( parentWdg, "urldialog", true, i18n("Delete Pages"), KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true ); + PageRangeWidget range( 1, numberOfPages(), currentPageNumber(), &dialog, "range widget" ); + QToolTip::add( &range, i18n( "Select the pages you wish to delete." ) ); + dialog.setButtonOK(i18n("Delete Pages")); + dialog.setMainWidget(&range); + if (dialog.exec() != QDialog::Accepted) + return; + + djvuRenderer.deletePages(range.getFrom(), range.getTo()); + + + // ========= + pageCache->deselectText(); + document_history.clear(); + pageCache->clear(); + + generateDocumentWidgets(); + + // Set number of widgets in the thumbnail sidebar + markList()->clear(); + markList()->setNumberOfPages(numberOfPages(), KVSPrefs::showThumbnails()); + + // Set Table of Contents + //@@@@@@@@@@ tableOfContents->setContents(renderer->getBookmarks()); + + // Clear Statusbar + emit setStatusBarText(QString::null); +} + + +void DjVuMultiPage::print() +{ + // Paranoid safety checks + if (djvuRenderer.isEmpty()) + return; + + // Allocate the printer structure + KPrinter *printer = getPrinter(false); + if (printer == 0) + return; + + KPrintDialogPage_DJVUPageOptions *pageOptions = new KPrintDialogPage_DJVUPageOptions(); + if (pageOptions == 0) { + kdError(1223) << "DjVuMultiPage::print(): Cannot allocate new KPrintDialogPage_PageOptions structure" << endl; + delete printer; + return; + } + printer->addDialogPage( pageOptions ); + + KPrintDialogPage_DJVUConversionOptions *conversionOptions = new KPrintDialogPage_DJVUConversionOptions(); + if (pageOptions == 0) { + kdError(1223) << "DjVuMultiPage::print(): Cannot allocate new KPrintDialogPage_ConversionOptions structure" << endl; + delete printer; + return; + } + printer->addDialogPage( conversionOptions ); + + // initialize the printer using the print dialog + if ( printer->setup(parentWdg, i18n("Print %1").arg(m_file.section('/', -1))) ) { + // Now do the printing. + QValueList pageList = printer->pageList(); + if (pageList.isEmpty()) + printer->abort(); + else { + // Printing usually takes a while. This is to keep the GUI + // updated. + qApp->processEvents(); + + // Printing... + DjVuToPS converter; + DjVuToPS::Options &options = converter.options; + + // Set PostScript Language Level, taking 3 as the default + options.set_format(DjVuToPS::Options::PS); + QString op = printer->option( "kde-kdjvu-pslevel" ); + if (op == "1") + options.set_level(1); + else + if (op == "3") + options.set_level(3); + else + options.set_level(2); + + // Set page size orientation + if (printer->option( "kde-kviewshell-rotatepage" ) == "true") + options.set_orientation (DjVuToPS::Options::AUTO); + else + if ( printer->orientation() == KPrinter::Landscape ) + options.set_orientation (DjVuToPS::Options::LANDSCAPE); + else + options.set_orientation (DjVuToPS::Options::PORTRAIT); + + // Set render mode, taking "color" as default + op = printer->option("kde-kdjvu-rendermode"); + if (op == "black-and-white") + options.set_mode(DjVuToPS::Options::BW); + else + if (op == "foreground") + options.set_mode(DjVuToPS::Options::FORE); + else + if (op == "background") + options.set_mode(DjVuToPS::Options::BACK); + else + options.set_mode(DjVuToPS::Options::COLOR); + + // Set Color or Grayscale mode + if (printer->colorMode() == KPrinter::Color) + options.set_color(true); + else + options.set_color(false); + + // Set Zoom + if (printer->option( "kde-kdjvu-fitpage" ) == "true") + options.set_zoom(0); + else + options.set_zoom(100); + + KTempFile tmpPSFile(QString::null, "ps"); + tmpPSFile.close(); + tmpPSFile.setAutoDelete(true); + + if (djvuRenderer.convertToPSFile(converter, tmpPSFile.name(), pageList ) == true) + printer->printFiles( QStringList(tmpPSFile.name()), true ); + else + printer->abort(); + } + delete printer; + } +} + + +bool DjVuMultiPage::isReadWrite() const +{ + return true; +} + + +bool DjVuMultiPage::isModified() const +{ + return djvuRenderer.isModified(); +} + + +void DjVuMultiPage::slotSave() +{ + // Paranoid safety checks + if (djvuRenderer.isEmpty()) + return; + + // Try to guess the proper ending... + QString formats; + QString ending; + int rindex = m_file.findRev("."); + if (rindex == -1) { + ending = QString::null; + formats = QString::null; + } else { + ending = m_file.mid(rindex); // e.g. ".dvi" + formats = fileFormats().grep(ending).join("\n"); + } + + QString fileName = KFileDialog::getSaveFileName(QString::null, formats, 0, i18n("Save File As")); + + if (fileName.isEmpty()) + return; + + // Add the ending to the filename. I hope the user likes it that + // way. + if (!ending.isEmpty() && fileName.find(ending) == -1) + fileName = fileName+ending; + + if (QFile(fileName).exists()) { + int r = KMessageBox::warningContinueCancel(parentWdg, i18n("The file %1\nalready exists. Do you want to overwrite it?").arg(fileName), + i18n("Overwrite File"), i18n("Overwrite")); + if (r == KMessageBox::Cancel) + return; + } + + djvuRenderer.save(fileName); + + /* + if (!djvuRenderer.save(fileName) == false) + KMessageBox::error( parentWdg, + i18n("File error. Unable to write to the specified file '%1'. The document is not saved.").arg(fileName), + i18n("File Error")); + */ + + return; +} + + + +#include "djvumultipage.moc" diff --git a/kviewshell/plugins/djvu/djvumultipage.desktop b/kviewshell/plugins/djvu/djvumultipage.desktop new file mode 100644 index 00000000..1de46b47 --- /dev/null +++ b/kviewshell/plugins/djvu/djvumultipage.desktop @@ -0,0 +1,57 @@ +[Desktop Entry] +Name=kdjview +Name[hu]=KDjView +Name[ja]=Kdjview +Name[ne]=केडीजे दृश्य +Name[sk]=kdjView +Name[sv]=Kdjview +Name[zh_CN]=KDjView +Icon=kdjview +Type=Service +Comment=KViewShell plugin for DjVu files +Comment[bg]=Приставка за файлове DjVu +Comment[br]=Lugent KViewShell evit ar restroù DjVu +Comment[bs]=KViewShell dodatak za DjVu datoteke +Comment[ca]=Connector pel KViewShell per fitxers DjVu +Comment[cs]=KViewShell modul pro DjVu soubory +Comment[da]=Kviewshell-plugin for DjVu-filer +Comment[de]=Ein KViewShell-Modul für DjVu-Dateien +Comment[el]=Πρόσθετο του KViewShell για αρχεία DjVu +Comment[es]=Extensión KViewShell para archivos DjVu +Comment[et]=KView DjVu-failide plugin +Comment[eu]=DjVu fitxategien KViewShell-en plugina +Comment[fa]=وصلۀ KViewShell برای پرونده‌های DjVu +Comment[fi]=KViewShell sovelma DjVu-tiedostoille +Comment[fr]=Module KViewShell pour les fichiers DjVu +Comment[gl]=Extensión de KViewShell para ficheiros DjVu +Comment[hu]=KViewShell-modul DjVu-fájlokhoz +Comment[is]=KViewShell íforrit fyrir DjVu skrár +Comment[it]=Plugin KViewShell per file DjVu +Comment[ja]=DjVu ファイル用の KViewShell プラグイン +Comment[kk]=DjVu файлдарына арналған KViewShell плагин модулі +Comment[km]=កម្មវិធី​ជំនួយ KViewShell សម្រាប់​ឯកសារ DjVu +Comment[lt]=KViewShell priedas, skirtas DjVu byloms +Comment[ms]=Plugin KViewShell untuk fail DjVu +Comment[nb]=KViewShell programtillegg for DjVu-filer +Comment[nds]=En "KViewShell"-Moduul för DjVu-Dateien +Comment[ne]=डिजे भीयू फाइलका लागि केडीई दृश्य शेल प्लगइन +Comment[nl]=KViewShell-plugin voor DjVu-bestanden +Comment[nn]=KViewShell-programtillegg for DjVu-filer +Comment[pl]=Wtyczka KViewShell do plików DjVu +Comment[pt]='Plugin' do KViewShell para ficheiros do DjVu +Comment[pt_BR]=Plugin KViewShell para arquivos DjVu +Comment[ru]=Компонент просмотра файлов DjVu +Comment[sk]=KViewShell modul pre DjVu súbory +Comment[sl]=Vstavek za KViewShell za datoteke DjVu +Comment[sr]=KViewShell-ов прикључак за DjVu фајлове +Comment[sr@Latn]=KViewShell-ov priključak za DjVu fajlove +Comment[sv]=Kviewshell-insticksprogram för DjVu-filer +Comment[tr]=DjVu dosyaları için KViewShell eklentisi +Comment[uk]=Втулок перегляду файлів DjVu для KViewShell +Comment[zh_CN]=DjVu 文件的 KViewShell 插件 +Comment[zh_HK]=用於 DjVu 檔案的 KViewShell 插件 +Comment[zh_TW]=DjVu 檔的 KViewShell 外掛程式 +ServiceTypes=KViewShell/MultiPage +X-KDE-MimeTypes=image/x-djvu +X-KDE-Library=djvuviewpart +X-KDE-MultiPageVersion=2 diff --git a/kviewshell/plugins/djvu/djvumultipage.h b/kviewshell/plugins/djvu/djvumultipage.h new file mode 100644 index 00000000..b417144b --- /dev/null +++ b/kviewshell/plugins/djvu/djvumultipage.h @@ -0,0 +1,149 @@ +/*************************************************************************** + * Copyright (C) 2005 by Stefan Kebekus * + * kebekus@kde.org * + * * + * Copyright (C) 2005 by Wilfried Huss * + * Wilfried.Huss@gmx.at * + * * + * This program 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 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef __DJVUMULTIPAGE_H +#define __DJVUMULTIPAGE_H + +#include + +#include "kmultipage.h" +#include "djvurenderer.h" + +#include "DjVuToPS.h" + +class KSelectAction; + +/*! \mainpage DjVuMultiPage + +\section intro_sec Introduction + +kvsdemo is a minimal, but well-documented reference implementation of +a kviewshell plugin that can serve as a starting point for a +real-world implementation. + +\section install_sec Usage + +When kvsdemo is installed, the kviewshell program can open C++ source +files, i.e. files of mime type text/x-c++src. When such a file is +loaded, kviewshell shows 10 blank pages of A4 size. + +\section content Content + +Only the two classes that are absolutely necessary for a working +plugin are implemented. The only other file that is installed is a +desktop file, which tells kviewhshell to use the plugin. + +- kvsdemo_multipage, an implementation of a kmultipage. In a real +application, this class would create and manage the GUI elements that +the plugin adds to the GUI of the kviewshell. This implementation adds +nothing, and does only the minimal initialization required.. + +- kvsdemo_renderer, an implementation of a documentRenderer. This +class is responsible for document loading and rendering. + +- kvsdemo.desktop, the desktop entry file that tells KDE that kvsdemo +is a plugin for kviewshell that handles files of type +text/x-c++src. Without this file installed, the file dialog in +kviewshell would not show C++ source files, and the command line +"kvieshell test.cpp" would fail with an error dialog "No plugin for +text/x-c++src files installed". + +*/ + + + + +/*! \brief Well-documented minimal implementation of a KMultiPage + +This class provides a well-documented reference implementation of a +KMultiPage, suitable as a starting point for a real-world +implementation. In a real application, this class would contain the +GUI elements that the plugin adds to the GUI of the kviewshell. Our +implementation adds nothing, and does only the minimal initialization +required. + +*/ + +class DjVuMultiPage : public KMultiPage +{ + Q_OBJECT + +public: + /** Constructor + + The constructor needs to initialize several members of the + kmultipage. Please have a look at the constructor's source code to + see how to adjust this for your implementation. + */ + DjVuMultiPage(QWidget *parentWidget, const char *widgetName, QObject *parent, + const char *name, const QStringList& args = QStringList()); + + /** Destructor + + This destructor does nothing. + */ + virtual ~DjVuMultiPage(); + + virtual void setFile(bool r); + + /** List of file formats for file saving + + This method returns the list of supported file formats for saving + the file. + */ + virtual QStringList fileFormats() const; + + /** Author information + + This member returns a structure that contains information about the + authors of the implementation + */ + static KAboutData* createAboutData(); + + /** Re-implementation of the print method */ + virtual void print(); + + virtual bool isReadWrite() const; + virtual bool isModified() const; + + virtual void slotSave(); + + protected: + virtual void enableActions(bool); + + private slots: + void setRenderMode(int mode); + + /** Opens a dialog to delete pages */ + void slotDeletePages(); + + private: + /** This member holds the renderer which is used by the demo + implementation */ + DjVuRenderer djvuRenderer; + + KSelectAction* renderModeAction; + KAction* deletePagesAction; +}; + +#endif diff --git a/kviewshell/plugins/djvu/djvumultipage.kcfg b/kviewshell/plugins/djvu/djvumultipage.kcfg new file mode 100644 index 00000000..478667b7 --- /dev/null +++ b/kviewshell/plugins/djvu/djvumultipage.kcfg @@ -0,0 +1,18 @@ + + + + + + Color + + + + + + + + + diff --git a/kviewshell/plugins/djvu/djvumultipage.rc b/kviewshell/plugins/djvu/djvumultipage.rc new file mode 100644 index 00000000..c340fe42 --- /dev/null +++ b/kviewshell/plugins/djvu/djvumultipage.rc @@ -0,0 +1,15 @@ + + + + + &Edit + + + + + &View + + + + + diff --git a/kviewshell/plugins/djvu/djvurenderer.cpp b/kviewshell/plugins/djvu/djvurenderer.cpp new file mode 100644 index 00000000..54a96b38 --- /dev/null +++ b/kviewshell/plugins/djvu/djvurenderer.cpp @@ -0,0 +1,719 @@ +/*************************************************************************** + * Copyright (C) 2005 by Stefan Kebekus * + * kebekus@kde.org * + * * + * Copyright (C) 2005 by Wilfried Huss * + * Wilfried.Huss@gmx.at * + * * + * This program 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 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "GBitmap.h" +#include "BSByteStream.h" +#include "IFFByteStream.h" + +#include "prefs.h" + +#include "documentWidget.h" +#include "djvurenderer.h" +#include "djvumultipage.h" +#include "hyperlink.h" +#include "renderedDocumentPagePixmap.h" +#include "textBox.h" + +//#define KF_DEBUG + +inline GUTF8String GStringFromQString(const QString& x) +{ + GUTF8String retval=(const char*)x.utf8(); + return retval; +} + + +inline QString QStringFromGString(const GUTF8String& x) +{ + QString retval=QString::fromUtf8((const char*)x); + return retval; +} + + +DjVuRenderer::DjVuRenderer(QWidget* par) + : DocumentRenderer(par) +{ +#ifdef KF_DEBUG + kdError() << "DjVuRenderer( parent=" << par << " )" << endl; +#endif + + PPMstream = ByteStream::create(); +} + + + +DjVuRenderer::~DjVuRenderer() +{ +#ifdef KF_DEBUG + kdDebug() << "~DjVuRenderer" << endl; +#endif + + // Wait for all access to this documentRenderer to finish + QMutexLocker locker( &mutex ); +} + + +void DjVuRenderer::drawPage(double resolution, RenderedDocumentPage* page) +{ +#ifdef KF_DEBUG + kdDebug() << "DjVuRenderer::drawPage(documentPage*) called, page number " << page->getPageNumber() << endl; +#endif + + // Paranoid safety checks + if (page == 0) { + kdError() << "DjVuRenderer::drawPage(documentPage*) called with argument == 0" << endl; + return; + } + if (page->getPageNumber() == 0) { + kdError() << "DjVuRenderer::drawPage(documentPage*) called for a documentPage with page number 0" << endl; + return; + } + + // Wait for all access to this documentRenderer to finish + QMutexLocker locker( &mutex ); + + // more paranoid safety checks + if (page->getPageNumber() > numPages) { + kdError() << "DjVuRenderer::drawPage(documentPage*) called for a documentPage with page number " << page->getPageNumber() + << " but the current fax file has only " << numPages << " pages." << endl; + return; + } + + int pageNumber = page->getPageNumber() - 1; + + GP djvuPage = document->get_page(pageNumber, true); + if (!djvuPage->wait_for_complete_decode()) + { + kdDebug() << "decoding failed." << endl; + return; + } + + if (!pageSizes[pageNumber].isValid()) + { + int djvuResolution = djvuPage->get_dpi(); + int djvuPageWidth = djvuPage->get_width(); + int djvuPageHeight = djvuPage->get_height(); + + Length w, h; + w.setLength_in_inch(djvuPageWidth / (double)djvuResolution); + h.setLength_in_inch(djvuPageHeight / (double)djvuResolution); + pageSizes[pageNumber].setPageSize(w, h); + + SimplePageSize ps = sizeOfPage(page->getPageNumber()); + + // If we are not printing we need to resize the pixmap. + RenderedDocumentPagePixmap* pagePixmap = dynamic_cast(page); + if (pagePixmap) + pagePixmap->resize(ps.sizeInPixel(resolution)); + } + + //kdDebug() << "render page " << pageNumber + 1 << " at size (" << pageWidth << ", " << pageHeight << ")" << endl; + + int pageHeight = page->height(); + int pageWidth = page->width(); + + GRect pageRect(0, 0, pageWidth, pageHeight); + + + GP djvuPixmap; + if (Prefs::renderMode() == Prefs::EnumRenderMode::Color) + djvuPixmap = djvuPage->get_pixmap(pageRect, pageRect); + else if (Prefs::renderMode() == Prefs::EnumRenderMode::Foreground) + djvuPixmap = djvuPage->get_fg_pixmap(pageRect, pageRect); + else if (Prefs::renderMode() == Prefs::EnumRenderMode::Background) + djvuPixmap = djvuPage->get_bg_pixmap(pageRect, pageRect); + + QPainter* foreGroundPaint = page->getPainter(); + if (foreGroundPaint != 0) + { + if(djvuPixmap && Prefs::renderMode() != Prefs::EnumRenderMode::BlackAndWhite) + { + PPMstream->seek(0); + djvuPixmap->save_ppm(*PPMstream); + long pixmapsize = PPMstream->tell(); + PPMstream->seek(0); + uchar* buf = new uchar[pixmapsize]; + long bytesRead = PPMstream->readall(buf, pixmapsize); + + bool ok = pixmap.loadFromData(buf, bytesRead, "PPM"); + if (!ok) + { + kdError() << "loading failed" << endl; + //draw an empty page + foreGroundPaint->fillRect(0, 0, pageWidth, pageHeight, Qt::white); + } + foreGroundPaint->drawPixmap(0, 0, pixmap); + delete[] buf; + +/* for (int i = 0; i < pageHeight; i++) + { + GPixel* pixmapRow = (*djvuPixmap)[i]; + + for (int j = 0; j < pageWidth; j++) + { + GPixel pixel = pixmapRow[j]; + foreGroundPaint->setPen(QColor(pixel.r, pixel.g, pixel.b)); + foreGroundPaint->drawPoint(j, pageHeight - i - 1); + } + }*/ + } + else + { + GP djvuBitmap = djvuPage->get_bitmap(pageRect, pageRect); + if(djvuBitmap) + { + PPMstream->seek(0); + if(djvuBitmap->get_grays() == 2) + djvuBitmap->save_pbm(*PPMstream); + else + djvuBitmap->save_pgm(*PPMstream); + + long pixmapsize = PPMstream->tell(); + PPMstream->seek(0); + uchar* buf = new uchar[pixmapsize]; + long bytesRead = PPMstream->readall(buf, pixmapsize); + + bool ok = pixmap.loadFromData(buf, bytesRead, "PPM"); + if (!ok) + { + kdError() << "loading failed" << endl; + //draw an empty page + foreGroundPaint->fillRect(0, 0, pageWidth, pageHeight, Qt::white); + } + foreGroundPaint->drawPixmap(0, 0, pixmap); + delete[] buf; +/* + for (int i = 0; i < pageHeight; i++) + { + unsigned char* bitmapRow = (*djvuBitmap)[i]; + for (int j = 0; j < pageWidth; j++) + { + unsigned char pixel = 255-bitmapRow[j]; + foreGroundPaint->setPen(QColor(pixel, pixel, pixel)); + foreGroundPaint->drawPoint(j, pageHeight - i - 1); + } + }*/ + } + else + { + //draw an empty page + foreGroundPaint->fillRect(0, 0, pageWidth, pageHeight, Qt::white); + } + } + + //kdDebug() << "rendering page " << pageNumber + 1 << " at size (" << pageWidth << ", " << pageHeight << ") finished." << endl; + page->returnPainter(foreGroundPaint); + } + + GP pageText = getText(pageNumber); + + if (pageText) + { + QSize djvuPageSize(djvuPage->get_width(), djvuPage->get_real_height()); + fillInText(page, pageText, pageText->page_zone, djvuPageSize); + //kdDebug() << "Text of page " << pageNumber << endl; + //kdDebug() << (const char*)pageText->textUTF8 << endl; + } + + getAnnotations(page, djvuPage); + + page->isEmpty = false; +} + + +bool DjVuRenderer::setFile(const QString &fname, const KURL &) +{ +#ifdef KF_DEBUG + kdDebug() << "DjVuRenderer::setFile(" << fname << ") called" << endl; +#endif + + // Wait for all access to this documentRenderer to finish + QMutexLocker locker( &mutex ); + + // If fname is the empty string, then this means: "close". + if (fname.isEmpty()) { + kdDebug() << "DjVuRenderer::setFile( ... ) called with empty filename. Closing the file." << endl; + return true; + } + + // Paranoid saftey checks: make sure the file actually exists, and + // that it is a file, not a directory. Otherwise, show an error + // message and exit.. + QFileInfo fi(fname); + QString filename = fi.absFilePath(); + if (!fi.exists() || fi.isDir()) { + KMessageBox::error( parentWidget, + i18n("File error. The specified file '%1' does not exist.").arg(filename), + i18n("File Error")); + // the return value 'false' indicates that this operation was not successful. + return false; + } + + // Clear previously loaded document + clear(); + + // Now we assume that the file is fine and load the file. + G_TRY { + document = DjVuDocEditor::create_wait(GURL::Filename::UTF8(GStringFromQString(filename))); + } + G_CATCH(ex) { + ; + } + G_ENDCATCH; + + // If the above assumption was false. + if (!document) + { + KMessageBox::error( parentWidget, + i18n("File error. The specified file '%1' could not be loaded.").arg(filename), + i18n("File Error")); + + clear(); + kdDebug(1223) << "Loading of document failed." << endl; + return false; + } + + bool r = initializeDocument(); + + // the return value 'true' indicates that this operation was successful. + return r; +} + +void DjVuRenderer::getAnnotations(RenderedDocumentPage* page, GP djvuPage) +{ + GP annotations = djvuPage->get_anno(); + if (!(annotations && annotations->size())) + return; + + GP ant = DjVuANT::create(); + + GP iff = IFFByteStream::create(annotations); + + GUTF8String chkid; + + while (iff->get_chunk(chkid)) + { + if (chkid == "ANTa") + { + ant->merge(*iff->get_bytestream()); + } + else if (chkid == "ANTz") + { + GP bsiff = BSByteStream::create(iff->get_bytestream()); + ant->merge(*bsiff); + } + iff->close_chunk(); + } + + if (!ant->is_empty()) + { + // Scaling factors for the coordinate conversion. + // TODO: Refractor this into a function shared with fillInText. + int pageWidth = page->width(); + int pageHeight = page->height(); + + double scaleX = pageWidth / (double)djvuPage->get_width(); + double scaleY = pageHeight / (double)djvuPage->get_height(); + + GPList map = ant->map_areas; + + for (GPosition pos = map; pos; ++pos) + { + // Currently we only support rectangular links + if (!map[pos]->get_shape_type() == GMapArea::RECT) + continue; + + GRect rect = map[pos]->get_bound_rect(); + + QRect hyperlinkRect((int)(rect.xmin*scaleX+0.5), (int)((djvuPage->get_height()-rect.ymax)*scaleY+0.5), + (int)(rect.width()*scaleX +0.5), (int)(rect.height()*scaleY+0.5)); + + QString url((const char*)map[pos]->url); + QString target((const char*)map[pos]->target); + QString comment((const char*)map[pos]->comment); + + // Create an anchor for this link. + if (!anchorList.contains(url)) + { + // For now we only accept links to pages in the same document. + if(url[0] == '#' && target == "_self") + { + bool conversionOk; + PageNumber targetPage = url.remove('#').toInt(&conversionOk); + if (conversionOk) + anchorList[url] = Anchor(targetPage, Length()); + } + } + + Hyperlink hyperlink(hyperlinkRect.bottom(), hyperlinkRect, url); + page->hyperLinkList.push_back(hyperlink); + } + } +} + + +bool DjVuRenderer::initializeDocument() +{ + if (document == 0) + return false; + + if (!document->wait_for_complete_init()) { + kdDebug() << "Document Initialization failed." << endl; + return false; + } + + // Set the number of pages page sizes + numPages = document->get_pages_num(); + + pageSizes.resize(numPages); + Length w,h; + + // Set the page sizes in the pageSizes array. Give feedback for + // very long documents + if (numPages > 100) + emit setStatusBarText(i18n("Loading file. Computing page sizes...")); + for(Q_UINT16 i=0; iprocessEvents(); + + GP djvuFile = document->get_djvu_file(i); + int resolution; + int pageWidth; + int pageHeight; + bool ok = getPageInfo(djvuFile, pageWidth, pageHeight, resolution); + if (!ok) + kdError() << "Decoding info of page " << i << " failed." << endl; + else { + w.setLength_in_inch(pageWidth / (double)resolution); + h.setLength_in_inch(pageHeight / (double)resolution); + pageSizes[i].setPageSize(w, h); + } + } + emit setStatusBarText(QString::null); + + // We will also generate a list of hyperlink-anchors in the document. + // So declare the existing lists empty. + anchorList.clear(); + return true; +} + + +GP DjVuRenderer::getText(PageNumber pageNumber) +{ + GUTF8String chkid; + + const GP file = document->get_djvu_file(pageNumber); + const GP bs(file->get_text()); + if (bs) + { + long int i=0; + const GP iff(IFFByteStream::create(bs)); + while (iff->get_chunk(chkid)) + { + i++; + if (chkid == GUTF8String("TXTa")) + { + GP txt = DjVuTXT::create(); + txt->decode(iff->get_bytestream()); + return txt; + } + else if (chkid == GUTF8String("TXTz")) + { + GP txt = DjVuTXT::create(); + GP bsiff=BSByteStream::create(iff->get_bytestream()); + txt->decode(bsiff); + return txt; + } + iff->close_chunk(); + } + } + return 0; +} + +void DjVuRenderer::fillInText(RenderedDocumentPage* page, const GP& text, DjVuTXT::Zone& zone, QSize& djvuPageSize) +{ + if (zone.children.isempty()) + { + int pageWidth = page->width(); + int pageHeight = page->height(); + + double scaleX = pageWidth / (double)djvuPageSize.width(); + double scaleY = pageHeight / (double)djvuPageSize.height(); + + QString zoneString = QStringFromGString(text->textUTF8.substr(zone.text_start, zone.text_length)); + + //kdDebug() << "zone text: " << zoneString << endl; + + QRect textRect((int)(zone.rect.xmin*scaleX+0.5), (int)((djvuPageSize.height()-zone.rect.ymax)*scaleY+0.5), + (int)(zone.rect.width()*scaleX+0.5), (int)(zone.rect.height()*scaleY+0.5)); + //kdDebug() << "zone rect: " << textRect.x() << ", " << textRect.y() << ", " << textRect.width() << ", " << textRect.height() << endl; + TextBox textBox(textRect, zoneString); + page->textBoxList.push_back(textBox); + } + else + { + for (GPosition pos=zone.children; pos; ++pos) + { + fillInText(page, text, zone.children[pos], djvuPageSize); + } + } +} + +bool DjVuRenderer::getPageInfo(GP file, int& width, int& height, int& dpi) +{ + if (!file || !file->is_all_data_present()) + return false; + + const GP pbs(file->get_djvu_bytestream(false, false)); + const GP iff(IFFByteStream::create(pbs)); + + GUTF8String chkid; + if (iff->get_chunk(chkid)) + { + if (chkid == "FORM:DJVU") + { + while (iff->get_chunk(chkid) && chkid!="INFO") + iff->close_chunk(); + if (chkid == "INFO") + { + GP gbs = iff->get_bytestream(); + GP info=DjVuInfo::create(); + info->decode(*gbs); + int rot = ((360-GRect::findangle(info->orientation))/90)%4; + + width = (rot&1) ? info->height : info->width; + height = (rot&1) ? info->width : info->height; + dpi = info->dpi; + return true; + } + } + else if (chkid == "FORM:BM44" || chkid == "FORM:PM44") + { + while (iff->get_chunk(chkid) && chkid!="BM44" && chkid!="PM44") + iff->close_chunk(); + if (chkid=="BM44" || chkid=="PM44") + { + GP gbs = iff->get_bytestream(); + if (gbs->read8() == 0) + { + gbs->read8(); + gbs->read8(); + unsigned char xhi = gbs->read8(); + unsigned char xlo = gbs->read8(); + unsigned char yhi = gbs->read8(); + unsigned char ylo = gbs->read8(); + + width = (xhi<<8)+xlo; + height = (yhi<<8)+ylo; + dpi = 100; + return true; + } + } + } + } + return false; +} + +void DjVuRenderer::getText(RenderedDocumentPage* page) +{ + QMutexLocker locker( &mutex ); + + int pageNumber = page->getPageNumber() - 1; + GP pageText = getText(pageNumber); + + if (pageText) + { + GP djvuFile = document->get_djvu_file(pageNumber); + int resolution; + int pageWidth; + int pageHeight; + bool ok = getPageInfo(djvuFile, pageWidth, pageHeight, resolution); + + if (ok) + { + QSize djvuPageSize(pageWidth, pageHeight); + fillInText(page, pageText, pageText->page_zone, djvuPageSize); + } + } +} + + +bool DjVuRenderer::convertToPSFile( DjVuToPS &converter, QString filename, QValueList &pageList ) +{ + if (document == 0) { + kdError(1223) << "DjVuRenderer::convertToPSFile(..) called when document was 0" << endl; + return false; + } + + QMutexLocker locker( &mutex ); + + // Set up progress dialog + KProgressDialog *pdialog = new KProgressDialog(parentWidget, "Printing-ProgressDialog", i18n("Printing..."), i18n("Preparing pages for printing..."), true); + pdialog->setButtonText(i18n("Abort")); + pdialog->showCancelButton(true); + pdialog->progressBar()->setTotalSteps(pageList.size()); + pdialog->progressBar()->setFormat(QString::null); + + // Open output file + GURL outname = GURL::Filename::UTF8(GStringFromQString(filename)); + GP obs = ByteStream::create(outname, "w"); + + QString pagename; + QValueList::ConstIterator it = pageList.begin(); + while (true) { + pagename += QString::number(*it); + ++it; + if (it == pageList.end()) + break; + pagename += ","; + } + GUTF8String pages = GStringFromQString(pagename); + + converter.set_info_cb(printerInfoCallBack, (void*)pdialog); + bool iscancelled = false; + G_TRY { + converter.print(*obs, (DjVuDocument *)document, pages ); + } + G_CATCH(ex) { + iscancelled = true; + } + G_ENDCATCH; + + delete pdialog; + + // This is to keep the GUI updated. + kapp->processEvents(); + + obs->flush(); + return !iscancelled; +} + + +void DjVuRenderer::deletePages(Q_UINT16 from, Q_UINT16 to) +{ + // Paranoia security checks + if (document == 0) { + kdError(1223) << "DjVuRenderer::deletePages(...) called when no document was loaded" << endl; + return; + } + if ((from > to) || (from == 0) || (from > totalPages()) || (to > totalPages())) { + kdError(1223) << "DjVuRenderer::deletePages(...) called with invalid arguments" << endl; + return; + } + + QMutexLocker locker( &mutex ); + + KProgressDialog *pdialog = 0; + if (to-from > 9) { + pdialog = new KProgressDialog(parentWidget, "Printing-ProgressDialog", i18n("Deleting pages..."), i18n("Please wait while pages are removed..."), true); + pdialog->showCancelButton(false); + pdialog->progressBar()->setTotalSteps(to-from+1); + pdialog->progressBar()->setFormat(QString::null); + pdialog->show(); + kapp->processEvents(); + } + + // set the document pointer temporarily to 0, so that no-one tries + // to render a page while we are deleting pages + GP document_new = document; + document = 0; + + // Delete pages + if (pdialog == 0) { + GList pageList; + for(Q_UINT16 i=from; i<= to; i++) + pageList.append(i-1); + document_new->remove_pages(pageList); + } else { + for(Q_UINT16 i=from; i<=to; i++) { + document_new->remove_page(from-1); + pdialog->progressBar()->setProgress(i-from); + pdialog->progressBar()->setFormat(i18n("deleting page %1").arg(i)); + kapp->processEvents(); + } + delete pdialog; + } + _isModified = true; + document = document_new; + + initializeDocument(); +} + + +bool DjVuRenderer::save(const QString &filename) +{ + if (document == 0) { + kdError() << "DjVuRenderer::save(..) called when document==0" << endl; + return false; + } + + QMutexLocker locker( &mutex ); + + G_TRY { + document->save_as(GURL::Filename::UTF8(GStringFromQString(filename)), true); + } + G_CATCH(ex) { + return false; + } + G_ENDCATCH; + + document->save_as(GURL::Filename::UTF8(filename.ascii()), true); + + if (QFile::exists(filename) == false) + return false; + + _isModified = false; + return true; +} + + +void DjVuRenderer::printerInfoCallBack(int page_num, int page_count, int, DjVuToPS::Stage, void *pd) +{ + if (pd == 0) + return; + + // Update the progress dialog. + KProgressDialog *pdialog = (KProgressDialog *)pd; + + pdialog->progressBar()->setProgress(page_count); + pdialog->progressBar()->setFormat(i18n("processing page %1").arg(page_num+1)); + pdialog->show(); + + if (pdialog->wasCancelled()) + G_THROW("STOP"); + + // This is to keep the GUI updated. + kapp->processEvents(); +} + + +#include "djvurenderer.moc" diff --git a/kviewshell/plugins/djvu/djvurenderer.h b/kviewshell/plugins/djvu/djvurenderer.h new file mode 100644 index 00000000..40418c23 --- /dev/null +++ b/kviewshell/plugins/djvu/djvurenderer.h @@ -0,0 +1,146 @@ +/*************************************************************************** + * Copyright (C) 2005 by Stefan Kebekus * + * kebekus@kde.org * + * * + * Copyright (C) 2005 by Wilfried Huss * + * Wilfried.Huss@gmx.at * + * * + * This program 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 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef _DJVURENDERER_H_ +#define _DJVURENDERER_H_ + +#include +#include + +#include "DjVuImage.h" +#include "DjVuDocEditor.h" +#include "DjVuText.h" +#include "DjVuToPS.h" +#include "ByteStream.h" + +#include "documentRenderer.h" + +class RenderedDocumentPage; + +/*! \brief Well-documented minimal implementation of a documentRenderer + +This class provides a well-documented reference implementation of a +documentRenderer, suitable as a starting point for a real-world +implementation. This class is responsible for document loading and +rendering. Apart from the constructor and the descructor, it +implements only the necessary methods setFile() and drawPage(). The +method setFile() ignores the file content and simulates a document +with 10 empty pages of A4 size and a few anchors and bookmarks. +*/ + +class DjVuRenderer : public DocumentRenderer +{ + Q_OBJECT + +public: + /** Default constructor + + This constructor simply prints a message and calls the default constructor. + */ + DjVuRenderer(QWidget* parent); + + /** Destructor + + The destructor simply prints a message. It uses the mutex to + ensure that this class is not destructed while another thread + is currently using it. + */ + ~DjVuRenderer(); + + /** Opening a file + + This implementation does the necessary consistency checks and + complains, e.g. if the file does not exist, but otherwise completely + disregards the file content. It simulates a document of 10 empty pages of + A4 size, with a few sample bookmarks and anchors "p1", "p2", "p3" + for page 1, 2 and 3, respectively. + + @param fname the name of the file that should be opened. + */ + virtual bool setFile(const QString& fname, const KURL &); + + /** Rendering a page + @param res resolution at which drawing should take place + @param page pointer to a page structur on which we should draw + */ + virtual void drawPage(double res, RenderedDocumentPage* page); + + /** Extract the hidden text layer + + This function decodes the hidden text layer without actually decoding the full page. + It is therefore much faster then drawPage if you only need the text information. + */ + virtual void getText(RenderedDocumentPage* page); + + virtual bool supportsTextSearch() const { return true; }; + + /** DJVU to PostScript conversion + + This method uses the converter to convert the document to a PostScript. + + @param converter a DjVuToPS converter, whose options should already + be set to + + @param filename name of the PostScript file to generate + + @param pageList list of pages that are to be converted, with the + usual convention that "1" means "first page" + + @returns 'true' if the conversion was successful, 'false' if it + wasn't. The conversion can fail, for example, when the user aborts + the operation. + */ + bool convertToPSFile( DjVuToPS &converter, QString filename, QValueList &pageList ); + + /** Deletes pages from the document */ + void deletePages(Q_UINT16 from, Q_UINT16 to); + + /** Saves the file */ + bool save(const QString &filename); + +private: + /* This method is called after a document is loaded with + create_wait() or has been modified (e.g. inserting/deleting + pages). It sets "numPages", fills the "pageSizes" array, and + clear the anchorList. */ + bool initializeDocument(); + + void getAnnotations(RenderedDocumentPage* page, GP djvuPage); + + bool getPageInfo(GP file, int& width, int& height, int& dpi); + + GP getText(PageNumber pageNumber); + + void fillInText(RenderedDocumentPage* page, const GP& text, DjVuTXT::Zone& zone, QSize& djvuPageSize); + + GP document; + + /** Method used internally to report the progress of the DjVu to + PostScript conversion */ + static void printerInfoCallBack(int page_num, int page_count, int tot_pages, DjVuToPS::Stage, void *); + + QPixmap pixmap; + GP PPMstream; +}; + +#endif diff --git a/kviewshell/plugins/djvu/kprintDialogPage_DJVUconversionoptions.cpp b/kviewshell/plugins/djvu/kprintDialogPage_DJVUconversionoptions.cpp new file mode 100644 index 00000000..aea7d6b7 --- /dev/null +++ b/kviewshell/plugins/djvu/kprintDialogPage_DJVUconversionoptions.cpp @@ -0,0 +1,118 @@ +/*************************************************************************** + * Copyright (C) 2005 by Stefan Kebekus * + * kebekus@kde.org * + * * + * This program 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 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "kprintDialogPage_DJVUconversionoptions.h" +#include "kprintDialogPage_DJVUconversionoptions_basewidget.h" + +KPrintDialogPage_DJVUConversionOptions::KPrintDialogPage_DJVUConversionOptions( QWidget *parent, const char *name ) + : KPrintDialogPage( parent, name ) +{ + setTitle( i18n("DJVU to PS Conversion") ); + + kprintDialogPage_pageoptions_baseLayout = new QVBoxLayout( this, 11, 6, "kprintDialogPage_pageoptions_baseLayout"); + if (kprintDialogPage_pageoptions_baseLayout == 0) { + kdError(1223) << "KPrintDialogPage_DJVUPageOptions::KPrintDialogPage_DJVUPageOptions() cannot create layout" << endl; + return; + } + + wdg = new kprintDialogPage_DJVUconversionoptions_basewidget(this, "basewdg" ); + if (wdg != 0) { + kprintDialogPage_pageoptions_baseLayout->addWidget( wdg ); + } +} + + + +void KPrintDialogPage_DJVUConversionOptions::getOptions( QMap& opts, bool ) +{ + if (wdg == 0) + return; + + opts["kde-kdjvu-pslevel"] = QString::number(wdg->psLevel->currentItem() + 1); + + kdDebug() << "getOptions: renderMode = " << wdg->renderMode->currentItem() << endl; + switch (wdg->renderMode->currentItem()) + { + case 1: + opts["kde-kdjvu-rendermode"] = "black-and-white"; + break; + case 2: + opts["kde-kdjvu-rendermode"] = "foreground"; + break; + case 3: + opts["kde-kdjvu-rendermode"] = "background"; + break; + default: // 0 + opts["kde-kdjvu-rendermode"] = "color"; + } +} + + +void KPrintDialogPage_DJVUConversionOptions::setOptions( const QMap& opts ) +{ + if (wdg == 0) + return; + + bool ok; + // Set PostScript Language Level, taking 2 as the default + int psLevel = opts["kde-kdjvu-pslevel"].toInt(&ok); + + if (ok && psLevel >= 1 && psLevel <= 3) + { + wdg->psLevel->setCurrentItem(psLevel - 1); + } + else + { + wdg->psLevel->setCurrentItem(1); // PostScript Level 2 + } + + // Set render mode, taking "color" as default + QString op = opts["kde-kdjvu-rendermode"]; + if (op == "black-and-white") + { + wdg->renderMode->setCurrentItem(1); + } + else + { + if (op == "foreground") + wdg->renderMode->setCurrentItem(2); + else + { + if (op == "background") + wdg->renderMode->setCurrentItem(3); + else + wdg->renderMode->setCurrentItem(0); + } + } +} + + +bool KPrintDialogPage_DJVUConversionOptions::isValid( QString& ) +{ + return true; +} diff --git a/kviewshell/plugins/djvu/kprintDialogPage_DJVUconversionoptions.h b/kviewshell/plugins/djvu/kprintDialogPage_DJVUconversionoptions.h new file mode 100644 index 00000000..9e3faa90 --- /dev/null +++ b/kviewshell/plugins/djvu/kprintDialogPage_DJVUconversionoptions.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (C) 2005 by Stefan Kebekus * + * kebekus@kde.org * + * * + * This program 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 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef KPRINTDIALOGPAGE_DJVUCONVERSIONOPTIONS_H +#define KPRINTDIALOGPAGE_DJVUCONVERSIONOPTIONS_H + +#include + + +class kprintDialogPage_DJVUconversionoptions_basewidget; + + +// This is a fairly standard KPrintDialogPage that allows the user to +// chose page size & placement options: shrink oversized pages, and +// expand small pages + +class KPrintDialogPage_DJVUConversionOptions : public KPrintDialogPage +{ + public: + KPrintDialogPage_DJVUConversionOptions( QWidget *parent = 0, const char *name = 0 ); + + void getOptions( QMap& opts, bool incldef = false ); + void setOptions( const QMap& opts ); + bool isValid( QString& msg ); + + kprintDialogPage_DJVUconversionoptions_basewidget* wdg; + + private: + QVBoxLayout* kprintDialogPage_pageoptions_baseLayout; +}; + + +#endif // KPRINTDIALOGPAGE_PAGEOPTIONS_H diff --git a/kviewshell/plugins/djvu/kprintDialogPage_DJVUconversionoptions_basewidget.ui b/kviewshell/plugins/djvu/kprintDialogPage_DJVUconversionoptions_basewidget.ui new file mode 100644 index 00000000..fbc48750 --- /dev/null +++ b/kviewshell/plugins/djvu/kprintDialogPage_DJVUconversionoptions_basewidget.ui @@ -0,0 +1,145 @@ + +kprintDialogPage_DJVUconversionoptions_basewidget + + + kprintDialogPage_DJVUconversionoptions_basewidget + + + + 0 + 0 + 548 + 126 + + + + + unnamed + + + + textLabel1 + + + + 4 + 5 + 0 + 0 + + + + PostScript language level: + + + + + textLabel2 + + + + 4 + 5 + 0 + 0 + + + + Render mode: + + + + + + Level 1 (almost obsolete) + + + + + Level 2 (default) + + + + + Level 3 (might print faster) + + + + psLevel + + + + 3 + 0 + 0 + 0 + + + + <p>With this dialog you can choose the PostScript language level used by KViewShell. The choice of a language level can dramatically affect printing speed, but has no impact on the quality of the printout.</p> +<p><b>Level 1:</b> This is the most conservative option, because PostScript Level 1 files can be printed on all printers. The files produced are, however, extremely long, and printing can be very slow.</p> +<p><b>Level 2:</b> Level 2 PostScript files are much smaller and print much faster than Level 1 files. Level 2 files are supported by almost all printers.</p> +<p><b>Level 3:</b> Level 3 PostScript files are much smaller and print even faster than Level 2 files. However, Level 3 files are supported only by some modern printers. If Level 3 works for you, this is the best option.</p> + + + + + + Print Full Page (default) + + + + + Black & White + + + + + Foreground Only + + + + + Background Only + + + + renderMode + + + + 3 + 0 + 0 + 0 + + + + <p>Good DJVU files are separated into foreground and background images. The foreground mostly contains the text. With the render mode you can decide what part of your page will be printed.</p> +<p><b>Print Full Page:</b> The full page, including foreground and background will be printed, either in color or in grayscale.</p> +<p><b>Black & White:</b> Foreground and background are printed, but only in black-and-white. If this option is chosen, the files generated will print much faster, but quality will not be as good.</p> +<p><b>Foreground Only:</b> This option is useful if the background of the page is disturbing and affects the readability of the text.</p> +<p><b>Background Only:</b> Print only the background of the page.</p> + + + + + spacer1 + + + Vertical + + + Expanding + + + + 20 + 40 + + + + + + + diff --git a/kviewshell/plugins/djvu/kprintDialogPage_DJVUpageoptions.cpp b/kviewshell/plugins/djvu/kprintDialogPage_DJVUpageoptions.cpp new file mode 100644 index 00000000..cd77fa0e --- /dev/null +++ b/kviewshell/plugins/djvu/kprintDialogPage_DJVUpageoptions.cpp @@ -0,0 +1,119 @@ +/*************************************************************************** + * Copyright (C) 2005 by Stefan Kebekus * + * kebekus@kde.org * + * * + * This program 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 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "kprintDialogPage_DJVUpageoptions.h" + +KPrintDialogPage_DJVUPageOptions::KPrintDialogPage_DJVUPageOptions( QWidget *parent, const char *name ) + : KPrintDialogPage( parent, name ) +{ + setTitle( i18n("Page Size & Placement") ); + + kprintDialogPage_pageoptions_baseLayout = 0; + checkBox_rotate = 0; + checkBox_fitpage = 0; + + + kprintDialogPage_pageoptions_baseLayout = new QVBoxLayout( this, 11, 6, "kprintDialogPage_pageoptions_baseLayout"); + if (kprintDialogPage_pageoptions_baseLayout == 0) { + kdError(1223) << "KPrintDialogPage_DJVUPageOptions::KPrintDialogPage_DJVUPageOptions() cannot create layout" << endl; + return; + } + + checkBox_rotate = new QCheckBox( this, "checkBox_rotate" ); + if (checkBox_rotate != 0) { + checkBox_rotate->setText( i18n( "Automatically choose landscape or portrait orientation" ) ); + QToolTip::add( checkBox_rotate, i18n( "If this option is enabled, some pages might be rotated to better fit the paper size." ) ); + QWhatsThis::add( checkBox_rotate, i18n( "

If this option is enabled, landscape or portrait orientation are automatically chosen on a " + "page-by-page basis. This makes better use of the paper and gives more visually-" + "appealing printouts.

" + "

Note: This option overrides the Portrait/Landscape option chosen in the printer " + "properties. If this option is enabled, and if the pages in your document have different sizes, " + "then some pages might be rotated while others are not.

" ) ); + kprintDialogPage_pageoptions_baseLayout->addWidget( checkBox_rotate ); + } + + checkBox_fitpage = new QCheckBox( this, "checkBox_shrink" ); + if (checkBox_fitpage != 0) { + checkBox_fitpage->setText( i18n( "Scale pages to fit paper size" ) ); + QToolTip::add( checkBox_fitpage, i18n( "If this option is enabled, all pages will be scaled to optimally fit the printer's paper size." ) ); + QWhatsThis::add( checkBox_fitpage, i18n( "

If this option is enabled, all pages will be scaled to optimally fit the printer's " + "paper size.

" + "

Note: If this option is enabled, and if the pages in your document have different sizes, " + "then different pages might be scaled by different scaling factors.

" ) ); + kprintDialogPage_pageoptions_baseLayout->addWidget( checkBox_fitpage ); + } + + kprintDialogPage_pageoptions_baseLayout->addStretch(); + + resize( QSize(319, 166).expandedTo(minimumSizeHint()) ); + clearWState( WState_Polished ); +} + + + +void KPrintDialogPage_DJVUPageOptions::getOptions( QMap& opts, bool ) +{ + // Save options, taking default values into consideration. Warning: + // The default values are also coded into setOptions() and + // kmultipage::print(..). + + if (checkBox_rotate != 0) + if (checkBox_rotate->isChecked()) + opts[ "kde-kviewshell-rotatepage" ] = "true"; + else + opts[ "kde-kviewshell-rotatepage" ] = "false"; + + if (checkBox_fitpage != 0) + if (checkBox_fitpage->isChecked()) + opts[ "kde-kdjvu-fitpage" ] = "true"; + else + opts[ "kde-kdjvu-fitpage" ] = "false"; +} + + +void KPrintDialogPage_DJVUPageOptions::setOptions( const QMap& opts ) +{ + // Warning: All default values are also coded into getOptions() and + // kmultipage::print(..). + + // same for rotation + QString op = opts[ "kde-kviewshell-rotatepage" ]; + if (checkBox_rotate != 0) + checkBox_rotate->setChecked( op != "false" ); + + // Sets the fitpage option. By default, this option is not checked + op = opts[ "kde-kdjvu-fitpage" ]; + if (checkBox_fitpage != 0) + checkBox_fitpage->setChecked( op == "true" ); +} + + +bool KPrintDialogPage_DJVUPageOptions::isValid( QString& ) +{ + return true; +} diff --git a/kviewshell/plugins/djvu/kprintDialogPage_DJVUpageoptions.h b/kviewshell/plugins/djvu/kprintDialogPage_DJVUpageoptions.h new file mode 100644 index 00000000..0121c1a0 --- /dev/null +++ b/kviewshell/plugins/djvu/kprintDialogPage_DJVUpageoptions.h @@ -0,0 +1,42 @@ +// KPrintDialogPage_PageOptions.h +// +// Part of KVIEWSHELL - A framework for multipage text/gfx viewers +// +// (C) 2005 Stefan Kebekus +// Distributed under the GPL + +// Add header files alphabetically + +#ifndef KPRINTDIALOGPAGE_DJVUPAGEOPTIONS_H +#define KPRINTDIALOGPAGE_DJVUPAGEOPTIONS_H + + +#include + + +class QVBoxLayout; +class QCheckBox; + + +// This is a fairly standard KPrintDialogPage that allows the user to +// chose page size & placement options: shrink oversized pages, and +// expand small pages + +class KPrintDialogPage_DJVUPageOptions : public KPrintDialogPage +{ + public: + KPrintDialogPage_DJVUPageOptions( QWidget *parent = 0, const char *name = 0 ); + + void getOptions( QMap& opts, bool incldef = false ); + void setOptions( const QMap& opts ); + bool isValid( QString& msg ); + + QCheckBox* checkBox_rotate; + QCheckBox* checkBox_fitpage; + + private: + QVBoxLayout* kprintDialogPage_pageoptions_baseLayout; +}; + + +#endif // KPRINTDIALOGPAGE_PAGEOPTIONS_H diff --git a/kviewshell/plugins/djvu/libdjvu/Arrays.cpp b/kviewshell/plugins/djvu/libdjvu/Arrays.cpp new file mode 100644 index 00000000..5cb7b04c --- /dev/null +++ b/kviewshell/plugins/djvu/libdjvu/Arrays.cpp @@ -0,0 +1,305 @@ +//C- -*- C++ -*- +//C- ------------------------------------------------------------------- +//C- DjVuLibre-3.5 +//C- Copyright (c) 2002 Leon Bottou and Yann Le Cun. +//C- Copyright (c) 2001 AT&T +//C- +//C- This software is subject to, and may be distributed under, the +//C- GNU General Public License, Version 2. The license should have +//C- accompanied the software or you may obtain a copy of the license +//C- from the Free Software Foundation at http://www.fsf.org . +//C- +//C- This program is distributed in the hope that it will be useful, +//C- but WITHOUT ANY WARRANTY; without even the implied warranty of +//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//C- GNU General Public License for more details. +//C- +//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library +//C- distributed by Lizardtech Software. On July 19th 2002, Lizardtech +//C- Software authorized us to replace the original DjVu(r) Reference +//C- Library notice by the following text (see doc/lizard2002.djvu): +//C- +//C- ------------------------------------------------------------------ +//C- | DjVu (r) Reference Library (v. 3.5) +//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved. +//C- | The DjVu Reference Library is protected by U.S. Pat. No. +//C- | 6,058,214 and patents pending. +//C- | +//C- | This software is subject to, and may be distributed under, the +//C- | GNU General Public License, Version 2. The license should have +//C- | accompanied the software or you may obtain a copy of the license +//C- | from the Free Software Foundation at http://www.fsf.org . +//C- | +//C- | The computer code originally released by LizardTech under this +//C- | license and unmodified by other parties is deemed "the LIZARDTECH +//C- | ORIGINAL CODE." Subject to any third party intellectual property +//C- | claims, LizardTech grants recipient a worldwide, royalty-free, +//C- | non-exclusive license to make, use, sell, or otherwise dispose of +//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the +//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU +//C- | General Public License. This grant only confers the right to +//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to +//C- | the extent such infringement is reasonably necessary to enable +//C- | recipient to make, have made, practice, sell, or otherwise dispose +//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to +//C- | any greater extent that may be necessary to utilize further +//C- | modifications or combinations. +//C- | +//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY +//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF +//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. +//C- +------------------------------------------------------------------ +// +// $Id: Arrays.cpp,v 1.8 2003/11/07 22:08:20 leonb Exp $ +// $Name: release_3_5_15 $ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#if NEED_GNUG_PRAGMAS +# pragma implementation +#endif + +#include "Arrays.h" +#include "GException.h" + + +#ifdef HAVE_NAMESPACES +namespace DJVU { +# ifdef NOT_DEFINED // Just to fool emacs c++ mode +} +#endif +#endif + +ArrayRep::ArrayRep(int xelsize, + void (* xdestroy)(void *, int, int), + void (* xinit1)(void *, int, int), + void (* xinit2)(void *, int, int, const void *, int, int), + void (* xcopy)(void *, int, int, const void *, int, int), + void (* xinsert)(void *, int, int, const void *, int)) : + data(0), minlo(0), maxhi(-1), lobound(0), hibound(-1), + elsize(xelsize), destroy(xdestroy), init1(xinit1), + init2(xinit2), copy(xcopy), insert(xinsert) +{ +} + +ArrayRep::ArrayRep(int xelsize, + void (* xdestroy)(void *, int, int), + void (* xinit1)(void *, int, int), + void (* xinit2)(void *, int, int, const void *, int, int), + void (* xcopy)(void *, int, int, const void *, int, int), + void (* xinsert)(void *, int, int, const void *, int), + int hi) : data(0), minlo(0), maxhi(-1), + lobound(0), hibound(-1), elsize(xelsize), destroy(xdestroy), init1(xinit1), + init2(xinit2), copy(xcopy), insert(xinsert) +{ + resize(0, hi); +} + +ArrayRep::ArrayRep(int xelsize, + void (* xdestroy)(void *, int, int), + void (* xinit1)(void *, int, int), + void (* xinit2)(void *, int, int, const void *, int, int), + void (* xcopy)(void *, int, int, const void *, int, int), + void (* xinsert)(void *, int, int, const void *, int), + int lo, int hi) : data(0), minlo(0), maxhi(-1), + lobound(0), hibound(-1), elsize(xelsize), destroy(xdestroy), init1(xinit1), + init2(xinit2), copy(xcopy), insert(xinsert) +{ + resize(lo,hi); +} + +ArrayRep::ArrayRep(const ArrayRep & arr) : data(0), minlo(0), maxhi(-1), + lobound(0), hibound(-1), elsize(arr.elsize), destroy(arr.destroy), + init1(arr.init1), init2(arr.init2), copy(arr.copy), insert(arr.insert) +{ + resize(arr.lobound, arr.hibound); + arr.copy(data, lobound-minlo, hibound-minlo, + arr.data, arr.lobound-arr.minlo, arr.hibound-arr.minlo); +} + +ArrayRep::~ArrayRep() +{ + destroy(data, lobound-minlo, hibound-minlo); + operator delete(data); + data=0; +} + +ArrayRep & +ArrayRep::operator= (const ArrayRep & rep) +{ + if (&rep == this) return *this; + empty(); + resize(rep.lobound, rep.hibound); + copy(data, lobound-minlo, hibound-minlo, + rep.data, rep.lobound-rep.minlo, rep.hibound-rep.minlo); + return *this; +} + +void +ArrayRep::resize(int lo, int hi) +{ + int nsize = hi - lo + 1; + // Validation + if (nsize < 0) + G_THROW( ERR_MSG("arrays.resize") ); + // Destruction + if (nsize == 0) + { + destroy(data, lobound-minlo, hibound-minlo); + operator delete(data); + data = 0; + lobound = minlo = lo; + hibound = maxhi = hi; + return; + } + // Simple extension + if (lo >= minlo && hi <= maxhi) + { + init1(data, lo-minlo, lobound-1-minlo); + destroy(data, lobound-minlo, lo-1-minlo); + init1(data, hibound+1-minlo, hi-minlo); + destroy(data, hi+1-minlo, hibound-minlo); + lobound = lo; + hibound = hi; + return; + } + // General case + int nminlo = minlo; + int nmaxhi = maxhi; + if (nminlo > nmaxhi) + nminlo = nmaxhi = lo; + while (nminlo > lo) { + int incr = nmaxhi - nminlo; + nminlo -= (incr < 8 ? 8 : (incr > 32768 ? 32768 : incr)); + } + while (nmaxhi < hi) { + int incr = nmaxhi - nminlo; + nmaxhi += (incr < 8 ? 8 : (incr > 32768 ? 32768 : incr)); + } + // allocate + int bytesize=elsize*(nmaxhi-nminlo+1); + void * ndata; + GPBufferBase gndata(ndata,bytesize,1); + memset(ndata, 0, bytesize); + // initialize + init1(ndata, lo-nminlo, lobound-1-nminlo); + init2(ndata, lobound-nminlo, hibound-nminlo, + data, lobound-minlo, hibound-minlo); + init1(ndata, hibound+1-nminlo, hi-nminlo); + destroy(data, lobound-minlo, hibound-minlo); + + // free and replace + void *tmp=data; + data = ndata; + ndata=tmp; + + minlo = nminlo; + maxhi = nmaxhi; + lobound = lo; + hibound = hi; +} + +void +ArrayRep::shift(int disp) +{ + lobound += disp; + hibound += disp; + minlo += disp; + maxhi += disp; +} + +void +ArrayRep::del(int n, unsigned int howmany) +{ + if (howmany == 0) + return; + if ((int)(n + howmany) > hibound +1) + G_THROW( ERR_MSG("arrays.ill_arg") ); + copy(data, n-minlo, hibound-howmany-minlo, + data, n+howmany-minlo, hibound-minlo); + destroy(data, hibound+1-howmany-minlo, hibound-minlo); + hibound = hibound - howmany; +} + +void +ArrayRep::ins(int n, const void * what, unsigned int howmany) +{ + int nhi = hibound + howmany; + if (howmany == 0) return; + if (maxhi < nhi) + { + int nmaxhi = maxhi; + while (nmaxhi < nhi) + nmaxhi += (nmaxhi < 8 ? 8 : (nmaxhi > 32768 ? 32768 : nmaxhi)); + int bytesize = elsize*(nmaxhi-minlo+1); + void *ndata; + GPBufferBase gndata(ndata,bytesize,1); + memset(ndata, 0, bytesize); + copy(ndata, lobound-minlo, hibound-minlo, + data, lobound-minlo, hibound-minlo); + destroy(data, lobound-minlo, hibound-minlo); + void *tmp=data; + data=ndata; + tmp=data; + maxhi = nmaxhi; + } + + insert(data, hibound+1-minlo, n-minlo, what, howmany); + hibound=nhi; +} + + + +#ifdef HAVE_NAMESPACES +} +# ifndef NOT_USING_DJVU_NAMESPACE +using namespace DJVU; +# endif +#endif + + +// --------------------------------------- +// BEGIN HACK +// --------------------------------------- +// Included here to avoid dependency +// from ByteStream.o to Arrays.o + +#ifndef DO_NOT_MOVE_GET_DATA_TO_ARRAYS_CPP +#include "ByteStream.h" + +#ifdef HAVE_NAMESPACES +namespace DJVU { +# ifdef NOT_DEFINED // Just to fool emacs c++ mode +} +#endif +#endif +TArray +ByteStream::get_data(void) +{ + const int s=size(); + if(s > 0) + { + TArray data(0, s-1); + readat((char*)data, s, 0); + return data; + }else + { + TArray data(0, -1); + return data; + } +} + +#ifdef HAVE_NAMESPACES +} +# ifndef NOT_USING_DJVU_NAMESPACE +using namespace DJVU; +# endif +#endif +#endif + +// --------------------------------------- +// END HACK +// --------------------------------------- + diff --git a/kviewshell/plugins/djvu/libdjvu/Arrays.h b/kviewshell/plugins/djvu/libdjvu/Arrays.h new file mode 100644 index 00000000..b2676d5a --- /dev/null +++ b/kviewshell/plugins/djvu/libdjvu/Arrays.h @@ -0,0 +1,997 @@ +//C- -*- C++ -*- +//C- ------------------------------------------------------------------- +//C- DjVuLibre-3.5 +//C- Copyright (c) 2002 Leon Bottou and Yann Le Cun. +//C- Copyright (c) 2001 AT&T +//C- +//C- This software is subject to, and may be distributed under, the +//C- GNU General Public License, Version 2. The license should have +//C- accompanied the software or you may obtain a copy of the license +//C- from the Free Software Foundation at http://www.fsf.org . +//C- +//C- This program is distributed in the hope that it will be useful, +//C- but WITHOUT ANY WARRANTY; without even the implied warranty of +//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//C- GNU General Public License for more details. +//C- +//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library +//C- distributed by Lizardtech Software. On July 19th 2002, Lizardtech +//C- Software authorized us to replace the original DjVu(r) Reference +//C- Library notice by the following text (see doc/lizard2002.djvu): +//C- +//C- ------------------------------------------------------------------ +//C- | DjVu (r) Reference Library (v. 3.5) +//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved. +//C- | The DjVu Reference Library is protected by U.S. Pat. No. +//C- | 6,058,214 and patents pending. +//C- | +//C- | This software is subject to, and may be distributed under, the +//C- | GNU General Public License, Version 2. The license should have +//C- | accompanied the software or you may obtain a copy of the license +//C- | from the Free Software Foundation at http://www.fsf.org . +//C- | +//C- | The computer code originally released by LizardTech under this +//C- | license and unmodified by other parties is deemed "the LIZARDTECH +//C- | ORIGINAL CODE." Subject to any third party intellectual property +//C- | claims, LizardTech grants recipient a worldwide, royalty-free, +//C- | non-exclusive license to make, use, sell, or otherwise dispose of +//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the +//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU +//C- | General Public License. This grant only confers the right to +//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to +//C- | the extent such infringement is reasonably necessary to enable +//C- | recipient to make, have made, practice, sell, or otherwise dispose +//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to +//C- | any greater extent that may be necessary to utilize further +//C- | modifications or combinations. +//C- | +//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY +//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF +//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. +//C- +------------------------------------------------------------------ +// +// $Id: Arrays.h,v 1.10 2004/05/13 15:16:34 leonb Exp $ +// $Name: release_3_5_15 $ + +#ifndef _ARRAYS_H_ +#define _ARRAYS_H_ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#if NEED_GNUG_PRAGMAS +# pragma interface +#endif + +#include "GException.h" +#include "GSmartPointer.h" +#include + +#ifdef HAVE_NAMESPACES +namespace DJVU { +# ifdef NOT_DEFINED // Just to fool emacs c++ mode +} +#endif +#endif + + + +/** @name Arrays.h + + Files #"Arrays.h"# and #"Arrays.cpp"# implement three array template classes. + Class \Ref{TArray} implements an array of objects of trivial types + such as #char#, #int#, #float#, etc. It is faster than general implementation + for any type done in \Ref{DArray} because it does not cope with + element's constructors, destructors and copy operators. Although + implemented as a template, which makes it possible to incorrectly use + \Ref{TArray} with non-trivial classes, it should not be done. + + A lot of things is shared by these three arrays. That is why there are + more base classes: + \begin{itemize} + \item \Ref{ArrayBase} defines functions independent of the elements type + \item \Ref{ArrayBaseT} template class defining functions shared by + \Ref{DArray} and \Ref{TArray} + \end{itemize} + + The main difference between \Ref{GArray} (now obsolete) and these ones + is the copy-on-demand strategy, which allows you to copy array objects + without copying the real data. It's the same thing, which has been + implemented in \Ref{GString} long ago: as long as you don't try to modify + the underlying data, it may be shared between several copies of array + objects. As soon as you attempt to make any changes, a private copy + is created automatically and transparently for you - the procedure, that + we call "copy-on-demand". + + Also, please note that now there is no separate class, which does fast + sorting. Both \Ref{TArray} (dynamic array for trivial types) and + \Ref{DArray} (dynamic array for arbitrary types) can sort their elements. + + {\bf Historical comments} --- Leon chose to implement his own arrays because + the STL classes were not universally available and the compilers were + rarely able to deal with such a template galore. Later it became clear + that there is no really good reason why arrays should be derived from + containers. It was also suggested to create separate arrays implementation + for simple classes and do the copy-on-demand strategy, which would allow + to assign array objects without immediate copying of their elements. + + At this point \Ref{DArray} and \Ref{TArray} should only be used when + it is critical to have the copy-on-demand feature. The \Ref{GArray} + implementation is a lot more efficient. + + @memo Template array classes. + @author + Andrei Erofeev -- Copy-on-demand implementation. + @version + #$Id: Arrays.h,v 1.10 2004/05/13 15:16:34 leonb Exp $# */ +//@{ + +// Auxiliary classes: Will be used in place of GPBase and GPEnabled objects +class _ArrayRep +{ + friend class _ArrayBase; +public: + _ArrayRep(void) : count(0) {} + _ArrayRep(const _ArrayRep &) {} + virtual ~_ArrayRep(void) {} + + _ArrayRep & operator=(const _ArrayRep &) { return *this; } + + int get_count(void) const { return count; } +private: + int count; + + void ref(void) { count++; } + void unref(void) { if (--count==0) delete this; } +}; + +class _ArrayBase +{ +public: + _ArrayBase(void) : rep(0) {} + _ArrayBase(const _ArrayBase & ab) : rep(0) + { + if (ab.rep) ab.rep->ref(); + rep=ab.rep; + } + _ArrayBase(_ArrayRep * ar) : rep(0) + { + if (ar) ar->ref(); + rep=ar; + } + virtual ~_ArrayBase(void) + { + if (rep) { rep->unref(); rep=0; } + } + + _ArrayRep * get(void) const { return rep; } + _ArrayBase & assign(_ArrayRep * ar) + { + if (ar) ar->ref(); + if (rep) rep->unref(); + rep=ar; + return *this; + } + _ArrayBase & operator=(const _ArrayBase & ab) { return assign(ab.rep); } + bool operator==(const _ArrayBase & ab) { return rep==ab.rep; } +private: + _ArrayRep * rep; +}; + +// Internal "Array repository" holding the pointer to the actual data, +// data bounds, etc. It copes with data elements with the help of five +// static functions which pointers are supposed to be passed to the +// constructor. +class ArrayRep : public _ArrayRep +{ +public: + ArrayRep(int elsize, + void (* xdestroy)(void *, int, int), + void (* xinit1)(void *, int, int), + void (* xinit2)(void *, int, int, const void *, int, int), + void (* xcopy)(void *, int, int, const void *, int, int), + void (* xinsert)(void *, int, int, const void *, int)); + ArrayRep(int elsize, + void (* xdestroy)(void *, int, int), + void (* xinit1)(void *, int, int), + void (* xinit2)(void *, int, int, const void *, int, int), + void (* xcopy)(void *, int, int, const void *, int, int), + void (* xinsert)(void *, int, int, const void *, int), + int hibound); + ArrayRep(int elsize, + void (* xdestroy)(void *, int, int), + void (* xinit1)(void *, int, int), + void (* xinit2)(void *, int, int, const void *, int, int), + void (* xcopy)(void *, int, int, const void *, int, int), + void (* xinsert)(void *, int, int, const void *, int), + int lobound, int hibound); + ArrayRep(const ArrayRep & rep); + + virtual ~ArrayRep(); + + // Following is the standard interface to DArray. DArray will call these + // functions to access data. + int size() const; + int lbound() const; + int hbound() const; + + void empty(); + void touch(int n); + void resize(int lobound, int hibound); + void shift(int disp); + void del(int n, unsigned int howmany=1); + + // ins() is an exception. It does it job only partially. + // The derived class is supposed to finish insertion. + void ins(int n, const void * what, unsigned int howmany); + + ArrayRep & operator=(const ArrayRep & rep); + + // All data is public because DArray... classes will need access to it + void *data; + int minlo; + int maxhi; + int lobound; + int hibound; + int elsize; +private: + // These functions can't be virtual as they're called from + // constructors and destructors :(( + // destroy(): should destroy elements in data[] array from 'lo' to 'hi' + void (* destroy)(void * data, int lo, int hi); + // init1(): should initialize elements in data[] from 'lo' to 'hi' + // using default constructors + void (* init1)(void * data, int lo, int hi); + // init2(): should initialize elements in data[] from 'lo' to 'hi' + // using corresponding elements from src[] (copy constructor) + void (* init2)(void * data, int lo, int hi, + const void * src, int src_lo, int src_hi); + // copy(): should copy elements from src[] to dst[] (copy operator) + void (* copy)(void * dst, int dst_lo, int dst_hi, + const void * src, int src_lo, int src_hi); + // insert(): should insert '*what' at position 'where' 'howmany' times + // into array data[] having 'els' initialized elements + void (* insert)(void * data, int els, int where, const void * what, + int howmany); +}; + +inline int +ArrayRep::size() const +{ + return hibound - lobound + 1; +} + +inline int +ArrayRep::lbound() const +{ + return lobound; +} + +inline int +ArrayRep::hbound() const +{ + return hibound; +} + +inline void +ArrayRep::empty() +{ + resize(0, -1); +} + +inline void +ArrayRep::touch(int n) +{ + if (hibound < lobound) + { + resize(n,n); + } else + { + int nlo = lobound; + int nhi = hibound; + if (n < nlo) nlo = n; + if (n > nhi) nhi = n; + resize(nlo, nhi); + } +} + +/** Dynamic array base class. + This is an auxiliary base class for \Ref{DArray} and \Ref{TArray} + implementing some shared functions independent of the type of array + elements. It's not supposed to be constructed by hands. Use \Ref{DArray} + and \Ref{TArray} instead. + */ + +class ArrayBase : protected _ArrayBase +{ +protected: + void check(void); + void detach(void); + + ArrayBase(void) {}; +public: + /// Returns the number of elements in the array + int size() const; + /** Returns the lower bound of the valid subscript range. */ + int lbound() const; + /** Returns the upper bound of the valid subscript range. */ + int hbound() const; + /** Erases the array contents. All elements in the array are destroyed. + The valid subscript range is set to the empty range. */ + void empty(); + /** Extends the subscript range so that is contains #n#. + This function does nothing if #n# is already int the valid subscript range. + If the valid range was empty, both the lower bound and the upper bound + are set to #n#. Otherwise the valid subscript range is extended + to encompass #n#. This function is very handy when called before setting + an array element: + \begin{verbatim} + int lineno=1; + DArray a; + while (! end_of_file()) { + a.touch[lineno]; + a[lineno++] = read_a_line(); + } + \end{verbatim} + */ + void touch(int n); + /** Resets the valid subscript range to #0#---#hibound#. + This function may destroy some array elements and may construct + new array elements with the null constructor. Setting #hibound# to + #-1# resets the valid subscript range to the empty range. + @param hibound upper bound of the new subscript range. */ + void resize(int hibound); + /** Resets the valid subscript range to #lobound#---#hibound#. + This function may destroy some array elements and may construct + new array elements with the null constructor. Setting #lobound# to #0# and + #hibound# to #-1# resets the valid subscript range to the empty range. + @param lobound lower bound of the new subscript range. + @param hibound upper bound of the new subscript range. */ + void resize(int lobound, int hibound); + /** Shifts the valid subscript range. Argument #disp# is added to both + bounds of the valid subscript range. Array elements previously + located at subscript #x# will now be located at subscript #x+disp#. */ + void shift(int disp); + /** Deletes array elements. The array elements corresponding to + subscripts #n#...#n+howmany-1# are destroyed. All array elements + previously located at subscripts greater or equal to #n+howmany# + are moved to subscripts starting with #n#. The new subscript upper + bound is reduced in order to account for this shift. + @param n subscript of the first element to delete. + @param howmany number of elements to delete. */ + void del(int n, unsigned int howmany=1); + + virtual ~ArrayBase(void) {}; +}; + +inline void +ArrayBase::detach(void) +{ + ArrayRep * new_rep=new ArrayRep(*(ArrayRep *) get()); + assign(new_rep); +} + +inline void +ArrayBase::check(void) +{ + if (get()->get_count()>1) detach(); +} + +inline int +ArrayBase::size() const +{ + return ((const ArrayRep *) get())->size(); +} + +inline int +ArrayBase::lbound() const +{ + return ((const ArrayRep *) get())->lobound; +} + +inline int +ArrayBase::hbound() const +{ + return ((const ArrayRep *) get())->hibound; +} + +inline void +ArrayBase::empty() +{ + check(); + ((ArrayRep *) get())->empty(); +} + +inline void +ArrayBase::resize(int lo, int hi) +{ + check(); + ((ArrayRep *) get())->resize(lo, hi); +} + +inline void +ArrayBase::resize(int hi) +{ + resize(0, hi); +} + +inline void +ArrayBase::touch(int n) +{ + check(); + ((ArrayRep *) get())->touch(n); +} + +inline void +ArrayBase::shift(int disp) +{ + check(); + ((ArrayRep *) get())->shift(disp); +} + +inline void +ArrayBase::del(int n, unsigned int howmany) +{ + check(); + + ((ArrayRep *) get())->del(n, howmany); +} + +/** Dynamic array template base class. + This is an auxiliary template base class for \Ref{DArray} and \Ref{TArray} + implementing some shared functions which {\em depend} on the type of + the array elements (this is contrary to \Ref{ArrayBase}). + It's not supposed to be constructed by hands. Use \Ref{DArray} and + \Ref{TArray} instead. + */ + +template +class ArrayBaseT : public ArrayBase +{ +public: + virtual ~ArrayBaseT(void) {}; + + /** Returns a reference to the array element for subscript #n#. This + reference can be used for both reading (as "#a[n]#") and writing (as + "#a[n]=v#") an array element. This operation will not extend the valid + subscript range: an exception \Ref{GException} is thrown if argument #n# + is not in the valid subscript range. */ + TYPE& operator[](int n); + /** Returns a constant reference to the array element for subscript #n#. + This reference can only be used for reading (as "#a[n]#") an array + element. This operation will not extend the valid subscript range: an + exception \Ref{GException} is thrown if argument #n# is not in the valid + subscript range. This variant of #operator[]# is necessary when dealing + with a #const DArray#. */ + const TYPE& operator[](int n) const; + + /** Returns a pointer for reading or writing the array elements. This + pointer can be used to access the array elements with the same + subscripts and the usual bracket syntax. This pointer remains valid as + long as the valid subscript range is unchanged. If you change the + subscript range, you must stop using the pointers returned by prior + invocation of this conversion operator. */ + operator TYPE* (); + /** Returns a pointer for reading (but not modifying) the array elements. + This pointer can be used to access the array elements with the same + subscripts and the usual bracket syntax. This pointer remains valid as + long as the valid subscript range is unchanged. If you change the + subscript range, you must stop using the pointers returned by prior + invocation of this conversion operator. */ + operator const TYPE* () const; + +#ifndef __MWERKS__ //MCW can't compile + operator const TYPE* (); +#endif + /** Insert new elements into an array. This function inserts + #howmany# elements at position #n# into the array. The initial value #val# + is copied into the new elements. All array elements previously located at subscripts + #n# and higher are moved to subscripts #n+howmany# and higher. The upper bound of the + valid subscript range is increased in order to account for this shift. + @param n subscript of the first inserted element. + @param val initial value of the new elements. + @param howmany number of elements to insert. */ + void ins(int n, const TYPE &val, unsigned int howmany=1); + + /** Sort array elements. Sort all array elements in ascending order. Array + elements are compared using the less-or-equal comparison operator for + type #TYPE#. */ + void sort(); + /** Sort array elements in subscript range #lo# to #hi#. Sort all array + elements whose subscripts are in range #lo#..#hi# in ascending order. + The other elements of the array are left untouched. An exception is + thrown if arguments #lo# and #hi# are not in the valid subscript range. + Array elements are compared using the less-or-equal comparison operator + for type #TYPE#. + @param lo low bound for the subscripts of the elements to sort. + @param hi high bound for the subscripts of the elements to sort. */ + void sort(int lo, int hi); +protected: + ArrayBaseT(void) {}; +private: + // Callbacks called from ArrayRep + static void destroy(void * data, int lo, int hi); + static void init1(void * data, int lo, int hi); + static void init2(void * data, int lo, int hi, + const void * src, int src_lo, int src_hi); + static void copy(void * dst, int dst_lo, int dst_hi, + const void * src, int src_lo, int src_hi); + static void insert(void * data, int els, int where, + const void * what, int howmany); +}; + +template inline +ArrayBaseT::operator TYPE* () +{ + check(); + + ArrayRep * rep=(ArrayRep *) get(); + return &((TYPE *) rep->data)[-rep->minlo]; +} + +#ifndef __MWERKS__ //MCW can't compile +template inline +ArrayBaseT::operator const TYPE* () +{ + const ArrayRep * rep=(const ArrayRep *) get(); + return &((const TYPE *) rep->data)[-rep->minlo]; +} +#endif + +template inline +ArrayBaseT::operator const TYPE* () const +{ + const ArrayRep * rep=(const ArrayRep *) get(); + return &((const TYPE *) rep->data)[-rep->minlo]; +} + +template inline TYPE& +ArrayBaseT::operator[](int n) +{ + check(); + + ArrayRep * rep=(ArrayRep *) get(); + if (nlobound || n>rep->hibound) + G_THROW( ERR_MSG("arrays.ill_sub") ); + return ((TYPE *) rep->data)[n - rep->minlo]; +} + +template inline const TYPE& +ArrayBaseT::operator[](int n) const +{ + const ArrayRep * rep=(const ArrayRep *) get(); + if (nlobound || n>rep->hibound) + G_THROW( ERR_MSG("arrays.ill_sub") ); + return ((const TYPE *) rep->data)[n - rep->minlo]; +} + +template inline void +ArrayBaseT::ins(int n, const TYPE &val, unsigned int howmany) +{ + check(); + + ((ArrayRep *) get())->ins(n, &val, howmany); +} + +template void +ArrayBaseT::sort() +{ + sort(lbound(), hbound()); +} + +template void +ArrayBaseT::sort(int lo, int hi) +{ + if (hi <= lo) + return; + // Test for insertion sort (optimize!) + if (hi <= lo + 20) + { + for (int i=lo+1; i<=hi; i++) + { + int j = i; + TYPE tmp = (*this)[i]; + while ((--j>=lo) && !((*this)[j]<=tmp)) + (*this)[j+1] = (*this)[j]; + (*this)[j+1] = tmp; + } + return; + } + // -- determine suitable quick-sort pivot + TYPE tmp = (*this)[lo]; + TYPE pivot = (*this)[(lo+hi)/2]; + if (pivot <= tmp) + { tmp = pivot; pivot=(*this)[lo]; } + if ((*this)[hi] <= tmp) + { pivot = tmp; } + else if ((*this)[hi] <= pivot) + { pivot = (*this)[hi]; } + // -- partition set + int h = hi; + int l = lo; + while (l < h) + { + while (! (pivot <= (*this)[l])) l++; + while (! ((*this)[h] <= pivot)) h--; + if (l < h) + { + tmp = (*this)[l]; + (*this)[l] = (*this)[h]; + (*this)[h] = tmp; + l = l+1; + h = h-1; + } + } + // -- recursively restart + sort(lo, h); + sort(l, hi); +} + +/** Dynamic array for simple types. + Template class #TArray# implements an array of + elements of {\em simple} type #TYPE#. {\em Simple} means that the type + may be #char#, #int#, #float# etc. The limitation is imposed by the + way in which the #TArray# is working with its elements: it's not trying + to execute elements' constructors, destructors or copy operators. It's + just doing bitwise copy. Except for this it's pretty much the same as + \Ref{DArray}. + + Please note that most of the methods are implemented in the base classes + \Ref{ArrayBase} and \Ref{ArrayBaseT}. +*/ + +template +class TArray : public ArrayBaseT { +public: + /** Constructs an empty array. The valid subscript range is initially + empty. Member function #touch# and #resize# provide convenient ways + to enlarge the subscript range. */ + TArray(); + /** Constructs an array with subscripts in range 0 to #hibound#. + The subscript range can be subsequently modified with member functions + #touch# and #resize#. + @param hibound upper bound of the initial subscript range. */ + TArray(int hibound); + /** Constructs an array with subscripts in range #lobound# to #hibound#. + The subscript range can be subsequently modified with member functions + #touch# and #resize#. + @param lobound lower bound of the initial subscript range. + @param hibound upper bound of the initial subscript range. */ + TArray(int lobound, int hibound); + + virtual ~TArray() {}; +private: + // Callbacks called from ArrayRep + static void destroy(void * data, int lo, int hi); + static void init1(void * data, int lo, int hi); + static void init2(void * data, int lo, int hi, + const void * src, int src_lo, int src_hi); + static void insert(void * data, int els, int where, + const void * what, int howmany); +}; + +template void +TArray::destroy(void * data, int lo, int hi) +{ +} + +template void +TArray::init1(void * data, int lo, int hi) +{ +} + +template void +TArray::init2(void * data, int lo, int hi, + const void * src, int src_lo, int src_hi) +{ + if (data && src) + { + int els=hi-lo+1; + if (els>src_hi-src_lo+1) els=src_hi-src_lo+1; + if (els>0) + memmove((void *) &((TYPE *) data)[lo], + (void *) &((TYPE *) src)[src_lo], els*sizeof(TYPE)); + }; +} + +// inline removed +template void +TArray::insert(void * data, int els, int where, + const void * what, int howmany) +{ + memmove(((TYPE *) data)+where+howmany, + ((TYPE *) data)+where, sizeof(TYPE)*(els-where)); + for(int i=0;i +TArray::TArray () +{ + this->assign(new ArrayRep(sizeof(TYPE), destroy, init1, + init2, init2, insert)); +} + +template +TArray::TArray(int hi) +{ + this->assign(new ArrayRep(sizeof(TYPE), destroy, init1, + init2, init2, insert, hi)); +} + +template +TArray::TArray(int lo, int hi) +{ + this->assign(new ArrayRep(sizeof(TYPE), destroy, init1, + init2, init2, insert, lo, hi)); +} + +//inline removal ends + +/** Dynamic array for general types. + Template class #DArray# implements an array of + elements of type #TYPE#. Each element is identified by an integer + subscript. The valid subscripts range is defined by dynamically + adjustable lower- and upper-bounds. Besides accessing and setting + elements, member functions are provided to insert or delete elements at + specified positions. + + This template class must be able to access + \begin{itemize} + \item a null constructor #TYPE::TYPE()#, + \item a copy constructor #TYPE::TYPE(const TYPE &)#, + \item and a copy operator #TYPE & operator=(const TYPE &)#. + \end{itemize} + + The class offers "copy-on-demand" policy, which means that when you + copy the array object, array elements will stay intact as long as you + don't try to modify them. As soon as you make an attempt to change + array contents, the copying is done automatically and transparently + for you - the procedure that we call "copy-on-demand". This is the main + difference between this class and \Ref{GArray} (now obsolete) + + Please note that most of the methods are implemented in the base classes + \Ref{ArrayBase} and \Ref{ArrayBaseT}. +*/ + +template +class DArray : public ArrayBaseT { +public: + /** Constructs an empty array. The valid subscript range is initially + empty. Member function #touch# and #resize# provide convenient ways + to enlarge the subscript range. */ + DArray(void); + /** Constructs an array with subscripts in range 0 to #hibound#. + The subscript range can be subsequently modified with member functions + #touch# and #resize#. + @param hibound upper bound of the initial subscript range. */ + DArray(const int hibound); + /** Constructs an array with subscripts in range #lobound# to #hibound#. + The subscript range can be subsequently modified with member functions + #touch# and #resize#. + @param lobound lower bound of the initial subscript range. + @param hibound upper bound of the initial subscript range. */ + DArray(const int lobound, const int hibound); + + virtual ~DArray() {}; +private: + // Callbacks called from ArrayRep + static void destroy(void * data, int lo, int hi); + static void init1(void * data, int lo, int hi); + static void init2(void * data, int lo, int hi, + const void * src, int src_lo, int src_hi); + static void copy(void * dst, int dst_lo, int dst_hi, + const void * src, int src_lo, int src_hi); + static void insert(void * data, int els, int where, + const void * what, int howmany); +}; + +template void +DArray::destroy(void * data, int lo, int hi) +{ + if (data) + for(int i=lo;i<=hi;i++) + ((TYPE *) data)[i].TYPE::~TYPE(); +} + +template void +DArray::init1(void * data, int lo, int hi) +{ + if (data) + for(int i=lo;i<=hi;i++) + new ((void *) &((TYPE *) data)[i]) TYPE; +} + +template void +DArray::init2(void * data, int lo, int hi, + const void * src, int src_lo, int src_hi) +{ + if (data && src) + { + int i, j; + for(i=lo, j=src_lo;i<=hi && j<=src_hi;i++, j++) + new ((void *) &((TYPE *) data)[i]) TYPE(((TYPE *) src)[j]); + }; +} + +template void +DArray::copy(void * dst, int dst_lo, int dst_hi, + const void * src, int src_lo, int src_hi) +{ + if (dst && src) + { + int i, j; + for(i=dst_lo, j=src_lo;i<=dst_hi && j<=src_hi;i++, j++) + ((TYPE *) dst)[i]=((TYPE *) src)[j]; + }; +} + +template inline void +DArray::insert(void * data, int els, int where, + const void * what, int howmany) +{ + // Now do the insertion + TYPE * d=(TYPE *) data; + + int i; + for (i=els+howmany-1; i>=els; i--) + { + if (i-where >= (int)howmany) + new ((void*) &d[i]) TYPE (d[i-howmany]); + else + new ((void*) &d[i]) TYPE (*(TYPE *) what); + } + + for (i=els-1; i>=where; i--) + { + if (i-where >= (int)howmany) + d[i] = d[i-howmany]; + else + d[i] = *(TYPE *) what; + } +} + +template inline +DArray::DArray () +{ + this->assign(new ArrayRep(sizeof(TYPE), destroy, init1, + init2, copy, insert)); +} + +template inline +DArray::DArray(const int hi) +{ + this->assign(new ArrayRep(sizeof(TYPE), destroy, init1, + init2, copy, insert, hi)); +} + +template inline +DArray::DArray(const int lo, const int hi) +{ + this->assign(new ArrayRep(sizeof(TYPE), destroy, init1, + init2, copy, insert, lo, hi)); +} + +/** Dynamic array for \Ref{GPBase}d classes. + + There are many situations when it's necessary to create arrays of + \Ref{GP} pointers. For example, #DArray ># or #DArray >#. + This would result in compilation of two instances of \Ref{DArray} because + from the viewpoint of the compiler there are two different classes used + as array elements: #GP# and #GP